Commit Graph
100 Commits
Author SHA1 Message Date
jpmschweitzerandClaude Fable 5 0c91ef28ba feat(simulation): D-252 — Facing is view-only; NPC gaze moves to path-follow intent (T-1093)
apply_move no longer writes Facing (was the only movement-facing coupling,
player-only); the player's view changes solely via explicit SetFacing.
NPC path-follow now sets Facing to the step direction — a strict improvement
recorded as a D-252 correction: NPCs previously never received Facing from
movement, their cones sat at spawn direction while walking. Bump-to-turn
retired (blocked moves change nothing) with a regression test for each
semantic. Wire schema unchanged; player_facing docs now say view/aim.
Gauntlet fixtures regenerated (facing octants now reflect view-only
semantics); client replay + live-roundtrip suites green against the new
server.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 21:07:18 +02:00
jpmschweitzerandClaude Fable 5 629c0a9b1e feat(client): D-252 view/movement split — body from leg velocity, view is the mouse (T-1093)
D-252 (new record, amends D-054/D-249, resolves Q-084's walk-vs-aim split):
Facing is view-only; movement no longer writes it. Client side: the rig's
moving-body yaw now always derives from leg velocity (the wire octant is the
VIEW and must never rotate the body — the follow-only commit flag
generalizes and disappears); the layered head/torso look-at runs during any
movement, WASD included; the ~100ms post-step re-assert mitigation is
removed as dead (server-side facing_from_delta removal lands separately).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 20:59:06 +02:00
jpmschweitzerandClaude Fable 5 6453f71220 fix(client): re-assert mouse facing after each follow step — vision-cone flap mitigation (T-1088)
Live finding: during a path-follow the cone snapped to path-forward on every
accepted step (server facing_from_delta overwrites Facing; the change-gated
SetFacing never re-sends an unchanged octant) and stayed there until the
mouse crossed an octant boundary. The follower now re-asserts the current
mouse octant 100ms (~2 ticks) after each emitted step — same-tick re-asserts
lose, movement wins within a tick — shrinking the flap to a ~100ms blip.
Full stability needs server-side aim-lock: filed T-1093 (Q-084's walk-vs-aim
split, now with play evidence); wire semantics untouched per the sidequest's
presentation-layer constraint.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 20:44:52 +02:00
jpmschweitzerandClaude Fable 5 cb6b39331d feat(client): follow-facing — body commits to path, mouse drives layered head/torso look-at (T-1088)
During an RMB path-follow the body yaw locks to the leg direction (rig
commit_body_to_motion, from interpolated velocity — immune to SetFacing
interleaving between throttled steps). The mouse instead drives a layered
look-at: LookAtModifier3D pair on Head (±70°) + spine_02 (±30° torso twist
for looking far lateral/behind — past their sum the character physically
cannot look further without turning). Forward axis measured from the
armature rest pose (+Z), not guessed. Influence fades in/out on follow
start/end. Pure client presentation per D-249; SetFacing still rides the
wire, so the server vision cone follows the mouse while walking — the
character looks where the player points.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 20:35:43 +02:00
jpmschweitzerandClaude Fable 5 72f88dae1d fix(client): median-of-5 timing in fog perf test — kills load flake (T-1092)
test_visibility_texture_update_performance asserted a single wall-clock
sample against the 0.5ms budget and blocked two pushes while a live session
shared the machine (0.704ms / 0.623ms; 46/46 green in isolation). Median of
5 runs preserves the D-059 budget intent while absorbing load spikes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 20:18:01 +02:00
jpmschweitzerandClaude Fable 5 6372537f2f fix(client): bottom-wall scan pierces 2-thick walls + corner diagonal; whole-box quantized cuts (T-1088)
Live-session findings, three in one: (1) Gauntlet walls are 2 tiles thick —
the outer row's camera-far neighbor is the inner WALL, so its flag stayed 0
and it stood full-height behind the collapsed inner stub; the flag now scans
up to 3 tiles through consecutive KNOWN walls (unknown stops the scan — no
assumptions past the info boundary), and any newly-learned tile refreshes the
wall chain behind it. (2) Corner pillars at the screen-bottom junction never
collapsed — their interior floor sits DIAGONALLY behind, which no straight
scan line reaches; the combined diagonal joins the scan set. (3) Per-fragment
smoothstep falloff carved organic notches (the 'sphere' read) — the cut now
computes per-instance in the vertex shader from the box's tile center and
quantizes at 0.5: every wall box is either full or stub, X2-crisp.

Verified via locomotion_cutaway autopilot capture: south runs read as clean
stub rows, corners collapse, camera-far walls stand.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 20:10:28 +02:00
jpmschweitzerandClaude Fable 5 ae04091f93 chore(meta): live-session decision trail — cutaway modes, RMB gestures; governance index sync
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 19:52:25 +02:00
jpmschweitzerandClaude Fable 5 49c8994943 feat(client): move-here path preview + RMB gesture vocabulary (T-1088, Q-084)
Hover marker + optimal path line over the KNOWN tile store only — the
character plans through what they know; fog is unpathable (info boundary at
the planning layer; the follower additionally revalidates every remaining
tile per step). Pure static 8-dir A*: uniform cost 1 incl. diagonals (D-248
time-optimal, no sqrt2), no corner-cutting, terrain-cost provider seam for
Phase-4 terrain. Execution streams ordinary Move* steps through the existing
throttle — zero protocol change, server validates every step.

RMB vocabulary (live-session spec): click = walk there at current stance;
double-click = sprint there (ToggleStanceUp burst — server toggle handler
verified cooldown-free so bursts climb deterministically — with net-zero
restore on arrival; a double upgrades the active follow in place);
long-press >=400ms = go there then Crouch on arrival, no restore (input-
vocabulary prototype; real cover mechanics are future combat design).
Cancellation: WASD override (stance kept), invalidation, teleport,
suppression. Two additive InputMapper seams (queue_move_step,
queue_stance_toggle); mouse unproject shared with the facing provider
(ground_hit_local). 44 new gdUnit tests across finder + follower ladders.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 19:52:03 +02:00
jpmschweitzerandClaude Fable 5 98032e9d5a feat(client): cutaway defaults to mode 2 (both) — user verdict from the live session (T-1088)
Known interiors open at a glance (bottom walls low) AND the sightline
corridor punches through unexplored exterior walls; C still cycles modes.
sandbox_constants.gd also carries the path-preview/gesture knobs for the
click-to-move feature landing in the next commit (single tuning file).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 19:51:38 +02:00
jpmschweitzerandClaude Fable 5 e32a041778 feat(client): cutaway modes — corridor / bottom-walls-low / both, C-key live toggle (T-1088)
Live-session two-minds resolution: the trippy sightline corridor stays as a
mode (candidate signature look); mode 1 drops any wall with a KNOWN non-wall
tile on its camera-far side to the stub (X2 bottom-walls read — the player
sees the room without walking to it); mode 2 combines. Bottom-wall flag rides
MultiMesh INSTANCE_CUSTOM.r, updated on paint and when newly-learned floors
promote camera-ward walls; camera-far directions derived from the live
WorldRoot basis, never hand-derived. Default stays corridor pending the
feel verdict.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 19:16:14 +02:00
jpmschweitzerandClaude Fable 5 2db7dd25e1 fix(client): cutaway cuts the camera-character sightline corridor, not a proximity dome (T-1088)
Live-session finding: the half-disc cut bit nearby side walls while leaving
the wall actually occluding the character at full height, with dome-contour
scallops across the two-row walls. Rewritten as a sightline corridor: walls
within CUT_CORRIDOR_HALF_W of the character's x, camera-side, out to a
pitch-derived reach (WALL_H / tan(pitch) — how far a wall can still occlude
in ortho; ~4.3 m at -30, breathes with the T-cycle tilt) drop to the stub.
FollowCamera3D exposes pitch_deg(); reach clamped 0.5-16 m.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 19:01:49 +02:00
jpmschweitzerandClaude Fable 5 b09a50efbf fix(tooling): depth-only epsilon bias for the clip discriminator + corrected findings
The pass-B garment shift is now a depth-only bias in the vertex shader (no
screen-space parallax), eliminating silhouette-growth false positives. This
supersedes the previous commit's mid-run numbers: final peasant run is
33/72 clip flags, ALL genuine tight-proximity findings — 0/18 on front
views (discriminator proof), sleeveless armhole seams on average_f (side),
deep-crouch waist gap (back, worst 150px), collar nape. Bare-arm-crossing-
torso cases correctly reclassed exposed_skin (non-gating). Sensitivity
knobs: clip_epsilon_m (3cm) + --min-pixels (8), tuned to surface tight
seams; calibrate against the first real modern garments.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 14:59:32 +02:00
jpmschweitzerandClaude Fable 5 74fa16260d feat(tooling): two-pass clip discriminator for garment QA (T-1089)
Second garment-only render pass per view at the identical paused animation
time; the analyzer intersects so body-key pixels split into exposed_skin
(no garment behind — informational: collars, sleeveless arms) vs
clip_through (garment behind — gating). Highlights differ: lime exposed,
red clip. Peasant re-run: 72 captures, 56 clip-through flags — real
collar micro-clips under crouch/walk plus suspected 1px boundary
artifacts; gate threshold + garment-mask dilation are the tuning knobs,
to be calibrated against the first real modern garments.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 14:51:04 +02:00
jpmschweitzerandClaude Fable 5 eaca6c8c44 feat(tooling): chromakey garment-clipping QA harness (T-1089)
Automated garment-under-animation QA: CharacterVisual composite with the
garment's covered body segments overridden to flat unshaded magenta, cycled
clips x frames x 4 yaws; PIL analyzer flags connected key-pixel blobs and
emits report.json + highlighted failure frames. Capture scene lives under
client/tools/garment_qa/ (res:// boundary; outside the gdUnit scan root),
driver/analyzer/config under tooling/garment-qa/.

Verified: 72 captures across peasant set x average_m/f x Walk/Sprint/
Crouch_Fwd. Finding: no true mid-cloth clip-through; flags are coverage-claim
vs silhouette mismatch (sleeveless/short-sleeve exposure at collar/cuffs) —
a two-pass garment-behind-pixel discriminator is the queued refinement.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 14:26:58 +02:00
jpmschweitzerandClaude Fable 5 e5657179b5 docs(governance): D-248..D-251 — locomotion presentation, facing authority, cutaway decoupling, character-route reconfirmation
D-248 (architecture): per-leg constant-velocity interpolation keyed to the
stance throttle; cadence-synced gaits; one smoothing layer per channel;
annotates D-054 (its 100-150ms tween scoped to the 2D renderer).
D-249 (architecture): 'server feet, client eyes' facing split with the
verified octant-to-yaw table and the set_facing() trap note.
D-250 (perception): wall cutaway is client camera presentation, decoupled
from fog-of-perception; fog-memory-for-geometry nuance parked for Phase 5.
D-251 (content): Quaternius rig reconfirmed after full 2026 re-evaluation;
Synty intake technically proven then product-rejected; in-house wardrobe
routes; UAL paid tiers close the animation gap; revisit tripwires recorded.
Annotations: D-148 editorial note (preset list authoritative; stepped camera
yaw needs a record), Q-020/Q-063/Q-079/Q-084 updates.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 14:07:27 +02:00
jpmschweitzerandClaude Fable 5 4bcd778e16 chore(assets): Synty intake spike — scripts, evidence logs, verdict data (T-1089)
Bridge-C evidence spike: unitypackage extraction, rest-pose recon, garment
transplant onto the Quaternius rig (Data Transfer POLYINTERP_NEAREST), 11-body
batch fit, Godot QA scenes. Technical PASS; route nonetheless REJECTED by
product call (cost, baked body-segment modularity, style) — full trail on
T-1089. Salvage: source-agnostic transplant/batch-fit scripts (the G1-family
pipeline for any donor mesh) and the T-1090 discovery (5 body types misrender
bare). Extracted vendor payload (spikes/**/raw/) now gitignored.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 14:01:24 +02:00
jpmschweitzerandClaude Fable 5 a7801a942a feat(client): 3D locomotion sandbox — character walks the live Gauntlet (T-1088)
New SR_LIVE sandbox scene: CharacterVisual composited in a 3D greybox world
derived from server snapshots. Per-leg constant-velocity interpolation keyed
to the stance throttle, 'server feet / client eyes' facing (wire octant while
moving, client aim octant idle), cadence-synced gait state machine on
AnimationPlayer custom blends, D-148 orthographic follow camera (-30deg
default, T-cycle presets), sim-space grid shader, camera-side wall cutaway,
accumulating never-evict tile store with four-state visibility tint.

Additive seams only: InputMapper.facing_angle_provider (2D path unchanged),
CharacterVisual.play_animation blend_time param + get_animation_player().
Visual harness gains per-scenario scene field + SR_AUTOPILOT input scripting.
210 new gdUnit assertions across five suites; verified live (230/230 total,
clean smoke, screenshot at .cache/screenshots/locomotion_idle_live.png).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 13:23:16 +02:00
jpmschweitzerandClaude Fable 5 ce1811b5f9 chore(meta): T-1088/T-1089 sidequest planning — tickets, route decisions, T-1090/T-1091 findings
Locomotion + clothing sidequest bookkeeping: T-1088 (locomotion sandbox) and
T-1089 (clothing engine + basic set) with full decision trail (Xenonauts-2
reference, cutaway scoping, style pins, Synty route rejection after the
evidence spike), T-1090 (5 body types misrender bare — blocks T-1089),
T-1091 (Rigify skin-bind log noise).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 13:22:57 +02:00
jpmschweitzerandClaude Opus 4.8 3dc9cc431c chore(meta): close T-1084/T-1085 (done), file T-1086/T-1087 follow-ups
PR #172 merged. T-1084 (mosaic) + T-1085 (biosphere register) → done. Remaining T-1085 work split into T-1086 (propagate Linnaeus to bodies.proper_name) and T-1087 (Forest/Wetland biome palettes + introduced-Earth register + §8 material follow-up).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 19:47:04 +02:00
jpmschweitzerandClaude Opus 4.8 895bb83bad fix(simulation): unify C1 climate gate across Wetland+Forest+Grassland (PR #172 N1)
Tyre's re-review found the C1 !Barren guard only covered the Grassland arm — the Wetland arm was an unconditional => true. Since derive_morphology_zone has no temperature gate, a frozen + wet + flat district still yields Wetland material, so the wetland palette would paint copse/bog onto frozen marsh: the exact C1 symptom via the material path. Not a regression (the arm was unchanged) and unreachable by the 2 harness bodies, but the D-246 amendment + the voxel.rs comment already claim the guarantee universally, so the gate must match the claim.

Gate is now: apply = !Barren && class in {Wetland, Forest, Grassland}. Behavior change is limited to frozen/hyper-arid Wetland districts (a temperate marsh is never Barren-dominant; Forest is Barren-free by construction). believability.json unchanged (neither harness body reaches the frozen-wet case). New regression test mosaic_pass_does_not_revegetate_frozen_wetland; D-246 amendment reworded to the unified gate. Full cargo test green; clippy -D warnings clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 19:12:05 +02:00
jpmschweitzerandClaude Opus 4.8 48fb749ee9 chore(skills): de-pin git-commit attribution trailer
The mandatory Commit Message Format block hard-coded 'Claude Opus 4.6', which stayed stale for months after the model moved on. Replace with the generic 'Co-Authored-By: Claude <noreply@anthropic.com>' and note that the harness-appended model-identifier variant is equally valid. Pinned versions are the root cause of this drift class (CLAUDE-CLEANUP.md section 4).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 17:52:17 +02:00
jpmschweitzerandClaude Opus 4.8 0a96d6eb83 chore(meta): update changelog — micro-habitat mosaic + biosphere register
Player-facing entries for the T-1084 intra-class mosaic and T-1085 native biosphere register shipped in this branch (D-246/D-247). Describes the shipped post-review behavior, so the never-released C1/H1 bugs need no separate Fixed lines.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 17:52:01 +02:00
jpmschweitzerandClaude Opus 4.8 c17b4f5442 fix(simulation): address PR #172 review — C1 over-vegetation + H1 biosphere gate (T-1084/T-1085)
Hoshe + Tyre review of the micro-habitat-mosaic branch requested changes on two
data-confirmed correctness bugs plus follow-through. All addressed.

Blocking:
- C1 (voxel.rs): the mosaic re-granted vegetation the climate withheld — a frozen
  ice world (Edict) read 61% vegetated tundra. The Grassland apply-gate now fires
  only where the climate already grants cover (!Barren); a climatically-barren
  district (frozen < -50C = surface ice/geology D-239 §2, or hyper-arid moisture<5,
  both resolved to VegetationClass::Barren upstream) is skipped. Genuine tundra
  (cold + moisture>=15) is Scrub upstream and still reaches the tundra palette via
  the same !Barren path. believability.json regenerated: Edict vegetated_districts
  39->0, Arbour 20->8 (its real cold-pole/arid districts revert to barren);
  intra-class variety preserved (Arbour vegetation_classes 3, micro_habitat_distinct 2).
- H1 (bodies.py): biosphere Gate 0 keyed on `inhabited`, conflating settlement with
  biosphere and force-Airless'ing uninhabited-but-alive worlds (D-247: worlds were
  alive before humans). Gate 0 is now settlement-independent — keyed on
  atmosphere/hydrosphere/planet_class. 24 uninhabited-alive worlds now classified
  (was 0); GJ0g-1 (dense atm + rivers) -> NativeMirror. Split 122 Compatible :
  121 Mirror; all 9 canon exemplars hold.

Follow-through:
- C2 (bodies.py + D-247): Gate 0 now reads planet_class (barren -> Airless) as
  D-247's "+ planet_class" phrasing names. D-247 amended to record the actual
  two-gate signal set (atm/hydro/planet_class habitability; economic_base_primary
  chirality; settlement-independence).
- C3 (believability.rs): micro_habitat_distinct criterion relaxed to `== 0 || >= 2`
  — the min-over-patches estimator makes K=3 unreachable against a dominant-entry
  palette; K=2 provisional, Q-123 calibrates.
- C4 + H2 (D-246): amended to record the v1 scope cut — only the Soil-derived
  vegetated/wet classes take the mosaic; material-driven families are `_ => false`
  so Hardpan/Scree are authored but unreachable in v1; no elevation change in v1;
  the mosaic OWNS the §8 climate->vegetation law for the classes it touches.
- H3 (voxel.rs): three dedicated mosaic-pass regression tests — C1 barren-respect,
  §8 material-untouched + forest-textured, T-1040 no-water-without-channel.
- H4 (voxel.rs): relief_signal comment corrected to ~[-1,+1].
- H5 (bodies.py): frontmatter override now strips quotes + validates against the
  4-value enum (warn-and-skip on typo).

systems.db regenerated + stamped (H1). believability golden regenerated (C1).
Full cargo test green; clippy -D warnings + ruff clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 17:46:19 +02:00
jpmschweitzerandClaude Opus 4.8 b71df601b2 chore(meta): T-1085 workstream progress bookkeeping
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 12:57:04 +02:00
jpmschweitzerandClaude Opus 4.8 cc7c5ada04 feat(db): biosphere_class authoring pipeline + values (T-1085 workstream 3, D-247)
The D-247 chirality/edibility register as authored data on every body, via the
stamped regen-db path (import_economics) — not a manual bake.

- systems-schema.sql + migration.py: nullable bodies.biosphere_class column.
- economy_import/bodies.py: populate_biosphere_class — reads the authored
  environment.biosphere_class frontmatter override, else the D-247 two-gate default
  (Gate 0 habitability from atmosphere/hydrosphere/inhabited; Gate 1 Compatible/Mirror
  from economic_base_primary; neutral remainder -> stable ~50/50 split). Recomputes
  every body each regen (frontmatter + default are its complete source).
- import_economics.py: wired as import step 17.
- frontmatter overrides for the bodies whose default deviates from canon:
  Solandar=NativeMirror, GJ-524=NativeMirror (uninhabited-but-alive), Ha Long=
  NativeCompatible (its transit economy hides its aquaculture identity). Linnaeus,
  Arbour, Oshima, Freyburg, Puerto Ultimo, Edict all default correctly.

systems.db regenerated + stamped. All 9 canon exemplars verified; distribution is
111 Compatible : 108 Mirror among inhabited alive worlds (~50/50 target), Airless for
uninhabited bodies, TerraformedSterile for thin-atmosphere worlds.

Follow-up (rename completion): propagating Linnaeus to bodies.proper_name in the DB
(still "Cadwal" — proper_name is atlas-CLI-owned, and a wipe+reimport would drop
non-proposal columns like founding_age_years; needs a targeted approach).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 11:56:52 +02:00
jpmschweitzerandClaude Opus 4.8 5fb34675eb feat(simulation): grassland biome-awareness + alien-ecology vocab (T-1085 workstream 4, D-246)
The mosaic palette gains a climate-biome dimension for the Grassland surface-class:
savanna / temperate / boreal / tundra now read distinctly rather than collapsing to
one biome-blind palette (the D-246 biome-awareness fix).

- atlas/mosaic.rs: ClimateBiome (from temperature_c + moisture_q) + four biome-keyed
  Grassland palettes; palette(class, biome). Savanna carries scattered Forest copses,
  tundra carries lichen + sparse bare ground and no forest. §8-safe (veg + water only).
- atlas/voxel.rs: derive the biome; a cold barren district (tundra/boreal) now takes
  the sparse mosaic rather than staying blank — worlds that read "0 vegetated / blank"
  now read structured-sparse (D-245 climate-appropriateness). vegetated_districts
  8→20 and 0→39 on the cold validation bodies.
- data/mosaic_constants.toml: biome-keyed grassland mirror.
- docs/design/alien-ecology-vocabulary.md: Miri's full biome × register naming layer
  (the cane/vane/wrack/husk/drum-root native lexicon + Earth-register names) — the
  derived-label source for the palette and Phase-5 rendering.

Believability golden regenerated. Full server suite green. Forest biomes and the
introduced-Earth register are the noted continuation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 20:30:33 +02:00
jpmschweitzerandClaude Opus 4.8 388168eef5 content(wiki): T-1085 biosphere continuity + Cadwal→Linnaeus rename (D-247)
Operationalize the D-247 native-biosphere premise in the wiki (workstreams 1-2).

Chirality continuity — additive clauses making each world's biosphere_class
legible without contradicting existing prose:
- GJ-524 (Mirror): the "no indigenous hazard" world has no indigenous *nutrition*
  either — mirror-handed, inedible/inert; its promise is Earth-crop suitability.
- GJ-166A / Keid (Compatible): names the stakes the charter defends — Linnaeus's
  biology is edible/cultivable/exploitable, which is *why* it is preserved.
- GJ-684A / Freyburg (Compatible): "robust but non-competitive" = compatible
  chemistry, outcompeted by bred cultivars — not inert.
- GJ-124 / Hạ Long (Compatible): the two-generation "learn to farm" was learning
  which native (chirality-compatible) organisms to harvest — a genuine alien crop.
- GJ-197 / Puerto Último (Compatible): native life is edible in its own right;
  farming leaned on trusted introduced cultivars.

IP fix — the Keid conservancy world was named "Cadwal", Jack Vance's exact book
title (same narrative role). Renamed **Linnaeus** (the great classifier; pairs
with its neighbour Solander/Solandar). Capital stays "Vance" (the author tribute).
Renamed in the body frontmatter (+ biosphere_class: NativeCompatible), the
GJ-166A infobox, and the atlas proposal; D-247 clarified. The systems.db bake
(workstream 3) will propagate the DB + regenerate the infobox authoritatively.

Solandar and Oshima need no continuity edit (already canon-consistent).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 22:39:20 +02:00
jpmschweitzerandClaude Opus 4.8 31b553a3b3 feat(simulation): intra-class micro-habitat mosaic v1 — vegetation/water texture (T-1084, D-246)
Sub-chunk mosaic that modulates the D-228 axes into a spatially-coherent,
relief/moisture-conditioned mosaic of micro-habitats within a terrain class —
the fix for the aliveness probe's uniform "Wetland 100%".

- seed.rs: SeedDomain::VoxelMosaic = 12 (append-only; pinned-discriminant guard)
- voxel.rs: five new D-228 axis values (Vegetation::{Meadow,Deadfall,Lichen},
  TerrainMaterial::{Hardpan,Scree}); the per-family-gated mosaic pass
- detail_scatter.rs: voxel_mosaic() selection field (~8-64 m band)
- atlas/mosaic.rs: surface-class palette + integer-basis-point weighted selection
  with moisture-affinity conditioning; temperate/native baseline palettes
- data/mosaic_constants.toml: source-canonical palette mirror
- believability.rs: micro_habitat_distinct metric + D-245 intra-class criterion

v1 scope (D-246-faithful): modulates vegetation + water only, in the vegetated
classes (Wetland/Forest/Grassland), so the D-239 §8 lithology law is untouched;
water is gated on the T-1040 has_active_channel hydrology rule. Material variants
(hardpan/scree) and the extreme classes are a §8-aware follow-up; the biome-aware
palette variants (T-1085 vocab) extend the baseline before generation.

Goldens regenerated (believability + derivation). Full server suite green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 10:42:20 +02:00
jpmschweitzerandClaude Opus 4.8 cf80c1e1b5 docs(decisions): add D-246 micro-habitat mosaic + D-247 native biospheres (amend D-228)
D-246 (architecture): intra-class micro-habitat mosaic — a voxel_mosaic()
sub-chunk noise band modulates the D-228 axes into spatially-coherent,
relief-conditioned micro-habitats; palette keyed on surface-class ×
climate-biome × biosphere-register; five new D-228 axis values front-loaded
for determinism; within-patch believability metric in scope. Governs T-1084.

D-247 (content): habitable Reach worlds were alive before humans — the
settlement timeline forbids terraforming from dead rock. An authored per-world
chirality bit gates whether native life is edible (Compatible) or
inedible-but-inert (Mirror); "safe" and "edible" are decoupled; colonization
is ecological war that grows an Earth-crop footprint outward from settlements.
Grounds D-246's native-vs-introduced register.

D-228 amended: +Vegetation{Meadow,Deadfall,Lichen}, +TerrainMaterial{Hardpan,Scree}.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 22:29:23 +02:00
jpmschweitzer 9753fcb48e gitignore fix and ticket bookkeeping 2026-07-02 11:28:49 +02:00
jpmschweitzerandClaude Opus 4.8 677de42bd2 fix(simulation): make voxel relief sub-district + fix integration-test fallout (T-1081)
The push gate's integration tests (not in cargo test --lib) caught two regressions
from the relief change:

- derivation_harness::cross_district_elevation_blend_reduces_seam_step — the relief's
  large per-position term (span 300 → ±200 m, far above the compressed elev_q/2 base)
  swamped the T-1042 seam measurement and clamped heavily at sea level. Fixes:
  (1) shift the voxel-relief octave band to 0.13–1 km (all sub-district, dropping the
  2 km octave that competed with elev_q's district role); (2) reduce VOXEL_RELIEF_SPAN_M
  300 → 100 so relief stays mostly below the base (fewer sea-level clamp artifacts,
  proportional hills); (3) rewrite the seam test's avg_elev to average over an 8 km
  multi-wavelength y-transect so the zero-mean relief cancels, isolating the base seam.
- derivation_harness::golden_seed_determinism_regression — legitimate golden refresh
  (determinism still holds; elevation values changed intentionally).

Believability relief now ≈22 m mean (was 5 m flat; 59 m at the over-aggressive span 300)
— navigable hills without clamp artifacts, 7/8 criteria. Both goldens regenerated; full
cargo test (38 binaries) + clippy --all-targets -D warnings green. D-239 amendment +
Q-123 item 4 updated to the final span/octave/numbers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 21:43:39 +02:00
jpmschweitzerandClaude Opus 4.8 dc1d905ce0 chore(meta): T-1081 -> done (voxel-relief merged)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 21:23:38 +02:00
jpmschweitzerandClaude Opus 4.8 1eb098129b fix(simulation): pin SeedDomain::VoxelRelief discriminant + record T-1081 review notes
T-1081 review (Hoshe + Tyre): the seed_domain_discriminants_are_pinned test (the
D-224 guard that fails CI if a variant is renumbered — which would silently re-roll
every world's relief field) did not pin the new VoxelRelief = 11. Add the assertion.

Also fold Tyre's two Q-123 calibration notes into item 4: (i) sanity-check the
slope_q*3 + elev_q envelope on a synthetic high-slope body (both terms cap at 100);
(ii) the relief transect is a single diagonal slice (fine for isotropic fBm, revisit
if an anisotropic ridge field is added).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 21:18:01 +02:00
jpmschweitzerandClaude Opus 4.8 b70b11a66a chore(meta): T-1081 -> review
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 20:52:37 +02:00
jpmschweitzerandClaude Opus 4.8 ab6e1413d9 feat(simulation): voxel-tier mid-scale relief — navigable hills (T-1081)
The voxel tier read flat (the D-245 "0–3 m, no hills to navigate by" bug):
family generators set elevation from elev_q at a compressed scale plus only ±4 m
micro-scatter, and detail-scatter's mid-scale relief (D-243 §2) only ever reached
the district tier (elev_q), never per-voxel elevation_m.

- detail_scatter.rs: extract the enveloped-fBm core; add `voxel_relief` at the
  0.25–2 km octave band (vs the district 4–40 km band).
- voxel.rs: add the mid-scale relief post-dispatch in derive_voxel_column, body-global
  SeedDomain::VoxelRelief seed (position-keyed), f64 truncated to integer metres (D-010).
  Envelope = slope_q*3 + elev_q — the coarse heightmap gives slope_q ≈ 0 even on high
  ground (Arbour max 13), so elevation must drive ruggedness. Flat families only
  (Alluvial/Lava/BraidedDelta/Dune/Meander); the dramatic families already carry strong
  internal relief and WaterBody stays at sea level.
- seed.rs: SeedDomain::VoxelRelief (D-224 domain separation).
- believability.rs: new `contrast.voxel_relief_m` metric — mean within-district elevation
  range over a 2 km transect (a single 64 m sample chunk is narrower than the relief
  band) + a "voxel relief" criterion.

Arbour @ yolo: voxel relief 5 m → 59 m, 6/8 → 7/8 criteria (remaining fail = the
Q-123 vegetation-denominator item). Edict 59 m. Golden regenerated; 1586 lib tests +
believability harness (determinism) pass; clippy -D warnings clean.

D-239 amended (T-1081); Q-123 item 4 updated. Deferred to Q-123/follow-up: the
provisional span + threshold, and a per-body hypsometric absolute-elevation model.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 20:41:59 +02:00
jpmschweitzerandClaude Opus 4.8 dcc422f0d8 chore(meta): T-1083/T-1082/T-1080 -> done (believability stack merged)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 18:03:09 +02:00
jpmschweitzerandClaude Opus 4.8 f771c9ce4e fix(simulation): address believability-stack review — all findings processed
Stack review (Hoshe + Tyre) of T-1083+T-1082+T-1080. Every finding fixed or disposed:

- believability.rs sample_indices: replace the rejection-sampling loop (could stall
  when n ≈ take) with deterministic partial Fisher-Yates — O(n), guaranteed
  termination, distinct, sorted (Hoshe+Tyre).
- believability.rs drainage proxy: exclude water-body districts (all elev 0, no banks)
  and require both wet + dry voxels — they were passing vacuously and inflating the
  metric (Hoshe).
- believability.rs read_cities: log skipped malformed rows instead of dropping silently
  (Hoshe).
- voxel.rs: add the 3 WaterBody zones to all_families_no_panic_at_extreme_positions +
  fix the "7 families" comment (Hoshe).
- climate_constants.toml: bold warning that [moisture_gradient] is not loaded until
  T-1032 — tune ClimateConstants::default() (Tyre).
- Q-123: record the per-zone "water renders wet" threshold + the land-relative
  vegetation-present denominator as calibration items (Tyre + the open 7th criterion).
- T-1083 ticket: note the sampling-fix attribution (landed in the T-1082 commit).

Believability golden regenerated (sampler + drainage fixes moved the metrics).
clippy --all-targets -D warnings clean; 1580 lib tests + harness pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 17:41:03 +02:00
jpmschweitzerandClaude Opus 4.8 bb5069aa13 feat(simulation): district moisture spatial gradient (T-1080)
moisture_q was a single body constant (derive_moisture_q took only &BodyParams →
80 for every one of 2048 ocean-world districts), so vegetation/terrain/ecotones
were uniform — "nothing to fuzz" (the T-1080 believability bug).

- district_profile.rs: derive_moisture_q is now a body ceiling (hydrosphere+atmosphere)
  × per-district gradient — latitude (equator wet → pole dry), elevation (orographic/
  rain-shadow), continentality (100 − ocean_fraction_q). Integer/D-010, no new plumbing
  (elev_q/ocean_fraction_q/latitude_deg already reach build_district_profile). Mirrors
  D-240's temperature model. Coefficients in ClimateConstants + climate_constants.toml
  [moisture_gradient] (provisional; Q-123 calibrates). Tuned so a wet body stays mostly
  green with drier patches and a frozen body clamps mostly barren. + gradient unit test.
- region_profile.rs: region-tier moisture gets the region-latitude gradient (elevation/
  continentality are district-scale).
- Propagates to precipitation_class / vegetation_class / morphology_zone (all read
  moisture_q). D-239 §2 amended. Believability golden regenerated.

Probe (Arbour @ yolo): moisture_q distinct 1 → 49 (spread 0 → 48); 5/7 → 6/7 criteria.
Edict (frozen): moisture 0..20 ×21 — gradient within its low ceiling. Remaining fail
(vegetation-present) is the metric dividing by all-sampled incl. water on a 2/3-ocean
world — a Q-123 calibration concern, not a climate defect.

clippy --all-targets -D warnings clean; 1580 lib tests + harnesses pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 17:25:18 +02:00
jpmschweitzerandClaude Opus 4.8 cdc55032df feat(simulation): WaterBody voxel family — oceans/lakes/tidal flats render wet (T-1082)
The water zones (OpenOcean/Lake/TidalFlat) fell through to the dry-land AlluvialPlain
fallback, so the sea rendered as dry forested land (the D-245 believability bug).

- voxel.rs: new MorphologyFamily::WaterBody (9th family) + generate_water_body,
  dispatched from zone_to_family. Deep open water with a Shallow shoal band on the
  district-anchored coast line (wider for shallower bodies); TidalFlat all-Shallow.
  Seabed Rock (steep) / Sand (gentle) / Wetland (tidal mud); Vegetation::Barren;
  water surface elevation_m = 0; seasonal Ice via derive_cover (frozen seas). Wetland
  stays AlluvialPlain (it is land — a marsh, not open water). Integer/D-010. + 4 tests.
- believability.rs: fix a sampling bias in the T-1083 enforcer found while verifying
  this — the metrics sampled the first 64 districts in BTreeMap order (a spatial corner,
  e.g. all-ocean), which reported a forested world as "0 vegetated". Now a deterministic
  seeded spread across the body (matches D-245's "randomly-sampled locations").
- D-239 amended (§5 8→9 families; §6 refined — the 3 water zones now dispatch to
  WaterBody). Believability golden regenerated.

Probe (Arbour @ yolo): water-renders-wet 4/64 FAIL → 42/44 PASS; terrain-material
variety 1 → 4 PASS; 3/7 → 5/7 criteria. (Remaining fails — moisture gradient,
vegetation-present — are T-1080.)

clippy --all-targets -D warnings clean; 1579 lib tests + the harness pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 15:30:25 +02:00
jpmschweitzerandClaude Opus 4.8 ed2c9853be chore(meta): record T-1083 implementation note (believability enforcer)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 14:56:40 +02:00
jpmschweitzerandClaude Opus 4.8 91a079718b feat(simulation): believability test protocol — D-245 enforcer (T-1083)
Promote the throwaway aliveness probe into a committed, repeatable believability
protocol — the instrument that found T-1080/T-1081/T-1082.

- atlas/believability.rs (new): BelievabilityReport (serde) + analyze() computing
  CONTRAST (per-field min/max/distinct for moisture/elev/slope/ocean over all
  districts; distinct morphology zones / vegetation classes / terrain materials)
  and COHERENCE (water-renders-wet, drainage-monotonic, vegetation-present) — never
  marginal per-tile counts (the lesson: that called a broken uniform world ALIVE).
  evaluate_criteria() = advisory D-245 checks; cascade_for_body()/seed_to_u64()
  loader shared by the bin and the harness. Unit tests prove the metric tells a
  uniform world (fails) from a varied one (passes) + determinism.
- bin/aliveness_probe.rs: refactored to a thin CLI over the module — prints the
  body-level report + advisory D-245 criteria, drops the naive per-tile verdict.
- tests/believability_harness.rs (+ golden): runs the real cascade for Arbour
  (temperate/ocean) + Edict (frozen/ice), asserts determinism, golden-snapshots
  the reports (regression — updates when T-1080/T-1082 land), advisory criteria
  with BELIEVABILITY_STRICT=1 to fail on unmet D-245 criteria. Skips if committed
  data absent. x86_64 golden (cascade has f32 warp paths).

Baseline @ believability-v1: Arbour 3/7, Edict 3/7 criteria pass — moisture
gradient, water-renders-wet, drainage all FAIL (T-1080/T-1082); Edict vegetation
0/64 (blank tundra — the frozen 'reads dead' case D-245 targets).

PNG layer maps (ticket item 3) deferred — explicitly optional; the contrast +
coherence metrics are the core enforcer.

clippy --all-targets -D warnings clean; 1575 lib tests + the harness pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 14:55:08 +02:00
jpmschweitzerandClaude Opus 4.8 528cd5d5f5 chore(meta): T-987 -> done (PR #171 merged)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 11:12:37 +02:00
jpmschweitzer cf746e505b Merge remote-tracking branch 'origin/fillchunk-shell-derive' 2026-06-28 10:50:55 +02:00
jpmschweitzerandClaude Opus 4.8 7597e3165e fix(simulation): address PR #171 review — all findings processed (T-987)
Every review finding fixed (no non-blocking parking lot):
- shell.rs: debug_assert the D-110 floor-range i8 invariant (H1); clarify the
  ground_offset fallback comment (T1) and the roof_z None-case (T3); clarify the
  sub-chunk clip test comment (T4); add a test for the elevated/no-ground-floor
  fallback (H2).
- scale.rs: add CHUNKS_PER_BLOCK (= BLOCK_M/CHUNK_M) + compile-time asserts; used
  by shell.rs fill_chunk's sub_chunk bounds assert (T5).
- gen_queue.rs: document why FillChunk's Vec<BuildingPropertyTag> needs no Box
  (large_enum_variant non-issue) (T2).

clippy --all-targets -D warnings clean; 1572 lib tests pass (+1).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 10:24:30 +02:00
jpmschweitzerandClaude Opus 4.8 e3dcf57054 chore(meta): T-987 -> review (PR #171)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 08:29:10 +02:00
jpmschweitzerandClaude Opus 4.8 a46946e2ac docs(meta): read the pql skill before non-trivial planning-store ops
settled-reach is always a pql repo, so make the rule repo-canonical (CLAUDE.md +
ticket-cli.md): routine ticket/decision CLI is covered by the rules, but the
load-bearing model lives only in the pql skill — changelog is write-through (never
git-restore it), `export` doesn't replicate ticket_idmap, post-checkout rebuilds
pql.db from the changelog, so cross-branch planning moves must re-create via
`pql ticket`, not changelog surgery. Back up pql.db before risky ops.

The clide-side equivalent (read the clide skill when running inside clide) is an
editor choice, not a repo property — it belongs in a clide-owned SessionStart hook,
not here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 08:15:23 +02:00
jpmschweitzerandClaude Opus 4.8 936563c1a3 docs(meta): keep Bash commands short/simple for the permission gate
Add an agent-scope rule: one operation per Bash call; avoid long pipelines,
chained commands, nested subshells, and intricate one-liners that the
permission system rejects as "too complex to approve cleanly".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 07:59:52 +02:00
jpmschweitzerandClaude Opus 4.8 c95f9d9a70 docs(governance): D-245 nature-layer believability acceptance gate + believability epic (T-1079..T-1084)
Lock the cascade's nature-half deliverable to "reads alive anywhere", not
"implemented" — the holy-grail objective surfaced by probing the generation
cascade.

- D-245 (architecture): the nature layers are accepted only when the
  believability litmus passes at randomly-sampled locations across all
  habitable bodies/seeds — multi-scale + never-repeating (macro identity,
  meso non-stationarity, micro mosaic), coherence + non-stationarity +
  intra-class variety + relief + climate-appropriateness, automated screen
  under a human sign-off, budgeted -> strict. Q-123: threshold calibration.
- T-1079 (epic, north-star, DoD=D-245) + findings T-1080 (uniform climate
  fields), T-1081 (near-zero relief), T-1082 (no water-body generator),
  T-1084 (intra-class micro-habitat mosaic), and T-1083 (the repeatable
  believability test protocol / D-245 enforcer).
- aliveness_probe bin: the exploratory probe that found these (runs the
  deterministic cascade for a body+seed, reports per-district nature +
  verdict). Seed for T-1083.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 07:59:34 +02:00
jpmschweitzerandClaude Opus 4.8 5f85dc55d5 feat(simulation): FillChunk shell derivation — Void/Wall/FloorSlab/Roof from cached tags (T-987)
Implement the D-230 on-demand derive phase (data-production half). New
atlas/shell.rs derives a sparse building shell for one 64 m chunk from the
plan-phase BuildingPropertyTags: rectangle-containment (footprint ∩ chunk) ×
z-range (per-floor voxel bands from FloorExtent), in a quarter-ground z frame
(D-110). Walls on the footprint perimeter, FloorSlab on interior floor bases,
Roof above the top floor; interior air is Void and never stored.

- gen_queue.rs: GenWorkItem::FillChunk carries pre-resolved block_tags +
  block_pos + sub_chunk (run_work_item stays cache-free, mirroring
  GenerateSkeleton); GenCompletion::ChunkFilled carries Box<FilledChunk>; the
  arm calls shell::fill_chunk; pure build_fill_chunk_item(&QuarterWorldState,..)
  added.
- plugin.rs: ChunkFilled handler accepts the shell (trace-only — the Phase-5
  rendering consumer and the on-demand streaming dispatch trigger are deferred;
  do not build on legacy chunk_streaming.rs before Phase 5, gated by T-962).

Tests: determinism, sparsity-vs-dense-volume, wall/floor/roof correctness,
basement z-origin, sub-chunk clipping, full submit→drain→ChunkFilled round-trip.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 23:34:46 +02:00
jpmschweitzerandClaude Opus 4.8 85311f716c chore(meta): T-1044/T-1047 -> done (PR #170 merged)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 10:14:43 +02:00
jpmschweitzerandClaude Opus 4.8 efa1dadfea Merge PR #170: cache TerrainAnalysis + basin_direction from D8 thalweg (T-1044, T-1047)
Reviewed by Hoshe + Tyre; Tyre approved, Hoshe's 2 findings addressed (test coverage + comment).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 10:14:29 +02:00
jpmschweitzerandClaude Opus 4.8 7c09f23b9a test(simulation): cover the Some(basin_dirs) threading + clarify on-demand default (T-1047)
Addresses PR #170 review (Hoshe H1/H2).

H1: the Some(basin_dirs) path through derive_all_districts was untested (tests
only used None). Added derive_all_districts_threads_supplied_basin_directions
(synthetic per-district directions propagate to DistrictProfile.basin_direction;
unmapped districts fall back to North), and added basin_direction to the cascade
determinism loop so the full run_layer1->district chain is guarded.

H2: clarified the derive_district on-demand comment — the North default is an
accepted limitation (a fallback, not a computed value); the batch path threads
the true D8 direction.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 10:11:55 +02:00
jpmschweitzerandClaude Opus 4.8 62a60b6c50 Merge PR #169: ratify 3D asset direction (D-244) + repurpose sprite-gen, reconcile sprite-era decisions
Reviewed by Tyre + Hoshe; findings addressed (D-148/D-149 precedent + D-043/D-044/D-049/D-066 amendments + doc fixes).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 09:51:53 +02:00
jpmschweitzerandClaude Opus 4.8 7d45d78674 chore(meta): T-1044/T-1047 -> review (PR #170)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 09:48:21 +02:00
jpmschweitzerandClaude Opus 4.8 0263b68df9 feat(simulation): cache TerrainAnalysis + derive basin_direction from the D8 thalweg (T-1044, T-1047)
T-1044: run_layer1 now returns TerrainAnalysis (carried transiently on
CascadeSnapshot, dropped after the district + road-graph passes), eliminating the
redundant per-body drainage::analyze + TerrainAnalysis::analyze re-run flagged by
PERF/TODO(T-1044). Not persisted on the LRU-cached state (D-203/T-1048 size concern).

T-1047: basin_direction is now derived from the real D8 thalweg. run_layer1
aggregates a per-district dominant D8 direction from the live fdir grid (carried
transiently on DrainageResult), threaded via Layer1Output.district_basin_dirs ->
derive_all_districts -> DistrictProfile.basin_direction; derive_chunk_context reads
it directly. Removed the false derive_basin_direction (it branched on ocean_fraction_q
then read seed bits despite a doc comment claiming an elev_q/slope_q D8 proxy) +
corrected the module contract. D-239 §8 (D8 thalweg) now actually honoured.

1559 tests pass; golden byte-identical (district_basin_dirs is #[serde(skip)], transient).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 09:46:42 +02:00
jpmschweitzerandClaude Opus 4.8 ae7606ed83 docs(governance): address PR #169 review — reconcile sprite-era decisions + doc fixes
Tyre: D-244 now references its precedent (D-148 3D camera / D-149 live 3D characters
— D-244 completes that pivot for objects + assets) and reconciles the 5 sprite-era
decisions it touched, all amended 2026-06-17:
- D-043: 'not 3D' / Light2D scoped to overlay layers; in-world is 3D.
- D-044: sprite footprint retired (sim occupancy + visual hierarchy survive).
- D-049: z-stack logical model survives; sprite/CanvasLayer implementation language retired.
- D-066: dual-scale coordinate model + 2x2 geometry minimum survive; sprite-footprint language legacy.

Hoshe (doc QA):
- D-244 broken cross-file anchors fixed ([D-159]->scope.md, [D-241]->process.md).
- renderer/README: bare [D-244] linked; D-019->D-148 camera note; legacy banner over the
  object-sprite workflow sections; resolution-chain output path qualified.
- docs/assets/_templates/sprite.md + README: marked the template legacy object-sprite schema
  (model/texture/artwork template TBD).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 09:40:41 +02:00
jpmschweitzerandClaude Opus 4.8 dae1498a6f docs(assets): ratify 3D asset direction (D-244); repurpose sprite-gen as 2D-artwork generator
D-244 ratifies what the character architecture (D-159..D-164, runtime
CharacterVisualDescriptor compositing) and the Trellis env pipeline already implied
but no decision had recorded: the in-world view renders 3D objects directly; the only
flattened 2D content is textures + flat 2D artwork (paintings/flags/billboards/signage).
There is no per-object sprite layer.

Roots out the drift: the early-spike 3D->2D sprite pipeline (#541) and the sprite-centric
docs/assets/visual catalog were never cleaned out when the project went 3D, so the
2026-06-12 fable-ous audit read them as live and re-injected the dead sprite model into
T-1049/T-1050. Fix:
- docs/assets/visual/README.md + docs/assets/README.md re-scoped to 3D models + textures
  + flat artwork (dropped the sprites/tilesets-as-entities framing).
- /sprite-gen + renderer/README repurposed as the 2D-artwork generator (paintings/flags/
  billboards/signage), not the in-world object format; legacy 4-direction object-sprite
  mode flagged as retired.
- T-961/T-1049/T-1050 already held in backlog pending this.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 22:36:13 +02:00
jpmschweitzerandClaude Opus 4.8 e3327a0d01 chore(meta): hold asset track — T-1049/T-1050 -> backlog (needs sprite->3D re-scope)
Separated the asset pipeline from the cascade work. T-1049/T-1050 assume a sprite-centric
catalog; direction is 3D objects (Trellis .glb) in-world with textures as the only
flattened content. Held for re-scope. Cascade track (T-1044/T-1047) continues.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 16:03:49 +02:00
jpmschweitzerandClaude Opus 4.8 711ac65d20 chore(meta): activate Phase-4 batch — T-1044/T-1047 (cascade) + T-1049/T-1050 (assets)
Two parallel tracks with refinement appends: T-1044+T-1047 compose on the run_layer1
pass (TerrainAnalysis cache + per-district D8 basin_direction); T-1049+T-1050 are the
asset-pipeline track (per-class story breakdown + catalog/manifest/conventions + glb-gen
path). Staleness corrected (T-1047: basin_direction threads through DistrictProfile, not
the post-T-1077 RegionProfile).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 15:42:26 +02:00
jpmschweitzerandClaude Opus 4.8 718a97cda6 chore(meta): T-1039/T-1043 -> done (PR #168 merged)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 13:05:04 +02:00
jpmschweitzerandClaude Opus 4.8 387ee1b4c2 Merge PR #168: L3→L4 dispatch threading — political_archetype / morphology_zone / road_entry_directions (T-1039, T-1043)
Reviewed by Hoshe + Tyre; Hoshe's 2 findings addressed, Tyre approved.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 12:56:35 +02:00
jpmschweitzerandClaude Opus 4.8 2d85f8ca3c chore(config): align branch post-checkout with main's do-nothing version
Reconciles the branch's earlier export --stage hook (d2cbdc243) with main's
superseding do-nothing fix (b24a3596b) so the two merge cleanly instead of
conflicting on this file. (The hook fix is already live on main; this just keeps
the branch copy identical.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 12:51:33 +02:00
jpmschweitzerandClaude Opus 4.8 43aadc4491 fix(simulation): address PR #168 review — fallback diagnostic, parity coverage, doc (T-1039)
Hoshe H1: the morphology_zone AlluvialPlain fallback fired silently. Now logs
tracing::debug! when the district grid is empty (expected: params-missing body /
early cascade) and tracing::warn! when a populated grid misses the key (indicates a
pixel->district convention bug) — no more silently-wrong topology.

Hoshe H2: the arrangement_pattern parity tripwire only covered transit_hub with
Commission + Corporate. Added Pioneer/Industrial/Military/Academic rows so an
accidental archetype-conditionalization of the cross-archetype override is caught.

Tyre (non-blocking): clarified the build_skeleton_work_item doc — the
arrangement_pattern re-derivation call lives in generate_quarter_skeleton (the
consumer), not in this function.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 12:51:27 +02:00
jpmschweitzerandClaude Opus 4.8 b24a3596b5 fix(config): post-checkout does nothing on same-HEAD instead of export --stage
Refines 34ffcda86. The export --stage approach preserved the mutation but did more
than the bug needs: it eagerly stages changelog rows mid-checkout (surprising in
git status), and those staged rows can leak onto the wrong branch when a later
switch rebuilds by replaying the working-tree changelog.

Minimal fix: on a branch *creation* / no-op checkout (prev-HEAD == new-HEAD) the
working tree is unchanged, so pql.db already holds the committed state plus any
uncommitted mutation — just skip the whole block (do nothing). The mutation stays
in pql.db untouched and the next commit's pre-commit hook flushes it normally. Only
a real branch *switch* (prev != new) rebuilds. No git-index side effects, no leak.

Verified: same-HEAD invocation preserves an uncommitted status mutation and stages
nothing. (Credit: pql-clide's review of the upstream feature request.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 12:42:08 +02:00
jpmschweitzerandClaude Opus 4.8 34ffcda86f fix(config): post-checkout preserves uncommitted pql mutations on branch creation
The post-checkout hook ran 'pql plan rebuild' (drop + replay changelog) on every
branch checkout, including 'git checkout -b'. That silently dropped any pql.db
ticket mutation not yet in the committed changelog — e.g. an in_progress status set
right before cutting a feature branch (hit this session: T-1039/T-1043 reverted to
backlog at branch creation).

Git has no pre-checkout/pre-worktree hook, so capture the changelog at post-checkout
instead: when prev-HEAD == new-HEAD (a branch *creation* — content unchanged, pql.db
already correct), run 'pql plan export --stage' (the same flush the pre-commit hook
does) instead of the destructive rebuild. Real branch *switches* (prev != new) still
rebuild to match the branch's changelog.

Verified: simulating a same-HEAD checkout with an uncommitted in_progress mutation now
preserves it (previously reverted).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 12:23:28 +02:00
jpmschweitzerandClaude Opus 4.8 d2cbdc2431 fix(config): post-checkout preserves uncommitted pql mutations on branch creation
The post-checkout hook ran 'pql plan rebuild' (drop + replay changelog) on every
branch checkout, including 'git checkout -b'. That silently dropped any pql.db
ticket mutation not yet in the committed changelog — e.g. an in_progress status set
right before cutting a feature branch (hit this session: T-1039/T-1043 reverted to
backlog at branch creation).

Git has no pre-checkout/pre-worktree hook, so capture the changelog at post-checkout
instead: when prev-HEAD == new-HEAD (a branch *creation* — content unchanged, pql.db
already correct), run 'pql plan export --stage' (the same flush the pre-commit hook
does) instead of the destructive rebuild. Real branch *switches* (prev != new) still
rebuild to match the branch's changelog.

Verified: simulating a same-HEAD checkout with an uncommitted in_progress mutation now
preserves it (previously reverted).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 12:05:19 +02:00
jpmschweitzerandClaude Opus 4.8 a3c3929c4e chore(meta): activate T-1039/T-1043 + board cleanup (T-960->backlog, T-1038->done)
T-1039/T-1043 in_progress + refinement appends (the locked arrangement_pattern
re-derive + RoadGraph-source decisions). Board hygiene: T-960 (Atlas map viewer)
parked since 2026-06-07 -> backlog; T-1038 (Layer 2 road graph) full scope landed
on main (c0d4ac89d) and consumed by T-1043 -> done.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 11:42:35 +02:00
jpmschweitzerandClaude Opus 4.8 9c8ad83071 feat(simulation): thread political_archetype/morphology_zone/road_entry_directions through L3->L4 dispatch (T-1039, T-1043)
Completes the GenerateSkeleton dispatch T-1022 wired (which only carried
founding_orientation). build_skeleton_work_item now also threads:

T-1039:
- political_archetype — real value from CityPlacement, replacing the Commission stub.
- morphology_zone — looked up from the covering DistrictProfile via new
  scale::heightmap_pixel_to_district (exported HEIGHTMAP_CELLS_PER_DISTRICT;
  cascade.rs drops its local CELLS_PER_REGION literal for the shared const).
- arrangement_pattern — RE-DERIVED at L4 (option b) via the single pure fn
  attractor_matching::arrangement_pattern(&archetype, &economic_role); both
  inputs already at L4. No CityGenerationContext field, no stored derived state
  (DB-as-cache). Parity test asserts L4 re-derivation == L3-stored value.

T-1043:
- road_entry_directions — derived from T-1038's BodyWorldState.road_graph:
  octant = bearing of each incident road edge, deduped per octant, ordered by
  MaintenanceAuthority rank (the AdminFacing prestige-edge consumer). Feeds
  derive_access_points -> AccessKind::QuarterEdge; BlockJunction fallback now
  fires only for genuinely isolated settlements.

Acceptance covered: Corporate+Fjord -> Ribbon topology (not mesh+Commission);
settlement with a road -> QuarterEdge on the correct octant. 11 new tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 11:34:22 +02:00
jpmschweitzerandClaude Opus 4.8 f98297d136 chore(meta): T-1042/T-1078 -> done (PR #167 merged)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 17:42:32 +02:00
jpmschweitzerandClaude Opus 4.8 2acab55b2a Merge PR #167: D-243 region-tier finish — region climate stack + cross-district blending (T-1078, T-1042)
Reviewed by Hoshe + Tyre; all findings addressed, T1 wiring re-reviewed (APPROVE).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 17:40:56 +02:00
jpmschweitzerandClaude Opus 4.8 ff5e7ee944 fix(simulation): VoxelCache precondition doc + sec_phase decontamination + cache blend test (T-1042)
Addresses PR #167 review (Hoshe H1/H2/H3, Tyre T2).

H1 — the VoxelCache 'same (seed, body_id, tile_pos) -> same column' invariant
is no longer unconditional after the T-1042 blend (the key omits blend_weight/
secondary). Replaced with an explicit precondition on the struct + get_or_derive:
the caller must pass the ChunkContext of the chunk that contains the tile.

H2/T2 — sec_phase claimed to be 'position-independent' but mixed in
primary_meander_phase/2 (the primary's per-position seed), making the secondary
phase proxy asymmetric and primary-contaminated. Dropped that term; sec_phase is
now the secondary's own morphology scalars (slope_q + moisture_q), with a comment
honestly naming it a bounded cosmetic approximation and where to thread the real
secondary seed if needed.

H3 — added cache_boundary_tile_blend_is_stable: derives a boundary ChunkContext
(blend_weight=128, secondary=Some), calls get_or_derive twice, asserts a cache
hit + identical blended elevation + that the Cow::Owned blend path actually ran.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 17:30:46 +02:00
jpmschweitzerandClaude Opus 4.8 d974cf42b0 fix(simulation): wire region baseline into production district temp + rename latitude field (T-1078)
Addresses PR #167 review (Tyre T1, T3).

T1 — the region climate tier was built but no live path consulted it: both
derive_district_profile (cascade) and derive_district (on-demand) passed
region_baseline_c: None, so the D-243 §4 edge-fuzz blend was dead in production
and district temperature was still derived from scratch. Now both paths compute
region_baseline_at_district(...) and pass it through build_district_profile so
the two-phase modulation (D-243 §3) actually runs. The cascade path
(derive_all_districts) builds a BTreeMap<RegionPos, RegionProfile> covering all
district positions + their +/-1 neighbours once per body and looks up from it;
the on-demand path derives the four surrounding region baselines on the fly.
No production path passes None except genuinely airless bodies (no planet_class).

T3 — renamed BodyParams.district_latitude_deg -> latitude_deg (it is the region
centre latitude in the region fns, a call-site trap under the old name);
dual-scale doc; propagated to body_params_reader.rs and all literal sites.

Golden fixtures are unaffected (they construct districts directly via make_region,
bypassing build_district_profile) — derivation_harness 37/37 green, no re-pin.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 17:30:33 +02:00
jpmschweitzerandClaude Opus 4.8 568370b7c2 fix(client): space proof moves past the stance cooldown — test_proof_corner_reveal flake (T-1037)
test_proof_corner_reveal drove moves back-to-back. The Gauntlet player is
Walk stance (ticks_per_move=2, server stance.rs), so a move arriving within
the cooldown window is silently throttled (movement.rs::apply_move ->
PlayerMoveCooldown::try_move). _send_and_receive returned the instant a move
landed, so the next send raced the cooldown and an occasional move was
dropped — leaving the player one tile short, which (via the test's cumulative
expectations) cascaded into the corner-reveal perception assert. A different
move dropped each run = flaky; exposed by the heavier post-cascade tick timing.

Test-side fix only — game behaviour is correct and the Gauntlet world is
immutable: after a move lands, wait for the server clock to advance
COOLDOWN_TICKS past the landing tick before the next send. Full client suite
2538/2538 green; the proof suite drops from ~28s (timeouts) to ~4s.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 16:24:13 +02:00
jpmschweitzerandClaude Opus 4.8 0bcc57d213 chore(meta): T-1042/T-1078 -> review (Batch A code-complete)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 14:06:03 +02:00
jpmschweitzerandClaude Opus 4.8 32010cc498 feat(simulation): cross-district parameter blending at chunk/voxel scale (T-1042)
Replaces the single-DistrictProfile walking-skeleton restriction so
continuous terrain parameters no longer step at the 2 km district pitch
(D-239 §4/§7/§8). ChunkContext gains secondary: Option<DistrictProfile> +
blend_weight: u8; derive_chunk_context detects a chunk within one chunk of
a district border, looks up the adjacent profile, and integer-blends
meander/channel params on the context. derive_voxel_column integer-blends
elev_q/moisture_q before material selection, reusing the same warp offset so
the seam cannot align with the chunk edge (Cow fast-path keeps interior
chunks bit-identical — golden seed unchanged).

Morphology FAMILY selection is never blended — stays sharp per D-239 §7
(family dispatch reads the primary district only). Climate feathering is the
separate T-1078 path. Adds cross_district_elevation_blend_reduces_seam_step
and cross_district_morphology_family_seams_stay_sharp to the derivation
harness.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 14:05:48 +02:00
jpmschweitzerandClaude Opus 4.8 030e0907bc feat(simulation): region climate tier — baseline + district modulation + edge fuzz (T-1078)
Introduces the region (~205 km) climate tier per D-243 §3/§4, above the
DistrictProfile carrier. New region_profile.rs: RegionProfile/RegionClock,
derive_region_baseline_c (latitude lerp + greenhouse, D-240 class-envelope,
no orbit/star inputs), and region_baseline_at_district — the D-243 §4
edge-fuzz warp-perturbed bilinear blend of surrounding region baselines so
the ~205 km grid is invisible in the output.

Splits district temperature (D-243 §3): derive_district_temperature_c now
modulates the region baseline with elevation lapse only, replacing the
from-scratch per-district derivation. build_district_profile takes an
Option<f32> region baseline; None preserves the legacy single-phase path
(existing call sites unchanged). derive_cover (voxel.rs) consumes the
post-refactor value with no signature change.

Region clock (season/weather) scaffolded; transient tick callbacks deferred
to Q-105 per the two-phase convention. 14 region_profile + 5 district
modulation tests added.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 14:05:37 +02:00
jpmschweitzerandClaude Opus 4.8 fcc9fcc4ec chore(meta): activate Batch A — T-1042/T-1078 in_progress, T-1046 done
/whats-next batch activation for the D-243 region-tier finish.
Refinement briefs (Si pass) appended to T-1042 and T-1078 reconciling
their 2026-06-12 scope against the post-T-1077 tree. T-1046 (Region→
Chunk→Voxel wiring) flipped to done — already committed in cfd5e18d0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 14:05:25 +02:00
jpmschweitzerandClaude Opus 4.8 cfd5e18d0a feat(client): district morphology generation overlay in the Atlas (T-1046, D-226)
Client half — the cascade's district tier is now visible in the Atlas map.

- protocol.gd: decode the district_grid field from AtlasLayerResponse.
- atlas_viewer.gd: a gen_district ('MRPH') toggle in OVERLAY_DEFS + the
  district-grid generation state (set/get) + wire it from the Ready response.
- atlas_marker_overlay.gd: _draw_gen_district() paints the coarse cols×rows grid,
  each cell coloured by its MorphologyZone discriminant (D-239 §6, 17-zone
  palette), semi-transparent under the Layer-1 line overlays. Planetary map view
  (not the 2km on-demand districts — those are Phase 5 in-world).

gdUnit4 test: overlay registered + district grid round-trips through the viewer
and the protocol decode. Visual tuning of the palette can follow once eyeballed
in the running Atlas.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 12:55:59 +02:00
jpmschweitzerandClaude Opus 4.8 d03b4d1e09 feat(simulation): serve the coarse district/morphology grid through the Atlas proxy (T-1046)
Server half of wiring the derived tier into production. The D-225 proxy
(AtlasLayerResponse) carried only Layer1Output, so the Atlas could not show the
DistrictProfile tier that the cascade derives. Adds DistrictGridLayer (cols/rows
+ row-major MorphologyZone discriminants + elev_q for relief shading) and
build_district_grid(), populated on a cache hit. Because the response is
rmp_serde msgpack end-to-end, the new field reaches the client automatically.

This is the planetary-scale coarse grid (the Atlas map view); the on-demand 2km
derive_district (T-1077) is for in-world Phase 5, not the map. MorphologyZone
gains Copy (fieldless repr(u8) enum; additive).

Next: client decode (protocol.gd) + the D-226 generation overlay in the Atlas
viewer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 12:30:47 +02:00
jpmschweitzerandClaude Opus 4.8 d1fa785678 chore(meta): T-1077 -> review (D-243 re-scale code-complete)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 10:49:40 +02:00
jpmschweitzerandClaude Opus 4.8 e96ed0e9e4 feat(simulation): detail-scatter synthesis + on-demand 2km derive_district (T-1077)
Phase 3 of the D-243 re-scale — the corrected 2km carrier and its 'stretch
magic'.

- detail_scatter.rs: the mid-scale terrain (2-40km) invented between coarse
  heightmap samples. Locked character (T-1077): ADAPTIVE (ruggedness follows
  local slope/morphology -> gentle flats, rugged highs) + ENVELOPE+MODULATION
  (heightmap relief caps amplitude; morphology flavors within). Deterministic
  seed+position value-noise (D-227/D-010); C1-continuous, no lattice creases.
- derive_district(): the on-demand 2km carrier. Maps the district to a
  fractional heightmap pixel via body_radius_km (the elastic seam, D-204),
  bilinearly interpolates the L1 envelope, composes the scatter, derives the
  profile. body_radius None falls back to direct indexing (tiny test bodies).
- Factored build_district_profile() (climate+morphology tail) shared by the
  cell-aggregate and interpolation paths.

5 scatter tests + 5 derive_district tests (determinism, latitude->climate via
the seam, the envelope rule, radius fallback). Full suite + clippy -D warnings
green; existing goldens untouched (additive).

Scope: T-1077 delivers the corrected on-demand 2km derivation + scatter. The
eager-grid -> on-demand region/district production + Atlas surfacing (decision
A) is T-1046's chartered job (derive_all_districts stays the coarse Atlas grid
for now, documented).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 10:00:01 +02:00
jpmschweitzerandClaude Opus 4.8 b3b5bfc2e3 refactor(simulation): rename carrier RegionProfile->DistrictProfile + re-scale to the D-243 ladder (T-1077)
Phase 2 of the D-243 re-scale. The ~1km carrier is renamed and re-scaled to
the 2km district, and every consumer reads scale from the canonical scale.rs
instead of a local literal.

- region_profile.rs -> district_profile.rs; RegionProfile -> DistrictProfile,
  RegionPos -> DistrictPos (re-exported from scale::DistrictPos), derive_*_regions
  -> derive_*_districts, across all 10 consumers + the derivation harness.
- chunk_context now references scale:: for the carrier cell: district 1024m -> 2048m,
  shift 4 -> 5 (CHUNK_DISTRICT_SHIFT). This caught a real latent bug: the seed-district
  index used a literal '>> 4' while the anchor used the constant, so same-district
  chunks could derive different anchors — now both use scale::CHUNK_DISTRICT_SHIFT.
- derivation_harness scale literals ('>> 4', '* 1024', '0..16') converted to
  scale:: constants (the same drift the canonical source eliminates). Believability
  tests pass at 2km; the voxel determinism golden re-pinned (anchors moved with the
  re-scale — deterministic, intended).

Full suite + clippy --all-targets -D warnings green. The district DERIVATION still
tiles the heightmap at 8 cells (the old coarse path); replacing it with on-demand
heightmap interpolation + detail-scatter is phase 3.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 22:53:18 +02:00
jpmschweitzerandClaude Opus 4.8 38054d4b12 feat(simulation): canonical spatial scale ladder + body_radius_km (T-1077)
First phase of the D-243 re-scale. Adds server/src/atlas/scale.rs as the
single source of truth for the metric containment ladder (voxel 1m -> chunk
64m -> block 128m -> quarter 512m -> district 2048m -> region 204.8km), the
fixed integer addressing (ChunkPos -> DistrictPos -> RegionPos), and the
elastic seam regions_per_equator(R). Compile-time const asserts enforce the
nesting so the rungs cannot silently drift again — the structural fix for the
Q-110 failure mode (three files, three different region sizes).

Wires body_radius_km (D-204) through BodyParams + the reader: the single
body-specific input to the elastic seam.

No behavior change — foundation only. The rename/re-scale of the carrier
(RegionProfile -> DistrictProfile) and on-demand district derivation follow.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 22:04:50 +02:00
jpmschweitzerandClaude Opus 4.8 e39ba89064 docs(governance): D-243 spatial scale ladder — resolve Q-110, Region→Province
Resolves Q-110 (region/chunk physical-scale anchoring), which had three
contradictory metres-per-scale assumptions in the cascade and no record
fixing metres-per-heightmap-pixel.

D-243 establishes a nested absolute-metre containment ladder with a single
elastic seam at planetary scale:
  voxel 1m -> chunk 64m -> block 128m -> quarter 512m -> district 2km
  -> region ~205km (100x100 districts) -> (elastic) -> planet
A body holds round(2*pi*R/204.8km) regions (the only per-body-floating
quantity); everything below is fixed integer math, so ChunkPos->RegionPos
is body-independent. The region is the largest hard block: the climate/
weather/season lockdown scale (the Q-105 cheap-dynamism source) and the
sane planetary grid. Sub-heightmap detail is invented deterministically
(interpolation + domain warp + detail-scatter, never stored, D-227); climate
is edge-fuzzed so the grid never shows ('climate does not change on a line').

Vocabulary locked and recorded in CLAUDE.md: 'region' = the 205km metric
cell only; the old 1km RegionProfile is dropped onto the 2km district; D-201
tier-4 'Region' renamed Province (the watershed/political overlay), amended
here. Refines D-239 §2 (district temperature now modulates a region baseline).

Implementation tickets: T-1077 (re-scale the code to the ladder + elastic-seam
resampling; blocks T-1046) and T-1078 (region climate stack + edge fuzz).
T-1046 is un-gated on Q-110 and now blocked only by T-1077.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 21:26:13 +02:00
jpmschweitzerandClaude Opus 4.8 8e44121391 chore(meta): update changelog
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 20:13:31 +02:00
jpmschweitzerandClaude Opus 4.8 c0d4ac89d1 feat(simulation): add Layer-2 inter-settlement road/rail graph (T-1038)
New deterministic cascade layer (CascadeLayer::RoadGraph) building the
transport topology between Layer-3 settlement placements, stored on
BodyWorldState.road_graph (session-cached, never serialized).

- MST force-connect (strict Kruskal over squared distance) + secondary
  links across a 30-60% body-scale band where the MST detours >1.5x.
- A* over the Layer-1 terrain-cost field on a coarse ~64-wide routing grid:
  ocean/lake impassable, river corridors 1/2 cost, slope >=35deg (D-210
  roughness ~0.7) 10x, else the D-210 terrain_modification_cost. Columns
  wrap (equirectangular); integer costs + index tie-break keep A*
  deterministic.
- MaintenanceAuthority per edge (new generator.rs enum) from endpoint
  political archetypes + haul length; waypoint nodes at long-edge midpoints;
  named-route identity join (designed-for, pool empty post-D-223); junction
  detection (high_connectivity_junctions, degree>=3).

Wired into the cascade (gen_queue requests CascadeLayer::RoadGraph). Adds
Copy to PoliticalArchetype. 10 road_graph unit tests + a cascade e2e test;
full suite + clippy --all-targets -D warnings green.

Deferred to T-1076 (gated on the D-242 settlement model): the RailHeadFacing
junction pass (needs a D-213 FoundingOrientation amendment + Layer-4 handling)
and the hub-selection refinement (needs baked population/specialization).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 20:13:26 +02:00
jpmschweitzerandClaude Opus 4.8 301be77b49 docs(governance): file D-242 corp-HQ settlement model + T-1074/1075/1076
Reviewing the T-1038 road-graph hub model surfaced that corp HQs are
cross-referenced into atlas_city_names as reserved rows — one per corp —
producing duplicate co-named "cities" (e.g. 10 'Groombridge' rows on
GJ380c) that the spatial layers place as separate settlements.

D-242 resolves the data model: corp HQs are not cities. The HQ relationship
lives with the corp; placement is a baked, specialization-keyed preference
(CityTenant vs Standalone, since corp_type is degenerate); population and
settlement_class are install-baked with only position seed-derived. This
supersedes the D-223 corp-HQ-cross-ref and deferred-pop/class notes.

Companion tickets under T-750: T-1074 (corp-HQ model / remove the cross-ref /
specialization map / standalone HQ settlements), T-1075 (bake per-settlement
population + settlement_class), T-1076 (road-graph hub refinement — scaled-cap
hubs, co-location collapse, hybrid minor attach, deferred RailHeadFacing pass;
blocked on T-1074 + T-1075). T-1038 annotated with shipped-vs-deferred.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 20:13:10 +02:00
jpmschweitzerandClaude Fable 5 1044939748 chore(meta): close T-1067
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 20:15:04 +02:00
jpmschweitzerandClaude Fable 5 3c3fd0d0df chore(db): regen systems.db — stamp refresh after the T-1067 importer split
Content byte-identical (proven by the empty table-dump diff); the regen
records the new source-set SHA (registry + economy_import modules).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 20:13:41 +02:00
jpmschweitzerandClaude Fable 5 4f73624eff refactor(db): split import_economics.py; single generator-source registry (T-1067)
import_economics.py 2,620 → 309 lines — a thin orchestrator keeping the
exact CLI, single-transaction/rollback contract, and exit codes. The 16
import steps, MIGRATION_SQL, brands shell-out, validators, and stamp
write now live in tooling/economy-db/economy_import/ (db, migration,
economy, corporations, brands, bodies, atlas, specialization, traits,
validators, stamp, paths, errors). Full type hints throughout.

tooling/generator_sources.py replaces the triplicated source registry
(importer / stamp checker / pr-process watch list — the skill now derives
its list via --list). The registry stamps itself, and economy_import/
modules are globbed fail-closed, so a future module is stamped the moment
it exists — closing the silently-weakened-stamp failure mode.

Rider: connector config helpers centralized in tooling/db/common.py.

Byte-identical behavior proven: full-import table dump diff EMPTY over
107,843 lines / 37 tables (volatile timestamp fields excluded); dry-run
output parity; generated_brands.toml sha unchanged. make test-tooling
PASS; ruff clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 20:13:28 +02:00
jpmschweitzerandClaude Fable 5 5b3f18da65 chore(meta): close T-1062
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 17:08:41 +02:00
jpmschweitzerandClaude Fable 5 257d979aed refactor(simulation): split the input.rs and dialogue.rs dispatchers (T-1062)
input.rs 2,739 → 858 lines: per-domain action handlers moved to their
owning modules (inventory, movement, stance, examine, follow, interaction,
save_io, settings, bridge::debug, economy, vision_cone, bookmark,
test_world reset + new teleport.rs); input.rs keeps the queue, the thin
dispatch table, and pause/cooldown glue. All 9 type_complexity allows
dissolved via one PlayerInputQuery alias.

dialogue.rs → dialogue/ directory module: selection (631), response
(1,473), confrontation (714), mod.rs (226, shared session components +
re-exports — public paths preserved). Documented seam deviation:
process_walk_away lives with confrontation (D-064/D-063 share the same
world-response shape).

Mechanical, zero behavior change: determinism + golden_suite byte-identical
(independently re-verified); 1,504 lib tests unchanged — 23 input tests
moved with their subjects, 53 dialogue tests redistributed, zero deleted.
System scheduling registrations untouched (input_plugin.rs 0-line diff).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 17:07:36 +02:00
jpmschweitzerandClaude Fable 5 3a23378a88 style(engine): rustfmt — workers/pool.rs test module (gate fixup)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 16:32:14 +02:00
jpmschweitzerandClaude Fable 5 3a3e7c72fe chore(config): blocking client-test gate in pre-push (T-1065); amend D-067 chime duration
pre-push now runs the full gdUnit4 suite via tests/run-godot when client/
changed — blocking, ~100s, suite made green by T-973 and independently
re-verified. The tooling gate (make test-tooling on TOOLING_CHANGED, T-1066)
rides in the same hook. D-067 amended: the shipped chime is a deliberate
800ms synthesis (#327, ui.md UI-005); prose said 300-400ms. Ticket closes
for the maintenance wave in the changelog.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 16:24:34 +02:00
jpmschweitzerandClaude Fable 5 eadbc5b24d chore(db): regen systems.db — stamp refresh after surname-corpus extraction
Generator output is byte-identical (verified on the full generated TOMLs);
the regen refreshes the meta stamp after generate_brands sources changed
(shared surname_corpus.rs) and import_economics.py registry/lint edits.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 16:23:33 +02:00
jpmschweitzerandClaude Fable 5 b4919c659b chore(meta): wiki sweep — 2,131 dead heightmap links, nav refresh, GOVERNANCE reality (T-1070, T-1071)
- T-1070: scaffold_bodies.py heightmap link now conditional (bake criteria
  per import_heightmaps.py); surgical removal of the dead image line from
  all 2,131 body pages lacking the file (267 with the file keep theirs)
- T-1071: 26 real link breaks fixed (knowledge/→concepts/, pre-governance
  decision anchors, 9 phantom catalog companions unlinked, cygni relink to
  the corporation page, wrong design-doc path); wiki/index.md counts fixed
  (301 systems) + Economics nav section; corporations/index.md regenerated
  from frontmatter (all 155, tier1.toml grouping — corrects 4 misfiled
  tier-1 corps); 25 orphaned station GTTRs linked from 11 system pages
  (own ##-heading so atlas sync cannot absorb it); GOVERNANCE.md +
  star-system template rewritten to the generated model (DB owns
  structured fields, wiki owns prose); triangles/index.md added
- Sol markers conversion REVERTED before commit: atlas_viewer.gd:433 still
  renders the legacy geometry schema, so conversion would drop Sol's Atlas
  overlays — split to T-1073 (convert together with the client read path)

Broken relative links: 2,180 → 25 (all remaining are intentional
_templates/ placeholders).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 16:23:16 +02:00
jpmschweitzerandClaude Fable 5 346d87df7a chore(meta): docs/build sweep + tooling test gate (T-1069, T-1066)
- make test-tooling: planet-gen determinism guard + import_economics
  --dry-run, wired into pre-push on TOOLING_CHANGED; ruff widened to
  E4/E7/E9/F/W (90 safe auto-fixes applied; E402/E702/F841 ignored with
  documented counts)
- one-generator reality fixed in DEVOPS.md, asset-pipeline rule, CLAUDE.md
  (import_economics sole generator since #951/D-223); dead check-protocol
  target deleted; DEVOPS hook/config sections rewritten from the actual
  hook sources; team-patterns gate description updated (client+tooling)
- project.yaml: 0.2.0 → 0.4.0 per the 0.{phase}.{n} scheme, description
  refreshed from the v0.1 Sova narration to cascade reality
- stale comment sweep: voxel.rs stub claims (all 8 families implemented),
  cascade.rs TODO recited to T-1044, main.rs D-192 handshake claim,
  relationships.rs/chunk_streaming.rs version targets → phase language
- gitignore: client/settings.db* e2e-run artifacts

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 16:22:55 +02:00
jpmschweitzerandClaude Fable 5 0bd895fcac chore(engine): server hygiene batch — workers tests, surname dedup, save pin (T-1063, T-1064)
- workers/pool.rs: 5 new tests; catch_unwind keeps worker threads alive on
  handler panic (in-flight request loss unchanged, pinned by test + #843
  docs); stubs.rs no longer falsely claims the pool is tested
- save/load: execute_save_load pinned .after(Storyteller) so the scheduler
  cannot legally save pre-Input state; exclusive-system exception recorded
  in tick_phases.rs rules
- surname corpus extracted to bin/shared/surname_corpus.rs (both economy
  generators import it; byte-identical output verified on 23.6MB+1.45MB
  TOMLs); all three stamp/watch registries updated
- generator_spike gated behind non-default 'generator-spike' feature
- economy.rs: 11 new D-181 signal-derivation tests on the new
  econ_sim Simulation::from_economy in-memory constructor
- perception exemption comments now state the consumer sort contract;
  unused bytemuck removed; rayon comment corrected; the 22 allow(dead_code)
  documented as serde schema enforcement

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 16:22:28 +02:00
jpmschweitzerandClaude Fable 5 c64231e8ee fix(client): clear the test debt — 2 production bugs, suite fully green (T-973 et al.)
Production fixes surfaced by honest test triage:
- hud_groups.gd: _set_group_z crashed on freed HUD nodes — the typed loop
  variable errors before the is_instance_valid guard runs; prune first
- fog_state.gd: _resize cleared _prev_visible (world-space keys survive
  resizes), so pre-resize tiles never decayed VISIBLE→EXPLORED (D-059)

Test debt (T-928/929/934/935/936/937/938/939, T-864, T-973): lambda
local-capture bugs rewritten with array captures (now assert exact
emission counts), e2e suites updated to the current handshake +
StartupMessage protocol and stream-aware reads against the live binary,
fog perf test measures steady state, chime test pins the shipped 800ms
catalog asset (D-067 amended separately), monologue gdUnit4 API typo,
battery-warning tests follow the MetaScreen on_open lifecycle. 3 sprint2
proof tests revived (corner_reveal had passed from the wrong tile — NPC3
blocks (18,14); route corrected). Soft-skips converted to real do_skip
reporting. T-1068: 7 orphan .gd.uid deleted, _format_pop/_format_radius
deduped into atlas_format.gd (preload, no class_name — headless cache).

Suite: 1264 cases/20 failures → 1268/0, independently re-verified
(2536/2536, exit 0).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 16:22:01 +02:00
jpmschweitzerandClaude Fable 5 b7a8cd1876 chore(meta): close bug-run tickets T-1040/T-1041/T-1045 with fix notes
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 13:50:31 +02:00