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:
@@ -87,6 +87,22 @@ CLIENT_STEP_CANVAS_DIR: Path = (
|
||||
# The accessor the cache reads its invalidation tag through.
|
||||
BUILD_VERSION_GD: Path = REPO_ROOT / "client" / "scripts" / "build_version.gd"
|
||||
|
||||
# The wire codec, which decides which planes EXIST client-side.
|
||||
#
|
||||
# Added 2026-08-16 after T-1213 proved the omission expensive: this file's decode
|
||||
# dictionary was missing `relief_q`, so the plane never reached the renderer and
|
||||
# the deep rungs rendered flat for weeks. The gate would not have flagged the fix,
|
||||
# because the registry only covered ui/.../step_canvas/ and this lives under
|
||||
# scripts/protocol/.
|
||||
#
|
||||
# It belongs here for a second, sharper reason: the disk cache stores the DECODED
|
||||
# canvas, so a decode change alters what a cached entry contains. Entries written
|
||||
# before that fix have no relief_q key at all and keep rendering flat until the
|
||||
# version moves — exactly the stale-cache class this registry exists to catch.
|
||||
STEP_CANVAS_PROTOCOL_GD: Path = (
|
||||
REPO_ROOT / "client" / "scripts" / "protocol" / "step_canvas_protocol.gd"
|
||||
)
|
||||
|
||||
|
||||
def _rust_sources(directory: Path, label: str) -> tuple[Path, ...]:
|
||||
"""Every .rs file in `directory`, collected by glob and fail-closed."""
|
||||
@@ -127,6 +143,7 @@ def canvas_sources() -> tuple[Path, ...]:
|
||||
SEED_RS,
|
||||
*_gdscript_sources(CLIENT_STEP_CANVAS_DIR, "client step_canvas"),
|
||||
BUILD_VERSION_GD,
|
||||
STEP_CANVAS_PROTOCOL_GD,
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user