Split root CLAUDE.md into 19 per-directory files scoped to their source area. Roll v0 history into docs/ARCHIVE.md; retire CONTEXT.md, CONTEXT-ARCHIVE.md, PLAN.md, COMPLETED.md. Move plan docs under docs/. Rescue 9 live deferrals into docs/TODO.md.
14 KiB
TODO
Forward-looking follow-ups. Deferred by decision, not oversight — each entry records why it was deferred and what "done" looks like.
Persist ReaSampler 9000 instance identity to let prune reclaim de-referenced captures after reopen
Context (what shipped — Phase S usage-detection). Each ReaSampler 9000 instance publishes the captures it holds to project ext-state (rsusage_<guid> keys, ComponentState v11). The extension's prune reads those records and unions every live instance's held captures into the referenced-set, so a capture any live instance holds can never be pruned. Fail-safe: unreadable/ambiguous usage state aborts prune (deletes nothing). Airtight on safety.
The wart. The per-instance identity token is minted fresh each incarnation and is NOT persisted. After save→reopen, an instance cannot recognize its OWN prior-session usage record — it looks foreign, so the instance defensively unions and marks the record append-only (poisoned). Net effect: after any reopen, prune stops reclaiming captures an instance once loaded but no longer uses. Safe (never deletes a used capture), but the bank folder grows without bound.
Intended fix. Persist the instance identity in ComponentState so an instance recognizes its own last-session record and does a clean-replace instead of union/poison → prune reclaims de-referenced instance-touched captures normally.
The constraint the fix MUST handle (why deferred). VST3 provides no stable per-instance identity, and Ctrl+D / in-place FX duplication clones plugin state. A persisted identity is inherited by an in-place duplicate → two live instances in one project share one rsusage_<guid> key. Harmless while both hold the same capture; the risk is a divergent clone — the copies load DIFFERENT captures, and last-writer-wins drops the other's held capture from the record, exposing it to prune. The fix must detect a genuine live same-identity collision and protect the union in that case, WITHOUT reintroducing the sibling-drop bug the fresh-per-session token was originally added to prevent. (Whole-project copies are a non-issue — bank files are cloned with the project and ext-state is per-project.)
Priority / risk. Low / deferred. Current behavior is safe; the only cost is unbounded bank-folder growth after reopens. Decided 2026-07-28 to ship the safe version and defer this.
Done looks like. Save → reopen → de-reference a capture from an instance → prune reclaims it. And: in-place-duplicate + diverge + delete-from-bank never deletes a capture a live instance holds.
Isolate capture from out-of-scope aux/parallel sends, not just FX/gain/pan
Context (carried from PLAN.md's "Open questions to resolve during build"). The FX-scope capture neutralizes out-of-scope FX, gain, and pan for both item and track scope — root CLAUDE.md's "Capture FX scope" precision invariant states this precisely: the out-of-scope chain (ancestors + master track, plus the item's own track for item scope) has its FX, gain, and pan/width/pan-law/mode neutralized to unity. Aux/parallel sends are conspicuously absent from that enumerated list — the invariant as currently written does not cover them, which is the gap this item exists to close.
The wart. A downstream coloring send (e.g. a folder → reverb-track send) still routes and blends into an item/track capture, past the intended isolation point. Repro from PLAN.md: folder F1; T1 (MIDI) sends MIDI to T2 (synth); T1+T2 → F1; F1 sends to reverb T3; capturing the MIDI item on T1 currently includes the reverb, but should be isolated to T2's synth output pre-F1 with the MIDI send preserved and the reverb send excluded.
Intended fix. Likely approach (PLAN.md): snapshot + mute out-of-scope tracks' aux sends during the render while preserving the main/source signal path.
The constraint the fix MUST handle. Distinguish source routing that must be preserved (e.g. a MIDI send T1→T2 where T2's synth is where a MIDI item's audio is actually produced — the "item level" for that MIDI item is T2's synth output) from coloring sends that must be excluded (folder→reverb). PLAN.md notes this is "the hard part" and that a rule is needed for which sends are load-bearing.
Settled rule (Daniel, 2026-07-29). The classification rule for which sends are load-bearing: (1) ancestor sends are excluded from the capture — the folder parent is up the folder tree but downstream in signal flow, so this item deliberately says "ancestor," not "upstream," which would read backwards to anyone applying signal-flow convention; (2) sibling sends are preserved and captured — a sibling is a track sharing the capture scope's parent; (3) if the send's destination has a different parent, ignore it in the capture — it isn't a sibling, so it isn't captured. Applied to the repro above: the T1→T2 MIDI send is a sibling send (T1 and T2 share parent F1) and is preserved — T2's synth is where the item's audio is actually produced; the F1→T3 reverb send is an ancestor send and is excluded. This resolves the repro.
Still open. The rule above settles which sends to mute, but the repro is only fully resolved together with a second, unspecified lever — where the capture taps. PLAN.md's own framing of this open question says a true item-level capture should be taken "at the isolated graph point — the target scope's output before out-of-scope track FX/gain/pan and before out-of-scope aux/parallel sends." How the mute-rule above and the tap-point interact is not yet specified.
Priority / risk. Not stated in PLAN.md (recorded there as an open (TODO) question, not yet triaged to a priority). Flagged here as mattering more than the other four carried-over items because it exposes a live gap in a stated precision invariant, not just a deferred feature.
Done looks like. Capturing the MIDI item on T1 in the repro above is isolated to T2's synth output pre-F1 — the T1→T2 MIDI send is preserved and the F1→reverb send is excluded — and the CLAUDE.md "Capture FX scope" invariant's neutralization list is extended to name sends explicitly.
Confirm REAPER's VST3 UID-vs-filename instance rebind behavior (Phase S compat verification)
Context. PLAN.md, under "Phase S — product name (ReaSampler 9000)": the working assumption is that REAPER rebinds a saved instance by its VST3 class UID, not by the module filename, so a filename rename with an unchanged UID keeps saved projects working (existing instances still resolve).
The wart. This is not yet confirmed from source — PLAN.md records that a web check surfaced a JUCE/VST3-replace-VST2 case suggesting REAPER's binding is more nuanced than "UID only" (it can involve an FXID match), so UID-rebind is to-verify, not asserted fact.
Intended fix / required check. DAW-verify: save a project with a ReaSampler 9000 instance under the old filename, rename the module, reopen — confirm the instance rebinds and restores its state.
The constraint the fix MUST handle. If REAPER does key partly on filename, the fallback is to keep the current filename (display-strings-only) and record that as the shipped choice.
Priority / risk. Marked "must-DAW-verify before shipping the rename" in PLAN.md; no explicit priority level stated beyond that.
Done looks like. The save→rename→reopen DAW check is performed and its result (rebind confirmed, or filename-revert fallback taken) is recorded.
S13 — cross-artifact ingest relay (deferred, spike verdict DEGRADED)
Context. PLAN.md records the ps-w12 (2026-07-27) spike verdict: DEGRADED — relay deferred. The instrument's REAPER bridge (reaper_bridge) is deliberately READ-ONLY; a relay would need a new instrument WRITE seam into ext-state and an extension-side timer poller servicing a drop-ingest inbox key with a claim/clear nonce — the same cross-process handshake race the S17 spec rejected for alternative (A). The shipped ingest gesture stays drop-onto-docked-panel (S8); the editor shows a "drop files onto the ReaSampler bank panel to add them" affordance as the degrade path.
The wart. Dropping a file directly onto the editor/instrument does not ingest it into the bank — only drop-onto-docked-panel does.
Intended fix. The editor hands the dropped path + this instance's identity to the extension as a bank-ingest request over an agreed seam.
The constraint the fix MUST handle. Requires (a) a new instrument WRITE seam into ext-state (breaking the current read-only-bridge invariant) and (b) an extension-side timer poller + claim/clear nonce — both are load-bearing design calls that need to be made deliberately, not as a call-site patch. Both the read-only-instrument boundary and the new poller were judged load-bearing enough that the relay is deferred to a future wave rather than pushed through now.
Priority / risk. PLAN.md marks this DEFERRED, awaiting a future wave, with no priority assigned.
Done looks like. Not stated in PLAN.md beyond "a future wave when the design is ready."
Phase D2 — per-track lane/mode-state panel indicator (deferred)
Context. PLAN.md: Phase D2 is functionally complete (D2-W1, D2-W2, D2-W3-A, D2-W3-B all landed). One item was deferred out of that completion: a panel UI indicator for per-track lane/mode state (a per-track lane-split marker).
The wart. The mode switch already shows the active mode, but there is no per-track indicator; PLAN.md records that no natural cheap home for one was found in the bank panel.
Intended fix. Not specified in PLAN.md beyond the goal (a per-track lane-split marker in the bank panel) — the design is unresolved, which is part of why it was deferred rather than built.
The constraint the fix MUST handle. Finding a home for the indicator in the bank panel's existing layout, which PLAN.md notes doesn't currently have a natural cheap spot for it.
Priority / risk. Not stated in PLAN.md. PLAN.md's own framing: "Explicitly deferred — not silently dropped. Can be picked up later if wanted."
Done looks like. Not stated in PLAN.md.
FX-GUID keying for restoreFxOffline (Design View park/restore)
Context. CONTEXT.md's "Open questions to resolve during build" (Design View section): the bulk of reconcile residuals shipped (ViewModeModel::reconcile(liveGuids) prunes orphaned snapshots on every toggle/load; folder restructure is self-healing because the tree is rebuilt each toggle; membership is intentionally kept so undo-delete preserves the tag). Two sub-items were left deferred out of that; this is the first.
The wart. restoreFxOffline currently restores per-FX offline state by slot index. If the FX chain is reshuffled while a track is parked, restore lands on whatever plugin now occupies that slot rather than the plugin it was originally captured from.
Intended fix. FX-GUID keying — key the per-FX offline snapshot entries by FX identity rather than slot index.
The constraint the fix MUST handle. The keying change requires a snapshot-schema migration; CONTEXT.md names this alongside the keying change as the reason the fix was deferred rather than folded into the reconcile-residuals work.
Priority / risk. Not stated in the source.
Done looks like. Not stated in the source beyond the fix description above.
Dormant membership entries in persisted view_state
Context. CONTEXT.md's "Open questions to resolve during build" (Design View section), the second of the two sub-items left deferred after the reconcile-residuals ship described above.
The wart. Truly-deleted tracks accumulate stale entries in persisted view_state.
Intended fix. A future user-initiated "compact" action to remove the stale entries.
The constraint the fix MUST handle. Must NOT be automatic pruning — automatic pruning would reintroduce the undo-delete tag-loss that the deliberate membership-retention was designed to prevent.
Priority / risk. Not stated as a priority level; the source characterizes the wart itself as "harmless and bounded."
Done looks like. Not stated in the source beyond "a future user-initiated 'compact' action."
Confirm no fight between Design View flags and screenset recall
Context. CONTEXT.md's "Open questions to resolve during build" (Design View section): Design View drives the same track flags a screenset recall would drive, and last writer wins between the two.
The wart. Not a defect — this is a verification task, not a code change. The open concern is confirming there is no surprising interaction between Design View's flag-driving and an active screenset recall.
Intended fix. N/A — no fix is proposed; the task is to confirm no surprising fight between the two mechanisms.
The constraint the fix MUST handle. N/A — verification only.
Priority / risk. Not stated in the source.
Done looks like. Not stated in the source beyond "confirm no surprising fight."
Active-bank indicator placement (B4 polish)
Context. CONTEXT-ARCHIVE.md's "Open questions to resolve during build" (B4 panel section): forks 1–5 are all settled; one panel-polish detail remains open. Fork 4 already settled that the active-bank indicator must be "visually unmistakable" — only its placement is undecided.
The wart. No placement chosen yet among three candidates: per-region headers, a single header readout, or a lit-tab treatment.
Intended fix. Not stated in the source beyond the three candidate placements above — the choice among them is the open item. This is explicitly a panel-polish detail.
The constraint the fix MUST handle. Not stated in the source.
Priority / risk. Not stated as a priority level; the source characterizes this as a "panel-polish detail."
Done looks like. Not stated in the source beyond choosing one of the three placement options.