Put the FX reclaimer to sleep on a project-state load instead of waking it

abandon() clears the wakeup where invalidate() raises it, so File > Revert
cannot converge FX or spend park records against a model nothing re-read.
This commit is contained in:
2026-08-07 14:23:56 -04:00
parent 39b995e824
commit 67d9ec3da9
4 changed files with 106 additions and 9 deletions
+16
View File
@@ -113,6 +113,22 @@ decide membership or mode rules.
`abandon`. Daniel's ruling, and the accepted cost: undoing a switch mid-drain leaves
a PARTIAL park — some FX offlined, some not — covered by the one point the
terminator closed.
- **A state load puts the reclaimer to SLEEP; only a re-read of the model wakes it.**
`abandon` clears the wakeup where `invalidate` raises it, because the two say
different things: an invalidation says the MODEL moved and owes a re-derivation, a
load says the PROJECT moved under a model nobody has re-read yet. `applyMode` is
`invalidateFxReclaim`'s one caller and `fxReclaimPending` gates the tick that is the
one path to any FX write or park-record spend, so every load that re-reads the model
wakes the loop on the same tick, through the reapply the reload drives — and a load
that re-reads nothing wakes nothing. `File > Revert` is exactly that load: same
`ReaProject`, same GUID, same path, so the identity poll answers `NoOp` and the model
is never re-read. Waking there was the only thing that ran, and it converged the FX
chains toward the pre-revert model and spent the park records the reverted project
still needed. The accepted cost of the sleep: an outstanding reclaim in a project
whose interrupting load was some OTHER project's waits for that project's next apply
rather than resuming on the next tick. (That a revert leaves the view model stale at
all is the identity poll's defect, not the reclaimer's — this invariant only keeps the
reclaimer from acting on it.)
- **A reapply that wrote nothing leaves no undo point** — and a reapply never holds
the span open, so a project open, a membership edit and `render_in_place`'s inner
reapply all keep the block shape they had. The load-tick reapply