docs(phase-q): record Q-W2 + Q-W2v + Q-W3 landings — points to COMPLETED.md; ceiling overages recorded, in-DAW verification marked pending, Q-W4 dedupe-shape notes preserved

This commit is contained in:
2026-07-29 11:43:22 -04:00
parent 3bcd4dcc7b
commit 5232227323
2 changed files with 234 additions and 124 deletions
+173
View File
@@ -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 ~322369 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).
+61 -124
View File
@@ -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 ~322369 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 `<epoch>-<n>` / `rt-<epoch>-<n>`; 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 —