Skip to content

fix(qcm): every remote read bounded, cancelable and latest-wins (main.js) - #37

Merged
joepetjr merged 7 commits into
masterfrom
qqa-13b2-main
Oct 24, 2026
Merged

joepetjr merged 7 commits into
masterfrom
qqa-13b2-main

Conversation

@joepetjr

Copy link
Copy Markdown
Contributor

Ports QQA-13b2: main.js asks for every remote read through the bounded helper, cancels a replaced area's source pass, and keeps latest-wins on quad search and toggles.

Source: headlessmode-archive PR #789 (head f21d2d24, own commits 145b0386 and f21d2d24). Cherry-picked because the archive heads share no history with master. Stacked on the 13b1 PR (#36); this PR's base stays on that branch until #36 merges, and master has been merged into it as asked.

What it does: main.js replaces its raw fetch calls (camera index and files, the topo tile probe, the camera still, the build's fetchImpl) with fetchWithDeadline; sourcePass runs under one AbortController that setArea and clearArea abort; radar, aurora and ecoregion toggles drop stale answers; quad search is latest-wins. Adds request-races-browser.test.mjs and takes main.js off the no-raw-fetch allow list.

Fixes found by the full suite (third commit, outside the source commit):

  • The camera still read used the 10 s default source deadline, shorter than the card's own 20 s picture limit, and a timeout abort of the card's controller returned silently. It now uses PICTURE_TIMEOUT_MS and still reports the did-not-load status when the timer fired.
  • request-races-browser.test.mjs reads the built site, so scripts/qcm/site-coupling.json lists it (regenerated with node scripts/ci/qcm-boundary.mjs write).

Tests, red first: 13b1 branch plus the ported no-raw-fetch and request-races-browser tests gave 8 tests, 4 failed (the raw-fetch scan and 3 browser race tests). First full CI test step on the port: 3057 tests, 4 failed (the camera picture limit, plus 3 site-coupling checks), all fixed by the third commit. Second full run: 3057 tests, 3056 pass, 1 fail (terrain-relief-browser, a 3D pixel check that took 101 s while the box was saturated by other suites). That test passes alone, and on the merged tree the targeted rerun is 367 of 367 (terrain, camera picture states, request races, no-raw-fetch, adapter-deadlines, request, camera snapshot, qcm-boundary, verify-claims, pr-ci-scope).

Stack: PR 3 of 3. Own diff 355 lines (+302/-53) against the 13b1 branch. Remaining raw fetch in the seven grandfathered modules is listed in #36.

…ad paging

The map had three hand-written copies of "abort after N ms"; two applied
the deadline only when AbortSignal.any existed. request.js is the one
place now: fetchWithDeadline (never throws; ok/timeout/aborted/error),
withDeadline, createLatest and createSearchGuard.

- arcgis-pager: pageThrough defaults to the 20 s REQUEST_POLICY deadline.
- map-index paging stops at MAX_PAGES, dedupes by cell id, stops when a
  page adds nothing, and reports timedOut instead of hanging.
- weather and NWS alerts read their registry timeoutMs; the registry
  gives every source a 10 s default, place names 20 s (measured up to
  31 s on a slow day, recorded beside it).
- A missing timeoutMs comes back as an error result, not an exception.

QQA-13 PR-A. Ports headlessmode-archive 85b71df0 (PR #784, rebuilt head
9acbd293) onto master. PR-B moves the remaining modules onto it.
…les)

Every source module now reads through request.js fetchWithDeadline instead
of a raw fetch, so each ends on its own deadline and a caller's cancel ends
it as a cancel. A hung service used to leave a pending note up forever.

- Default deadlines come from the source registry (10 s). The 20 s
  REQUEST_POLICY value is no longer a request deadline. A caller's timeoutMs
  still wins, and pager callers pass their registry entry.
- request.js gains `anyStatus` (read a non-2xx body) and `orThrow`. No
  signature or return shape changes.
