- poi-extract.sh: PBF download -> osmium tags-filter -> centroid NDJSON +
manifest, published via the Caddy sidecar at vSwitch-only /poi/*
- osmium-filters.txt + poi-selectors.sql generated from map-core selectors,
guarded by sync tests so poiCategories stays the single source of truth
- poi-import.sh: checksum verify -> classify into category rows ->
70% guard (--bootstrap override) -> atomic rename swap; node_exporter
textfile metric for import outcome
- systemd service+timer units for both halves (monthly, offset)
- cd-infra.yml: ship infrastructure/scripts to the flagship
- e2e: mock /api/pois instead of /api/overpass
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Diagnosis (reproduced by looping cold-server runs): the recurring
"cold start" failures in the auth/follow specs were a hydration race,
not a Vite dep-reload (the server.warmup config already handles that —
no reload events in the logs). FollowButton is an onClick button, and
Playwright considers it actionable (visible + enabled) before React
attaches the handler on a freshly-navigated page. A click in that
window is dropped (or triggers a native form submit), so the expected
state change never happens — e.g. notifications.test.ts:59 clicked
"Request to follow" with no hydration wait and the button never
flipped to "Requested".
The existing waitForHydration guard was applied per-interaction and so
was easy to forget (test 1 had it, test 3 didn't). Fix it at the
navigation instead:
- add gotoHydrated(page, url) = goto + waitForHydration, documented as
the default for "navigate then interact with a React control"
- use it before every FollowButton interaction in notifications +
social
- consolidate the setProfileVisibility helper (copy-pasted in three
specs, two missing the hydration wait) into e2e/helpers/profile.ts,
built on gotoHydrated
Validation against a fresh Postgres, cold servers: notifications 0/10
failures (was the proven flaker); notifications+social+explore 0/5
(55 tests); planner unaffected (25/25).
Note: two other "cold-start"-attributed flakes are NOT this race and
are out of scope here — planner map-load latency (mitigated by warmup
+ CI retries) and the /explore directory assertion (a local artifact
of the scratch DB accumulating >20 public users; CI's fresh DB stays
under the page size, so it doesn't bite there).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two issues caused the same class of flake locally:
1. Default workers were CPU-count, but the journal/planner are served
by Vite dev (not the production build CI uses). Cold-compiling
`/api/auth/register` under N parallel hits produced 30s timeouts
on a quarter of runs. Set workers to 1 in both environments for
parity with CI.
2. Even sequentially, a button is clickable per Playwright's
actionability check before React has hydrated its `onClick`. So
the first click after a navigation could fire native form submit
(or do nothing), which manifested as "URL never changed to /" or
"menuitem Log Out never appeared". Add a `waitForHydration` helper
that polls for React fibers (`__reactProps$<id>`) attached to a
DOM node and call it after each cross-page navigation that ends
in an interactive form or dropdown.
CI is unaffected (production builds hydrate fast and didn't expose
either bug), but the helper is harmless there.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two e2e tests intermittently failed with "unmocked external request"
when the Sentry browser SDK emitted an envelope to the real ingest
endpoint despite `enabled: false`. The BrowserTracing integration
captures the page-load transaction before init's enabled flag fully
propagates, so a single envelope leaks on cold start.
Add a SILENT_DROP list that aborts matching requests without recording
them as blocked, so legitimate missing-mock failures still surface.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Surface net for the class of bug we hit in #282 — a POI test silently
relied on a live Overpass server for months because its `page.route`
mock was targeting a URL the browser no longer hit directly. CI stayed
green on coincidence (real OSM data happened to satisfy the "any
marker renders" assertion) until upstream behaviour drifted.
Add a shared Playwright fixture (e2e/fixtures/test.ts) that installs a
catch-all `page.route("**", ...)` before each test. Requests to
localhost + known tile CDNs pass through via `route.continue()`;
anything else is aborted and accumulated. At test teardown, a non-empty
blocked list throws, failing the test with the offending URLs and a
pointer to the fixture.
All seven e2e *.test.ts files updated to import test/expect (+ types)
from ./fixtures/test.
Full suite passes with this fixture in place (50/50 at --workers=2;
catch-all never fires, meaning no test currently relies on an
unallowlisted external service).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>