Files
settled-reach/project.yaml
T
jpmschweitzerandClaude Opus 5 48fee8a0b6 feat(config): make the canvas-generation/version pairing a gate, not a habit (T-1242)
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>
2026-08-15 00:06:32 +02:00

89 lines
4.9 KiB
YAML

name: The Settled Reach
# Version scheme: 0.{phase}.{n} — phase = active Development Cascade phase (D-166).
# Phase 4 (deterministic world generation) is active.
# 0.4.1-tagged step canvases carried lake_margin_q's flat absolute-ceiling
# semantics (pre-per-basin-normalization) and were written to real disk
# caches during T-1188 eyeball runs — 0.4.2 forces those entries to miss.
# 0.4.2-tagged Global/Region-rung step canvases sampled the coastline
# position raw (no coast_warp_px) — T-1160 applies the warp at orbital
# sampling, changing orbital-rung canvas bytes (elev_q/temperature_dc/
# moisture_q shift near coasts) — 0.4.3 forces those cached entries to miss.
# 0.4.3-tagged canvases predate the D-255 extent inversion (a rung now fixes
# the canvas EXTENT and the gridunit spacing falls out, rather than the
# reverse). District/Quarter/Block/Chunk kept the same 960x540 cell counts
# through that change, so their cache keys are byte-identical while a District
# canvas now covers 3.6 km of ground instead of 1,966 km — a warm cache would
# silently serve pre-inversion canvases. 0.4.4 forces those entries to miss.
# 0.4.4-tagged GLOBAL canvases are all 2x1 — `serve_step_canvas_request` was
# still zeroing Global's wire extent (a pre-extent-inversion sentinel), so
# every Global request resolved to a two-cell canvas regardless of viewport.
# Those entries were also cached under a key that ignored extent, so they
# answered every later request forever. 0.4.5 forces them to miss.
# 0.4.5-tagged canvases carry pre-T-1237 river courses: one course per D8 HOP
# rather than one per river (build_paths walks whole headwater->mouth rivers
# now). The hop-shaped entries survived that fix because it changed only server
# and client code, never this version — so Ferrath Global replayed 375 fragments
# with a 106 km longest run, all of them below D-261's read-as-a-line floor, and
# drew NOTHING, while a cold cache on the same build produced 73 whole rivers
# with a 1,644 km trunk and drew 18. Diagnosed as T-1239. 0.4.6 forces them to
# miss.
#
# THE PATTERN, now four bumps deep: a change to how a canvas is GENERATED is
# only half the change — the other half is this line. Nothing enforces the
# pairing, so a canvas-generation commit that leaves this version alone ships a
# silent regression that reproduces only on machines with a warm cache. The
# capture harness no longer hides it (tests/run-visual isolates user:// per run,
# T-1239), but a real player's cache is still governed by this number alone.
# 0.4.7 carries NO canvas-generation change — it is the gate that enforces the
# pairing described above, arriving (T-1242). tooling/canvas_sources.py lists the
# paths, tooling/check-canvas-version rejects a push that touches them without
# moving this line, and the registry includes ITSELF so that narrowing it and
# changing a canvas file in one push still demands a bump. That self-inclusion is
# why this bump exists: adding the registry trips its own rule. The version is
# spent rather than special-cased, because "this change is obviously harmless" is
# the reasoning that produced all five regressions above.
version: 0.4.7
repository: settled-reach
description: >
Top-down life-sim set in an original science fiction universe. Asymmetric
information and occlusion-based perception from a single-character
perspective, with a Rimworld-style storyteller. Systems interactions like
The Sims, combat and visuals like single-character Rimworld, world
generation inheriting from Dwarf Fortress and NMS, economy inspired by
X4/EVE. Every system is interactable but ignorable — the world is alive
for any given run.
setting: >
The Settled Reach — a network of star systems connected by Founder Gates.
Neural lattice technology enables soft immortality, forking, and
re-embodiment.
development: >
Built outside-in along the six-phase Development Cascade (D-166): wiki
content and star map, economics layer, planetary maps and atlas,
deterministic world generation (active), player control and in-world
rendering, room-level detail.
architecture:
client: Godot 4 (GDScript)
server: Rust with bevy_ecs (simulation server)
transport: subprocess/IPC via TCP with MessagePack serialization
protocol: length-prefixed MessagePack frames (4-byte big-endian)
determinism: ChaCha20 seeded RNG, deterministic tick processing
simulation:
tick_rate: 10 ticks per game-minute
time_model: 4 day phases (Morning, Afternoon, Evening, Night)
grid: dual-scale (0.5m simulation tiles, 1m visual tiles)
visibility: symmetric shadowcasting + forward/peripheral/blind vision cone
knowledge: per-entity knowledge graphs with confidence decay
content:
format: YAML with JSON Schema validation
structure: campaigns/systems/stations/districts hierarchy
npcs: 10-axis model (7 essential + 3 supporting) with CombatCapability
dialogue: tagged line pools with 4-layer relational filtering
population: 30% flat / 50% mundane triangles / 20% intrigue-entangled