Two faults, one fix.
Captures were stealing the desktop. Only the golden path even tried to go
offscreen, via xvfb-run -- which is not installed here, so it took the
"using visible window" fallback; --screenshot and --movie never wrapped at
all. Every capture opened a Godot window on the machine Jeroen is working
and gaming on. Now a single wrapper covers all three paths.
gamescope, not the alternatives, for two independent reasons. It renders on
the real AMD GPU, and the goldens are pinned to this box's Mesa/AMD output
(T-1121 -- they do not port across rendering stacks), so xvfb-run's llvmpipe
would shift every pixel: offscreen must not silently mean a different
renderer. And it is the only installed option that lets the output size be
set. cage is also present and also GPU-backed, but it is a kiosk compositor
and forces its client to the headless output's default -- measured, a
960x540 request produced a 1280x720 PNG. A wrapper that quietly changes
resolution is worse than none here.
Worse, because resolution is not cosmetic on this map. D-255's extent
inversion makes the shorter viewport axis span exactly one cell of the rung,
so the viewport decides how much world a rung shows and at what cell count
-- a small capture is a DIFFERENT map, not a scaled one. 960x540 was also
16:9, so it never exercised the ultrawide aspect added in 21e263d0a, which
is the aspect actually in daily use. Raised to the panel's native 3440x1440.
It paid for itself immediately: at native, Ferrath Global reports
courses=375 drawn=0 -- every river culled, where the same build drew them at
960x540. Filed as T-1239. That is exactly the class of bug a too-small
capture hides.
Goldens are NOT regenerated here. They are stale across 15 commits already,
and blessing the current look before it has been reviewed is the trap this
suite just spent a day proving.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The visual gate had stopped measuring anything: 30 of 32 scenarios
failed, and the two that passed were the worst result of the lot.
Deleted the 15 top-down scenarios (fog, HUD, dialogue, NPC, minimap,
cursor) and their goldens. They all failed at a near-uniform ~12%, and
that uniformity across unrelated scenes is one global cause -- the
ultrawide UI stretch moved every element. They cover the renderer the
cascade freezes until Phase 5, which will need its own tests anyway, so
re-baselining would only have blessed a deprecated layer nobody is
reviewing. Jeroen's call.
The remaining problem was the goldens that PASSED. atlas_GJ338Bd_Block
and atlas_GJ445c-m1_Chunk matched at 0.0% because capture and golden
were both blank -- the same "goldens have been measuring nothing" trap
e024cfb3f caught at Global, still live at the bottom of the ladder. The
cause is that every below-Global golden descends at jump_to(ZERO), and
world-metre zero is merely the origin of the region grid, not anywhere
chosen. So _setup_atlas_golden_shot now takes an optional world_center
(default ZERO -- existing goldens are untouched), and a new
atlas_GJ820Bc_land_* set walks Region through Chunk at ONE land point,
so the rungs can be read as a descent instead of five unrelated frames.
aliveness_probe prints the placement's world metres alongside its pixel
and survey cell, since that is the coordinate the Atlas actually
navigates in.
Recorded because it will be asked again: the ladder is anchored via a
CityPlacement, but that is a match record -- a pixel, an archetype, an
orientation -- not built geography. No settlement exists anywhere yet
and none is due before T-1207, so the empty deep rungs are the expected
state. What the ladder judges is the nature layer.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
_setup_atlas_golden_shot and _run_atlas_matrix rebuilt on the real D-255
surface: nav.push('regional') through AtlasApp's own body-selection tail,
then StepCanvasViewer.jump_to at a fixed center (inventory item 5) — no
shim over the retired continuous-zoom API. is_pending()-aware bounded
settle (mirroring atlas_agent_driver.gd) and view-transform logging
(inventory item 3) wired into both capture paths. The 12 z2_0/z4_0/zfit
goldens are replaced by 12 (body, rung) goldens captured live against
fresh --test-mode servers; atlas_shots.json/visual.json re-keyed;
atlas_gen_open's stale gen_l1_* overlay ids fixed to gen_dw_temp.
Verification: two consecutive District runs byte-identical, and a
cold-vs-warm disk-cache invariance proof on both terrain draw branches
(Global/NEAREST, District/LINEAR) — byte-identical either way, so
capture output does not depend on the shared user://atlas_cache state.
DEVOPS.md's real-rendering exception note now records the fold-target
mapping for the smoke file T-1182 already deleted (Global + District
goldens exercise its two real-pixel draw branches). Old legacy-tracked
.import sidecars go with their PNGs; new goldens ship bare per
.gitignore's client/**/*.import rule.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
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>
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>
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>
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>
Add live server lifecycle to tests/run-visual (start/stop server per
scenario, parse LISTENING:{port}). Add MessagePack snapshot replay to
visual_capture.gd via Protocol.decode_snapshot() — exercises the full
client pipeline from wire bytes to rendered fog. Three replay scenarios
(hub_spawn, fog_theater, hub_after_movement) plus one live scenario
(fog_live_hub). Add gen_gauntlet_fixtures.rs to produce .msgpack fixtures
from the Gauntlet test world. Add max_diff_pct threshold to visual-diff.
Makefile: add fixtures-gauntlet target, fix build-client double-import,
preserve .godot cache in clean.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>