Skip to content

Commit b15d859

Browse files
committed
docs(15.1-07a): record three post-UAT stabilization fixes in STATE
Real-DAW UAT on builds 284β†’288β†’289β†’290 caught three 15.1-07a regressions, all rooted in one architectural mistake (slot-picking placed on the run-thread publisher when it belonged on the apply visitor which runs on the audio thread). build 288 (b8ca083) β€” Direction-B stale UI reader (VU dead while audio works); routed UI reads through findRemoteUserSlot β†’ mirror. build 289 (7e69e1a) β€” every-other-interval cutout from XOR shadow. Mitigation: hardcode publisher slot=0. build 290 (00dfee7) β€” random bursty cutout from always-slot-0 dropping data on multi-publish-per-drain. Final fix: apply visitor picks slot per legacy `useidx = !!next_ds[0]` semantic. User-side memory feedback_legacy_invariant_audit.md updated with Direction-C "decision-relocation drift" pattern (decisions whose inputs the new architecture forbids). Full pattern set: Direction A β€” writer drift (legacy mutator outside the publish path) Direction B β€” stale legacy reader (UI reads canonical, not mirror) Direction C β€” decision relocated away from its semantic inputs Phase 15.1-10 mechanical signals still hold (drop-counter zero gates, audit CRITICAL=0, grep audit, TSan ctest), but the TSan-Standalone build 287 used for Signal 1c is pre-stabilization; needs a rebuild before formal UAT.
1 parent e151dd8 commit b15d859

1 file changed

Lines changed: 2 additions & 2 deletions

File tree

β€Ž.planning/STATE.mdβ€Ž

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ See: .planning/PROJECT.md (updated 2026-04-05)
2525

2626
## Current Position
2727

