docs(meta): body-map-viewer workshop — rounds, measurements, outcomes, as-built briefing

The complete workshop record: four round-1 positions, five round-2 syntheses
(incl. Troblum's adversarial pass with addendum + final scorecard — all seven
findings resolved), both lead interviews, Qatux's round notes and the 8-section
workshop-outcomes.md (the lakes message-crossing documented as process
history), measurement ⑥ (set_pixel/c1) + the population-survey and chunk/S2
addenda in the measurement docs, the brief's appendix updated through ⑥, and
architecture-briefing-final.md — Jeroen's outline written back as-built
(six-level ladder, lakes, ~9MB resident global tier). README row: Complete.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-24 10:57:45 +02:00
co-authored by Claude Fable 5
parent b613443d51
commit 29c22cb728
20 changed files with 8689 additions and 3 deletions
@@ -0,0 +1,314 @@
---
title: "Round 1 Notes — Body Map Viewer Workshop"
description: "Compiled record of Round 1 positions: per-question summary, cross-agent agreements, conflicts/tensions, the open-for-synthesis decision list, and scope-drift check against settled premises."
type: workshop
status: active
workshop: body-map-viewer
agent: qatux
round: 1
created: 2026-07-25
---
# Body Map Viewer — Round 1 Notes
**Compiled by:** Qatux
**Round:** 1 — Positions against the measured appendix
**Participants:** Dudley, Araminta, Stig, Tyre (Troblum is round 2 only)
**Sources:** [dudley-round1.md](dudley-round1.md), [araminta-round1.md](araminta-round1.md),
[stig-round1.md](stig-round1.md), [tyre-round1.md](tyre-round1.md)
All four positions are argued from the measured appendix (①–⑤,
[the brief's appendix](body-map-viewer-workshop-brief.md#pre-workshop-measurement-appendix))
with no extrapolation beyond what was measured — each agent says so explicitly and
the citations check out against the four measurement docs.
---
## 1. Per-question position summary
### Dudley — server derivation (hydrology, step-canvas generation, chunking, cache tiers)
1. **Hydrology algorithm:** adopt T-1177's priority-flood + Dijkstra prototype as-is
(production-shaped, not throwaway). Cost: ~24 ms/body single-threaded at 512×256;
all 273 bodies in parallel ≈ 0.7–0.8 s; solved once per body (like `drainage::analyze`
today), held in a D-203-shaped cache, never re-solved per step/request.
2. **Cliff representation:** `elevation` (unchanged) + `channel_depth: u16` +
`cliff_edge: bool` — direct, non-lossy carry of solver output, no min/max synthesis.
Gorge carving measured **structurally rare** (zero carved cells across all three
production-scale benches) — weakens, doesn't eliminate, the wire-cost argument.
Explicitly defers the Phase-4-vs-Phase-5 scope call to Tyre/Araminta.
3. **Canonical-vs-viewport (red flag 3):** **viewport-sized canvases at every step,
no canonical fixed canvas past the orbital/region rung** — argued as a governance
necessity (D-226(d)), not merely a cache-cost preference. Fixed pixel budget per
canvas (e.g. 3840×2160), not literal client viewport echo.
4. **Compute-chunk partitioning:** the existing row-chunked `into_par_iter()` loop in
`build_district_window_layer` holds flat (190–220 ns/cell) at every measured size
and spacing — "the single most load-bearing measured result across all four gates."
Flags that courses are excluded from the replica-loop numbers (small, bounded tax,
not a different order of magnitude) and that chunking-as-seed-input-for-next-tier
is unmeasured, an open data-flow question for round 2/implementation.
5. **Cache tiers:** global/orbital tier only, "always keep" ≈ ~174 MB PNG-encoded
across all 273 bodies, as a D-203-shaped resource extension (not SQLite — cost
doesn't force it). Everything finer: `TTL = BASE_TTL[rung] × time_decay ×
distance_decay`, no disk tier below orbital.
### Araminta — named-feature encoding, per-gridunit payload, encoding continuity
1. **Named-feature encoding is three decisions, not one**, per the existing carrier
three-way rule: settlements/POIs → ids-with-lookup against the already-built
`atlas_city_names` pool (D-223) — presence + id per gridunit, never inline name.
Rivers → geometry already settled (T-1170 Ruling 1c `courses`); adds a new
whole-body `river_names: BTreeMap<edge_id, String>` lookup, many-edges-to-one-name.
Roads: out of scope but the pattern generalizes for free when they land.
2. **Payload schema:** the existing six dense fields stay as-is (no new classification
vocabulary); one new dense field `settlement_id: Vec<u32>`; the cliff fields are
**sparse, not dense** — a `cliffs: Vec<CliffSegment>` list parallel to `courses`,
not two more mostly-zero dense arrays (this differs from Dudley's dense-field framing
— see Conflicts below). States a hard client rule: color/style/tween presentation
only, never invent geometry/flooding/cliffs — missing data is a schema gap, not a
license to interpolate.
3. **Encoding continuity:** one colorizer family confirmed across every step (same
field set, same enum vocabularies, only sampling density changes). Average-back is
safe for continuous fields (`elev_q`/`temp_dc`/`moisture_q`) but **meaningless for
categorical fields** (`morphology`/`vegetation`/`glaciation`) — coarser steps must
re-derive via dominant-mode/plurality pick, never arithmetic mean. "Clearings/ponds
at low zoom" is scoped as sub-zone octave detail within an existing classification,
not new vocabulary — no new wire field needed.
4. **Wire-contract summary for synthesis:** confirms PNG-per-field for all dense arrays,
MessagePack-native for sparse lists; confirms the payload is categorically over the
30 KB cap at every size regardless of her additions — doesn't change the
tagged-envelope verdict.
### Stig — client component, step-cross UX, overlay compositing, cache store
1. **Client structure:** kill `_canvas.scale` entirely — two sibling layers replace it:
RTT terrain/classification layer (texel-exact `ImageTexture`, generalizing the
existing `_build_tile_texture`/`_rebuild_texture_if_needed` mosaic path from
per-tile to universal) + an unscaled screen-space annotation layer (world→screen
transform per frame, literal px sizes, deletes `_zs()`/`_zs_stroke()`/
`_zs_ring_radius()` by construction). T-1158 (viewer decomposition) is **subsumed**
— recommends cancellation with a supersession note, not separate scheduling.
2. **Step-cross UX:** hold-fetch-swap baseline (cursor-anchored), cache-hit swaps
immediately, cache-miss holds the current texture magnified during fetch (bounded
by measurement ①/④: uncached 330K canvas ≈ 75 ms derive + 5 ms encode). Morph/tween
is real but **strictly cosmetic and sequenced after** the baseline ships, as an
optional toggle. Upload cost (⑤) confirmed non-gating; prefers `texture.update()`
reuse over fresh allocation (avoids Texture object churn, despite being marginally
slower in raw ms) and L8 wherever a plane is single-channel.
3. **Overlay compositing (c1):** **ship CPU `set_pixel` coloring first**, not shaders
— today's code already does this and works; nothing in ①–⑤ prices CPU coloring cost
at step-canvas scale (330K–8.3M cells), which Stig names explicitly as **the missing
sixth measurement** (`Image.set_pixel` cost at those sizes). Shader migration is the
natural landing spot for T-1175's tapering work later, not a precondition for the
ladder itself.
4. **Client cache store:** **(iii) plain `FileAccess` cache dir + index** — rejects both
(i) server-side SQLite (relocates a client decision onto the server's process
boundary, dilutes the "server owns the DB" mental model) and (ii) godot-sqlite (a
relational addon for a point-lookup-with-expiry access pattern that doesn't need
one). Two-tier eviction: geometry entries get LRU + a retention floor at step-0
(the concrete "always keep global" mechanism, disk-budget-safe at ~440 MB where RAM
would not be); sim-state-tagged entries get an explicit TTL sweep (the literal
self-cleaning behavior Jeroen asked for). In-memory `atlas_window_tile_set.gd`-style
LRU stays on top as the hot tier.
### Tyre — governance ratification, gridunit↔D-243, determinism boundary, cliff ruling
1. **Governance delta ratified as concrete amendment texts** (five, drafted and ready
to file): D-166 corollary repoint (per-step derivation floor + display ratio,
between-step magnification named as a bounded exception not a silent violation);
T-1143 ruling 3 superseded for zoom transport only (cursor-centering/edge-scroll/
full-reset survive); `select_rung`/coverage-walk replaced by the step index;
**tagged-envelope migration ruled triggered, not merely likely** (21×–563× over
the ceiling, "off by two to three orders of magnitude before encoding is even
considered"); T-1170 carrier rule survives with a terminology gloss only
("windowed payload" → "tagged step-canvas envelope").
2. **Gridunit↔D-243 — the load-bearing call: gridunit SNAPS to D-243 rungs, does not
float.** Argued from determinism (`derive_at_metres` on viewport-relative spacing
would contaminate the cache key with a presentation parameter, breaking premise 9's
"canvas for a fixed seed never changes") and from cost (measurement ③ shows no
derivation-cost reason to invent a seventh spacing value — the six D-243 rungs
already cover every depth cheaply). What floats instead: the **display ratio**
(px-per-gridunit, 1×1 to 5×5), a pure client-side presentation parameter, decoupled
from spacing. Files the D-243 gridunit vocabulary entry as "a role, not a new rung."
3. **Determinism boundary:** generalizes the T-1170 course-invention ruling into a
three-bucket test — legal client interpolation is interpolation over a **closed,
server-supplied input set** (two arrived textures, wire-carried control points);
illegal is inventing any sample outside that set or smoothing across a step/
truncation/cliff boundary. Three concrete legal cases named (step-cross morph,
river/road curve-fitting through wire-carried stations, texture-to-viewport
scaling), two illegal (upsampling terrain detail, blending across a step boundary
as if continuous), one gray case flagged for Araminta (label de-dup at coarse-step
seams — legal only if identity, not proximity, drives it).
4. **Cliff ruling:** adopts Dudley's dominant-height + `channel_depth` + `cliff_edge`
representation outright (settled by what the solver emits, zero re-derivation).
**Rules Phase-4 Atlas scope, not deferred to Phase-5** — argues deferral would
silently contradict "settled hydrology" itself (a map showing a smooth shoreline
where the solver computed a carved channel misrepresents the settled state), and
that the rarity finding makes inclusion nearly free rather than making exclusion
safe. Flags his own caveat: rarity is measured on one real body (GJ1c) + two
synthetics, not surveyed across ~273 bodies — names this explicitly as something
for Troblum's round-2 adversarial pass to stress.
---
## 2. Cross-agent agreements (settled going into round 2 — do not re-litigate)
- **Dudley, Araminta, Tyre** all treat the **tagged-envelope migration as settled by
the numbers**, not a round-2 open question. Each cites T-1179 independently and
lands on the same order-of-magnitude reading (21×–563× over the 30 KB cap). Tyre's
position sharpens the brief's "likely triggers" framing to "triggered, unambiguous."
Round 2 should treat *whether* as closed and spend synthesis time only on the
*shape* of the tagged envelope (which is genuinely open — see §4).
- **Dudley and Tyre** independently land on **viewport-sized canvases, no canonical
fixed canvas past the orbital/region rung** — Dudley from cost-shape-plus-D-226(d)
necessity, Tyre from the same D-226(d) argument plus the determinism/cache-key
argument in his gridunit↔D-243 ruling. These are two independently-argued paths to
the same conclusion, not one agent citing the other — worth naming as convergent,
not coincidental.
- **Dudley, Araminta, and Tyre all adopt the T-1177 cliff representation
(`elevation` + `channel_depth` + `cliff_edge`) without dispute.** The only open
edge is dense-vs-sparse wire shape (§3) and Phase scope (§3), not the field set
itself.
- **Araminta and Tyre agree explicitly** that the client may never invent
geometry/flooding/cliff state — Araminta states it as a payload-schema hard rule,
Tyre generalizes it into the three-bucket determinism-boundary test. Same
conclusion, complementary framings (schema discipline vs. interpolation discipline).
- **Stig and Dudley/Araminta agree** that morph/tween between steps is real,
cosmetic-only, and non-blocking for the baseline — Stig sequences it as a
follow-up after hold-fetch-swap ships; Tyre's bucket-A ruling gives it the
determinism green light; nobody argues for shipping it in the first cut.
- **All four agents report their four gated measurements (①–④) as clean GO/VIABLE
results with no extrapolation** — no agent treats any of the pre-workshop numbers
as contested or requiring a re-run.
---
## 3. Conflicts and tensions (named, not yet resolved)
- **Dudley vs. Araminta — dense vs. sparse wire shape for the cliff fields.** Dudley's
round-1 text frames `channel_depth`/`cliff_edge` as "the wire field" without
specifying dense-array vs. sparse-list shape, and his cost argument ("cheap under
any of the encodings in ④'s table... PNG's DEFLATE in particular loves a field
that's constant almost everywhere") reads as implicitly assuming dense per-gridunit
arrays alongside the other six. Araminta explicitly rejects that shape: "as dense
per-gridunit arrays would be wasteful given near-zero occupancy" and proposes a
sparse `cliffs: Vec<CliffSegment>` list parallel to `courses` instead. Tyre's
synthesis leans toward Araminta's read ("I'd steer toward 'new arrays' over 'steal
a bit'... a sparse-friendly encoding... helps this field cost less than its raw
byte width suggests" — but this sentence is ambiguous on dense-vs-sparse, using
"new arrays" language while endorsing a sparse-friendly encoding argument).
**This needs an explicit round-2 resolution, not an inferred one** — the three
positions are close but not identical, and "new arrays" (Tyre) vs. "sparse feature
list, not arrays" (Araminta) is a real implementation-shape fork even if the wire
bytes converge.
- **Stig vs. the brief's implicit assumption — shader-vs-CPU (c1) is not close to
resolved, and Stig's position is a deferral, not an answer.** The brief posed c1 as
"genuinely open for the workshop"; Stig's position doesn't rule for CPU on the
merits so much as rule for CPU *by default* pending a measurement that doesn't
exist yet. This isn't a disagreement with another agent (no one else took a
position on c1), but it is a gap between what the brief expected round 1 to
produce (a position) and what it got (a sequencing recommendation plus a flagged
missing measurement) — surfaced here so the lead interview doesn't mistake "ship
CPU first" for "shader question closed."
- **Scope-boundary tension, not a disagreement: Dudley defers the Phase-4-vs-Phase-5
cliff-scope call to "Tyre/Araminta," and Tyre rules on it unilaterally** ("Phase-4
Atlas scope, not deferred to Phase-5") in the same round without an explicit
Araminta sign-off in her own document (her round-1 text adopts the field shape but
does not independently address the Phase-4-vs-Phase-5 question at all). Tyre's
ruling may be correct and well-argued, but strictly by the documents, it is a
two-of-three-invited-parties call, not a three-way confirmed one — worth a direct
Araminta confirm-or-object in round 2 rather than treating it as fully closed.
---
## 4. OPEN-FOR-SYNTHESIS decision list (for the lead interview)
Carried into Jeroen's Round 1 lead interview and/or Round 2 synthesis, in the order
the brief's Expected Outputs raises them:
1. **Step count and step factor** (largest → visible tile) — every agent treats this
as still-open and downstream of their own numbers; Dudley's table gives per-rung
costs but explicitly does not propose a step count. This is the brief's own
Jeroen-interview question 2 and remains unanswered by round 1.
2. **Map time axis** (climatology vs. current sim state for frozen/flooded) — not
addressed head-on by any of the four round-1 documents beyond Araminta's schema
table flagging it as "where the outline's sea/flooded distinction needs a decision
the workshop, not me, should rule on." Still fully open; this is Jeroen-interview
question 1.
3. **Tagged-envelope migration shape** (not the yes/no, which is agreed — see §2 —
but the concrete framing: new IPC message type, demux mechanics, how the legacy
`district_window` carrier coexists) — Tyre's amendment text names the destination
but defers the mechanical design; this is round-2 synthesis work.
4. **Cliff field wire shape: dense arrays vs. sparse feature list** — the Dudley/
Araminta/Tyre tension in §3, needs an explicit round-2 call, not an inferred one.
5. **Cliff field Phase-4 vs. Phase-5 scope** — Tyre ruled Phase-4; Araminta has not
independently confirmed; the §3 two-of-three tension needs closing explicitly.
6. **Shader-vs-CPU styling (c1)** — Stig's position is "CPU first, sequence shader
later," not a resolution of the open question the brief posed. **Depends on the
missing sixth measurement (below) before it can be treated as settled even
provisionally.**
7. **NEW: the missing sixth measurement — `Image.set_pixel` cost at 330K/2.07M/8.3M
cells (GDScript, client-side).** Stig names this explicitly as a gap: nothing in
measurements ①–⑤ prices CPU per-cell coloring cost at step-canvas scale, and the
c1 shader-vs-CPU call cannot be made "with the same rigor as everything else in
this brief" without it. This should be added to the measurement appendix (as ⑥)
or explicitly scoped as a round-2/pre-implementation follow-up — flagging per the
coordinator's instruction that this lands in the decision list, not just Stig's
own document.
8. **Chunking-as-seed-input-for-next-tier data flow** — Dudley flags this as
unmeasured and architecturally undecided (does a finer step re-derive independently
from `(seed, position)`, or literally consume the coarser step's output values?).
His own cost measurements assume independent re-derivation; round 2 needs to either
confirm that assumption or scope a new cost pass if the alternative is preferred.
9. **Region-as-step-0 confirmation** — Tyre's §1e amendment note flags this needs
confirming with Araminta in round 2 synthesis ("Region likely IS the global/step-0
rung, worth confirming").
10. **The gray determinism case — label placement de-duplication at step seams** —
Tyre flags this explicitly as unresolved and hands it to Araminta's named-feature
call; not yet addressed in her document.
---
## 5. Scope-drift check against settled premises
No round-1 document relitigates a settled premise (1–9) or a "settled by round A"
clarification-round item. Specific checks:
- **Stepped zoom, vocabulary (tile vs. gridunit), data-resolution tunable, hydrology
as deterministic equilibrium** — all four agents use the settled vocabulary and
model correctly throughout; no drift back to continuous zoom or "tile" misuse
detected in any of the four documents.
- **Server-determines-content / client-draws-art (premise 2)** — held firmly by all
four; Araminta's explicit client-rule statement and Tyre's determinism-boundary
bucket test both *reinforce* this premise rather than erode it. No agent proposes
client-side derivation of any invented-detail category.
- **CPU/Rust-server-side-only derivation, GPU presentation-only (premise 2, the c2
pre-empt)** — untouched; Stig's shader discussion (c1) is explicitly about
*styling/coloring already-derived data*, not derivation, and he states this
distinction himself. No drift toward GPU-side derivation anywhere in round 1.
- **One caution, not a violation:** Stig's structural recommendation to cancel
T-1158 outright (not just note supersession) is a **ticket-plan action**, one
category beyond a "position" — it's appropriate content for round 1 (the brief's
Expected Output 2 explicitly wants conflicting tickets named), but it is a
concrete cancellation recommendation rather than a design position, worth the lead
noting as an actionable item distinct from the architecture questions proper.
- **No Phase-5/Phase-6 drag detected.** Stig explicitly declines to scope Phase-5
reuse speculatively ("I don't want to speculatively design against now — that
would be exactly the kind of later-phase drag the cascade discipline warns
against") — this is the correct cascade-discipline call, named here because it's
a positive scope-discipline example, not a violation.
---
## Summary for the lead interview
Round 1 produced four internally consistent, cross-citing positions with **no cost
surprises** — every measured gate came back GO, and three of the four agents
converge on viewport-sized canvases and the tagged-envelope migration independently.
The genuinely open items are load-bearing but narrow: step count itself, the map
time axis, the cliff field's wire shape (dense vs. sparse) and phase scope, the
shader-vs-CPU call (blocked on a **new, named missing measurement** —
`Image.set_pixel` cost at step-canvas scale), and two smaller synthesis-confirmation
items (chunking/seed-input data flow, Region-as-step-0). Nothing here requires
relitigating a settled premise, and no scope drift toward later cascade phases was
observed.