diff --git a/docs/architecture/atlas-zoom-ladder-t1143.md b/docs/architecture/atlas-zoom-ladder-t1143.md index e1e5ffbfe..ba6124f60 100644 --- a/docs/architecture/atlas-zoom-ladder-t1143.md +++ b/docs/architecture/atlas-zoom-ladder-t1143.md @@ -108,6 +108,8 @@ Confirmed by direct code inspection (not aspirational): `value_noise`, `terrain_ **Split:** rungs govern *what classification granularity is available and legal to request* (a policy/cost question, §2/§10); canvas-resolution sampling governs *what density the client actually asks for*, tracking the viewport continuously. The rung-selection rule (§2) is the join: pick the coarsest legal rung whose spacing is ≤2× the current screen sample spacing. +> **Erratum (2026-07-22, T-1153 implementation — Stig):** the single-table-scan reading of the rule above is unsatisfiable for the District rung at any real viewport: with `CELL_PIXEL_SIZE = 16` and the server's `DISTRICT_WINDOW_MAX_N = 64` per-axis cap, the ≤2× visual-tolerance band and the window-coverage ceiling never overlap (boundary zooms at 1600×900: coverage releases Region at `_view_zoom ≈ 1.5625`, the 2× band hands District→Quarter at `≈ 0.125` — pinned by executable tests in `client/tests/test_atlas_window_geometry.gd`). As implemented, `AtlasWindowGeometry.select_rung()` splits the rule into two independent gates: a **coverage ceiling** (can a District-extent window span the requested world extent at all — decides Region) checked first, then the **2× visual tolerance** (decides District vs Quarter) on the remainder. Net effect at real viewports: the ladder steps Region → Quarter directly; District has no felt band. Pacing knobs if that's undesirable: `CELL_PIXEL_SIZE` shifts both crossings but cannot open a District band; the `2.0` multiplier in `select_rung()` is the client-only lever (at the cost of loosening the one-tier-finer-than-a-pixel guarantee); a real District band needs `DISTRICT_WINDOW_MAX_N ≥ ~canvas_px/2` — a server wire-budget change requiring re-measurement. + **Bounded key space, not unbounded.** A continuous field sampled at arbitrary density would give the cache an unbounded key space (client obstacle flagged in the grounding: the 24-entry exact-match LRU would thrash to ~0% hit rate). This is avoided because **requests snap to quantized rung tiers** (granularity ∈ {1, 4, …}) and integer district-aligned centers — only *display* is continuous; every *request* the wire actually carries is one of a small number of discrete shapes. **Gap flagged by critique:** as specified, `window_min_wl_m` is viewport-continuous (`E/C`) while the cache key/echo tuple is `(body, center, n, granularity)` — same key, different `min_wl`, would silently collide. Fix: **quantize `min_wl_m` to a small fixed set of bands per rung** (matching the rung's own octave bands) rather than passing a raw continuous value, and add the quantized band to both the echo and the cache key. This closes the gap without reopening the unbounded-key problem. **Region/orbital granularity is unrepresentable in the current sketch.** `window_granularity: u32` with `spacing = DISTRICT_M / granularity` can express district (1) and quarter (4) but not region (coarser than district, i.e. granularity < 1). If the planetary rung's chosen carrier (§4) reuses this same field, the type needs to change to something that can express both directions (e.g. a signed log-scale or an explicit rung enum) — noted for the implementer, not resolved here.