Skip to main content

mapv10 Current Checkpoint - 2026-05-06

Status: SUPERSEDED by Wave 2 (forbidZ0UnderlayAtPrimaryZ + MAX_ANCESTOR_Z_DISTANCE = 1)

This checkpoint describes the resolver/sidecar/loader state as of 2026-05-06, before the LOD/Data Coherence Foundation chain landed. Wave 2 redesigned the resolver+sidecar contract: MAX_ANCESTOR_Z_DISTANCE = 1 (viewer/src/renderer/lod/RenderResolver.ts) caps ancestor promotion at a single z step, the structural-parent walk replaces bounds-containment-alone selection, and the isFullyResident AND-gate (RenderResolver.ts) requires both CPU and GPU residency before a tile can act as a fallback source. Wave 1 introduced the typed gate vocabulary (forbidZ0UnderlayAtPrimaryZ, ancestorZDistanceMax, sidecarReadyForActiveMeshes, noPlaceholderTextureBound, coverageHoleMax, labelTextUniqueness, labelTextMinDistinctCount, labelMaxDuplicatesForText) in viewer/src/scenarios/scenarioTypes.ts, evaluated by viewer/scripts/scenario-gates.mjs. The text below is preserved verbatim for provenance — it describes the pre-Wave-2 picture and must not be cited as the current resolver, fallback, or sidecar contract. For current behavior read architecture.md § "Streaming, LOD Selection, And Cache", docs/viewer.md § "Ancestor-fallback 'kicking'", and docs/performance-and-streaming-hardening-spec.md §7.3.


This checkpoint records the current mapv10 state after the latest browser/debug hardening pass. It exists so future work does not reopen already-closed loader, preview, and lifecycle issues by accident.

What Changed In This Checkpoint

  • The 5443 viewer target was verified at http://100.97.188.110:5443/?manifest=/mapv10/runs/continent-lod6/manifest.json.
  • The browser console issue was split into two causes:
    • classifier.js / TensorFlow backend registration messages are injected browser-extension noise.
    • Unexpected token '<' was a real viewer-load failure caused by Vite returning the HTML shell for a JSON artifact path.
  • viewer/src/data/rasterLoader.ts now checks JSON response media type and reports artifact-specific failures such as: manifest expected JSON from /continent-lod6/manifest.json but got text/html.
  • viewer/src/data/manifestLoader.ts now uses the same JSON-aware helper for the top-level run manifest and validation summary.
  • viewer/src/ui/manifestUrl.ts normalizes browser query values before load: no value, /continent, or /continent-lod means the canonical /mapv10/runs/continent-lod6/manifest.json, and run-directory inputs such as /continent-lod6 become /mapv10/runs/continent-lod6/manifest.json. The loader should not be asked to parse the Vite app shell from shorthand paths such as /continent.
  • viewer/server/mapv10ArtifactMiddleware.ts makes generated runs a first-class artifact namespace. /mapv10/runs/<run-id>/... serves run files with JSON content types, range support for large binary products, run-status/list endpoints, and typed application/problem+json failures. Legacy /continent-lod6/... paths are intercepted as protected compatibility paths so missing artifacts no longer fall through to the Vite app shell.
  • The viewer now surfaces load progress as first-class UX: manifest fetch, generated product loading, validation, renderer setup, and first tile residency emit typed progress events. The shell shows a boot progress panel and a persistent stream panel for network queue, terrain/data residency, and frame-budget work, so map loading state is visible without opening the developer HUD.
  • Load failures now use user-facing diagnosis instead of repeating raw exceptions across the chrome. HTML-app-shell JSON fallbacks are presented as missing generated fixture/artifact states with a clear recovery action and a collapsed technical detail. The dev HUD is hidden by default and remains available through F3; selection and scale readouts stay hidden until a run is actually loaded.
  • viewer/src/data/__tests__/rasterLoader.test.ts covers Vite HTML fallback for the manifest path, byte-checked product JSON path, and malformed JSON.
  • The Products debug drawer is lazy. It no longer renders product rows or preview images until the drawer is opened.
  • The drawer loads only global overview previews. Per-tile previews stay in the artifact tree and are summarized in the drawer instead of creating thousands of hidden image requests.
  • viewer/scripts/verify-browser.mjs now records preview-request counts and fails the browser proof if normal map loading fetches previews/ or tiles/previews/ debug images.
  • The browser proof now captures all current map modes at both continent overview and location detail: terrain, political, routes, elevation, slope, and normals.
  • The terrain resolver no longer renders deeper loaded parent/ancestor underlay beneath direct-resident child terrain. Parent terrain is still used for real missing-child fallback; a single z0 root remains as broad background context.
  • Terrain commits are opaque once resident. Continuity comes from resolver fallback instead of alpha-crossfading two different terrain LOD rasters, which was creating temporal shimmer around water masks and coastlines.
  • Continuous terrain sidecar textures now use mipmapped linear filtering with modest anisotropy. Discrete semantic textures such as province IDs, biome enums, LUTs, and selection masks stay nearest-sampled.
  • Terrain LOD selection now gates on both geometric height SSE and raster/material sample footprint SSE. This prevents the root z0 water/splat/coast masks from staying active through slow continent-to-realm zooms, which was the source of the coarse crawling shoreline noise in the manual screenshots.
  • Open-sea fragments from terrain tiles are discarded when they are outside the global location-id mask; the dedicated ocean base owns that surface so coarse sea-mask texels no longer write depth over it.
  • The browser proof now captures a nine-step slow zoom screenshot sequence between full-continent and close-realm scale and asserts that terrain monotonically refines off z0 before the coarse coast raster can magnify.
  • The render resolver keeps a single resident z0 terrain root as background context behind refined primary tiles, while reserving deeper parent underlays for real missing-child fallback. This prevents the refined focal tile from becoming a rectangular island over the ocean during slow zoom.
  • Coarse terrain levels now use full-coverage selection while the selected level remains small enough to fit inside the full-coverage budget. On the lod6 continent this keeps z1 and z2 stable while panning at the same camera distance instead of swapping a target-centred patch against the z0 context surface.
  • The browser proof now captures a five-step constant-distance camera-move sequence and asserts that the selected z2 coverage and visibility signature stay stable while the camera target moves.
  • viewer/scripts/verify-browser.mjs now owns local screenshot baselines for visual regression. --update-baseline snapshots the canonical proof images under viewer/baselines/browser/<run-id>, and --check-baseline compares a fresh proof run against that manifest with changed-pixel ratio, RGB RMS, max channel delta, and diff PNG output on failure.
  • Label placement reserves fixed UI regions, so close-up labels no longer sit under the HUD, mode bar, layer panel, inspector, or scale ruler.
  • Current shoreline fix owner: open sea must be a generated water mesh derived from seaRegions.json with land polygons as holes. Terrain outside-land clipping must use the global location-id semantic raster; the per-tile waterMask remains a topology/material hint and must not own open-sea clipping.

