docs: settle removal/prune forks R-A..R-E; add owned-file manifest seam
R-A this-bank; R-B batched REAPER undo points (Phase-B-wide, SDK must-verify); R-C trash-preferred w/ unlink fallback; R-D owned-file manifest, landed early as new B-cap capture point; R-E manual action + bank_panel button.
This commit is contained in:
@@ -194,6 +194,35 @@ active id. Legacy `bank_index` JSON parses into `{ pool }` with zero named banks
|
||||
with dest collapse; cross-bank same-hash coexistence; dest collapse on move into a
|
||||
bank already holding the hash; JSON lossless; legacy migration.
|
||||
|
||||
> **Phase-B-wide undo (fork R-B, settled 2026-07-24 — batched REAPER undo points).**
|
||||
> Every index verb across B1–B5 (create/rename/reorder/delete-bank, move, copy,
|
||||
> evacuate, remove) wraps its bank/index mutation in a **batched REAPER undo point**
|
||||
> (`Undo_BeginBlock` / `Undo_EndBlock`), so one bank operation is one Ctrl-Z. This is
|
||||
> a cross-cutting decision that retro-touches B1–B4, not a B5-local one; the
|
||||
> per-verb points above inherit it. **Must-verify before build:** confirm against
|
||||
> `vendor/reaper-sdk` that `"reasampler"` ext-state mutations participate correctly
|
||||
> in `Undo_BeginBlock`/`Undo_EndBlock` undo blocks — the whole approach depends on
|
||||
> it. See CONTEXT.md §Sample removal (Guardrails) + product notes §Fork R-B.
|
||||
|
||||
## B-cap — owned-file manifest seam (capture writes; prune consumes in Phase R)
|
||||
**Goal:** Capture writes each file it creates into an **owned-file manifest**
|
||||
persisted in the `"reasampler"` ext-state, so Phase R prune can later distinguish
|
||||
the bank system's own orphans from hand-dropped files. Consumed only in Phase R
|
||||
(R1/R2) — landed early here because reconstructing the manifest retroactively is a
|
||||
backfill cliff (fork R-D, settled 2026-07-24: *defer the feature, design the seam*).
|
||||
CONTEXT.md §Prune (Settled decisions — orphan attribution) + product notes §Fork R-D.
|
||||
**Verify:** every file the capture path creates is recorded in the owned-file
|
||||
manifest; the manifest round-trips through the `"reasampler"` ext-state (Save / Save
|
||||
As / reopen); relative-paths-only preserved. Prune's consumption of it is Phase R.
|
||||
**Depends on:** the capture add-path (M7) + persist blob machinery (M4 / B2).
|
||||
|
||||
- [ ] Capture records each created file into an owned-file manifest (the set of
|
||||
files the book has created), persisted in the `"reasampler"` ext-state (sibling
|
||||
key or folded into the `banks` blob — persistence shape is a small build-time
|
||||
residual, not a fork).
|
||||
- [ ] Manifest round-trips: survives Save / Save As / reopen via the M4 blob
|
||||
machinery; relative-paths-only. (Consumed by Phase R R1/R2 — not consumed here.)
|
||||
|
||||
## B2 — persist slice (banks ↔ project ext state)
|
||||
**Goal:** Serialize the book under the `banks` key in `"reasampler"` alongside the
|
||||
existing sections, with the pool folded in as bank-zero; migrate a legacy
|
||||
@@ -282,8 +311,9 @@ timeline item).
|
||||
- [ ] Surface `BankIndex::remove` through `bank_book`: remove a `Sample` from a
|
||||
bank's index; pool contents removable, pool-container privileges unchanged.
|
||||
- [ ] "Remove selected sample(s)" action (`command_id`/`gaccel`/`hookcommand`),
|
||||
MIDI-bindable; carries a `scope: this-bank | all-banks` seam (fork R-A — default
|
||||
this-bank until Daniel settles).
|
||||
MIDI-bindable; carries a `scope: this-bank | all-banks` seam (fork R-A, settled
|
||||
2026-07-24: **this-bank** is the default and only surfaced affordance; all-banks
|
||||
stays a latent seam-only parameter, not shipped).
|
||||
- [ ] `bank_panel` remove affordance on the current selection (reuse M5 selection
|
||||
model, as move/copy do).
|
||||
- [ ] Confirm-on-last-reference guardrail: remove that orphans a file (no other
|
||||
@@ -305,12 +335,16 @@ ready to scope into implementation waves. One polish detail remains:
|
||||
vs. lit-tab. "Unmistakable" is settled; only placement is open. Polish detail.
|
||||
(touches B4)
|
||||
|
||||
- **B5 sample-remove forks (NEW, unsettled — need Daniel):** **R-A** — remove scope
|
||||
(this-bank | all-banks | both); spec-of-record is this-bank-primary with a
|
||||
scope-parameter seam. **R-B** — undo model for `"reasampler"` ext-state index
|
||||
mutations (affects *all* of Phase B, surfaced by remove; move/copy/evacuate/
|
||||
delete-bank/remove are not on REAPER Ctrl-Z as specced). Lean: a single-snapshot
|
||||
ReaSampler-internal "undo last bank change." Both in `docs/product/removal-and-prune.md`.
|
||||
**B5 sample-remove forks — settled 2026-07-24:**
|
||||
- **R-A — remove scope.** Settled: **this-bank**. Removes the entry from the bank in
|
||||
view only; the `scope: this-bank | all-banks` seam stays in the action signature
|
||||
but all-banks is a latent parameter, not a surfaced verb. Folded into the B5 action
|
||||
point above.
|
||||
- **R-B — undo model (Phase-B-wide).** Settled: **batched REAPER undo points**
|
||||
(`Undo_BeginBlock`/`Undo_EndBlock`), one bank op = one Ctrl-Z. Applies across
|
||||
B1–B5 (retro-touches B1–B4) — captured as the cross-cutting note under B1 above,
|
||||
with the ext-state-participation SDK check as a must-verify-before-build.
|
||||
Both in `docs/product/removal-and-prune.md` §Fork R-A / §Fork R-B.
|
||||
|
||||
---
|
||||
|
||||
@@ -338,68 +372,84 @@ ready to scope into implementation waves. One polish detail remains:
|
||||
> **not** depend on the B3/B4 UI.
|
||||
|
||||
## R1 — prune-reconcile core (pure)
|
||||
**Goal:** REAPER-free, filesystem-free reconciler — given the set of files present
|
||||
in the bank folder and the set of files referenced by the book (unioned across all
|
||||
banks, pool included), compute the orphan set. The mirror of
|
||||
**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 `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).
|
||||
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.
|
||||
|
||||
- [ ] Prune-reconcile pure function: `(present, referenced) → orphans`, referenced
|
||||
unioned across the whole book (copies keep a file alive).
|
||||
- [ ] Tests: prune null test (all-referenced → empty); orphan = present−referenced;
|
||||
a copied file referenced by a second bank survives; empty folder / empty book edge
|
||||
cases.
|
||||
- [ ] Prune-reconcile pure function: `(present, referenced, owned) → orphans`,
|
||||
computing `(owned ∩ present) − referenced`; referenced unioned across the whole
|
||||
book (copies keep a file alive).
|
||||
- [ ] 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.
|
||||
|
||||
## 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, per fork R-D, the owned-file set) 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).
|
||||
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.
|
||||
|
||||
- [ ] Prune shell: enumerate the resolved current bank folder; feed the pure core.
|
||||
- [ ] Session supplies the referenced-set (union across the book); resolve the bank
|
||||
folder via the M4 project-relative machinery.
|
||||
- [ ] 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.
|
||||
- [ ] Dry-run manifest: orphan count + reclaimed size (+ files for a small set);
|
||||
**no deletion in this wave.**
|
||||
|
||||
## R3 — deletion + action (the destructive step, guarded)
|
||||
**Goal:** The confirmed deletion step and the bindable "Prune bank folder" action:
|
||||
dry-run-first, confirm-with-manifest, then reclaim the orphan set — via OS trash if
|
||||
portably available (fork R-C), else unlink. CONTEXT.md §Prune (guardrails, API).
|
||||
**Verify (in DAW):** "Prune bank folder" 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; non-bank and
|
||||
capture invariants untouched.
|
||||
**Depends on:** R2. **Forks R-C / R-D / R-E must be settled before this wave.**
|
||||
**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.
|
||||
|
||||
- [ ] "Prune bank folder" action (`command_id`/`gaccel`/`hookcommand`),
|
||||
dry-run-first, confirm-to-delete.
|
||||
- [ ] Deletion mechanism (fork R-C): OS trash if a portable move-to-trash is
|
||||
verified available, else unlink with the dry-run/confirm guardrail. **Verify the
|
||||
platform move-to-trash surface before use.**
|
||||
- [ ] Orphan attribution (fork R-D): reclaim only the bank system's own leavings,
|
||||
not hand-dropped folder files (owned-file manifest per the lean — see below).
|
||||
- [ ] Trigger (fork R-E): manual-primary; optional "…and prune now" offered at the
|
||||
delete-bank confirmation; **no** background sweep.
|
||||
- [ ] `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.
|
||||
- [ ] 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. **Verify the platform move-to-trash surface before use
|
||||
(per platform).**
|
||||
- [ ] 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.)
|
||||
|
||||
## Phase R open questions (unsettled — need Daniel)
|
||||
- **Fork R-C — deletion mechanism (OS trash vs. unlink).** Lean: trash if portably
|
||||
available (recoverable), else unlink with strong dry-run/confirm. Needs Daniel +
|
||||
a platform to-verify (SWELL / per-platform trash APIs).
|
||||
- **Fork R-D — orphan attribution (owned-file manifest vs. index-diff vs.
|
||||
folder-sweep).** Lean: **owned-file manifest**. **Design-the-seam call:** the
|
||||
manifest is cheap to maintain from capture onward but a backfill cliff to
|
||||
reconstruct later — so **start tracking owned files as part of capture / Phase B
|
||||
now, even though prune ships in Phase R.** Folder-sweep rejected as unsafe (deletes
|
||||
hand-dropped files). Needs Daniel (touches the persisted shape + ideally lands
|
||||
earlier than R3).
|
||||
- **Fork R-E — trigger (manual-only vs. offer-on-orphaning vs. periodic).** Lean:
|
||||
manual-primary + optional delete-time "prune now"; no background sweep. Needs Daniel.
|
||||
## 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 (SWELL / Win
|
||||
`SHFileOperation`·`IFileOperation` / macOS `trashItemAtURL:` / Linux XDG) is a
|
||||
**must-verify before use**. 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) is a small build-time residual.
|
||||
- **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