docs: 1.0 documentation restructure
Split root CLAUDE.md into 19 per-directory files scoped to their source area. Roll v0 history into docs/ARCHIVE.md; retire CONTEXT.md, CONTEXT-ARCHIVE.md, PLAN.md, COMPLETED.md. Move plan docs under docs/. Rescue 9 live deferrals into docs/TODO.md.
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
# src/core/model — the pure bank/sample index and its multi-bank container
|
||||
|
||||
## Scope
|
||||
|
||||
Pure (REAPER-free, unit-tested outside the DAW) sample-index models: the single-bank
|
||||
index, the multi-bank registry that wraps it, its JSON codec, the gap-preserving
|
||||
per-bank slot carrier, the owned-file manifest, and the capture-recipe fingerprint.
|
||||
No REAPER types, no filesystem I/O — see root `CLAUDE.md` for the pure-core/shell
|
||||
split this directory sits on.
|
||||
|
||||
## Invariants
|
||||
|
||||
**Pool privileges (multi-bank).**
|
||||
- The pool is privileged, not special-cased: structurally one `BankIndex` among many
|
||||
in `bank_book`; semantically it always exists, is un-deletable, and un-renamable
|
||||
(fixed id + fixed display name "Pool"). New projects and migrated single-bank
|
||||
projects start with the pool and zero named banks. Enforced in the pure rules
|
||||
layer, not just the UI.
|
||||
- No action path may delete or rename the pool, leave a project with zero banks, or
|
||||
evacuate the pool (the pool is evacuation's destination, not a source).
|
||||
|
||||
**Bank identity, movement, dedup.**
|
||||
- Bank id is the stable key (GUID-style, minted on create); display name and ordinal
|
||||
are mutable. Display names are unique — trimmed + case-insensitive (ASCII) —
|
||||
enforced by `createBank`/`renameBank`; the pool's reserved name "Pool" is protected
|
||||
by the same check.
|
||||
- Movement moves the index entry, not the file: move/copy between banks is
|
||||
index-only (remove from A's `BankIndex`, add to B's); the underlying file stays in
|
||||
the shared project bank folder. Per-bank subfolders on disk are an explicit
|
||||
non-goal.
|
||||
- Dedup-by-hash is per-bank. Moving a sample whose hash already exists in the
|
||||
destination bank collapses onto the existing entry there. Cross-bank dedup is not
|
||||
enforced — the same hash may exist in the pool and a named bank simultaneously.
|
||||
- Move is the default (removes from source, adds to destination); copy is the
|
||||
deliberate secondary act (adds to destination, leaves source intact).
|
||||
- Delete drops members (files are not deleted); evacuate returns all of a bank's
|
||||
members to the pool (index-only, same destination-collapse rule). Evacuate cannot
|
||||
be applied to the pool. A plain delete of a non-empty bank orphans those members
|
||||
out of every index until prune reclaims their files — the UI confirms on
|
||||
non-empty delete and offers evacuate as the alternative.
|
||||
|
||||
**Sample removal.**
|
||||
- Remove is index-only: drops one `Sample` entry from one `BankIndex`; mutates only
|
||||
index + ext-state, no file written/moved/deleted, no timeline item touched.
|
||||
- Remove can orphan a file — the same designed orphaned-until-prune state a
|
||||
non-empty delete-bank produces — when it drops the last index reference to a
|
||||
file. Reclaimed later by prune, never by remove.
|
||||
- The pool's contents are removable; the pool container is not. Remove-from-pool is
|
||||
allowed.
|
||||
- Remove scope is this-bank only (settled 2026-07-24): drops the entry from this
|
||||
bank, leaving copies in other banks untouched. `scope: this-bank | all-banks` is a
|
||||
latent seam; only this-bank is a surfaced verb.
|
||||
- Removes are silent — no confirm dialog. Recoverability comes from batched REAPER
|
||||
undo (`Undo_BeginBlock`/`Undo_EndBlock`): one Ctrl-Z restores the index entry.
|
||||
This undo-batching is Phase-B-wide (create/rename/reorder/delete-bank, move, copy,
|
||||
evacuate, and remove all batch this way). `hashReferencedElsewhere` is a tested
|
||||
model API retained for Phase R prune; it has no shell caller in the remove path.
|
||||
|
||||
**Precision implications.**
|
||||
- Relative-paths-only survives unchanged: every `BankIndex` in the book keeps the
|
||||
relative-path invariant at its `add` boundary; movement is index-only so files
|
||||
never relocate.
|
||||
- Non-destructive: bank create/rename/delete/activate/evacuate and sample
|
||||
move/copy/remove mutate only index + ext-state; no file is written, moved, or
|
||||
deleted, and no timeline item is touched.
|
||||
|
||||
## Modules
|
||||
|
||||
- `bank_model` — `Sample` metadata struct + `BankIndex` (add/remove/query/tier/dedup-by-hash + JSON round-trip). Test it hard — it is the heart.
|
||||
- `bank_book` — multi-bank registry: an ordered set of banks each wrapping a `BankIndex`. **Pool privileges (un-deletable/un-renamable/un-evacuable, never zero banks) enforced in-model.** Owns create/rename/reorder/delete of named banks, active-bank id, and index-only move/copy/remove of a sample between banks. The JSON round-trip lives in the sibling `bank_book_json` TU (Q-W5 split; serialize/deserialize via a private static `nameKey` seam) — one model, one codec, same public surface.
|
||||
- `slot_map` (`core/model`) — the gap-preserving display-position carrier for ONE bank (sample id → slot, ≥0), extracted from `bank_book` (Q-W1): append/remove/reorder (insert-before-and-shift)/`reconcile` against live membership, `resetDense` migration seed, JSON round-trip. Wrapped (not merged) by `bank_book`.
|
||||
- `owned_manifest` — the set of project-relative files the capture path itself created, persisted under the `"owned_files"` ext-state key, so the prune path can distinguish the bank system's own orphans from hand-dropped files.
|
||||
- `provenance` — capture-recipe fingerprint: build/encode/compare a `rsprov1` fingerprint of scope, range, tail, rate/channels, track GUIDs, and FX-chain identity. **A thin reproducibility fingerprint — NOT a serialized chain to restore.**
|
||||
|
||||
## Gotchas
|
||||
|
||||
- `bank_book` wraps `BankIndex`; it does not modify it (additive — no `bank-id`
|
||||
field on `Sample`). Do not add per-bank subfolders on disk or a global
|
||||
cross-bank dedup — both are rejected-in-review non-goals.
|
||||
- `bank_book_json` is a sibling TU, not a separate module — its round-trip is part
|
||||
of `bank_book`'s public surface, not a distinct thing to describe separately.
|
||||
Reference in New Issue
Block a user