docs: reflect D2-W2 landing in PLAN.md / COMPLETED.md

Remove D2-W2 from PLAN.md; append completed entry to COMPLETED.md.
Track-level auto-tag/park live; item-lane DAW verify deferred to
post-D2-W3 (lane minting). D2-W3 left open.
This commit is contained in:
2026-07-23 18:30:43 -04:00
parent ae0e76bff7
commit 4241ef4408
2 changed files with 81 additions and 63 deletions
+80
View File
@@ -284,6 +284,51 @@ round-trip of the lane index. REAPER-free, unit-tested; mirror of D1. CONTEXT.md
--- ---
## D2-W2 — shell: lane application + new-content detection
**Goal:** The view shell applies the planner's managed-lane ops in the DAW and the
bank_panel timer detects new content and auto-tags it to the active mode. Resolves
the two flagged implementation design points (I_FIXEDLANE reorder/renumber
fragility; the auto-tag / manual-lane detection heuristic). See CONTEXT.md
§Two-canvas sub-phase (Module architecture — shell; New-content detection).
**Verify (in DAW):** Toggling a mode shows + plays only the active mode's managed
lane, hides + silences the inactive-mode lane, and **never touches a manual lane**
(its `C_LANEPLAYS` stays exactly as the user set it); new content created while a
mode is active is tagged to that mode; pre-existing content stays Arrange (no
mass-tag on the first poll after open).
**Depends on:** D2-W1.
- [x] Apply managed-lane ops in the view shell (`I_FREEMODE`/`I_FIXEDLANE`/
`C_LANEPLAYS`/`B_FIXEDLANE_HIDDEN` via the item/track info setters;
`UpdateTimeline()` after `I_FREEMODE`); **managed lanes only, never manual**.
Verify every flag name/signature against the SDK header.
- [x] New-content detection on the bank_panel timer: diff the live track/item GUID
set against the previous poll; tag any GUID new since the last poll to the
then-active mode, with a **first-poll-after-open guard** (pre-existing ⇒ Arrange,
no mass-tag) and the **manual-lane exemption** (items in a manual lane not tagged).
- [x] Resolve the manual-lane detection heuristic (which new items are exempt) and
the `I_FIXEDLANE` lane-identity fragility (index survival across lane
reorder/renumber/deletion) — the two open design points from CONTEXT.md.
- [x] D2-W1 review polish: document the one-managed-lane-per-mode-per-track
exclusivity assumption in `laneModeState` (comment / debug-guard); clarify the
`serialize()` one-line style note; optional round-trip tests for the
last-writer-wins lane-replace contract.
**Notes/decisions:**
- Two new pure modules added with unit tests: `guid_diff` (diffs live track/item
GUID sets between polls) and `lane_keys` (manages lane identity via durable
`P_LANENAME` rather than the renumber-prone `I_FIXEDLANE` ordinal, reconciled each
apply — the resolution to the lane-identity fragility design point). CTest green.
- **Manual-lane protection:** a single pure predicate `isOnManualLane` is the
exclusive gate; manual lanes — including REAPER's default unnamed fixed lanes —
are provably never driven or auto-tagged.
- **Track-level auto-tag and park behavior is live.** Item-lane show/hide is
correctly structured but is a provable no-op on real projects until D2-W3 mints
the `reasampler:`-prefixed named lanes. End-to-end DAW verification of item-lane
show/hide is sequenced after D2-W3 for this reason.
- W1 review polish was folded in during this wave.
---
## Milestone 7 — capture action family ## Milestone 7 — capture action family
**Goal:** Bindable capture actions for master / selected tracks / selected items / **Goal:** Bindable capture actions for master / selected tracks / selected items /
razor area, each with wet-dry + tail options. CONTEXT.md §actions, Build order 7. razor area, each with wet-dry + tail options. CONTEXT.md §actions, Build order 7.
@@ -433,3 +478,38 @@ path.
- **Follow-ons noted, not done:** Manual fine-adjust UI; per-project persistence of - **Follow-ons noted, not done:** Manual fine-adjust UI; per-project persistence of
the toggle (currently extension-session lifetime, resets to None on unload); T2 the toggle (currently extension-session lifetime, resets to None on unload); T2
realtime tail. realtime tail.
---
## T2 — realtime tail (follow-on to T1)
**Goal:** The parallel tail path for the M8 realtime backend, which does not drive
`RENDER_*`: record an 8 s-capped tail window past the range end, then **trim in a
PCM decay-scan** to the -72 dB point (Manual = record fixed tail, skip the scan).
See `docs/product/capture-tail.md` §The realtime path.
**Verify (in DAW):** A realtime Auto capture of a decaying source records ≥ the range
then trims at the -72 dB decay point (± inherent realtime tolerance); realtime tail is
**not** asserted bit-identical (documented non-determinism).
**Depends on:** T1, M8.
- [x] Record `[start, end + clamp(tail, 8 s)]` (extend the record time selection in
`capture_realtime.cpp`); Manual skips the scan, Auto proceeds to it.
- [x] Pure decay-scan helper alongside `peaks`: `lastFrameAboveThreshold(interleaved,
channels, frames, linearThreshold) -> frameIndex` (backward scan, per-frame max-abs
across channels, no fold); unit-tested with a synthetic decaying ramp. (Spec §realtime
path option (a) — recommended over bending `computeEnvelope`.)
- [x] Realtime shell: read the recorded wav PCM into a float buffer, find the trim
frame, rewrite the file truncated (new I/O the backend does not do today).
**Notes/decisions:**
- New pure module `wav_trim` (`src/wav_trim.{h,cpp}`): 32-bit-float WAV parse + header-aware
truncate plan (RIFF/data size rewrite). Rejects WAVE_FORMAT_EXTENSIBLE with non-float
SubFormat GUID. Depends on `peaks` for the `AudioSample` float alias. Unit-tested via a
new `wav_trim_tests` CTest target.
- `peaks` gained `lastFrameAboveThreshold` (backward PCM scan, per-frame max-abs across
channels, no fold) for the Auto decay scan.
- **Auto/Manual/Off semantics.** Auto: records `[start, end + 8 s cap]`, scans backward
for the last frame above -72 dBFS, truncates the WAV header-aware at that frame. Manual:
records `[start, end + fixed tail]`, skips the scan. Off: byte-identical to the pre-tail
exact-bounds capture.
- **Realtime tail is non-deterministic by design** (inherent to the realtime backend).
Bit-identical repeats are not asserted for the realtime path; this is documented, not a defect.
+1 -63
View File
@@ -65,39 +65,6 @@ landed milestone.
--- ---
# Milestone T — capture tail (rider on the offline render path)
> **Rider, not a new pillar.** Tail preservation wires into the already-shipped
> offline `OfflineRenderBackend` (M3/M7) — no new backend, no new render trigger.
> It takes a **T** tag (not an M-number) because it is an enhancement to landed
> capture, sequenced independently of M8M11. Authoritative spec:
> **`docs/product/capture-tail.md`** (full `RENDER_*` values, the surgical
> `RENDER_NORMALIZE`, the realtime parallel path, invariant interactions,
> acceptance criteria, DAW-confirm items). Parameters set by Daniel: auto-trim
> threshold **-72 dB**, max-tail cap **8 s**. When a point lands, doc-keeper moves
> it to `COMPLETED.md`.
## T2 — realtime tail (follow-on to T1)
**Goal:** The parallel tail path for the M8 realtime backend, which does not drive
`RENDER_*`: record an 8 s-capped tail window past the range end, then **trim in a
PCM decay-scan** to the -72 dB point (Manual = record fixed tail, skip the scan).
See `docs/product/capture-tail.md` §The realtime path.
**Verify (in DAW):** A realtime Auto capture of a decaying source records ≥ the range
then trims at the -72 dB decay point (± inherent realtime tolerance); realtime tail is
**not** asserted bit-identical (documented non-determinism).
**Depends on:** T1, M8.
- [ ] Record `[start, end + clamp(tail, 8 s)]` (extend the record time selection in
`capture_realtime.cpp`); Manual skips the scan, Auto proceeds to it.
- [ ] Pure decay-scan helper alongside `peaks`: `lastFrameAboveThreshold(interleaved,
channels, frames, linearThreshold) -> frameIndex` (backward scan, per-frame max-abs
across channels, no fold); unit-tested with a synthetic decaying ramp. (Spec §realtime
path option (a) — recommended over bending `computeEnvelope`.)
- [ ] Realtime shell: read the recorded wav PCM into a float buffer, find the trim
frame, rewrite the file truncated (new I/O the backend does not do today).
---
# Phase D2 — Two-canvas (item-level mode projection; additive to D1) # Phase D2 — Two-canvas (item-level mode projection; additive to D1)
> **Design View sub-phase.** Extends D1's track-level mode projection to **item > **Design View sub-phase.** Extends D1's track-level mode projection to **item
@@ -111,36 +78,7 @@ then trims at the -72 dB decay point (± inherent realtime tolerance); realtime
> spec. Product framing: `docs/product/design-view.md` §Two-canvas direction. When a > spec. Product framing: `docs/product/design-view.md` §Two-canvas direction. When a
> point lands, doc-keeper moves it to `COMPLETED.md`. > point lands, doc-keeper moves it to `COMPLETED.md`.
> >
> **D2-W1 (pure lane extension) has landed** — see `COMPLETED.md`. > **D2-W1 (pure lane extension) and D2-W2 (shell: lane application + new-content detection) have landed** — see `COMPLETED.md`.
## D2-W2 — shell: lane application + new-content detection
**Goal:** The view shell applies the planner's managed-lane ops in the DAW and the
bank_panel timer detects new content and auto-tags it to the active mode. Resolves
the two flagged implementation design points (I_FIXEDLANE reorder/renumber
fragility; the auto-tag / manual-lane detection heuristic). See CONTEXT.md
§Two-canvas sub-phase (Module architecture — shell; New-content detection).
**Verify (in DAW):** Toggling a mode shows + plays only the active mode's managed
lane, hides + silences the inactive-mode lane, and **never touches a manual lane**
(its `C_LANEPLAYS` stays exactly as the user set it); new content created while a
mode is active is tagged to that mode; pre-existing content stays Arrange (no
mass-tag on the first poll after open).
**Depends on:** D2-W1.
- [ ] Apply managed-lane ops in the view shell (`I_FREEMODE`/`I_FIXEDLANE`/
`C_LANEPLAYS`/`B_FIXEDLANE_HIDDEN` via the item/track info setters;
`UpdateTimeline()` after `I_FREEMODE`); **managed lanes only, never manual**.
Verify every flag name/signature against the SDK header.
- [ ] New-content detection on the bank_panel timer: diff the live track/item GUID
set against the previous poll; tag any GUID new since the last poll to the
then-active mode, with a **first-poll-after-open guard** (pre-existing ⇒ Arrange,
no mass-tag) and the **manual-lane exemption** (items in a manual lane not tagged).
- [ ] Resolve the manual-lane detection heuristic (which new items are exempt) and
the `I_FIXEDLANE` lane-identity fragility (index survival across lane
reorder/renumber/deletion) — the two open design points from CONTEXT.md.
- [ ] D2-W1 review polish: document the one-managed-lane-per-mode-per-track
exclusivity assumption in `laneModeState` (comment / debug-guard); clarify the
`serialize()` one-line style note; optional round-trip tests for the
last-writer-wins lane-replace contract.
## D2-W3 — actions, persist wiring, panel UI ## D2-W3 — actions, persist wiring, panel UI
**Goal:** Any new lane/mode-management actions, the persist slice serializing the **Goal:** Any new lane/mode-management actions, the persist slice serializing the