Commit graph

3 commits

Author SHA1 Message Date
1d09abdc8b feat(classifier): workspaces — scan-once, resume from snapshot (phase 6)
The classifier re-scanned the source on every session; on cloud-backed mounts
(OneDrive/Samba) that's minutes of per-op latency. Workspaces fix it: scan a
folder ONCE, snapshot the completed tree, and resume instantly — all
classification runs on the data model; the filesystem is only touched at copy.

- persist.js v2: multi-workspace IndexedDB (tiny 'index' store for the welcome
  list + 'data' store holding the source handle, tree snapshot, and map). DB v2.
- scanner.js: snapshotTree()/loadSnapshot() (compact, handle-less, marked done,
  totals recomputed) + lazy resolveFileHandle/resolveDirHandle from the root.
- workspace.js: welcome manager (new/open/rename/delete), debounced autosave of
  the active workspace, 'Refresh from disk' (re-scan → re-snapshot, path-keyed
  map carries over). New workspace = the one slow full scan; reopen = instant.
- copy.js: resolves snapshot files' handles from the workspace root with a
  one-click read permission re-grant; missing-on-disk files surface as errors.
- app.js: enterAppShell() shared by rename/workspace flows; exposes setMode;
  classify.js decoupled from persistence.
- template/css: welcome workspace list + header 'Workspaces' button.
- tests: snapshot round-trip, persist CRUD + classify-only-preserves-tree,
  copy-from-snapshot via mock root handle (28 classify/classifier tests green).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 15:07:40 -05:00
eb1e3ec948 feat(classifier): left-tree markers, exclude, cross-tree find (phase 4)
- Each source file row shows a classification state dot (unassigned →
  has-tracking/transmittal → done), and each folder shows an aggregate dot
  over its subtree.
- Right-click a file or folder to Exclude/Include from the copy (folder applies
  to its whole subtree) or clear an axis; excluded files are struck through and
  never copied.
- Cross-tree find is bidirectional: click a placed file in the target pane to
  reveal+flash it in the source tree (expanding its folders); click a source
  file to switch the target pane to its placed axis and flash the node.
- Target pane now reverse-looks-up over ALL scanned files (the left tree), not
  the selection-scoped grid, with placements grouped in one pass per render.
- classify.getAssignment() read-only accessor; 5 new tests (18 total green).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 12:32:42 -05:00
a8f116734d feat(classifier): Classify & Copy state model + persistence (phase 1)
Foundation for the non-destructive map+copy workflow: source stays read-only,
files are mapped onto two orthogonal target trees, a later step copies renamed
copies to a separate output dir.

- classify.js: the single source of truth. assignments map keyed by
  source-relative path (survives re-pick); tracking tree (positional: ancestors
  joined '-' = tracking number, immediate parent 'REV (STATUS)' leaf = rev+status,
  title from original name) and transmittal tree (<party>/{received,issued}/<bin>).
  deriveTarget() computes filename + output path + validation purely; pub/sub +
  debounced autosave; node CRUD with dangling-placement cleanup.
- persist.js: IndexedDB store of the serialized map + the source
  FileSystemDirectoryHandle, with queryPermission/requestPermission re-grant on
  reload and a re-pick fallback.
- tests/classify.spec.js: 9 in-page unit tests for the derive/assignment logic
  (no FS Access needed) — tracking join, leaf REV (STATUS) parse incl. invalid
  status, title derivation/override, transmittal path composition, exclude,
  cascade delete.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 12:11:04 -05:00