overpass-topup.mjs — maintainer-time repo tool, six hard laws:
- never imported by bot/src or web/src (TP1 gate); Worker reads only the committed JSON
- exactly ONE request per run: both live paths (Overpass POST, Nominatim GET)
share a single requestJson helper — one fetch( call site (TP7)
- identifying User-Agent araharah-gazetteer-topup/1.0 mandatory (missing UA = HTTP 406)
- busy/saturated/unusable response -> 'Overpass instance busy — retry later', exit 0 (TP4)
- output is a PROPOSAL only; source never names the curated file, so it cannot write it (TP6)
- --source=overpass|nominatim|fixture (--fixture implies fixture), --endpoint/OVERPASS_ENDPOINT
override, bbox-bounded single-family query pinned verbatim (3.05,101.55,3.25,101.80) (TP3)
- --fixture selects the offline path by itself (a fixture flag silently hitting the
live network would be a trap — fixed during GREEN)
overpass-response.json — committed real-shape Overpass response (6 KL elements:
nodes with lat/lon, ways/relation with center) so the test is deterministic.
json-to-sqlite.mjs — backend #2's dataset format reachable today (D-05):
- reads the same committed kl-gazetteer.json, emits kl-gazetteer.sqlite via
node:sqlite (zero added deps) with the SAME id set (CV1), plus the ODbL
notice embedded in a metadata table + NOTICE sidecar (ODbL s4.4, T-04-20)
- deterministic: rows in dataset order, no timestamps
- golden-corpus.json: 75 hand-written pinned cases (D-13) — landmark 17 /
abbreviation 15 / glued 7 / typo 14 / alias 15 / negative 7, incl. two
near-miss negatives (Penang 0.625, Kampung Cina ~0.58) below the 0.72
admission line; threshold.top3_hit_rate pinned at 0.9
- gazetteer-corpus.mjs: the D-14 runner — imports the SAME src/index.ts the
bot uses, measures top-1/top-3 + per-category rates + avg ms/query, prints
the refusal margin and the fixed escalation ladder on failure, exports
measureCorpus() for the in-process suite, exits 0 only on threshold + zero leaks
- corpus.test.mjs goes green: CO1-CO8 (the Nyquist gate inside npm run search:test)
- delegates: search:corpus (root) + corpus (search workspace)
Measured: top-3 68/68 (100.0%) >= 90%, negatives refused 7/7, margin 0.643 < 0.72 —
threshold met on the first run (D-14 lever: None).