← back to Crazy News Channel
Chaos Index: serialize live announcements, reserve 100% for meltdown, fix standby re-arm
679e2f48a237643ad56c45668458a6ab97862c3c · 2026-09-23 19:53:38 -0700 · Steve Abrams
Cody gate on 0e2f7d8..f961c67, each hole reproduced before fixing:
- announce() was last-write-wins on one shared polite live region; a story
update and a chaos band change in the same tick landed 0ms apart, so a
screen reader heard only the last. Now a FIFO drains one message per
1.2s. Measured gap: 0ms -> 1209ms.
- The +10 klaxon bump could clamp the gauge to 100% ("Post-Journalism
100%") while PLEASE STAND BY never fired, since standby keys off every
story concluded. 100% is now reserved for that same condition (99% max
otherwise). Repro: 100 -> 99 with 1 story unconcluded; true meltdown
still reads 100 and flashes.
- Standby re-arm within 2.9s didn't restart the animation and the first
arm's untracked timeout hid the second mid-cycle. Timer is now tracked
and cleared, animation restarted via reflow. Verified visible after the
old timer would have fired, hidden on the new one.
Regressions pass: overflow sweep 4 widths x Chrome/WebKit, hash freeze,
Cody fixes 4/4, arcs, attribute escaping, grid race 30/30, reduced motion.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011iuURMrsPBwAqMc5LgvFLH
Files touched
Diff
commit 679e2f48a237643ad56c45668458a6ab97862c3c
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed Sep 23 19:53:38 2026 -0700
Chaos Index: serialize live announcements, reserve 100% for meltdown, fix standby re-arm
Cody gate on 0e2f7d8..f961c67, each hole reproduced before fixing:
- announce() was last-write-wins on one shared polite live region; a story
update and a chaos band change in the same tick landed 0ms apart, so a
screen reader heard only the last. Now a FIFO drains one message per
1.2s. Measured gap: 0ms -> 1209ms.
- The +10 klaxon bump could clamp the gauge to 100% ("Post-Journalism
100%") while PLEASE STAND BY never fired, since standby keys off every
story concluded. 100% is now reserved for that same condition (99% max
otherwise). Repro: 100 -> 99 with 1 story unconcluded; true meltdown
still reads 100 and flashes.
- Standby re-arm within 2.9s didn't restart the animation and the first
arm's untracked timeout hid the second mid-cycle. Timer is now tracked
and cleared, animation restarted via reflow. Verified visible after the
old timer would have fired, hidden on the new one.
Regressions pass: overflow sweep 4 widths x Chrome/WebKit, hash freeze,
Cody fixes 4/4, arcs, attribute escaping, grid race 30/30, reduced motion.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011iuURMrsPBwAqMc5LgvFLH
---
index.html | 30 +++++++++++++++++++++++++++---
1 file changed, 27 insertions(+), 3 deletions(-)
diff --git a/index.html b/index.html
index 7d94990..0caaa48 100644
--- a/index.html
+++ b/index.html
@@ -1357,10 +1357,26 @@ const els = {
standbyFlash: document.getElementById("standbyFlash"),
};
+// Serialized: every caller shares one polite live region, and two writes in
+// the same frame collapse into the last one (a story update and a chaos band
+// change in one tick lost the story update). Messages queue and drain one at
+// a time, spaced so a screen reader finishes each before the next lands.
+const announceQueue = [];
+let announceDraining = false;
function announce(text) {
+ announceQueue.push(text);
+ if (!announceDraining) drainAnnounce();
+}
+function drainAnnounce() {
+ const next = announceQueue.shift();
+ if (next === undefined) { announceDraining = false; return; }
+ announceDraining = true;
els.srLive.textContent = "";
// re-set on next frame so repeated identical strings still get announced
- requestAnimationFrame(() => { els.srLive.textContent = text; });
+ requestAnimationFrame(() => {
+ els.srLive.textContent = next;
+ setTimeout(drainAnnounce, 1200);
+ });
}
function visibleStories() {
@@ -1565,7 +1581,11 @@ function computeChaos() {
// BREAKING klaxon integration: an active klaxon reads as its own bump on
// the escalation gauge, independent of story stages.
if (state.breaking) pct += 10;
- return Math.max(0, Math.min(100, pct));
+ // 100% is reserved for true meltdown (every story concluded), the same
+ // condition that fires PLEASE STAND BY, so the gauge never reads 100%
+ // while the standby card stays silent.
+ const allConcluded = STORIES.every((s) => s.stageIndex === s.stages.length - 1);
+ return Math.max(0, Math.min(allConcluded ? 100 : 99, pct));
}
function chaosBandFor(pct) {
@@ -1612,9 +1632,13 @@ function updateChaosUI() {
const allConcluded = STORIES.length > 0 && STORIES.every((s) => s.stageIndex === s.stages.length - 1);
if (allConcluded && !state.standbyFlashShown && !state.reducedMotion) {
state.standbyFlashShown = true;
+ clearTimeout(state.standbyTimer);
els.standbyFlash.hidden = false;
+ // restart the animation even if a previous arm hasn't finished
+ els.standbyFlash.classList.remove("flashing");
+ void els.standbyFlash.offsetWidth;
els.standbyFlash.classList.add("flashing");
- setTimeout(() => {
+ state.standbyTimer = setTimeout(() => {
els.standbyFlash.hidden = true;
els.standbyFlash.classList.remove("flashing");
}, 2900);
← f961c67 Fix real horizontal overflow from the chaos-tier-3 broadcast
·
back to Crazy News Channel
·
auto-data-snapshot: 2026-09-23T20:04:48 (1 data files) — scr 5d6d91c →