Current Verification Evidence

Latest local checks:

npm test -> pass, 17 files / 239 tests
npm run build -> pass
artifact namespace HTTP probes -> pass
/mapv10/runs/continent-lod6/manifest.json -> 200 application/json
/continent-lod6/manifest.json -> 200 application/json (legacy protected)
/mapv10/runs/missing-run/manifest.json -> 404 application/problem+json
Range: height.f32.bin bytes=0-15 -> 206 partial content
browser failure UX smoke -> pass
verification/ux-friendly-load-error.png
browser ready UX smoke -> pass
verification/ux-ready-no-debug-hud.png
node scripts/verify-browser.mjs
--proof-name artifact-namespace-proof
--timeout-ms 180000
--port 5195 -> pass
npm run verify:browser:baseline:update
-- --port 5196 -> pass, 33 baseline screenshots written
npm run verify:browser:baseline
-- --port 5197 -> pass, 33 screenshots compared
maxChangedRatio 0.0002752544
maxRms 1.7784523
npm run verify:browser:baseline
-- --port 5198
--proof-name m10-lod6-visual-baseline-zero-threshold
--baseline-pixel-tolerance 0
--baseline-max-changed-ratio 0
--baseline-max-rms 0 -> expected fail, 8/33 diffs written
git diff --check -- examples/map/mapv10
-> pass

Latest browser proof network summary:

totalRequests: 3161
uniqueRequests: 3150
previewRequests: 0
tilePreviewRequests: 0
forbiddenRootHighDetailFetches: []

The proof covers continent overview, province cluster, close route detail, boundary views, zoom-back-out, all six current map modes at overview/detail, a dedicated slow zoom sequence, a constant-distance camera-move sequence, and the missing-required-product failure case.

Current Work Queue Interpretation

next-work.md currently marks the renderer hardening chain as resolved through:

  • lifecycle/hitch metrics and warn/fail budgets
  • label lifecycle candidate gating and frame-budgeted residency
  • strict parent fallback contract
  • terrain geometric-error SSE
  • terrain lifecycle pacing
  • route adaptive batching and upload pacing

That means the next active lane should not be another generic lifecycle-metrics pass unless new scenario evidence opens a fresh owner.

Valenar integration is deferred. Valenar must continue to use its dummy world-42 fixture while mapv10 is still being refined.

The immediate mapv10 work stays on the producer/render side:

  • wire visual baseline checks into CI/local clean-fixture verification
  • keep verifying fully zoomed-out, slow-zoom, constant-distance camera-move, and close geographic views in the real browser
  • continue fixing any newly evidenced base-map visual owner through generated products and scenario proof, not ad hoc shader parameter drift
  • keep the browser proof checking JSON loader failures and forbidden preview requests
  • only produce/export data structures from mapv10; do not wire Valenar runtime consumption yet