docs(phase-q): fold Q-W0 sign-off into PLAN/CONTEXT — all 59 dispositions settled; Q-W2v wave, T4-18 VST placement, ~600 ceiling + structural heuristics, W3 riders (wav_codec, ICaptureBackend, Q-9)

This commit is contained in:
2026-07-28 18:44:48 -04:00
parent a4571cc074
commit 78a214b247
2 changed files with 431 additions and 105 deletions
+183 -40
View File
@@ -2301,7 +2301,10 @@ shell maps that pure result to a cursor. No cue logic in the shell; the shell on
> findings report — a functional-correctness/algorithm-quality complement to the SOLID/naming audit > findings report — a functional-correctness/algorithm-quality complement to the SOLID/naming audit
> below. **Q-W1 is gated on Q-W0's triage being complete and Daniel signing off on each finding's > below. **Q-W1 is gated on Q-W0's triage being complete and Daniel signing off on each finding's
> disposition** (fix-now vs. document-and-defer). Spec: §"The pre-restructure audit wave (Q-W0)" > disposition** (fix-now vs. document-and-defer). Spec: §"The pre-restructure audit wave (Q-W0)"
> below. > below. **STATUS (2026-07-28): Q-W0 COMPLETE and SIGNED OFF — all 59 dispositions approved; the
> Q-W1 sub-gate is satisfied once the six approved fix-now remediations land (in flight on
> `pq-w0-fixes`). The audit's plan reshape is folded into this spec: Q-W2 6→8 seams, NEW wave
> Q-W2v (parallel with Q-W2), Q-W3 3→4 hoists + riders, Q-W5 + the ext-state-loop dedupe.**
## What it is ## What it is
@@ -2330,6 +2333,21 @@ reinvented wheel or a numerically-fragile DSP path should be eliminated or consc
tree. Bringing the code "into the realm of something I can stand to look at" is not only a matter of tree. Bringing the code "into the realm of something I can stand to look at" is not only a matter of
shape; it is also a matter of the code being *functionally sound*. shape; it is also a matter of the code being *functionally sound*.
**STATUS (2026-07-28): Q-W0 is COMPLETE — audit run, triage done, sign-off given.** Four parallel
tracks (T1 DSP, T2 architecture, T3 env-coupled constants, T4 sizing + placement), **59
findings**; report: `docs/product/code-quality-audit.md`, appendices:
`docs/product/audit-notes/q-w0-t{1..4}-*.md`. Daniel approved **every disposition as proposed** on
2026-07-28. Six findings are fix-now *in Q-W0***T1-01** (linked-lag stereo splice alignment),
**T1-03** (Preserve prime bound + immediate `freezeTail()`), **T1-09** (`declickR_` dead-state
removal, riding the `sampler_core` edits), **T2-01(a)** (provenance wire-cursor hardening
backport), **T3-01** (gain-ramp seconds), **T3-03** (fade-ceiling seconds) — in flight on branch
`pq-w0-fixes`; **the Q-W1 sub-gate is satisfied once they land** (each with its module's CTest
target green; the audible DSP fixes with a stated before/after listening check). All other
fix-nows are assigned to the wave that already opens their file and are recorded in the wave specs
below. **The Q-11 question is answered:** the correlation-aligned SOLA pitch engine is **sound —
no technique replacement (phase-vocoder / WSOLA) warranted**; every pitch finding is a bounded
in-technique fix or a documented operating limit.
**Audit scope — the named surfaces:** **Audit scope — the named surfaces:**
1. **DSP / audio, close eye on pitch.** Assess *algorithm quality* — correctness, artifacts, 1. **DSP / audio, close eye on pitch.** Assess *algorithm quality* — correctness, artifacts,
@@ -2395,10 +2413,11 @@ the subsystem map off the folders. ReaSampler adopts the *pattern* (directory =
adapted to its own most load-bearing invariant — the pure/shell split — as the top level (see adapted to its own most load-bearing invariant — the pure/shell split — as the top level (see
below). Vital is GPLv3; the borrowed artifact is the **structural pattern**, not code. below). Vital is GPLv3; the borrowed artifact is the **structural pattern**, not code.
## Settled decisions (Q-1 settled; Q-2..Q-6 recommended — see `docs/product/code-organization.md` §6) ## Settled decisions (Q-1/Q-10/Q-11 settled 2026-07-27; Q-5/Q-6/Q-8/Q-9 + the audit's §4 forks settled 2026-07-28 — REC history kept; see `docs/product/code-organization.md` §6 and `docs/product/code-quality-audit.md` §4)
- **Q-1 — namespace letter. SETTLED: `Q` (Quality).** Point-id family `Q1..Qn`, wave prefixes - **Q-1 — namespace letter. SETTLED: `Q` (Quality).** Point-id family `Q1..Qn`, wave prefixes
`Q-W0` (the pre-restructure audit) then `Q-W1..Q-W6` (the structural reorg). `O` (Organization) `Q-W0` (the pre-restructure audit) then `Q-W1..Q-W6` (the structural reorg; + **`Q-W2v`**, the
VST god-module wave added at the Q-W0 sign-off, 2026-07-28). `O` (Organization)
was set aside: the glyph reads ambiguously against zero in was set aside: the glyph reads ambiguously against zero in
point ids, and "Organization" undersells a phase measured against a *quality* bar. point ids, and "Organization" undersells a phase measured against a *quality* bar.
- **Q-2 — JSON extraction in scope + first. REC: yes.** The 4× duplicated `Parser` is the largest - **Q-2 — JSON extraction in scope + first. REC: yes.** The 4× duplicated `Parser` is the largest
@@ -2413,17 +2432,43 @@ below). Vital is GPLv3; the borrowed artifact is the **structural pattern**, not
`audio`/`ui`/`reclaim`/`version`/`json`. Directory and namespace agree; a symbol's home is `audio`/`ui`/`reclaim`/`version`/`json`. Directory and namespace agree; a symbol's home is
unambiguous from either. unambiguous from either.
- **Q-5 — god-module split granularity. REC: to the audit's named seams, no finer.** Well-factored, - **Q-5 — god-module split granularity. REC: to the audit's named seams, no finer.** Well-factored,
not atomized. not atomized. **SETTLED (Daniel, 2026-07-28): seams-by-responsibility with the Q-W0 T4 seam
- **Q-6 — OCP registration-table. REC: in scope, last (most droppable if narrowing).** lists adopted** — `bank_panel` 6→8 seams (+ `panel_layout`, `panel_drag`; T4-01),
`capture_orchestrator` further split with `capture_batch` (T4-02) — **and the ~600-line file
ceiling is an acceptance criterion on every split wave**: seams are the method, the ceiling is
the bar; arbitrary bisection to hit the number is rejected. One documented exception:
`sampler_core.cpp` stays whole (T4-14/T4-27).
- **Q-6 — OCP registration-table. REC: in scope, last (most droppable if narrowing).** **SETTLED
(Daniel, 2026-07-28): in scope, last wave, as planned.**
- **Q-7 — naming rides the relocation waves, no dedicated naming wave. REC: yes** (forced once - **Q-7 — naming rides the relocation waves, no dedicated naming wave. REC: yes** (forced once
Q-3/Q-4 settle — a rename is near-free during relocation, near-pure-churn standalone). Q-3/Q-4 settle — a rename is near-free during relocation, near-pure-churn standalone).
- **Q-8 — class/module renames beyond the free namespace fix. REC: fix the two that actively - **Q-8 — class/module renames beyond the free namespace fix. REC: fix the two that actively
mislead** — `BankIndex``BankModel` (the `bank_model.h`/`BankIndex` file↔class word-mismatch) mislead** — `BankIndex``BankModel` (the `bank_model.h`/`BankIndex` file↔class word-mismatch)
and the unified JSON parser → `json::Reader`/`json::Writer` (or `json::Parser`) — **leave the and the unified JSON parser → `json::Reader`/`json::Writer` (or `json::Parser`) — **leave the
merely-quirky** (`Book`/`Bank`/`Index`, `Sample`/`AudioSample`, `MinMax`, `KitBox`). Daniel's merely-quirky** (`Book`/`Bank`/`Index`, `Sample`/`AudioSample`, `MinMax`, `KitBox`). Daniel's
to call. to call. **SETTLED (Daniel, 2026-07-28): both renames**`BankIndex``BankModel` (W1) and the
JSON parser minted as `json::Reader`/`json::Writer` (W1). From the audit, additionally:
**`ICaptureBackend` is deleted in Q-W3** (T4-26 — one deriver, zero polymorphic call sites; the
CLAUDE.md/CONTEXT "two backends behind one interface" correction **rides Q-W3's own commit**,
not earlier).
- **Q-9 — align the `capture_realtime` (shell) / `realtime_record` (pure) word-order inversion. - **Q-9 — align the `capture_realtime` (shell) / `realtime_record` (pure) word-order inversion.
REC: yes, during Q-W3** (a free rider — W3 already hoists the realtime lifecycle). REC: yes, during Q-W3** (a free rider — W3 already hoists the realtime lifecycle). **SETTLED
(Daniel, 2026-07-28): yes** — the pure module takes the stem `capture_realtime`, the shell
takes the suffix (the `drag_out``drag_out_win` model), during W3.
- **Audit §4a — VST placement. SETTLED (Daniel, 2026-07-28): T4-18** — `src/vst/` integrates into
the single `core/`/`shell/` top split as `core/instrument/{engine,map,ui}` +
`shell/instrument/`. One rule, no special case: a file's directory says whether it may touch a
*host* type (REAPER **or** VST3 SDK); the artifact boundary is a link-graph fact the sources
already straddle. The T4-19 artifact-first subtree was set aside. Directory map below updated.
- **Audit §4e — WAV/RIFF consolidation moment. SETTLED (Daniel, 2026-07-28): a named rider on
Q-W3** — one pure **`wav_codec`** owner (chunk walker + layout + build + patch), absorbing the
T4-10 ingest extraction (T2-08 / T4-23 / T4-10). The dedup-by-hash / null-test maintenance
surface gets exactly one implementation.
- **Audit §4f — Q-W2v scheduling. SETTLED (Daniel, 2026-07-28): parallel with Q-W2** (different
artifact, zero file overlap); the serial "Q-W7" alternative was set aside.
- **Audit §4b/§4c/§4d — the Q-W0 fix-now set. SETTLED (Daniel, 2026-07-28): all approved
fix-now** — T1-01 + T1-03 (with T1-09 riding), T2-01(a), T3-01 + T3-03; in flight on
`pq-w0-fixes`; landing them closes Q-W0 and opens Q-W1.
## The directory + namespace map (Q-3 / Q-4) ## The directory + namespace map (Q-3 / Q-4)
@@ -2434,24 +2479,42 @@ directories.
- `core/model/` (`::model`) — `bank_model`, `bank_book`, `owned_manifest`, `provenance` - `core/model/` (`::model`) — `bank_model`, `bank_book`, `owned_manifest`, `provenance`
- `core/view/` (`::view`) — `view_mode_model`, `view_tree`, `lane_keys`, `mode_switch` - `core/view/` (`::view`) — `view_mode_model`, `view_tree`, `lane_keys`, `mode_switch`
- `core/capture/` (`::capture`) — `render_settings`, `batch_capture`, `tail_control`, - `core/capture/` (`::capture`) — `render_settings`, `batch_capture`, `tail_control`,
`capture_paths`, `wav_trim`, `insert_plan` `capture_paths`, `wav_trim`, `insert_plan`; **post-Q-W3** `wav_codec` (the one pure WAV/RIFF
owner — audit §4e rider)
- `core/audio/` (`::audio`) — `peaks` - `core/audio/` (`::audio`) — `peaks`
- `core/ui/` (`::ui`) — `theme`, `component_geometry`, `bank_grid`, `tab_strip`, `action_buttons`, - `core/ui/` (`::ui`) — `theme`, `component_geometry`, `bank_grid`, `tab_strip`, `action_buttons`,
`prune_button` `prune_button`
- `core/reclaim/` (`::reclaim`) — `prune_reconcile` - `core/reclaim/` (`::reclaim`) — `prune_reconcile`
- `core/version/` (`::version`) — `app_version` - `core/version/` (`::version`) — `app_version`
- `core/json/` (`::json`) — **NEW** — extracted parser/serializer (replaces the 4 duplicate - `core/json/` (`::json`) — **NEW** — extracted parser/serializer, minted as
`Parser`s) `json::Reader`/`json::Writer` (replaces the 5 duplicate hand-rolled decoders — the four
`Parser`s + `tail_control`'s, T2-02)
- `core/instrument/`**T4-18 SETTLED (Daniel, 2026-07-28)** — the VST artifact's pure side
joins the one top split (directory = "may it touch a host type", REAPER *or* VST3 SDK):
- `core/instrument/engine/``sampler_core`, `pitch_shift`, `velocity_curve`, `master_gain`
- `core/instrument/map/``sample_map` (+ `component_state_io` post-Q-W2v), `bank_sync`,
`bridge_marshal`, `note_entry`, `trigger_seam`
- `core/instrument/ui/``editor_geometry`, `keyboard_strip`, `waveform_view`,
`capture_browser`, `browser_scroll`, `param_slider`, `knob_deck`, `curve_popup`,
`envelope_overlay`, `envelope_edit`, `embed_strip`
**`shell/` (REAPER-facing — subdir by subsystem, namespace as house style prefers):** **`shell/` (REAPER-facing — subdir by subsystem, namespace as house style prefers):**
- `shell/capture/``capture`, `capture_realtime`, `provenance_shell`, `track_guid`, `item_read`; - `shell/capture/``capture`, `capture_realtime`, `provenance_shell`, `track_guid`, `item_read`;
**post-Q-W3** `capture_orchestrator`, `scope_resolve`, `realtime_lifecycle` **post-Q-W3** `capture_orchestrator`, `capture_batch`, `scope_resolve`, `realtime_lifecycle`,
`capture_realtime_finalize` (with the Q-9 stem/suffix rename)
- `shell/panel/``draw_kit`; **post-Q-W2** `panel_render`, `panel_thumbnails`, - `shell/panel/``draw_kit`; **post-Q-W2** `panel_render`, `panel_thumbnails`,
`panel_audition`, `panel_input`, `panel_bank_ops`, `panel_window` (from `bank_panel`) `panel_audition`, `panel_input`, `panel_layout`, `panel_drag`, `panel_bank_ops`,
`panel_window` (from `bank_panel` — eight seams, T4-01)
- `shell/view/``view` - `shell/view/``view`
- `shell/persist/`**post-Q-W5** `session`, `ext_state_io`, `prune_fs` (from `persist`) - `shell/persist/`**post-Q-W5** `session`, `ext_state_io`, `prune_fs` (from `persist`)
- `shell/actions/``drag_out_win`; **post-Q-W4** `design_view_actions`, `bank_actions`, - `shell/actions/``drag_out_win`; **post-Q-W4** `design_view_actions`, `bank_actions`,
`prune_action` (from `actions`) `prune_action` (from `actions`)
- `shell/instrument/``reaper_bridge`, `reasampler_embed`, `vst_entry`, `reasampler_vst.h` /
`reasampler_uid.h`; **post-Q-W2v** the editor TUs (`editor_session` / `editor_controls` /
`editor_paint_sample` / `editor_paint_browse_zone` / `editor_input_sample` /
`editor_input_browse_zone` / `editor_platform``editor_layout` hoists *pure*
`core/instrument/ui/`, discharging T2-06) and the processor TUs (`processor_state` /
`processor_reload` / lifecycle+`process()`)
**`app/`:** `main.cpp` (post-Q-W3: API-pointer ownership + `ReaperPluginEntry` + dispatch only). **`app/`:** `main.cpp` (post-Q-W3: API-pointer ownership + `ReaperPluginEntry` + dispatch only).
@@ -2459,37 +2522,83 @@ directories.
unified `Parser` (`::json`) must not collide once flattened into granular namespaces; resolve by unified `Parser` (`::json`) must not collide once flattened into granular namespaces; resolve by
subsystem home. subsystem home.
## The god-module split seams (Q-5) ## The god-module split seams (Q-5 — SETTLED 2026-07-28: T4 seam lists adopted; ~600 ceiling is the bar)
Split each to the audit-validated seams, no finer: Split each to the audit-validated seams, no finer — **and every shipped TU lands under the
~600-line ceiling** (the Q-5 settlement: seams are the method, the ceiling is the bar; arbitrary
bisection to hit the number is rejected; the one documented exception is `sampler_core.cpp`).
LOC figures updated to the Q-W0 T4 census (2026-07-28):
- **`bank_panel.cpp` (2424 LOC → `shell/panel/`, Q-W2):** `panel_render` (draw/paint) / - **`bank_panel.cpp` (3459 LOC → `shell/panel/`, Q-W2 — eight seams, T4-01):** `panel_render`
`panel_thumbnails` (compute+cache) / `panel_audition` (preview engine — **hot path, direct (draw/paint) / `panel_thumbnails` (compute+cache) / `panel_audition` (preview engine — **hot
call-through**) / `panel_input` (mouse/key/wheel + new-content detection) / `panel_bank_ops` path, direct call-through**) / `panel_input` (mouse/key/wheel + new-content detection) /
(bank CRUD — the single owner W4 dedupes against) / `panel_window` (lifecycle + OS **`panel_layout`** (toolbar/footer/menu rects + row/cluster builders + region geometry — new
drag-out/drop-target). Split the fat `bank_panel.h` per seam (I). seam) / **`panel_drag`** (the card-drag/hover state machine, pure mirror `card_drag` — new
- **`main.cpp` (1762 LOC → hoist to `shell/capture/`, Q-W3):** `capture_orchestrator` seam) / `panel_bank_ops` (bank CRUD — the single owner W4 dedupes against) / `panel_window`
(`RunCapture`/`captureAndIndexOne`/`renderOffline`/batch/recapture/realtime `Run*`) / (lifecycle + OS drag-out/drop-target). Without the two new seams, `panel_render` (~700) and
`scope_resolve` (range/razor/track resolution + provenance assembly inputs) / `panel_input` (~800) would ship over the ceiling. Split the fat `bank_panel.h` per seam (I).
`realtime_lifecycle` (state machine + globals + selection guards). `FxBypassGuard` moves out - **`main.cpp` (1897 LOC → hoist to `shell/capture/`, Q-W3 — four hoists, T4-02):**
but **stays stack RAII** (precision-critical). `main.cpp``app/`, reduced to pointers + entry `capture_orchestrator` (`RunCapture`/`captureAndIndexOne`/`renderOffline`/single-capture +
+ dispatch. realtime/insert action bodies — lands ~450) / **`capture_batch`** (batch family +
- **`actions.cpp` (981 LOC → `shell/actions/`, Q-W4):** `design_view_actions` / `RunRecaptureFromSource` + the two RAII selection guards — new hoist; recapture is
planner-driven like batch and shares the guard machinery) / `scope_resolve` (range/razor/track
resolution + provenance assembly inputs) / `realtime_lifecycle` (state machine + globals).
`FxBypassGuard` moves out but **stays stack RAII** (precision-critical). `main.cpp``app/`,
reduced to pointers + entry + dispatch. **Wave riders (SETTLED 2026-07-28):** delete
`ICaptureBackend` + correct the CLAUDE.md/CONTEXT description in the same commit (T4-26);
shared `stampCaptureSample` epilogue dedupe (T2-09); `capture_realtime_finalize` split with
the Q-9 rename (T4-08); `makeUniqueTag` per-session monotonic counter (T1-11); the pure
`wav_codec` consolidation (audit §4e).
- **`actions.cpp` (1016 LOC → `shell/actions/`, Q-W4 — T4-03: seams unchanged, still
sub-600):** `design_view_actions` /
`bank_actions` / `prune_action` (`doBankPruneFolder` — the single file-deletion action). Dedupe `bank_actions` / `prune_action` (`doBankPruneFolder` — the single file-deletion action). Dedupe
`promptText`/`mintBankId` + bank verbs against `panel_bank_ops`. `promptText`/`mintBankId` + bank verbs against `panel_bank_ops`.
- **`persist.cpp` (766 LOC → `shell/persist/`, Q-W5):** `session` (lifecycle/poll + - **`persist.cpp` (852 LOC → `shell/persist/`, Q-W5 — T4-04: seams unchanged; the pS-usage
growth landed exactly where this wave isolates it):** `session` (lifecycle/poll +
`BeginLoadProjectState` reload hook) / `ext_state_io` (serialization bridge + GUID minting + `BeginLoadProjectState` reload hook) / `ext_state_io` (serialization bridge + GUID minting +
folder relocation) / **`prune_fs`** (prune scan + `deleteOrphanFile` via `SHFileOperationW` folder relocation) / **`prune_fs`** (prune scan + `deleteOrphanFile` via `SHFileOperationW`
the isolated single file-deletion authority). the isolated single file-deletion authority). **Wave rider (T2-04):** the `GetProjExtState`
grow-loop ×3 dedupes onto `bridge_marshal`'s generalized retry policy — `usage_scan`'s
prune-safety-adjacent copy included.
- **`reasampler_editor.cpp` (3065 LOC — the largest file in the repo → `shell/instrument/`,
Q-W2v — eight TUs, T4-11; split axis = the Sample/Browse/Zone face structure):**
`editor_session` / `editor_controls` / `editor_layout` (**pure-candidate hoist** →
`core/instrument/ui/`, `editor_geometry` the named owner — discharges T2-06's
stranded-layout-math finding) / `editor_paint_sample` / `editor_paint_browse_zone` /
`editor_input_sample` / `editor_input_browse_zone` / `editor_platform`. Rider: adopt the pure
`ThumbnailKey` on the VST side while the editor is open (T2-10).
- **`reasampler_processor.cpp` (1164 LOC → `shell/instrument/`, Q-W2v — three TUs, T4-12):**
`processor_state` / `processor_reload` / lifecycle+`process()` kept whole. **No virtual seam
on the atomic-pointer-swap reload pattern (T4-29).**
- **`sample_map` (970 LOC + 708-line header → Q-W2v, T4-13 ≡ T2-07):** resolution core vs the
**`component_state_io`** binary ComponentState codec (+ matching header split) — the codec
grows every envelope bump (v6→v11 in one quarter); the extension stops linking the whole voice
engine to serialize one preset blob. The `core/wire` LE byte-codec template
(`putLE`/`readLE`, T4-20) lands with it.
- **`sampler_core.cpp` (968 LOC + 762-line header — Q-W2v, T4-14/T4-27): the TU stays WHOLE —
the documented hot-path exception to the ~600 ceiling.** Envelope `tick()`s run
per-voice-per-sample; same-TU definition is what lets the compiler inline the stack (no LTO in
the build); a by-class split is the exact heuristic-(3) dispatch blowout. The header splits
into `zone_params.h` + `sampler_core.h`. Recorded here so nobody "fixes" it later.
## The JSON extraction (Q-2 / Q-W1) ## The JSON extraction (Q-2 / Q-W1)
Extract one pure **`core/json`** (`::json`): parser (`parseString`/`parseInt`/`parseKey`/ Extract one pure **`core/json`** (`::json` — minted as **`json::Reader`/`json::Writer`**, Q-8
SETTLED 2026-07-28): parser (`parseString`/`parseInt`/`parseKey`/
`skipValue` + escape) + serialize/emit helpers. Rewire `bank_model`, `bank_book`, `skipValue` + escape) + serialize/emit helpers. Rewire `bank_model`, `bank_book`,
`view_mode_model`, `owned_manifest` onto it and **delete their four hand-rolled `Parser`s**. `view_mode_model`, `owned_manifest`, **and `tail_control` (T2-02 — the fifth hand-rolled decoder
the §2 audit undercounted)** onto it and **delete all five hand-rolled decoders**.
Round-trip output must be **byte-identical** to before — this is a structural dedupe, not a format Round-trip output must be **byte-identical** to before — this is a structural dedupe, not a format
change. Off all hot paths (serialization runs at save/load, never per frame) — safe to abstract change. Off all hot paths (serialization runs at save/load, never per frame) — safe to abstract
freely. freely. **W1 siblings (from the Q-W0 sign-off):** the shared `readFileBytes` pure helper
(T2-03); the length-prefixed wire-`Cursor` collapse into one shared wire codec beside
`core/json`, consumed by `provenance` / `assignment_request` / `sample_usage` /
`parseBankGeneration` (T2-01(b) — the structural half; the hardening backport lands in Q-W0);
the **concrete** `ui::Rect` unification + `contains()` + per-role aliases, retiring the
XYWH-vs-LTRB fork — NOT a template (T2-05 ≡ T4-21), with the `clamp01` rider (T4-24) and the
`hitIndex` template only as an opportunistic follow-on (T4-22); the `slot_map` extraction
(T4-05) and optional `view_mode_model` planner split (T4-06) riding files W1 already opens; the
relocation scope grows to the ~20 clean VST pure libs under `core/instrument/` (T4-18).
## The OCP registration-table (Q-6 / Q-W6) ## The OCP registration-table (Q-6 / Q-W6)
@@ -2515,7 +2624,7 @@ focus. The audit (2026-07-27) is grep-verified; the load-bearing findings:
one `json::Parser` in Q-W1; the shared pure-UI rect types `FooterRect` / `ButtonRect` (defined in one `json::Parser` in Q-W1; the shared pure-UI rect types `FooterRect` / `ButtonRect` (defined in
`prune_button.h`, reused by `footer_bar.h` under an explicit hand-collision "NAME NOTE") get one `prune_button.h`, reused by `footer_bar.h` under an explicit hand-collision "NAME NOTE") get one
`ui::` owner; `Sample` (`model::`) vs `AudioSample` (`audio::`) de-collide by home. `ui::` owner; `Sample` (`model::`) vs `AudioSample` (`audio::`) de-collide by home.
- **Genuine renames (Q-8/Q-9 — Daniel's call):** `BankIndex``BankModel` (the `bank_model.h` - **Genuine renames (Q-8/Q-9 — SETTLED, Daniel 2026-07-28: all land):** `BankIndex``BankModel` (the `bank_model.h`
file↔class word-mismatch — the worst legibility wart, rec: rename the class so the model family file↔class word-mismatch — the worst legibility wart, rec: rename the class so the model family
reads `BankModel`/`BankBook`/`ViewModeModel`); the unified JSON parser named `json::Reader`/ reads `BankModel`/`BankBook`/`ViewModeModel`); the unified JSON parser named `json::Reader`/
`json::Writer` at W1 mint; align `capture_realtime`(shell)/`realtime_record`(pure) to the house `json::Writer` at W1 mint; align `capture_realtime`(shell)/`realtime_record`(pure) to the house
@@ -2550,6 +2659,25 @@ the following are acceptance criteria on every point:
**Net:** every recommended split falls on a cold path or preserves call/inline shape on the two **Net:** every recommended split falls on a cold path or preserves call/inline shape on the two
hot ones. *A split that would add a hot-path indirection is out of scope — rework it or drop it.* hot ones. *A split that would add a hot-path indirection is out of scope — rework it or drop it.*
## Structural heuristics (Daniel, 2026-07-28 — acceptance criteria phase-wide)
Three heuristics postdate the original framing and bind every wave. They **generalize** the
three-hot-path performance guardrail above — they do not replace it:
1. **More directories is a must; more files is good; ~600-line file ceiling.** SRP applies to
namespaces, encapsulation, and file organization alike. The ceiling is the *bar*, the audit's
named seams are the *method*: a file landing over ~600 needs a responsibility seam, not an
arbitrary bisection (bisection-to-hit-the-number is rejected). A documented hot-path
exception (`sampler_core.cpp`, T4-14/T4-27) is legitimate; silent overshoot is not.
2. **Templates are the right tool for compile-time dedup — use them where earned.** The LE
byte-codec `putLE`/`readLE` (T4-20) is earned: compile-time dispatch, zero runtime cost, off
the hot paths. The rect family is NOT (T4-21): the types differ in name only, so one
**concrete** `ui::Rect` — a template there would model nothing.
3. **SOLID is great, but saved CPU is better.** No dispatch-stack blowouts *anywhere* — not just
the three named hot paths; prefer static polymorphism where the types are compile-time-known.
The T4-27 warning is the canonical case: a by-class `sampler_core` split would put virtual
envelope `tick()`s on the per-voice-per-sample path — exactly the blowout this forbids.
## The GATE (load-bearing — Phase Q is last) ## The GATE (load-bearing — Phase Q is last)
Phase Q is **gated on the tree being otherwise quiescent.** Daniel's plain readiness target: Phase Q is **gated on the tree being otherwise quiescent.** Daniel's plain readiness target:
@@ -2583,16 +2711,27 @@ every commit), a property only an *incremental* reorg uses. Risk-ordered:
pre-restructure audit wave (Q-W0)"). Produces a written, triaged findings report; runs **first** pre-restructure audit wave (Q-W0)"). Produces a written, triaged findings report; runs **first**
and **gates Q-W1** — no structural point begins until the triage closes and Daniel signs off on and **gates Q-W1** — no structural point begins until the triage closes and Daniel signs off on
every disposition. Fix-now findings are remediated here or folded into the wave that opens the every disposition. Fix-now findings are remediated here or folded into the wave that opens the
file; the report may add/reshape downstream Q-W1..Q-W6 points before they start. file; the report may add/reshape downstream Q-W1..Q-W6 points before they start. **COMPLETE
- **Q-W1** — safe opener: `core/json` extract (delete 4 `Parser`s) + impose the directory/ and signed off 2026-07-28; the sub-gate closes when the six fix-now remediations land
(`pq-w0-fixes`).**
- **Q-W1** — safe opener: `core/json` extract (delete the 5 hand-rolled decoders — T2-02 adds
`tail_control`) + impose the directory/
namespace layout on the 30 clean pure libs + clean shells (pure relocation, no logic change). namespace layout on the 30 clean pure libs + clean shells (pure relocation, no logic change).
All later waves assume this layout. **Carries the naming collision fixes + the model-class All later waves assume this layout. **Carries the naming collision fixes + the model-class
renames (Q-8), which are free during this relocation.** renames (Q-8), which are free during this relocation.** **Scope grown by Q-W0 (2026-07-28):**
- **Q-W2..Q-W5** — the four god-module splits, one per wave, risk-ordered (`bank_panel` + `readFileBytes` (T2-03), the wire-`Cursor` codec (T2-01(b)), the concrete `ui::Rect`
`main.cpp``actions.cpp``persist.cpp`). Q-W4 depends on Q-W2 (`panel_bank_ops` dedupe unification (T2-05 ≡ T4-21) + `clamp01` (T4-24), the `slot_map`/planner riders (T4-05/T4-06),
target); Q-W5 best after Q-W4 (`prune_action``prune_fs` routing); otherwise parallel-safe. and the ~20 clean VST pure libs under `core/instrument/` (T4-18).
- **Q-W2..Q-W5 (+ Q-W2v)** — the god-module splits, risk-ordered (`bank_panel`
`main.cpp``actions.cpp``persist.cpp`), plus **Q-W2v** (NEW, added at the Q-W0 sign-off:
the VST god-modules — editor eight TUs / processor three TUs / `component_state_io`;
`sampler_core` TU whole, the documented exception), which **runs parallel with Q-W2**
(different artifact, zero file overlap — audit §4f SETTLED). Q-W4 depends on Q-W2
(`panel_bank_ops` dedupe target); Q-W5 best after Q-W4 (`prune_action``prune_fs` routing);
otherwise parallel-safe.
**Q-W2 carries the `panel_*` names; Q-W3 carries the `capture_realtime`/`realtime_record` **Q-W2 carries the `panel_*` names; Q-W3 carries the `capture_realtime`/`realtime_record`
word-order fix (Q-9).** word-order fix (Q-9) + the settled riders (`ICaptureBackend` deletion + doc correction,
`wav_codec`, `stampCaptureSample` dedupe, T1-11, `capture_realtime_finalize`).**
- **Q-W6** — OCP registration-table + residual fat-header (I) splits. Depends on Q-W3 (registration - **Q-W6** — OCP registration-table + residual fat-header (I) splits. Depends on Q-W3 (registration
code isolated first). Sequenced last; most droppable if narrowing. code isolated first). Sequenced last; most droppable if narrowing.
- **Naming (Q-7): no dedicated wave** — every rename rides the wave already relocating/splitting - **Naming (Q-7): no dedicated wave** — every rename rides the wave already relocating/splitting
@@ -2624,7 +2763,9 @@ every commit), a property only an *incremental* reorg uses. Risk-ordered:
realtime-tick — ever (a hard acceptance bar, not advice). realtime-tick — ever (a hard acceptance bar, not advice).
- **No design-level (D-letter SOLID) rework.** `main`/`bank_panel` depending on concrete capture - **No design-level (D-letter SOLID) rework.** `main`/`bank_panel` depending on concrete capture
backends is a low-priority Dependency-Inversion concern — **out of scope** (a design change, not backends is a low-priority Dependency-Inversion concern — **out of scope** (a design change, not
a reorg). Phase Q reorganizes; it does not re-architect interfaces. a reorg). Phase Q reorganizes; it does not re-architect interfaces. (Deleting the *dead*
`ICaptureBackend` abstraction in Q-W3 is the opposite move — removing a false interface with
one deriver and zero polymorphic call sites, T4-26 — and is in scope.)
- **No `peaks` data-ownership change.** `peaks` forcing a whole-file `std::vector<float>` copy on - **No `peaks` data-ownership change.** `peaks` forcing a whole-file `std::vector<float>` copy on
the thumbnail path is noted but **not touched** — reworking it risks the hot path. the thumbnail path is noted but **not touched** — reworking it risks the hot path.
- **No big-bang commit.** Every wave is independently landable and CTest-green; reject a change set - **No big-bang commit.** Every wave is independently landable and CTest-green; reject a change set
@@ -2632,5 +2773,7 @@ every commit), a property only an *incremental* reorg uses. Risk-ordered:
- **Do not begin before the GATE.** Re-confirm the tree is quiescent (Phase S + L + D2 merged/closed; - **Do not begin before the GATE.** Re-confirm the tree is quiescent (Phase S + L + D2 merged/closed;
M9 abandoned) before any Q point. **And do not begin any structural point (Q-W1+) before the Q-W0 M9 abandoned) before any Q point. **And do not begin any structural point (Q-W1+) before the Q-W0
sub-gate:** the audit's triage is complete and Daniel has signed off on every finding's disposition. sub-gate:** the audit's triage is complete and Daniel has signed off on every finding's disposition.
(Sign-off given 2026-07-28; the sub-gate now closes when the six fix-now remediations land on
`pq-w0-fixes`.)
- **Verify** the CMake `src/` path updates and the SWELL/LICE surfaces still resolve after - **Verify** the CMake `src/` path updates and the SWELL/LICE surfaces still resolve after
relocation, as the existing build already requires. relocation, as the existing build already requires.
+248 -65
View File
@@ -220,8 +220,21 @@ panel adopts knob deck + curve popup, `param_slider` slider rows retired on that
> downstream Q-W1..Q-W6 points; fixes that Q-W0 classifies fix-now are remediated in Q-W0 (or folded > downstream Q-W1..Q-W6 points; fixes that Q-W0 classifies fix-now are remediated in Q-W0 (or folded
> into the wave that already touches the file), **not** deferred silently into the structural waves. > into the wave that already touches the file), **not** deferred silently into the structural waves.
> >
> **Q-W0 SIGN-OFF: COMPLETE (Daniel, 2026-07-28).** The audit ran as four parallel tracks (T1 DSP,
> T2 architecture, T3 env-coupled constants, T4 sizing/placement — **59 findings**; report
> `docs/product/code-quality-audit.md`, appendices `docs/product/audit-notes/`), and **all 59
> findings' dispositions are approved as proposed.** The Q-W1 sub-gate is satisfied **once the six
> approved fix-now remediations land** (in flight on branch `pq-w0-fixes`, Q-W0-scoped): T1-01,
> T1-03, T1-09, T2-01(a), T3-01, T3-03. The audit's §3 plan reshape is **folded into the waves
> below** (Q-W2 6→8 seams; NEW wave **Q-W2v** parallel with Q-W2; Q-W3 3→4 hoists + riders; Q-W5
> + the ext-state-loop dedupe), and its §4 decision list is settled — see the settlement block
> below. The Q-11 question is answered by the audit: the SOLA pitch engine is **sound — no
> technique replacement warranted**; every pitch finding is a bounded in-technique fix or a
> documented operating limit.
>
> **Settled (Q-1, this-doc):** the phase is **`Q` (Quality)**; point-id family `Q1..Qn`, wave > **Settled (Q-1, this-doc):** the phase is **`Q` (Quality)**; point-id family `Q1..Qn`, wave
> prefixes `Q-W0` (the pre-restructure audit) then `Q-W1..Q-W6` (the structural reorg). > prefixes `Q-W0` (the pre-restructure audit) then `Q-W1..Q-W6` (the structural reorg; **+
> `Q-W2v`**, the VST god-module wave added at the Q-W0 sign-off, 2026-07-28).
> **Settled (Q-10/Q-11, Daniel 2026-07-27):** Q-10 audit-report home = a **committed doc** > **Settled (Q-10/Q-11, Daniel 2026-07-27):** Q-10 audit-report home = a **committed doc**
> (`docs/product/code-quality-audit.md`, not a tracked issue list); Q-11 pitch-remediation depth = > (`docs/product/code-quality-audit.md`, not a tracked issue list); Q-11 pitch-remediation depth =
> **defer to findings** (default document-and-defer; weigh a bounded OLA fix before a technique > **defer to findings** (default document-and-defer; weigh a bounded OLA fix before a technique
@@ -238,6 +251,25 @@ panel adopts knob deck + curve popup, `param_slider` slider rows retired on that
> `BankModel`; the JSON `Parser``json::Reader`/`Writer`), leave the merely-quirky (rec); > `BankModel`; the JSON `Parser``json::Reader`/`Writer`), leave the merely-quirky (rec);
> Q-9 align the `capture_realtime`/`realtime_record` shell↔core word order during W3 (rec: yes).** > Q-9 align the `capture_realtime`/`realtime_record` shell↔core word order during W3 (rec: yes).**
> >
> **SETTLED (Daniel, 2026-07-28 — with the Q-W0 sign-off; the REC record above kept as history):**
> **Q-5 SETTLED** — split to **seams-by-responsibility with the T4 seam lists adopted**
> (`bank_panel` 6→8 seams adding `panel_layout` + `panel_drag`, T4-01; `capture_orchestrator`
> further split with `capture_batch`, T4-02), and the **~600-line file ceiling is an acceptance
> criterion on every split wave** — seams are the method, the ceiling is the bar; arbitrary
> bisection to hit the number is rejected. **Q-6 SETTLED: in scope, last wave, as planned.**
> **Q-8 SETTLED: both renames**`BankIndex``BankModel` (W1) and the JSON parser minted as
> `json::Reader`/`json::Writer` (W1); additionally from the audit, **`ICaptureBackend` is deleted
> in Q-W3** (T4-26 — one deriver, zero polymorphic call sites; the CLAUDE.md/CONTEXT "two
> backends behind one interface" correction **rides Q-W3 itself**, recorded as a rider — the docs
> are not edited before that wave). **Q-9 SETTLED: yes** — align to stem `capture_realtime`,
> shell suffixed, during W3. **VST placement (audit §4a) SETTLED: T4-18**`src/vst/` integrates
> into the single `core/`/`shell/` top split as `core/instrument/{engine,map,ui}` +
> `shell/instrument/` (Q-3 directory map updated in CONTEXT.md §Phase Q). **WAV/RIFF
> consolidation (audit §4e) SETTLED:** a named rider on **Q-W3** — one pure **`wav_codec`** owner
> (walker + layout + build + patch), absorbing the T4-10 ingest extraction. **Q-W2v scheduling
> (audit §4f) SETTLED: parallel with Q-W2** (different artifact, zero file overlap; the serial
> "Q-W7" alternative set aside).
>
> **HARD CONSTRAINT — performance (see CONTEXT.md §Phase Q, `docs/product/code-organization.md` > **HARD CONSTRAINT — performance (see CONTEXT.md §Phase Q, `docs/product/code-organization.md`
> §3).** The reorg must cost **zero runtime.** On the three hot paths — `peaks` envelope > §3).** The reorg must cost **zero runtime.** On the three hot paths — `peaks` envelope
> compute, audition/preview, the realtime-capture tick — **no added virtual dispatch, no > compute, audition/preview, the realtime-capture tick — **no added virtual dispatch, no
@@ -247,6 +279,21 @@ panel adopts knob deck + curve popup, `param_slider` slider rows retired on that
> an acceptance criterion on every point: *a split that would add a hot-path indirection is out > an acceptance criterion on every point: *a split that would add a hot-path indirection is out
> of scope — rework it or drop it.* > of scope — rework it or drop it.*
> >
> **STRUCTURAL HEURISTICS (Daniel, 2026-07-28 — acceptance criteria on every wave; these
> *generalize* the three-hot-path guardrail above, they do not replace it):**
> (1) **More directories is a must, more files is good, ~600-line file ceiling** — SRP applies to
> namespaces, encapsulation, and file organization alike. The ceiling is the *bar*, the audit's
> named seams are the *method*: a file landing over ~600 needs a responsibility seam, not an
> arbitrary bisection; a documented hot-path exception (`sampler_core.cpp`, T4-14/T4-27) is
> legitimate, silent overshoot is not.
> (2) **Templates are the right tool for compile-time dedup — use them where earned** (the LE
> byte codec `putLE`/`readLE`, T4-20), not for name-only unification (the rect family is one
> **concrete** `ui::Rect`, NOT a template — T4-21's ruling).
> (3) **SOLID is great but saved CPU is better** — no dispatch-stack blowouts *anywhere*, not
> just the three named hot paths; prefer static polymorphism where types are compile-time-known
> (T4-27's warning is the canonical case: a by-class `sampler_core` split would put virtual
> envelope `tick()`s on the per-voice-per-sample path).
>
> **NAMING dimension (added 2026-07-27; grep-verified audit in `docs/product/code-organization.md` > **NAMING dimension (added 2026-07-27; grep-verified audit in `docs/product/code-organization.md`
> §2b).** Beyond giving symbols a directory + namespace *home* (Q-3/Q-4), Phase Q also gives > §2b).** Beyond giving symbols a directory + namespace *home* (Q-3/Q-4), Phase Q also gives
> poorly/inconsistently-named symbols a consistent *name*, against the same Vital bar. The audit > poorly/inconsistently-named symbols a consistent *name*, against the same Vital bar. The audit
@@ -265,9 +312,14 @@ panel adopts knob deck + curve popup, `param_slider` slider rows retired on that
> per-module static-lib + per-module test-executable seams already draw the module boundaries; > per-module static-lib + per-module test-executable seams already draw the module boundaries;
> a file move + namespace change is mechanically verifiable — `ctest --test-dir build` is green > a file move + namespace change is mechanically verifiable — `ctest --test-dir build` is green
> or it isn't. **Green-CTest-at-every-point is an acceptance criterion.** Big-bang is rejected; > or it isn't. **Green-CTest-at-every-point is an acceptance criterion.** Big-bang is rejected;
> the reorg is risk-ordered waves (W1 safe opener → W2W5 god-module splits → W6 OCP finish). > the reorg is risk-ordered waves (W1 safe opener → W2/W2vW5 god-module splits → W6 OCP finish).
## Q-W0 — pre-restructure functional + DSP quality audit (runs FIRST; gates Q-W1) ## Q-W0 — pre-restructure functional + DSP quality audit (runs FIRST; gates Q-W1)
**STATUS (2026-07-28): audit COMPLETE, triage COMPLETE, sign-off COMPLETE.** The findings report
is committed (`docs/product/code-quality-audit.md`; track appendices in
`docs/product/audit-notes/` — T1 DSP, T2 architecture, T3 env-constants, T4 sizing/placement; 59
findings). Daniel approved every disposition 2026-07-28. **The Q-W1 sub-gate is satisfied once
the six approved fix-now remediations land** (final point below; in flight on `pq-w0-fixes`).
**Goal:** Before a single structural point moves, perform a **thorough static/functional audit** of **Goal:** Before a single structural point moves, perform a **thorough static/functional audit** of
the codebase and produce a **written, triaged findings report**. This is the *functional-correctness the codebase and produce a **written, triaged findings report**. This is the *functional-correctness
and algorithm-quality* complement to the grep-verified SOLID/naming audit that already grounds and algorithm-quality* complement to the grep-verified SOLID/naming audit that already grounds
@@ -322,19 +374,33 @@ before/after listening or null check. **The gate to Q-W1 is: triage complete + D
are a decision, not an omission. are a decision, not an omission.
- [ ] **Sign-off gate.** Daniel reviews the triage and signs off on each disposition. Q-W1 does not - [ ] **Sign-off gate.** Daniel reviews the triage and signs off on each disposition. Q-W1 does not
begin until this is done; fold any new/reshaped downstream points the audit surfaces into begin until this is done; fold any new/reshaped downstream points the audit surfaces into
Q-W1..Q-W6 before starting them. Q-W1..Q-W6 before starting them. **DONE (Daniel, 2026-07-28): all 59 dispositions approved as
proposed; the §3 plan reshape and §4 decisions are folded into Q-W1..Q-W6 + Q-W2v below.**
- [ ] **Fix-now remediations (approved 2026-07-28; Q-W0-scoped; in flight on branch
`pq-w0-fixes`):** T1-01 linked-lag stereo splice alignment, T1-03 Preserve prime bound +
immediate `freezeTail()`, T1-09 `declickR_` dead-state removal (rider on the `sampler_core`
edits), T2-01(a) provenance wire-cursor hardening backport, T3-01 gain-ramp seconds, T3-03
fade-ceiling seconds. Each lands with its module's CTest target green; the audible DSP fixes
with a stated before/after listening check. **Landing these closes Q-W0 and opens Q-W1.**
## Q-W1 — safe opener: extract `core/json` + impose the directory/namespace layout on clean modules ## Q-W1 — safe opener: extract `core/json` + impose the directory/namespace layout on clean modules
**Goal:** The zero-god-module-risk opener. Two moves: (1) extract a pure **`core/json`** module **Goal:** The zero-god-module-risk opener. Two moves: (1) extract a pure **`core/json`** module
(parser + serializer) and **delete the four hand-rolled `Parser`s** in `bank_model` / (parser + serializer) and **delete the five hand-rolled JSON decoders** — the four `Parser`s in
`bank_book` / `view_mode_model` / `owned_manifest` (the single largest DRY+SRP violation, and `bank_model` / `bank_book` / `view_mode_model` / `owned_manifest` **plus `tail_control`'s fifth
entirely off the hot paths); (2) impose the settled `core/`/`shell/`/`app/` directory layout + decoder** (T2-02, Q-W0's undercount fix — the wave's one-JSON-path goal is not met without it) —
sub-namespaces (`reasampler::model`/`view`/`capture`/`audio`/`ui`/`reclaim`/`version`/`json`) on the single largest DRY+SRP violation, entirely off the hot paths; (2) impose the settled
the **30 clean pure libs + the clean shells that need no splitting** — pure relocation, no logic `core/`/`shell/`/`app/` directory layout + sub-namespaces
change. Proves the wave discipline (relocate + encapsulate, CTest-green) before any god-module (`reasampler::model`/`view`/`capture`/`audio`/`ui`/`reclaim`/`version`/`json` + the `instrument`
surgery. CONTEXT.md §Phase Q (json extraction; directory + namespace map). family) on the **30 clean pure libs + the clean shells that need no splitting + the ~20 clean
**Verify:** CTest green at every commit. The four duplicate `Parser`s are gone, replaced by one VST pure libs** (T4 §1.5, under the settled T4-18 `core/instrument/{engine,map,ui}` +
`core/json` consumed by all four models; round-trip serialization is byte-identical to before `shell/instrument/` shape) — pure relocation, no logic change. **Q-W0 additions (SETTLED
2026-07-28):** the shared `readFileBytes` pure helper (T2-03); the wire-`Cursor` collapse into
one shared codec beside `core/json` (T2-01(b)); the rect unification — one **concrete**
`ui::Rect` + `contains()` + per-role aliases, NOT a template (T2-05 ≡ T4-21). Proves the wave
discipline (relocate + encapsulate, CTest-green) before any god-module surgery. CONTEXT.md
§Phase Q (json extraction; directory + namespace map).
**Verify:** CTest green at every commit. The five duplicate JSON decoders are gone, replaced by
one `core/json` consumed by all five consumers; round-trip serialization is byte-identical to before
(no format change — a *structural* dedupe, not a behavior change). Every relocated clean module (no format change — a *structural* dedupe, not a behavior change). Every relocated clean module
compiles and its test executable passes unmoved. `Sample` (model) vs `AudioSample` (audio) vs compiles and its test executable passes unmoved. `Sample` (model) vs `AudioSample` (audio) vs
unified `Parser` (json) do not collide once sub-namespaced. No REAPER type crosses into any unified `Parser` (json) do not collide once sub-namespaced. No REAPER type crosses into any
@@ -345,81 +411,174 @@ any fix-now findings the audit assigned to Q-W1 folded in). First structural wav
- [ ] Extract `core/json` (pure parser + serializer: parseString/parseInt/parseKey/skipValue + - [ ] Extract `core/json` (pure parser + serializer: parseString/parseInt/parseKey/skipValue +
escape, plus emit helpers); unify under `reasampler::json`; guard the `Parser` name against escape, plus emit helpers); unify under `reasampler::json`; guard the `Parser` name against
cross-lib collision. Off all hot paths — safe to abstract freely. cross-lib collision. Off all hot paths — safe to abstract freely.
- [ ] Rewire `bank_model`, `bank_book`, `view_mode_model`, `owned_manifest` onto `core/json`; - [ ] Rewire `bank_model`, `bank_book`, `view_mode_model`, `owned_manifest`, **and
**delete the four duplicate `Parser`s.** Round-trip output byte-identical (dedupe, not `tail_control` (T2-02)** onto `core/json`; **delete the five duplicate decoders.** Round-trip
reformat). output byte-identical (dedupe, not reformat).
- [ ] Add the shared `readFileBytes` pure helper to the `core/` utility home; both artifacts
link it (T2-03).
- [ ] Collapse the length-prefixed wire-`Cursor` family into one shared wire codec beside
`core/json`, consumed by `provenance` / `assignment_request` / `sample_usage` /
`parseBankGeneration` (T2-01(b) — the structural half; the hardening backport lands in Q-W0).
- [ ] Riders on files this wave already opens: `slot_map` extraction from `bank_book` (T4-05);
`view_mode_model` planner split (T4-06 — optional if the wave wants to stay minimal);
`view_lanes` split only if relocation touches `view.cpp` anyway (T4-09).
- [ ] Relocate the 30 clean pure libs into `core/{model,view,capture,audio,ui,reclaim,version, - [ ] Relocate the 30 clean pure libs into `core/{model,view,capture,audio,ui,reclaim,version,
json}/` and the clean shells into `shell/{capture,panel,view,persist,actions}/`; move json}/` **+ the ~20 clean VST pure libs into `core/instrument/{engine,map,ui}/` (T4-18
`main.cpp` to `app/`. Update `CMakeLists.txt` `src/` paths only (no target-graph change). SETTLED, Daniel 2026-07-28)**, and the clean shells into
`shell/{capture,panel,view,persist,actions,instrument}/`; move `main.cpp` to `app/`. Update
`CMakeLists.txt` `src/` paths only (no target-graph change).
- [ ] Apply sub-namespaces matching the directories on every relocated *clean* module (the - [ ] Apply sub-namespaces matching the directories on every relocated *clean* module (the
god-modules re-namespace their own new TUs as they split, W2W5). Resolve `Sample`/ god-modules re-namespace their own new TUs as they split, W2/W2vW5). Resolve `Sample`/
`AudioSample`/`Parser` homes. **This alone resolves the naming *collisions*** (§2b.2): the `AudioSample`/`Parser` homes. **This alone resolves the naming *collisions*** (§2b.2): the
shared pure-UI rect types (`FooterRect`/`ButtonRect`/`Selection`/`CellRect`) get one `ui::` shared pure-UI rect types (`FooterRect`/`ButtonRect`/`Selection`/`CellRect`) get one `ui::`
owner — retire the hand-collision "NAME NOTE" in `footer_bar.h`. owner — one **concrete** `ui::Rect` + `contains()` + per-role aliases, retiring the
- [ ] **Naming riders (Q-8, if settled):** rename the survivor JSON parser to `json::Parser` XYWH-vs-LTRB fork and folding in `editor_geometry`'s `Rect` (T2-05 ≡ T4-21 — explicitly NOT a
(or `json::Reader`/`json::Writer`); if Daniel takes the `BankIndex``BankModel` rename, land template); retire the hand-collision "NAME NOTE" in `footer_bar.h`. Riders: `clamp01` dedup
it here (mechanical class rename, verified by `bank_model_tests`). No rename on a file this (T4-24); the `hitIndex` hit-test template only as an opportunistic follow-on once the rect
wave isn't already relocating (Q-7). unification lands (T4-22).
- [ ] **Naming riders (Q-8 — SETTLED, Daniel 2026-07-28: both renames):** the survivor JSON
parser is minted as **`json::Reader`/`json::Writer`**; land **`BankIndex``BankModel`** here
(mechanical class rename, verified by `bank_model_tests`). No rename on a file this wave isn't
already relocating (Q-7).
- [ ] Confirm CTest green + no hot-path change: `peaks`/audition/realtime-tick untouched by this - [ ] Confirm CTest green + no hot-path change: `peaks`/audition/realtime-tick untouched by this
wave (pure relocation of clean modules; `peaks` stays a free function). wave (pure relocation of clean modules; `peaks` stays a free function).
## Q-W2 — split `bank_panel.cpp` (the biggest god-module, 2424 LOC) ## Q-W2 — split `bank_panel.cpp` (the biggest extension god-module — 3459 LOC at the Q-W0 census)
**Goal:** Split the largest god-module (8+ responsibilities) along the audit's named seams: **Goal:** Split the largest extension god-module (8+ responsibilities) along the audit's named
seams — **eight TUs (Q-5 SETTLED with the T4-01 reshape, Daniel 2026-07-28)**:
`panel_render` / `panel_thumbnails` / `panel_audition` / `panel_input` / `panel_bank_ops` / `panel_render` / `panel_thumbnails` / `panel_audition` / `panel_input` / `panel_bank_ops` /
`panel_window`. Split the fat `bank_panel.h` alongside (Interface Segregation). **Preserve the `panel_window` **+ `panel_layout` (toolbar/footer/menu rects + row/cluster builders + region
geometry glue) + `panel_drag` (the card-drag/hover state machine — it already has a pure mirror,
`card_drag`)** — without the two new seams, `panel_render` (~700) and `panel_input` (~800) would
ship over the ~600 ceiling on day one. Split the fat `bank_panel.h` alongside (Interface
Segregation). **Preserve the
audition hot path as a direct call-through, never virtual.** `panel_bank_ops` becomes the single audition hot path as a direct call-through, never virtual.** `panel_bank_ops` becomes the single
home for the bank-CRUD verbs that W4 will dedupe `actions.cpp` against. CONTEXT.md §Phase Q home for the bank-CRUD verbs that W4 will dedupe `actions.cpp` against. CONTEXT.md §Phase Q
(bank_panel split seams; hot-path audition guardrail). See `docs/product/code-organization.md` (bank_panel split seams; hot-path audition guardrail). See `docs/product/code-organization.md`
§2.1, §5. §2.1, §5.
**Verify:** CTest green at every commit. Each seam is its own TU under `shell/panel/`; the panel **Verify:** CTest green at every commit. Each seam is its own TU under `shell/panel/` and
**every TU lands under the ~600-line ceiling** (the Q-5 acceptance bar); the panel
draws, thumbnails, auditions, handles input, does bank ops, and manages its window exactly as draws, thumbnails, auditions, handles input, does bank ops, and manages its window exactly as
before (no behavior change — verify in DAW that the panel is visually and interactively before (no behavior change — verify in DAW that the panel is visually and interactively
unchanged). Audition/preview call path stays a **direct call-through** (no virtual dispatch, no unchanged). Audition/preview call path stays a **direct call-through** (no virtual dispatch, no
added header→TU indirection on the preview path). The ~20-function public API is now segmented added header→TU indirection on the preview path). The ~20-function public API is now segmented
across the split headers. across the split headers.
**Depends on:** Q-W1 (directory/namespace layout established). Independently landable. **Depends on:** Q-W1 (directory/namespace layout established). Independently landable.
**Parallel-safe with Q-W2v** (different artifact, zero file overlap — §4f SETTLED).
- [ ] Split rendering (`draw*`/`paint*`) → `panel_render`; thumbnail compute+cache → - [ ] Split rendering (`draw*`/`paint*`) → `panel_render`; thumbnail compute+cache →
`panel_thumbnails`. `panel_thumbnails`; toolbar/footer/menu rect + row/cluster builders + region geometry →
**`panel_layout`** (new seam, T4-01).
- [ ] Split the audio audition/preview engine → `panel_audition` — **direct call-through, not - [ ] Split the audio audition/preview engine → `panel_audition` — **direct call-through, not
virtual; preview idle path unchanged.** virtual; preview idle path unchanged.**
- [ ] Split input handling (mouse/key/wheel) + new-content detection → `panel_input`; window - [ ] Split input handling (mouse/key/wheel) + new-content detection → `panel_input`; window
lifecycle + OS drag-out/drop-target → `panel_window`. lifecycle + OS drag-out/drop-target → `panel_window`; the card-drag/hover state machine →
**`panel_drag`** (new seam, T4-01). Per-mouse-move work stays plain free-function calls
(T4-28).
- [ ] Extract bank-CRUD verbs → `panel_bank_ops` (the future single owner; W4 dedupes - [ ] Extract bank-CRUD verbs → `panel_bank_ops` (the future single owner; W4 dedupes
`actions.cpp` against it). Split `bank_panel.h` into per-seam headers (I). `actions.cpp` against it). Split `bank_panel.h` into per-seam headers (I).
- [ ] Verify in DAW: panel unchanged; CTest green; no hot-path indirection added. - [ ] Verify in DAW: panel unchanged; CTest green; no hot-path indirection added; all eight TUs
under the ~600 ceiling.
## Q-W2v — split the VST god-modules (NEW wave — Q-W0 T4 §1.5; runs parallel with Q-W2)
**Goal:** Close the audit's structural scope gap: the VST artifact's god-modules had no owning
wave, and `reasampler_editor.cpp` (3065 LOC) is the largest file in the repo. Split the editor
into **eight TUs along the Sample/Browse/Zone face axis** (T4-11): `editor_session` /
`editor_controls` / `editor_layout` (**pure-candidate hoist** into the existing pure homes —
`editor_geometry` is the named owner; this discharges T2-06's stranded-layout-math finding) /
`editor_paint_sample` / `editor_paint_browse_zone` / `editor_input_sample` /
`editor_input_browse_zone` / `editor_platform`. Split `reasampler_processor.cpp` (1164 LOC) into
**three TUs** (T4-12): `processor_state` / `processor_reload` / lifecycle+`process()` kept
whole. Split `sample_map` into resolution core vs the **`component_state_io`** binary codec +
matching header split (T4-13 ≡ T2-07 — the codec grows every envelope bump; the extension stops
linking the whole voice engine to serialize one preset blob). **`sampler_core.cpp` stays whole
(968 LOC) — a DOCUMENTED hot-path exception to the ~600 ceiling** (T4-14/T4-27: envelope
`tick()`s run per-voice-per-sample; same-TU definition is what lets the compiler inline the
stack, no LTO in the build; a by-class split is the exact heuristic-(3) dispatch blowout); its
header splits into `zone_params.h` + `sampler_core.h`. The `core/wire` LE byte-codec template
(`putLE`/`readLE`, T4-20) lands here with its biggest consumer. CONTEXT.md §Phase Q (VST split
seams; `sampler_core` exception).
**Verify:** CTest green at every commit. Editor and processor behave identically in DAW (visual
+ interactive parity across all three faces; `process()` audio unchanged). Every new TU lands
under the ~600-line ceiling **except the one documented `sampler_core.cpp` exception**.
`process()` + its per-block helpers stay one TU; the atomic-pointer-swap reload pattern gains
**no virtual seam** (T4-29); no dispatch-stack blowout anywhere (heuristic 3).
**Depends on:** Q-W1 (layout + the T4-18 `instrument/` placement established). **Parallel-safe
with Q-W2** (different artifact, zero file overlap — §4f SETTLED, Daniel 2026-07-28; the serial
"Q-W7" alternative was set aside).
- [ ] Split `reasampler_editor.cpp` → the eight face-axis TUs; hoist `editor_layout`'s pure
geometry into the existing pure homes (`editor_geometry` — discharges T2-06).
- [ ] Split `reasampler_processor.cpp``processor_state` / `processor_reload` /
lifecycle+`process()` whole; **no virtual seam on the atomic-swap pattern** (T4-29).
- [ ] Split `sample_map` → resolution core + `component_state_io` codec (+ header split); the
extension's preset-blob path stops linking the voice engine (T4-13 ≡ T2-07).
- [ ] `sampler_core`: split `zone_params.h` out of the header; **TU stays whole — documented
exception** (T4-14/T4-27), recorded in the wave brief so nobody "fixes" it later.
- [ ] Land the `core/wire` LE byte-codec template (`putLE`/`readLE`, T4-20) with
`component_state_io`; other consumers rewire opportunistically.
- [ ] Rider: adopt the pure `ThumbnailKey` on the VST editor side (T2-10).
- [ ] Verify in DAW: editor + processor unchanged; CTest green; ceiling met (one documented
exception); no added dispatch.
## Q-W3 — split `main.cpp` (hoist orchestration; leave main = pointers + entry + dispatch) ## Q-W3 — split `main.cpp` (hoist orchestration; leave main = pointers + entry + dispatch)
**Goal:** Reduce `main.cpp` (1762 LOC) to its actual job — API pointers + `ReaperPluginEntry` + **Goal:** Reduce `main.cpp` (1897 LOC at the Q-W0 census) to its actual job — API pointers +
dispatch (~the owns-pointers ~120 lines) — by hoisting: `capture_orchestrator` (`RunCapture` / `ReaperPluginEntry` + dispatch — by hoisting **four** TUs (T4-02 reshape, SETTLED with Q-5,
`captureAndIndexOne` / `renderOffline` / batch/recapture/realtime `Run*`), `scope_resolve` Daniel 2026-07-28 — the planned three left `capture_orchestrator` at ~885, over the ceiling):
`capture_orchestrator` (`RunCapture` / `captureAndIndexOne` / `renderOffline` / single-capture +
realtime/insert action bodies — lands ~450), **`capture_batch`** (the batch family +
`RunRecaptureFromSource` + the two RAII selection guards — recapture is planner-driven like
batch and shares the guard machinery), `scope_resolve`
(`resolveRange`/`resolveRazorRange`/`collectSelectedTracks` + provenance assembly inputs), and (`resolveRange`/`resolveRazorRange`/`collectSelectedTracks` + provenance assembly inputs), and
`realtime_lifecycle` (the realtime-capture state machine + globals + selection guards). `realtime_lifecycle` (the realtime-capture state machine + globals).
**`FxBypassGuard` moves out but stays a stack RAII object (precision-critical); the realtime idle **`FxBypassGuard` moves out but stays a stack RAII object (precision-critical); the realtime idle
tick stays a single pointer test.** CONTEXT.md §Phase Q (main split seams; FxBypassGuard + tick stays a single pointer test.** **Q-W0 riders owned by this wave (all SETTLED 2026-07-28):**
delete `ICaptureBackend` (T4-26 — one deriver, zero polymorphic call sites; `OfflineRenderBackend`
becomes concrete; the CLAUDE.md/CONTEXT "two backends behind one interface" correction **rides
this wave's own commit**, not earlier); the shared `stampCaptureSample` capture-epilogue dedupe
(T2-09); the `capture_realtime_finalize` split riding the Q-9 rename (T4-08); the `makeUniqueTag`
per-session monotonic-counter fix (T1-11); and the **WAV/RIFF consolidation (audit §4e)** — one
pure **`wav_codec`** owner (walker + layout + build + patch), absorbing `ingest.cpp`'s pure WAV
build helpers (T2-08 / T4-23 / T4-10). CONTEXT.md §Phase Q (main split seams; FxBypassGuard +
realtime-tick guardrails). See `docs/product/code-organization.md` §2.1, §3. realtime-tick guardrails). See `docs/product/code-organization.md` §2.1, §3.
**Verify:** CTest green at every commit. Capture (offline + realtime + batch + recapture) behaves **Verify:** CTest green at every commit. Capture (offline + realtime + batch + recapture) behaves
identically in DAW; the null test still nulls, bit-identical repeats still match (the precision identically in DAW; the null test still nulls, bit-identical repeats still match (the precision
invariants `FxBypassGuard` protects are unchanged); capture ≠ placement holds (no hoisted `Run*` invariants `FxBypassGuard` protects are unchanged); capture ≠ placement holds (no hoisted `Run*`
path gains an `InsertMedia` call). The realtime idle fast-path is still a single pointer test. path gains an `InsertMedia` call). The realtime idle fast-path is still a single pointer test.
`main.cpp` is now pointers + entry + dispatch only. `main.cpp` is now pointers + entry + dispatch only. The four hoisted TUs + `wav_codec` land
**Depends on:** Q-W1. Independent of Q-W2. under the ~600 ceiling; the WAV/RIFF layout has **one** pure owner (the dedup-by-hash and
null-test invariants now rest on one implementation); `ICaptureBackend` is gone with no behavior
change and the CLAUDE.md/CONTEXT description is corrected in the same commit.
**Depends on:** Q-W1. Independent of Q-W2/Q-W2v.
- [ ] Hoist capture orchestration → `capture_orchestrator` (`shell/capture/`); keep - [ ] Hoist capture orchestration → `capture_orchestrator` (`shell/capture/`); keep
`FxBypassGuard` a **stack RAII** object as it moves (precision-invariant-critical). `FxBypassGuard` a **stack RAII** object as it moves (precision-invariant-critical).
- [ ] Hoist the batch family + `RunRecaptureFromSource` + the two RAII selection guards →
**`capture_batch`** (fourth hoist, T4-02) so `capture_orchestrator` lands ~450.
- [ ] Hoist scope/source resolution + provenance assembly inputs → `scope_resolve`. - [ ] Hoist scope/source resolution + provenance assembly inputs → `scope_resolve`.
- [ ] Hoist the realtime-capture lifecycle state machine + globals + the two RAII selection - [ ] Hoist the realtime-capture lifecycle state machine + globals `realtime_lifecycle`;
guards → `realtime_lifecycle`; **idle tick stays a single pointer test.** **idle tick stays a single pointer test.**
- [ ] Leave `main.cpp` = API-pointer ownership + `ReaperPluginEntry` + dispatch; move to `app/`. - [ ] Leave `main.cpp` = API-pointer ownership + `ReaperPluginEntry` + dispatch; move to `app/`.
- [ ] **Naming rider (Q-9, if settled):** align the `capture_realtime` (shell) / `realtime_record` - [ ] **Naming rider (Q-9 — SETTLED, Daniel 2026-07-28: yes):** align the `capture_realtime`
(pure) word-order inversion to the house shell↔core convention (rec: stem `capture_realtime`, (shell) / `realtime_record` (pure) word-order inversion to the house shell↔core convention
shell suffixed) — a free rider since W3 already hoists the realtime lifecycle. No rename on a the pure module takes the stem `capture_realtime`, the shell takes the suffix
file this wave isn't already touching (Q-7). (`drag_out``drag_out_win` is the model). Split `capture_realtime_finalize` (async lifecycle
vs file-side finalize) in the same surgery (T4-08). No rename on a file this wave isn't
already touching (Q-7).
- [ ] Delete `ICaptureBackend` (T4-26): `OfflineRenderBackend` becomes concrete; correct the
CLAUDE.md/CONTEXT "two backends behind one interface" description **in the same commit**.
- [ ] Dedupe the capture-stamp epilogue → shared `stampCaptureSample` (T2-09 — the divergent
bits stay in the realtime caller); fix `makeUniqueTag` with a per-session monotonic counter,
both call sites (T1-11 — same-second batch captures currently collide silently).
- [ ] **WAV/RIFF consolidation rider (audit §4e — SETTLED, Daniel 2026-07-28):** one pure
`wav_codec` owner (chunk walker + layout + build + patch), absorbing `ingest.cpp`'s pure
WAV/PCM build (T4-10 — the ingest shell drops to ~500 and the WAV build gains a test target).
- [ ] Verify in DAW: null test nulls, bit-identical repeats match, capture≠placement holds; - [ ] Verify in DAW: null test nulls, bit-identical repeats match, capture≠placement holds;
CTest green; no realtime-tick branch-shape change. CTest green; no realtime-tick branch-shape change.
## Q-W4 — split `actions.cpp` + dedupe bank verbs against `panel_bank_ops` ## Q-W4 — split `actions.cpp` + dedupe bank verbs against `panel_bank_ops`
**Goal:** Split the two unrelated command-id families in one TU (981 LOC) into **Goal:** Split the two unrelated command-id families in one TU (1016 LOC at the Q-W0 census —
T4-03: the planned seams still land sub-600, no reshape) into
`design_view_actions` / `bank_actions` / `prune_action`, and **dedupe** `actions.cpp`'s own `design_view_actions` / `bank_actions` / `prune_action`, and **dedupe** `actions.cpp`'s own
`promptText`/`mintBankId` and bank verbs against the `panel_bank_ops` single-owner established in `promptText`/`mintBankId` and bank verbs against the `panel_bank_ops` single-owner established in
Q-W2. `prune_action` keeps the `doBankPruneFolder` deletion authority contract intact (routes to Q-W2. `prune_action` keeps the `doBankPruneFolder` deletion authority contract intact (routes to
@@ -442,12 +601,16 @@ contract — a reorg must not touch a shipped command id).
no-undo/no-ext-state; CTest green. no-undo/no-ext-state; CTest green.
## Q-W5 — split `persist.cpp` (isolate the single file-deletion authority into `prune_fs`) ## Q-W5 — split `persist.cpp` (isolate the single file-deletion authority into `prune_fs`)
**Goal:** Split `persist.cpp` (766 LOC, 5 responsibilities) into `session` (lifecycle+poll, **Goal:** Split `persist.cpp` (852 LOC at the Q-W0 census — T4-04: seams unchanged; the
`BeginLoadProjectState` reload hook), `ext_state_io` (the ext-state ↔ JSON serialization bridge + pS-usage growth landed exactly where this wave isolates it; 5 responsibilities) into `session`
GUID minting + folder relocation), and **`prune_fs`** (prune scanning + `deleteOrphanFile` via (lifecycle+poll, `BeginLoadProjectState` reload hook), `ext_state_io` (the ext-state ↔ JSON
`SHFileOperationW`). The split **concentrates** the byte-deleting authority into one obvious serialization bridge + GUID minting + folder relocation), and **`prune_fs`** (prune scanning +
module — it must never spread it. CONTEXT.md §Phase Q (persist split seams; deletion-authority `deleteOrphanFile` via `SHFileOperationW`). The split **concentrates** the byte-deleting
isolation). See `docs/product/code-organization.md` §2.1, §7. authority into one obvious module — it must never spread it. **Q-W0 rider (T2-04, SETTLED
2026-07-28):** generalize the `GetProjExtState` grow-loop retry policy into `bridge_marshal`'s
pure decode home (or its `core/` successor) and rewire all three hand-rolled copies —
`usage_scan`'s prune-safety-adjacent copy included. CONTEXT.md §Phase Q (persist split seams;
deletion-authority isolation). See `docs/product/code-organization.md` §2.1, §7.
**Verify:** CTest green at every commit. Session save/load/undo-reload, ext-state round-trip, **Verify:** CTest green at every commit. Session save/load/undo-reload, ext-state round-trip,
folder relocation, and prune deletion all behave identically in DAW. **File deletion lives in folder relocation, and prune deletion all behave identically in DAW. **File deletion lives in
exactly one module (`prune_fs`)** — the single-file-deletion-authority invariant is *improved* exactly one module (`prune_fs`)** — the single-file-deletion-authority invariant is *improved*
@@ -459,6 +622,9 @@ independently landable.
(serialization bridge + GUID minting + folder relocation). (serialization bridge + GUID minting + folder relocation).
- [ ] Isolate prune scanning + `deleteOrphanFile` (`SHFileOperationW`) → **`prune_fs`** — the - [ ] Isolate prune scanning + `deleteOrphanFile` (`SHFileOperationW`) → **`prune_fs`** — the
one file-deletion module; nothing else may delete bytes. one file-deletion module; nothing else may delete bytes.
- [ ] Dedupe the `GetProjExtState` grow-loop ×3 (T2-04): one retry policy generalized from
`bridge_marshal`; rewire `usage_scan`'s prune-safety-adjacent copy with `sample_usage_tests`
green.
- [ ] Verify in DAW: save/load/undo-reload/relocation/prune unchanged; deletion authority is one - [ ] Verify in DAW: save/load/undo-reload/relocation/prune unchanged; deletion authority is one
module; relative-paths-only holds; CTest green. module; relative-paths-only holds; CTest green.
@@ -466,7 +632,9 @@ independently landable.
**Goal:** Close the last SOLID wart: replace the ~350-line hand-written **non-table** action **Goal:** Close the last SOLID wart: replace the ~350-line hand-written **non-table** action
registration blocks (now isolated in `app/main.cpp` after Q-W3) with a **registration table**, so registration blocks (now isolated in `app/main.cpp` after Q-W3) with a **registration table**, so
adding an action edits one place, not four parallel ones (OCP). Split any remaining fat headers adding an action edits one place, not four parallel ones (OCP). Split any remaining fat headers
(`capture.h`/`persist.h`) not already resolved by their TU splits (I). CONTEXT.md §Phase Q (OCP (`capture.h`/`persist.h`) not already resolved by their TU splits (I). (Q-W0: no reshape
T4-02 notes the ~385-line registration residue left in `app/main.cpp` after Q-W3 shrinks
further under the table.) CONTEXT.md §Phase Q (OCP
registration-table). See `docs/product/code-organization.md` §2.3, §6 (Q-6). registration-table). See `docs/product/code-organization.md` §2.3, §6 (Q-6).
**Verify:** CTest green at every commit. Every action still registers, appears in the Actions **Verify:** CTest green at every commit. Every action still registers, appears in the Actions
list, and fires via `hookcommand` exactly as before; command-id + display strings unchanged list, and fires via `hookcommand` exactly as before; command-id + display strings unchanged
@@ -488,27 +656,42 @@ GATE: Phase S + Phase L L3 merged to dev (D2 complete, M9 abandoned) — tree qu
("when Phase S and L3 are finished" — L1/L2/L3/L4L7 all landed — GATE SATISFIED) ("when Phase S and L3 are finished" — L1/L2/L3/L4L7 all landed — GATE SATISFIED)
Q-W0 (pre-restructure functional + DSP quality audit — findings report + triage) Q-W0 (audit + triage + report — COMPLETE; all 59 dispositions signed off 2026-07-28)
│ ── SUB-GATE: triage complete + Daniel signed off on every disposition ── │ ── SUB-GATE: satisfied once the six approved fix-now remediations land ──
▼ (fix-now findings remediated/assigned; downstream Q-W1..W6 reshaped as needed) ▼ (T1-01 T1-03 T1-09 T2-01a T3-01 T3-03 — in flight on pq-w0-fixes)
Q-W1 (safe opener: core/json extract + directory/namespace layout on clean modules) Q-W1 (safe opener: core/json ×5 + wire codec + rect unification + relocation incl. ~20 VST
├─► Q-W2 (split bank_panel) ──► Q-W4 (split actions + dedupe bank verbs vs panel_bank_ops) │ pure libs under core/instrument/{engine,map,ui} + riders)
├─► Q-W3 (split main.cpp; hoist orchestration) ──► Q-W6 (OCP registration-table + I splits) ├─► Q-W2 (split bank_panel — 8 seams) ──► Q-W4 (split actions + dedupe vs panel_bank_ops)
─► Q-W5 (split persist; isolate prune_fs) [best after Q-W4] ─► Q-W2v (NEW: VST god-modules — editor 8 TUs / processor 3 TUs / component_state_io;
│ sampler_core TU whole — documented exception) [parallel with Q-W2: zero overlap]
├─► Q-W3 (split main — 4 hoists incl. capture_batch; + wav_codec, ICaptureBackend deletion,
│ stamp dedupe, T1-11, capture_realtime_finalize) ──► Q-W6 (OCP registration-table)
└─► Q-W5 (split persist; + ext-state-loop dedupe) [best after Q-W4]
``` ```
Q-W0 is the **entry point** — the functional/DSP audit runs FIRST and gates Q-W1 (no structural Q-W0 has run and is signed off (2026-07-28); its sub-gate closes when the six fix-now
point begins until its triage closes and Daniel signs off). W1 is then the safe, high-leverage remediations land. W1 is the safe, high-leverage structural opener (all later waves assume the
structural opener (all later waves assume the layout it establishes). The four god-module splits layout — including the T4-18 `instrument/` placement — it establishes). The god-module splits
(W2W5) are risk-ordered and mostly parallel-safe; W4 depends on W2's `panel_bank_ops`, W6 depends (W2, W2v, W3, W5) are risk-ordered and mostly parallel-safe; **Q-W2v runs parallel with Q-W2**
on W3's isolated registration code. Big-bang is rejected — every wave is independently landable and (different artifact, zero file overlap — audit §4f SETTLED); W4 depends on W2's
CTest-green. `panel_bank_ops`, W6 depends on W3's isolated registration code. Big-bang is rejected — every
wave is independently landable and CTest-green.
## Phase Q — must-verify-before-build ## Phase Q — must-verify-before-build
- **Q-W0 closed before any structural point** — the functional/DSP audit's findings report exists, - **Q-W0 closed before any structural point** — the functional/DSP audit's findings report exists,
every finding is triaged (fix-now vs. document-and-defer, each with rationale), fix-now findings every finding is triaged (fix-now vs. document-and-defer, each with rationale), fix-now findings
are remediated or assigned to the wave that opens their file, and **Daniel has signed off on every are remediated or assigned to the wave that opens their file, and **Daniel has signed off on every
disposition.** Q-W1 does not begin otherwise. (CONTEXT.md §Phase Q Q-W0; naming/DSP smell disposition.** Q-W1 does not begin otherwise. (CONTEXT.md §Phase Q Q-W0; naming/DSP smell
categories §2c of `docs/product/code-organization.md`.) categories §2c of `docs/product/code-organization.md`.) **Status 2026-07-28: triage + sign-off
COMPLETE (all 59 dispositions); the sub-gate closes when the six fix-now remediations land
(`pq-w0-fixes`).**
- **~600-line ceiling on every split wave** — every TU a split wave ships lands under ~600 LOC,
with `sampler_core.cpp` the single documented exception (T4-14/T4-27). Seams are the method,
the ceiling is the bar; arbitrary bisection to hit the number is rejected (Q-5 settlement,
2026-07-28).
- **No dispatch-stack blowouts anywhere** — heuristic (3) generalizes the hot-path guardrail
beyond the three named paths: prefer static polymorphism where types are compile-time-known;
templates only where earned for compile-time dedup (T4-20 yes; T4-21's rect NO-template
ruling).
- **Hot-path call/inline shape** — before landing each split, confirm no virtual dispatch and no - **Hot-path call/inline shape** — before landing each split, confirm no virtual dispatch and no
header→TU indirection was added on `peaks` envelope compute, audition/preview, or the realtime header→TU indirection was added on `peaks` envelope compute, audition/preview, or the realtime
tick. `computeEnvelope` stays a free function on `const std::vector<float>&`; tick. `computeEnvelope` stays a free function on `const std::vector<float>&`;