# 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.
