docs(meta): body-map-viewer workshop brief signed off — T-1176 prep session
Three-way prep session (Jeroen + lead + Tyre) for the map-handler revision: Jeroen's design outline captured verbatim, two clarification rounds, Tyre's governance-delta/implications pass, brief co-written and ratified (zero misrepresentations, zero blocking gaps), signed off by Jeroen with three edit rounds (vocabulary repair tile->gridunit, client cache-store question with SQLite fact base, explicit DQR/ticket deprecation sweep as gated deliverable). Workshop: 5 seats (Dudley/Araminta/Stig/Tyre + Troblum r2), 2 rounds + lead interview extendable at Jeroen's call, round 1 gated on measurements T-1177/T-1178/T-1154/T-1179 (T-1180 non-gating). T-1176 in_progress with gate blocker edges; T-1154 repurposed as measurement (3) and set ready. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -17,3 +17,7 @@ INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updat
|
||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCEZ47J16E3XKE957HGR8H4', '06FRCF1A0K41K6S85X0HTXACHM', '2026-07-21 19:52:17.907', '2026-07-21 19:52:17.907', NULL, 'd01687ee1d1ae90d4deff2dede04cd47', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRJD57678SVWD7XTSV9E3MSW', '06FRV224PD3NMWKR1AAC0J0D58', '2026-07-23 05:52:32.863', '2026-07-23 05:52:32.863', NULL, '82d45a9df84bc505496deee667c9ee1c', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRJD57678SVWD7XTSV9E3MSW', '06FRV2GT1FQVATWX641KY9K66C', '2026-07-23 05:54:30.767', '2026-07-23 05:54:30.767', NULL, 'fce045ecebed0a640b95cc17f7f130f3', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRZKAV6ZK4KAZ6YCGFNBQ4T0', '06FRY9W24PV55Z6FMW8TEM7XER', '2026-07-23 16:27:44.598', '2026-07-23 16:27:44.598', NULL, '75525a43db615fb250602e74b76f8803', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRZKBTD7VKSXNWADWHV3QDQ8', '06FRY9W24PV55Z6FMW8TEM7XER', '2026-07-23 16:27:48.490', '2026-07-23 16:27:48.490', NULL, 'fff210cdb088a9b906b7c32affb24535', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCF0CX1Y5DTD3ER2JCDT27G', '06FRY9W24PV55Z6FMW8TEM7XER', '2026-07-23 16:27:51.709', '2026-07-23 16:27:51.709', NULL, '58d44b37860bb90007503623bdbb4477', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
||||
INSERT INTO ticket_deps (blocker_record_id, blocked_record_id, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRZKCN13EF5TD9EZTXMSJ7EG', '06FRY9W24PV55Z6FMW8TEM7XER', '2026-07-23 16:27:57.651', '2026-07-23 16:27:57.651', NULL, '30cf45ca163b805f90e444bf9a054a26', 2) ON CONFLICT(blocker_record_id, blocked_record_id) DO UPDATE SET updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > ticket_deps.updated_at OR (excluded.updated_at = ticket_deps.updated_at AND excluded.hash > ticket_deps.hash);
|
||||
|
||||
@@ -36,3 +36,4 @@ docs/workshops/
|
||||
| [v0.1 Content Scoping](v01-content-scoping/) | — | Complete (2 rounds + closing, 38 tickets created) |
|
||||
| [Art Direction & Mood Board](art-direction-mood-board/) | — | Complete (3 rounds + closing + technical session, D-019 amended, D-043-D-052 confirmed) |
|
||||
| [Control & Interaction Scheme](control-interaction/) | — | Brief ready |
|
||||
| [Body Map Viewer](body-map-viewer/) | — | Brief signed off (2026-07-25); round 1 gated on measurements T-1177/T-1178/T-1154/T-1179 |
|
||||
|
||||
@@ -0,0 +1,269 @@
|
||||
---
|
||||
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 (owners; numbers land here before round 1)
|
||||
|
||||
| # | Measurement | Owner | Effort |
|
||||
|---|---|---|---|
|
||||
| ① | Equilibrium hydrology solver prototype + bench (512×256 and 4K-class) incl. cliff representation output | Dudley | 1–2 d |
|
||||
| ② | Per-gridunit derive at real canvas sizes (330K and 8.3M cells, production par_iter path — no extrapolation) | Dudley | 0.5 d |
|
||||
| ③ | T-1154 block/tile rung costs (now unblocked) — prices the ladder's bottom | Dudley | 0.5 d |
|
||||
| ④ | Wire-size table for candidate encodings (raw/bit-packed/RLE/PNG; MessagePack round-trip on one real canvas) | Araminta + Dudley | 0.5 d |
|
||||
| ⑤ | Godot ImageTexture upload cost per step-cross (330K–8.3M px) | Stig | 0.25 d |
|
||||
|
||||
## 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).
|
||||
@@ -0,0 +1,77 @@
|
||||
---
|
||||
title: "Body Map Viewer — Clarification Rounds"
|
||||
description: "Q&A rounds on Jeroen's outline (T-1176 prep session): settled premises vs deferred workshop deliverables"
|
||||
type: workshop
|
||||
status: active
|
||||
workshop: body-map-viewer
|
||||
created: 2026-07-25
|
||||
---
|
||||
|
||||
# Clarification Rounds (prep session)
|
||||
|
||||
Two AskUserQuestion rounds on [jeroen-outline.md](jeroen-outline.md), questions
|
||||
merged from the lead and Tyre. Answers verbatim where they carry nuance.
|
||||
|
||||
## Settled by round A
|
||||
|
||||
1. **Zoom model — fully stepped.** *"fully stepped zoom, but still cursor centers
|
||||
and the edge scrolling also works. Just, we click through the zoom levels on
|
||||
scroll. We could investigate a client side morph."* Scroll wheel steps through
|
||||
discrete zoom levels; cursor-anchored centering and edge-scroll pan are retained;
|
||||
a client-side morph/tween between levels is an investigation item. **Supersedes**
|
||||
the continuous-multiplier zoom of the T-1143 ruling (entry-seam ruling 3) — to be
|
||||
recorded as a deliberate revision when the workshop's decisions are filed.
|
||||
2. **Vocabulary — "tile" repaired, "gridunit" coined.** Tile means the ground-level
|
||||
1×1 m unit (D-243) — Jeroen: *"I misused the term several times. Tile should mean
|
||||
the ground level 1x1m. I suggest we talk about gridunit (at zoom level) for the
|
||||
wrong uses."* Legitimate tile uses in the outline: the "~10px per tile" bottom-out
|
||||
(deepest step shows the 1 m tile at ~10 screen px on the smaller axis) and "the
|
||||
amount of steps … from largest to visible tile". Everything else (the n×n grid,
|
||||
per-pixel records) reads as **gridunits at a zoom level**.
|
||||
3. **Data resolution is a tunable, not a constant.** *"I would like pixel resolution
|
||||
on the maps, but that may be too much, so maybe we do 5x5 pixels as a display
|
||||
unit … Crisper is better, but the computer must not catch fire."* Ideal = 1
|
||||
gridunit per screen pixel; acceptable fallback ≈ 1 gridunit per 5×5 px display
|
||||
unit (a 4K-class canvas drops from ~8.3M to ~330K gridunits). The knob is decided
|
||||
by measurement, not taste.
|
||||
4. **Hydrology — deterministic equilibrium.** Lake fill, overflow re-routing,
|
||||
gorge carving are a single-pass settled end-state computed from heightmap +
|
||||
moisture/climate as a pure function of seed ("over time" = geological backstory).
|
||||
Extends today's D8 drainage; no stateful simulation.
|
||||
|
||||
## Confirmed inline
|
||||
|
||||
- **Step boundaries = compute-chunk boundaries.** Tyre's reading that zoom-step
|
||||
boundaries and deterministic-generation load-partitioning boundaries are intended
|
||||
to be the same boundaries stands unchallenged.
|
||||
- **Server side is in play** (premise from the outline itself): content
|
||||
determination relocates to the server; the server sends what is at a given
|
||||
world coordinate at that zoom level. Dudley is core roster.
|
||||
- **Performance is a first-class driver** (lazy/late compute, TTL cache,
|
||||
"snappy after first calc").
|
||||
|
||||
## Deferred to the workshop (round B — all four explicitly "workshop deliverable")
|
||||
|
||||
1. **Named-feature encoding** (rivers/settlements/roads/POIs: dense rasters +
|
||||
sparse feature list vs inline identity vs ids-with-lookup). Jeroen's constraint:
|
||||
*"best fidelity vs wire contract possible … The information the client needs
|
||||
needs to be there."*
|
||||
2. **Data-canvas sizing** (canonical fixed size for all clients vs viewport-sized
|
||||
capped): *"I see value in both."*
|
||||
3. **Cache-tier architecture** (server TTL / client layer cache / disk-persisted
|
||||
global tier / predictive precache — which exist, and what "always keep the
|
||||
global level" means concretely).
|
||||
4. **Map time axis** (climatology vs current sim state for frozen/flooded).
|
||||
Jeroen's hint, on record as direction not ruling: *"maybe we put shorter ttl on
|
||||
the climate sim state components?"*
|
||||
5. **Step count** largest→visible-tile (deferred in the outline itself), coupled to
|
||||
compute-chunk partitioning.
|
||||
|
||||
## Flags carried forward (not questions)
|
||||
|
||||
- **Cliff/multi-height data model gap** (Tyre): "two heights in the same tile and
|
||||
cliff forming" exceeds the one-height-per-cell model (`elev_q` u8); the per-
|
||||
gridunit payload needs a sub-unit vertical-structure answer, and a ruling on
|
||||
whether cliffs are Phase-4 Atlas content or Phase-5 geometry.
|
||||
- **Phase-5 reuse** of the map drawing component (same code path as the future
|
||||
in-world viewport or Atlas-only) — scoping decision for the workshop.
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
title: "Body Map Viewer — Jeroen's Design Outline"
|
||||
description: "Verbatim capture of Jeroen's opening outline for the map-handler revision (T-1176 prep session, round 1)"
|
||||
type: workshop
|
||||
status: active
|
||||
workshop: body-map-viewer
|
||||
created: 2026-07-25
|
||||
---
|
||||
|
||||
# Jeroen's Design Outline
|
||||
|
||||
Captured 2026-07-25, opening the three-way prep session (Jeroen, lead, Tyre).
|
||||
His instruction accompanying it: *"before we get to discussing the actual game
|
||||
implications … read my text and ask for clarifications if I was ambiguous or
|
||||
incomplete"*, and *"Let's discuss/askuserquestion this properly the three of us
|
||||
until I sign off on the briefing document."* Clarification rounds follow in
|
||||
`clarifications.md`.
|
||||
|
||||
**Vocabulary repaired at Jeroen's request (sign-off round)** to prevent context
|
||||
confusion, per his round-A ruling (*tile* = the 1×1 m ground unit only; *gridunit
|
||||
(at zoom level)* = the per-step data cell). Exactly two replacements were made,
|
||||
each marked `[was: tile(s)]`: the "n by n grid", and the hydrology "two heights"
|
||||
sentence. The two uses he ruled legitimately *tile* ("10px per tile", "largest to
|
||||
visible tile") are untouched. Reading note for the same reason: where "pixel"
|
||||
below means the data cell rather than a literal screen pixel (e.g. "what is in
|
||||
each pixel", "tier0 pixels"), read it as *gridunit*; the 1-gridunit-per-screen-px
|
||||
ideal vs ~5×5 fallback is recorded in `clarifications.md`. No other wording is
|
||||
edited.
|
||||
|
||||
---
|
||||
|
||||
**How I would build this**
|
||||
|
||||
to honor late/lazy compute principles we will be designing this with LoD information exposure and generation in mind. In essense the rule is: don't calculate inside the game loop what is not needed for the game state: smart-precaching is okay, but it is not blocking for the user output. We cache calculated results so we don't recalculate things we already have (smart cache, dependent on zoom level and player position (atlas application viewport counts as player position. player is the focus, both character location as well as disembodied atlas usage) A function of detail level, time and distance determine the ttl. With this I mean, we keep always keep the global level calculations for each body to make atlas navigation snappy after first calc, but everything under that gets a shorter ttl as the values of detail level and the player distance increase.
|
||||
|
||||
architecture:
|
||||
- pixel drawing is a function of the client, not the server. There exists a map drawing component inside the client that can deal with drawing maps, zooming them and applying overlays.
|
||||
|
||||
- content determination is a server function. The server sends what is at a given pixel (world coordinate) that is in screen at that zoom level
|
||||
|
||||
- zoom levels are stepped:
|
||||
- there is global zoom, which is the atlas opener screen for a body
|
||||
- one zoom in we normalize to the highest zoom level of the dynamic set. this is a n by n grid of gridunits `[was: tiles]`. always the same size on the smallest axis of the viewport, adding more pixels in the larger axis (widescreen support)
|
||||
- every subsequent zoom clicks step through a similar viewport bounding down, right up to the point the smaller axis is, say 10px per tile so we can show some detail if needed later.
|
||||
- the amount of steps that make sense from largest to visible tile is to be discussed in the workshop and will also play a role in how we break up the load of the deterministic algos that generate the content
|
||||
|
||||
- on opening of a body, the following happens:
|
||||
- the heightmap and relevant inputs are read
|
||||
- the seed generators run to do water distribution and global calculations that are relevant. (later, settlement generation and placement, roads, railroads, etc will also be in scope) We basically generate everything to show the world, it's main infrastructure, setllements and POIs
|
||||
- here is where it starts getting tricky to do good code and step separation; the code also generates enough biome and coastline and height generation to fill out a pixel for each screen pixel. We probably want to do this at 4k resolution so we have spare room to scale out the map on larger monitors. This does not get drawn, this determines what is in each pixel: average biome, average ground type, height, is the pixel predominantly flooded or not, is the pixel predominantly frozen or not. This at the same time serves as seed informaation for the deeper cascade, as well as as input for the client. The server needs to be smart about this: if a river ends in a basin that is above sealevel, a lake will fill, which will overflow to a new path to the sea, or be such a large inland body that it maintains it's own water cycle. a river may carve a gorge through higher terrain over time when no easier overflow path is available. This will need to be properly communicated to the client and the underlying generators, since that will end with two heights in the same gridunit `[was: tile]` and cliff forming. I feel this behavior should be governed by the moisture and climate properties of the body.
|
||||
- the client receives this pixel information (think: biome: grassland, settlement: null/"name here", river: null/"name here/unnamed", frozen: true/false, flooded: true/false, sea: true/false, etc, etc) It then smartly uses that information to color pixels, tween rivers/roads, apply settlements and names to the map and overlays, etc etc. What is shown and drawn is a map art function, not a data function.
|
||||
|
||||
- on zooming a step the following happens:
|
||||
- the server grabs the bounds of the data canvas (separate from the view canvas) (I think we may also want to land on a 4k window to make sure the client has enough for all monitors)
|
||||
- with these bounds the server pulls the tier0 (atlas body level) pixels and their information that cover the data canvas and runs the deterministic generation to again fill out the information for all the pixels needed to send to the client (and again also serve as the seed input for tier2 generation) At this point the exact position of the river, biomes, coastlines, water etc etc are determined at pixel level for this layer.
|
||||
- the client acts in the same pattern as above, but with different classes of content to draw at some point (at low enough zoom, a green forest biome may start showing clearings and ponds or such - to be determined and tinkered with)
|
||||
- When the sizes become true, items start taking more than 1 pixel: at 50 km, a 1km wide settlement will stretch across pixels for example, and a river will, with varying width and maybe dependent on climate and rain/floodplane cycles or frost change shape and texture
|
||||
|
||||
There may be elements I miss in this, which is why we co-write the plan. or things that need to be done differently.
|
||||
@@ -0,0 +1,163 @@
|
||||
---
|
||||
title: "Body Map Viewer — Prep Grounding"
|
||||
description: "Pre-read for the T-1176 prep session (Jeroen + lead + Tyre) and later the workshop: current mechanism, error-class evidence, delivered ladder design, binding constraints, candidate directions"
|
||||
type: workshop
|
||||
status: active
|
||||
workshop: body-map-viewer
|
||||
created: 2026-07-25
|
||||
decision_refs: [D-166, D-226, D-227, D-243]
|
||||
---
|
||||
|
||||
# Body Map Viewer — Prep Grounding
|
||||
|
||||
Prepared by the lead for the three-way prep session (Jeroen, lead, Tyre) that writes
|
||||
the workshop brief. Working name `body-map-viewer` (Jeroen's phrase) — rename with the
|
||||
brief if a better one emerges. Everything here is *input*, not position: Jeroen's
|
||||
outline of his own design opens the session and nothing below pre-empts it.
|
||||
|
||||
## 1. Why this exists
|
||||
|
||||
Jeroen, 2026-07-23 (T-1176): *"I want to discuss and maybe revise the pixel
|
||||
scan/output mechanism for drawing the map. I feel we can be smarter about this and
|
||||
bypass an entire class of errors we are seeing as well as probably improve
|
||||
performance."* Follow-up 2026-07-25: he, the lead, and Tyre write a plan to start a
|
||||
wider-team workshop on the new map handler; Jeroen will outline how he would build
|
||||
**the body map viewer with zoom to ground level** and **how the deterministic
|
||||
generation cascade connects into it**.
|
||||
|
||||
## 2. The error-class evidence (PRs #195–#197, recorded in D-226 implementation notes)
|
||||
|
||||
All rendering-layer bugs of the river arc descend from one architectural choice:
|
||||
**immediate-mode `draw_*` calls issued by children of a zoom-scaled canvas**
|
||||
(`_canvas.scale = _view_zoom`), which makes every on-screen size a canvas-local value
|
||||
divided by zoom:
|
||||
|
||||
- **Per-call-site compensation fragility** — every radius/stroke needs `_zs`/`_zs_stroke`/
|
||||
`_zs_ring_radius` wrapping (atlas_window_geometry_nature.gd); a missed site degrades
|
||||
silently. Happened twice (PR #195 attractor strokes, PR #197 course widths).
|
||||
- **Godot line-rasterizer stroke floor** — widths below ~1.0 canvas units collapse to a
|
||||
1 px hairline (bracketed live: 0.6 → hairline, 1.1 → visible). Consequence on record:
|
||||
per-class course *width* grading is inert at every shipping fit zoom; classes
|
||||
distinguish by opacity alone until T-1175.
|
||||
- **`draw_arc` blob regime** — ring radius below stroke width renders a filled blob
|
||||
(bracketed: 1×stroke = blob, 1.5× = recovers, 2× = clean; floored at 2×).
|
||||
- **Wrap-image resolution family** — seam tiles must mirror the painter's
|
||||
`nearest_wrap_image(tile_center, held_center, cols)` exactly (T-1172 round 2 inverted
|
||||
it); shared index math now lives in `cell_index_for_local_offset`.
|
||||
- **Auditability** — the mechanism defeated visual verification three times in one
|
||||
batch (lead capture misreads corrected only by wire data). A mechanism whose
|
||||
correctness can't be eyeballed is itself a finding.
|
||||
|
||||
## 3. The current mechanism (the thing being revised)
|
||||
|
||||
**Client** (`client/ui/implant/apps/atlas/`): `AtlasWindowViewer` (~1017 ln) owns a
|
||||
`_canvas` Node2D; pan/zoom = `_canvas.position/_canvas.scale` (`_apply_transform`).
|
||||
Terrain: `atlas_window_overlay.gd` builds one Image texel per derived cell →
|
||||
ImageTexture → `draw_texture_rect` (COMPOSITE_SMOOTH pipeline axis; rebuilt only on
|
||||
window change — pan/zoom is free), per-rung sampling filter `_filter_for_granularity_v2`
|
||||
(Region/orbital-mosaic → NEAREST, District/Quarter → LINEAR; T-1161 two-axes outcome).
|
||||
Nature features (`atlas_window_nature_overlay.gd`): `draw_polyline`/`draw_circle`/
|
||||
`draw_arc` inside the scaled canvas with the §2 compensation family. Orbital rest
|
||||
state: whole-body mosaic of capped Region tiles (per-tile ImageTextures,
|
||||
`AtlasWindowTileSet`). Rung selection: coverage-ceiling walk (`select_rung()`,
|
||||
MAX_COVERAGE_M — Quarter ≈ 32.8 km, District ≈ 131 km, Region ≈ 13,107 km, beyond →
|
||||
tile mode). CELL_PIXEL_SIZE = 16 px at zoom 1.0. Redraws on pan/zoom/rung-cross/
|
||||
arrival, not per-frame.
|
||||
|
||||
**Server** (`server/src/atlas/`): windowed derives on the Rayon background queue,
|
||||
never inline (D-226 T-1124 §1 [HARD]); one windowed payload (`DistrictWindowLayer`:
|
||||
per-cell u8 arrays + `courses: Vec<RiverCourse>`), echo/cache keyed on
|
||||
`(body, center, n, granularity)`; wire clamp `window_n² × granularity² ≤
|
||||
WIRE_CAP_CELLS (4096)`; whole-body Layer1 family (512×256: heightmap analysis, D8
|
||||
drainage/rivers) rung-independent. Measured (zoom_ladder_bench, release, 16 cores):
|
||||
District derive 3.0 µs/cell uncut, 1.785 µs @2048 m cutoff; Quarter 1.823 µs @512 m;
|
||||
orbital 1.454 µs; served Region window (4096 cells) **0.617 ms/call**.
|
||||
|
||||
## 4. The delivered ladder design and what it already settles
|
||||
|
||||
`docs/architecture/atlas-zoom-ladder-t1143.md` (9-agent pass, 2026-07-21) + Jeroen's
|
||||
three rulings (recorded as D-226 amendment):
|
||||
|
||||
1. **Floor OPENED** — *"we set a new BHAG so old restrictions are up for debate."*
|
||||
The D-226(d) ceiling is opened for the Atlas ladder; "down to tile scale" reads
|
||||
literally. Below-quarter rungs (block/tile) are **implementation-gated on T-1154**
|
||||
(below-quarter measurement pass — backlog, now unblocked: the octave-cutoff
|
||||
plumbing it was blocked on has existed since T-1162). Chunk/tile output still never
|
||||
appears as a *whole-body planetary layer* — windowed viewport only.
|
||||
2. **Planetary carrier** — progressive capped-density tiling on the generalized
|
||||
`district_window` carrier (shipped as the orbital mosaic).
|
||||
3. **Entry seam** — continuous cursor-anchored zoom, full-zoom-out resets to the
|
||||
canonical planetary frame (shipped, T-1153).
|
||||
|
||||
Standing risks from that doc that touch this workshop: **R1** planetary/canvas-fill
|
||||
cost story (full-canvas sample still extrapolated, ~524 ms @2 px/cell parallel-
|
||||
estimated); **R2** temperature steps at district boundaries by construction at every
|
||||
rung (never continuous); **R3** average-back unverified for categorical morphology
|
||||
gates; **R6** border-fade referent must repoint when the heightmap-texture path
|
||||
retires.
|
||||
|
||||
## 5. Binding governance (verified verbatim)
|
||||
|
||||
- **D-166 amendment + corollary (2026-07-21):** continuous zoom ladder planetary→tile,
|
||||
every level *"deterministically calculated information at that level's native
|
||||
granularity … never magnified interpolation of a coarser composite"*; display
|
||||
*"samples the derivation at canvas resolution (the ladder is a continuous field, not
|
||||
a stack of fixed display rasters)"*; heightmap PNGs are invisible derivation input.
|
||||
Hard Phase-4 exit bar (T-750).
|
||||
- **D-226(d)** as amended by ruling 1 above: the old hard ceiling is opened for the
|
||||
windowed viewport; the whole-body-planetary-layer prohibition stands.
|
||||
- **D-227:** derive-don't-store — `subtile(x,y,z) = derive(seed, atlas, position)`,
|
||||
transient evictable caches only; coast crinkle + river courses are rung-indexed
|
||||
invention.
|
||||
- **D-243:** the containment ladder (voxel 1 m … region 204.8 km, one elastic
|
||||
planetary seam); climate edge-fuzzed (*"climate does not change on a line"*),
|
||||
morphology seams sharp-but-organic.
|
||||
- **Carrier three-way rule** (docs/architecture/river-courses-t1170.md, binding):
|
||||
(i) rung-independent discrete features → whole-body family, filtered client-side;
|
||||
(ii) continuous per-metre fields → windowed per-cell arrays; (iii) rung-indexed
|
||||
invented detail → windowed payload regardless of geometric kind.
|
||||
- **Windowed-family ceiling** (D-226 T-1124 §2 [HARD]): exactly one windowed-query
|
||||
field on `AtlasLayerResponse`; a second forces the tagged-envelope migration.
|
||||
|
||||
## 6. T-1176 candidate directions (sparring material, not positions)
|
||||
|
||||
- **(a) Unscaled screen-space sibling layer** — annotation/feature drawing moves to an
|
||||
unscaled sibling of the canvas; positions transformed to screen space, sizes literal
|
||||
px. Kills the whole §2 compensation class for vector features. (Tyre's earlier note,
|
||||
T-1156 wave 2 / T-1158-adjacent.)
|
||||
- **(b) Render-to-texture per window/tile** — features rendered at native resolution
|
||||
into textures; zoom becomes pure texture transform; sizes texel-exact. Must be
|
||||
argued against D-166's "canvas resolution / continuous field, not fixed display
|
||||
rasters" sentence. Prior art in-tree (Tyre): the orbital tile-mode mosaic already
|
||||
composites per-tile ImageTextures (`_tile_texture_cache`, `compute_tile_grid()` —
|
||||
Lendel 3×2, verified this session) — the terrain path is halfway to this model.
|
||||
- **(c) Shader-side composition** — morphology/courses as data textures, coloring +
|
||||
feature rendering in fragment shader; per-vertex width/tapering (T-1175) comes free;
|
||||
likely the performance route for canvas-resolution sampling at planetary scale (R1).
|
||||
- **(d) Hybrid** — e.g. terrain via (c), vector annotations via (a).
|
||||
|
||||
## 7. Adjacent work that intersects
|
||||
|
||||
| Item | Status | Intersection |
|
||||
|---|---|---|
|
||||
| T-1154 below-quarter measurement pass | backlog, unblocked | the gate for "zoom to groundlevel"; block/tile rung costs + wire |
|
||||
| T-1158 viewer decomposition | backlog | any new mechanism restructures the same file |
|
||||
| T-1175 polish collector | backlog | tapering/width grammar wants Polygon2D strips or shaders — mechanism-dependent |
|
||||
| T-1157 capture harness redesign | backlog | §2's auditability finding — verification story for whatever ships |
|
||||
| T-1174 batch/window sampling divergence | backlog | pre-existing sampling debt |
|
||||
| D-239 tile-derivation contract | **verified in-session**: confirmed/active, "coarse→fine refinement chain (resolves Q-101)", 2026-06-07 | the derivation side of "connect the cascade" is settled governance |
|
||||
| Phase-5 boundary (D-166 generation-before-player) | standing | ground-level *rendering* is Phase 5; the Atlas ladder maps derived layers — where Jeroen's viewer sits relative to this line is his to outline |
|
||||
|
||||
Prior workshop art: `atlas-derivation-model.md` (brief-only, data side),
|
||||
`generation-cascade/` (atlas UI coords vs sim coords), `world-generation/` (atlas as
|
||||
annotated information layer), `map-authoring-pipeline/` (brief-only, predates the
|
||||
no-hand-made-test-map rule — historical only).
|
||||
|
||||
## 8. What the prep session must produce
|
||||
|
||||
1. Jeroen's design outline, captured faithfully (the session's round 1).
|
||||
2. Every point sorted: **settled by the three of us** vs **genuinely open → workshop
|
||||
question** vs **already ruled** (cite the record).
|
||||
3. The workshop brief (`body-map-viewer-workshop-brief.md`): question, locked/open
|
||||
context, roster, per-agent questions, format, input docs, expected outputs
|
||||
(D-record(s), ticket plan).
|
||||
@@ -0,0 +1,94 @@
|
||||
---
|
||||
title: "Body Map Viewer — Tyre's Implications Pass"
|
||||
description: "Tyre's five-section implications analysis of Jeroen's clarified outline (T-1176 prep session): governance delta, candidate re-ranking, measurements, workshop shape, red flags"
|
||||
type: workshop
|
||||
status: active
|
||||
workshop: body-map-viewer
|
||||
created: 2026-07-25
|
||||
---
|
||||
|
||||
# Tyre's Implications Pass (prep session, verbatim)
|
||||
|
||||
Delivered after the clarification rounds ([clarifications.md](clarifications.md)),
|
||||
before the brief was drafted. Jeroen's prep rulings on its proposals are recorded in
|
||||
the brief. Unedited below.
|
||||
|
||||
---
|
||||
|
||||
## 1. GOVERNANCE DELTA
|
||||
|
||||
**AMENDS / SUPERSEDES:**
|
||||
|
||||
- **D-166 corollary (2026-07-21)** — sentence at stake: *"Display at every rung samples the derivation at canvas resolution (the ladder is a continuous field, not a stack of fixed display rasters)."* The stepped model is exactly "a stack of fixed display rasters" — one server-generated data canvas per zoom step. **Amendment direction:** the corollary's *intent* survives (no magnified interpolation of a coarser composite; each step's data is derived at that step's native gridunit spacing), but "continuous field, not fixed display rasters" is narrowed to "each *step* is a derivation sampled at gridunit resolution; display between steps holds that step's canvas." The anti-oversample/anti-undersample guarantee is re-expressed as a *per-step* property (a gridunit is never smaller than one screen px times the tunable, never coarser than the source-raster floor). Do NOT delete the corollary — repoint it.
|
||||
|
||||
- **T-1143 ruling 3 (entry seam, continuous cursor-anchored zoom)** — **Superseded** for the zoom-transport mechanism: scroll steps through discrete levels. What SURVIVES: cursor-anchored centering, edge-scroll pan, and the "full zoom-out resets to the canonical planetary frame" HARD condition (orthogonal to stepped-vs-continuous). The client-side morph/tween is an *investigation item*, not a reinstatement of continuous derivation.
|
||||
|
||||
- **T-1143 §2–§5 rung model / `select_rung` coverage-ceiling walk** — the shipped Quarter/District/Region "rung" selector keyed on `MAX_COVERAGE_M` is superseded by the *stepped gridunit ladder* (global → step1 n×n → … → 10px/1m-tile). Rungs-as-derivation-granularity survives conceptually, but the selector is no longer a coverage-ceiling walk — it's a discrete step index. The workshop's step-count decision defines the new ladder; `select_rung` is replaced, not patched.
|
||||
|
||||
- **D-243 spatial ladder** — **additive, not superseded.** "tile = 1×1 m" is CONFIRMED (matches D-243's voxel row — Jeroen repaired his own misuse *toward* D-243). "gridunit (at zoom level)" is a NEW vocabulary term for the per-step data cell and must be added to the locked vocabulary block. **Critical open point:** a gridunit is a *display-derived* spacing (viewport px ÷ tunable) which floats with monitor and step — D-243 rungs are *absolute metres*, fixed on every body. The brief must state whether gridunit spacing SNAPS to D-243 rung spacings or floats freely. The single most load-bearing vocabulary reconciliation — surface as a workshop question, don't pre-decide.
|
||||
|
||||
- **D-226 T-1124 §2 windowed-family ceiling [HARD]** — sentence at stake: *"exactly one windowed-query field on `AtlasLayerResponse`; a second forces the tagged-envelope migration."* Server-side per-step content determination with a richer payload likely EXCEEDS what one additive field can hold cleanly. This is where the tagged-envelope migration D-225 deferred probably lands. The brief should NOT assume it's avoidable this time. Named-feature encoding IS the decision that determines whether the ceiling breaks. The ceiling's *purpose* (prevent uncorrelated concurrent windowed queries) survives; the tagged envelope is the sanctioned way past it.
|
||||
|
||||
- **river-courses-t1170.md carrier three-way rule** — rule (iii) *"rung-indexed invented detail rides the windowed payload"* SURVIVES structurally: courses are still invention, still step-indexed, still server-side. "The windowed payload" becomes "the per-step data canvas payload" (same idea, new carrier name). Rules (i) and (ii) survive too. **This ruling is robust to the pivot** — it was cut on the axis (skeleton vs continuous vs invention) that the server relocation doesn't touch.
|
||||
|
||||
**SURVIVES UNTOUCHED (state explicitly to prevent over-rewrite):**
|
||||
- **D-227 derive-don't-store** — fully intact. The TTL cache is a *concrete eviction policy layered on* "transient evictable caches only." Nothing persisted as source-of-truth. (Workshop must confirm any disk-persisted-global-tier option stays consistent with D-227 — the one place it could drift.)
|
||||
- **D-010 four principles** — the server relocation *reinforces* principle 4 (server owns simulation state). Client art-function is pure presentation. The determinism boundary moves *toward* the server.
|
||||
- **D-166 cascade + phase gating** — unchanged; still Phase-4 Atlas work.
|
||||
- **D-226(d) whole-body prohibition** — survives, stress-tested by the deepest step (Red Flag 3). Chunk/tile output still never becomes a whole-body planetary layer.
|
||||
- **D-169/D-170 implant UI** — the map component lives inside the implant Atlas app, occludes gameplay, uses HudGroups. Unchanged.
|
||||
|
||||
---
|
||||
|
||||
## 2. CANDIDATE DIRECTIONS UNDER THE NEW PREMISES
|
||||
|
||||
The new premises *pre-decide most of T-1176*: server owns content determination → the client no longer does immediate-mode `draw_*` of derived data. The entire error class (zoom-scaled-canvas compensation, `_zs`/`_zs_stroke`/`_zs_ring_radius`, the line-rasterizer floor) exists because the client draws derived features inside a `_canvas.scale = _view_zoom` node. **Stepped zoom + server-resolved per-step canvas kills the root cause, not the symptoms.**
|
||||
|
||||
**Baseline (recommended, not the workshop's to relitigate):**
|
||||
- **(b) render-to-texture per step, for the terrain/classification raster.** Each step's data canvas → one ImageTexture → drawn 1:1 (or at the tunable px ratio). Sizes are texel-exact by construction — the rasterizer floor and per-call compensation *cannot occur*. Already half-built: `_tile_texture_cache` + `_rebuild_texture_if_needed` + `_filter_for_granularity_v2` are a render-to-texture path today; the stepped model makes RTT the *primary* path.
|
||||
- **(a) unscaled screen-space sibling layer, for vector annotations** (labels, settlement glyphs, POI markers, mouth rings). Screen-space at literal px sizes — no zoom compensation. Positions transform world→screen; sizes are constants.
|
||||
|
||||
**Genuinely open for the workshop:**
|
||||
- **(c1) shader colorize/style of the classification raster** vs CPU `set_pixel` — perf/quality call; where T-1175's per-vertex river tapering "comes free."
|
||||
- **(c2) GPU-side derivation — almost certainly NO** (determinism, the two-language-mirror liability rejected for T-1170 applies doubly to GLSL). Pre-empt in the brief: **derivation stays CPU/Rust server-side; GPU is presentation only.**
|
||||
- **Client-side morph between steps** — a *presentation tween* of the held texture, NOT re-derivation. Open, low-risk, scoped as "cosmetic interpolation while the next step's canvas is in flight."
|
||||
|
||||
(d) hybrid isn't a separate option; (b)+(a)+optional-(c1) IS the hybrid.
|
||||
|
||||
---
|
||||
|
||||
## 3. PRE-WORKSHOP MEASUREMENTS
|
||||
|
||||
The T-1143 lesson: the planetary rung died of stacked extrapolation. Priority order:
|
||||
|
||||
1. **Equilibrium hydrology solver cost** — highest priority, biggest unknown, critical path for "settled hydrology" feasibility. Lake-fill + overflow re-routing + gorge carving as single-pass priority-flood (Barnes/Planchon-Darboux class). Measure at 512×256 AND 4K-class (~330K–8.3M cells). Effort: 1–2 days (the overflow+carve variant needs prototyping, not just benchmarking). Who: Dudley. Could *invalidate* per-body-open settled hydrology if it's seconds not milliseconds. **Should also output the cliff representation, not just the cost** (Red Flag 4).
|
||||
2. **Per-gridunit derive cost at 1×1 vs 5×5, at real canvas sizes** — known: 1.785 µs/cell (District cutoff), 1.454 µs/cell (orbital), 0.617 ms per 4,096-cell served window. Scale math: 330K gridunits × ~1.5 µs ≈ ~0.5 s single-thread, ~35–50 ms across 14 workers *if par_iter chunking holds at that scale* (measured at 4,096 cells only). 8.3M × 1.5 µs ≈ ~12 s single-thread, ~0.9 s parallel — the "computer catches fire" case. Effort: 0.5 day — run `zoom_ladder_bench` at 330K and 8.3M cells on the production path; don't extrapolate. Who: Dudley. **Closes the exact gap that killed the T-1143 planetary story.**
|
||||
3. **Wire-size table for candidate encodings** — 330K-gridunit canvas: dense classification ≈ 4–5 bytes/gridunit ≈ 1.3–1.6 MB/step raw, before MessagePack overhead and named-feature lists. Compare raw dense vs bit-packed vs run-length vs PNG-encoded. Effort: 0.5 day. Who: Araminta with a number from Dudley. Feeds named-feature encoding + the tagged-envelope call.
|
||||
4. **T-1154 block/tile rung numbers (now unblocked)** — deepest steps derive at metre spacing over a viewport canvas; never benchmarked. Effort: 0.5 day (cutoff plumbing exists since T-1162). Who: Dudley. Prices the bottom of the ladder.
|
||||
5. **Godot ImageTexture upload cost per step** — `create_from_image` for a 330K–8.3M px image on step-cross; could stutter. Effort: 0.25 day. Who: Stig. Interactive-latency input, not a blocker.
|
||||
|
||||
**Discipline line: items 1, 2, 4 must be MEASURED and in the brief's appendix before round 1.** Cite the T-1143 planetary rung by name as the cautionary tale.
|
||||
|
||||
---
|
||||
|
||||
## 4. WORKSHOP SHAPE
|
||||
|
||||
**Roster (small as honesty allows):** Dudley — CORE (server owns content determination; hydrology, per-gridunit derive, step-canvas generation, compute-chunk partitioning). Araminta — CORE (the map-art function AND named-feature encoding). Stig — CORE (the client component: RTT + screen-space rebuild; owns the atlas/ cluster). Tyre — architecture/feasibility, governance delta, determinism boundary, tagged-envelope call. Troblum — adversarial/perf, **round-2 reviewer, not round-1 designer** (stress the cost story and memory budget; the extrapolation-hunting from PR #185). **Gestalt — NO**: deterministic geology, not systems design; seating him drags toward live-sim scope the clarifications parked. Pull in async for the one map-time question if it grows sim coupling. Five seats.
|
||||
|
||||
**Format:** 2-round + lead interview (tile-derivation-contract precedent). Round 1: per-seat positions against pre-measured numbers. Round 2: synthesis + cross-cutting decisions (tagged-envelope yes/no, gridunit↔D-243, canonical-vs-viewport). Lead interviews Jeroen each round. **Gate round 1 on the §3 measurements landing.**
|
||||
|
||||
**Question list per participant:** (folded into the brief's Questions section.)
|
||||
|
||||
---
|
||||
|
||||
## 5. RED FLAGS (for the brief to state honestly)
|
||||
|
||||
1. **Stepped zoom vs D-166's "no over/undersampling" — the between-steps gap.** Between two steps the held texture is scaled by the display transform: at the moment before a step-cross you ARE magnifying step-N's canvas — the exact thing D-166 was written against, for the width of one step interval. Step count + px-per-gridunit tunable jointly bound how bad this gets; they are the knobs that keep between-step magnification below perceptibility. The D-166 corollary amendment must own this honestly.
|
||||
2. **Global-tier "always keep" across ~273 inhabited bodies.** ~330K gridunits × ~5 bytes ≈ 1.6 MB/body ≈ **~440 MB resident** at 5×5 if never-evict and all-bodies; ~13 GB at 1×1 — infeasible. Force the question: "always keep" = always-derivable-fast (cache is a bonus) or a permanent resident allocation (needs a budget and probably a disk tier, which stress-tests D-227). The cache deliverable must produce a number, not a vibe.
|
||||
3. **Deepest step (10 px/1 m tile) vs D-226(d).** At 10 px/tile on a 2160 px axis: ~216 m across — a viewport-scale window of metre-resolution derivation. *Within* the opened windowed-viewport carve-out (gated on T-1154 numbers) — allowed. But: **if the workshop picks "canonical fixed canvas for all steps," the deepest step's canonical canvas at 1 m spacing IS a near-whole-body metre-resolution derivation, which violates the surviving D-226(d) prohibition. Canonical-vs-viewport is not just a cache tradeoff — at the deep end it's a governance boundary.** The sharpest thing in the whole design.
|
||||
4. **Cliff/multi-height data-model gap.** Settled hydrology *produces* gorges; a gorge is two heights in one gridunit; the sketched payload carries one. Either the gridunit payload gains a vertical-structure field (min/max height + cliff-edge flag) at Phase-4 Atlas scope, or cliffs are declared Phase-5 in-world geometry and the Atlas shows dominant height + a "steep" classification. Hydrology can't be "settled as producing gorges" while the data model can't represent one.
|
||||
5. **The tagged-envelope migration is probably now unavoidable — and that's fine, but it's work.** Present it as *expected scope*, not a risk to avoid; under-scoping repeats the T-1143 §8-step-4 mistake. Honest tier: challenging but doable — the envelope framing already exists in D-225's deferral; we're executing a planned migration, not inventing one.
|
||||
|
||||
---
|
||||
|
||||
**Meta-note:** this pivot is *architecturally cleaner than what ships today*, not messier. Server-owns-content + client-art-function + RTT+screen-space-vectors eliminates the entire error class at the root, makes the render auditable (the data canvas is inspectable server-side, decoupled from draw), and the one hard part I'd have feared — reconciling derived geometry with a zoom-scaled canvas — stops existing because there's no zoom-scaled canvas anymore. The T-1170 carrier rule survives the pivot untouched because it was cut on the right axis. The genuine risks are the four measured-cost questions and the two governance boundaries (D-226(d) canonical-canvas coupling, D-166 between-step magnification) — all nameable, none fatal. Feasible. Challenging but doable.
|
||||
Reference in New Issue
Block a user