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:
+93
-63
@@ -771,13 +771,12 @@ model capability.
|
||||
container. Individual samples **can** be removed from the pool — otherwise the
|
||||
pool would be a one-way trap. Remove-from-pool is the pool's own "drop this
|
||||
sample" verb and is allowed.
|
||||
- **Remove scope (fork R-A, OPEN — needs Daniel).** Whether "remove" drops the
|
||||
entry from *this* bank only (leaving copies elsewhere), purges the sample from
|
||||
*every* bank, or offers both. Spec-of-record until settled: **remove-from-this-
|
||||
bank** is the core verb (it is the model primitive and composes into
|
||||
from-everywhere); design the action to carry a `scope: this-bank | all-banks`
|
||||
parameter so from-everywhere is a later flag, not a rewrite. See product notes
|
||||
§Fork R-A.
|
||||
- **Remove scope (fork R-A, SETTLED 2026-07-24 — this-bank).** Remove drops the
|
||||
entry from *this* bank only, leaving copies in other banks untouched — the core
|
||||
and only shipped verb. The action carries a `scope: this-bank | all-banks` seam,
|
||||
but **this-bank is the settled default and the only surfaced affordance**;
|
||||
all-banks stays a latent parameter (promotable later behind the seam without a
|
||||
rewrite), never a surfaced verb now. See product notes §Fork R-A.
|
||||
|
||||
## Precision / invariant implications
|
||||
|
||||
@@ -796,12 +795,18 @@ model capability.
|
||||
remove of a sample still referenced by another bank is cheap and re-derivable
|
||||
(re-copy it back) and needs no confirmation. The confirmation is *earned by
|
||||
actual orphan risk*, not fired on every remove.
|
||||
- **Undo (fork R-B, OPEN — shared across all of Phase B).** REAPER's undo stack
|
||||
does not cover `"reasampler"` ext-state mutations, so remove — like
|
||||
move/copy/evacuate/delete-bank — is not on REAPER's Ctrl-Z as specced. The undo
|
||||
model is a Phase-B-wide decision, not a remove-local one; see product notes
|
||||
§Fork R-B. Surfaced here because remove is the first verb whose *only* effect is
|
||||
index-entry destruction with no relocation, so it is where the gap first bites.
|
||||
- **Undo (fork R-B, SETTLED 2026-07-24 — batched REAPER undo points, Phase-B-wide).**
|
||||
Bank/index mutations integrate into REAPER's undo system as **batched undo points**
|
||||
(`Undo_BeginBlock` / `Undo_EndBlock`): the related index mutations of one bank
|
||||
operation are batched into a single undo point, so one bank operation is one
|
||||
Ctrl-Z. This is a **Phase-B-wide** decision — it applies to
|
||||
create/rename/reorder/delete-bank, move, copy, evacuate, *and* remove, retro-
|
||||
touching B1–B4, not just B5. **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. Surfaced with remove because remove is the first verb whose *only* effect is
|
||||
index-entry destruction with no relocation, so it is where the gap first bit; the
|
||||
fix is shared. See product notes §Fork R-B.
|
||||
|
||||
## Module architecture (preserve the pure/shell split)
|
||||
|
||||
@@ -821,13 +826,14 @@ No new REAPER API. Pure model + a new action command-id string under the sampler
|
||||
family prefix + a panel affordance on the existing M5 LICE surface. Verify the
|
||||
command-id/gaccel/hookcommand usage against `main.cpp` (unchanged contract).
|
||||
|
||||
## Open questions
|
||||
## Settled forks (Daniel, 2026-07-24)
|
||||
|
||||
- **Fork R-A — remove scope (this-bank | all-banks | both).** Open; needs Daniel.
|
||||
Spec-of-record: this-bank primary with a scope-parameter seam. Product notes
|
||||
§Fork R-A.
|
||||
- **Fork R-B — undo model for index mutations.** Open; a Phase-B-wide decision
|
||||
surfaced by remove. Product notes §Fork R-B.
|
||||
- **Fork R-A — remove scope.** Settled: **this-bank** (this-bank-primary, all-banks
|
||||
a latent seam-only parameter). Folded into Settled decisions above.
|
||||
- **Fork R-B — undo model for index mutations.** Settled: **batched REAPER undo
|
||||
points** (`Undo_BeginBlock`/`Undo_EndBlock`), Phase-B-wide (retro-touches B1–B4),
|
||||
with the ext-state-participation SDK check as a must-verify-before-build. Folded
|
||||
into Guardrails above and the Phase B / B1 plan points.
|
||||
|
||||
---
|
||||
|
||||
@@ -902,9 +908,19 @@ pure/shell split as `bank_model` / `view_mode_model` / `bank_book`.
|
||||
irreversible file-delete.
|
||||
- **Scope is the bank system's own leavings, not the folder at large.** Prune
|
||||
reclaims files that *were* bank files and are now unreferenced — never a file a
|
||||
user hand-dropped into the folder. How prune attributes ownership is fork R-D
|
||||
(below). Prune is a reclaimer of ReaSampler's own orphans, not a general folder
|
||||
cleaner.
|
||||
user hand-dropped into the folder. Prune is a reclaimer of ReaSampler's own
|
||||
orphans, not a general folder cleaner.
|
||||
- **Orphan attribution is an owned-file manifest (fork R-D, SETTLED 2026-07-24).**
|
||||
The book tracks the set of files it has created (an **owned-file manifest**);
|
||||
prune reclaims `(owned ∩ on-disk) − referenced`. This is the honest encoding of
|
||||
"reclaim only our own leavings" and rejects folder-sweep (which would delete
|
||||
hand-dropped files). **The seam lands early:** because the manifest is cheap to
|
||||
maintain from capture onward but a backfill cliff to reconstruct later, **capture
|
||||
writes each file it creates into the owned-file manifest starting in Phase B**,
|
||||
even though prune consumes it only in Phase R. R1/R2 consume the manifest; they do
|
||||
not build it. The manifest is persisted in the `"reasampler"` ext-state; the exact
|
||||
persistence shape (a sibling key vs. folded into the `banks` blob) is a small
|
||||
build-time residual, but the manifest-now decision is firm.
|
||||
|
||||
## Precision / invariant implications
|
||||
|
||||
@@ -928,35 +944,41 @@ pure/shell split as `bank_model` / `view_mode_model` / `bank_book`.
|
||||
- **Never a referenced file; never a non-bank file.** The union-across-all-banks
|
||||
rule protects referenced files; the ownership-attribution rule (fork R-D)
|
||||
protects hand-dropped files.
|
||||
- **Safest platform deletion available (fork R-C, OPEN — needs Daniel + verify).**
|
||||
Route deletions to the platform recycle bin / trash if a portable move-to-trash
|
||||
is available (recoverable outside the app); fall back to unlink with the dry-run +
|
||||
confirm guardrail if not. Default to the safest deletion the platform affords.
|
||||
- **Manual, explicit trigger (fork R-E, OPEN).** Prune is a deliberate action the
|
||||
user invokes, dry-run-first — never a silent background sweep. An optional "…and
|
||||
prune now" convenience may be offered at the delete-bank confirmation; a periodic
|
||||
background sweep is rejected (silent irreversible file-deletion violates the
|
||||
- **Safest platform deletion available (fork R-C, SETTLED 2026-07-24 — trash-
|
||||
preferred, unlink fallback).** Route deletions to the platform recycle bin / trash
|
||||
wherever a portable move-to-trash is available (recoverable outside the app); fall
|
||||
back to unlink — behind the dry-run + confirm guardrail — only where the platform
|
||||
affords no portable trash. "Delete where possible" means recoverable-trash-
|
||||
preferred, never plain unlink-by-default. The move-to-trash surface is an explicit
|
||||
per-platform **to-verify** (see REAPER/platform API surface).
|
||||
- **Manual, explicit trigger (fork R-E, SETTLED 2026-07-24 — manual action + panel
|
||||
button).** Prune runs via a bindable manual action (dry-run-first, confirm-to-
|
||||
delete) **and** a `bank_panel` button that fires that same action — never a silent
|
||||
background sweep. The earlier optional "…and prune now at the delete-bank
|
||||
confirmation" convenience was **not** selected and is out of scope; a periodic
|
||||
background sweep remains rejected (silent irreversible file-deletion violates the
|
||||
guardrails).
|
||||
|
||||
## Module architecture (preserve the pure/shell split)
|
||||
|
||||
Pure (no REAPER types, unit-tested — the mirror of `reconcile`):
|
||||
- **Prune-reconcile core** — given `{ files present in the bank folder }` and
|
||||
`{ files referenced by the book }` (and, per fork R-D, `{ files the book owns }`),
|
||||
compute the orphan set. REAPER-free, filesystem-free, unit-tested hard (the prune
|
||||
null test lives here). The referenced-set is unioned across all banks by asking
|
||||
the `bank_book`.
|
||||
- **Prune-reconcile core** — given `{ files present in the bank folder }`,
|
||||
`{ files referenced by the book }`, and `{ files the book owns }` (the owned-file
|
||||
manifest, R-D), compute the orphan set `(owned ∩ present) − referenced`.
|
||||
REAPER-free, filesystem-free, unit-tested hard (the prune null test lives here).
|
||||
The referenced-set is unioned across all banks by asking the `bank_book`.
|
||||
|
||||
REAPER-facing / filesystem-facing (thin):
|
||||
- `persist` / session — supplies the referenced-set (union across the book) and,
|
||||
per fork R-D, the owned-file manifest; resolves the current project bank folder
|
||||
via the M4 project-relative machinery.
|
||||
- `persist` / session — supplies the referenced-set (union across the book) and the
|
||||
owned-file manifest (R-D, written from capture onward in Phase B); resolves the
|
||||
current project bank folder via the M4 project-relative machinery.
|
||||
- A **prune shell** — enumerates the bank folder (filesystem I/O), feeds the
|
||||
pure core, presents the dry-run manifest, and on confirmation deletes the orphan
|
||||
set (via trash if available — fork R-C — else unlink). Filesystem I/O only; the
|
||||
decision stays in the pure core.
|
||||
- `actions` (entry) — "Prune bank folder" (dry-run-first, confirm-to-delete);
|
||||
registered with the `command_id`/`gaccel`/`hookcommand` contract.
|
||||
set (via OS trash where portably available — fork R-C — else unlink). Filesystem
|
||||
I/O only; the decision stays in the pure core.
|
||||
- `actions` (entry) — "Prune bank folder" (dry-run-first, confirm-to-delete),
|
||||
registered with the `command_id`/`gaccel`/`hookcommand` contract; **plus a
|
||||
`bank_panel` button** (R-E) that fires the same action.
|
||||
|
||||
## REAPER / platform API surface (verify all signatures)
|
||||
|
||||
@@ -965,13 +987,15 @@ No new REAPER *audio* API. New surfaces to verify before use:
|
||||
project bank folder. **Verify** the portable approach against SWELL / the existing
|
||||
file-handling in `persist` / `capture` (which already resolve and write files);
|
||||
prefer reusing whatever path/file machinery M4 established.
|
||||
- **Move-to-trash (fork R-C)** — if adopted, verify a portable move-to-trash
|
||||
exists (SWELL, or per-platform: Win `IFileOperation`/`SHFileOperation`, macOS
|
||||
`NSFileManager trashItemAtURL:`, Linux XDG trash spec). This is a **to-verify**,
|
||||
not an assumed capability.
|
||||
- **Persistence (fork R-D, if owned-file manifest adopted)** — a new tracked set in
|
||||
the `"reasampler"` ext-state (or folded into the `banks` blob); shared M4 blob
|
||||
machinery, new data only.
|
||||
- **Move-to-trash (fork R-C, settled trash-preferred)** — verify a portable
|
||||
move-to-trash exists (SWELL, or per-platform: Win `IFileOperation`/
|
||||
`SHFileOperation`, macOS `NSFileManager trashItemAtURL:`, Linux XDG trash spec).
|
||||
This is a **must-verify per platform** before use, not an assumed capability;
|
||||
where it is unavailable, fall back to unlink behind the dry-run/confirm guardrail.
|
||||
- **Owned-file manifest persistence (fork R-D, settled)** — a new tracked set in
|
||||
the `"reasampler"` ext-state (a sibling key or folded into the `banks` blob —
|
||||
build-time residual); shared M4 blob machinery, new data only. **Written from
|
||||
capture onward in Phase B** (the seam lands early), consumed by prune in Phase R.
|
||||
- **Actions** — the `command_id`/`gaccel`/`hookcommand` contract from `main.cpp`
|
||||
(unchanged), a new command-id string under the sampler family prefix.
|
||||
|
||||
@@ -990,18 +1014,24 @@ No new REAPER *audio* API. New surfaces to verify before use:
|
||||
- **Additive only.** Prune reads the book and the folder; it does not modify
|
||||
`BankIndex`, `bank_book`, the capture roadmap, or Design View semantics.
|
||||
|
||||
## Open questions to resolve during build
|
||||
## Settled forks (Daniel, 2026-07-24)
|
||||
|
||||
- **Fork R-C — deletion mechanism: OS trash vs. unlink.** Open; needs Daniel + a
|
||||
platform to-verify. Lean: trash if portably available, else unlink with strong
|
||||
dry-run/confirm. Product notes §Fork R-C.
|
||||
- **Fork R-D — orphan attribution: owned-file manifest vs. index-diff vs.
|
||||
folder-sweep.** Open; needs Daniel. Lean: **owned-file manifest**, and — because
|
||||
the manifest is cheap to maintain from capture onward but a backfill cliff to
|
||||
reconstruct later — **start tracking owned files as part of capture / Phase B
|
||||
even though prune ships in Phase R** (defer the feature, design the seam).
|
||||
Folder-sweep is rejected as unsafe (deletes hand-dropped files). Product notes
|
||||
§Fork R-D.
|
||||
- **Fork R-E — trigger: manual-only vs. offer-on-orphaning vs. periodic.** Open.
|
||||
Lean: manual-primary (dry-run-first), an optional "…and prune now" at the
|
||||
delete-bank confirmation, no background sweep. Product notes §Fork R-E.
|
||||
- **Fork R-C — deletion mechanism.** Settled: **trash-preferred, unlink fallback.**
|
||||
Route to the OS trash where a portable move-to-trash is available (recoverable),
|
||||
else unlink behind the dry-run/confirm guardrail. Per-platform trash surface is a
|
||||
must-verify. Folded into Settled decisions + Guardrails + API surface above.
|
||||
Product notes §Fork R-C.
|
||||
- **Fork R-D — orphan attribution.** Settled: **owned-file manifest**, `(owned ∩
|
||||
present) − referenced`; folder-sweep rejected as unsafe. The **seam lands early** —
|
||||
capture writes each created file to the manifest starting in Phase B, prune
|
||||
consumes it in Phase R. Persistence shape (sibling key vs. `banks` blob) is a
|
||||
build-time residual. Folded into Settled decisions + Module architecture + API
|
||||
surface above, and added as an up-front Phase B / capture plan point. Product
|
||||
notes §Fork R-D.
|
||||
- **Fork R-E — trigger.** Settled: **manual action + `bank_panel` button**, dry-run-
|
||||
first, confirm-to-delete; no background sweep. The delete-time "…and prune now"
|
||||
convenience was not selected (out of scope). Folded into Guardrails + Module
|
||||
architecture above and the R3 plan points. Product notes §Fork R-E.
|
||||
|
||||
**Build-time residual (not a fork):** the owned-file manifest's exact persistence
|
||||
shape (sibling `"reasampler"` ext-state key vs. folded into the `banks` blob).
|
||||
|
||||
Reference in New Issue
Block a user