fix(client): the deep rungs were flat because relief_q fell off the wire (T-1213)

`relief_q` is the one field with signal below District — elev_q's 80 m steps
quantise sub-district detail away, which is precisely why relief_q was invented.
The server has encoded it since 5eb394b36 and the terrain layer has asked for it
by name ever since. step_canvas_protocol.gd's decode dictionary never listed the
key, so `canvas.get("relief_q")` was always null and the plane arrived nowhere.
The server half of that change landed; the protocol half did not.

That is the whole reason Region and below rendered as a flat wash. Measured plane
variety at District before the fix:

    {morphology: 1, elev_q: 11, relief_q: 0, moisture_q: 25, vegetation: 3}

A 0 there means ABSENT, not constant — a distinction the capture could not make
until this commit adds it, and the reason two earlier sessions read the flatness
as a missing generator rather than a missing key.

Also spends the field properly. It drove a stipple PROBABILITY only, so a ridge
and a plain differed in dot density, which at one pixel per cell reads as noise;
and `_ruggedness()` took absf(relief_q - 50), discarding the sign the server
deliberately preserved ("a hollow and a rise are different ground... the reverse
is not recoverable"). Relief now shades continuously and signed — rises lighten,
hollows darken — UNDER the stipple rather than instead of it. Ruggedness
(unsigned) and elevation (signed) are different questions and both are worth
asking.

Ladder, before -> after (tooling/atlas-flatness, lum p1-p99):

    Global    145.69 -> 145.69   unchanged, 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: 7.6% -> 29%.

NOT finished, and the ticket says so: Region now reads as heavy speckle, because
ruggedness is real data instead of an elev_q-gradient fallback and far more cells
earn a mark than the T-1194 tuning assumed; District reads as soft blobby relief,
form without directionality. Both are grammar/tuning follow-ups on a channel that
finally carries signal.

0.4.9 is a REQUIRED bump. The disk cache stores the DECODED canvas, so every
earlier entry physically lacks the field and would keep rendering flat against a
build that reads it — the first bump in this series where a warm cache is wrong
about CONTENT, not merely stale. tooling/canvas_sources.py gains
step_canvas_protocol.gd for the same reason: it decides which planes exist, the
cache stores its output, and the T-1242 gate would not have flagged this fix
while the registry stopped at ui/.../step_canvas/.

Regression cover: 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 walking all eight dense planes of EncodedStepCanvas,
verified by disabling the fix and watching it fail by name.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-16 15:22:50 +02:00
co-authored by Claude Opus 5
parent e5224b1a44
commit 3ec35b87c8
11 changed files with 690 additions and 7 deletions
+302
View File
@@ -332,3 +332,305 @@ THE OPEN DECISION — three readings, materially different work:
scale. Tuning only; 1.07% is near-invisible.
Not chosen here — it needs Jeroen''s call, and it touches D-258.', NULL, '2026-08-16 10:32:31', '2026-08-16 10:32:31.457', '2026-08-16 10:32:31.457', NULL, '09a8f8872c230a04e1cb4a59d8fb52c8', 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.', '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.', NULL, '2026-08-16 13:05:35', '2026-08-16 13:05:35.162', '2026-08-16 13:05:35.162', NULL, 'fc36ad2f1acb58e73b53d53ac6402a95', 2) ON CONFLICT(hash) DO NOTHING;
+179
View File
@@ -431,3 +431,182 @@ THE OPEN DECISION — three readings, materially different work:
scale. Tuning only; 1.07% is near-invisible.
Not chosen here — it needs Jeroen''s call, and it touches D-258.', 'in_progress', 'high', NULL, NULL, 'D-258', '2026-07-26 21:54:15.245', '2026-08-16 10:32:31.457', NULL, '21d816226e574f3b6489810453220b5e', 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.', 'in_progress', 'high', NULL, NULL, 'D-258', '2026-07-26 21:54:15.245', '2026-08-16 13:05:35.162', NULL, 'e611e465ff1fd8de7b71b3de10702fec', 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;