Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions scripts/qcm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,11 +292,11 @@ switch-off, an older decode landing after a newer ask, and an uninterrupted ask

## Remote reads (QQA-13)

`quiet-corners-maps/request.js` is the one way the map reads from the network. `fetchWithDeadline(url, { fetchImpl, signal, timeoutMs })` answers `{ ok, status: 'ok' | 'timeout' | 'aborted' | 'error' }` and never throws. Its timer is a plain `AbortController`, so it works without `AbortSignal.any`, it ends a fetch that ignores its signal, and it clears the timer and the listener on the caller's signal when the call settles. A caller's cancel is `aborted`, never `timeout`. `createLatest()` is latest-wins: a new call aborts the previous one and the older answer comes back `stale`. `source-terrain-names.js` re-exports `fetchJson` and `createSearchGuard` from it for the callers that already import them.
`quiet-corners-maps/request.js` is the one way the map reads from the network. `fetchWithDeadline(url, { fetchImpl, signal, timeoutMs, init, read, anyStatus })` (`read` swaps the body reader, e.g. `r => r.blob()`; `anyStatus` also reads the body of a non-2xx for services whose error answer carries the reason) answers `{ ok, status: 'ok' | 'timeout' | 'aborted' | 'error' }` and never throws. Its timer is a plain `AbortController`, so it works without `AbortSignal.any`, it ends a fetch that ignores its signal, and it clears the timer and the listener on the caller's signal when the call settles. A caller's cancel is `aborted`, never `timeout`. `orThrow(result, message)` is for the few adapters that throw on failure: the body of an ok result, else an Error carrying the result's `status` and `httpStatus` (a caller's cancel keeps the name `AbortError`). `createLatest()` is latest-wins: a new call aborts the previous one and the older answer comes back `stale`. `source-terrain-names.js` re-exports `fetchJson` and `createSearchGuard` from it for the callers that already import them.

The deadline is per source: `SOURCES.<id>.timeoutMs` in `source-registry.js`, `DEFAULT_SOURCE_TIMEOUT_MS` (10 s) unless the source cites a slower measurement in `timeoutMeasured`. GNIS place names keep 20 s because their latency is measured up to 31 s. Only the modules moved onto the helper honour it so far: GNIS place names, the quad index, and the NWS forecast and alerts loaders. Every other source (road names, hillshade, MVUM, stream names, topo tiles and the rest) carries the value but still runs at `REQUEST_POLICY.timeoutMs` (20 s) until it is converted. The quad index pages at most `MAX_PAGES` (20) times and stops on a page that adds no new cell, ending `coverage: 'partial'`; its `timeoutMs` bounds each attempt, including `searchByName`, and a timeout is not retried.
The deadline is per source: `SOURCES.<id>.timeoutMs` in `source-registry.js`, `DEFAULT_SOURCE_TIMEOUT_MS` (10 s) unless the source cites a slower measurement in `timeoutMeasured`. GNIS place names keep 20 s because their latency is measured up to 31 s, and the wetlands and government-units layers keep the 20 s page their measurements were taken against. Every module in that directory except `main.js` and the seven listed next reads through the helper at its own source's value (the paged boundary and site callers pass it to `pageThrough`; a module with no registry entry, such as the ecoregions export, uses the default). `main.js` still has raw reads until PR-B2. The seven that reached master after this work was written (`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`) still make their own raw calls, with no deadline from the helper, and are on the `ALLOW` list until a follow-up moves them. `REQUEST_POLICY.timeoutMs` is no longer a request deadline. The quad index pages at most `MAX_PAGES` (20) times and stops on a page that adds no new cell, ending `coverage: 'partial'`; its `timeoutMs` bounds each attempt, including `searchByName`, and a timeout is not retried.

`request.test.mjs` covers the helper (timeout, abort, cleanup, no `AbortSignal.any`, latest-wins); `map-index.test.mjs`, `arcgis-pager.test.mjs` and `registry.test.mjs` hold the quad paging cap, the pager deadline and the per-source `timeoutMs` rule.
`request.test.mjs` covers the helper (timeout, abort, cleanup, no `AbortSignal.any`, `anyStatus`, `orThrow`, latest-wins); `no-raw-fetch.test.mjs` fails on any raw `fetch(` or `fetchImpl(` call in that directory outside `request.js` and its `ALLOW` list (`main.js`, removed in PR-B2, and the seven named above; it also fails if an entry stops holding a raw call, so the list cannot rot); `adapter-deadlines.test.mjs` hands every adapter that takes `fetchImpl` a fetch that never answers and asserts it settles at its deadline, and that a caller's abort ends it as a cancel, not a timeout (a new `source-*.js` module that takes `fetchImpl` must be added to its table); `build.test.mjs` holds that the build's cancel reaches the aerial, relief and elevation requests; `map-index.test.mjs`, `arcgis-pager.test.mjs` and `registry.test.mjs` hold the quad paging cap, the pager deadline and the per-source `timeoutMs` rule.

## Accessibility checks

Expand Down
Loading
Loading