Skip to content

fix(qcm): every remote read bounded, cancelable and latest-wins (modules) - #36

Merged
joepetjr merged 3 commits into
masterfrom
qqa-13b1-modules
Oct 24, 2026
Merged

joepetjr merged 3 commits into
masterfrom
qqa-13b1-modules

Conversation

@joepetjr

Copy link
Copy Markdown
Contributor

Ports QQA-13b1: every remote read in the source modules bounded, cancelable and latest-wins (modules only; main.js is the next PR).

Source: headlessmode-archive PR #788 (head 95ff4d8f, own commit c2e09cbe). Cherry-picked onto the 13a branch because the archive heads share no history with master. Stacked on the 13a PR.

What it does: the source adapters call fetchWithDeadline with a caller signal instead of raw fetch; adds no-raw-fetch.test.mjs and adapter-deadlines.test.mjs.

Deviation from the source commit: master has seven modules that did not exist when the source was written and still call raw fetch: address-geocode.js, source-avalanche.js, source-nrhp.js, source-ntad-rail-airports.js, source-nws-observations.js, source-snotel.js, source-stream-gauges.js. Converting them is outside this commit and would break the diff cap, so they sit on the ALLOW list in no-raw-fetch.test.mjs and a pending list in adapter-deadlines.test.mjs (with a stale-entry check), and are documented in scripts/qcm/README.md. The address-geocode.js header comment (lines 16-17, "There is no shared request helper") is rewritten, since request.js now exists. Follow-up needed: move those seven onto fetchWithDeadline; until then they have no deadline.

Tests, red first: with the 13a branch plus only the ported tests, 132 tests ran and 71 failed. After the code, targeted 158/158. Full CI test step (scope full): 3054 tests, 3054 pass, 0 fail, 0 skipped.

Stack: PR 2 of 3. Own diff 845 lines (+648/-197) against the 13a branch.

…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.
@joepetjr
joepetjr changed the base branch from qqa-13a-request to master October 24, 2026 20:42
# 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
@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: 5f44d21
Status: ✅  Deploy successful!
Preview URL: https://6e7f911a.headlessmode-current.pages.dev
Branch Preview URL: https://qqa-13b1-modules.headlessmode-current.pages.dev

View logs

@joepetjr
joepetjr merged commit d4f77d3 into master Oct 24, 2026
5 checks passed
@joepetjr
joepetjr deleted the qqa-13b1-modules branch October 24, 2026 21:08
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