docs: archive Phase R (R1-R3) to COMPLETED; reconcile CLAUDE.md + CONTEXT.md
This commit is contained in:
+149
@@ -1034,3 +1034,152 @@ LICE-drawn tabs + overflow, and both move affordances with drop-highlighting (5)
|
||||
Active-bank indicator placement (the one residual polish detail) was resolved at
|
||||
build time. B5 forks R-A and R-B settled 2026-07-24 (see B5 and B1 notes above).
|
||||
Both in `docs/product/removal-and-prune.md` §Fork R-A / §Fork R-B.
|
||||
|
||||
---
|
||||
|
||||
# Phase R — Reclaim (file lifecycle: the prune path)
|
||||
|
||||
> **New pillar, own lettered namespace.** Prune is the file-lifecycle path the
|
||||
> capture and multi-bank specs forward-reference throughout ("files persist on disk
|
||||
> until prune") but that had no phase, module, or point. It is the **only** operation
|
||||
> in ReaSampler that deletes bytes off disk. Namespaced **`R` (Reclaim)** alongside
|
||||
> `M`/`D`/`B` because it is a distinct pillar — it serves *every* orphan-producing
|
||||
> path (delete-bank, sample-remove B5, potentially M10 re-capture), not just
|
||||
> Multi-bank, and it carries a new risk class (file deletion) with its own
|
||||
> invariants. Authoritative spec: **CONTEXT.md §Prune — file-lifecycle spec**.
|
||||
> Product framing + phase-placement justification + forks:
|
||||
> `docs/product/removal-and-prune.md` §Prune.
|
||||
>
|
||||
> **Boundary (load-bearing):** *remove creates orphans; prune reclaims them.* No
|
||||
> operation other than prune deletes a file; prune deletes only files no index
|
||||
> references. A bank op that deletes a file is still a bug.
|
||||
>
|
||||
> **Depends on:** B1, B2 (needs the multi-bank book to union the referenced-set
|
||||
> across all banks) and B5 conceptually (sample-remove is a primary orphan-producer,
|
||||
> so remove-then-prune is the coherent pair — mirror of evacuate-then-delete). Does
|
||||
> **not** depend on the B3/B4 UI.
|
||||
|
||||
## R1 — prune-reconcile core (pure)
|
||||
**Goal:** REAPER-free, filesystem-free reconciler — given the files present in the
|
||||
bank folder, the files referenced by the book (unioned across all banks, pool
|
||||
included), and the **owned-file manifest** (fork R-D, written from capture onward by
|
||||
B-cap), compute the orphan set `(owned ∩ present) − referenced`. The mirror of
|
||||
`ViewModeModel::reconcile(liveGuids)`, one level down (files instead of GUIDs).
|
||||
CONTEXT.md §Prune (Module architecture — pure).
|
||||
**Verify:** CTest green. **Prune null test:** a folder whose every file is
|
||||
referenced deletes nothing; prune returns exactly `(owned ∩ present) − referenced`
|
||||
and nothing else. Referenced-set unioned across every bank (a file referenced by any
|
||||
bank — including via a copy — is never an orphan); a present-but-not-owned file (a
|
||||
hand-dropped file) is never an orphan.
|
||||
|
||||
- [x] Prune-reconcile pure function: `(present, referenced, owned) → orphans`,
|
||||
computing `(owned ∩ present) − referenced`; referenced unioned across the whole
|
||||
book (copies keep a file alive).
|
||||
- [x] Tests: prune null test (all-referenced → empty); orphan = (owned∩present)−
|
||||
referenced; a copied file referenced by a second bank survives; a present-but-
|
||||
unowned (hand-dropped) file is never reclaimed; empty folder / empty book / empty
|
||||
manifest edge cases.
|
||||
|
||||
**Notes/decisions:**
|
||||
- New pure module `src/prune_reconcile.{h,cpp}`: exports `pruneOrphans(present,
|
||||
referenced, owned)` (the safety-critical set algebra), `buildPruneReport`
|
||||
(count/bytes/display-capped list, unit-testable), and `pruneDeletePlan` (the R3
|
||||
confirm-time staleness intersection — `confirmed ∩ freshOrphans` in confirm order).
|
||||
Exact-string path match throughout (no case-folding, no separator normalization).
|
||||
`BankBook::referencedPaths()` additive const union query (all banks incl. pool,
|
||||
de-duped) added to `bank_book`. New `prune_reconcile_tests` CTest target.
|
||||
|
||||
---
|
||||
|
||||
## R2 — prune shell + persist wiring (filesystem I/O, thin)
|
||||
**Goal:** Enumerate the current project bank folder (M4 project-relative resolution),
|
||||
supply the referenced-set and the **owned-file manifest** (from B-cap) from the
|
||||
session, feed the pure core, and produce a dry-run manifest. No deletion in this
|
||||
wave — the report path only. CONTEXT.md §Prune (persist / prune shell).
|
||||
**Verify (in DAW):** Dry-run reports the orphan count + reclaimed size (+ file list
|
||||
for a small set) against the resolved current bank folder; resolves paths the same
|
||||
way the index does (survives a Save-As relocation); deletes nothing.
|
||||
**Depends on:** R1, B1, B2.
|
||||
|
||||
- [x] Prune shell: enumerate the resolved current bank folder; feed the pure core.
|
||||
- [x] Session supplies the referenced-set (union across the book) **and the
|
||||
owned-file manifest** (written by B-cap); resolve the bank folder via the M4
|
||||
project-relative machinery.
|
||||
- [x] Dry-run manifest: orphan count + reclaimed size (+ files for a small set);
|
||||
**no deletion in this wave.**
|
||||
|
||||
**Notes/decisions:**
|
||||
- `ReaSamplerSession::pruneDryRun()` (read-only, non-throwing) enumerates the
|
||||
resolved current bank folder, unioning `book().referencedPaths()` and
|
||||
`owned().paths()`, feeds `pruneOrphans`, and calls `buildPruneReport` with a 64-file
|
||||
display cap. Pure `bankRelativeForName` (`capture_paths`) normalizes the folder-
|
||||
enumeration spelling to match the index convention so the pure core's exact-string
|
||||
match lines up. Forever-stable `BANK_PRUNE_FOLDER` action registered (dry-run report
|
||||
to console in R2; deletion wired in R3 behind the same action id).
|
||||
|
||||
---
|
||||
|
||||
## R3 — deletion + action (the destructive step, guarded)
|
||||
**Goal:** The confirmed deletion step, the bindable "Prune bank folder" action, and
|
||||
a `bank_panel` prune button: dry-run-first, confirm-with-manifest, then reclaim the
|
||||
orphan set — via OS trash where portably available (fork R-C), else unlink.
|
||||
CONTEXT.md §Prune (guardrails, API).
|
||||
**Verify (in DAW):** "Prune bank folder" (action or panel button) reports first,
|
||||
deletes only on explicit confirm, and reclaims exactly the orphan set — never a
|
||||
referenced file, never a hand-dropped non-bank file; the referenced/owned-set safety
|
||||
holds; deletions route to OS trash where available; non-bank and capture invariants
|
||||
untouched.
|
||||
**Depends on:** R2 (and B-cap's owned-file manifest). All forks settled 2026-07-24.
|
||||
|
||||
- [x] "Prune bank folder" action (`command_id`/`gaccel`/`hookcommand`),
|
||||
dry-run-first, confirm-to-delete.
|
||||
- [x] `bank_panel` prune button (fork R-E) that fires the "Prune bank folder"
|
||||
action through the existing command-id contract — the panel affordance alongside
|
||||
the bindable action; split: button hit-test/layout is pure (mirror of
|
||||
`mode_switch`/`bank_grid`), draw + dispatch is bank_panel shell.
|
||||
- [x] Deletion mechanism (fork R-C, settled trash-preferred): route to OS trash
|
||||
where a portable move-to-trash is verified available, else unlink behind the
|
||||
dry-run/confirm guardrail.
|
||||
- [x] Orphan attribution (fork R-D, settled owned-file manifest): reclaim only
|
||||
`(owned ∩ present) − referenced` — the bank system's own leavings, never a
|
||||
hand-dropped folder file. (Manifest written by B-cap; consumed via R1/R2.)
|
||||
|
||||
**Notes/decisions:**
|
||||
- Deletion is guarded: dry-run → REAPER `ShowMessageBox` confirm (count+bytes+files)
|
||||
→ `pruneDeletePlan` staleness intersection (confirmed ∩ fresh pure-core output) →
|
||||
delete exactly the plan. Zero ext-state writes, no undo point (file deletion is not
|
||||
REAPER-undoable by design).
|
||||
- **Windows:** routes to Recycle Bin via `SHFileOperationW` + `FOF_ALLOWUNDO`
|
||||
(verified against SDK 10.0.26100). **macOS / Linux:** no portable SWELL trash
|
||||
surface; falls back to `unlink` behind the dry-run/confirm guardrail.
|
||||
- Manifest entries are deliberately NOT removed on deletion (the owned-file manifest
|
||||
algebra self-cleans: a deleted file will drop from `present` on the next prune scan,
|
||||
and `pruneOrphans` returns `(owned ∩ present) − referenced` — the absent file
|
||||
contributes nothing regardless).
|
||||
- New pure module `src/prune_button.{h,cpp}`: layout (`computePruneButton`) and
|
||||
hit-test (`hitTestPruneButton`) for the footer prune button, right-anchored,
|
||||
suppressed gracefully when the footer is too narrow. Mirror of `mode_switch` /
|
||||
`tab_strip`. New `prune_button_tests` CTest target.
|
||||
- `bank_panel` footer button dispatches `BANK_PRUNE_FOLDER` via `Main_OnCommand`
|
||||
through the registered command id (the same action as the bindable menu entry —
|
||||
no duplicate logic).
|
||||
|
||||
## Phase R forks — settled 2026-07-24
|
||||
- **Fork R-C — deletion mechanism.** Settled: **trash-preferred, unlink fallback.**
|
||||
Route to OS trash where a portable move-to-trash is available (recoverable), else
|
||||
unlink behind strong dry-run/confirm. Per-platform trash surface verified at build:
|
||||
Windows `SHFileOperationW` + `FOF_ALLOWUNDO` (SDK 10.0.26100); macOS/Linux no
|
||||
portable SWELL trash surface → unlink fallback. Folded into R3.
|
||||
- **Fork R-D — orphan attribution.** Settled: **owned-file manifest**,
|
||||
`(owned ∩ present) − referenced`; folder-sweep rejected as unsafe. **Seam lands
|
||||
early** — the manifest is written from capture onward (new **B-cap** point in
|
||||
Phase B), not reconstructed at prune time; R1/R2 consume it. Persistence shape
|
||||
(sibling `"reasampler"` key vs. `banks` blob) resolved at build time: sibling
|
||||
`"owned_files"` key.
|
||||
- **Fork R-E — trigger.** Settled: **manual action + `bank_panel` button**,
|
||||
dry-run-first, confirm-to-delete. No background sweep. The earlier optional
|
||||
delete-time "…and prune now" convenience was **not** selected — out of scope.
|
||||
Folded into R3.
|
||||
|
||||
Both docs of record: `docs/product/removal-and-prune.md` §Fork R-C/R-D/R-E and
|
||||
CONTEXT.md §Prune (Settled forks).
|
||||
|
||||
Reference in New Issue
Block a user