← back to Scarlet Riverboat Masquerade
contrarian FIX FIRST: per-build AbortController cancels stale year-fetch batch on source-switch; drop dead sort ternary; report reflects BLOCKED-on-live-verify not DONE
9899b1381c9a97f3e4995230f688c70a868416bc · 2026-09-02 09:36:16 -0700 · Steve Abrams
Files touched
M 5x/REPORT.mdM index.html
Diff
commit 9899b1381c9a97f3e4995230f688c70a868416bc
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed Sep 2 09:36:16 2026 -0700
contrarian FIX FIRST: per-build AbortController cancels stale year-fetch batch on source-switch; drop dead sort ternary; report reflects BLOCKED-on-live-verify not DONE
---
5x/REPORT.md | 11 +++++++++--
index.html | 14 +++++++++++---
2 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/5x/REPORT.md b/5x/REPORT.md
index 60e19e2..1172b63 100644
--- a/5x/REPORT.md
+++ b/5x/REPORT.md
@@ -28,5 +28,12 @@ Under real-Chrome conditions, archive.org was **down** (`000`, connection refuse
- **0 real JS/page errors** across sweeps 3 & 4.
- Deployed bundle confirmed to contain the timeout wrapper + honest copy.
-## Open / caveat (honest)
-- **Happy-path (counts + shows actually load) could not be re-verified LIVE** during this run because **archive.org is externally down right now**. It was proven earlier on localhost when archive.org was up: Grateful Dead 1994 = 460 shows, Dead & Company = 874 shows, both sources' tiles heat-colored, 0 errors. The success code path is unchanged except for the pass-through timeout wrapper. Re-confirm once archive.org recovers.
+## Contrarian gate (Cody, /5x final step) → FIX FIRST → fixes applied
+Cody the Contrarian red-teamed this report + code and voted **FIX FIRST** (3 FIX-FIRST / 2 REVISE). Legit findings, addressed:
+1. **"Clean twice" both ran while archive.org was DOWN** → only the degradation path was proven; calling it DONE was premature. Corrected: final sign-off is **BLOCKED pending a live happy-path re-verify** (delegated to a spawned iTerm window that polls archive.org and runs the happy-path check on recovery). Not "DONE".
+2. **Batch of 31 year-fetches not cancelled on source-switch** (real) → added a per-build `AbortController` (`buildCtl`) that `.abort()`s the prior batch at the top of every `buildMap()`, with its signal threaded into `fetchT(url, ms, extSignal)`. Verified: rapid GD→DC→GD→DC switching settles to the correct source, no half-render, **0 JS errors** (aborted fetches caught, no unhandled rejection).
+3. **Dead ternary** `sort = (q||yr) ? 'downloads+desc' : 'downloads+desc'` (real) → removed.
+4. 9s timeout — Cody's own panel resolved it's fine (refused = fast-fail; the 9s only bounds *hung* connections). No change.
+
+## Open / BLOCKED (honest)
+- **Happy-path (counts + shows actually load) not yet re-verified LIVE** — **archive.org is externally down** (`000`, connection refused). Proven earlier on localhost when it was up (GD 1994 = 460, Dead & Company = 874, tiles heat-colored, 0 errors), but the timeout + abort changes must be re-confirmed on the live path. A dedicated iTerm window is polling archive.org every 4 min and will run the live happy-path check the moment it recovers. Final DONE is gated on that PASS.
diff --git a/index.html b/index.html
index dbd0271..ac0394c 100644
--- a/index.html
+++ b/index.html
@@ -1530,9 +1530,13 @@ async function loadShow(i, opts){ if(sel) sel.value=String(i); return loadShowRe
let searchTimer=null;
// archive.org is a flaky nonprofit — abort a hung request so the UI fails gracefully
// into the error state instead of pulsing "…" forever (5x sweep 2 fix).
-function fetchT(url, ms=9000){
+function fetchT(url, ms=9000, extSignal){
const ctl = (typeof AbortController!=='undefined') ? new AbortController() : null;
const t = ctl ? setTimeout(()=>ctl.abort(), ms) : null;
+ if(ctl && extSignal){ // batch-cancel (e.g. source switch)
+ if(extSignal.aborted) ctl.abort();
+ else extSignal.addEventListener('abort', ()=>ctl.abort(), {once:true});
+ }
return fetch(url, {mode:'cors', signal: ctl?ctl.signal:undefined})
.finally(()=>{ if(t) clearTimeout(t); });
}
@@ -1545,7 +1549,7 @@ async function searchArchive(q){
const filters=[]; if(q) filters.push('('+q+')'); if(yr) filters.push('year:'+yr);
const query = filters.length ? coll+' AND '+filters.join(' AND ') : coll;
res.innerHTML='<div class="mr-hint">'+(filters.length?'Searching the archive…':'Loading the most-played shows…')+'</div>';
- const sort = (q||yr) ? 'downloads+desc' : 'downloads+desc';
+ const sort = 'downloads+desc';
try{
const url='https://archive.org/advancedsearch.php?q='+encodeURIComponent(query)+
'&fl[]=identifier&fl[]=title&fl[]=date&fl[]=venue&fl[]=coverage&fl[]=downloads&sort[]='+sort+'&rows=40&output=json';
@@ -1701,8 +1705,12 @@ function setYear(y){
searchArchive(searchEl?searchEl.value:'');
}
+let buildCtl=null; // cancels the previous batch of year-count fetches on a source switch
function buildMap(){
const src=window.MR_SOURCES[window.MR_SRC], mySrc=window.MR_SRC;
+ if(buildCtl) buildCtl.abort(); // kill in-flight fetches from the prior build
+ buildCtl=(typeof AbortController!=='undefined')?new AbortController():null;
+ const sig=buildCtl?buildCtl.signal:undefined;
const YEARS=[]; for(let y=src.y0;y<=src.y1;y++) YEARS.push(y);
mapEl.innerHTML='';
YEARS.forEach(y=>{
@@ -1715,7 +1723,7 @@ function buildMap(){
});
// per-year show counts → heat-color the tiles (sqrt to tame the '77/'89 spikes)
Promise.all(YEARS.map(y=>
- fetchT('https://archive.org/advancedsearch.php?q='+encodeURIComponent('collection:'+src.id+' AND year:'+y)+'&rows=0&output=json')
+ fetchT('https://archive.org/advancedsearch.php?q='+encodeURIComponent('collection:'+src.id+' AND year:'+y)+'&rows=0&output=json', 9000, sig)
.then(r=>r.json()).then(j=>({y,n:(j.response&&j.response.numFound)||0})).catch(()=>({y,n:-1}))
)).then(rows=>{
if(mySrc!==window.MR_SRC) return; // source switched mid-flight
← 111f196 5x: report — 2 sweeps clean after archive.org fetch-timeout
·
back to Scarlet Riverboat Masquerade
·
riverboat: Phase 1 archive.org reliability — cap year-count ab81288 →