The relationship between wiki/, the generators, systems.db and the runtime is
a directed graph with two edges running opposite to the obvious direction and
one running backwards into its own producer. Prose renders that badly: every
document that has described it states a single ownership direction and is
therefore wrong about part of the tree. D-262 makes the diagram the source of
truth and points CLAUDE.md, Skill(wiki), project-structure.md and
wiki/GOVERNANCE.md at it.
The correction that matters most: body pages were described everywhere as
machine-owned and reverted on sync. They are not. scaffold_bodies.py writes
one once and never overwrites it, and import_economics then reads that
frontmatter directly as input — so a hand-edit is not reverted, it is obeyed,
and silently changes world generation. Worse than being overwritten, and the
actual reason GOVERNANCE.md forbids the edit.
New: tooling/check-dataflow-graph.py, wired into the Makefile and the pre-push
hook. It asserts every repo path named in a hand-authored diagram still
resolves — and its docstring states plainly what it cannot do: verify that an
edge still MEANS what it says. If wiki_sync.py stopped writing body pages
tomorrow, every path would still exist and the check would still pass. Edge
semantics stay a human check against the tool's source, so nobody reads a green
gate as a verified map.
Verified by breaking it: pointing one label at a moved path fails with exit 1
naming that path; restoring it passes. Building the checker also caught two
real vaguenesses in the diagram — "GJ-*/index.md" and "bodies/{id}/index.md"
were written without their wiki/star-systems/ prefix, which is precisely the
ambiguity this map exists to remove. Generated star-map .d2 files are excluded
by name; their correctness belongs to their generator under D-223.
Also files Q-124 + T-1246 (tooling): whether the 123 Python files under
tooling/ should become one Rust CLI of pql's calibre. The friction is real and
mostly not about the language — the permission gate prefix-matches whole
command strings and a blanket Bash(python3 *) grant is forbidden, so each tool
prompts near-individually, while a single binary is one allowlist entry. The
record requires pricing the cheap alternative (a Python dispatcher entrypoint)
before recommending Rust, and flags the hard constraint: import_economics is
stamped by source SHA, so any port must keep that contract intact through the
transition rather than disabled during it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three findings, all doc-accuracy, and all the same root cause: folding the
spacing predicate into the ring walk changed what three comments describe, and
two of those comments were written by this same PR one round earlier.
TYRE 1 — road_graph.rs's T-1206 gap-closure comment cited `nearest_land_cell`,
which round 2 made `#[cfg(test)]`. A reader chasing that name lands on a
test-only function and reasonably wonders whether they are looking at dead
code. Repointed to `nearest_cell_matching`, and the paragraph's closing claim
that "T-1206 guarantees the placement pixel is land" is corrected: it has been
land-AND-spacing-or-skip since round 2.
TYRE 2 — `max_land_search_ring`'s doc named the same test-only wrapper as the
thing that walks the bound. It now names the production consumer and both
callers.
TYRE 3 — the D-211 amendment was written in round 1, before round 2 existed,
and still described a land-only correction. It now carries a dated refinement
recording what the code actually does: the walk satisfies BOTH of step 4's
promises in one search, and SKIP therefore also fires where land exists but
none of it clears spacing within the bound. The no-re-decision conclusion is
unaffected — position remains a deterministic, non-fabricated function of seed
and terrain — and the refinement notes the spacing promise is step 4's alone,
since Tier A/B/C placements sit on their matched attractor and were never
subject to it.
HOSHE's three findings were the same three hunks, observed uncommitted while
the review ran: accurate content, but not in the branch tip, so the PR would
have merged a governance record that misdescribes its own commit. That is this
commit.
Both reviewers independently confirmed what the round-2 fix claims. Tyre traced
the ring geometry and tie-break order by hand against the spacing predicate;
Hoshe re-ran the full 267-body corpus scan live (850s) and reproduced the
figures exactly — 267 bodies, 267 reaching Layer 3, 344 placements, 109
synthetic, 0 in water, 0 spacing violations.
The shared-ring-search-helper retraction is confirmed and settled, with NEW
grounds rather than a restatement: round 2 strengthened the case for keeping
them separate, since this walk is now parameterized by an arbitrary predicate
over native u16 terrain coordinates while road_graph's is a RouteGrid method
over downsampled routing cells with a fixed cost test and an unrelated bound.
22 module tests green; clippy and fmt clean.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Measured during T-1213, through the production canvas builder on Ferrath: at
Quarter and below, morphology collapses to ONE zone and vegetation to ONE
class. The uniform frames in the 2026-08-06 descent ladder were those rungs
drawing exactly what they contain.
The cause is arithmetic, not a missing feature. At the uniform 2x2 px display
ratio a 3440x1440 window gives 540 gridunits on the short axis, so:
Quarter 512 m -> 0.948 m/gridunit -> 0.474 m/px ~1 subtile per pixel
Block 128 m -> 0.237 m/gridunit 4 gridunits per voxel
Chunk 64 m -> 0.119 m/gridunit 8 gridunits per voxel
Block and Chunk magnify beneath the finest datum that can exist, so they can
only ever draw one voxel larger. Quarter lands within 5% of one subtile per
pixel and becomes the floor.
Stated as a rule so it survives the constants moving: the deepest Atlas rung
is the one at which a screen pixel shows one subtile. It is derived from the
data model rather than chosen, and it moves automatically if the subtile does.
WHAT THIS IS NOT. Chunk remains the 64 m stream/derive unit of D-243 and stays
vital — it is what Phase 5 derives first-person walkable content on, and
D-012's load-around-the-player is expressed in chunks. Block remains the 128 m
generator planning unit. Only Atlas VIEWABILITY is retired; the containment
ladder is untouched. This record governs what the map draws, not what the
generator builds.
The justification is the Atlas's purpose (Jeroen): it exists to give the player
information, and a rung earns its place by answering a question the rung above
cannot. Once a pixel is a subtile there is no finer datum to answer with.
The resulting Global -> Region -> District -> Quarter steps at ~93x -> 100x ->
4x. That unevenness is NOT from this change — the rungs removed were 4x and 2x
steps carrying no information — it is D-243's one non-power-of-2 rung, and
T-1218 already exists to re-balance it. A compensating rung above Region was
considered and declined here; it belongs with that ticket.
CLAUDE.md's cascade line updated in the same commit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The 2026-07-27 amendment closed by naming the live question: does biome
un-summarisation need a stored layer, or does it ride the existing
sample-fresh-at-every-rung mechanism. A descent ladder answers a prior one:
it is not happening in any form, stored or derived.
One body, one land-anchored point, one capture per rung, no overlays, at the
panel's native 3440x1440. Ferrath's heightmap is 1024x512 over a 38,089 km
circumference -- 37.2 km per source pixel. Global draws at 35.267 km/gridunit,
about 1:1 with the source, and reads as a world. Region draws at 0.379 --
98x finer than anything stored -- and is a uniform colour field with dither.
District, at 0.0038, is ~9,800x finer and identical in character. The Atlas is
legible exactly where it samples the heightmap and flat everywhere it invents.
So the D-227 carve-out cannot be argued yet on any basis, disproven or
measured, because there is no artefact to store. Ruling: build the expansion
as a pure function first, following the mechanism that already exists
(D-255(f) mechanism B), measure that, and reopen storage only if the numbers
force it. T-1211 re-scoped, T-1212 retired as a gate with its measurement
moved downstream, T-1213 unblocked as the epic's first child.
Recorded with the same process note the previous amendment earned: this was
found by capturing the ladder and looking at it, after the goldens had been
failing for 15 commits with two of them passing against blank screens.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three findings from Hoshe (QA) and Tyre (architecture), plus a bug the first
of them uncovered.
HOSHE — the headline evidence lived only in a deleted scratch scan. All nine
tests used synthetic fixtures, so nothing committed held the "46 of 109
synthetic placements in water" claim on real data. Two tests now do. The
T-1206 verification scan itself is committed as an #[ignore]d full-corpus
test (267 bodies, run with --ignored), which also makes the recalibration
instruction on the search bound executable rather than aspirational; a fast
test pins the bodies it identifies.
That scan promptly caught a bug in its own first draft, and it is the reason
this commit is worth reading. `CascadeSnapshot::terrain_analysis` is
transient — the cascade nulls it the moment DistrictProfile and RoadGraph are
done (D-203/T-1048, ~2 MB a body) — so it is ALWAYS None on a returned
snapshot, whatever cascade_snapshot_for_body's doc-comment implies. Reading
the ocean mask off the snapshot and skipping when absent therefore skipped
every body while reporting success: 267 bodies "scanned", 0 findings, a green
assert over an empty set, in 697 seconds. Terrain is now re-derived through
the same run_layer1_with_moisture call the cascade used, reproducing the grid
the placements were computed against.
Two habits caught it, both prompted by Hoshe's finding: a vacuity guard that
refuses to pass when no synthetic placement was seen, and counters that stop
"none found" and "never got that far" from looking identical. Corrected
figures at seed 42: 267 bodies, all reaching Layer 3, 344 placements, 109
synthetic, 0 in water — the synthetic count matching the original scan, so
the claim is reproducible now rather than anecdotal.
TYRE 1 — MAX_LAND_SEARCH_RING was justified as grid_h/2 but written as a
literal 128, leaving the 512x256 coupling implicit. It is now derived from
the grid in scope, so the value cannot drift from its own rationale. On the
current working grid it evaluates to exactly 128: no behaviour change, and
the byte-identical-placement guarantee is untouched. Recalibration owner
recorded.
That derivation does change one test. nearest_land_cell_clamps_rows_no_wrap
uses a 16x16 fixture, so its bound drops 128 -> 8, which now sits BETWEEN the
clamped distance to the far pole (15) and the wrapped one (1). The assertion
moves from position to absence and gets sharper for it: previously both
implementations returned Some((15,0)) and only the position could be pinned;
now any Some at all proves rows wrapped.
TYRE 2 — D-211 carried no note though its behaviour changed. Dated amendment
added: step 4's outcome set is no longer total (synthetic overflow may now
resolve to a defined SKIP), and step 5's warning fires for a new legitimate
reason. No re-decision needed — position remains a pure function of seed and
terrain — and the dead-end cross-reference to D-210's closure is now a live
anchor.
Full cargo test green (30 binaries).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A river is sub-pixel at almost every Atlas scale (a 100 m channel against
Global's ~17.6 km per screen pixel), so drawing it to scale draws nothing.
The line becomes a symbol whose job is legibility: a fixed 5 px screen-space
stroke, contiguous through the river's own cell centres, never drawn over
water, and culled when too small to read.
The cull threshold derives from the stroke rather than being stipulated. A
mark reads as a line at roughly 3x its own width, so the minimum is 15 px of
on-screen length — and the kilometre thresholds then fall out of each rung's
scale: 264 km at Global, 2.8 km at Region, 28 m at District. A level-of-detail
ladder with no hand-tuned constants, which self-corrects if the width changes.
Measured on the visible extent, not total river length: a course crossing the
window always spans it and passes, so only a course wholly inside the view and
small is culled. Correct at both ends of the ladder, and no new wire field.
Records a tension that had to be resolved rather than split. Jeroen proposed a
flat 100 km cutoff, then noted that 5x5 px still reads as a dot and asked for
15-20. Those are incompatible: the km threshold depends only on the pixel
length, so 100 km implies ~6 px, which is dot-shaped at a 5 px stroke.
Admitting 100 km rivers AND keeping them line-shaped needs a ~2 px stroke.
Thick lines mean fewer rivers; thin lines mean more. Ruled for the bold stroke.
Client-side, and provably so: the cull is measured in screen pixels, and the
display ratio is a client-side viewport-dependent parameter that never reaches
a wire request or cache key, so the server cannot know how many pixels a
course occupies. Water-clipping needs nothing new either — the per-cell
classification is already in the adopted canvas.
Built on the 2026-07-27 measurement in D-258's amendment: 375 courses present,
458 of 518,400 pixels different. The rivers were not failing to render, they
were correctly beneath notice; the defect was drawing specks instead of
drawing properly or not at all.
T-1237 implements. T-1238 restores size-varying width as polish, deliberately
deferred — noting width and cull are coupled, since a thinner stroke lowers
its own visibility threshold.
Co-Authored-By: Claude <noreply@anthropic.com>
Written one day after the record, on evidence, and it narrows D-258's scope.
The Rationale claimed hydrology 'was not derivable at all under the old
model'. Not true, and not true when written: layer1.rs already solves drainage
AND settled-equilibrium hydrology once per body, folds the filled surface into
TerrainAnalysis, and every rung bilinearly samples it. The code's own comment
names it — 'a coarse continuous primitive computed once, sampled fresh at
every rung, never re-solved', mechanism B, D-255(f). The pattern rung 0.5 was
invented to provide already existed. I inferred the claim from Region having
no rivers without reading the layer-1 pipeline.
What actually made Global flat was a stale sentinel zeroing its extent, giving
a 2x1 canvas. Once sized correctly Global reads as a world with no hydrology
work at all. Rivers there measured negligible: 375 courses present, 458 of
518,400 pixels changed versus courses-off, because at ~39.7 km/gridunit most
courses are shorter than one gridunit.
Survives: reliefmap-as-plurality, composition-on-descent, the conservation
invariant, and the lake-shore amendment — none depend on hydrology moving.
Weakened: the stored expanded layer and its D-227 carve-out, since the
compute-once-sample-everywhere mechanism it argued for is already shipped.
T-1211 and T-1212 flagged needs-refinement with the reasoning attached; the
measurement as scoped would have priced work that is not required.
The amendment also records why this survived review: the sizing fix's tests
called resolve_canvas_extent directly rather than the serve path, and the
capture goldens could not have caught it either since they never supplied a
body radius. Two verification layers, both green, neither looking at the thing.
Co-Authored-By: Claude <noreply@anthropic.com>
Everything else from the pair session was either shipped or ticketed with its
rationale in git. These two were design decisions Jeroen made, living only in
a scratchpad under /tmp, one cleanup away from gone.
D-259 — ENCLOSED SETTLEMENTS. Open-air requires atmosphere == standard;
everything else is enclosed, as point locations on the Atlas with interiors
deferred to a separate generator and handled like embedded stations. Branch on
an explicit `enclosed` property rather than the atmosphere string, so enclosed
settlements on breathable worlds (hostile-biome posts, undersea, arcologies)
need no second code path. NULL defaults to enclosed, which fails safe.
The load-bearing claim is that D-220's density model is PHYSICALLY
INAPPLICABLE to a pressure vessel, not mistuned: it measures people per km2 of
footprint driven by utility cost per metre of street, so run airless it yields
1,500 ppl/km2 of open-air streets in vacuum. The handoff mechanism was already
planned — D-166's door boundary contract, where a dome's airlock IS that door.
Atmosphere keeps its full range for the surface-expedition layer; the binary
collapse applies to settlement layout only, and the record says so to stop the
collapse being read as atmosphere not mattering.
D-260 — GENERATOR SCOPE. Sol is encoded as Authored { deepest_rung: Global }
rather than excluded by convention. The DLC gate is a DEPTH, not a boolean, so
a Sol expansion changes one value instead of unpicking an exclusion. No new
wire status: "viewable at Global, no deeper" IS the existing rung-liveness
path. Sol art is an authored data canvas, not a finished image, so it rides
the existing wire and is drawn by the same map-art function as all 269
procedural bodies.
The hazard that made encoding necessary is recorded: systems.db still carries
terrain_reference rows for Sol bodies pointing at heightmaps deliberately never
baked, so a real Earth DEM dropped at that exact path would silently start
generating a procedural homeworld. The importer comment said Sol was excluded;
nothing enforced it.
Also files the last three parked items, which were likewise /tmp-only:
T-1233 tiled/interlaced map loading (workshop-sized D-255 revision, blocked in
spirit on the rung-0.5 cost numbers), T-1234 enumerate the flow tweaks the
fetch panel exposed but which were never written down, T-1235 zoom
discoverability — the person who specified wheel-only zoom could not find it.
T-1231 closed.
Co-Authored-By: Claude <noreply@anthropic.com>
D-255 described a system that stopped existing this morning. It said a rung
fixes gridunit SPACING and that spacing is "never viewport-derived"; both are
now exactly backwards. Anything reading it — a refinement agent, a reviewer,
a future session — would have built against a fiction with no way to tell.
Records the inversion (a rung fixes EXTENT, the shorter viewport axis spans
one cell of that level, spacing falls out), Global moving from the body's
region grid to a viewport-sized 2:1 canvas, Region leaving the orbital derive
set, and the display-ratio band collapsing to a uniform 2x2.
Two corrections matter beyond bookkeeping.
D-255 justified Global's D-226(d) legality by it being COARSER than the region
grid. It is now finer — 40.8 km against 204.8 km. The conclusion survives,
since D-226(d) prohibits tile-level maps and caps at settlement/quarter
granularity and 40.8 km is twenty times coarser than a district, but the
premise is dead and nothing downstream should lean on it.
And the always-keep cache figure is invalidated. The "~8.85 MB across 267
bodies, trivially process-resident" number assumed ~18,073 cells per body; a
viewport-sized Global is 460,800 on a 1080p display, which is 25x — about
226 MB, and roughly 900 MB on a 4K display, with per-body derive going from
~16-21 ms to about half a second. An always-keep tier whose size scales with
the user's monitor is the wrong shape, which is an independent argument for
D-258: rung 0.5 is fixed-resolution and baked, and Global becomes a view of
it rather than a canvas retained in its own right.
Also records the two retired mechanisms (the S2 station-spacing floor,
cap_extent_to_body superseded by rung liveness) and states plainly that
Global is still broken — correctly sized now, but with no hydrology until
rung 0.5 lands. Region is eyeball-confirmed working.
Pair session with Jeroen, 2026-07-26.
Co-Authored-By: Claude <noreply@anthropic.com>
Jeroen, eyeballing the lakes: "they did not seem to run the same coastline
code as ocean does". Correct, in two separate ways.
The coastline warp was ocean-only. invent_primitives displaces the sample
through coast_warp_px before reading the ocean mask, but the lake test read
the UNWARPED position, so ocean coasts got invented bays and capes while lake
shores traced the bare elevation contour. It cannot be fixed by warping the
lake sample alone: a lake is where a filled surface sits above terrain, two
reads that must agree, so moving one and not the other puts water on
hillsides or holes inside lakes. Both surfaces move together in the rung-0.5
pass, or neither does.
And shore morphology was structurally unreachable at a lake edge. Every gate
keyed on ocean_fraction_q, which is always 0 in a lake basin because lakes sit
above sea level. Ruled: lakes get full shore morphology — cliffs, beaches,
deltas. Gates key on proximity to water, not to ocean. No new vocabulary
needed; MorphologyZone already carries Fjord, Delta, Wetland, CliffCoast and
DuneStrand.
The interesting part is what separates the sea-flavoured types, because it
isn't salinity. A delta builds land outward where the river deposits faster
than the water removes; an estuary is the inverse, a drowned valley widening
seaward. The discriminator is tidal energy: the microtidal Mediterranean is
ringed with deltas (Nile, Rhone, Po) despite being salt, while the macrotidal
Atlantic gives estuaries (Thames, Severn, Gironde). So lakes always resolve to
Delta — and so does a tideless sea, which an ocean-vs-lake switch would have
got wrong. Tidal energy governs TidalFlat too, so one derived quantity
replaces two stipulations and no "is it the ocean" branch survives.
Salinity is a property of water, not a landform, and is excluded from
morphology entirely. Derive it from below-sea-level connectivity if gameplay
ever needs it. Parked.
Pair session with Jeroen, 2026-07-26.
Co-Authored-By: Claude <noreply@anthropic.com>
Every Atlas rung currently re-derives from the heightmap independently. D-258
inserts one deterministic whole-body layer between the baked inputs and the
ladder, and points every deeper rung at it instead of at the source files.
Two failures forced it. The Global rung was deriving a five-class hue map
while a per-body artefact labelled "clean color hypsometric render (display /
Atlas)" sat unused beside it. And hydrology was not derivable at all: flow is
a global solve, so no per-window derivation could produce a coherent water
system — Region carried no courses and lakes could not fill.
The record also fixes what the reliefmap IS. It is a plurality, not a
classification: each cell names the biome dominating ~38 km, a vote already
counted and discarded. So rung 0.5 un-summarises it rather than upscaling it,
which binds three consequences — biome edges are gradients never lines
(D-243's climate rule extended to biome), descending reveals composition
rather than sharpness, and invented detail must downsample back to the
summary it came from. That last one is the acceptance gate for any sub-biome
algorithm.
Rung 0.5 is a stored derived artefact and therefore a named carve-out from
D-227's derive-don't-store. The boundary is principled: D-227 governs what is
LOCALLY computable, where storage is pure cost. A whole-body flow solve is not
locally computable by construction — that is why it must exist — so storage
here buys correctness, not convenience. Everything below rung 0.5 stays
derive-don't-store.
Record precedes implementation; no code changes here. Complements the same
session's D-255 extent inversion, which governs how a canvas is sized rather
than what it is made of.
Pair session with Jeroen, 2026-07-26.
Co-Authored-By: Claude <noreply@anthropic.com>
synthetic_attractor now takes the terrain analysis and land-corrects
its pure-arithmetic position via a bounded nearest-land ring walk
(T-1116's pattern: row-major tie-break, column wrap, row clamp,
MAX_LAND_SEARCH_RING=128 sized empirically — real polar ocean bands
push nearest land up to 125 cells). Land positions pass through
UNTOUCHED — verified by direct before/after scan of all 267 real
bodies: 63 land-arithmetic placements byte-identical, and every
golden/determinism harness passes unchanged. The gap was real and
widespread: 46 of 109 synthetic-overflow placements sat in open water
at seed 42 (e.g. GJ903c at a genuine polar ocean cell); post-fix zero,
with all 109 preserved (confirmed at a second seed). Degradation is
defined and pinned: no land within the bound -> the synthetic
attractor is skipped and Phase 5's existing not-placed warning
reports it — never a panic, never a fabricated water position (the
bound never triggers on any scanned real body). 9 new unit tests;
road_graph's anchor comment and the D-210 amendment record the gap
CLOSED (validated).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The surcharge is now COASTAL_ACCESS_SURCHARGE_HOPS_PER_RING=1 added
directly to length_cells (a pure hop count) — the old cost-unit
constant div_ceil'd through MIN_CELL_COST silently produced 4 hops per
ring, worst-case +24 (double the waypoint threshold) for physically
short edges; worst case is now 6. A formula-pinning test asserts both
the arithmetic and the constant. GJ251c's repro tightened to the
documented 2 edges. The always-land citation now points at the real
guarantee (features.rs::extract_attractors, D-209) — and checking the
D-211 Phase-4 synthetic-overflow path exposed a real gap: it has no
ocean-mask guard at all (T-1206 filed); documented, not papered over.
D-210 gains a dated amendment recording the surrogate-anchor-at-cost
carve-out and the relaxation-over-nudge adjudication. The bare 100
dependency dissolved with the unit fix. Edge counts on both repro
bodies verified unchanged (reachability was never affected).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Tyre's PR #209 finding: every prior D-226 re-scope carries a dated
amendment in the record, and this vocabulary change existed only in
code comments and ticket appends. Records the drops (select_city,
open_regional — no settlement hit-test affordance post-D-255; one
screen Region..Chunk), the additions (open_atlas, jump_to_center via
the constrained jump_to seam), the summary-field reconciliation, and
the in-process-only transport narrowing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Records the T-1192 presentation ruling: the Global opener's display
ratio is viewport-fitted per body to the largest integer px/gridunit
that fits the legend-reserved viewport (floored at 1x1, letterbox
centred), texel-exact by construction; fixed rungs keep their tuned
constants. Explicitly notes that non-integer resting-state scaling
remains unsanctioned and that a PR #205 review finding removed a
fractional-fit branch which had cited this record for an exception it
does not contain — the mis-citation episode is part of the record so it
cannot recur silently.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Records the T-1174 ruling: derive(seed, absolute world metres) via the
derive_at_metres family is the only derive core; the batch 64x32
pseudo-grid is re-scoped as a survey raster with a real SurveyCellPos
newtype (role name, not a D-243 rung); derive_district_profile becomes
a thin wrapper at survey-cell-centre positions with binding basin and
riparian preservation; point-feature terrain judgments move to exact
world positions; D-255 step canvases are fenced to the window family.
LayerRegionOutput rebuild deferred to T-1181 (tripwire verified: sole
reader is the region_grid overlay); voxel carrier deferred to Phase 5.
Consults: Tyre APPROVE-WITH-CHANGES, Dudley FEASIBLE-WITH-CHANGES —
both incorporated. Discharges the T-1174 blocker on D-255's T-1181
step-canvas envelope.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Jeroen's gap catch: T-750 never stated that the seed-to-tile cascade is
also what determines the world where the player walks. Now connected in
one statement across three homes: D-012 amendment (the founding 'chunks
load/unload around the player' driver now concretely = the D-227/D-239
cascade; 3x3 chunk neighborhood minimum, coarser context self-provided by
D-255(f) function composition, Atlas interaction never a precondition,
byte-identical either way), the matching T-750 deliverable note (in
changelog), and a one-truth consumer note on Q-093 for the Phase-5 insert
minimap (design deferred, no independent map pipeline expected).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Tyre's two governance sentences on the D-226 course note: (a) the
Godot rasterizer floor makes per-class course WIDTH differentiation
inert at every shipping fit zoom — classes distinguish by opacity
alone until T-1175's per-vertex tapering; the 'trunk widest' promise
is design intent, not current pixels. (b) The pole-row edge-drain
branch is structurally unreachable; the real mechanism is interior
k<0 (revert-verification discovery). Plus the dangling cargo-fmt
reflow in the course-cost bench from the gate-bounce round.
Tickets: T-1170
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Tyre's binding ruling from the three-audit design pass (full text:
docs/architecture/river-courses-t1170.md). Keystone: the wave-1
carrier rule refines three-way — rung-independent discrete features
ride whole-body; continuous fields ride windowed per-cell arrays;
RUNG-INDEXED INVENTED DETAIL rides the windowed payload regardless of
geometric kind (courses = the coast crinkle's vector sibling; no
ceiling impact — content of the one windowed payload, not a second
query). Courses invented server-side per window on the T-1137 queue,
terminated against the window's own rung-consistent water verdict
(the two-waterline terminus fork dissolves); Region's skeleton chords
ARE the rung-truncated course. river_downstream sentinels reserve
TERMINAL for future endorheic basins. D-226 + D-227 captures added.
Tickets: T-1170, T-1168
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The drawn coastline is a family of curves indexed by rung (warp cutoff
admits more octaves at finer rungs), so no single authoritative server-
side waterline exists — reconciliation is a presentation-frame
operation at the draw site; the skeleton stays rung-independent. Clip
retires into T-1170's coast-terminating courses.
Tickets: T-1172
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
I1: _draw_attractor_shape's three stroke-width args (Confluence arc,
Coastal/NaturalHarbor arc, Oasis spokes) were raw screen-space literals
— Godot multiplies stroke widths by canvas scale exactly like radii, so
at the Region orbital fit zoom the outlines rasterized at ~0.01px, the
identical sub-pixel class the dot/ring compensation fixed, missed on
glyph internals (and attractors are Region-only — precisely where it
bites). Widths now arrive pre-compensated via a px_w param, keeping the
primitive pure. Regression pin: a source-scan test asserting no
draw_arc/draw_line in the function carries a bare numeric width (the
draw-smoke suite documents its own vacuous-pass mode, so source-scan is
the environment-independent gate); revert-verified by name. I2: D-226
visibility-direction sentence — Araminta's fade-down inversion recorded
as pre-T-1170 with its single revisit point named. I3: class-header
call-site claim corrected (enter() funnels through _enter_at_rung).
Tickets: T-1156
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rivers/basins/attractors ride the existing whole-body layer1 field —
neither AtlasLayerResponse ceiling touched, no tagged-envelope
migration. Per-rung refinement is client-side class filtering on the
additive river_class (distinct from T-1162's server-side Nyquist
cutoff: a fixed finite graph has nothing to truncate). General rule:
discrete map features ride the whole-body overlay family filtered
client-side; continuous per-metre fields ride the windowed per-cell
arrays — wave 2's roads/settlements inherit this unchanged. Riparian
vegetation response is the named T-1168 forward contract, deferred.
Tickets: T-1156
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Tyre's exact capture: the design pass's 'retire COMPOSITE_SMOOTH /
crisp draw_rect as the only path' is superseded — the const survives
as the compile-time pipeline axis, the crisp path stays as debug/
compare, and crispness-at-sparse-rungs is delivered by the per-rung
sampling-filter policy instead. T-1155's retirement framing is
cancelled (ticket closes on merge). Also records the R2 softening:
the T-1162 relief band adds sub-district elevation variance at
Quarter cutoff, so temperature no longer steps strictly at the
district there — intended, noted so nobody is surprised later.
Tickets: T-1161, T-1162
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Tyre's APPROVE items (T-1163): record the two-legal-wire-shapes-for-one-
logical-state protocol invariant (whole-response Pending AND Ready+null
district_window both mean 're-poll'; only NotFound/Error are terminal) as
a D-226 note under the T-1124 §4 amendment area, so a future server
refactor of the asymmetry must migrate every consumer in the same change.
Drop the duplicated 5-line stagger comment in atlas_window_tile_set.gd.
Follow-up tickets filed on main: T-1164 (tiled terminal-recovery),
T-1165 (queue_redraw edge root-cause), T-1166 (cold-launch test tier).
Tickets: T-1163
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
All Hoshe/Araminta findings addressed (Tyre approved outright), none
retracted — plus a Dudley stop-and-flag discovery that improved on the
asked-for fix:
- Legend 100x lie (Araminta, blocking): subtitle computed via
spacing_for_rung() and refreshed at all three _held_granularity_v2
write sites. Region test asserts 204.800 km/cell; the District
direction needed a stale-header-aware helper — a District-only test
spuriously passes against the old literal by coincidence.
- Region coalescing coverage (Hoshe 1): both directions tested
(Region-vs-District separate slots; Region-vs-Region coalesces).
- Clamp boundary tests + dangling citations (Hoshe 2): writing the
requested halving-loop-fires test surfaced that the loop is PROVABLY
UNREACHABLE at current constants (per-axis clamp forecloses it —
brute-forced independently on both server and client sides). Ruling:
the loop stays as defensive code; the test became a property sweep
pinning both the wire-cap invariant and the loop's no-op status (a
future constant change breaks it loudly); doc comments on both sides
drop the load-bearing framing and state the truth; the old client
mirror test that claimed the loop fires (passing on the per-axis
clamp alone) is replaced the same way. Client citations now name the
real server tests verbatim.
- Governance (Tyre): D-226 amendment note — progressive cross-rung
refinement EXTENDS T-1124 §4 (not supersedes); legacy u32 field
scheduled for retirement (T-1159).
Server: 1818 lib tests green, clippy/fmt clean. Client: zoom_ladder
48/48, window_request 26/26, viewer 74/74; gdlint clean. Every fix
revert-verified.
All seven Hoshe/Tyre findings addressed, none retracted:
- n-clamp/echo/staleness triangle (Tyre C1): client _clamp_window_n_mirror
(bit-for-bit twin of the server clamp, canonicalize_district_center
precedent) applied before _n is stored/sent; server test pins the
quarter n=32 -> echo 16 contract.
- min_wl band quantization (Hoshe 1/Tyre C3): quantize_min_wl_m snaps to
MIN_WL_BANDS_M {0, 32768, 16384, 8192, 4096} before cache key and echo
(design doc §5's unbounded-key fix), reusing the one true
OCTAVE_WAVELENGTHS_M array; docstrings now state the server-quantizes/
client-sends-raw split; same-band cache-sharing test.
- coalescing granularity axis (Hoshe 2): two tests pin different-
granularity requests as separate in-flight slots and same-granularity
coalescing unchanged.
- orphaned fixture (Hoshe 3): test_protocol.gd consumer decodes
atlas_response_ready_with_window.msgpack through the real IPC path and
asserts the new fields.
- atlas_window_request coverage (Hoshe 4): new test file — stale-drop on
granularity mismatch, old-server-shape defaults accepted, clamp mirror
formula + wiring. First draft's quarter-via-request_now test would have
passed for the wrong reason (request_now resets granularity by design
until T-1153) — split into formula pin + reachable-path wiring proof.
- granularity type seam (Tyre C2): field + resolver docstrings state
finer-only integer multiples with resolve_window_granularity as the
single widening point; matching contract note added to the D-226
T-1143-rulings amendment.
cargo --lib 1807/1807; goldens bit-identical; gdlint clean.
Jeroen's three rulings on the zoom-ladder design pass, recorded as a
D-226 amendment: (1) 'we set a new BHAG so old restrictions are up for
debate' — the item-(d) ceiling opens for the Atlas windowed viewport
(below-quarter rungs gated on the T-1154 measurement pass; chunk/tile
still never a whole-body planetary layer); (2) planetary rung ships as
progressive capped-density tiling on the generalized district_window
carrier; (3) planetary->regional entry becomes continuous cursor-anchored
zoom with full-zoom-out resetting to the canonical orbital frame (D-013
zoom-owns-descent restored; click-through cut superseded).
Design doc stamped with the resolved rulings. T-1143 closed. Implementation
chain: T-1149 (derive_at_metres + octave cutoff) -> T-1150 (granularity
carrier + aliasing test) / T-1151 (window par_iter) -> T-1152 (derived
planetary rung) / T-1153 (client continuous ladder) -> T-1155 (smoothing
retirement); T-1154 below-quarter measurement gate.
Jeroen's same-day corollary to the zoom-ladder condition: no zoom level
displays the authored heightmaps directly — even the orbital/planetary map
is derived output, sampled at canvas resolution (continuous field, not
fixed rasters). Kills zoom over/undersampling by construction and makes
the map viewport-adaptive. import_heightmaps survives as input storage
only; AtlasViewer's texture display path retires when the derived
planetary rung lands. T-1143 design pass extended with items (e)-(g).
Jeroen's ruling from the Groombridge/Lendel zoom-ladder captures: the BHAG
stays 'a Reach a character can travel through'; the Phase 4 exit bar now
additionally requires a continuous Atlas zoom ladder (planetary map -> tile
scale, each level deterministically derived at native granularity, never
magnified interpolation). Evidence in the record: the 16-district window is
sub-pixel vs its heightmap source at Lendel scale, so everything below fit
zoom is D-227 invented detail that must be derived, not smoothed.
CLAUDE.md Phase-4 row carries the condition; T-1143 (the ladder design
pass) appended + raised to high — it and the D-226(d) floor question are
now phase-gating.
Cover-fit: fit_window_view zooms from the viewport's LARGER dimension,
no margin factor (any factor under 1.0 leaves a long-axis gap — checked
numerically) — the composite fills edge to edge, overhanging the short
axis into pan-space; the refloat center-equality early-return already
prevents refetch churn at rest (proved, not just tested).
Input model (Jeroen: drag breaks click semantics with map objects):
LMB-drag pan REMOVED from the regional window; clicks are
object-reserved. Pan = held WASD/arrows polled in _process (delta- and
zoom-scaled, camera-pans-toward-key convention verified numerically)
plus edge-scroll within 24px of the viewport border; both suppressed
over UI and on OS focus loss; both set _user_adjusted; wheel zoom and
Esc unchanged. Reads RAW physical keycodes deliberately — independent
of the shared D-054 move_* InputMap actions bound to the same keys
(whose occlusion-leak is pre-existing and now ticketed as T-1146).
Pole wall + east-west wrap unchanged, re-driven through the new
inputs; drag tests replaced, not kept.
Smoothed composite (interim pending T-1143): per-cell colors bake into
an n x n Image/ImageTexture (exact existing colorizer incl. overlay +
ice tint) drawn once with LINEAR filtering — GPU bilinear reads as
terrain, the planetary heightmap's own treatment. Crisp per-cell path
preserved behind COMPOSITE_SMOOTH for T-1143 A/B. Rebuild only on
reference-identity change of window/toggle (is_same — verified true
reference equality; value-equal distinct dicts DO rebuild).
Governance: T-1145 amendment paragraph on D-226 T-1124 SS5 (all three
supersessions); pql decisions validate ok.
Suites: window_viewer 74/74, window_geometry 32/32, window_overlay
(new) 16/16; gdlint clean on all six files.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SS4: the 7/29ms per-window figures now state their warm-analysis
assumption — the first window on a body additionally pays one ~45ms
run_layer1 into the lazy per-body LRU on the GenerationQueue
(capacity 8, browsed-bodies-only, recency eviction, eviction re-pays);
subsequent windows any (center, n) hit the LRU. SS5: the glaciation
tint gate corrected from >= Light to >= Moderate, matching
apply_ice_tint's reference gate (Light is erosion signatures, not
visible ice) — code stood, prose was wrong.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The regional-map entry changes from zoom-threshold LOD swap to
explicit click-through: the planetary heightmap view becomes FIXED
(pan/zoom removed together with its replacement in T-1138, never
before); hovering shows a rectangle cursor representing the
regional-mode bounds; click descends centered on the click point's
derived DistrictPos. DISTRICT_WINDOW_MIN_ZOOM retired before ever
being built; D-013's zoom-owns-descent superseded for this seam only
(click owns descent). In-mode behavior unchanged (pan-only refetch,
debounce, cache, border-fade). Morph transition explicitly deferred.
Open at T-1138: the rectangle is an affordance, not to scale — n=64
is ~131 km = a few px on a planetary canvas; resolve the honest
representation in the screen design. T-1138 description updated;
T-1140 filed for the two companion UI defects fixed alongside.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
All five findings applied, none touching the option-(c) carrier choice:
(1) SS2 gains a binding windowed-family ceiling — exactly ONE
windowed-query field; a second windowed query is a dedicated response
message by rule (two concurrent windowed payloads would need the
per-field request-correlation that IS the tagged framing — that is the
trigger to build it); symmetric with the request side's five-hard cap.
(2) SS1 gains a binding serving model — window derives ride the same
Rayon queue + Pending pattern as whole-body cache misses, never inline
in the PreInput drain (which the codebase deliberately keeps expensive
work off); per-connection coalescing recommended; SS4's 7/29ms figures
reframed as worker latency, not tick-thread cost. (3) The
layer_proxy.rs growth-ceiling comment (comment-only diff) now records
the T-1124 ruling as RESOLVED — scoped to the dense whole-body family,
district_window outside it, second windowed field = dedicated-message
migration — instead of deferring to an open design question. (4) SS2
documents that body scoping rides the enclosing AtlasLayerResponse
envelope (cache key body_id+center+n; echo disambiguates within-body).
(5) SS5 entry clarified: zoom threshold alone triggers the swap
(works over open ocean), first window centers on the pan-center's
derived DistrictPos; downstream settlement-anchoring phrasing
reconciled.
pql decisions validate clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
D-227: records the two-tier driver model (body envelope from authored
params only, D-240 tilt exclusion upheld; position tier with fjord/
latitude/wetness/heterogeneity), the shared invent_primitives path,
the scatter floor-vs-ceiling reading, shoreline carving, and the
one-step-stale circularity ruling. D-239: Marine appended at
discriminant 6, morphology-derived verdict, airless precedence,
non-semantic Ord position.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Future implant apps/screens automatically extend the external app; per-app manifest bool (default true) locks out gameplay-dependent apps; in-game implant ignores the flag. Jeroen's suggested name availableInAtlasApp recorded with the rename rationale.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
F1: T-1112 amendment touch-point list gains the ZoningType PartialOrd/Ord derive (mirroring DistrictType's T-994 precedent) so the dominant_zoning declaration-order tie-break is computable. F2: stale terminal-layer doc on AtlasLayerRequest.up_to corrected to Region. F3: believability cascade_for_body bumped to Region — harness mirrors production depth, invariant documented. F4: end-to-end dispatch coverage — populated-regions test asserts regions + second handle_atlas_request returns region_grid; no-params sibling asserts regions empty. Suites: layer_proxy 10, believability 4, gen_queue 8, cascade 10.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Aggregates-only layer keyed by city_id (QuarterWorldState carries no spatial position — QuarterId is a content-addressed hash; a 512m quarter is sub-pixel at planetary projection, so no outline geometry by construction). Five quantized fields (density_avg_pct, dominant_district_type, dominant_zoning, landmark_count, corridor_count); scaled-glyph encoding anchored on the L3 settlement dot (shape=dominant type, color=density ramp); landmark/corridor counts tooltip-only per the D-226(d) aggregate-stats ceiling; five wiring touch points named for the follow-up ticket.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>