--- title: "Workshop Brief: Body Map Viewer — the stepped map handler" description: "Design the new Atlas map handler: server-side content determination per zoom step, client map-art rendering (RTT + screen-space vectors), stepped gridunit ladder to ground level, cache/TTL architecture, wire contract" type: workshop status: active workshop: body-map-viewer created: 2026-07-25 decision_refs: [D-166, D-226, D-227, D-243, D-239, D-225, D-010] --- # Workshop Brief: Body Map Viewer — the stepped map handler ## The Question Jeroen's design outline ([jeroen-outline.md](jeroen-outline.md)) replaces the Atlas render mechanism: **content determination moves to the server** (per-gridunit data canvases generated per zoom step, doubling as seed input for the next tier down), **the client becomes a map-art function** (colorize, style, annotate — never invent geometry), and **zoom becomes a stepped ladder** from the body-global view down to ~10 px per 1 m tile. This dissolves the T-1176 error class at the root (there is no zoom-scaled canvas anymore) and turns the D-166 seamless-ladder mandate into a concrete serving + caching + rendering architecture. The premises are settled (below). The workshop designs the remaining load-bearing pieces: the wire contract, the cache tiers, the step ladder itself, and four honest risk confrontations — against **measured numbers, not extrapolation** (the T-1143 planetary rung is the named cautionary tale). ## Context — settled premises (not for relitigation) From the outline + two clarification rounds ([clarifications.md](clarifications.md)) + prep rulings (Jeroen, 2026-07-25): 1. **Lazy/late compute.** Nothing computed in the game loop that game state doesn't need; smart precache allowed, never blocking user output. TTL = f(detail level, time, distance); player focus = character location AND atlas viewport. 2. **Server determines content; client draws art.** The server answers "what is at this world coordinate at this zoom step"; the client styles it. Derivation is **CPU/Rust server-side only — GPU is presentation only** (locked; the two-language-mirror liability, T-1170 precedent). 3. **Stepped zoom.** Scroll clicks through discrete levels; cursor-anchored centering, edge-scroll pan, and full-zoom-out-reset survive. A client-side morph/tween between steps is an investigation item (cosmetic only, never re-derivation). Supersedes the continuous-multiplier zoom (T-1143 ruling 3) — recorded as a deliberate revision at filing. 4. **Vocabulary:** *tile* = the 1×1 m ground unit (D-243), only. *Gridunit (at zoom level)* = the per-step data cell. The ladder bottoms out at ~10 px per tile on the viewport's smaller axis. 5. **Data resolution is a tunable:** 1 gridunit per screen px ideal; ~1 per 5×5 px display unit acceptable ("crisper is better, but the computer must not catch fire"). Decided by measurement. 6. **Hydrology = deterministic equilibrium.** Lake fill, overflow re-routing, gorge carving: a settled end-state, pure function of seed + moisture/climate, extending D8 drainage. No stateful simulation. 7. **Render baseline (locked):** per-step data canvas → **render-to-texture** terrain layer (texel-exact, drawn 1:1 or at the tunable ratio) + **unscaled screen-space sibling layer** for vector annotations (literal px sizes). Open *within* the baseline: shader-vs-CPU styling (c1) and the step morph. 8. **Step boundaries = compute-chunk boundaries** for the deterministic generators. 9. **Jeroen's cache direction (to cost and confirm, not overturn):** the primary atlas cache lives **client-side** — received step canvases are retained (compressed to what's needed) and simply not re-requested; determinism makes this safe (a canvas for a fixed seed never changes). Only sim-state components (frozen/flooded — "maybe shorter ttl on the climate sim state components") need invalidation at all. **Open within this premise (Jeroen, sign-off round):** whether the client needs a dedicated cache *store* — disk-backed, redis-like TTL semantics, self-cleaning records — rather than in-memory retention only; his lean: *"on disk probably, but with self cleaning of cache records."* D-227's discipline applies client-side too: whatever the store, it is an evictable cache, never a source of truth. **Governance delta** (full analysis: [tyre-implications.md](tyre-implications.md) §1): amends the D-166 corollary (anti-over/undersampling becomes a *per-step* property — repointed, not deleted), T-1143 ruling 3 (stepped supersedes continuous), the `select_rung` coverage walk (replaced by step index), D-243 (adds *gridunit*), and likely triggers the **tagged-envelope migration** (D-225's deferral — expected scope, not a risk to avoid). Survives untouched: D-227 derive-don't-store (the TTL cache is its concrete eviction policy), D-010, D-226(d)'s whole-body prohibition, D-169/D-170, and the T-1170 carrier three-way rule (repointed "window" → "step canvas"). ## Red flags the workshop must confront (stated honestly, not to relitigate) 1. **Between-step magnification.** Just before a step-cross the held texture is a magnified coarser composite — the exact thing D-166 forbids — for one step interval. Step count + px-per-gridunit are the knobs that keep it imperceptible; the D-166 amendment must own this. 2. **"Always keep global" memory.** ~1.6 MB/body at 5×5 ≈ **~440 MB** across ~273 bodies if never-evict; ~13 GB at 1×1. The cache deliverable produces a number, not a vibe: always-derivable-fast vs permanent residency (vs disk tier — which must stay consistent with D-227). 3. **Canonical-vs-viewport canvas is a governance boundary at the deep end.** A canonical fixed canvas at 1 m spacing is a near-whole-body metre-resolution derivation — violating the D-226(d) prohibition that survives. Viewport-sized keeps the deep ladder legal by construction. Not just a cache tradeoff. 4. **Cliff/multi-height gap.** Settled hydrology *produces* gorges; a gorge is two heights in one gridunit; the sketched payload carries one height. Either a vertical-structure field at Phase-4 Atlas scope, or cliffs are Phase-5 geometry with a "steep" classification on the map. The hydrology measurement must output the cliff representation, not just cost. 5. **Tagged-envelope migration is expected scope** — tier: challenging but doable (executing D-225's planned deferral, not inventing a migration). ## Participants Dudley, Araminta, Stig, Tyre, Troblum (round 2 only) (+ Qatux documenting, SI reviewing ticket outputs) ## Questions for participants **Dudley**: 1. The equilibrium hydrology solver: algorithm choice (priority-flood family with overflow re-routing + gorge carving), measured cost at 512×256 and 4K-class, and the **cliff/two-heights output representation** (red flag 4). 2. Step-canvas generation and the canonical-vs-viewport data canvas (red flag 3): cost, cache shape, and the D-226(d) boundary at the deep steps. 3. Compute-chunk partitioning: how a step's derivation decomposes across the Rayon queue (chunked par_iter at 330K–8.3M cells — measured, not extrapolated) with step boundaries as the chunk boundaries (premise 8). 4. Cache tiers server-side: what "always keep the global level" costs across ~273 bodies (red flag 2), and the TTL(detail, time, distance) eviction policy as D-227's concrete instantiation. **Araminta**: 1. Named-feature encoding (THE wire decision): dense classification rasters + sparse feature list vs inline identity vs ids-with-lookup — for rivers, settlements, roads, POIs and their names. Jeroen's constraint: "best fidelity vs wire contract possible; the information the client needs needs to be there." Feeds the tagged-envelope call. 2. The per-gridunit payload schema: exactly which typed fields the map-art function receives (biome, ground type, height, flooded/frozen/sea, river/settlement presence + identity), and what the client is allowed to do with them. 3. Encoding continuity across steps: one colorizer family (T-1143 §6), average-back across step boundaries, and what "different classes of content at lower zoom" (forest → clearings/ponds) means for the classification vocabulary. **Stig**: 1. The client map-drawing component: structure of the RTT terrain layer + unscaled screen-space annotation layer, replacing the `_canvas.scale` model; what of the existing atlas/ cluster survives vs retires (T-1158 decomposition folds in here). 2. Step-cross experience: hold-fetch-swap, the morph investigation (cosmetic tween only), ImageTexture upload cost per step, and the client-side cache (premise 9: retain received canvases compressed, stop re-requesting; sim-state components TTL'd). 3. Overlay compositing under RTT (temperature/moisture/vegetation toggles, glaciation modifier): shader vs CPU styling — the (c1) decision, including T-1175's tapering/width grammar coming along for free if shaders win. 4. The client cache store (premise 9's open half): does the map cache need a persistent, disk-backed store with self-cleaning TTL records (redis-like semantics in an embedded shape), or does in-memory retention suffice per session? **Fact base (verified, sign-off round): SQLite ships with the game but not inside the Godot client** — the Rust server (a local subprocess) owns the SQLite path (`systems.db`, D-138 persisted state); the client's only addons are gdUnit4 and messagepack. Three candidate shapes to cost (with Dudley on the first): (i) **server-side SQLite cache DB** — zero new dependencies, "client-primary" reads as *local-machine-primary* (a warm local subprocess answering from disk is nearly as snappy as client memory); (ii) **godot-sqlite addon** in the client — a real client-side store, one new dependency; (iii) **plain Godot `FileAccess` cache dir + index** — no dependency, hand-rolled TTL sweep. Hard boundary in every shape: the cache is its own file — `systems.db` is the read-only canonical snapshot (asset-pipeline golden rule) and never doubles as cache. Size the store from the wire table (④); D-227's cache-never-truth constraint applies at every tier. **Tyre**: 1. Ratify the governance delta (§1 of your implications pass) as concrete amendment texts: D-166 corollary repoint, T-1143 ruling revision, D-243 gridunit entry, the tagged-envelope decision. 2. The gridunit ↔ D-243 reconciliation: does gridunit spacing snap to the absolute-metre rungs or float freely per viewport/step? (Your "most load-bearing vocabulary reconciliation.") 3. The determinism boundary in the new split: server-resolved geometry vs client art — where exactly may the client interpolate ("tween rivers/roads") without creating a second truth? 4. The cliff/multi-height ruling proposal (with Dudley's measurement output). **Troblum** (round 2): 1. Stress the cost story against the measured appendix — find the extrapolation. 2. The memory budget (red flag 2) and the wire-size table under realistic play patterns (step-thrashing, body-hopping). 3. The deepest-step extent vs D-226(d) (red flag 3) — verify the chosen canvas policy actually holds the boundary. **Questions for Jeroen** (lead interview, each round): 1. Map time axis: climatology vs current sim state for frozen/flooded — your "shorter ttl on climate sim state components" hint as the working model? 2. Step count and the step factor (largest → visible tile), once the measured costs frame what a step can afford. 3. Canonical vs viewport-sized data canvas — you saw value in both; the deep-step governance boundary (red flag 3) may force the split answer (canonical shallow, viewport deep). 4. Phase-5 reuse: is the map-drawing component the future in-world viewport's code path, or Atlas-only? (Scopes the component's ambitions.) ## Workshop Format **2 rounds + lead interview per round; extendable at Jeroen's call** — after each round Jeroen is asked whether another round is needed, for as long as he feels necessary (workshops are not closed early on partial convergence). - **Gate:** round 1 does not start until measurements ①–④ below are done and their numbers are in this brief's appendix (⑤ may land during round 1). - **Round 1 — positions.** Each core participant answers their question slice against the measured numbers, in writing (`{agent}-round1.md`). - **Lead interview 1.** Jeroen rules on what round 1 surfaced (step count, canvas policy, map time axis). - **Round 2 — synthesis.** Cross-cutting decisions: the wire contract + tagged-envelope call, gridunit↔D-243, cache-tier architecture, the cliff ruling. Troblum's adversarial pass runs here against the whole picture. - **Lead interview 2 → sign-off or another round.** - **Filing:** D-records claimed and written before dismissal (amendment set per the governance delta + the new render-architecture record), **including the explicit deprecation sweep (Expected Output 2) — a Clerk consistency audit verifies no conflicting record or ticket is left standing before the team is dismissed**; tickets drafted by the lead, reviewed by SI; Qatux produces `workshop-outcomes.md` and diagram updates. ## Pre-workshop measurement appendix — MEASURED (2026-07-25, 16-core / Rayon 14 / RX 9070, release builds; all numbers post-date a background-load closure with stability re-runs — details + repro commands in each linked doc) **The gate is satisfied: ①–④ measured, ⑤ measured. Round 1 may start.** | # | Ticket | Headline result | Doc | |---|---|---|---| | ① | T-1177 | **Settled hydrology VIABLE**: 512×256 ~24 ms/body; all 273 bodies Rayon-parallel ~0.7–0.8 s; 8.3M cells ~5.7 s single-thread (no production path needs it synchronously). Cliff representation: dominant height + `channel_depth` + `cliff_edge` flag. Finding: gorge carving is structurally RARE (priority-flood finds true spill levels; zero carved cells at production scales — needs chained-basin geometry). Solver: priority-flood + Dijkstra overflow, pure function, determinism-proved. **POPULATION SURVEY addendum (post-adversarial, Troblum finding that the 273-body bench was one body solved 273×): all 267 real committed bodies solved independently, ~0.86s total, ZERO carved cells / zero cliff_edge cells population-wide (267/267) — the rarity finding upgrades from "one real body + structural argument" to "not observed anywhere in the real population," strengthening the cliff Phase-4 wire-cost case.** | [t1177](measurements/t1177-hydrology.md) | | ② | T-1178 | **Parallel throughput HOLDS at scale** (the T-1143 extrapolation gap, closed): ~190–220 ns/cell parallel flat from 330K→8.3M cells; 330K canvas ~64 ms, 2.07M ~0.4 s, 8.3M ~1.7–1.8 s (7.5–8.8× speedup); single-thread flat ~1.65 µs/cell, matches prior baseline within 8%. Throughput cross-validated on three bodies across two call paths (square real-`build_district_window_layer` = courses-light, 3–10 in window; rectangular replica loop = courses-empty by construction — agreeing within 0.3%); the courses-inclusive rate at real production density is measured once, GJ1c 330K with 18 courses at 195.0 ns/cell (within 2%, consistent with the <5% course-cost bound). | [t1178+t1154](measurements/t1178-t1154-derive-bench.md) | | ③ | T-1154 | **Block GO, Tile GO on cost** (~1.8–1.9 µs/cell, same band as District/Quarter). Octave cutoff buys ZERO below District spacing (verified: wavelength table bottoms at 128 m). Deepest-step realistic canvas (216×384 m @ 1 m = 83K cells): **~17 ms parallel — trivially interactive**. `voxel_relief` already in the Atlas path; `voxel_mosaic` untouched by it. Real gates are wire carrier + D-226(d) canvas policy, not cost. | [t1178+t1154](measurements/t1178-t1154-derive-bench.md) | | ④ | T-1179 | **PNG-per-field wins everywhere** — smallest AND fastest: 330K canvas = 638 KB (0.32× raw, 5.4/3.6 ms enc/dec) vs raw rmp 1.99 MB; RLE loses to raw (elev/temp near-noise per cell). **No encoding brings a step canvas near the existing windowed-payload budget** (best case 21× the ~30 KB cap at the smallest size; 563× at 8.3M) — the tagged-envelope migration cannot be dodged by payload optimization. Whether the letter of the D-226 §2 *field-count* rule is what triggers it is a workshop synthesis call, not a measured result. Corrected density: 6.00 B/cell measured raw. | [t1179](measurements/t1179-wire-table.md) | | ⑤ | T-1180 | **Upload cost is a non-issue**: worst case (8.3M px RGBA8 create) ~3.2 ms median, ~2.4–2.9 ms frame-delta spike — never near the 16.6 ms budget. **L8 is 4–9× cheaper at every size** (~0.5–0.7 ms at 4K). Prefer `texture.update` reuse on step-cross; use L8 for single-channel planes. Windowed-only measurement (headless renderer fakes uploads). | [t1180](measurements/t1180-imagetexture.md) | | ⑥ | round 2 (lead interview 1 ruling) | **MEASURED — CPU colorize is the c1 gate, not upload.** `Image.set_pixel` flat ~78 ns/cell (330K→8.3M, no cliff): 330K ~25.7 ms, 2.07M ~165 ms, 8.3M ~644 ms. Direct `PackedByteArray` write is ~2× SLOWER (~153 ns/cell) — counter to the naive "skip the method call" assumption; **prefer `set_pixel`**. At the realistic per-step canvas size (330K, Dudley's viewport-sized recommendation) colorize is cheap (25.7 ms) and ranks second only to server derivation in the arrival-side cost chain (ahead of ④'s decode and ⑤'s upload); at the 8.3M stress-ceiling size it becomes non-trivial (~1/3 of server derive time at that size) — reinforces viewport-sized canvases over any canonical whole-canvas colorize. Headless-valid (pure CPU, no GPU path, unlike ⑤). | [t-setpixel-c1](measurements/t-setpixel-c1.md) | Bench code (all `#[ignore]`d release tests): `server/src/atlas/hydrology_equilibrium.rs` + `server/tests/hydrology_equilibrium_bench.rs`, `server/tests/bmv_gridunit_bench.rs`, `server/tests/wire_encoding_bench.rs`. Client-side: `client/tests/` (temporary uncommitted drivers per measurement doc, ⑤/⑥). ## Input Documents | Doc | Why | |---|---| | [jeroen-outline.md](jeroen-outline.md) | The design, verbatim | | [clarifications.md](clarifications.md) | Settled premises + deferred deliverables, verbatim answers | | [tyre-implications.md](tyre-implications.md) | Governance delta, candidate re-ranking, red flags | | [prep-grounding.md](prep-grounding.md) | Current mechanism, error-class evidence, measured baselines | | docs/architecture/atlas-zoom-ladder-t1143.md | The predecessor ladder design + Jeroen's three rulings | | docs/architecture/river-courses-t1170.md | The carrier three-way rule (survives, repointed) | | governance/decisions/architecture.md | D-166 amendment+corollary, D-226 chain, D-227, D-243, D-239, D-225 | ## Expected Outputs 1. **D-record set:** the body-map-viewer render architecture (new record) + the amendment set from the governance delta (D-166 corollary repoint, T-1143 ruling revision, D-243 gridunit vocabulary, tagged-envelope decision, cache/TTL policy as D-227's instantiation). 2. **Explicit deprecation sweep — no conflicting record left standing (Jeroen, sign-off round).** Every DQR record and ticket that conflicts with the decided setup is explicitly amended, superseded, or deprecated in the same filing pass — never left silently contradicting. Starting set = the governance delta's known conflicts (the D-166 corollary sentence, T-1143 ruling 3 and its `select_rung` coverage-walk model, the windowed-family ceiling if the tagged envelope is chosen); completed by a systematic consistency sweep (Clerk audit) to catch conflicts the delta did not name. Conflicting tickets are cancelled or re-scoped with the supersession noted on the ticket (T-1158 subsumed, T-1154 repurposed as measurement ③, T-1175/T-1157/T-1174 reconciled in the ticket plan). 3. **The step ladder:** step count, step factor, per-step gridunit spacing and its D-243 relationship, the deepest step's canvas policy. 4. **The wire contract:** per-gridunit payload schema + named-feature encoding + envelope framing, with the measured wire-size table. 5. **The cache architecture:** client-primary retention (premise 9) + the client store decision (in-memory vs disk-backed with self-cleaning TTL) + server tiers + TTL formula + the global-tier memory answer. 6. **Ticket plan:** implementation chain (measurement-informed), explicitly reconciling T-1158 (viewer decomposition — subsumed), T-1175 (polish — styling engine dependent), T-1157 (capture harness — the new mechanism's verification story), T-1174, and the retirement path for the `_canvas.scale` model. 7. `workshop-outcomes.md` + updated diagrams (Qatux).