Commit Graph
449 Commits
Author SHA1 Message Date
jpmschweitzerandClaude Fable 5 fcf913a413 fix(client): move golden-provenance key out of scenarios{} — crashed visual_capture --list (PR #180 review, Hoshe)
The _comment_atlas_goldens key inside scenarios{} hit _print_list's .get() on a bare String (reproduced: Invalid call on String at visual_capture.gd:699). Moved to a top-level key alongside resolution/golden_dir; _print_list now also skips _-prefixed and non-Dictionary entries so future comment keys cannot crash it. Verified: --list runs clean, JSON valid.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 21:40:03 +02:00
jpmschweitzerandClaude Fable 5 3819e65759 test(client): pace input-roundtrip moves past the D-053 stance cooldown (T-1068 fix ported)
Root-caused with server trace logs: Walk stance throttles 1 move per 2 ticks and SILENTLY discards early moves (movement.rs apply_move -> try_move, TRACE-only) — under load the test's MoveEast landed exactly 1 tick after MoveNorth and was consumed. Server behavior is correct, deliberate D-053, pinned by Rust tests; production clients re-send while keys are held. Fix: COOLDOWN_TICKS=3 post-ack spacing, same as test_sprint2_proof.gd (T-1068) whose fix never reached this file due to helper copy-paste. Pre-fix repro at run 17/30 under load; post-fix 30/30 stress green + full suite 2956/2956.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 21:30:52 +02:00
jpmschweitzerandClaude Fable 5 8d1121d13a test(client): wall-clock deadline + 10s ceiling for input-roundtrip response waits
Second distinct flake in this suite today (gate run: MoveEast observed mid-move at the 5s window). The old accounting accrued elapsed only on empty polls — load-dependent effective window. Wall-clock deadline via Time.get_ticks_msec; ceiling 5s->10s (exit-on-arrival, costs nothing when healthy). Targeted suite 6/6.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 20:47:12 +02:00
jpmschweitzerandClaude Fable 5 9427b165f0 docs(client): golden provenance notes — atlas_* goldens are machine-local until T-1121 (PR #180 review, Tyre T1)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 20:42:37 +02:00
jpmschweitzerandClaude Fable 5 56b9f135d0 test(client): add_child AtlasViewer in view-api tests — bare .new() has nil _canvas
Three of the four new tests skipped scene-tree entry, so _ready() never resolved _canvas and set_view crashed _apply_transform. Mirrors the fourth (passing) test. Targeted suite green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 20:34:01 +02:00
jpmschweitzerandClaude Fable 5 2b2f4f8abb test(client): 12 Atlas golden screenshots — 7 bodies x 3 zooms x 3 overlay sets (T-1120)
Curated from the 42-shot matrix, one per body spanning all zoom levels and overlay sets; self-consistency verified 12/12 at exact pixel match on this box. .import sidecars force-added per the existing golden convention. Bodies: GJ380c, GJ144e, GJ338Bd, GJ820Bc (Metropolis + Cygni yard), GJ251c (T-1116 water/no-roads exhibit), GJ244Ad (frozen), GJ445c-m1 (moon).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 20:29:53 +02:00
jpmschweitzerandClaude Fable 5 799156b140 feat(client): Atlas screenshot capture matrix + set_view API (T-1120)
AtlasViewer gains public set_view(zoom, offset)/get_view_offset (clamped, review-flagged API gap) + gdUnit suite. visual_capture.gd gains an atlas_matrix scenario (one boot, tests/atlas_shots.json-driven: 7 verified bodies x zoom x overlay sets, signal-gated waits on atlas_layers_received/city_names_received with timeout fallback). 12 individually-addressable golden scenarios registered in tests/visual.json. Root-level settings.db* gitignored (capture-spawned servers write their settings store to cwd). Fixes found live: GDScript lambdas capture value-type locals BY VALUE (wait-flag moved to Array carrier); RegionalScreen.enter() no-ops when the screen id is unchanged (direct enter() per body after the first).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 20:29:14 +02:00
jpmschweitzerandClaude Fable 5 bba14cb9ba test(client): retry input-roundtrip server spawn on fresh port when it dies pre-connect
The server binds AFTER ~250ms of plugin/sim init, so a random-port collision (os error 98) escapes the 0.15s spawn-liveness check and surfaced as a hard test failure at the push gate. Death during the connect window now retries on a fresh port within MAX_PORT_ATTEMPTS. Verified: targeted suite 6/6.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 19:05:43 +02:00
jpmschweitzerandClaude Fable 5 4f52abd532 feat(simulation): wire region climate layer into the cascade + proxy (T-1113, D-243)
CascadeLayer::Region appended per the enum's append-only Ord rule (depends only on seed/body_params/heightmap dims — documented); BodyWorldState.regions BTreeMap per the districts precedent; RegionGridLayer dense row-major all-integer encoding (season/weather repr(u8) discriminants, mean_temp deci-degC i16 with i16::MIN airless sentinel, moisture_q u8); build_region_grid mirrors build_district_grid; protocol.gd region_grid passthrough (visual overlay deliberately out of scope); wire fixtures regenerated via make fixtures. atlas:: suite 507 green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 18:51:43 +02:00
jpmschweitzerandClaude Fable 5 3304ee30da fix(simulation): PR #176 review round — all 12 findings + 2 recommendations addressed
H1 demux: ShapeProbe defensive multi-shape rejection (union frames now Err, not first-match; +2 tests) and doc claim made honest. H2/T1 SystemIndex.reset_test_state() folded into SimBridge.reset_test_state() (load() inline per autoload rule) + has_pending_request() accessor. H3 no-op tests now assert the replay flag both directions. H4 retry test actually ingests a failure and asserts the retry semantic. H5 error fixture uses the normalized status string. H6 bridge_tcp e2e sends all five frame shapes over real TCP (star-map + city-names buffers asserted). H7 positive replay-on-CONNECTED test via the test_local_bridge test-mode-flip precedent (stub bridge captures + decodes the request bytes). H8/T2 stale PLACEHOLDER doc replaced with the confirmed contract. H9 is_capital doc matches the COALESCE reality. T-r1 demux ceiling written down (next shape = tagged envelope). T-r2 AtlasLayerResponse governance ceiling comment. Lead item: the four cargo-fmt-formatted files from the gate round are now committed (layer_proxy/plugin/bridge-mod/main). H10 note for the record: the 13 snapshot_*.msgpack fixtures in commit 845737617 were regenerated because they were stale against their own generator (pre-existing version-key removal) — verified harmless, no client reads that key.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 17:31:15 +02:00
jpmschweitzerandClaude Fable 5 845737617c feat(client): atlas roads/settlements overlays + legend + server-API data delivery (T-960, T-949)
T-960: gen_l2_roads (MaintenanceAuthority-colored polylines, rail styling, junction markers) + gen_l3_settlements (size-scaled markers, capital shape, name labels) overlays — cities render on generated bodies for the first time; left-side generation legend panel (D-226 item 3, data-driven per-overlay spec, implant component library); protocol.gd decodes road_graph/settlements + the two new response types. T-949: system_index/atlas_app/overview_screen migrated off the direct star_map_data.json read to StarMapRequest over the bridge (loading state + replay-on-connect, no silent file fallback); atlas_viewer _load_markers requests CityNamesResponse for non-Sol bodies; Sol keeps the legacy authored markers.json geometry read (D-236/T-1073, load-bearing guard). Lead fix: _send_star_map_request now carries the same guard as request_star_map — the autoload's _star_map_wanted leaked across gdUnit suites and the unguarded replay-on-CONNECTED crashed 8 pre-existing flow tests on a Nil bridge; reset_test_state clears the flag. Fixtures regenerated via gen_fixtures (road/settlement samples). Full suite 2946/2946.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 15:45:54 +02:00
jpmschweitzerandClaude Fable 5 6bda9f1697 feat(simulation): auto-pause sim on implant-fullscreen — inspection substrate (T-970)
D-226 layer 1. World-advancing phases gated on pause: Movement/Storyteller/Knowledge/TickAdvance set-gated via sim_not_paused; Simulation + Economy gated per-system at their registration sites — collect_sound_events and serve_econ_state_query stay unconditioned (transient-buffer clear + paused-allowed query; set-gating Simulation leaked a stale tick-7 footstep into frozen snapshots — caught by golden_suite, fixed without touching the fixture; regression test encodes the bug shape). New PlayerAction::AutoPause/AutoResume + AutoPauseState resource implement Option A reconciliation: auto-resume only fires if auto-pause caused the pause; manual pause and Half rate survive implant open/close. PauseParams SystemParam bundle keeps process_player_input under the 16-param ceiling (BookmarkInputParams precedent). Client: HudGroups.gameplay_occluded now sends AutoPause/AutoResume via send_named_action; 5 gdUnit tests + 7 Rust tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 15:44:56 +02:00
jpmschweitzerandClaude Fable 5 3d6dcc9d05 docs+fix: sidequest close-out — T-1095 head tint, design doc, wardrobe docs, changelog (T-1088/T-1089)
T-1095 fixed: template heads now receive the body's skin tone (same
treatment as seg_head) — _load_head passes tone.lit with a full-white
fallback mask through _attach_to_bone; without a mask sidecar the tint was
silently ignored, so untinted templates read grey against mid/dark tones.
Verified by lookbook render (head_001 on child, tone 6 — face matches arms).

Docs: the T-1088 locomotion design document committed to docs/design/ (the
sandbox code's 'design §' references now resolve in-repo); character-asset-
organization gains §11 Wardrobe Pipeline and sheds three stale claims (the
never-built indexed-greyscale mask plan, single-mask-per-asset for clothing,
the resolved multi-region open question); CHANGELOG carries the sidequest
entry; D-250 amended with the shipped cutaway-modes verdict (mode 2 default,
user-decided live).

Tickets: T-1088, T-1089, T-1095 closed; T-1096 filed (S9 live feel-tuning,
needs the user). The Fable-5 cascade exception is closed — the cascade
resumes at Phase 4 (T-750).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 14:15:56 +02:00
jpmschweitzerandClaude Fable 5 e709462a7b fix(assets): convex toe boxes on closed footwear — no more foot-shaped shoes (T-1089)
User review finding: sneakers/formal shoes/boots conformed to individual
toes (and toes poked the closed front). Root cause: the skin-conforming
clearance clamp ran AFTER toe smoothing and re-imprinted the original toe
bumps; boots also copied per-toe skin weights (ripple under flex). Fix:
shared base.convex_toe_box() — per-slice enclosing ellipse from the skin,
notch fill, projection onto the smooth cap (outside skin by construction),
extended rounded nose past the longest toe, uniform feathered ball-bone
binding so shoes flex rigidly at the ball joint. Style-parameterized
(sneakers roomy / formal sleek tapered / boots chunky). Re-authored x 11
bodies; QA all-green (worst 82px « 150 gate; residuals are collar/sole-edge
slivers, not toes). Lookbook shots re-rendered on the desktop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 12:59:00 +02:00
jpmschweitzerandClaude Fable 5 e562418d06 fix(assets): lookbook findings — 44 missing extracted albedos, manifest nesting, lookbook tool (T-1089)
The lookbook render pass load-checked all 264 garment GLBs and found four
garments (boots, cargo pants, jeans, tank top) shipped WITHOUT their
per-body Godot-extracted albedo textures — 44 GLBs would fail to load after
a clean import. Textures regenerated via forced reimport and committed.
Also: swimsuit_onepiece manifest entry was double-nested (lead's merge bug —
runtime unaffected, reads coverage.json); flattened. The parameterized
lookbook_scene tool (drives the production compositor, auto-framing, job
list) is committed for future catalogue renders. Grey head-template finding
filed as T-1095. Lookbook itself delivered to the desktop, not committed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 12:04:36 +02:00
jpmschweitzerandClaude Fable 5 e5ca650164 feat(assets): outfit presets — 12 named complete looks over the wardrobe (T-1089)
casual street/warm/hoodie, business, black suit, training, gym, two swim
looks, worker, thrds cold-weather, and sleepwear-as-tints (soft palette over
daywear meshes — no dedicated sleep meshes). Per-item 4-region tints + brand
logos where sensible; all references validated against the manifest. The
seam for NPC dressing, shop outfits, and creation-screen randomize.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 11:23:15 +02:00
jpmschweitzerandClaude Fable 5 ded5c62515 feat(assets): wardrobe wave 2 — footwear, sportswear, swimwear, sweater, cargos, thrds parka, slides (T-1089)
Twelve garments, per-body on all 11 bodies, chromakey-gated (worst clips:
parka 3px, boots 54, sweater/tank 83, sneakers 100 final-geometry, slides
123, swim trunks 132, cargo 138 — all under the 150px gate), previewed:
tank top, sweater (crew-neck via per-body ring-valley probe — first draft
read mock-neck, fixed by measured rim circularization), track jacket
(recolorable sleeve-stripe region), joggers (side-stripe region), cargo
pants, swim trunks, one-piece swimsuit, sneakers (prism-sole), formal
shoes, ankle boots (calf shaft), slides (open strap + sole), and the
hip-length thrds parka — the first canon-branded garment (Braemar
cold-weather cooperative), quilted, logo-capable.

Tops now hem into real hip geometry (the natural seg_torso bottom is a
9-14cm tooth ring — the sweater established the hem-into-hips practice).
Manifest merged by the lead: 24 clothing entries with region/default-tint
metadata. Full modern catalogue: 21 garments across tops/bottoms/feet/
full-body x casual/formal/sport/swim/outerwear.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 11:20:18 +02:00
jpmschweitzerandClaude Fable 5 c765efd54e feat(assets): wardrobe wave 1 — per-body shells, 8 garments, try-on UI (T-1089)
Infra: offset-shell gains --per-body mode (each body's own segments, cut/mask
thresholds derived from that body's bone landmarks — reproduces the
hand-calibrated reference constants exactly on average_m); compositor prefers
<body>_mask.png with reference_mask.png fallback; tshirt re-authored per-body
on all 11 (the Q-060 torso poke-through class is GONE — residual flags are a
sleeve-hem epsilon artifact on thick arms, offset-insensitive, documented).

Garments (all per-body x 11, chromakey-gated <=150px worst, previewed):
hoodie (hood-down roll, kangaroo pocket, logo), button-down (collar/placket),
shorts, jeans (analytic denim field driving albedo+mask together; boundary
weld + open-rim flattening — real segment-splitter findings), formal pants,
jacket (over-shirt standoff, zip), suit_jacket_black (lapel region, tintable
shirt triangle — the hand-author proof), uniform_utility (11-segment
coverall, gap-free waist join by construction, 4-zone showcase, logo patch).

Try-on UI: creation screen shows per-region tint pickers (multi_region
garments) + logo picker (logo_capable + logos/*.png scan), data-driven off
manifest+coverage. Manifest merged by the lead: 12 clothing entries.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 00:35:20 +02:00
jpmschweitzerandClaude Fable 5 278e8b7c21 feat(client): compositor plumb for multi-region garments + per-character logos (T-1089)
_apply_clothing_shader routes coverage.json multi_region garments to
toon_garment (4 tints, cascading fallback) with the brand logo resolved from
the new descriptor field clothing_logos (item_id -> brand id -> logos/<id>.png
— a logo is a per-CHARACTER wardrobe choice, so it rides the descriptor, not
the garment). Legacy garments keep the single-tint path untouched. Server-side
descriptor mirror stays parked with T-1060/Q-114 (appearance is client-local).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 22:21:52 +02:00
jpmschweitzerandClaude Fable 5 e22ea0fa4a feat(assets): wardrobe engine + proof t-shirt — batch-fit, offset-shell, 4-region tint, thrds logo (T-1089)
Engine: tooling/garment-fit/blender_batch_fit_skinned.py (G1 — the skinned
Surface-Deform batch the old script couldn't produce; self-check green),
blender_author_offset_shell.py (route c: garment shells from OUR body
segments, weights inherited by construction, bone-plane cuts, procedural
RGBA region mask, UV2 chest channel), make_logo.py. Shader:
toon_garment.gdshader — channel-blended 4-region tint + UV2 logo composited
after tint / before toon shading. Proof: tshirt_modern fitted to the six
healthy bodies, manifest entry with style:modern + logo_capable, thrds
wordmark, 18-assertion test suite, 216-capture chromakey QA.

Key finding (Q-060 evidence): single-reference SD-fit of an offset-shell
degrades on girth-divergent bodies (muscular_m worst) — 24mm standoff
tripled headroom but the mechanism limits. Route guidance recorded on
T-1089: per-body shell authoring for offset-shell garments; SD-fit for
derived/hand-authored ones.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 22:21:33 +02:00
jpmschweitzerandClaude Fable 5 b54b8189d9 fix(assets): T-1090 — five fork bodies rebuilt; mesh+armature scale baked together
Root cause was double: (1) segment_body's apply_scale scaled fork MESH
vertices but not each segment's embedded armature — the shared-skeleton
compositor relocates segments by bone name, so internally-inconsistent
segments exploded (child worst at 0.72x: head bone 0.35m above its mesh —
detached heads, spider arms); (2) thin/heavy were stale high-poly artifacts
from an older segmentation, missing seg_hips. Fix: apply_fork_scale bakes
mesh AND embedded armature via transform_apply (edit-bone poking shears
chains — first attempt proved it); new blender_rebuild_forks.py rebuilds
exactly the five from the owned UBC Source exports. All five now 19 low-poly
segments matching the healthy six.

QA on the real compositor (idle+walk, front+side): 5/5 coherent; healthy
controls unchanged. Q-060 answered at the extremes: 15/15 peasant-garment
Surface Deform binds on the forks, zero shrinkwrap fallbacks, no
bust-through — the 6-of-11 placeholder debt is paid (fork garment variants
included). Follow-up filed: T-1094 (child/teen composite at adult height —
pre-existing shared-skeleton normalization, not a regression).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 22:06:10 +02:00
jpmschweitzerandClaude Fable 5 c82ea3ec92 feat(client): purchased UAL tiers wired — lib/Clip addressing, stance enter/exits, turn-in-place (T-1088)
ual1.glb (120 clips) + ual2.glb (134) replace the free-tier subsets;
CharacterVisual loads both under explicit library names with lib/Clip exact
addressing (bare names keep cross-library search). Gait table re-pointed;
two new one-shot overlays in the gait machine: stance transitions
(Sprint/Crouch Enter/Exit, destination-Enter priority, clip-length timer,
movement never stalls) and turn-in-place (Turn90/180 L/R from shortest-arc
sign, >=60/135 deg idle yaw jumps, retrigger-guarded). All clip names
verified by dumping the imported GLBs. 70 gait tests + live smoke green
(both libraries load with exact counts).

S9 live-tune list: turn handedness (unverified headless — one-line swap),
TURN_SPEED_SCALE=2.0 compromise vs the snappy yaw ease, turn-on-stop feel.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 21:53:35 +02:00
jpmschweitzerandClaude Fable 5 e46aa404fc test(client): corner-reveal proof updated to D-252 semantics + deterministic cone wait
The proof encoded move-writes-facing ('Move West -> now facing West'); under
D-252 the view changes only via SetFacing, so the test now looks West
explicitly (helper gains an action_data passthrough). The +2-tick wait could
catch the facing flip before the visibility recompute — the assertion now
polls (bounded) until the westward cone content lands.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 21:15:32 +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 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 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 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 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 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 Opus 4.8 b73b4e6d92 feat(simulation): Layer-1 water bearing + D-234 waterfront rule (#957)
Close the last D-234 piece — terrain water-direction extraction wired through
to founding orientation and the quarter waterfront rule:

- Layer 1: TerrainAnalysis::water_bearing — 8-octant integer bearing toward the
  nearest water from the water_dist gradient (D-010, no atan2). Stored on
  GeographicAttractor.water_bearing (360 = none).
- #956 founding orientation: coastal/river settlements now get a real
  water-facing bearing (the anchoring attractor's), replacing the 0 stub.
- #957 waterfront rule (D-234b): the water-facing quarter edge (from the
  settlement's Coastal founding orientation) drops its block setback to 0 so
  buildings present flush to the quay (dock-orthogonal). Typed Edge + coastal_edge
  + per-block gating.

Golden + atlas_response fixture rebaked (additive water_bearing field only).
8 new tests. All integer-deterministic (D-010).

Pending: the waterfront rule reads context.founding_orientation, which
city_context_reader still stubs to Cardinal — real per-settlement orientation
reaches quarter generation once the Layer-3 placement -> Layer-4 GenerateSkeleton
dispatch is wired (the remaining cross-layer integration).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 10:22:14 +02:00
jpmschweitzerandClaude Opus 4.8 31d7870823 test(simulation): rebake golden + atlas fixture for Layer-3 enrichment (#956)
DrainageBasin gained a territorial_status field, so the Layer-1 golden and the
atlas_response msgpack fixture pick it up. Both changes are additive/
representational — basin/attractor/river selection is unchanged.

- cascade_golden.rs: pass None dominant_faction; golden rebaked (only
  "territorial_status": "FrontierUnclaimed" added per basin).
- gen_fixtures.rs: set the new field in the atlas_response generator; fixture
  regenerated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 14:57:18 +02:00
jpmschweitzerandClaude Opus 4.8 adce12035a fix(simulation): route atlas_response fixtures in the serialize test
all_fixtures_deserialize panicked with "unknown fixture naming
convention: atlas_response_ready" — the test reads every .msgpack in
client/tests/fixtures/msgpack but had no branch for the atlas_response
prefix (the AtlasLayerResponse fixtures gen_fixtures emits, #969). A
pre-existing gap (present on main; the suite isn't gated by the pre-push
hook, which runs cargo-deny/ruff/JSON/stamp, not cargo test).

Add an atlas_response branch deserializing AtlasLayerResponse, and
regenerate atlas_response_ready.msgpack so its bytes match the now-integer
GeographicAttractor types (#955).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 16:31:19 +02:00
jpmschweitzerandClaude Opus 4.8 8dc6c0ed42 data(content): address PR #146 review — Ghawr rename, faction pins, catalog
Review fixes for the #1019 heritage rebalance:

- Marib's farm world Ghouta -> Ghawr (Miri): "Ghouta" carries strong
  modern associations (2013 Damascus attack); Ghawr (the Jordan Rift
  Valley, an irrigated lowland farming region) keeps the water-fed-
  drylands sense without the resonance.
- Add dominant_faction = "independent" to GJ 914A / 508A / 1245B (Hoshe)
  — all five rebalanced systems are self-governing independent
  communities; uniform with siblings GJ 722 / 680 and clears V-FAC-01.
- catalog.md: fill GJ 914A -> Marib and GJ 722 -> Sığınak (Hoshe) — the
  two anchor systems still showed em-dash placeholders.
- Marib gttr: name the second aperture neighbour Sığınak instead of the
  bare "GJ 722" (Miri).

Pre-existing Golestan aperture/spur wording (reviewers split on whether
it is even wrong) is left for a separate content pass — not introduced
by this rename.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 09:17:07 +02:00
jpmschweitzerandClaude Opus 4.8 8844bef139 data(content): rebalance 5 thin afrikaans systems to MENA heritage (#1019)
The corridor over-represented southern-African heritage (afrikaans on 15
systems; arab=2, persian/turkic=0) as an artifact of the earlier
name-balancing overcorrecting. Convert five genuinely-thin afrikaans
systems — whose distinctive threads are heritage-agnostic — into
Arab/Persian/Turkic founders so the cultural cascade is built on a
balanced set. Load-bearing mystery systems (Eerste Wacht / Helderoog /
Brandpunt etc.) are left untouched.

  Droëland  (GJ 914A)  -> Marib    (arab)
  Stilwater (GJ 508A)  -> Sawad    (arab)
  Koeberg   (GJ 1245B) -> Akhgar   (persian)
  Skuilplek (GJ 722)   -> Siginak  (turkic)
  Carnarvon (GJ 680)   -> Golestan (persian; Mostert dynasty -> Farahani)

Result: afrikaans 15->10; arab 0->2, persian 0->2, turkic 0->1.

Full narrative retouch (not just names): gttr.md + index.md prose,
body/station proper_names, cultural_specialization, gttr_hook,
atlas_city_names, and the four brand-corps named after the converted
systems (corp IDs kept stable; only display names + products renamed).
Cross-references in neighbour systems, the catalog, the aggregate
drifter guides, and the atlas proposals are updated to match.

arab/persian/turkic added to _CULTURAL_HERITAGE so the values validate;
the full canonical 47-value migration remains #1016.

Also fixes a pre-existing canon bug: Sawad (GJ 508A) no longer claims
GJ 914A is "unsettled" — it is Marib, a three-century settlement.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 07:11:10 +02:00
jpmschweitzerandClaude Opus 4.7 89596dbb87 test(client): live atlas generation-overlay inspection scenario (#960)
atlas_gen_open opens the real atlas app via HudGroups, navigates to GJ71c's
regional screen, and enables the Layer-1 overlays — exercising the production
opener + the live request→cascade→render pipeline against a --test-mode server
(SR_LIVE=1). Capture with: tests/run-visual --screenshot atlas_gen_open.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 10:09:48 +02:00
jpmschweitzerandClaude Opus 4.7 6134296840 fix(ui): atlas overlay scale, opener robustness, rivers match water (#960)
- Generation overlays map positions from Layer1Output.grid_w/grid_h onto the
  displayed texture (not the markers.json grid), fixing the off-by-2 scale.
- AtlasViewer loads ImplantPending by path instead of referencing the new
  class_name, so a stale global-class cache (a session that hasn't re-imported
  after the class was added) can't fail to parse AtlasViewer and break the
  atlas from opening.
- Rivers and mouths use the reliefmap's own water colour (sampled median ocean
  blue) so river lines blend into surface water instead of reading as a
  distinct-coloured line flowing onto the sea.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 10:03:47 +02:00
jpmschweitzerandClaude Opus 4.7 adbd7f6744 fix(simulation): Layer-1 self-describing grid dims + Moore basin trace (#960)
Two Layer-1 generation fixes surfaced by the per-layer atlas viewer:

- Layer1Output now carries grid_w/grid_h (the downsampled working-grid the
  positions live in). The client maps overlays from these, so the scale is
  correct for any source heightmap resolution rather than assuming the texture
  size — fixes overlays projecting at half scale into a corner.
- Drainage basin boundaries are traced as ordered, non-self-crossing contours
  via Moore-neighbour tracing instead of an angle-from-centroid sort. The sort
  produced star-shaped, self-crossing polygons for concave basins that rendered
  as straight chords across the map.

Golden (cascade_layer1.json) and the cross-language atlas_response_ready
fixture regenerated. 100 atlas lib tests + the new tracer test pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 10:02:32 +02:00
jpmschweitzerandClaude Opus 4.7 c3bcf09c72 chore(client): gdformat visual_capture + visual_scenarios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 22:54:51 +02:00
jpmschweitzerandClaude Opus 4.7 6bb21db2cb test(client): implant_pending visual scenario (#960)
Ad-hoc capture scenario that overlays the ImplantPending "generating" indicator
on the booted scene for visual sign-off — `tests/run-visual --screenshot
implant_pending`. No golden committed; this is an inspection scenario, not a
regression gate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 22:53:57 +02:00
jpmschweitzerandClaude Opus 4.7 9733cbc0af fix(client): visual_capture Protocol decode in -s mode
visual_capture.gd runs via `godot -s`, where the `class_name` registry isn't
populated — so the bare `Protocol.decode_snapshot()` reference failed to
compile, breaking ALL --screenshot/--movie/golden captures (not just the
replay scenarios that use it). Instantiate the script and call the static
decoder on the instance (then free), matching the file's existing -s-mode
load() workaround for VisualScenarios.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 22:51:51 +02:00