- build.js passes the signal through and checks for a cancel after each
  extra, so a cancel ends the build instead of reading as "this extra
  failed".
- fetchAqi, fetchFire, fetchAccess and fetchSmoke keep "never throws the
  map": a missing or malformed area answers null.

no-raw-fetch.test.mjs fails on a new raw fetch call outside request.js.
adapter-deadlines.test.mjs runs every adapter against a fetch that never
answers, and fails when a new source module is missing from its table.

Seven modules reached master after this work was written (the E-P1..E-P6
field-map layers: avalanche, NRHP, NTAD rail and airports, NWS
observations, SNOTEL, stream gauges; and address-geocode.js). They still
make their own raw calls, so main.js plus those seven are on the
no-raw-fetch allow list, and the six source modules sit in a `pending`
list in adapter-deadlines.test.mjs. Each list fails if an entry stops
matching. address-geocode.js's header comment no longer says there is no
shared request helper.

QQA-13 PR-B1. Ports headlessmode-archive c2e09cbe (PR #788, rebuilt head
95ff4d8f) onto master, stacked on the PR-A branch.
….js)

main.js was the last caller of the original set with raw fetch calls. Its
reads now go through fetchWithDeadline, and each source pass owns an
AbortController that setArea and clearArea abort. The requests of a pass
whose area was replaced are cancelled at the network, and an answer that
lands after the area changed is dropped instead of drawn over the new one.

The base-map probe reads a plan with no tile as "unavailable" rather than
throwing, which would have left Check sources disabled.

request-races-browser.test.mjs proves the cancel and the latest-wins
ordering in a real page. main.js leaves the no-raw-fetch ALLOW list, which
now holds only the seven modules that reached master after this work was
written (address-geocode.js and six E-P source modules); they are named in
the PR-B1 commit and in scripts/qcm/README.md.

QQA-13 PR-B2. Ports headlessmode-archive 145b0386 (PR #789, rebuilt head
f21d2d24, which also carries the allow-list test change) onto master,
stacked on the PR-B1 branch.
…er test is listed as site-coupled

Integration fixes for the QQA-13b2 port (source f21d2d24): the road-camera still read
goes through fetchWithDeadline, whose default source deadline (10 s) fired before the
card's own 20 s picture limit, and a timeout abort of the card's controller returned
silently instead of reporting the did-not-load status. The still now uses
PICTURE_TIMEOUT_MS as its deadline and reports when it is the timer that aborted.
request-races-browser.test.mjs reads the built site, so scripts/qcm/site-coupling.json
lists it (regenerated with node scripts/ci/qcm-boundary.mjs write).
# Conflicts:
#	scripts/qcm/README.md
#	scripts/qcm/registry.test.mjs
#	scripts/qcm/request.test.mjs
#	themes/headlessmode/static/js/quiet-corners-maps/arcgis-pager.js
#	themes/headlessmode/static/js/quiet-corners-maps/request.js
#	themes/headlessmode/static/js/quiet-corners-maps/source-nws-alerts.js
#	themes/headlessmode/static/js/quiet-corners-maps/source-registry.js
#	themes/headlessmode/static/js/quiet-corners-maps/source-weather.js
@joepetjr
joepetjr changed the base branch from qqa-13b1-modules to master October 24, 2026 21:07
# Conflicts:
#	scripts/qcm/README.md
#	scripts/qcm/no-raw-fetch.test.mjs
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Deploying headlessmode-current with  Cloudflare Pages  Cloudflare Pages

Latest commit: f03b608
Status: ✅  Deploy successful!
Preview URL: https://70353cb3.headlessmode-current.pages.dev
Branch Preview URL: https://qqa-13b2-main.headlessmode-current.pages.dev

View logs

@joepetjr
joepetjr merged commit fdfc050 into master Oct 24, 2026
5 checks passed
@joepetjr
joepetjr deleted the qqa-13b2-main branch October 24, 2026 21:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant