docs(meta): D-258 amended — rung 0.5 measured, storage not forced (T-1212, T-1213)
The 2026-08-06 amendment ruled: build the un-summarisation as a pure function, measure it, and open the storage question only if the numbers force it. They do not. tests/rung_cost_bench.rs (ignored, run with --release) times the real derive on Ferrath at the ladder anchor: the whole-body solve 114 ms once per body, one served canvas 118 / 141 / 175 / 175 ms at Global / Region / District / Quarter. Storage that could serve Region is ~71 GB for one body; a layer at the record's own sizing holds only Global's resolution, the rung that least needs it. The amendment also states what the conservation gate actually protects: the reliefmap D-258 names as the biome input is read by no server code, so the "summary" is the derive's own uncomposed verdict. Whether it should become an input is left for Jeroen. T-1214/T-1215 are annotated, not cancelled. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -684,3 +684,427 @@ Amended again 2026-08-20: NINE epics. T-1264 was added after a session finding t
|
||||
|
||||
DONE 2026-09-23. All eight epics closed (E1-E8). tooling/ is one package behind reach: 14 domains, 41 Blender payloads in the carve-out, provenance in tooling/archive/, nine conformance invariants in the push gate. Adoption: Skill(reach), the CLAUDE.md standing rule, and docs/diagrams/architecture/reach-cli.d2 linked from D-263. Follow-ups filed from what the ports found: T-1291 (reliefmap render drift), T-1292 (the destructive wiki renderer), T-1294 (frozen S-keyed star-map diagrams).', NULL, '2026-09-23 18:21:58', '2026-09-23 18:21:58.287', '2026-09-23 18:21:58.287', NULL, '1764f4e010e67cb55b49398a9ffb42af', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06G1S37Y1ARMV68RJT802Z3VPG', 'status', 'in_progress', 'done', NULL, '2026-09-23 18:21:58', '2026-09-23 18:21:58.799', '2026-09-23 18:21:58.799', NULL, '7f4b87f4397a8ea322f299199f144b59', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FT0TZC9MJV6KZTSRVRYQ327M', 'description', 'Build the deterministic expansion from rung 0 (heightmap.png 1024x512 16-bit elevation + reliefmap.png 1024x512 colour biome) to rung 0.5, sized per D-258''s 2-px-per-gridunit-at-large-display rule. Same body + same seed must produce the same layer every time (byte-identical, per D-227''s determinism discipline extended by this carve-out). The reliefmap is a PLURALITY, not ground truth: each reliefmap cell already voted-and-discarded the dominant biome across ~38 km of ground, so this generator un-summarises it -- it does not upscale/interpolate it. Three binding invariants from D-258: (1) biome edges are gradients, never lines -- transitions blend so no boundary falls on a rung-0 cell edge (the D-243 climate edge-fuzz rule applied to biome); (2) descending the ladder reveals COMPOSITION not sharpness -- a cell reading ''forest'' globally must be able to contain clearings/marsh/rock/scrub the vote suppressed, emerging deterministically as the ladder descends; (3) CONSERVATIVE invention is the binding acceptance gate -- downsampling rung 0.5 must reproduce the rung-0 summary it came from (a forest cell may gain marsh pockets but must still read as forest from orbit). Blocked on T-1212 (cost/size measurement) landing first. Depends on: nothing else in this epic to start scaffolding, but hydrology (sibling ticket) and this generator are tightly coupled -- coordinate sequencing with whoever picks up hydrology. See governance/decisions/architecture.md#d-258.
|
||||
|
||||
---
|
||||
UNBLOCKED 2026-08-06 (T-1211 re-scope, Jeroen''s call). The T-1212 blocker edge is
|
||||
removed: that measurement priced a hydrology move that is not happening, and the
|
||||
descent ladder showed there is no expansion artefact to measure yet anyway.
|
||||
|
||||
BUILD IT AS A PURE FUNCTION FIRST, not as a stored layer. The stored-layer half of
|
||||
D-258 was materially weakened by its own 2026-07-27 amendment (the "not locally
|
||||
computable" argument for the D-227 carve-out does not hold, because the whole-body
|
||||
solve it cited already runs once per body in layer1.rs and is sampled at every
|
||||
rung). So follow the mechanism that exists — D-255(f) mechanism B,
|
||||
compute-once-sample-everywhere — measure it, and only argue for storage on those
|
||||
numbers. Do NOT open with a cache.
|
||||
|
||||
WHAT "FLAT" MEANS CONCRETELY, so the fix has a target. Ferrath''s heightmap is
|
||||
1024x512 over a 38,089 km circumference: 37.2 km per source pixel. Global draws at
|
||||
35.267 km/gridunit, roughly 1:1 with the source, and reads as a real map. Region
|
||||
draws at 0.379 km/gridunit — 98x finer than any stored datum — and is a single
|
||||
uniform colour with dither. District is 0.0038 km/gridunit, ~9,800x finer, also
|
||||
uniform. So the acceptance bar is not subtle: at Region, ~98 gridunits across a
|
||||
single source pixel must carry visible, deterministic, non-repeating composition
|
||||
that still downsamples back to that pixel''s summary (D-258''s conservation
|
||||
invariant, the binding gate).
|
||||
|
||||
VERIFY BY CAPTURE, NOT BY REASONING. The scenarios exist: atlas_GJ820Bc_land_*
|
||||
(Region/District/Quarter/Block/Chunk, one land-anchored world point, no overlays)
|
||||
in tests/visual.json. Captures run offscreen under gamescope at native 3440x1440
|
||||
via tests/run-visual --screenshot <name> — they do not steal the desktop. Re-shoot
|
||||
the ladder and look at it; a green unit test proves nothing here.
|
||||
|
||||
Note the ladder currently also reports courses=0 at every rung below Global —
|
||||
rivers vanish on descent. That is tracked separately as T-1239 and is NOT this
|
||||
ticket''s scope, but it will be visible in the same captures, so do not mistake it
|
||||
for a failure of the un-summarisation work.
|
||||
|
||||
---
|
||||
LADDER RE-SHOT COLD 2026-08-16 — the first ladder whose numbers can be trusted.
|
||||
Every previous ladder, including the one this ticket''s re-scope was written from,
|
||||
was captured against the developer''s persistent user:// cache (T-1239). The
|
||||
harness now isolates user:// per capture, so these are fresh derives.
|
||||
|
||||
RESULT: the acceptance bar is NOT met. Region and below are still flat.
|
||||
|
||||
Flatness, measured rather than eyeballed (.cache/t1213_flatness.py samples the
|
||||
terrain area, excluding the panels):
|
||||
|
||||
rung distinct R std G std B std lum p1-p99
|
||||
Global 1581 24.05 35.75 36.21 145.69
|
||||
Region 2923 4.80 8.31 4.19 33.59
|
||||
District 53 2.56 4.90 2.56 13.72
|
||||
Quarter 46 2.42 4.78 2.42 11.01
|
||||
|
||||
Note Region carries MORE distinct colours than Global (2923 vs 1581) while
|
||||
holding a quarter of the structure. That is the dither/stipple pass adding colour
|
||||
noise, not information — so distinct-count is precisely the wrong metric, and the
|
||||
percentile luminance spread is the honest one. Structure falls ~92% from Global
|
||||
to Quarter.
|
||||
|
||||
WHY IT IS FLAT — a channel mismatch, not a missing generator.
|
||||
|
||||
Composition IS working in the data. The conservation test, run explicitly against
|
||||
real terrain, reports over a 2,048 m patch at the ladder''s own anchor:
|
||||
|
||||
conservation: majority class 3 at 98.9% across 2 classes {1: 175, 3: 16209}
|
||||
|
||||
So D-258 invariant 3 (conservation) holds and invariant 2 (composition) is
|
||||
happening: 1.07% of the patch is a minority class.
|
||||
|
||||
But composition perturbs `moisture_q` and `slope_q`, which resolve into
|
||||
`vegetation_class`. The base map draws neither. step_canvas_colorize.gd''s own
|
||||
comment states it: "The base layer reads hue from morphology and lightness from
|
||||
elev_q, and on a real body below Global that collapses: morphology resolves to
|
||||
ONE zone". The ladder scenarios pass `[]` for overlays deliberately
|
||||
(visual_scenarios.gd: "No overlays, deliberately: a colour ramp on top would mask
|
||||
the very thing being judged"), so the composed fields are never rendered in the
|
||||
shots that judge this work.
|
||||
|
||||
The un-summarisation lands in channels the default view does not draw. That is
|
||||
why perfectly correct composition and a flat map coexist.
|
||||
|
||||
THE CONSERVATION TEST WAS NOT PROTECTING ANYTHING (fixed here).
|
||||
|
||||
Its "not a monoculture" assertion read:
|
||||
|
||||
assert!(tally.len() > 1 || share == 1.0, ...)
|
||||
|
||||
which is a TAUTOLOGY — a single-class tally has a 100% share by definition, so
|
||||
both branches are always satisfiable and the check could never fail, including in
|
||||
the exact case its message names ("or nothing was composed"). It was the only
|
||||
thing standing behind invariant 2, and it stood behind nothing. Now split into
|
||||
the two bounds the invariant actually has: majority > 50% (conservation, the
|
||||
ceiling on invention) and minority >= 0.1% (composition, the floor). Measured
|
||||
1.07% against a 0.1% floor.
|
||||
|
||||
It is also still `#[ignore]`d, so the binding acceptance gate for this epic runs
|
||||
only when someone types it. Worth moving into a harness that runs — the
|
||||
believability and window-derivation harnesses already load real bodies in the
|
||||
normal `cargo test` path, so the precedent exists.
|
||||
|
||||
courses=0 BELOW GLOBAL IS NOT A BUG — it is arithmetic, and the ticket''s note
|
||||
attributing it to T-1239 is superseded. Global now reports courses=73 drawn=18
|
||||
(T-1239 fixed). Region/District/Quarter report courses=0 because the hydrology
|
||||
network is 615 river cells on a 512x256 grid (74.4 km/cell) and a Region window
|
||||
is 489 x 205 km = 0.0217% of a 462M km2 body: expected river cells in view = 615
|
||||
x 0.000217 = 0.13. Zero is the likely outcome, not a failure. The real
|
||||
observation underneath it is that 615 river cells on an Earth-sized body is a
|
||||
sparse network (~45,000 km of total watercourse), which is a believability
|
||||
question for hydrology, not a rendering one.
|
||||
|
||||
THE OPEN DECISION — three readings, materially different work:
|
||||
|
||||
(A) Make the DISPLAYED channels carry sub-source-pixel composition. The literal
|
||||
reading of this ticket''s acceptance bar ("at Region, ~98 gridunits across a
|
||||
single source pixel must carry visible, deterministic, non-repeating
|
||||
composition"). Means morphology and/or elev_q gain a fine tier, which is
|
||||
D-227/D-258 territory and the largest change.
|
||||
(B) Accept that the base view is morphology + elevation, and judge composition
|
||||
through the overlays — i.e. the ladder gains VEG/MST companion shots. Test
|
||||
change only, but it concedes that the default map stays flat below Global.
|
||||
(C) Raise inclusion density so the existing vegetation texture reads at map
|
||||
scale. Tuning only; 1.07% is near-invisible.
|
||||
|
||||
Not chosen here — it needs Jeroen''s call, and it touches D-258.
|
||||
|
||||
---
|
||||
FIXED 2026-08-16 (option A). The un-summarisation was reaching the wire and
|
||||
falling off it one line before the renderer.
|
||||
|
||||
ROOT CAUSE: `step_canvas_protocol.gd`''s decode dictionary listed every dense
|
||||
plane EXCEPT relief_q. The server has encoded it since 5eb394b36
|
||||
(step_canvas.rs:1234) and the terrain layer has asked for it by name ever since
|
||||
(`canvas.get("relief_q")`), but the key was never put in the decoded dictionary,
|
||||
so the plane arrived nowhere. The server half of relief_q landed; the protocol
|
||||
half did not.
|
||||
|
||||
That is why the deep rungs were flat. relief_q is the ONE field with signal below
|
||||
District — elev_q''s 80 m steps quantise sub-district detail away — and it was
|
||||
absent. Measured plane variety at District, before: {morphology: 1, elev_q: 11,
|
||||
relief_q: 0, moisture_q: 25, vegetation: 3}. A 0 there means ABSENT, not merely
|
||||
constant; the distinction is what made this diagnosable, and it did not exist
|
||||
until this session added the plane-variety readout.
|
||||
|
||||
TWO CHANGES:
|
||||
1. Decode relief_q (one line, client/scripts/protocol/step_canvas_protocol.gd).
|
||||
2. Shade with it, SIGNED and continuously (step_canvas_colorize.gd). It was
|
||||
previously spent only as a stipple PROBABILITY, so a ridge and a plain
|
||||
differed in dot density, which at one pixel per cell reads as noise rather
|
||||
than landform — and `_ruggedness()` took absf(relief_q - 50), discarding the
|
||||
sign the server deliberately preserved ("a hollow and a rise are different
|
||||
ground"). Rises now lighten, hollows darken, under the stipple rather than
|
||||
instead of it.
|
||||
|
||||
LADDER, before -> after (tooling/atlas-flatness, lum p1-p99):
|
||||
|
||||
Global 145.69 -> 145.69 unchanged, and correct: relief_q is flat 50 at
|
||||
orbital rungs by construction
|
||||
Region 33.59 -> 71.01 2.1x
|
||||
District 13.72 -> 77.01 5.6x
|
||||
Quarter 11.01 -> 42.56 3.9x
|
||||
|
||||
Structure retention Global->Quarter went from 7.6% to 29%. Plane variety after:
|
||||
Region relief_q 101 values, District 91, Quarter 33.
|
||||
|
||||
HONEST STATE. The acceptance bar ("at Region, ~98 gridunits across a single
|
||||
source pixel must carry visible, deterministic, non-repeating composition") is
|
||||
MET. It is not yet cartographically finished: Region reads as heavy speckle
|
||||
because ruggedness is now real data rather than an elev_q-gradient fallback, so
|
||||
far more cells earn a stipple mark than the T-1194 tuning assumed (17,599
|
||||
distinct colours there). District reads as soft blobby relief — form without
|
||||
directionality, since the field is isotropic noise with no hillshade direction
|
||||
and no drainage alignment. Both are tuning/grammar follow-ups on top of a channel
|
||||
that now carries signal, not blockers.
|
||||
|
||||
REGRESSION COVER ADDED. Every protocol test passed throughout the weeks the plane
|
||||
was missing, because each asserted a field it already knew about and none
|
||||
asserted the SET. There is now a test that walks all eight dense planes of
|
||||
EncodedStepCanvas and fails if any is absent from the decode — verified by
|
||||
disabling the fix and watching it fail by name.', 'Build the deterministic expansion from rung 0 (heightmap.png 1024x512 16-bit elevation + reliefmap.png 1024x512 colour biome) to rung 0.5, sized per D-258''s 2-px-per-gridunit-at-large-display rule. Same body + same seed must produce the same layer every time (byte-identical, per D-227''s determinism discipline extended by this carve-out). The reliefmap is a PLURALITY, not ground truth: each reliefmap cell already voted-and-discarded the dominant biome across ~38 km of ground, so this generator un-summarises it -- it does not upscale/interpolate it. Three binding invariants from D-258: (1) biome edges are gradients, never lines -- transitions blend so no boundary falls on a rung-0 cell edge (the D-243 climate edge-fuzz rule applied to biome); (2) descending the ladder reveals COMPOSITION not sharpness -- a cell reading ''forest'' globally must be able to contain clearings/marsh/rock/scrub the vote suppressed, emerging deterministically as the ladder descends; (3) CONSERVATIVE invention is the binding acceptance gate -- downsampling rung 0.5 must reproduce the rung-0 summary it came from (a forest cell may gain marsh pockets but must still read as forest from orbit). Blocked on T-1212 (cost/size measurement) landing first. Depends on: nothing else in this epic to start scaffolding, but hydrology (sibling ticket) and this generator are tightly coupled -- coordinate sequencing with whoever picks up hydrology. See governance/decisions/architecture.md#d-258.
|
||||
|
||||
---
|
||||
UNBLOCKED 2026-08-06 (T-1211 re-scope, Jeroen''s call). The T-1212 blocker edge is
|
||||
removed: that measurement priced a hydrology move that is not happening, and the
|
||||
descent ladder showed there is no expansion artefact to measure yet anyway.
|
||||
|
||||
BUILD IT AS A PURE FUNCTION FIRST, not as a stored layer. The stored-layer half of
|
||||
D-258 was materially weakened by its own 2026-07-27 amendment (the "not locally
|
||||
computable" argument for the D-227 carve-out does not hold, because the whole-body
|
||||
solve it cited already runs once per body in layer1.rs and is sampled at every
|
||||
rung). So follow the mechanism that exists — D-255(f) mechanism B,
|
||||
compute-once-sample-everywhere — measure it, and only argue for storage on those
|
||||
numbers. Do NOT open with a cache.
|
||||
|
||||
WHAT "FLAT" MEANS CONCRETELY, so the fix has a target. Ferrath''s heightmap is
|
||||
1024x512 over a 38,089 km circumference: 37.2 km per source pixel. Global draws at
|
||||
35.267 km/gridunit, roughly 1:1 with the source, and reads as a real map. Region
|
||||
draws at 0.379 km/gridunit — 98x finer than any stored datum — and is a single
|
||||
uniform colour with dither. District is 0.0038 km/gridunit, ~9,800x finer, also
|
||||
uniform. So the acceptance bar is not subtle: at Region, ~98 gridunits across a
|
||||
single source pixel must carry visible, deterministic, non-repeating composition
|
||||
that still downsamples back to that pixel''s summary (D-258''s conservation
|
||||
invariant, the binding gate).
|
||||
|
||||
VERIFY BY CAPTURE, NOT BY REASONING. The scenarios exist: atlas_GJ820Bc_land_*
|
||||
(Region/District/Quarter/Block/Chunk, one land-anchored world point, no overlays)
|
||||
in tests/visual.json. Captures run offscreen under gamescope at native 3440x1440
|
||||
via tests/run-visual --screenshot <name> — they do not steal the desktop. Re-shoot
|
||||
the ladder and look at it; a green unit test proves nothing here.
|
||||
|
||||
Note the ladder currently also reports courses=0 at every rung below Global —
|
||||
rivers vanish on descent. That is tracked separately as T-1239 and is NOT this
|
||||
ticket''s scope, but it will be visible in the same captures, so do not mistake it
|
||||
for a failure of the un-summarisation work.
|
||||
|
||||
---
|
||||
LADDER RE-SHOT COLD 2026-08-16 — the first ladder whose numbers can be trusted.
|
||||
Every previous ladder, including the one this ticket''s re-scope was written from,
|
||||
was captured against the developer''s persistent user:// cache (T-1239). The
|
||||
harness now isolates user:// per capture, so these are fresh derives.
|
||||
|
||||
RESULT: the acceptance bar is NOT met. Region and below are still flat.
|
||||
|
||||
Flatness, measured rather than eyeballed (.cache/t1213_flatness.py samples the
|
||||
terrain area, excluding the panels):
|
||||
|
||||
rung distinct R std G std B std lum p1-p99
|
||||
Global 1581 24.05 35.75 36.21 145.69
|
||||
Region 2923 4.80 8.31 4.19 33.59
|
||||
District 53 2.56 4.90 2.56 13.72
|
||||
Quarter 46 2.42 4.78 2.42 11.01
|
||||
|
||||
Note Region carries MORE distinct colours than Global (2923 vs 1581) while
|
||||
holding a quarter of the structure. That is the dither/stipple pass adding colour
|
||||
noise, not information — so distinct-count is precisely the wrong metric, and the
|
||||
percentile luminance spread is the honest one. Structure falls ~92% from Global
|
||||
to Quarter.
|
||||
|
||||
WHY IT IS FLAT — a channel mismatch, not a missing generator.
|
||||
|
||||
Composition IS working in the data. The conservation test, run explicitly against
|
||||
real terrain, reports over a 2,048 m patch at the ladder''s own anchor:
|
||||
|
||||
conservation: majority class 3 at 98.9% across 2 classes {1: 175, 3: 16209}
|
||||
|
||||
So D-258 invariant 3 (conservation) holds and invariant 2 (composition) is
|
||||
happening: 1.07% of the patch is a minority class.
|
||||
|
||||
But composition perturbs `moisture_q` and `slope_q`, which resolve into
|
||||
`vegetation_class`. The base map draws neither. step_canvas_colorize.gd''s own
|
||||
comment states it: "The base layer reads hue from morphology and lightness from
|
||||
elev_q, and on a real body below Global that collapses: morphology resolves to
|
||||
ONE zone". The ladder scenarios pass `[]` for overlays deliberately
|
||||
(visual_scenarios.gd: "No overlays, deliberately: a colour ramp on top would mask
|
||||
the very thing being judged"), so the composed fields are never rendered in the
|
||||
shots that judge this work.
|
||||
|
||||
The un-summarisation lands in channels the default view does not draw. That is
|
||||
why perfectly correct composition and a flat map coexist.
|
||||
|
||||
THE CONSERVATION TEST WAS NOT PROTECTING ANYTHING (fixed here).
|
||||
|
||||
Its "not a monoculture" assertion read:
|
||||
|
||||
assert!(tally.len() > 1 || share == 1.0, ...)
|
||||
|
||||
which is a TAUTOLOGY — a single-class tally has a 100% share by definition, so
|
||||
both branches are always satisfiable and the check could never fail, including in
|
||||
the exact case its message names ("or nothing was composed"). It was the only
|
||||
thing standing behind invariant 2, and it stood behind nothing. Now split into
|
||||
the two bounds the invariant actually has: majority > 50% (conservation, the
|
||||
ceiling on invention) and minority >= 0.1% (composition, the floor). Measured
|
||||
1.07% against a 0.1% floor.
|
||||
|
||||
It is also still `#[ignore]`d, so the binding acceptance gate for this epic runs
|
||||
only when someone types it. Worth moving into a harness that runs — the
|
||||
believability and window-derivation harnesses already load real bodies in the
|
||||
normal `cargo test` path, so the precedent exists.
|
||||
|
||||
courses=0 BELOW GLOBAL IS NOT A BUG — it is arithmetic, and the ticket''s note
|
||||
attributing it to T-1239 is superseded. Global now reports courses=73 drawn=18
|
||||
(T-1239 fixed). Region/District/Quarter report courses=0 because the hydrology
|
||||
network is 615 river cells on a 512x256 grid (74.4 km/cell) and a Region window
|
||||
is 489 x 205 km = 0.0217% of a 462M km2 body: expected river cells in view = 615
|
||||
x 0.000217 = 0.13. Zero is the likely outcome, not a failure. The real
|
||||
observation underneath it is that 615 river cells on an Earth-sized body is a
|
||||
sparse network (~45,000 km of total watercourse), which is a believability
|
||||
question for hydrology, not a rendering one.
|
||||
|
||||
THE OPEN DECISION — three readings, materially different work:
|
||||
|
||||
(A) Make the DISPLAYED channels carry sub-source-pixel composition. The literal
|
||||
reading of this ticket''s acceptance bar ("at Region, ~98 gridunits across a
|
||||
single source pixel must carry visible, deterministic, non-repeating
|
||||
composition"). Means morphology and/or elev_q gain a fine tier, which is
|
||||
D-227/D-258 territory and the largest change.
|
||||
(B) Accept that the base view is morphology + elevation, and judge composition
|
||||
through the overlays — i.e. the ladder gains VEG/MST companion shots. Test
|
||||
change only, but it concedes that the default map stays flat below Global.
|
||||
(C) Raise inclusion density so the existing vegetation texture reads at map
|
||||
scale. Tuning only; 1.07% is near-invisible.
|
||||
|
||||
Not chosen here — it needs Jeroen''s call, and it touches D-258.
|
||||
|
||||
---
|
||||
FIXED 2026-08-16 (option A). The un-summarisation was reaching the wire and
|
||||
falling off it one line before the renderer.
|
||||
|
||||
ROOT CAUSE: `step_canvas_protocol.gd`''s decode dictionary listed every dense
|
||||
plane EXCEPT relief_q. The server has encoded it since 5eb394b36
|
||||
(step_canvas.rs:1234) and the terrain layer has asked for it by name ever since
|
||||
(`canvas.get("relief_q")`), but the key was never put in the decoded dictionary,
|
||||
so the plane arrived nowhere. The server half of relief_q landed; the protocol
|
||||
half did not.
|
||||
|
||||
That is why the deep rungs were flat. relief_q is the ONE field with signal below
|
||||
District — elev_q''s 80 m steps quantise sub-district detail away — and it was
|
||||
absent. Measured plane variety at District, before: {morphology: 1, elev_q: 11,
|
||||
relief_q: 0, moisture_q: 25, vegetation: 3}. A 0 there means ABSENT, not merely
|
||||
constant; the distinction is what made this diagnosable, and it did not exist
|
||||
until this session added the plane-variety readout.
|
||||
|
||||
TWO CHANGES:
|
||||
1. Decode relief_q (one line, client/scripts/protocol/step_canvas_protocol.gd).
|
||||
2. Shade with it, SIGNED and continuously (step_canvas_colorize.gd). It was
|
||||
previously spent only as a stipple PROBABILITY, so a ridge and a plain
|
||||
differed in dot density, which at one pixel per cell reads as noise rather
|
||||
than landform — and `_ruggedness()` took absf(relief_q - 50), discarding the
|
||||
sign the server deliberately preserved ("a hollow and a rise are different
|
||||
ground"). Rises now lighten, hollows darken, under the stipple rather than
|
||||
instead of it.
|
||||
|
||||
LADDER, before -> after (tooling/atlas-flatness, lum p1-p99):
|
||||
|
||||
Global 145.69 -> 145.69 unchanged, and correct: relief_q is flat 50 at
|
||||
orbital rungs by construction
|
||||
Region 33.59 -> 71.01 2.1x
|
||||
District 13.72 -> 77.01 5.6x
|
||||
Quarter 11.01 -> 42.56 3.9x
|
||||
|
||||
Structure retention Global->Quarter went from 7.6% to 29%. Plane variety after:
|
||||
Region relief_q 101 values, District 91, Quarter 33.
|
||||
|
||||
HONEST STATE. The acceptance bar ("at Region, ~98 gridunits across a single
|
||||
source pixel must carry visible, deterministic, non-repeating composition") is
|
||||
MET. It is not yet cartographically finished: Region reads as heavy speckle
|
||||
because ruggedness is now real data rather than an elev_q-gradient fallback, so
|
||||
far more cells earn a stipple mark than the T-1194 tuning assumed (17,599
|
||||
distinct colours there). District reads as soft blobby relief — form without
|
||||
directionality, since the field is isotropic noise with no hillshade direction
|
||||
and no drainage alignment. Both are tuning/grammar follow-ups on top of a channel
|
||||
that now carries signal, not blockers.
|
||||
|
||||
REGRESSION COVER ADDED. Every protocol test passed throughout the weeks the plane
|
||||
was missing, because each asserted a field it already knew about and none
|
||||
asserted the SET. There is now a test that walks all eight dense planes of
|
||||
EncodedStepCanvas and fails if any is absent from the decode — verified by
|
||||
disabling the fix and watching it fail by name.
|
||||
|
||||
DONE 2026-09-24.
|
||||
|
||||
Acceptance bar met and verified by capture: the fresh ladder (first since T-1240) reads as terrain at every rung. lum p1-p99, flat -> now: Region 33.59 -> 63.60, District 13.72 -> 84.15, Quarter 11.01 -> 76.58.
|
||||
|
||||
Found and fixed on that ladder (commit 6b50829d6):
|
||||
- A straight diagonal seam of blocky stair-steps across Region. Traced by dumping the canvas planes: it lived in relief_q, caused by the coast/terrain character reading the CATEGORICAL glaciation grade (fjord weight jumping 0 -> 0.30 on the None/Light isotherm). The character now reads a continuous glacial_weight. Invariant (1), "edges are gradients, never lines".
|
||||
- Aliased ValleyFloor speckle at Region: composition''s 192 m inclusions ignored the rung''s octave cutoff. Now gated. ValleyFloor at Region 8,453 -> 0 cells, distinct colours 26,701 -> 2,102, structure unchanged.
|
||||
|
||||
The conservation gate (invariant 3) now RUNS in plain cargo test, and now actually compares: it derives 13 patches across Ferrath with and without composition, and the composed plurality must equal the uncomposed one. It had been #[ignore]d, and derived only once. Mutation-proven both ways.
|
||||
|
||||
T-1212''s measurement is carried here (tests/rung_cost_bench.rs): the whole-body solve takes 114 ms; a canvas takes 118-175 ms wall at every rung. A stored layer at Region pitch would be ~71 GB per body. Storage is not forced. Recorded as the 2026-09-24 D-258 amendment.
|
||||
|
||||
Left open for Jeroen, in that amendment: the reliefmap is still not read by any server code, so the "summary" being conserved is the derive''s own verdict. Should it become an input at all, given it is a render of the same heightmap?', NULL, '2026-09-24 20:44:25', '2026-09-24 20:44:25.427', '2026-09-24 20:44:25.427', NULL, '77d7a61e9f2cfaef332f7f6e4b8eace3', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FT0TYBD74TQNVKTJMKA8D9KM', 'description', 'MUST run and be reviewed before any other T-1211 child starts -- this measurement could reshape the rung-0.5 design, per the pair session''s explicit sequencing note. Measure, at minimum: (1) per-body derive cost for the expanded layer at a resolution sized so a whole body draws at 2 screen px per gridunit on a large display (the D-258 sizing rule) -- both single-body cold-derive time and the full ~271-body population sum; (2) per-body and total disk footprint if the layer is cached/stored (rung 0.5 is a named D-227 carve-out -- storage is deliberate, but its size must be known, not assumed); (3) whole-body hydrology solve cost on this layer (drainage + course routing + lake fill) at the same resolution, since D-258 requires this to run exactly once per body and nowhere else. Reference point: D-255''s own rung-0 always-keep tier estimate went from ~8.85 MB (measured against a stale ~18K-cell/body figure) to an estimated 226 MB (1080p) / ~900 MB (4K) once the extent inversion made Global viewport-sized -- D-255 amendment item 6 explicitly says ''re-measure against rung 0.5, not against this record.'' This ticket is that re-measurement. Report back to the team before T-1211''s other children are started; if the numbers are structurally bad (e.g. rung 0.5 at the sizing D-258 specifies costs an order of magnitude more than the old rung-0 model), that is grounds to revisit the resolution target with Jeroen before writing generator code. See governance/decisions/architecture.md#d-258 (rationale + Implementation note).
|
||||
|
||||
SCOPE INVALIDATED 2026-07-27 (see T-1211 and the D-258 amendment). This ticket was written to measure the cost of moving a whole-body hydrology solve onto rung 0.5. That solve does not need to move -- it already runs once per body in layer1.rs and is sampled fresh at every rung. Do NOT run this measurement as written; it would price work that is not required. If a measurement is still wanted after T-1211 is re-scoped, the question is narrower: what does BIOME un-summarisation cost, and does it need storing at all.
|
||||
|
||||
---
|
||||
RETIRED AS A GATE 2026-08-06. This no longer blocks T-1213 or the T-1211 epic.
|
||||
|
||||
It was already SCOPE INVALIDATED (2026-07-27) for pricing a hydrology move that
|
||||
does not need to happen. The 2026-08-06 descent ladder (see T-1211) closes the
|
||||
remaining reason to keep it as a gate: every rung below Global renders a flat
|
||||
wash, so biome un-summarisation is not happening at all. There is no artefact
|
||||
whose cost or disk footprint can be measured, because none is produced.
|
||||
|
||||
The measurement question survives, but it is now DOWNSTREAM of T-1213 rather
|
||||
than upstream of it: once the un-summarisation exists as a pure function, measure
|
||||
THAT, and only then decide whether a stored layer is warranted. Re-scope this
|
||||
ticket to that measurement when T-1213 lands, or close it and let T-1213 carry
|
||||
its own measurement step.', 'MUST run and be reviewed before any other T-1211 child starts -- this measurement could reshape the rung-0.5 design, per the pair session''s explicit sequencing note. Measure, at minimum: (1) per-body derive cost for the expanded layer at a resolution sized so a whole body draws at 2 screen px per gridunit on a large display (the D-258 sizing rule) -- both single-body cold-derive time and the full ~271-body population sum; (2) per-body and total disk footprint if the layer is cached/stored (rung 0.5 is a named D-227 carve-out -- storage is deliberate, but its size must be known, not assumed); (3) whole-body hydrology solve cost on this layer (drainage + course routing + lake fill) at the same resolution, since D-258 requires this to run exactly once per body and nowhere else. Reference point: D-255''s own rung-0 always-keep tier estimate went from ~8.85 MB (measured against a stale ~18K-cell/body figure) to an estimated 226 MB (1080p) / ~900 MB (4K) once the extent inversion made Global viewport-sized -- D-255 amendment item 6 explicitly says ''re-measure against rung 0.5, not against this record.'' This ticket is that re-measurement. Report back to the team before T-1211''s other children are started; if the numbers are structurally bad (e.g. rung 0.5 at the sizing D-258 specifies costs an order of magnitude more than the old rung-0 model), that is grounds to revisit the resolution target with Jeroen before writing generator code. See governance/decisions/architecture.md#d-258 (rationale + Implementation note).
|
||||
|
||||
SCOPE INVALIDATED 2026-07-27 (see T-1211 and the D-258 amendment). This ticket was written to measure the cost of moving a whole-body hydrology solve onto rung 0.5. That solve does not need to move -- it already runs once per body in layer1.rs and is sampled fresh at every rung. Do NOT run this measurement as written; it would price work that is not required. If a measurement is still wanted after T-1211 is re-scoped, the question is narrower: what does BIOME un-summarisation cost, and does it need storing at all.
|
||||
|
||||
---
|
||||
RETIRED AS A GATE 2026-08-06. This no longer blocks T-1213 or the T-1211 epic.
|
||||
|
||||
It was already SCOPE INVALIDATED (2026-07-27) for pricing a hydrology move that
|
||||
does not need to happen. The 2026-08-06 descent ladder (see T-1211) closes the
|
||||
remaining reason to keep it as a gate: every rung below Global renders a flat
|
||||
wash, so biome un-summarisation is not happening at all. There is no artefact
|
||||
whose cost or disk footprint can be measured, because none is produced.
|
||||
|
||||
The measurement question survives, but it is now DOWNSTREAM of T-1213 rather
|
||||
than upstream of it: once the un-summarisation exists as a pure function, measure
|
||||
THAT, and only then decide whether a stored layer is warranted. Re-scope this
|
||||
ticket to that measurement when T-1213 lands, or close it and let T-1213 carry
|
||||
its own measurement step.
|
||||
|
||||
DONE 2026-09-24 — measured inside T-1213, as the 2026-08-06 note allowed.
|
||||
|
||||
Measured with tests/rung_cost_bench.rs (release, 16 cores, Ferrath at the ladder anchor, 1290x540):
|
||||
- whole-body solve: 114 ms, once per body
|
||||
- one canvas: Global 118 ms, Region 141 ms, District 175 ms, Quarter 175 ms (wall)
|
||||
|
||||
A stored layer at Region pitch would be ~5.05e9 cells, about 71 GB per body; District is 10^4x more. A layer at D-258''s own sizing can serve only Global, which already derives in 118 ms.
|
||||
|
||||
Storage is not forced. See the D-258 amendment of 2026-09-24.', NULL, '2026-09-24 20:44:25', '2026-09-24 20:44:25.937', '2026-09-24 20:44:25.937', NULL, 'db81891e2ee521e494207711a25a7364', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FT0V04XYBWC93Q1QTETMSQE8', 'description', 'Move hydrology resolution so it runs exactly ONCE per body, on the rung-0.5 layer, and nowhere else. D-258''s structural rationale: drainage/course-routing/lake-fill are whole-body computations (water arrives from upstream and leaves downstream, both off-screen at every rung below Global), so no per-window derivation at Region/District/Quarter/Block/Chunk can produce a coherent water system -- this is why Region currently carries no courses and lakes cannot fill under the old per-rung-independent model. Cross-rung agreement (the coastline zoomed out is the coastline zoomed in; a river crossing a district reaches the sea on the global map) must hold BY CONSTRUCTION once every rung sources from this one solved layer, not by policing two derivation paths against each other. Contradiction to fix in the same pass: Global currently still rides uses_orbital_derive()==true and the orbital path skips the course/water pass entirely (confirmed live in the pair session) -- that is why Global reads flat at any resolution today; this is not a tuning gap, it is a missing pass, and this ticket is what closes it. Blocked on T-1212 (measurement) and coordinates tightly with the expanded-layer generator sibling ticket. See governance/decisions/architecture.md#d-258 and #d-255 (amendment item 3, ''Region carrying no rivers at all was much of why the top of the ladder read flat'').', 'Move hydrology resolution so it runs exactly ONCE per body, on the rung-0.5 layer, and nowhere else. D-258''s structural rationale: drainage/course-routing/lake-fill are whole-body computations (water arrives from upstream and leaves downstream, both off-screen at every rung below Global), so no per-window derivation at Region/District/Quarter/Block/Chunk can produce a coherent water system -- this is why Region currently carries no courses and lakes cannot fill under the old per-rung-independent model. Cross-rung agreement (the coastline zoomed out is the coastline zoomed in; a river crossing a district reaches the sea on the global map) must hold BY CONSTRUCTION once every rung sources from this one solved layer, not by policing two derivation paths against each other. Contradiction to fix in the same pass: Global currently still rides uses_orbital_derive()==true and the orbital path skips the course/water pass entirely (confirmed live in the pair session) -- that is why Global reads flat at any resolution today; this is not a tuning gap, it is a missing pass, and this ticket is what closes it. Blocked on T-1212 (measurement) and coordinates tightly with the expanded-layer generator sibling ticket. See governance/decisions/architecture.md#d-258 and #d-255 (amendment item 3, ''Region carrying no rivers at all was much of why the top of the ladder read flat'').
|
||||
|
||||
PREMISE GONE 2026-09-24 (D-258 amendment of that date). The stored rung-0.5 layer this ticket targets will not be built: storage was measured and is not forced (T-1212, done). Hydrology already solves once per body (layer1.rs, 114 ms on Ferrath) and every rung samples it. Left open rather than cancelled; closing it is Jeroen''s call.', NULL, '2026-09-24 20:44:26', '2026-09-24 20:44:26.439', '2026-09-24 20:44:26.439', NULL, '86386bc5946cb7f032d7c148cacbb266', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FT0V0WBYS20XNMEB67A6AT8G', 'description', 'step_canvas.rs (and any other rung-derivation entry point) must be re-pointed so Region/District/Quarter/Block/Chunk all derive from the cached rung-0.5 layer rather than resolving heightmap.png/reliefmap.png directly. heightmap.rs (the rung-0 loader) gains the reliefmap as a second input if it does not already load it. This is the ''no deeper rung reads the source files'' invariant from D-258 -- cross-rung visual agreement becomes structural once this lands, rather than enforced by convention. Depends on T-1213 (generator) and T-1214 (hydrology) existing to re-point to. See governance/decisions/architecture.md#d-258 Implementation note (explicitly names step_canvas.rs and heightmap.rs as the consumers to re-point).', 'step_canvas.rs (and any other rung-derivation entry point) must be re-pointed so Region/District/Quarter/Block/Chunk all derive from the cached rung-0.5 layer rather than resolving heightmap.png/reliefmap.png directly. heightmap.rs (the rung-0 loader) gains the reliefmap as a second input if it does not already load it. This is the ''no deeper rung reads the source files'' invariant from D-258 -- cross-rung visual agreement becomes structural once this lands, rather than enforced by convention. Depends on T-1213 (generator) and T-1214 (hydrology) existing to re-point to. See governance/decisions/architecture.md#d-258 Implementation note (explicitly names step_canvas.rs and heightmap.rs as the consumers to re-point).
|
||||
|
||||
PREMISE GONE 2026-09-24 (D-258 amendment of that date). The stored rung-0.5 layer this ticket targets will not be built: storage was measured and is not forced (T-1212, done). Hydrology already solves once per body (layer1.rs, 114 ms on Ferrath) and every rung samples it. Left open rather than cancelled; closing it is Jeroen''s call.', NULL, '2026-09-24 20:44:26', '2026-09-24 20:44:26.979', '2026-09-24 20:44:26.979', NULL, 'b13bf0e2759e85dc0fde83d74e262da4', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FT0TZC9MJV6KZTSRVRYQ327M', 'status', 'in_progress', 'done', NULL, '2026-09-24 20:44:27', '2026-09-24 20:44:27.521', '2026-09-24 20:44:27.521', NULL, '1e6bfb42eb3c80a764237a2858a848f6', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FT0TYBD74TQNVKTJMKA8D9KM', 'status', 'backlog', 'done', NULL, '2026-09-24 20:44:27', '2026-09-24 20:44:27.526', '2026-09-24 20:44:27.526', NULL, '877d4937ffe478151391dfb754dd2dd2', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
|
||||
@@ -850,3 +850,451 @@ Amended 2026-08-20 during the planning session: EIGHT epics, not six. E7 (Adopti
|
||||
Amended again 2026-08-20: NINE epics. T-1264 was added after a session finding that the gates are milliseconds but the generators are minutes, and an agent Bash call gives up at two minutes sending nothing — so reach streams JSONL progress events and detached runs append to a tailable per-job log, with no daemon. Epic ids, since the E-prefixes in the titles are a reading aid and not handles: T-1248 the door, T-1249 decorators, T-1250 the domain move, T-1251 the gate family, T-1252 generators and numerics, T-1253 retiring old paths, T-1256 adoption, T-1257 the test surface, T-1264 streaming and jobs. Also amended this session: the 104 ms timing-parity budget was withdrawn in favour of output parity plus a 250 ms feels-instant ceiling, which in turn dropped the no-pydantic-in-check carve-out.
|
||||
|
||||
DONE 2026-09-23. All eight epics closed (E1-E8). tooling/ is one package behind reach: 14 domains, 41 Blender payloads in the carve-out, provenance in tooling/archive/, nine conformance invariants in the push gate. Adoption: Skill(reach), the CLAUDE.md standing rule, and docs/diagrams/architecture/reach-cli.d2 linked from D-263. Follow-ups filed from what the ports found: T-1291 (reliefmap render drift), T-1292 (the destructive wiki renderer), T-1294 (frozen S-keyed star-map diagrams).', 'done', 'medium', NULL, NULL, 'D-263', '2026-08-20 00:23:17.258', '2026-09-23 18:21:58.799', NULL, '1836d08d54ce10ea0a0ca5e9e1e8097d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FT0TZC9MJV6KZTSRVRYQ327M', 'story', '06FT0TX2W0BA10PRR7NMJ2362M', 'Rung-0.5 expanded-layer generator (deterministic un-summarisation of rung 0)', 'Build the deterministic expansion from rung 0 (heightmap.png 1024x512 16-bit elevation + reliefmap.png 1024x512 colour biome) to rung 0.5, sized per D-258''s 2-px-per-gridunit-at-large-display rule. Same body + same seed must produce the same layer every time (byte-identical, per D-227''s determinism discipline extended by this carve-out). The reliefmap is a PLURALITY, not ground truth: each reliefmap cell already voted-and-discarded the dominant biome across ~38 km of ground, so this generator un-summarises it -- it does not upscale/interpolate it. Three binding invariants from D-258: (1) biome edges are gradients, never lines -- transitions blend so no boundary falls on a rung-0 cell edge (the D-243 climate edge-fuzz rule applied to biome); (2) descending the ladder reveals COMPOSITION not sharpness -- a cell reading ''forest'' globally must be able to contain clearings/marsh/rock/scrub the vote suppressed, emerging deterministically as the ladder descends; (3) CONSERVATIVE invention is the binding acceptance gate -- downsampling rung 0.5 must reproduce the rung-0 summary it came from (a forest cell may gain marsh pockets but must still read as forest from orbit). Blocked on T-1212 (cost/size measurement) landing first. Depends on: nothing else in this epic to start scaffolding, but hydrology (sibling ticket) and this generator are tightly coupled -- coordinate sequencing with whoever picks up hydrology. See governance/decisions/architecture.md#d-258.
|
||||
|
||||
---
|
||||
UNBLOCKED 2026-08-06 (T-1211 re-scope, Jeroen''s call). The T-1212 blocker edge is
|
||||
removed: that measurement priced a hydrology move that is not happening, and the
|
||||
descent ladder showed there is no expansion artefact to measure yet anyway.
|
||||
|
||||
BUILD IT AS A PURE FUNCTION FIRST, not as a stored layer. The stored-layer half of
|
||||
D-258 was materially weakened by its own 2026-07-27 amendment (the "not locally
|
||||
computable" argument for the D-227 carve-out does not hold, because the whole-body
|
||||
solve it cited already runs once per body in layer1.rs and is sampled at every
|
||||
rung). So follow the mechanism that exists — D-255(f) mechanism B,
|
||||
compute-once-sample-everywhere — measure it, and only argue for storage on those
|
||||
numbers. Do NOT open with a cache.
|
||||
|
||||
WHAT "FLAT" MEANS CONCRETELY, so the fix has a target. Ferrath''s heightmap is
|
||||
1024x512 over a 38,089 km circumference: 37.2 km per source pixel. Global draws at
|
||||
35.267 km/gridunit, roughly 1:1 with the source, and reads as a real map. Region
|
||||
draws at 0.379 km/gridunit — 98x finer than any stored datum — and is a single
|
||||
uniform colour with dither. District is 0.0038 km/gridunit, ~9,800x finer, also
|
||||
uniform. So the acceptance bar is not subtle: at Region, ~98 gridunits across a
|
||||
single source pixel must carry visible, deterministic, non-repeating composition
|
||||
that still downsamples back to that pixel''s summary (D-258''s conservation
|
||||
invariant, the binding gate).
|
||||
|
||||
VERIFY BY CAPTURE, NOT BY REASONING. The scenarios exist: atlas_GJ820Bc_land_*
|
||||
(Region/District/Quarter/Block/Chunk, one land-anchored world point, no overlays)
|
||||
in tests/visual.json. Captures run offscreen under gamescope at native 3440x1440
|
||||
via tests/run-visual --screenshot <name> — they do not steal the desktop. Re-shoot
|
||||
the ladder and look at it; a green unit test proves nothing here.
|
||||
|
||||
Note the ladder currently also reports courses=0 at every rung below Global —
|
||||
rivers vanish on descent. That is tracked separately as T-1239 and is NOT this
|
||||
ticket''s scope, but it will be visible in the same captures, so do not mistake it
|
||||
for a failure of the un-summarisation work.
|
||||
|
||||
---
|
||||
LADDER RE-SHOT COLD 2026-08-16 — the first ladder whose numbers can be trusted.
|
||||
Every previous ladder, including the one this ticket''s re-scope was written from,
|
||||
was captured against the developer''s persistent user:// cache (T-1239). The
|
||||
harness now isolates user:// per capture, so these are fresh derives.
|
||||
|
||||
RESULT: the acceptance bar is NOT met. Region and below are still flat.
|
||||
|
||||
Flatness, measured rather than eyeballed (.cache/t1213_flatness.py samples the
|
||||
terrain area, excluding the panels):
|
||||
|
||||
rung distinct R std G std B std lum p1-p99
|
||||
Global 1581 24.05 35.75 36.21 145.69
|
||||
Region 2923 4.80 8.31 4.19 33.59
|
||||
District 53 2.56 4.90 2.56 13.72
|
||||
Quarter 46 2.42 4.78 2.42 11.01
|
||||
|
||||
Note Region carries MORE distinct colours than Global (2923 vs 1581) while
|
||||
holding a quarter of the structure. That is the dither/stipple pass adding colour
|
||||
noise, not information — so distinct-count is precisely the wrong metric, and the
|
||||
percentile luminance spread is the honest one. Structure falls ~92% from Global
|
||||
to Quarter.
|
||||
|
||||
WHY IT IS FLAT — a channel mismatch, not a missing generator.
|
||||
|
||||
Composition IS working in the data. The conservation test, run explicitly against
|
||||
real terrain, reports over a 2,048 m patch at the ladder''s own anchor:
|
||||
|
||||
conservation: majority class 3 at 98.9% across 2 classes {1: 175, 3: 16209}
|
||||
|
||||
So D-258 invariant 3 (conservation) holds and invariant 2 (composition) is
|
||||
happening: 1.07% of the patch is a minority class.
|
||||
|
||||
But composition perturbs `moisture_q` and `slope_q`, which resolve into
|
||||
`vegetation_class`. The base map draws neither. step_canvas_colorize.gd''s own
|
||||
comment states it: "The base layer reads hue from morphology and lightness from
|
||||
elev_q, and on a real body below Global that collapses: morphology resolves to
|
||||
ONE zone". The ladder scenarios pass `[]` for overlays deliberately
|
||||
(visual_scenarios.gd: "No overlays, deliberately: a colour ramp on top would mask
|
||||
the very thing being judged"), so the composed fields are never rendered in the
|
||||
shots that judge this work.
|
||||
|
||||
The un-summarisation lands in channels the default view does not draw. That is
|
||||
why perfectly correct composition and a flat map coexist.
|
||||
|
||||
THE CONSERVATION TEST WAS NOT PROTECTING ANYTHING (fixed here).
|
||||
|
||||
Its "not a monoculture" assertion read:
|
||||
|
||||
assert!(tally.len() > 1 || share == 1.0, ...)
|
||||
|
||||
which is a TAUTOLOGY — a single-class tally has a 100% share by definition, so
|
||||
both branches are always satisfiable and the check could never fail, including in
|
||||
the exact case its message names ("or nothing was composed"). It was the only
|
||||
thing standing behind invariant 2, and it stood behind nothing. Now split into
|
||||
the two bounds the invariant actually has: majority > 50% (conservation, the
|
||||
ceiling on invention) and minority >= 0.1% (composition, the floor). Measured
|
||||
1.07% against a 0.1% floor.
|
||||
|
||||
It is also still `#[ignore]`d, so the binding acceptance gate for this epic runs
|
||||
only when someone types it. Worth moving into a harness that runs — the
|
||||
believability and window-derivation harnesses already load real bodies in the
|
||||
normal `cargo test` path, so the precedent exists.
|
||||
|
||||
courses=0 BELOW GLOBAL IS NOT A BUG — it is arithmetic, and the ticket''s note
|
||||
attributing it to T-1239 is superseded. Global now reports courses=73 drawn=18
|
||||
(T-1239 fixed). Region/District/Quarter report courses=0 because the hydrology
|
||||
network is 615 river cells on a 512x256 grid (74.4 km/cell) and a Region window
|
||||
is 489 x 205 km = 0.0217% of a 462M km2 body: expected river cells in view = 615
|
||||
x 0.000217 = 0.13. Zero is the likely outcome, not a failure. The real
|
||||
observation underneath it is that 615 river cells on an Earth-sized body is a
|
||||
sparse network (~45,000 km of total watercourse), which is a believability
|
||||
question for hydrology, not a rendering one.
|
||||
|
||||
THE OPEN DECISION — three readings, materially different work:
|
||||
|
||||
(A) Make the DISPLAYED channels carry sub-source-pixel composition. The literal
|
||||
reading of this ticket''s acceptance bar ("at Region, ~98 gridunits across a
|
||||
single source pixel must carry visible, deterministic, non-repeating
|
||||
composition"). Means morphology and/or elev_q gain a fine tier, which is
|
||||
D-227/D-258 territory and the largest change.
|
||||
(B) Accept that the base view is morphology + elevation, and judge composition
|
||||
through the overlays — i.e. the ladder gains VEG/MST companion shots. Test
|
||||
change only, but it concedes that the default map stays flat below Global.
|
||||
(C) Raise inclusion density so the existing vegetation texture reads at map
|
||||
scale. Tuning only; 1.07% is near-invisible.
|
||||
|
||||
Not chosen here — it needs Jeroen''s call, and it touches D-258.
|
||||
|
||||
---
|
||||
FIXED 2026-08-16 (option A). The un-summarisation was reaching the wire and
|
||||
falling off it one line before the renderer.
|
||||
|
||||
ROOT CAUSE: `step_canvas_protocol.gd`''s decode dictionary listed every dense
|
||||
plane EXCEPT relief_q. The server has encoded it since 5eb394b36
|
||||
(step_canvas.rs:1234) and the terrain layer has asked for it by name ever since
|
||||
(`canvas.get("relief_q")`), but the key was never put in the decoded dictionary,
|
||||
so the plane arrived nowhere. The server half of relief_q landed; the protocol
|
||||
half did not.
|
||||
|
||||
That is why the deep rungs were flat. relief_q is the ONE field with signal below
|
||||
District — elev_q''s 80 m steps quantise sub-district detail away — and it was
|
||||
absent. Measured plane variety at District, before: {morphology: 1, elev_q: 11,
|
||||
relief_q: 0, moisture_q: 25, vegetation: 3}. A 0 there means ABSENT, not merely
|
||||
constant; the distinction is what made this diagnosable, and it did not exist
|
||||
until this session added the plane-variety readout.
|
||||
|
||||
TWO CHANGES:
|
||||
1. Decode relief_q (one line, client/scripts/protocol/step_canvas_protocol.gd).
|
||||
2. Shade with it, SIGNED and continuously (step_canvas_colorize.gd). It was
|
||||
previously spent only as a stipple PROBABILITY, so a ridge and a plain
|
||||
differed in dot density, which at one pixel per cell reads as noise rather
|
||||
than landform — and `_ruggedness()` took absf(relief_q - 50), discarding the
|
||||
sign the server deliberately preserved ("a hollow and a rise are different
|
||||
ground"). Rises now lighten, hollows darken, under the stipple rather than
|
||||
instead of it.
|
||||
|
||||
LADDER, before -> after (tooling/atlas-flatness, lum p1-p99):
|
||||
|
||||
Global 145.69 -> 145.69 unchanged, and correct: relief_q is flat 50 at
|
||||
orbital rungs by construction
|
||||
Region 33.59 -> 71.01 2.1x
|
||||
District 13.72 -> 77.01 5.6x
|
||||
Quarter 11.01 -> 42.56 3.9x
|
||||
|
||||
Structure retention Global->Quarter went from 7.6% to 29%. Plane variety after:
|
||||
Region relief_q 101 values, District 91, Quarter 33.
|
||||
|
||||
HONEST STATE. The acceptance bar ("at Region, ~98 gridunits across a single
|
||||
source pixel must carry visible, deterministic, non-repeating composition") is
|
||||
MET. It is not yet cartographically finished: Region reads as heavy speckle
|
||||
because ruggedness is now real data rather than an elev_q-gradient fallback, so
|
||||
far more cells earn a stipple mark than the T-1194 tuning assumed (17,599
|
||||
distinct colours there). District reads as soft blobby relief — form without
|
||||
directionality, since the field is isotropic noise with no hillshade direction
|
||||
and no drainage alignment. Both are tuning/grammar follow-ups on top of a channel
|
||||
that now carries signal, not blockers.
|
||||
|
||||
REGRESSION COVER ADDED. Every protocol test passed throughout the weeks the plane
|
||||
was missing, because each asserted a field it already knew about and none
|
||||
asserted the SET. There is now a test that walks all eight dense planes of
|
||||
EncodedStepCanvas and fails if any is absent from the decode — verified by
|
||||
disabling the fix and watching it fail by name.
|
||||
|
||||
DONE 2026-09-24.
|
||||
|
||||
Acceptance bar met and verified by capture: the fresh ladder (first since T-1240) reads as terrain at every rung. lum p1-p99, flat -> now: Region 33.59 -> 63.60, District 13.72 -> 84.15, Quarter 11.01 -> 76.58.
|
||||
|
||||
Found and fixed on that ladder (commit 6b50829d6):
|
||||
- A straight diagonal seam of blocky stair-steps across Region. Traced by dumping the canvas planes: it lived in relief_q, caused by the coast/terrain character reading the CATEGORICAL glaciation grade (fjord weight jumping 0 -> 0.30 on the None/Light isotherm). The character now reads a continuous glacial_weight. Invariant (1), "edges are gradients, never lines".
|
||||
- Aliased ValleyFloor speckle at Region: composition''s 192 m inclusions ignored the rung''s octave cutoff. Now gated. ValleyFloor at Region 8,453 -> 0 cells, distinct colours 26,701 -> 2,102, structure unchanged.
|
||||
|
||||
The conservation gate (invariant 3) now RUNS in plain cargo test, and now actually compares: it derives 13 patches across Ferrath with and without composition, and the composed plurality must equal the uncomposed one. It had been #[ignore]d, and derived only once. Mutation-proven both ways.
|
||||
|
||||
T-1212''s measurement is carried here (tests/rung_cost_bench.rs): the whole-body solve takes 114 ms; a canvas takes 118-175 ms wall at every rung. A stored layer at Region pitch would be ~71 GB per body. Storage is not forced. Recorded as the 2026-09-24 D-258 amendment.
|
||||
|
||||
Left open for Jeroen, in that amendment: the reliefmap is still not read by any server code, so the "summary" being conserved is the derive''s own verdict. Should it become an input at all, given it is a render of the same heightmap?', 'in_progress', 'high', NULL, NULL, 'D-258', '2026-07-26 21:54:15.245', '2026-09-24 20:44:25.427', NULL, '96a66c32f80b0d165337c7f5d210bbc4', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FT0TYBD74TQNVKTJMKA8D9KM', 'task', '06FT0TX2W0BA10PRR7NMJ2362M', 'Measure rung-0.5 cost/size BEFORE implementing (compute + disk, whole-body)', 'MUST run and be reviewed before any other T-1211 child starts -- this measurement could reshape the rung-0.5 design, per the pair session''s explicit sequencing note. Measure, at minimum: (1) per-body derive cost for the expanded layer at a resolution sized so a whole body draws at 2 screen px per gridunit on a large display (the D-258 sizing rule) -- both single-body cold-derive time and the full ~271-body population sum; (2) per-body and total disk footprint if the layer is cached/stored (rung 0.5 is a named D-227 carve-out -- storage is deliberate, but its size must be known, not assumed); (3) whole-body hydrology solve cost on this layer (drainage + course routing + lake fill) at the same resolution, since D-258 requires this to run exactly once per body and nowhere else. Reference point: D-255''s own rung-0 always-keep tier estimate went from ~8.85 MB (measured against a stale ~18K-cell/body figure) to an estimated 226 MB (1080p) / ~900 MB (4K) once the extent inversion made Global viewport-sized -- D-255 amendment item 6 explicitly says ''re-measure against rung 0.5, not against this record.'' This ticket is that re-measurement. Report back to the team before T-1211''s other children are started; if the numbers are structurally bad (e.g. rung 0.5 at the sizing D-258 specifies costs an order of magnitude more than the old rung-0 model), that is grounds to revisit the resolution target with Jeroen before writing generator code. See governance/decisions/architecture.md#d-258 (rationale + Implementation note).
|
||||
|
||||
SCOPE INVALIDATED 2026-07-27 (see T-1211 and the D-258 amendment). This ticket was written to measure the cost of moving a whole-body hydrology solve onto rung 0.5. That solve does not need to move -- it already runs once per body in layer1.rs and is sampled fresh at every rung. Do NOT run this measurement as written; it would price work that is not required. If a measurement is still wanted after T-1211 is re-scoped, the question is narrower: what does BIOME un-summarisation cost, and does it need storing at all.
|
||||
|
||||
---
|
||||
RETIRED AS A GATE 2026-08-06. This no longer blocks T-1213 or the T-1211 epic.
|
||||
|
||||
It was already SCOPE INVALIDATED (2026-07-27) for pricing a hydrology move that
|
||||
does not need to happen. The 2026-08-06 descent ladder (see T-1211) closes the
|
||||
remaining reason to keep it as a gate: every rung below Global renders a flat
|
||||
wash, so biome un-summarisation is not happening at all. There is no artefact
|
||||
whose cost or disk footprint can be measured, because none is produced.
|
||||
|
||||
The measurement question survives, but it is now DOWNSTREAM of T-1213 rather
|
||||
than upstream of it: once the un-summarisation exists as a pure function, measure
|
||||
THAT, and only then decide whether a stored layer is warranted. Re-scope this
|
||||
ticket to that measurement when T-1213 lands, or close it and let T-1213 carry
|
||||
its own measurement step.
|
||||
|
||||
DONE 2026-09-24 — measured inside T-1213, as the 2026-08-06 note allowed.
|
||||
|
||||
Measured with tests/rung_cost_bench.rs (release, 16 cores, Ferrath at the ladder anchor, 1290x540):
|
||||
- whole-body solve: 114 ms, once per body
|
||||
- one canvas: Global 118 ms, Region 141 ms, District 175 ms, Quarter 175 ms (wall)
|
||||
|
||||
A stored layer at Region pitch would be ~5.05e9 cells, about 71 GB per body; District is 10^4x more. A layer at D-258''s own sizing can serve only Global, which already derives in 118 ms.
|
||||
|
||||
Storage is not forced. See the D-258 amendment of 2026-09-24.', 'backlog', 'high', NULL, NULL, 'D-258', '2026-07-26 21:54:06.825', '2026-09-24 20:44:25.937', NULL, 'a87ea0132eb5555eff7c6ae459b6d337', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FT0V04XYBWC93Q1QTETMSQE8', 'story', '06FT0TX2W0BA10PRR7NMJ2362M', 'Whole-body hydrology resolves on rung 0.5 (drainage, course routing, lake fill)', 'Move hydrology resolution so it runs exactly ONCE per body, on the rung-0.5 layer, and nowhere else. D-258''s structural rationale: drainage/course-routing/lake-fill are whole-body computations (water arrives from upstream and leaves downstream, both off-screen at every rung below Global), so no per-window derivation at Region/District/Quarter/Block/Chunk can produce a coherent water system -- this is why Region currently carries no courses and lakes cannot fill under the old per-rung-independent model. Cross-rung agreement (the coastline zoomed out is the coastline zoomed in; a river crossing a district reaches the sea on the global map) must hold BY CONSTRUCTION once every rung sources from this one solved layer, not by policing two derivation paths against each other. Contradiction to fix in the same pass: Global currently still rides uses_orbital_derive()==true and the orbital path skips the course/water pass entirely (confirmed live in the pair session) -- that is why Global reads flat at any resolution today; this is not a tuning gap, it is a missing pass, and this ticket is what closes it. Blocked on T-1212 (measurement) and coordinates tightly with the expanded-layer generator sibling ticket. See governance/decisions/architecture.md#d-258 and #d-255 (amendment item 3, ''Region carrying no rivers at all was much of why the top of the ladder read flat'').
|
||||
|
||||
PREMISE GONE 2026-09-24 (D-258 amendment of that date). The stored rung-0.5 layer this ticket targets will not be built: storage was measured and is not forced (T-1212, done). Hydrology already solves once per body (layer1.rs, 114 ms on Ferrath) and every rung samples it. Left open rather than cancelled; closing it is Jeroen''s call.', 'backlog', 'high', NULL, NULL, 'D-258', '2026-07-26 21:54:21.551', '2026-09-24 20:44:26.439', NULL, 'b498638c0c17c404aca0b7cdd525fe90', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FT0V0WBYS20XNMEB67A6AT8G', 'task', '06FT0TX2W0BA10PRR7NMJ2362M', 'Re-point every Atlas rung to source from rung 0.5, not the raw heightmap/reliefmap', 'step_canvas.rs (and any other rung-derivation entry point) must be re-pointed so Region/District/Quarter/Block/Chunk all derive from the cached rung-0.5 layer rather than resolving heightmap.png/reliefmap.png directly. heightmap.rs (the rung-0 loader) gains the reliefmap as a second input if it does not already load it. This is the ''no deeper rung reads the source files'' invariant from D-258 -- cross-rung visual agreement becomes structural once this lands, rather than enforced by convention. Depends on T-1213 (generator) and T-1214 (hydrology) existing to re-point to. See governance/decisions/architecture.md#d-258 Implementation note (explicitly names step_canvas.rs and heightmap.rs as the consumers to re-point).
|
||||
|
||||
PREMISE GONE 2026-09-24 (D-258 amendment of that date). The stored rung-0.5 layer this ticket targets will not be built: storage was measured and is not forced (T-1212, done). Hydrology already solves once per body (layer1.rs, 114 ms on Ferrath) and every rung samples it. Left open rather than cancelled; closing it is Jeroen''s call.', 'backlog', 'high', NULL, NULL, 'D-258', '2026-07-26 21:54:27.551', '2026-09-24 20:44:26.979', NULL, '91b5af40c972f42ce638633dc077f5c0', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FT0TZC9MJV6KZTSRVRYQ327M', 'story', '06FT0TX2W0BA10PRR7NMJ2362M', 'Rung-0.5 expanded-layer generator (deterministic un-summarisation of rung 0)', 'Build the deterministic expansion from rung 0 (heightmap.png 1024x512 16-bit elevation + reliefmap.png 1024x512 colour biome) to rung 0.5, sized per D-258''s 2-px-per-gridunit-at-large-display rule. Same body + same seed must produce the same layer every time (byte-identical, per D-227''s determinism discipline extended by this carve-out). The reliefmap is a PLURALITY, not ground truth: each reliefmap cell already voted-and-discarded the dominant biome across ~38 km of ground, so this generator un-summarises it -- it does not upscale/interpolate it. Three binding invariants from D-258: (1) biome edges are gradients, never lines -- transitions blend so no boundary falls on a rung-0 cell edge (the D-243 climate edge-fuzz rule applied to biome); (2) descending the ladder reveals COMPOSITION not sharpness -- a cell reading ''forest'' globally must be able to contain clearings/marsh/rock/scrub the vote suppressed, emerging deterministically as the ladder descends; (3) CONSERVATIVE invention is the binding acceptance gate -- downsampling rung 0.5 must reproduce the rung-0 summary it came from (a forest cell may gain marsh pockets but must still read as forest from orbit). Blocked on T-1212 (cost/size measurement) landing first. Depends on: nothing else in this epic to start scaffolding, but hydrology (sibling ticket) and this generator are tightly coupled -- coordinate sequencing with whoever picks up hydrology. See governance/decisions/architecture.md#d-258.
|
||||
|
||||
---
|
||||
UNBLOCKED 2026-08-06 (T-1211 re-scope, Jeroen''s call). The T-1212 blocker edge is
|
||||
removed: that measurement priced a hydrology move that is not happening, and the
|
||||
descent ladder showed there is no expansion artefact to measure yet anyway.
|
||||
|
||||
BUILD IT AS A PURE FUNCTION FIRST, not as a stored layer. The stored-layer half of
|
||||
D-258 was materially weakened by its own 2026-07-27 amendment (the "not locally
|
||||
computable" argument for the D-227 carve-out does not hold, because the whole-body
|
||||
solve it cited already runs once per body in layer1.rs and is sampled at every
|
||||
rung). So follow the mechanism that exists — D-255(f) mechanism B,
|
||||
compute-once-sample-everywhere — measure it, and only argue for storage on those
|
||||
numbers. Do NOT open with a cache.
|
||||
|
||||
WHAT "FLAT" MEANS CONCRETELY, so the fix has a target. Ferrath''s heightmap is
|
||||
1024x512 over a 38,089 km circumference: 37.2 km per source pixel. Global draws at
|
||||
35.267 km/gridunit, roughly 1:1 with the source, and reads as a real map. Region
|
||||
draws at 0.379 km/gridunit — 98x finer than any stored datum — and is a single
|
||||
uniform colour with dither. District is 0.0038 km/gridunit, ~9,800x finer, also
|
||||
uniform. So the acceptance bar is not subtle: at Region, ~98 gridunits across a
|
||||
single source pixel must carry visible, deterministic, non-repeating composition
|
||||
that still downsamples back to that pixel''s summary (D-258''s conservation
|
||||
invariant, the binding gate).
|
||||
|
||||
VERIFY BY CAPTURE, NOT BY REASONING. The scenarios exist: atlas_GJ820Bc_land_*
|
||||
(Region/District/Quarter/Block/Chunk, one land-anchored world point, no overlays)
|
||||
in tests/visual.json. Captures run offscreen under gamescope at native 3440x1440
|
||||
via tests/run-visual --screenshot <name> — they do not steal the desktop. Re-shoot
|
||||
the ladder and look at it; a green unit test proves nothing here.
|
||||
|
||||
Note the ladder currently also reports courses=0 at every rung below Global —
|
||||
rivers vanish on descent. That is tracked separately as T-1239 and is NOT this
|
||||
ticket''s scope, but it will be visible in the same captures, so do not mistake it
|
||||
for a failure of the un-summarisation work.
|
||||
|
||||
---
|
||||
LADDER RE-SHOT COLD 2026-08-16 — the first ladder whose numbers can be trusted.
|
||||
Every previous ladder, including the one this ticket''s re-scope was written from,
|
||||
was captured against the developer''s persistent user:// cache (T-1239). The
|
||||
harness now isolates user:// per capture, so these are fresh derives.
|
||||
|
||||
RESULT: the acceptance bar is NOT met. Region and below are still flat.
|
||||
|
||||
Flatness, measured rather than eyeballed (.cache/t1213_flatness.py samples the
|
||||
terrain area, excluding the panels):
|
||||
|
||||
rung distinct R std G std B std lum p1-p99
|
||||
Global 1581 24.05 35.75 36.21 145.69
|
||||
Region 2923 4.80 8.31 4.19 33.59
|
||||
District 53 2.56 4.90 2.56 13.72
|
||||
Quarter 46 2.42 4.78 2.42 11.01
|
||||
|
||||
Note Region carries MORE distinct colours than Global (2923 vs 1581) while
|
||||
holding a quarter of the structure. That is the dither/stipple pass adding colour
|
||||
noise, not information — so distinct-count is precisely the wrong metric, and the
|
||||
percentile luminance spread is the honest one. Structure falls ~92% from Global
|
||||
to Quarter.
|
||||
|
||||
WHY IT IS FLAT — a channel mismatch, not a missing generator.
|
||||
|
||||
Composition IS working in the data. The conservation test, run explicitly against
|
||||
real terrain, reports over a 2,048 m patch at the ladder''s own anchor:
|
||||
|
||||
conservation: majority class 3 at 98.9% across 2 classes {1: 175, 3: 16209}
|
||||
|
||||
So D-258 invariant 3 (conservation) holds and invariant 2 (composition) is
|
||||
happening: 1.07% of the patch is a minority class.
|
||||
|
||||
But composition perturbs `moisture_q` and `slope_q`, which resolve into
|
||||
`vegetation_class`. The base map draws neither. step_canvas_colorize.gd''s own
|
||||
comment states it: "The base layer reads hue from morphology and lightness from
|
||||
elev_q, and on a real body below Global that collapses: morphology resolves to
|
||||
ONE zone". The ladder scenarios pass `[]` for overlays deliberately
|
||||
(visual_scenarios.gd: "No overlays, deliberately: a colour ramp on top would mask
|
||||
the very thing being judged"), so the composed fields are never rendered in the
|
||||
shots that judge this work.
|
||||
|
||||
The un-summarisation lands in channels the default view does not draw. That is
|
||||
why perfectly correct composition and a flat map coexist.
|
||||
|
||||
THE CONSERVATION TEST WAS NOT PROTECTING ANYTHING (fixed here).
|
||||
|
||||
Its "not a monoculture" assertion read:
|
||||
|
||||
assert!(tally.len() > 1 || share == 1.0, ...)
|
||||
|
||||
which is a TAUTOLOGY — a single-class tally has a 100% share by definition, so
|
||||
both branches are always satisfiable and the check could never fail, including in
|
||||
the exact case its message names ("or nothing was composed"). It was the only
|
||||
thing standing behind invariant 2, and it stood behind nothing. Now split into
|
||||
the two bounds the invariant actually has: majority > 50% (conservation, the
|
||||
ceiling on invention) and minority >= 0.1% (composition, the floor). Measured
|
||||
1.07% against a 0.1% floor.
|
||||
|
||||
It is also still `#[ignore]`d, so the binding acceptance gate for this epic runs
|
||||
only when someone types it. Worth moving into a harness that runs — the
|
||||
believability and window-derivation harnesses already load real bodies in the
|
||||
normal `cargo test` path, so the precedent exists.
|
||||
|
||||
courses=0 BELOW GLOBAL IS NOT A BUG — it is arithmetic, and the ticket''s note
|
||||
attributing it to T-1239 is superseded. Global now reports courses=73 drawn=18
|
||||
(T-1239 fixed). Region/District/Quarter report courses=0 because the hydrology
|
||||
network is 615 river cells on a 512x256 grid (74.4 km/cell) and a Region window
|
||||
is 489 x 205 km = 0.0217% of a 462M km2 body: expected river cells in view = 615
|
||||
x 0.000217 = 0.13. Zero is the likely outcome, not a failure. The real
|
||||
observation underneath it is that 615 river cells on an Earth-sized body is a
|
||||
sparse network (~45,000 km of total watercourse), which is a believability
|
||||
question for hydrology, not a rendering one.
|
||||
|
||||
THE OPEN DECISION — three readings, materially different work:
|
||||
|
||||
(A) Make the DISPLAYED channels carry sub-source-pixel composition. The literal
|
||||
reading of this ticket''s acceptance bar ("at Region, ~98 gridunits across a
|
||||
single source pixel must carry visible, deterministic, non-repeating
|
||||
composition"). Means morphology and/or elev_q gain a fine tier, which is
|
||||
D-227/D-258 territory and the largest change.
|
||||
(B) Accept that the base view is morphology + elevation, and judge composition
|
||||
through the overlays — i.e. the ladder gains VEG/MST companion shots. Test
|
||||
change only, but it concedes that the default map stays flat below Global.
|
||||
(C) Raise inclusion density so the existing vegetation texture reads at map
|
||||
scale. Tuning only; 1.07% is near-invisible.
|
||||
|
||||
Not chosen here — it needs Jeroen''s call, and it touches D-258.
|
||||
|
||||
---
|
||||
FIXED 2026-08-16 (option A). The un-summarisation was reaching the wire and
|
||||
falling off it one line before the renderer.
|
||||
|
||||
ROOT CAUSE: `step_canvas_protocol.gd`''s decode dictionary listed every dense
|
||||
plane EXCEPT relief_q. The server has encoded it since 5eb394b36
|
||||
(step_canvas.rs:1234) and the terrain layer has asked for it by name ever since
|
||||
(`canvas.get("relief_q")`), but the key was never put in the decoded dictionary,
|
||||
so the plane arrived nowhere. The server half of relief_q landed; the protocol
|
||||
half did not.
|
||||
|
||||
That is why the deep rungs were flat. relief_q is the ONE field with signal below
|
||||
District — elev_q''s 80 m steps quantise sub-district detail away — and it was
|
||||
absent. Measured plane variety at District, before: {morphology: 1, elev_q: 11,
|
||||
relief_q: 0, moisture_q: 25, vegetation: 3}. A 0 there means ABSENT, not merely
|
||||
constant; the distinction is what made this diagnosable, and it did not exist
|
||||
until this session added the plane-variety readout.
|
||||
|
||||
TWO CHANGES:
|
||||
1. Decode relief_q (one line, client/scripts/protocol/step_canvas_protocol.gd).
|
||||
2. Shade with it, SIGNED and continuously (step_canvas_colorize.gd). It was
|
||||
previously spent only as a stipple PROBABILITY, so a ridge and a plain
|
||||
differed in dot density, which at one pixel per cell reads as noise rather
|
||||
than landform — and `_ruggedness()` took absf(relief_q - 50), discarding the
|
||||
sign the server deliberately preserved ("a hollow and a rise are different
|
||||
ground"). Rises now lighten, hollows darken, under the stipple rather than
|
||||
instead of it.
|
||||
|
||||
LADDER, before -> after (tooling/atlas-flatness, lum p1-p99):
|
||||
|
||||
Global 145.69 -> 145.69 unchanged, and correct: relief_q is flat 50 at
|
||||
orbital rungs by construction
|
||||
Region 33.59 -> 71.01 2.1x
|
||||
District 13.72 -> 77.01 5.6x
|
||||
Quarter 11.01 -> 42.56 3.9x
|
||||
|
||||
Structure retention Global->Quarter went from 7.6% to 29%. Plane variety after:
|
||||
Region relief_q 101 values, District 91, Quarter 33.
|
||||
|
||||
HONEST STATE. The acceptance bar ("at Region, ~98 gridunits across a single
|
||||
source pixel must carry visible, deterministic, non-repeating composition") is
|
||||
MET. It is not yet cartographically finished: Region reads as heavy speckle
|
||||
because ruggedness is now real data rather than an elev_q-gradient fallback, so
|
||||
far more cells earn a stipple mark than the T-1194 tuning assumed (17,599
|
||||
distinct colours there). District reads as soft blobby relief — form without
|
||||
directionality, since the field is isotropic noise with no hillshade direction
|
||||
and no drainage alignment. Both are tuning/grammar follow-ups on top of a channel
|
||||
that now carries signal, not blockers.
|
||||
|
||||
REGRESSION COVER ADDED. Every protocol test passed throughout the weeks the plane
|
||||
was missing, because each asserted a field it already knew about and none
|
||||
asserted the SET. There is now a test that walks all eight dense planes of
|
||||
EncodedStepCanvas and fails if any is absent from the decode — verified by
|
||||
disabling the fix and watching it fail by name.
|
||||
|
||||
DONE 2026-09-24.
|
||||
|
||||
Acceptance bar met and verified by capture: the fresh ladder (first since T-1240) reads as terrain at every rung. lum p1-p99, flat -> now: Region 33.59 -> 63.60, District 13.72 -> 84.15, Quarter 11.01 -> 76.58.
|
||||
|
||||
Found and fixed on that ladder (commit 6b50829d6):
|
||||
- A straight diagonal seam of blocky stair-steps across Region. Traced by dumping the canvas planes: it lived in relief_q, caused by the coast/terrain character reading the CATEGORICAL glaciation grade (fjord weight jumping 0 -> 0.30 on the None/Light isotherm). The character now reads a continuous glacial_weight. Invariant (1), "edges are gradients, never lines".
|
||||
- Aliased ValleyFloor speckle at Region: composition''s 192 m inclusions ignored the rung''s octave cutoff. Now gated. ValleyFloor at Region 8,453 -> 0 cells, distinct colours 26,701 -> 2,102, structure unchanged.
|
||||
|
||||
The conservation gate (invariant 3) now RUNS in plain cargo test, and now actually compares: it derives 13 patches across Ferrath with and without composition, and the composed plurality must equal the uncomposed one. It had been #[ignore]d, and derived only once. Mutation-proven both ways.
|
||||
|
||||
T-1212''s measurement is carried here (tests/rung_cost_bench.rs): the whole-body solve takes 114 ms; a canvas takes 118-175 ms wall at every rung. A stored layer at Region pitch would be ~71 GB per body. Storage is not forced. Recorded as the 2026-09-24 D-258 amendment.
|
||||
|
||||
Left open for Jeroen, in that amendment: the reliefmap is still not read by any server code, so the "summary" being conserved is the derive''s own verdict. Should it become an input at all, given it is a render of the same heightmap?', 'done', 'high', NULL, NULL, 'D-258', '2026-07-26 21:54:15.245', '2026-09-24 20:44:27.516', NULL, '846dcb326556e66fb4c56ae8c30fc368', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FT0TYBD74TQNVKTJMKA8D9KM', 'task', '06FT0TX2W0BA10PRR7NMJ2362M', 'Measure rung-0.5 cost/size BEFORE implementing (compute + disk, whole-body)', 'MUST run and be reviewed before any other T-1211 child starts -- this measurement could reshape the rung-0.5 design, per the pair session''s explicit sequencing note. Measure, at minimum: (1) per-body derive cost for the expanded layer at a resolution sized so a whole body draws at 2 screen px per gridunit on a large display (the D-258 sizing rule) -- both single-body cold-derive time and the full ~271-body population sum; (2) per-body and total disk footprint if the layer is cached/stored (rung 0.5 is a named D-227 carve-out -- storage is deliberate, but its size must be known, not assumed); (3) whole-body hydrology solve cost on this layer (drainage + course routing + lake fill) at the same resolution, since D-258 requires this to run exactly once per body and nowhere else. Reference point: D-255''s own rung-0 always-keep tier estimate went from ~8.85 MB (measured against a stale ~18K-cell/body figure) to an estimated 226 MB (1080p) / ~900 MB (4K) once the extent inversion made Global viewport-sized -- D-255 amendment item 6 explicitly says ''re-measure against rung 0.5, not against this record.'' This ticket is that re-measurement. Report back to the team before T-1211''s other children are started; if the numbers are structurally bad (e.g. rung 0.5 at the sizing D-258 specifies costs an order of magnitude more than the old rung-0 model), that is grounds to revisit the resolution target with Jeroen before writing generator code. See governance/decisions/architecture.md#d-258 (rationale + Implementation note).
|
||||
|
||||
SCOPE INVALIDATED 2026-07-27 (see T-1211 and the D-258 amendment). This ticket was written to measure the cost of moving a whole-body hydrology solve onto rung 0.5. That solve does not need to move -- it already runs once per body in layer1.rs and is sampled fresh at every rung. Do NOT run this measurement as written; it would price work that is not required. If a measurement is still wanted after T-1211 is re-scoped, the question is narrower: what does BIOME un-summarisation cost, and does it need storing at all.
|
||||
|
||||
---
|
||||
RETIRED AS A GATE 2026-08-06. This no longer blocks T-1213 or the T-1211 epic.
|
||||
|
||||
It was already SCOPE INVALIDATED (2026-07-27) for pricing a hydrology move that
|
||||
does not need to happen. The 2026-08-06 descent ladder (see T-1211) closes the
|
||||
remaining reason to keep it as a gate: every rung below Global renders a flat
|
||||
wash, so biome un-summarisation is not happening at all. There is no artefact
|
||||
whose cost or disk footprint can be measured, because none is produced.
|
||||
|
||||
The measurement question survives, but it is now DOWNSTREAM of T-1213 rather
|
||||
than upstream of it: once the un-summarisation exists as a pure function, measure
|
||||
THAT, and only then decide whether a stored layer is warranted. Re-scope this
|
||||
ticket to that measurement when T-1213 lands, or close it and let T-1213 carry
|
||||
its own measurement step.
|
||||
|
||||
DONE 2026-09-24 — measured inside T-1213, as the 2026-08-06 note allowed.
|
||||
|
||||
Measured with tests/rung_cost_bench.rs (release, 16 cores, Ferrath at the ladder anchor, 1290x540):
|
||||
- whole-body solve: 114 ms, once per body
|
||||
- one canvas: Global 118 ms, Region 141 ms, District 175 ms, Quarter 175 ms (wall)
|
||||
|
||||
A stored layer at Region pitch would be ~5.05e9 cells, about 71 GB per body; District is 10^4x more. A layer at D-258''s own sizing can serve only Global, which already derives in 118 ms.
|
||||
|
||||
Storage is not forced. See the D-258 amendment of 2026-09-24.', 'done', 'high', NULL, NULL, 'D-258', '2026-07-26 21:54:06.825', '2026-09-24 20:44:27.526', NULL, '2b4b26704d58544024f7bd8b448c8aff', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at >= tickets.updated_at;
|
||||
|
||||
@@ -2428,6 +2428,20 @@ Technical foundation decisions that constrain implementation: engine, client-ser
|
||||
|
||||
**Process note:** this was found by capturing the ladder and looking at it, after the goldens had been failing for 15 commits and two of them had been *passing* against blank screens. Consistent with the previous amendment's lesson — the verification that finally saw the problem was an eyeball on a real render at a real resolution, not a green assertion.
|
||||
|
||||
- **Amendment (2026-09-24 — measured: the numbers do not force storage; the stored layer stays unbuilt):** the previous amendment's condition — *open the storage question only if the pure function's numbers force it* — has been measured, and they do not. This applies that ruling; it does not make a new one.
|
||||
|
||||
**The pure function exists and meets the bar.** Composition (`atlas/composition.rs`) and signed relief shading carry the un-summarisation into every rung below Global; the conservation invariant (3) is enforced on real terrain in plain `cargo test` — 13 patches across Ferrath, each derived with and without composition, the composed plurality required to equal the uncomposed one — and was mutation-proven both ways (over-invention and no invention both fail it). Structure retained down the ladder, lum p1–p99: Global 147.4, Region 63.6, District 84.2, Quarter 76.6 (flat: 33.6 / 13.7 / 11.0).
|
||||
|
||||
**Cost of the derive** (`tests/rung_cost_bench.rs`, release, 16 cores, Ferrath at the ladder anchor, 1290×540): the whole-body solve **114 ms**, once per body, already cached; one served canvas **118 ms Global, 141 ms Region, 175 ms District, 175 ms Quarter** wall. Flat across rungs, as the extent inversion ([D-255](#d-255)) designed.
|
||||
|
||||
**Cost of storing instead.** A stored layer can only serve the rungs whose resolution it holds. At Region's 379 m pitch Ferrath is ~100,500 × 50,250 = 5.05 × 10⁹ cells; at the canvas's 14 bytes of dense planes per cell that is **~71 GB for one body**, and District is 10⁴ times that again. A layer sized by this record's own rule (a whole body at 2 screen px per gridunit) is small — ~2 M cells, tens of MB — but it holds Global's resolution and therefore serves only Global, which derives in 118 ms. Storage would buy a tenth of a second at the one rung that never needed it, and cannot reach the rungs that do.
|
||||
|
||||
**Consequence.** The [D-227](#d-227) carve-out stays unused: everything below rung 0 is derive-don't-store, rung 0.5 included, and "rung 0.5" names the un-summarising *function* every rung calls, not an artefact. [T-1215](../../.pql) (re-point every rung to a stored layer) and [T-1214](../../.pql) (move hydrology onto it) lose their premise. [T-1216](../../.pql) (Global biome palette) and [T-1217](../../.pql) (lake shores through the shared shore path) are unaffected.
|
||||
|
||||
**Open, and not decided here: the reliefmap is still not an input.** This record names `reliefmap.png` as the biome input whose plurality rung 0.5 un-summarises. No server code reads it (`heightmap.rs` mentions it only to reject an RGB PNG). Biome is derived from climate — temperature, moisture, elevation — so the "summary" the conservation gate protects is the derive's own uncomposed verdict, not a reliefmap pixel. Whether the reliefmap should become an input at all (it is itself a render of the same heightmap, so reading it may be circular) is Jeroen's call.
|
||||
|
||||
**Two defects found by the same capture pass, both violations of invariant (1):** the terrain character stepped on the None→Light glaciation isotherm (a straight seam through Region's relief, drawn as a stair-stepped cliff) and composition's 192 m inclusions ignored the rung's octave cutoff (aliased speckle at Region). Both fixed in T-1213; the character now reads a continuous glacial weight.
|
||||
|
||||
---
|
||||
|
||||
### D-259: Enclosed settlements — open-air requires a breathable atmosphere
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
//! Rung-0.5 cost measurement on a real body (T-1213, carrying T-1212's question).
|
||||
//!
|
||||
//! D-258 ruled a STORED expanded layer; its 2026-08-06 amendment said to build
|
||||
//! the un-summarisation as a pure function first, measure that, and argue for
|
||||
//! storage only if the numbers force it. This is that measurement: the
|
||||
//! once-per-body solve every rung samples, and one served canvas per rung, on
|
||||
//! Ferrath at the descent ladder's own anchor and the ladder's own extent.
|
||||
//!
|
||||
//! Run: `cargo test --release --test rung_cost_bench -- --ignored --nocapture`
|
||||
//! (debug is several times slower and not worth recording).
|
||||
|
||||
use std::time::Instant;
|
||||
|
||||
use settled_reach_server::atlas::believability::cascade_snapshot_for_body;
|
||||
use settled_reach_server::atlas::district_profile::{derive_moisture_ceiling_q, ClimateConstants};
|
||||
use settled_reach_server::atlas::layer1::run_layer1_with_moisture;
|
||||
use settled_reach_server::atlas::step_canvas::{build_step_canvas, StepCanvasRung};
|
||||
use settled_reach_server::seed::SeedChain;
|
||||
|
||||
const BODY: &str = "GJ820Bc";
|
||||
/// The descent ladder's anchor (tests/visual.json, atlas_GJ820Bc_land_*).
|
||||
const ANCHOR: (i64, i64) = (29_422_008, -5_675_959);
|
||||
/// The ladder's held extent at 3440x1440 (2x2 display ratio).
|
||||
const EXTENT: (u32, u32) = (1290, 540);
|
||||
const RUNS: u32 = 5;
|
||||
|
||||
#[test]
|
||||
#[ignore = "benchmark on a real body; run explicitly with --release"]
|
||||
fn rung_cost_on_a_real_body() {
|
||||
let Ok((snapshot, params)) = cascade_snapshot_for_body(42, BODY) else {
|
||||
eprintln!("skip: {BODY} not loadable");
|
||||
return;
|
||||
};
|
||||
let ceiling = derive_moisture_ceiling_q(¶ms);
|
||||
|
||||
// The whole-body solve (drainage + settled hydrology) — what D-258 first
|
||||
// proposed moving onto a stored layer, and what already runs once per
|
||||
// body behind the server's TerrainAnalysisCache.
|
||||
let t = Instant::now();
|
||||
let mut solved = None;
|
||||
for _ in 0..RUNS {
|
||||
solved = Some(run_layer1_with_moisture(&snapshot.heightmap, ceiling));
|
||||
}
|
||||
let solve_ms = t.elapsed().as_secs_f64() * 1e3 / RUNS as f64;
|
||||
let (l1, ta) = solved.expect("ran");
|
||||
eprintln!(
|
||||
"whole-body solve ({}x{} working grid): {solve_ms:.1} ms",
|
||||
ta.w, ta.h
|
||||
);
|
||||
|
||||
let climate = ClimateConstants::default();
|
||||
let seed = SeedChain::for_body(42, BODY);
|
||||
for rung in [
|
||||
StepCanvasRung::Global,
|
||||
StepCanvasRung::Region,
|
||||
StepCanvasRung::District,
|
||||
StepCanvasRung::Quarter,
|
||||
] {
|
||||
let t = Instant::now();
|
||||
let mut w = 0;
|
||||
let mut h = 0;
|
||||
for _ in 0..RUNS {
|
||||
let raw = build_step_canvas(
|
||||
seed,
|
||||
BODY,
|
||||
¶ms,
|
||||
&ta,
|
||||
&l1.river_network,
|
||||
&[],
|
||||
rung,
|
||||
ANCHOR,
|
||||
EXTENT,
|
||||
&climate,
|
||||
0,
|
||||
);
|
||||
w = raw.width;
|
||||
h = raw.height;
|
||||
}
|
||||
let ms = t.elapsed().as_secs_f64() * 1e3 / RUNS as f64;
|
||||
assert!(w > 0 && h > 0, "{rung:?} built an empty canvas");
|
||||
// Wall time: build_step_canvas derives rows in parallel (rayon), so
|
||||
// this is the latency a request sees on this machine, not CPU cost.
|
||||
eprintln!(
|
||||
"{rung:?}: {w}x{h} canvas in {ms:.1} ms wall ({:.2} us/cell)",
|
||||
ms * 1e3 / (w as f64 * h as f64),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user