Space keeps its scans and refreshes them: zfs diff, folder mtimes, resume after cancel

A scan is saved beside the config and read back after a restart. The next scan starts
from it: on a pool with snapshots zfs diff names what changed and only those folders are
read; elsewhere a folder whose mtime is unchanged keeps its list and only its kept files
are stat'ed again. A cancelled scan keeps what it walked and Resume reads the rest.
Forget drops the saved result. The treemap is every file a tile, grouped by folder, with
no nested boxes: the folder chains of a Linux system made a staircase of empty headers.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Mitchell-Johnson
2026-09-23 00:43:30 -07:00
co-authored by Claude Fable 5.1
parent c96d6facad
commit 53d1da08a5
11 changed files with 869 additions and 145 deletions
+21 -4
View File
@@ -346,10 +346,27 @@ something long in one, switch away and back, refresh — it's all still there.
databases & logs, other; the validated categorical set, dark and light) with folders as
labelled boxes; hover for path, size and share; click a folder to drill, breadcrumbs and ↑
to come back. The map asks the server for the folder pruned to what a tile could show
(`min` = 1/4000 of the folder, depth 12), the list one level at a time. **Largest files**:
the 1,000 biggest with a path filter. Works on every machine through the hub. Not kept
across a restart; not done: delete from here, a size-over-time history, per-user column
choices.
(`min` = 1/6000 of the folder, 24 deep; deeper folders come back as one lump), the list
one level at a time. **Largest files**: the 1,000 biggest with a path filter. Works on
every machine through the hub.
**Smarter and faster (2026-09-23, at Mitchell's request):** a scan is *kept* — in memory
and in `<data>/space/<target>.scan` (the same varint stream) + `.json`, read back after a
restart — and the next scan *starts from it*: the helper is handed the last tree on stdin
and reads a directory again only when something says it changed. On a ZFS pool with
snapshots, the scan records the newest snapshot of each dataset at start (`bases`), and the
next one runs `zfs diff -H -F <base>` per dataset: only the directories it names are
read, their ancestors kept but looked into, everything else kept wholesale without a
stat. Elsewhere (ext4, or a dataset with no snapshot) a directory whose mtime — to the
nanosecond — is unchanged keeps its list and only its kept files are stat'ed again, since
a file can grow without its directory noticing. A **cancelled** scan keeps what it walked,
marks the folders it never got to (`partial`, "not yet read" in the tree) and **Resume**
reads just those. core: full 1.2 s → refresh 0.3 s (2 folders read, 84,755 kept). The
status line says which (`method`, `by_root`, read/kept counts); **Forget** drops the saved
result so the next scan is full. The old result stays browsable while a refresh runs.
**Treemap rethought** the same day: every file a tile grouped by folder — folders are only
a thin line and a name strip on the first level — instead of nested boxes with headers,
which on Linux's single-child folder chains was a staircase of headers around nothing.
Not done: delete from here, a size-over-time history, per-user column choices.
- **Auth hardening** — WebAuthn passkeys (phone Face ID), TOTP fallback, optional NPM
access list restricting to WireGuard/LAN.
- **Files tab** — **shipped 2026-09-18** (`internal/files`, `Files.tsx`): browse from