docs(multi-bank): settle Phase B forks 1-4; draft fork-5 options analysis
Fold Daniel's decisions into CONTEXT.md, PLAN.md, and the product notes: - Fork 1 (persistence): pool folds into the `banks` blob; legacy `bank_index` key retired after a one-way lossless migration. - Fork 2 (delete): delete drops member index entries; add an `evacuate` verb (B1 pure op + B3 action) returning members to the pool. Design the orphaned-until-prune window and confirm-on-non-empty-delete guardrail. - Fork 3 (move): move is the default gesture, copy the deliberate secondary. - Fork 4 (active bank): active-bank and shown-tab stay distinct; the active-bank indicator must be visually unmistakable. Fork 5 (tab rendering + move affordance) remains open with an options analysis and pending recommendations. Additive; M0-M11 and Phase D untouched.
This commit is contained in:
@@ -98,42 +98,53 @@ privileged, create/rename/reorder/delete named banks, active-bank id, move/copy
|
||||
sample between banks, JSON round-trip + legacy-migration. The heart of the phase;
|
||||
mirror of `bank_model` / `view_mode_model`; **`BankIndex` untouched (additive)**.
|
||||
CONTEXT.md §Multi-bank (Module architecture — pure).
|
||||
**Verify:** CTest green. Pool always present, un-deletable, un-renamable (rules
|
||||
rejected in-model). Active-bank defaults to pool. Move is index-only (source loses
|
||||
entry, destination gains it) and observes destination collapse-by-hash; copy leaves
|
||||
source intact. JSON round-trip lossless across banks + per-bank indices + ordinals +
|
||||
**Verify:** CTest green. Pool always present, un-deletable, un-renamable,
|
||||
un-evacuable (rules rejected in-model). Active-bank defaults to pool. Move is
|
||||
index-only (source loses entry, destination gains it) and observes destination
|
||||
collapse-by-hash; copy leaves source intact. Delete drops member index entries.
|
||||
Evacuate moves all members to the pool, leaving the bank empty. JSON round-trip
|
||||
lossless across pool-as-bank-zero + named banks + per-bank indices + ordinals +
|
||||
active id. Legacy `bank_index` JSON parses into `{ pool }` with zero named banks.
|
||||
|
||||
- [ ] Bank registry: ordered `{ bank id, display name, ordinal, BankIndex }`; pool
|
||||
seeded with fixed id + fixed name; create / rename / reorder / delete named banks.
|
||||
seeded with fixed id + fixed name; create / rename / reorder / delete named banks
|
||||
(delete drops the bank's member index entries).
|
||||
- [ ] Pool-privilege rules enforced in-model: reject delete-pool, reject
|
||||
rename-pool, never allow zero banks.
|
||||
rename-pool, reject evacuate-pool, never allow zero banks.
|
||||
- [ ] Active-bank id (get/set; defaults to pool); resolve active bank's `BankIndex`.
|
||||
- [ ] Move sample between banks (index-only; destination collapse-by-hash observed;
|
||||
source entry removed).
|
||||
- [ ] Copy sample between banks (index-only; source entry retained; destination
|
||||
collapse-by-hash observed).
|
||||
- [ ] JSON round-trip: banks + per-bank indices + ordinals + active id.
|
||||
- [ ] Evacuate bank: move every member to the pool (index-only; destination
|
||||
collapse-by-hash observed), leaving the bank empty; pool cannot be evacuated.
|
||||
- [ ] JSON round-trip: pool-as-bank-zero inside the blob + named banks + per-bank
|
||||
indices + ordinals + active id.
|
||||
- [ ] Legacy migration: a bare `bank_index` JSON promotes to the pool's index with
|
||||
zero named banks (one-way, lossless).
|
||||
- [ ] Tests: pool privileges (delete/rename rejected); move source-loses/dest-gains;
|
||||
copy source-retained; cross-bank same-hash coexistence; dest collapse on move into
|
||||
a bank already holding the hash; JSON lossless; legacy migration.
|
||||
zero named banks (one-way, lossless; blob authoritative thereafter).
|
||||
- [ ] Tests: pool privileges (delete/rename/evacuate rejected); move
|
||||
source-loses/dest-gains; copy source-retained; evacuate empties source into pool
|
||||
with dest collapse; cross-bank same-hash coexistence; dest collapse on move into a
|
||||
bank already holding the hash; JSON lossless; legacy migration.
|
||||
|
||||
## B2 — persist slice (banks ↔ project ext state)
|
||||
**Goal:** Serialize the book under the `banks` key in `"reasampler"` alongside the
|
||||
existing sections; migrate a legacy `bank_index` key into the pool on first load;
|
||||
reload-on-open and Save-As survival via the existing M4 machinery. CONTEXT.md
|
||||
§Multi-bank (persist). **Verify (in DAW):** Banks + named banks + active bank + all
|
||||
per-bank samples survive Save / Save As / close+reopen; **relative paths only**;
|
||||
bank travels with the `.rpp`; a project saved before this phase (legacy `bank_index`
|
||||
only) loads as pool + zero named banks with no sample loss.
|
||||
**Depends on:** B1. Resolve the `bank_index` retirement-vs-retention fork first
|
||||
(see Phase B open questions).
|
||||
existing sections, with the pool folded in as bank-zero; migrate a legacy
|
||||
`bank_index` key into the pool on first load and retire the legacy key; reload-on-open
|
||||
and Save-As survival via the existing M4 machinery. CONTEXT.md §Multi-bank (persist).
|
||||
**Verify (in DAW):** Banks + named banks + active bank + all per-bank samples survive
|
||||
Save / Save As / close+reopen; **relative paths only**; bank travels with the `.rpp`;
|
||||
a project saved before this phase (legacy `bank_index` only) loads as pool + zero
|
||||
named banks with no sample loss, and after save carries `banks` with no `bank_index`
|
||||
written.
|
||||
**Depends on:** B1. (Persistence-key fork settled — fork 1 (a): pool inside the
|
||||
`banks` blob, legacy key retired after one-way migration.)
|
||||
|
||||
- [ ] Serialize/deserialize the book under the `banks` key (shared blob, distinct
|
||||
section from `bank_index` / `view_state`).
|
||||
- [ ] Legacy-migration path on load: absent `banks` + present `bank_index` → pool.
|
||||
- [ ] Serialize/deserialize the book under the `banks` key (pool-as-bank-zero inside
|
||||
the blob; distinct section from `view_state`; no `bank_index` key written going
|
||||
forward).
|
||||
- [ ] Legacy-migration path on load: absent `banks` + present `bank_index` → promote
|
||||
into pool, mint the blob, treat blob as authoritative (legacy key retired).
|
||||
- [ ] Session exposes the book; the active bank's `BankIndex` is the capture add
|
||||
target (route the M7 capture family through it — additive to M7, no M7 rewrite).
|
||||
- [ ] Confirm survival across Save / Save As; confirm legacy-project load path.
|
||||
@@ -141,44 +152,54 @@ only) loads as pool + zero named banks with no sample loss.
|
||||
## B3 — actions
|
||||
**Goal:** Bindable action set for the multi-bank workflow. CONTEXT.md §Multi-bank
|
||||
(actions). **Verify (in DAW):** Each action registered (bindable in Actions list);
|
||||
bank-activate + move/copy MIDI-bindable; create/rename/delete drive the B1 model via
|
||||
the B2-persisted session.
|
||||
bank-activate + move/copy + evacuate MIDI-bindable; create/rename/delete/evacuate
|
||||
drive the B1 model via the B2-persisted session.
|
||||
**Depends on:** B1, B2.
|
||||
|
||||
- [ ] Create bank / rename bank / delete bank (delete honors the resolved
|
||||
member-disposition rule — see open questions).
|
||||
- [ ] Create bank / rename bank / delete bank (delete drops member index entries;
|
||||
confirm-on-non-empty offered at the UI layer in B4).
|
||||
- [ ] Evacuate bank → pool (move all members back to the pool; refuses on the pool).
|
||||
- [ ] Activate bank (direct-by-id + cycle).
|
||||
- [ ] Move selected samples → bank / copy selected samples → bank.
|
||||
- [ ] Move selected samples → bank / copy selected samples → bank (move is default).
|
||||
- [ ] Pool full-height / banks full-height toggles.
|
||||
- [ ] Register each (`command_id`/`gaccel`/`hookcommand`); bank-activate + move/copy
|
||||
MIDI-bindable.
|
||||
+ evacuate MIDI-bindable.
|
||||
|
||||
## B4 — bank_panel vertical split (UI)
|
||||
**Goal:** The vertical-split bank window — pool on top, named-banks tab-page region
|
||||
below, full-height toggles — extending the M5 docked grid. CONTEXT.md §Multi-bank
|
||||
(bank_panel). **Verify (in DAW):** Pool grid renders on top; named-banks tab strip
|
||||
below (empty when no named banks, one tab per named bank); active-bank indicated;
|
||||
both full-height toggles collapse the split correctly; sample move/copy affordance
|
||||
works (drag and/or menu); the Design View mode switch in the header is unaffected.
|
||||
**Depends on:** B1, B2, B3.
|
||||
below (empty when no named banks, one tab per named bank); active-bank **unmistakably**
|
||||
indicated; both full-height toggles collapse the split correctly; sample move/copy
|
||||
affordance works; non-empty delete confirms and offers evacuate; the Design View mode
|
||||
switch in the header is unaffected.
|
||||
**Depends on:** B1, B2, B3. (Tab rendering + move-affordance mechanics — fork 5 —
|
||||
pending Daniel's decision; see Phase B open questions and product notes → *Fork 5*.)
|
||||
|
||||
- [ ] Vertical split: pool grid region (top) + named-banks tab-page region (bottom).
|
||||
- [ ] Named-banks tab strip: one tab per named bank; empty state when none.
|
||||
(SWELL-native vs. LICE-drawn — fork 5a, pending.)
|
||||
- [ ] Pool full-height / banks full-height toggle affordances wired to B3.
|
||||
- [ ] Active-bank indicator.
|
||||
- [ ] Create / rename / delete / activate affordances driving B3 actions.
|
||||
- [ ] Sample move/copy affordance (drag between regions and/or "send to bank" menu).
|
||||
- [ ] Active-bank indicator — **visually unmistakable** (settled constraint);
|
||||
placement (per-region header / single readout / lit-tab) is the residual polish
|
||||
detail.
|
||||
- [ ] Create / rename / delete / activate / evacuate affordances driving B3 actions.
|
||||
- [ ] Delete confirms on a non-empty bank, naming the evacuate alternative.
|
||||
- [ ] Sample move/copy affordance (drag between regions and/or "send to bank" menu —
|
||||
fork 5b, pending).
|
||||
|
||||
## Phase B open questions
|
||||
- **`bank_index` key retirement vs. retention** — (a) fold the pool into the `banks`
|
||||
blob and retire the legacy key, vs (b) keep `bank_index` as the pool's canonical
|
||||
slot and store only named banks under `banks`. Leaning (b) for additive-minimalism
|
||||
against in-flight M7/M8 persist work. Resolve before B2. (blocks B2)
|
||||
- **Named-bank delete → member disposition** — (i) reabsorb into pool, (ii)
|
||||
orphan-check by file reference, (iii) forbid non-empty delete. Leaning (i).
|
||||
(touches B1/B3)
|
||||
- **Move affordance + tab rendering** — drag vs. menu as primary; SWELL-native vs.
|
||||
LICE-drawn tabs. Verify SWELL tab-control availability against the M5 reference.
|
||||
Forks 1–4 settled by Daniel (2026-07-23): persistence key = fold pool into `banks`,
|
||||
retire legacy key (1a); delete drops members + add evacuate verb (2); move is the
|
||||
default gesture (3); active-bank/shown-tab distinct with an unmistakable indicator
|
||||
(4). Folded into CONTEXT.md §Multi-bank + the B1–B4 points above. Remaining:
|
||||
|
||||
- **Fork 5 — tab rendering + move affordance** — (5a) SWELL-native tab control vs.
|
||||
LICE-drawn tabs matching the grid aesthetic; (5b) drag-between-regions vs.
|
||||
"send to bank" menu vs. both. Options analysis + pending recommendations in product
|
||||
notes → *Fork 5*. Verify SWELL tab-control availability + cross-platform parity
|
||||
against the SWELL headers / SWS reference before choosing native tabs. Decision
|
||||
pending Daniel. (touches B4)
|
||||
- **Active-bank indicator placement** — per-region headers vs. single header readout
|
||||
vs. lit-tab. "Unmistakable" is settled; only placement is open. Polish detail.
|
||||
(touches B4)
|
||||
- **Active-bank indicator placement** — per-region headers vs. single header
|
||||
readout. (touches B4)
|
||||
|
||||
Reference in New Issue
Block a user