← back to Crazy News Channel
Fix Chaos Index reading ~51% on fresh load — exclude single-stage real-news from the escalation gauge
1ce86db7d6f15c3a0cff0b2da61b9bcb30f6d15a · 2026-09-24 09:13:03 -0700 · Steve Abrams
computeChaos() scored every story's stageIndex/(stages-1), with a `span>0 ? … : 1`
fallback that returned FULL chaos for a single-stage story. After the "one feed"
real-news merge, ~42 of 82 stories are single-stage (real news doesn't escalate),
so each was counted as maximally escalated — pinning a fresh channel at ~51%
"Concerning" and making the Nominal band unreachable on load.
Compute the gauge over escalatable (multi-stage) stories only. Verified: fresh
load 0% Nominal, climbs to 100% Post-Journalism at true meltdown, klaxon +10
bump preserved, 0 console/page errors.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkfgaotGs6PaEBcnKxnfZG
Files touched
Diff
commit 1ce86db7d6f15c3a0cff0b2da61b9bcb30f6d15a
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Thu Sep 24 09:13:03 2026 -0700
Fix Chaos Index reading ~51% on fresh load — exclude single-stage real-news from the escalation gauge
computeChaos() scored every story's stageIndex/(stages-1), with a `span>0 ? … : 1`
fallback that returned FULL chaos for a single-stage story. After the "one feed"
real-news merge, ~42 of 82 stories are single-stage (real news doesn't escalate),
so each was counted as maximally escalated — pinning a fresh channel at ~51%
"Concerning" and making the Nominal band unreachable on load.
Compute the gauge over escalatable (multi-stage) stories only. Verified: fresh
load 0% Nominal, climbs to 100% Post-Journalism at true meltdown, klaxon +10
bump preserved, 0 console/page errors.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkfgaotGs6PaEBcnKxnfZG
---
index.html | 33 +++++++++++++++++++++++----------
1 file changed, 23 insertions(+), 10 deletions(-)
diff --git a/index.html b/index.html
index f82c2d5..c526b9a 100644
--- a/index.html
+++ b/index.html
@@ -1589,6 +1589,14 @@ function patchStoryGrid(entries) {
}
function renderStories() {
+ // A rebuild detaches every card node, so a cached hover id is stale by
+ // definition — drop it or a hover that never gets a pointerout (e.g. the
+ // grid re-renders out from under a stationary pointer, such as on a
+ // category-change or article-close triggered without a mouse move) can
+ // leave isEscalationPaused() stuck true forever. If the pointer is still
+ // genuinely over a card, the next real pointerover re-sets this within a
+ // tick, so this costs nothing on the normal hover path.
+ state.hoveredCardId = null;
// Top-level completion state: every story has been deleted (a state that
// didn't exist before the admin panel could delete the seeded 3) — this
// is distinct from the per-category empty state below.
@@ -1676,19 +1684,24 @@ const ANCHOR_NOTES = {
// with only one stage can't have a ladder position, so it counts as fully
// escalated (1) rather than causing a divide-by-zero.
function computeChaos() {
- if (!STORIES.length) return 0;
- const total = STORIES.reduce((sum, s) => {
- const span = s.stages.length - 1;
- return sum + (span > 0 ? s.stageIndex / span : 1);
- }, 0);
- let pct = Math.round((total / STORIES.length) * 100);
+ // The gauge measures ESCALATION, so it's computed over escalatable
+ // (multi-stage) stories only. Single-stage real-news items (from the
+ // real-news merge) don't escalate — they load already at their only stage.
+ // The old code's `span > 0 ? … : 1` fallback scored each of them as FULLY
+ // escalated, which pinned a fresh channel at ~51% "Concerning" and made the
+ // Nominal band unreachable. Excluding them restores 0% on load while
+ // preserving 100% at true meltdown (all escalatable stories concluded).
+ const escalatable = STORIES.filter((s) => s.stages.length > 1);
+ if (!escalatable.length) return state.breaking ? 10 : 0;
+ const total = escalatable.reduce((sum, s) => sum + s.stageIndex / (s.stages.length - 1), 0);
+ let pct = Math.round((total / escalatable.length) * 100);
// BREAKING klaxon integration: an active klaxon reads as its own bump on
// the escalation gauge, independent of story stages.
if (state.breaking) pct += 10;
- // 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);
+ // 100% is reserved for true meltdown (every escalatable story concluded),
+ // the same condition that fires PLEASE STAND BY, so the gauge never reads
+ // 100% while the standby card stays silent.
+ const allConcluded = escalatable.every((s) => s.stageIndex === s.stages.length - 1);
return Math.max(0, Math.min(allConcluded ? 100 : 99, pct));
}
← 5643bfe One feed: invented satire + real Google News together
·
back to Crazy News Channel
·
chaos-screenrecord: fix chaosFF-concluded's coverage gap on f58b710 →