diff --git a/COMPLETED.md b/COMPLETED.md index 613de11..6ca7464 100644 --- a/COMPLETED.md +++ b/COMPLETED.md @@ -2955,3 +2955,176 @@ unmoved. No REAPER type crosses into any `core/` file. identified but blocked on a `nameKey` linkage design decision, escalated to Daniel and **pending** as of 2026-07-29. Downstream waves touching `bank_book` should check this residual before assuming the split is finished. + +--- + +## Q-W2 — split `bank_panel.cpp` (the biggest extension god-module — 3459 LOC at the Q-W0 census) (2026-07-29) + +> **Merged to `phase-q` 2026-07-29 (merge of `pq-w2-panel`). Integrated suite 61/61 green, +> reviewed-approved.** + +**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_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 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` §2.1, §5. +**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 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 added header→TU indirection on +the preview path). The ~20-function public API is now segmented across the split headers. + +- [x] Split rendering (`draw*`/`paint*`) → `panel_render`; thumbnail compute+cache → + `panel_thumbnails`; toolbar/footer/menu rect + row/cluster builders + region geometry → + `panel_layout` (new seam, T4-01). +- [x] Split the audio audition/preview engine → `panel_audition` — direct call-through, not + virtual; preview idle path unchanged. +- [x] Split input handling (mouse/key/wheel) + new-content detection → `panel_input`; 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). +- [x] 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). +- [ ] Verify in DAW: panel unchanged; CTest green; no hot-path indirection added; all eight TUs + under the ~600 ceiling. — **PENDING**: in-DAW panel-parity verification not yet performed on + `phase-q` (deferred by design). + +**Notes/decisions:** +- **Recorded ceiling overages (reviewer-endorsed, preserved as a durable record per CONTEXT's + "silent overshoot is not legitimate" rule):** `panel_input.cpp` 636, `panel_render.cpp` 613, + `panel_state.h` 608 — overage is comment volume; non-comment lines are ~322–369 per file; no + honest seam remains; bisection was rejected. +- **Review note for the Q-W4 planning record:** `panel_bank_ops`'s verbs still embed + prompts/panel-state nudges — Q-W4's dedupe needs promptless inner verbs (`renameBank(id,name)` + etc.), not a call-site swap; `promptText`/`mintBankId` are byte-identical twins with + `actions.cpp` and are the cheapest first dedupe. +- ~50 TU-private helpers wrapped in anonymous namespaces (review follow-up landed in the same + merge). + +--- + +## Q-W2v — split the VST god-modules (2026-07-29) + +> **Merged to `phase-q` 2026-07-29 (merge of `pq-w2v-vst`). Integrated suite 61/61 green, +> reviewed-approved.** + +**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). + +- [x] 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). +- [x] Split `reasampler_processor.cpp` → `processor_state` / `processor_reload` / + lifecycle+`process()` whole; no virtual seam on the atomic-swap pattern (T4-29). +- [x] 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). +- [x] `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. +- [x] Land the `core/wire` LE byte-codec template (`putLE`/`readLE`, T4-20) with + `component_state_io`; other consumers rewire opportunistically. +- [x] 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. — **PENDING**: in-DAW editor/processor-parity verification not + yet performed on `phase-q` (deferred by design). + +**Notes/decisions:** +- Golden full-blob v11 fixture pins the `component_state_io` codec bytes. +- The `src/vst/` directory is gone — all VST sources now live under the Q-W1 `core/instrument/` + and new `shell/instrument/` layout. +- **Deferred/known:** `component_state_io.h` still includes `sample_map.h`→`sampler_core.h` + transitively (T2-07's header half — future work); the `engine` namespace is deferred + (`sampler_core` stays flat `reasampler`); capture-side LE rewires are left for the capture + family. + +--- + +## Q-W3 — split `main.cpp` (hoist orchestration; leave main = pointers + entry + dispatch) (2026-07-29) + +> **Merged to `phase-q` 2026-07-29 (merge of `pq-w3-main`). Integrated suite 61/61 green, +> reviewed-approved.** + +**Goal:** Reduce `main.cpp` (1897 LOC at the Q-W0 census) to its actual job — API pointers + +`ReaperPluginEntry` + dispatch — by hoisting four TUs (T4-02 reshape, SETTLED with Q-5, 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 `realtime_lifecycle` (the +realtime-capture state machine + globals). `FxBypassGuard` moves out but stays a stack RAII +object (precision-critical); the realtime idle 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. +**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 +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. +`main.cpp` is now pointers + entry + dispatch only. The four hoisted TUs + `wav_codec` land 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. + +- [x] Hoist capture orchestration → `capture_orchestrator` (`shell/capture/`); keep + `FxBypassGuard` a stack RAII object as it moves (precision-invariant-critical). +- [x] Hoist the batch family + `RunRecaptureFromSource` + the two RAII selection guards → + `capture_batch` (fourth hoist, T4-02) so `capture_orchestrator` lands ~450. +- [x] Hoist scope/source resolution + provenance assembly inputs → `scope_resolve`. +- [x] Hoist the realtime-capture lifecycle state machine + globals → `realtime_lifecycle`; idle + tick stays a single pointer test. +- [x] Leave `main.cpp` = API-pointer ownership + `ReaperPluginEntry` + dispatch; move to `app/`. +- [x] Naming rider (Q-9 — SETTLED, Daniel 2026-07-28: yes): align the `capture_realtime` (shell) + / `realtime_record` (pure) word-order inversion to the house shell↔core convention — the pure + module takes the stem `capture_realtime`, the shell takes the suffix (`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). +- [x] Delete `ICaptureBackend` (T4-26): `OfflineRenderBackend` becomes concrete; correct the + CLAUDE.md/CONTEXT "two backends behind one interface" description in the same commit. +- [x] 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). +- [x] 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; CTest + green; no realtime-tick branch-shape change. — **PENDING**: in-DAW null-test / + bit-identical-repeats verification not yet performed on `phase-q` (deferred by design). + +**Notes/decisions:** +- `wav_codec_tests` replaces `wav_trim_tests`; `capture_realtime_tests` replaces + `realtime_record_tests`. +- **Known open:** `wav_trim.h`'s transitional forwarding shim still has three live includers + (`sample_map.h`, `editor_session.cpp`, `processor_reload.cpp`) — repoint-and-retire is a named + follow-up; `ingest.cpp` trimmed to 567 LOC but keeps the `namespaces.h` shim (`ingest` + `view` + remain the shim's unowned consumers). diff --git a/PLAN.md b/PLAN.md index 5624d3c..703d1a8 100644 --- a/PLAN.md +++ b/PLAN.md @@ -405,137 +405,74 @@ before/after listening or null check. **The gate to Q-W1 is: triage complete + D > split wave (Q-W2 onward) retires its own includes of it as that module splits. ## Q-W2 — split `bank_panel.cpp` (the biggest extension god-module — 3459 LOC at the Q-W0 census) -**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_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 -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` -§2.1, §5. -**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 -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 -added header→TU indirection on the preview path). The ~20-function public API is now segmented -across the split headers. -**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 → - `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 - virtual; preview idle path unchanged.** -- [ ] Split input handling (mouse/key/wheel) + new-content detection → `panel_input`; 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 - `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; all eight TUs - under the ~600 ceiling. +> **Landed on `phase-q` (2026-07-29, merge of `pq-w2-panel`). Integrated suite 61/61 green, +> reviewed-approved.** `bank_panel.cpp` (3459 LOC) split into eight TUs under `shell/panel/`: +> `panel_render` / `panel_thumbnails` / `panel_audition` / `panel_input` / `panel_bank_ops` / +> `panel_window` / `panel_layout` / `panel_drag`, plus per-seam public headers and internal +> `panel_state.h`; audition stays a direct call-through; the one-bank-op-one-undo invariant is +> preserved; ~50 TU-private helpers wrapped in anonymous namespaces (a review follow-up). See +> `COMPLETED.md` for the full narrative. +> +> **Recorded ceiling overages (reviewer-endorsed, preserved as a durable record per CONTEXT's +> "silent overshoot is not legitimate" rule):** `panel_input.cpp` 636, `panel_render.cpp` 613, +> `panel_state.h` 608 — the overage is comment volume; non-comment lines are ~322–369 per file; +> no honest seam remains; bisection was rejected. +> +> **Review note for the Q-W4 planning record:** `panel_bank_ops`'s verbs still embed +> prompts/panel-state nudges — Q-W4's dedupe needs promptless inner verbs (`renameBank(id,name)` +> etc.), not a call-site swap; `promptText`/`mintBankId` are byte-identical twins with +> `actions.cpp` and are the cheapest first dedupe. +> +> **In-DAW verification (panel parity) is PENDING on `phase-q`** — deferred by design, not yet +> performed. ## 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. +> **Landed on `phase-q` (2026-07-29, merge of `pq-w2v-vst`). Integrated suite 61/61 green, +> reviewed-approved.** `reasampler_editor.cpp` (3084 LOC, the largest file in the repo) split +> into eight face-axis TUs under `shell/instrument/`, with pure layout hoisted into +> `core/instrument/ui/editor_geometry` (discharges T2-06, newly tested); `reasampler_processor.cpp` +> split into `processor_state` / `processor_reload` / lifecycle+`process()` kept whole (no +> virtual seam, T4-29); `sample_map` split into a resolution core + `component_state_io` codec +> (the extension preset path no longer links the voice engine — link-proven; T4-13 ≡ T2-07); +> `sampler_core.cpp` stays whole with the documented hot-path exception comment (T4-14/T4-27); +> `zone_params.h` split out; `core/wire/bytes.h` (`putLE`/`ByteReader`) lands (T4-20); +> `ThumbnailKey` adopted (T2-10); a golden full-blob v11 fixture pins the codec bytes. The +> `src/vst/` directory is gone. See `COMPLETED.md` for the full narrative. +> +> **Deferred/known:** `component_state_io.h` still includes `sample_map.h`→`sampler_core.h` +> transitively (T2-07's header half — future work); the `engine` namespace is deferred +> (`sampler_core` stays flat `reasampler`); capture-side LE rewires are left for the capture +> family. +> +> **In-DAW verification (editor/processor parity) is PENDING on `phase-q`** — deferred by +> design, not yet performed. ## Q-W3 — split `main.cpp` (hoist orchestration; leave main = pointers + entry + dispatch) -**Goal:** Reduce `main.cpp` (1897 LOC at the Q-W0 census) to its actual job — API pointers + -`ReaperPluginEntry` + dispatch — by hoisting **four** TUs (T4-02 reshape, SETTLED with Q-5, -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 -`realtime_lifecycle` (the realtime-capture state machine + globals). -**`FxBypassGuard` moves out but stays a stack RAII object (precision-critical); the realtime idle -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. -**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 -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. -`main.cpp` is now pointers + entry + dispatch only. The four hoisted TUs + `wav_codec` land -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 - `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 the realtime-capture lifecycle state machine + globals → `realtime_lifecycle`; - **idle tick stays a single pointer test.** -- [ ] Leave `main.cpp` = API-pointer ownership + `ReaperPluginEntry` + dispatch; move to `app/`. -- [ ] **Naming rider (Q-9 — SETTLED, Daniel 2026-07-28: yes):** align the `capture_realtime` - (shell) / `realtime_record` (pure) word-order inversion to the house shell↔core convention — - the pure module takes the stem `capture_realtime`, the shell takes the suffix - (`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; - CTest green; no realtime-tick branch-shape change. +> **Landed on `phase-q` (2026-07-29, merge of `pq-w3-main`). Integrated suite 61/61 green, +> reviewed-approved.** `app/main.cpp` reduced 1897 → 653 LOC (pointers + entry + dispatch; the +> remaining bulk is the registration residue Q-W6 dissolves) via four hoists into +> `shell/capture/`: `capture_orchestrator`, `capture_batch`, `scope_resolve`, +> `realtime_lifecycle`; `FxBypassGuard` moved intact as a stack RAII object; the realtime idle +> tick stays a single pointer test; `ICaptureBackend` deleted (T4-26) with the +> CLAUDE.md/CONTEXT-ARCHIVE corrections landed in the same commit; the Q-9 rename done (pure +> `core/capture/capture_realtime`, shell `capture_realtime_shell` + `capture_realtime_finalize` +> split, T4-08); `stampCaptureSample` dedupe (T2-09, divergent time-sig behavior preserved via +> caller arg); `makeUniqueTag` gains a per-session monotonic counter (T1-11 behavior fix — stems +> now `-` / `rt--`; the per-process residual is documented in-code); one pure +> `wav_codec` RIFF owner absorbs `wav_trim` + `ingest`'s WAV build + content hashes, with golden +> hash literals pinned (`wav_codec_tests` replaces `wav_trim_tests`; `capture_realtime_tests` +> replaces `realtime_record_tests`). See `COMPLETED.md` for the full narrative. +> +> **Known open:** `wav_trim.h`'s transitional forwarding shim still has three live includers +> (`sample_map.h`, `editor_session.cpp`, `processor_reload.cpp`) — repoint-and-retire is a named +> follow-up; `ingest.cpp` is trimmed to 567 LOC but keeps the `namespaces.h` shim (`ingest` + +> `view` remain the shim's unowned consumers). +> +> **In-DAW verification (null test, bit-identical repeats) is PENDING on `phase-q`** — deferred +> by design, not yet performed. ## Q-W4 — split `actions.cpp` + dedupe bank verbs against `panel_bank_ops` **Goal:** Split the two unrelated command-id families in one TU (1016 LOC at the Q-W0 census —