Both tests pre-dated this branch and failed only on Windows checkouts — the
product code was correct in both cases:
- audio-effects-executor 'preload exposes the trusted surface': asserted a
byte-exact two-line bridge snippet with \n, which never matches a
core.autocrlf (CRLF) working tree. Line endings are now normalized before
the includes checks.
- config-paths 'SAFETY: ... ONLY in optInExtras': rebuilt the expected ML
cache paths with host-native path.join, producing backslash paths that
never equal the forward-slash simulated envs — failing the mlCaches
equality and, worse, making the protected-root child checks vacuously
pass on Windows (a silent coverage gap in the safety assertions). The
test now uses the envs' resolved torchHome/hfHome fields, exactly what
production returns, with '/' as the child separator.
npm test: 78/78 passing (1 quarantined storm gate, green under CHAIN_STORM=1).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The old single monitorMuted atomic had five writers fighting
last-writer-wins: the settings checkbox, startup restore, the executor's
preload read-force-restore, releaseRoute's unconditional setMonitorMute(true)
(which clobbered the user's persisted preference), and the renderer's
song-load suppression (un-refcounted — overlapping windows un-suppressed
each other early).
Native arbiter on SourceChain: userMonitorMute (the preference — checkbox +
restore only), refcounted monitorMuteHolds (force-mute overrides), and
refcounted suppressions (setMonitorMuteSuppressed keeps its bool surface;
true=acquire, false=release, clamped at 0). Effective dry-mute =
(holds || pref) && chain empty && no suppression — the suppressed-beats-muted
precedence is unchanged. New exports: acquire/releaseMonitorMuteHold,
getMonitorMuteState (diag); snapshots regenerated.
Executor rewrite: acquires a suppression (dry-during-load, the default) or a
hold, and releases exactly what it acquired via a single-fire closure that
runs UNCONDITIONALLY (each load owns its acquisition — the stale-snapshot
race against a mid-hold user toggle is structurally gone). releaseRoute no
longer touches mute state at all. The ownership test now pins: preference
API never called, acquire/release balanced.
Renderer callers are unchanged: the checkbox writes the preference as
before, and the song-load suppression sites now compose instead of racing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The JS half of the phase-7a serializer (TLC Part II §1, executor-state
hazard): the executor's stageSlots map (stageId → native slotId) is built at
load time, but any direct loadPreset/clearChain from the audio_engine bundle
or rig_builder's legacy path silently invalidated it — subsequent
setStageBypass/setStageParameter/activateSegment flipped bypass/params on
the WRONG slots or returned no-target with nothing detecting the divergence.
Now: the route records the chainGeneration its load returned; every stage
operation compares it against getChainGeneration() first and reports a
stale-route no-target ('re-load the plan', with expected/current generations)
instead of mutating someone else's chain. loadChainPlan also verifies the
generation didn't move between its loadPreset and the getChainState slot
mapping, rolling back if a foreign write landed in that window. Old addons
without the counter degrade gracefully (checks no-op).
Pinned by a new executor test: fresh route flows, foreign bump → all three
stage ops refuse without touching native slots.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>