docs(meta): D-226 T-1124 amendment — windowed district-resolution regional map design (T-1124)

Five sections, Tyre data shape + Araminta screen/encoding (T-1112
pattern): (1) request = serde-default window_center/window_n ON
AtlasLayerRequest (five-shape demux cap honored); (2) response carrier
RULING — district_window is a windowed viewport query keyed
(body, center, n) with echoed-center staleness guard, deliberately
OUTSIDE the dense whole-body layer family whose growth ceiling is
re-scoped (not busted) to that family; (3) six per-cell fields incl.
glaciation_grade (T-1127 deferral accepted) and Marine-exhaustive
vegetation; (4) binding budget — 7 bytes/cell, MAX_N=64 (~28 KiB),
DEFAULT_N=32, temp shares the T-1118 region-ramp colorizer across zoom
levels (D-243 continuity), pan-only re-request (zoom never refetches),
D-227-determinism client cache; (5) screen — zoom-threshold LOD swap
in the existing AtlasViewer, morphology base with elev_q lightness,
gen_dw_* toggles, glaciation as always-on tint modifier, Marine
transparent, implant chrome discipline.

Validated via pql decisions validate. Implementation is follow-up
ticket scope (server wiring must resolve the named TerrainAnalysis
transience decision; client screen).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-18 12:01:05 +02:00
co-authored by Claude Fable 5
parent 8c7a0d6f3d
commit 67bd0ec294
+64 -1
View File
@@ -1597,11 +1597,74 @@ Technical foundation decisions that constrain implementation: engine, client-ser
- **(4) Six wiring touch points (follow-up ticket, not built here).** `AtlasLayerResponse` gains `quarter_footprints: Option<QuarterFootprintLayer>` + a `build_quarter_footprint_layer(state, placements)` function mirroring `build_district_grid`'s "empty source → `None`" contract (`server/src/atlas/layer_proxy.rs`); `ZoningType` gains `PartialOrd, Ord` derives mirroring `DistrictType`'s T-994 precedent (`server/src/simulation/generator.rs` — declaration order is not a stability-pinned wire format on either enum, so the additive derive is safe), which is what makes §1's lowest-declaration-order tie-break computable for `dominant_zoning` (PR #179 review: `DistrictType` already carries the derives, `ZoningType` does not — the tie rule itself is unchanged); `protocol.gd` passthrough for the new field (mirrors the existing `district_grid`/`road_graph`/`settlements` fields); a `gen_l4_quarters` entry in `OVERLAY_DEFS` (`client/ui/implant/apps/atlas/atlas_viewer.gd`); a `_draw_gen_l4_quarters()` function imitating `_draw_gen_district`'s "read `viewer.get_generation_quarter_footprints()`, guard on `Dictionary`, draw" shape (`atlas_marker_overlay.gd`); and the `GENERATION_LEGEND` entry above (`atlas_legend_panel.gd`). `layer_proxy.rs` was mid-concurrent-edit for T-1113's `region_grid` addition at design time — read-only pass, no conflict expected (both land as new sibling `Option` fields on `AtlasLayerResponse`, following the same one-field-per-layer pattern the growth-ceiling note on that struct already anticipates naming T-1112 and T-1113 as the last two candidates).
**Amended 2026-07-18 (T-1124 — windowed district-resolution regional map, the jet-plane altitude between the planetary Atlas and the never-mapped chunk/voxel world):** a new Atlas *viewing mode*, deliberately not counted alongside item (3)/T-1112/T-1113's whole-body-layer sequence, because it is a different kind of thing from all of them — those are **whole-body layers** (computed once, cached per body, one screenful, `up_to`-gated but otherwise request-independent); this is a **windowed viewport query** (parameterized by a client-chosen rect, re-issued on every pan, never a whole-body snapshot). District resolution (2,048 m/cell, D-243) sits strictly between the D-226(d) settlement/quarter-skeleton ceiling and the never-Atlas-mapped chunk/voxel tier — in remit, and the first time the D-227 "invented deterministically" terrain (everything finer than the ~4078 km/px heightmap) has ever been surfaced to a screen rather than a debug probe. Design only — implementation is a follow-up ticket (T-1124 report; touch points named below).
- **(1) Request — extend `AtlasLayerRequest`, do not add a sixth inbound shape.** `bridge/mod.rs`'s `Inbound` demux doc names `BrowseRequest` (T-1131, PR #184) the **fifth and last** map-shape probe this hand-rolled scheme should ever carry; a sixth top-level request shape is explicitly forbidden without migrating the whole channel to the tagged-envelope framing D-225 deferred. The window parameters therefore ride on the **existing** `AtlasLayerRequest{body_id, up_to}` as new `#[serde(default)]` fields, absent = whole-body (today's behavior, byte-unchanged for every existing caller):
```rust
pub struct AtlasLayerRequest {
pub body_id: String,
pub up_to: CascadeLayer,
/// District-window centre (T-1124). `None` = no window requested
/// (whole-body layers only, today's behavior).
#[serde(default)]
pub window_center: Option<DistrictPos>,
/// Window side length in districts. Ignored when `window_center` is
/// `None`. Clamped server-side to `[1, DISTRICT_WINDOW_MAX_N]` (§4) —
/// never trusted from the wire.
#[serde(default)]
pub window_n: u32,
}
```
This is the identical pattern `StartupMessage.role` already uses (`bridge/types.rs`, D-254 §2) — an old client sending only `{body_id, up_to}` still decodes cleanly, `window_center` defaults to `None`, no protocol version bump, no new demux branch. `up_to` is unaffected and keeps gating which whole-body layers run; a window request can ride alongside any `up_to` value (the window path calls `derive_district` directly — it does not depend on which whole-body layers the cascade has cached, only on `TerrainAnalysis` + `BodyParams` being resolvable for the body, the same precondition `--render` already has).
- **(2) Response carrier — a distinct payload, not a sixth/seventh dense-layer `Option` field (RULING, binding).** The growth-ceiling note on `AtlasLayerResponse` (this record's base text, re-affirmed by T-1112 §4's "last two candidates" framing) governs one specific family: **dense, whole-body, cache-keyed-on-body-alone layers**`district_grid`, `road_graph`, `settlements`, `region_grid`, and `quarter_footprints` (T-1112/T-1119, landing concurrently with this design). A windowed district payload is a different kind of traffic by construction: its content is keyed on **`(body, center, n)`**, it is re-requested on every pan (not cached once per body and reused), and a stale response must be **detectable and discardable** by the client rather than silently rendered — none of which is true of the five/six-member family the ceiling was written for. Retrofitting it into that family as a bare `district_window: Option<DistrictWindowLayer>` sitting next to `region_grid` would misrepresent its semantics (implying the same "cached snapshot, always current" contract its neighbours have) even before the slot-count argument. The ceiling's subject is therefore explicitly re-scoped here to **the dense whole-body layer family** — it does not gate this field, and this field does not count against it. This is option (c) from the T-1124 refinement's three choices, chosen over (a) (a bare seventh/eighth `Option` peer — technically fits the struct, dishonestly fits the family) and (b) (a second response message — real complexity, a new framing concept, for a problem the existing struct already solves once the semantics are named correctly).
`AtlasLayerResponse` gains exactly one new field along these lines:
```rust
pub struct AtlasLayerResponse {
// ...existing fields unchanged...
pub region_grid: Option<RegionGridLayer>,
/// The requested district window (T-1124), or `None` when the request
/// carried no `window_center` / no window data is cached yet for a
/// pending body. Distinct from the five layers above: keyed on the
/// REQUEST (body, center, n), not on the body alone — see §2.
pub district_window: Option<DistrictWindowLayer>,
}
```
`DistrictWindowLayer` **echoes `center`/`n` back on the response** — this is the client's race-condition guard, not a convenience field. Because window derivation is pure and deterministic (D-227: `derive_district` is a function of `(seed, body_id, body_params, terrain, district_pos)` only — no hidden request-order dependence), the same `(center, n)` query always yields the same payload, so the echoed tuple *is* the cache/staleness key: the client compares it against whichever window it most recently asked for and discards any response whose echo doesn't match (superseded by a later pan). No sequence number or request-id is needed — D-227's purity is what makes the echo sufficient.
```rust
pub struct DistrictWindowLayer {
pub center: DistrictPos,
pub n: u32, // window side length in districts (n × n cells)
pub morphology: Vec<u8>, // MorphologyZone discriminant, 17-entry frozen vocab (D-239 §6)
pub elev_q: Vec<u8>, // 0-100, matches DistrictGridLayer.elev_q encoding
pub temp_dc: Vec<i16>, // deci-°C, REGION_TEMP_NONE_DC sentinel — same scheme as RegionGridLayer.mean_temp_dc, deliberately NOT a separate district-tier quantization (see rationale below)
pub moisture_q: Vec<u8>, // 0-100, matches DistrictGridLayer precedent
pub vegetation: Vec<u8>, // VegetationClass discriminant, 0-6 incl. Marine (T-1126)
pub glaciation: Vec<u8>, // GlaciationGrade discriminant, 0-4 (T-1127, accepted — see §3)
}
```
All six arrays are dense row-major `n × n`, same indexing convention as `DistrictGridLayer`/`RegionGridLayer` (`i = row * n + col`), built by iterating `derive_district` over `[center.0 - n/2, center.0 + n/2) × [center.1 - n/2, center.1 + n/2)` exactly as `aliveness_probe --render`'s `render_window_panels` already does — this design promotes that probe's window loop from a debug binary to a served layer, unchanged in mechanism. **Temperature stays `i16` deci-°C with the existing `REGION_TEMP_NONE_DC` sentinel**, not a new `u8` band-relative scheme (a live design-round proposal, overruled here): the district window and the region climate overlay (item T-1113) must share one temperature colorizer on the client, and D-243's edge-fuzz discipline ("climate does not change on a line") argues against two independently-chosen quantizations that could paint a visible ramp discontinuity at the region/district zoom-swap threshold — a rendering seam standing in for a data seam that D-243 explicitly rules out. The 1 extra byte/cell this costs over `u8` is immaterial at the window sizes in §4.
- **(3) Field-list dispositions (mandatory per the T-1124 refinement).** Six fields ship, all already-derived `DistrictProfile` members with no new derivation logic:
- **`glaciation_grade`: ACCEPT.** T-1127 (done, PR merged) explicitly deferred this field's wire half to this design pass and flagged the render pattern already works — the per-pixel ice tint on the morphology panel (`aliveness_probe::apply_ice_tint`) is production-proven, and `glaciation_grade` is already a first-class `DistrictProfile` field with a stable 04 discriminant. Shipping it as its own array (rather than baking the tint server-side into `morphology`) matches Araminta's encoding needs: the client can choose to tint, use a dedicated glaciation overlay, or ignore it, exactly as the probe renderer offers a sixth dedicated panel alongside the tinted morphology panel.
- **`vegetation` palette/legend must be exhaustive over `Marine = 6`.** T-1126 appended `Marine` to `VegetationClass` (open water, morphology-derived, never a threshold of its own) specifically because the district tier is where the ocean-blind-vegetation bug (frozen bodies reading Forest over open sea) was caught. Any client palette/legend for this field that omits `Marine` reintroduces exactly that bug at window resolution — non-negotiable inclusion, not a nice-to-have.
- **T-1127's ceiling ruling generalizes to this whole field list.** Its refinement text is explicit: *"the cap governs new top-level Option layers, not per-cell fields inside a shipped layer"* — the precedent it cites (`elev_q` already riding inside `DistrictGridLayer` with no separate governance gate) is the same shape as all six fields here riding inside one `DistrictWindowLayer`. Per-cell field additions to an already-shipped layer are engineering, not governance, unless a field would reopen a frozen vocabulary (D-239 §6's 17-zone freeze) — none of these six do; `morphology_zone` and `vegetation_class` both ship their existing frozen/T-1126-amended discriminant sets unchanged.
- **(4) Budget (binding numbers).** Per-cell wire cost is **7 bytes** (`morphology` 1 + `elev_q` 1 + `temp_dc` 2 + `moisture_q` 1 + `vegetation` 1 + `glaciation` 1), before MessagePack array-header overhead (negligible at these sizes — six flat byte/i16 arrays, no per-element framing). **`DISTRICT_WINDOW_MAX_N = 64`** (request-side hard clamp, §1): 64×64 = 4,096 cells → 28 KiB raw payload. This is deliberately the same `n` as `aliveness_probe --render`'s default window (T-1123) — a value already proven to render correctly server-side and matching the "regional inspection" altitude the ticket names (64 districts × 2.048 km ≈ 131 km per side — city-and-hinterland scale, not planetary). **`DISTRICT_WINDOW_DEFAULT_N = 32`** (client's interactive default, 1,024 cells → 7 KiB) — half the cap, chosen so the common pan-and-look case stays comfortably inside a single-digit-millisecond derive cost even before any release-build speedup: at the ~7 µs/derive debug-build rate T-1123's window renderer measured, 1,024 cells ≈ 7 ms, 4,096 cells (the n=64 cap) ≈ 29 ms. **This is a debug-build figure with no committed release-build number yet** — release is expected meaningfully faster (no debug assertions, inlining) but the design does not presume a specific multiplier; if profiling later shows the cap needs to move, `DISTRICT_WINDOW_MAX_N` is the one constant to tune, not a redesign. Neither figure is gated by D-200's 5 ms on-demand tile-fill budget — that budget governs the main-tick-thread chunk-boundary path; this request is served off the D-226 item (1) paused-sim bridge path (Snapshot/PostSnapshot stay alive while Movement/Simulation/Economy/etc. freeze), so its budget is interactive-UX responsiveness on a paused screen, not a per-tick deadline. **Re-request-on-pan policy:** the client re-requests only when a **pan** carries the view past the held window's edge — **never on zoom** (§5): only pan changes `center`, and because window derivation is deterministic (D-227) a zoom-triggered re-fetch of the same `(center, n)` would spam byte-identical responses for zero new information. The client debounces pan motion (do not fire on every drag-frame delta); the exact debounce interval and whether windows snap to a fixed grid vs. float on the pan center are client-side screen decisions (Araminta's §5) using the request/response contract fixed here. **Client cache policy:** windows are cacheable client-side keyed on `(body_id, center, n)` — D-227's determinism guarantee (same seed/body/position → same derived output, always) means a previously-fetched window is valid forever for that body+seed and can be kept in an LRU without a freshness check, exactly the same guarantee that makes the whole invention pipeline (D-227's "invented deterministically" clause, the actual subject T-1124 surfaces to a screen for the first time) safe to memoize; eviction policy (size, LRU depth) is a client implementation detail, not fixed here.
- **(5) Screen (Araminta).** The regional view is a **zoom-threshold LOD swap on the existing `AtlasViewer`, not a new screen**: a second, higher zoom threshold (`DISTRICT_WINDOW_MIN_ZOOM`, proposed `6.0`, past the existing `SETTLEMENT_LABEL_MIN_ZOOM = 2.0`) crossed while the pan center is over/near a settlement swaps the draw target in place — same `AtlasViewer` node, same `RegionalScreen` nav-stack "regional" state `show_body()` already establishes, no nav-stack push, no second `Control` scene, no new crumb. Both thresholds live on the existing `_view_zoom` float. Crossing back out (zoom below the threshold, or Esc — the two exits are one code path, a zoom-value transition watcher) swaps back. This reuses the viewer's own established LOD vocabulary (zoom past a threshold reveals more detail — labels at 2.0, the district window here) and its "reveal more without leaving" instinct (city-click opens a sidebar, not a nav push). **Rejected:** a nav-stack push (the planetary→regional push earns its crumb because the rendering genuinely changes — galaxy scatter → heightmap texture; body→window is the same viewer at a smaller camera window, so a crumb would imply "you left somewhere" for a metric reached by scrolling in); click-to-open on the settlement dot (overloads the existing city-click sidebar gesture — two intents on one gesture, and D-013 argues the zoom gesture should own spatial descent); a dedicated "view district" button (duplicates what pan/zoom already promises at every other level of this map).
- **Pan re-fetches; zoom does not.** A **pan** past the held window's edge re-centers `window_center` and fires a new request (§1's optional fields, same request machinery); **zoom never re-fetches** — with `DISTRICT_WINDOW_MAX_N = 64` the composite is a texture the client zooms client-side (the existing `_view_zoom` mechanic, now on the smaller composite) to get from a coarse read (~14 px/cell at n=64, 1.0×) to a detail read (~28 px/cell at 2×, comparable to the T-1123 `w256` probe renders' native fine texture) **from already-held data**. In-window zoom doing real legibility work is what separates "fetch = ground coverage" from "render zoom = detail resolution"; a zoom-triggered re-fetch would spam byte-identical (D-227) responses for the exact `(center, n)` already on screen. This is the §4 re-request policy's client-side rationale.
- **Debounce + window origin (the two client-side calls §4 left open).** Re-fetch fires **150 ms after the last drag-release** (not per-drag-frame) — long enough to collapse a flick-and-resettle into one request, short enough that a deliberate single pan-and-stop never feels delayed (no competing tick-driven redraw under the D-226 pause). Windows **float on the pan center** (nearest `DistrictPos` to the new screen-center), **not grid-snapped** — snapping would jump the composite by up to half a window-width across a snap boundary (a visually discontinuous "invisible re-fetch"), and floating keeps the anchor settlement exactly centered on entry every time; the §4 client cache still gets real hit value because Esc-then-re-enter and pan-back reproduce the same `(body_id, center, n)` (D-227 makes exact-repeat the common case for the two navigation patterns that matter), without a grid forcing arbitrary alignment.
- **What renders during the wait** (the "invisible re-fetch"): the previous composite, panned to its new screen position, with a **border-fade to the underlying whole-body heightmap** (already resident, coarser `district_grid`/`region_grid` data — real data seen through, not a placeholder) at the newly-exposed edge; **no black, no spinner** unless the wait exceeds a ~0.5 s grace window (reusing the existing `_gen_pending_indicator`, not a new mechanism). Because §4's cache is D-227-valid indefinitely, a pan back toward a recently-cached window composites from cache with zero wait — the genuine-miss `Pending`/re-poll path (D-225's existing loop) becomes the minority case, not the default.
- **Overlay/legend reuse against §2–§4.** The base layer is **morphology, lightness-modulated by `elev_q`** (one `0.7 + 0.3*(elev_q/100)` multiply per cell — relief read without a second draw call, the T-1112 "shape=identity, cheap second channel=magnitude" instinct as hue=type / lightness=elevation), reusing the T-1123 probe's 17-entry `MORPHOLOGY_RGB` hues verbatim; it is always-on once the LOD threshold is crossed (it *is* this screen's `terrain` layer), so it takes no toggle id. Three switchable overlays get new `gen_dw_temp` / `gen_dw_moisture` / `gen_dw_veg` `OVERLAY_DEFS` ids (`group: "toggle"`, the `gen_l1_*` multi-toggle-over-one-base precedent): **temperature** reuses T-1118's region-grid ramp *exactly* (same `i16` deci-°C domain + `REGION_TEMP_NONE_DC` sentinel disposition — one colorizer across both zoom levels, §2's consistency ruling); **moisture** reuses the existing `SUB_BIOME_COLORS` dry-sand→wet-teal endpoints; **vegetation** is a green-family ramp with **`Marine = 6` rendered transparent** (lets the morphology water-blue show through — `Marine` is `derive_vegetation`'s bookkeeping answer for already-`OpenOcean`/`Lake` districts, not new player information; a second blue would fight or duplicate the morphology read — this is the exhaustive disposition §3 mandates). **Glaciation is a modifier, not a toggle**: an ice-tint wash gated on `glaciation_grade >= Light` (alpha scaling with grade) composited over whichever layer shows — the `aliveness_probe::apply_ice_tint` approach ported to the player composite; it keeps sea-ice (tint over `OpenOcean` navy → whitened blue) visually distinct from open ocean and from ice-capped land (tint over alpine grey → near-white) by alpha-compositing over different bases rather than three drifting hard-coded colors. Legend: one `GENERATION_LEGEND` entry per new id (existing data-driven `atlas_legend_panel.gd` table, no new panel class); the morphology base folds its 17 zones into ~5 family rows (water / coastal-transition / plains-river / upland / volcanic) with the full mapping in the city-click sidebar, mirroring T-1112's "not everything earns permanent screen space" discipline. Implant chrome discipline (D-169/D-170): `ImplantHeader` carries the anchor name + extent-in-real-units subtitle (e.g. "4.1 × 4.1 km · 2.0 km/cell") + one optional flavor line; the map-data palettes stay **out of** the theme's semantic accent roles (especially `ACCENT_ACTIVE` gold, which the settlement marker owns and must not compete with); no scanline/glitch dressing (the implant is confident working tech — a signal-quality state, if ever needed, rides `_gen_pending_indicator`, not cosmetic noise). Full color/ramp/compositing/legibility rationale and the n=32↔n=64 on-screen-scale math live in Araminta's companion T-1124 sections (visual encoding / implant aesthetic / legibility constraints), not re-derived here.
- **Rationale:** Reusing the real UI — rather than a parallel offline renderer or dumped files — means the debug/review surface never diverges from what ships, and a dropped artifact can't go stale. Agent-navigability converts qualitative "does the synthesis look natural?" review from a manual eyeball pass into an automatable sweep that flags the few outliers for a human. The harness rides seams that already exist (`TickRate::Paused`, the paused-allowlist, `gameplay_occluded`, the bridge framing, the `run-visual` capture primitive) — a naming-and-contract exercise, not a new subsystem.
- **New surface:** server pause-gating (run-conditions on the world phases keyed to a pause command); client `AtlasAgentInterface` (`observe`/`act`, Control-tree walker) + its local transport; the generation overlay rendering + selector + legend; interactive capture wired to `run-visual`.
- **Implementation:** Phase 4 (epic T-750), built bottom-up — auto-pause substrate, T-969 proxy (D-225), T-960 viewer, agent channel, agent capture. Geography is the first consumer.
- **Raised by:** Jeroen + Claude (design), with Tyre (channel/pause/headless architecture) + Araminta (overlay encoding + affordance UX), 2026-05-24.
- **Cross-reference:** [D-225](#d-225) (layer-stream proxy — the data path), [D-166](#d-166) (per-layer Atlas progress viewer), [D-191](#d-191) (Atlas viewer), [D-169](#d-169) / [D-170](#d-170) (implant components / HUD occlusion — `gameplay_occluded` trigger), [D-200](#d-200) / [D-203](#d-203) (execution tiers / LRU cache), Q-099 (mod content catalog), `tests/run-visual` (capture primitive), `save_state.rs` (save-inspection consumer). **T-1112 amendment additionally:** [D-222](#d-222) (Quarter terminology — the 512m unit this layer surfaces), [D-234](#d-234) (footprint geometry — the block-subdivision source the aggregates summarize), [D-243](#d-243) (quarter = 512m rung, and the containment ladder that makes a quarter sub-pixel at planetary projection — Araminta's no-outline rationale), [D-010](#d-010) (determinism — integer-only aggregates, `BTreeMap` keying).
- **Cross-reference:** [D-225](#d-225) (layer-stream proxy — the data path), [D-166](#d-166) (per-layer Atlas progress viewer), [D-191](#d-191) (Atlas viewer), [D-169](#d-169) / [D-170](#d-170) (implant components / HUD occlusion — `gameplay_occluded` trigger), [D-200](#d-200) / [D-203](#d-203) (execution tiers / LRU cache), Q-099 (mod content catalog), `tests/run-visual` (capture primitive), `save_state.rs` (save-inspection consumer). **T-1112 amendment additionally:** [D-222](#d-222) (Quarter terminology — the 512m unit this layer surfaces), [D-234](#d-234) (footprint geometry — the block-subdivision source the aggregates summarize), [D-243](#d-243) (quarter = 512m rung, and the containment ladder that makes a quarter sub-pixel at planetary projection — Araminta's no-outline rationale), [D-010](#d-010) (determinism — integer-only aggregates, `BTreeMap` keying). **T-1124 amendment additionally:** [D-227](#d-227) (derive-don't-store + the "invented deterministically" clause this design is the first to surface on a screen; determinism is what makes the echoed-center staleness guard and the client-side window cache both sound), [D-243](#d-243) (district = 2,048m rung — this is precisely the D-226(d) ceiling's floor, the regional altitude above quarter-skeleton and below the never-mapped chunk/voxel tier; edge-fuzz discipline — the temperature quantization-consistency rationale), [D-239](#d-239) §6 (the frozen 17-zone `MorphologyZone` vocabulary this layer serves unchanged) / §8 (vegetation climate law, amended by T-1126's `Marine`), D-225 extension / T-1131 / PR #184 (the five-map-shape demux ceiling — why the window rides on `AtlasLayerRequest` rather than a new inbound shape), [D-010](#d-010) (wire-integer discipline — all six per-cell fields are integer/quantized, no `f32` on the wire). §5 (screen) additionally leans on [D-191](#d-191) (the `AtlasViewer` whose `_view_zoom` LOD vocabulary and `SETTLEMENT_LABEL_MIN_ZOOM` threshold the district window extends in place), [D-169](#d-169) / [D-170](#d-170) (implant chrome / theme accent-role discipline — map palettes stay out of `ACCENT_ACTIVE` gold the settlement marker owns), and [D-013](#d-013) (diegetic navigation — the zoom gesture owns spatial descent, so it is not overloaded onto the city-click sidebar). Tickets: T-1123 (the `derive_district` window-render precedent this design promotes to a served layer), T-1127 (glaciation_grade derivation + probe render pattern, wire half deferred here and now accepted), T-1126 (`VegetationClass::Marine`), T-1118 (region-grid climate overlay — §5's temperature/moisture overlays reuse its ramp so one colorizer spans both zoom levels), T-1119 (concurrent `quarter_footprints` wiring — the sibling whole-body layer this design's §2 distinguishes itself from).
- **Dissent:** None
---