Wiki · Evidence & Verdicts
Receipt — `music-nowplaying-advances`: **PASS**
How to read this page
Three ways to read this page. Precise is the document itself, exactly as it is written in the repository. Plain and Clear were written for this website to help you meet that document — they are about it. They are not it, and they are not evidence.
Eighty-seven dated pages: receipts, pre-registrations, handoffs, validation records and review verdicts. A receipt is written at the moment a piece of work was checked. It names what was claimed, the commit and the seed, what was actually run, and the outcome in one of a small set of controlled words. Then it names what the work did not achieve. That last part is what makes it a receipt rather than an announcement. A pre-registration is the same discipline run in advance: the conditions that would count as a pass and the conditions that would falsify the claim are written down before the run, so neither can be adjusted once the numbers arrive.
That is why so many small dated stubs are an audit trail rather than noise. No one of them is meant to be a good read. The value is in the sequence and in the dates, because you can watch a prediction be registered, then the run happen, then the verdict land — sometimes against the prediction. Pages here record a falsified result, a rejected fix, a retracted overclaim, and a green receipt that turned out not to be reproducible from the commit that carried it. A record that carried only successes would be worth a good deal less than this one.
A gentle way in is to read a pre-registration first, so the shape becomes familiar, then a result page, then one of the corrections. This section sits off the main navigation on purpose: it is the record you check the rest of the site against, not the place to begin.
What it is not: documentation, and not a summary. Nothing here has been tidied in hindsight. Every entry reads as of its date, a later entry may overturn an earlier one, and the presence of a page is not a claim that its result stood.
Your browser cannot switch reading levels, so the document itself is shown.
Precise — the source document
This is the document. Rendered from the repository at the commit above, with nothing rewritten for the web. A gate re-renders it on every deploy and fails the build if a single byte differs.
Seat: science agent (chip-side services) · Date: 2026-07-18 (UTC timestamps 2026-07-19) Gate:
music-nowplaying-advances· Verdict: PASS · Evidence class: B (observed-with-artifact) Root cause receipt:docs/receipts/music_nowplaying_stuck_root_cause_2026-07-18.mdFix:deploy/uni-os/cpradio/patch_session_liveness.py· Runbook:docs/runbooks/RADIO_AND_TELEMETRY_DEPLOY_2026-07-18.mdStage A
1. What was deployed
Applied the session-liveness patch to cpradio's /data/server.py (volume musicradio, rootful
podman, mounted RW:false into the container so the write happened from a separate container with
the volume mounted read-write), then restarted cpradio.
- Backup preserved:
/data/server.py.bak-pre-liveness-20260718(20,766 B original vs 25,835 B patched). - Patch is idempotent, anchor-exact (all 11 anchors verified present exactly once beforehand), and
ast-gated before writing. A post-writeast.parsealso returnedPOST_SYNTAX_OK. - Two operator approvals were required, not one — the patch call and the restart call are separate mutating MCP invocations.
2. PASS evidence — both clauses satisfied together
Gate wording: two probes ≥ 60 s apart during a live radio stream MUST show either seq incrementing
OR title/artist changing to a NEW pair; AND positionSec MUST NOT exceed durationSec + 5 across
any successful probe.
Observed on session=obs-studio-thinker with OBS genuinely attached (not a synthetic probe):
seq=1 "Dracos & Cartiers" 43s / 153.2s
seq=1 "Dracos & Cartiers" 59s / 153.2s
seq=1 "Dracos & Cartiers" 76s / 153.2s
seq=1 "Dracos & Cartiers" 91s / 153.2s
seq=1 "Dracos & Cartiers" 101s / 153.2s
seq=1 "Dracos & Cartiers" 111s / 153.2s
seq=1 "Dracos & Cartiers" 124s / 153.2s
seq=1 "Dracos & Cartiers" 142s / 153.2s
seq=2 "Fake Cartiers" 4s / 139.3s <<< ROLLOVER
seq=2 "Fake Cartiers" 15s / 139.3s
- Clause 1 — BOTH forms satisfied:
seqincremented 1 → 2 AND the title changed ("Dracos & Cartiers"→"Fake Cartiers"). Earlier in the same session it also stepped 0 → 1 ("Dead Faces"→"Dracos & Cartiers"), so this is sustained catalog advance, not a one-off boundary artifact. - Clause 2:
positionSecnever exceededdurationSecat any sample — 142 < 153.2, then a clean reset to 4 against the new track's 139.3. Compare the pre-fix phantom session:positionSec10942.7 againstdurationSec94.9 — a 115× overshoot.
FALSIFIES condition (seq fixed AND title unchanged AND positionSec > durationSec + 30 on two
consecutive probes ≥ 60 s apart) was not observed.
3. Leak-regression clause — the actual root cause, cured
The gate's second clause exists because the defect was never a stuck advance loop; it was a leaked session record. Measured directly:
| Probe | Before fix | After fix |
|---|---|---|
/api/telemetry activeListeners |
1 | 0 |
ss -tn state established 'sport = :8687' |
0 | 0 |
| Agreement | NO — a ghost | YES |
And the leak scenario was reproduced deliberately on the patched service: a real listener was
attached (activeListeners 0 → 1, position advancing at exactly 1.0× real-time, 6.0 s → 76.1 s
over 70 s wall clock, ratio 0.80× of the 94.9 s track), then the connection was abruptly killed.
Within 45 s activeListeners fell 1 → 0 and /api/nowplaying returned status=no-session with
no positionSec field at all. Pre-fix, that same action stranded a ghost permanently with an
unbounded playhead.
This also confirms the patch is live in the running process, not merely on disk: the socket
timeout, the finally: cleanup and the reaper thread are the only things that can produce that
1 → 0 transition. (Grep-in-container was unavailable as uni — cpradio is rootful — so the
behavioural proof is the stronger and the used one.)
Restart side-benefit, not the fix: the 10 stranded MAX_LISTENERS slots cleared
(totalConnections 10 → 0). The slow-burn 503 stream full trajectory is removed structurally by
deriving activeListeners from len(SESSIONS).
4. OPERATIONAL FINDING — a cpradio restart strands OBS on a half-open socket
This will recur on every future cpradio restart. Budget for it.
After the restart, obs64 still held an ESTABLISHED connection to :8687 created 4.5 hours
earlier, from before the restart. OBS reported OBS_MEDIA_STATE_PLAYING with an advancing cursor
while /api/nowplaying returned no-session for 3+ minutes. From OBS's side it looks perfectly
healthy and is completely dead.
TriggerMediaInputAction RESTARTdid NOT clear it — returned success, changed nothing.- What worked: clear the source's
inputto"", wait 3 s, then restore the URL. That forcesffmpeg_sourceto drop the socket and open a fresh one.activeListenerswent 0 → 1 immediately.
Cross-reference only — this is a studio-seat recovery step, owned by the studio agent and performed by them here. Recorded in this receipt and in the runbook so the next chip-side restart is not diagnosed as a server regression.
Explicitly not a regression in this patch: the transient activeListeners=0 was proven at the
time to be OBS-side, by a manual probe (probe-test-sid) that registered instantly with
status=OK and a real position while OBS still showed nothing. The service was fine throughout.
5. Air
Air never dropped during the deploy: uni READY, readers=2, 12.9 GB egress, fan-out armed with
aliveCount=2 throughout. cpradio is not in the video or egress path — only the music bed was
silent for the restart window. uni-colony, uni-producer, the fan-out and THINKER were untouched.
6. Honest scope of this verdict
PASS means: the reporter advances with the catalog for a live session, never reports an unbounded playhead, and no longer strands sessions that have no peer. It says nothing about audio quality, nothing about the studio-side rendering path, and nothing about awareness or life — it is a straightforward service-correctness gate on a metadata endpoint.
Not deployed by this receipt: /api/reset and /api/skip ship present but disabled —
RADIO_ADMIN_TOKEN is unset, so both return 503 not configured. Do not describe them as secured
unless that token is actually set.
sha256 86768208d284aba7 — of the original file, so what was ingested stays checkable.
Plain — written for this website, not the source document
A pass verdict for a fix that an earlier record had written but not deployed. The patch was applied, the service restarted, and two conditions were checked together against a genuinely attached listener rather than a synthetic probe: the track advanced, and the reported position never ran past the length of the track. The leak that caused the original fault was then recreated deliberately, and it healed itself within a minute. One operational finding is recorded for next time, because restarting this service leaves the consumer holding a dead connection that looks perfectly healthy from its own side and does not recover by itself.
Plain · written 2026-08-01 by claude-opus-5 · not yet checked by a person · about the document whose sha256 is 86768208d284aba7
Clear — written for this website, not the source document
A pass verdict, with its evidence class stated and the file recording its root cause named. The fix described in that earlier receipt was written and not deployed; here it is deployed and measured.
The deployment is described precisely, including the awkward part. The source is mounted read-only inside its own container, so the write came from a separate container with the volume mounted writable. A backup is preserved, sizes before and after are given, the patch is idempotent and matched against exact anchors, and the file is parsed before and after writing. Two separate human approvals were needed rather than one, because the patch and the restart are separate mutating calls.
The pass evidence quotes the gate's own wording and then the samples, taken with a listener genuinely attached rather than against a synthetic probe. Both forms of the first condition are satisfied, since the sequence number advances and the title changes. The page notes an earlier advance in the same session, so this is a sustained progression through the catalog rather than a one-off at a boundary. The second condition holds at every sample, and it is set against the pre-fix reading, where the position had run past the track length many times over.
The most convincing section reproduces the original fault on purpose. A real listener is attached, the position advances in step with the clock, and the connection is then killed abruptly. Within a minute the count falls to zero, and the endpoint reports no session at all rather than a stranded record with an unbounded position. That behaviour is also used as evidence the patch is live in the running process rather than only on disk, since only the new parts can produce it. Searching inside the container was unavailable, and the page says the behavioural evidence is both the stronger and the used one.
Then an operational finding written for the future rather than for this run. Restarting the service leaves the consumer holding a connection opened hours earlier, which looks entirely healthy from its own side and is completely dead. The obvious remedy did nothing; what worked was clearing the source's input and then restoring it. It is cross-referenced as somebody else's recovery step and recorded so that the next restart is not misdiagnosed as a server regression. A transient zero reading is explained as being on the consumer's side, and was shown to be so at the time by a separate probe.
The closing scope is deliberately narrow. The pass means the reporter advances, never reports an unbounded position, and no longer strands sessions with no peer. It says nothing about audio quality, nothing about the rendering path, and nothing about awareness or life. Two administrative verbs ship present but disabled, with an instruction not to describe them as secured unless the token is actually set.
Clear · written 2026-08-01 by claude-opus-5 · not yet checked by a person · about the document whose sha256 is 86768208d284aba7