- The CI gate builds the app and serves it with `vite preview`, with a
dummy non-secret client token (a fork PR never gets secrets), and
answers the Graph API, image tiles and thumbnails from fixtures: 41
photos on a line under the parked camera and one generated 640x320 JPEG
(scripts/fixtures/street-level). All 7 photo steps now run in CI, plus a
real click on a coverage line and on a cone, the framing flight stopping
on close, the inert modal, the viewer returning into the panel, and a
reload keeping a collapsed panel collapsed (share ui token t).
- Fixture interception is limited to Mapillary hosts via CDP
Fetch.enable: page-wide request interception stalled Cesium's workers,
so the old fixture mode never drew anything on the globe.
- Failure evidence (screenshots, UI state, console, failed requests,
render errors) is written to qa-artifacts/ with keys and tokens redacted
and uploaded on failure; qa-artifacts/ is gitignored.
- Cesium render-loop errors fail the gate; Google 3D branches that cannot
run print as skips, and --strict rejects any other skip.
- Panel presses log their diagnostics, warn on a retry, and CI now fails
on any retry (QA_FAIL_ON_RETRY=1) since the rail settles; a press with
no pointerdown is a failure, not a retry.
- Assertion-gating sleeps 27 -> 1; the rejected-key "no requests" check
has a positive control.
Verified locally: strict fixture gate on the production build 28 ok + 2
"no Google 3D" skips (twice, fail-on-retry on); panel gate 5/5 plus no
render errors; live gate with a real token 25 ok + 3 fixture-only skips.
Co-Authored-By: Claude Opus 5.5 <[email protected]>