28-
Phase: 15.1 (rt-safety-hardening) β€” IN PROGRESS (all 10 impl plans landed; 15.1-10 mechanical verification GREEN; awaiting bundled human-verify UAT covering 07a/07c/09/08 + phase-close ceremony per CONTEXT D-08)
29-
Plan: 15.1-10 mechanical signals 1a/1b/2/4/5 GREEN (build 287 TSan Standalone). Signal 1a β€” 9/9 RT-safety tests pass under TSan zero reports. Signal 1b β€” NEW test_peer_churn_simulation 1/1 PASS Release + TSan (3 threads Γ— 1000 cycles, drop-counter zero gate enforced in-test). Signal 2 β€” closing audit CRITICAL=0 (12β†’0 across phase), all 21 pre-fix findings dispositioned, Codex HIGH-1/HIGH-2/HIGH-3 special-checks PASS. Signal 4 β€” m_users_cs/m_locchan_cs/m_misc_cs absent from all audio-path function ranges (m_misc_cs zero matches anywhere). Signal 5 β€” fopen/fread/writeLog/writeUserChanLog absent from audio-path; line 478 fread VERIFIED-UNREACHABLE per HIGH-1 invariant. spsc_payloads.h verification: ONE commit ever touches this file (8f47965 from 15.1-04 inception) β€” Codex M-9 Wave-0 finality preserved end-to-end. Architecture-mirror dead-but-live finding (njclient.cpp:1648 lobby renormalize) flagged in deferred-items.md per option (b) β€” VERIFIED-UNREACHABLE in modern JamWide. Awaiting HUMAN signals: 1c (manual standalone UAT under TSan, 30+ min populated server, bundled-UAT scope explicit per feedback_uat_scope_redflags.md), 3 (audible glitches + CPU history pattern check), 6 (lldb attach + read 6 production drop-counter accessors at session-end, all must == 0), 7 (Instruments Time Profiler 60s under broadcast load, BlockRecord memcpy CPU < 5%). Build for UAT: build-tsan/JamWideJuce_artefacts/Debug/Standalone/JamWide.app (build 287). On UAT approval: phase 15.1 closes, v1.2 milestone closure proceeds, PR #14 (VDO sync) hold released.
28+
Phase: 15.1 (rt-safety-hardening) β€” STABILIZING (all 10 impl plans landed; 15.1-10 mechanical verification GREEN; real-DAW UAT exposed THREE 15.1-07a regressions in builds 284β†’288β†’289β†’290, all root-caused to one architectural mistake β€” slot picking placed on the wrong thread. User reports continuous remote audio at build 290.)
29+
Plan: 15.1-10 mechanical signals 1a/1b/2/4/5 GREEN (build 287 TSan Standalone β€” pre-stabilization). 15.1-07a post-UAT stabilization commits: (1) b8ca083 build 288 β€” Direction-B stale UI reader: GetRemoteUsersSnapshot:4164-4165 + GetUserChannelPeak:4388-4390 still read legacy chan->decode_peak_vol; routed both through findRemoteUserSlot β†’ mirror.peak_vol_l/r. Audio worked, only VU was dead. (2) 7e69e1a build 289 β€” every-other-interval audio cutout: 07a's run_thread_next_ds_idx XOR shadow alternated 0/1, but audio thread always reads next_ds[0] and shifts next_ds[1]β†’next_ds[0]β†’null, so slot-1 publishes were unreachable until next shift. Mitigation: hardcode useidx_to_publish=0 at all 3 publish sites. (3) 00dfee7 build 290 β€” random bursty cutout: build-289's always-slot-0 mitigation defer-deleted prior next_ds[0] on every publish, dropping data when run thread published 2+ updates between drains. Final fix: move slot pick from publisher to apply visitor (which runs on audio thread via drainRemoteUserUpdates from AudioProc and CAN read mirror state); apply visitor logic = "fill empty slot 0; queue slot 1 if 0 occupied; defer-delete oldest only if both full" β€” recreates legacy `useidx = !!next_ds[0]` semantic on the correct thread. The 07a executor's original slot-picking-on-publisher decision was the architectural mistake; all three bugs stem from variations of that. feedback_legacy_invariant_audit.md updated with new Direction-C "decision-relocation drift" pattern. Awaiting decision: continue with formal bundled UAT (TSan Standalone build 287 β€” needs rebuild to include the three fixes β€” + lldb counter readout + Instruments perf budget) or close phase on real-DAW evidence + mechanical signals.
3030
Status: 15.1-07b COMPLETE (UAT approved 2026-04-26, build 249 VST3 + TSan standalone). m_locchan_cs.Enter/Leave removed from all 4 audit-cited audio-path sites (process_samples 1961+2118, on_new_interval 2698+2721); replaced with LocalChannelMirror[MAX_LOCAL_CHANNELS] (POD-with-embedded-SPSC, owned by audio thread) populated by drainLocalChannelUpdates() at the top of AudioProc. Mirror is BY-VALUE β€” Codex HIGH-2 closed (no Local_Channel* / lc_ptr / void* escape-hatch field; the per-channel BlockRecord SPSC is stored AS A MEMBER of the mirror entry; encoder consumer side wired in 15.1-07b same wave). Codex HIGH-3 closed via DeleteLocalChannel publish-wait-defer protocol with 200ms timeout. Earlier-context retained: m_locchan_cs.Enter/Leave removed from all 4 audit-cited audio-path sites (process_samples 1961+2118, on_new_interval 2698+2721); replaced with LocalChannelMirror[MAX_LOCAL_CHANNELS] (POD-with-embedded-SPSC, owned by audio thread) populated by drainLocalChannelUpdates() at the top of AudioProc. Mirror is BY-VALUE β€” Codex HIGH-2 closed (no Local_Channel* / lc_ptr / void* escape-hatch field; the per-channel BlockRecord SPSC is stored AS A MEMBER of the mirror entry; encoder consumer side wired in 15.1-07b same wave). Codex HIGH-3 closed via DeleteLocalChannel publish-wait-defer protocol with 200ms timeout: snapshot m_audio_drain_generation+1 β†’ publish RemovedUpdate β†’ yield-spin until audio thread bumps gate (release-store from AudioProc) β†’ enqueue canonical Local_Channel* onto m_locchan_deferred_delete_q β†’ drainLocalChannelDeferredDelete on run thread runs ~Local_Channel() off audio thread. NinjamRunThread::run() drains both queues in-loop AND post-loop. spsc_payloads.h UNTOUCHED β€” Wave-0 M-9 stability preserved. Two documented deviations: (1) Instatalk PTT cbf is preserved via SEPARATE inline-defined SPSC ring (m_locchan_processor_q) β€” AUDIT H-03 said zero callers, juce/NinjamRunThread.cpp:374 actually registers one; this is critical Phase 14.2 functionality; cbf+cbf_inst added to mirror by-value (NOT a HIGH-2 violation β€” cbf_inst is JamWideJuceProcessor-owned, not Local_Channel-owned); (2) VU peak migrated to std::atomic<float> on the mirror β€” GetLocalChannelPeak now reads lock-free from mirror (was reading lc->decode_peak_vol under m_locchan_cs). m_locchan_update_overflows counter exposed via GetLocalChannelUpdateOverflowCount() (Codex M-8). tests/test_local_channel_mirror.cpp added: 5 cases (Add/Info/Monitoring/Remove apply roundtrip, 1000-cycle concurrent producer/consumer, out-of-range channel ignored, HIGH-3 generation-gate deferred-free, HIGH-3 gate rejects premature free) + 6 static_assert HIGH-2 contract checks; 5/5 PASSED under both Release (build-test/) and TSan (build-tsan/) with zero ThreadSanitizer reports. JamWideJuce_Standalone build green in both build-juce/ and build-tsan/. Next: human-verify checkpoint UAT (populated-server TSan listening for 5+ min, exercise local-channel mutations, verify DeleteLocalChannel ≀ 200ms, confirm no audible glitches, confirm zero TSan reports). Then 15.1-07a (m_users_cs mirror, CR-01).
3131
Last activity: 2026-04-27
3232

0 commit comments

Comments
Β (0)