Docs: reflect the Design View redesign — EXPOSE replaces the park refusal, FX offlining moved to the reclaimer, undo repair is ours

This commit is contained in:
2026-08-06 23:56:50 -04:00
parent c9c957a3da
commit 2173263bb9
4 changed files with 106 additions and 138 deletions
+4 -4
View File
@@ -867,9 +867,9 @@ public accessor surface. Doing that in the same commit that changed the byte for
the golden test literals pin would roll a format change and a codec extraction
together, which is the riskier order.
**`src/shell/view/view.cpp` is no longer over the bar.** It measures **594 lines**
**`src/shell/view/view.cpp` is no longer over the bar.** It measures **230 lines**
(`wc -l`, re-measured after the undo collapse moved one track's whole park/restore —
snapshot, flags and per-FX offline — into `view_fx_park`'s `parkTrack`/
snapshot, flags and per-FX offline — into `view_park`'s `parkTrack`/
`restoreTrack`). Recorded because the entry above used to name it as a second
over-ceiling file: if it grows again, note that a further seam there is blocked
not by a private-state/friend question but by a build file another team owns —
@@ -885,7 +885,7 @@ sidestepped), dropping the file under the ~600-line ceiling.
## FX-GUID stability for the park's restore is unverified in the DAW
**Context.** The Design View park/restore FX keying (`restoreTrack`,
`src/shell/view/view_fx_park.cpp`) rests on `TrackFX_GetFXGUID` returning an identity that
`src/shell/view/view_park.cpp`) rests on `TrackFX_GetFXGUID` returning an identity that
survives a chain reorder while a track is parked. SWS issue #802 reports that after
`SNM_MoveOrRemoveTrackFX` reorders a chain, the FXID lines do not follow the plugin
(`SNM_PreObjectState()` → `RemoveAllIds()`) — if that still holds, an SWS-driven
@@ -896,7 +896,7 @@ operation this keying targets.
instances of the same plugin.
**Already flagged in code — this entry is the tracked home, not a restatement.**
There is a `[verify — DAW]` marker at `fxGuidString` in `src/shell/view/view_fx_park.cpp` and
There is a `[verify — DAW]` marker at `fxGuidString` in `src/shell/view/view_park.cpp` and
a note in `src/shell/view/CLAUDE.md`'s Gotchas; point at them rather than restating
them in full.
+8 -5
View File
@@ -47,15 +47,18 @@ Checks for Θ, Ξ, Ψ, Ε, Ρ, Γ, and Ω work that no unit test can close. Buil
- [ ] Solo tracks in Arrange, switch to Design, solo different tracks, switch back — each mode restores its own solo set verbatim (`docs/COMPLETED.md` §"Ψ-W1-T2")
- [ ] Attempt a mode switch while the transport is playing, then while recording — both refuse, visibly (`docs/COMPLETED.md` §"Ψ-W1-T2")
- [ ] Click the footer mode segment, save, reopen the project — the mode persisted (`docs/COMPLETED.md` §"Ψ-W1-T2")
- [ ] `[verify — DAW]` Reproduce the strand: project with FX in both modes, switch to Design, save, close, reopen, toggle to Arrange. Toggle back and forth several more times — the arrangement's FX must NOT converge on permanently offline/hidden. A track the tool refuses to park is NAMED in the console, and the same refusal is not reprinted on a later reapply unless the refused set changed (`src/shell/view/view_fx_park.h`'s `decidePark` / `reportRefusedParks`)
- [ ] `[verify — DAW]` **ONE switch, ONE point.** In a project with several FX across several tracks, switch modes once and count the undo points REAPER shows (Ctrl-Z tooltip / undo history): expect exactly ONE, `ReaSampler: activate <mode> view` — never two, and never one per FX. Then press Ctrl-Z once: the flags unpark and EVERY FX comes back online, in that single step. Verify the EFFECT, not merely that one entry exists — a mask that failed to pick up `UNDO_STATE_FX` would still show one correct-looking entry while leaving every plugin offline, which reads as a pass and isn't. Then Ctrl-Y: the redo re-parks all of it, also in one step (`src/shell/view/CLAUDE.md` §Invariants — "ONE mode switch is ONE undo point")
- [ ] `[verify — DAW]` Reproduce the strand: a track with no park record whose live chain already reads park-shaped (hand-offline a plugin, or drop the tool's record via undo/redo), then switch modes — the track is driven visible, in-mix and FX-enabled (not parked), and NAMED in the console once. Switch again with nothing else changed and confirm the same message does NOT reprint (`src/shell/view/view_park.h`'s `parkTrack` / `reportExposedTracks` / `shouldReport`)
- [ ] `[verify — DAW]` **ONE switch, ONE point.** In a project with several FX across several tracks, switch modes once and count the undo points REAPER shows (Ctrl-Z tooltip / undo history): expect exactly ONE, `ReaSampler: activate <mode> view` — never two, and never one per FX. Then press Ctrl-Z once: the flags and lane state unpark in that single step — FX are the reclaimer's and are not part of this undo point (see the item below on undo and FX). Then Ctrl-Y: the redo re-parks the flags and lane state, also in one step (`src/shell/view/CLAUDE.md` §Invariants — "ONE mode switch is ONE undo point")
- [x] **VERIFIED — the discard-block mint-suppression premise.** Ten unblocked `TrackFX_SetOffline` calls minted ten undo points; the same ten calls wrapped in `Undo_BeginBlock2(p)` … `Undo_EndBlock2(p, "", 0)` minted zero. This is what the reclaimer's per-write discard block (`fx_reclaim.cpp`'s `writeOffline`) and the off-switch FX design both rest on — no longer an unobserved inference (`src/shell/view/CLAUDE.md` §Invariants — "ONE mode switch is ONE undo point")
- [ ] `[verify — DAW]` Whether a `SetProjExtState` issued from inside `SaveExtensionConfig` reaches the `<EXTSTATE>` block of the file being written now, or lands one save later (`src/shell/view/fx_reclaim.h`'s `ReleaseFlush`, `fx_reclaim.cpp`'s `fxReclaimFlushRelease`)
- [ ] `[verify — DAW]` Whether an undo (Ctrl-Z) of a mode switch now restores visibility correctly, now that FX offline/online moved off `applyMode`'s block onto the reclaimer — a Ctrl-Z rolls back only the flags and lane state, not whatever the reclaimer had (or had not) converged (`src/shell/view/CLAUDE.md` §Gotchas — "An UNDO of a mode switch no longer rolls back FX at all")
- [ ] `[verify — DAW]` **Where the `view_state` lands on undo AND redo, and whether the redo strands a track.** `persistViewState` writes the ext state AFTER `applyMode`'s block closes, so the point never saw the new `view_state` — the undo direction is expected to come out right by position, the redo direction is the open one. Use a project with FX on the tracks that park. After the Ctrl-Z above, read the footer segment: it must show the mode the user came FROM, and a further switch must bank solos under that mode id. Then Ctrl-Y and read it again: if the tracks re-park while the footer still shows the pre-switch mode, the redo restored the stale ext state and model-vs-project is out of step. **Then switch modes ONCE MORE and read the console** — the hypothesised consequence is a `left unparked` refusal line naming those tracks, because the redo-restored model carries no snapshot for a chain that reads parked. A clean switch with no refusal line kills the hypothesis; the line appearing confirms a NEW refusal route and the persist position has to be reopened. Report which, and the footer state at each step. Do NOT fix by moving `persistViewState` inside the block — it can open a modal Save-As (`src/shell/view/CLAUDE.md` §Gotchas)
- [ ] `[verify — DAW]` **No point on open.** Open a project saved in Design mode with every inactive leaf already fully parked (flags AND FX), and check the undo history: the load-tick reapply writes nothing, so it must add NO undo point at all — the `("", 0)` discard form. This only holds when the saved state really was fully parked; a first open after tagging a new leaf, an FX added to a parked track, or a plugin hand-onlined since the last save all have real state to write and legitimately mint one correct point. An entry appearing on a project that WAS fully parked means the discard is not working — and since `mintManagedLanes`' no-op path rests on the same idiom, check that alongside it (`src/shell/view/view.h`'s `applyMintsUndoPoint`)
- [ ] `[verify — DAW]` **The hitch now sits on the switch.** On a project with heavy plugins (convolution, a loaded sampler) across several parked tracks, time the mode toggle: by design the action does not return until every plugin has unloaded/reloaded. Report roughly how long, and whether the UI recovers cleanly afterwards — the whole write phase runs under one `PreventUIRefresh(1)` hold (`src/shell/view/CLAUDE.md` §Invariants — the documented caveat)
- [ ] `[verify — DAW]` **Nested blocks around the FX writes.** Two directions, both undocumented in the SDK header. (a) `render_in_place` calls `applyMode` inside its OWN undo block, so its single `ReaSampler: render selected track to a new track` point should now absorb the reapply's FX moves — run that verb from Design mode over a track with FX and confirm ONE point, not two, and that Ctrl-Z reverses all of it. (b) The inverse: fire a mode-switch action WHILE a switch's plugin loads are in flight (a heavy chain widens the window) — `applyMode` is latched, so the expected outcome is that the second switch is DROPPED entirely and silently; the history must show one point, and the footer must still read the first switch's target. Re-firing it afterwards must work normally. (c) The same window, but let `OnTimer` -> `bankPanelRefresh` -> `mintManagedLanes` run into it: that path is NOT latched and opens a block of its own, so check the history for a split or misordered point (`src/shell/view/CLAUDE.md` §Gotchas)
- [ ] `[verify — DAW]` **The switch itself returns fast; the hitch moved to the reclaimer.** On a project with heavy plugins (convolution, a loaded sampler) across several parked tracks, time the mode toggle action itself — it no longer waits on any plugin load/unload, so it should return near-instantly. Then watch the background reclaim: once a track has read continuously parked for `kParkHoldMs` (3s), the reclaimer moves it in budgeted ticks (`kOnlineBudgetMs`/`kOfflineBudgetMs`) — report whether those ticks are noticeable/disruptive to the UI while they run (`src/shell/view/CLAUDE.md` §Invariants — the documented caveat, `fx_reclaim.h`'s `kOnlineBudgetMs`/`kOfflineBudgetMs`)
- [ ] `[verify — DAW]` **Nested blocks around the flag/lane writes.** Two directions, both undocumented in the SDK header (`applyMode` no longer writes FX at all — that moved to the reclaimer, off this block entirely). (a) `render_in_place` calls `applyMode` inside its OWN undo block, so its single `ReaSampler: render selected track to a new track` point should absorb the reapply's flag/lane writes — run that verb from Design mode over a track with FX and confirm ONE point, not two, and that Ctrl-Z reverses all of it. (b) The inverse: fire a mode-switch action WHILE a switch's plugin loads are in flight (a heavy chain widens the window) — `applyMode` is latched, so the expected outcome is that the second switch is DROPPED entirely and silently; the history must show one point, and the footer must still read the first switch's target. Re-firing it afterwards must work normally. (c) The same window, but let `OnTimer` -> `bankPanelRefresh` -> `mintManagedLanes` run into it: that path is NOT latched and opens a block of its own, so check the history for a split or misordered point (`src/shell/view/CLAUDE.md` §Gotchas)
- [ ] `[verify — DAW]` **The load reapply is never lost to the latch.** Open a project saved in Design mode with heavy plugins on parked tracks (so an apply is long) while another apply can overlap — e.g. trigger a project open from an action fired during a switch. The saved mode must still be applied: the load glue tests `modeApplyInProgress` before spending its one-shot signal and retries on the next timer tick, so a delayed-by-a-tick reapply is a pass and a never-applied one is a failure (`src/app/main.cpp`'s load glue, `src/shell/view/view.h`'s `modeApplyInProgress`)
- [ ] `[verify — DAW]` **A tab switch mid-apply cannot split the block.** `applyMode` pins the project once at entry and threads it through `Undo_BeginBlock2`/`Undo_EndBlock2`/`ValidatePtr2`. With a long switch in flight, switch project tabs (the pump premise makes this reachable) and confirm the undo point lands on the project the switch started in, with nothing written into the other tab (`src/shell/view/view.cpp`'s `applyMode`)
- [ ] `[verify — DAW]` **A→B→A costs two full cycles.** Toggle Arrange→Design→Arrange quickly on a project with heavy plugins: every plugin unloads and reloads twice, where the retired intent queue made a fast double-toggle free. Confirm the END STATE is still correct (every FX online, every driven flag back at its captured value) and report whether the doubled cost is tolerable in practice (`src/shell/view/CLAUDE.md` §Invariants — the A→B→A bullet)
- [ ] `[verify — DAW]` **A fast A→B→A moves zero plugins; a held one costs a cycle each way.** Toggle Arrange→Design→Arrange quickly (well inside `kParkHoldMs`, 3s) on a project with heavy plugins — the debounce should mean nothing ever unloads: confirm the END STATE is correct (every FX online, every driven flag back at its captured value) and that the reclaimer reports no writes. Then repeat holding each side past 3s before flipping back and confirm the reclaimer now does converge each leg (offline while parked, online again on return), reporting whether that cost is tolerable in practice (`src/shell/view/CLAUDE.md` §Invariants — "A rapid A→B→A flip moves zero plugins", `fx_reclaim.h`'s `kParkHoldMs`)
- [ ] `[verify — DAW]` For a track the console names as left unparked, follow the message's recovery IN FULL: re-enable its TCP/mixer visibility, main send and FX enable, **and set every FX in its chain online** (FX enable is the chain bypass — it does not bring an individually offlined FX back). Then switch modes twice: it parks and restores normally, with no further console line. Do the flag half ONLY on a second such track and confirm it is still refused — the FX half of the trust test, and the reason the message spells the step out (unit-tested only as a decision, never against a live chain)
## Actions and drops