A script scanned every tracked doc, rule, skill, agent, hook and source file
for tooling/ paths that no longer exist, skipping historical records (sprints,
discussions, workshops, governance, generated wiki pages). It found 62. The
ones that tell a reader what to RUN now name the reach verb:
- The atlas skill still sent agents to tooling/atlas, atlas-verify,
atlas-update-field and atlas-commit-and-sync — about forty lines, all
retired in T-1285. They now name the `reach atlas` verbs, and the skill
records that commit-and-sync STAGES by default (--commit to commit) and
takes --corridor as an option.
- The clerk agent named tooling/clerk-review (now `reach dev clerk`). The Si
and clerk briefings sent those agents to the retired tooling/db/decision
and sqlite-query CLIs and to decisions/*.md paths that moved to
governance/ in the pql migration. They now name pql.
- The ticket-cli rule documented `pql decisions read`, which does not exist;
`show` already includes the body.
- The culture authoring guide and the RON sources name
`reach validate ron`, with the same arguments as before.
- The 41 Blender payloads' usage lines ran the retired tooling/blender
wrapper, and the docstrings still cited pre-carve-out paths. They now read
`reach blender run <payload>`.
- Doc comments in server/, client/, wiki TOMLs and the domain modules.
What is left is deliberate: "Formerly …" provenance, dated plans and findings
docs, the retired-pipeline doc, and a build-artefact path.
project.yaml 0.4.14 (mirrored to the client). Comment-only, but four touched
files are in the canvas-version registry (trait_catalog_reader.rs, since
T-1289, canvas_sources.py itself, and two client files). The gate is
path-based and has no override. The previous push was rejected on exactly
this.
Three of the edits are stamped ledger sources, so systems.db is regenerated
and the stamp is fresh.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`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>
project.yaml's version is the Atlas disk cache's only invalidation signal, and
nothing enforced that changing canvas GENERATION also moved it. It broke five
times -- 0.4.2 lake_margin_q, 0.4.3 coast_warp_px, 0.4.4 the extent inversion,
0.4.5 the Global sentinel, 0.4.6 one-course-per-river -- each bumped only after
someone noticed a wrong map. The failure is invisible to its author: it needs a
warm cache to reproduce, so a cold checkout looks fine. T-1239 is the last one,
and it took eight days.
tooling/canvas_sources.py is the path registry; tooling/check-canvas-version
rejects a push that touches those paths without moving project.yaml's version
line. Wired into the pre-push hook, `make check-canvas-version`, and, for the
parsing units, `make test-tooling`.
Verified against real history rather than a synthetic branch: run over
4e503c356 -- the commit that actually caused T-1239 -- the gate rejects and names
the three files. Run over the commits that DID bump (bdea71953, 39f0fd8c5, and
T-1239's own fix), it passes.
The registry is globbed, not hand-listed. step_canvas.rs imports ten sibling
modules and those import more, so a traced closure would be stale within a month,
and stale here is silent. It over-includes on purpose: a false positive costs one
bump and one round of cache misses, a false negative costs another week of a
wrong map -- the ticket's own ruling.
Two deliberate calls worth naming. The registry includes ITSELF, which closes the
narrowing hole: remove a path and change that same path in one push, and the gate
still fires because the registry file is in the set. And there is no override
flag -- it would be reached for exactly when someone is certain their change is
harmless, which is the reasoning behind all five regressions.
Version bumped 0.4.6 -> 0.4.7 with NO canvas-generation change: self-inclusion
means adding the registry trips its own rule. Spent rather than special-cased,
because the first exception is how a rule like this dies.
The units cover the property no branch run can show -- that editing project.yaml's
comment block, which quotes old version NUMBERS directly above the field, is not
a bump -- plus a registry-coverage test naming the files each of the five known
regressions touched, so a future narrowing past them fails loudly.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>