257 Commits
Author SHA1 Message Date
jpmschweitzerandClaude Opus 4.6 a1788dad32 fix(client): guard battery test against CI on-battery false-fail (S7)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 11:40:12 +01:00
jpmschweitzerandClaude Sonnet 4.6 f51366b3f5 fix(ui): address PR #90 review — 8 items (W1–W4, S5–S6, A3–A4)
W1/A2: add SimBridge.CONNECTED guard before send_input in toggle handler
W2/A1: assert PlatformInfo != null in HardwareDetector._ready();
       add ordering comment in project.godot [autoload] section
W3: replace FileAccess.open() with get_file_as_string() in
    read_benchmark_cache() — auto-closes, no leak
W4/A3: add _extract_bool_setting() helper in game_state.gd that handles
       both {"Bool": true} and plain bool; push_warning on type mismatch
S5: sync _pre_battery_pref from GameState after load_ai_pref() in
    HardwareDetector._ready() — closes race if system starts on battery
S6: separate "red" TPT status into its own arm with STATUS_RED dot and
    label colour — three-colour mapping: green/yellow/red now distinct
A4: replace DebugConsole.PREFS_PATH compile-time dependency in
    _save_ai_pref() with local SETTINGS_CFG_PATH constant

S7 (battery CI guard) already applied by Hoshe in test file.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 11:39:47 +01:00
jpmschweitzerandClaude Opus 4.6 d3ed73bcb3 test(client): Sprint 26 AI dialogue + PlatformInfo tests
67 tests covering #646 AI-Enhanced Dialogue toggle, hardware
detection (RAM/TPT/degradation), PlatformInfo power state,
battery suspend/resume, and settings dialog integration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 10:55:44 +01:00
jpmschweitzerandClaude Sonnet 4.6 9108e5d9ed feat(ui): add get_battery_warning_visible() getter to settings_dialog
Testable API for Hoshe's battery warning visibility assertions (#646).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 10:54:54 +01:00
jpmschweitzerandClaude Sonnet 4.6 73b4f37de5 fix(ui): include all 7 path properties in PlatformInfo.get_diagnostics()
config_dir, benchmark_cache_path, executable_path, model_dir were
populated in _init_paths() but missing from the diagnostics dict.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 10:50:05 +01:00
jpmschweitzerandClaude Sonnet 4.6 41d16d01ae fix(ui): toggle stays clickable during battery suspend — D-138 player autonomy
Player autonomy wins: AI Dialogue toggle is only greyed out for RAM fail
(< 1.6 GB free). Battery suspend shows a warning label instead of
disabling the toggle — player can override the auto-suspend at any time.

Changes:
- settings_dialog: toggle disabled = hw_status == "fail" only
- settings_dialog: add _ai_battery_warning_label (STATUS_YELLOW) shown
  when _ai_inference_suspended; hidden when plugged back in via
  set_ai_inference_suspended()
- settings_dialog: is_ai_dialogue_toggle_enabled() no longer checks
  _ai_inference_suspended
- settings_dialog: set_ai_inference_suspended() updates warning label
  visibility, not toggle disabled state
- ui-strings: add settings.ai_battery_warning "High battery usage"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 10:49:06 +01:00
jpmschweitzerandClaude Sonnet 4.6 12d25ce17f feat(ui): expand PlatformInfo to full D-141 Tier 1 interface
23 properties, 2 methods, 1 signal:
- Power: raw_power_state + battery_percent added to _poll_power()
- CPU: cpu_name (OS.get_processor_name), cpu_logical_cores
- GPU: gpu_name, gpu_vendor, gpu_api_version, gpu_type (mapped from
  RenderingDevice.DeviceType), gpu_driver_info — all guarded for headless
- Platform: platform_name, os_version, distribution, is_sandboxed
- Display: screen_count, screen_size, screen_dpi, screen_refresh_rate,
  display_scale (macOS screen_get_scale / dpi÷96 fallback)
- Locale: locale, locale_language
- get_diagnostics() -> Dictionary for bug report inclusion
- OS.get_distribution_name() and DisplayServer.screen_get_scale()
  use callv() pattern for headless build safety

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 10:46:44 +01:00
jpmschweitzerandClaude Sonnet 4.6 d7a4e3268a feat(ui): PlatformInfo abstraction + battery detection + fixes (#646 D-138)
Platform abstraction:
- New PlatformInfo autoload (extends Node, registered first in project.godot).
  Owns all OS queries: power state monitoring (30s poll), memory (on demand),
  file path resolution (user_data_dir, config_dir, benchmark_cache_path,
  install_dir, executable_path, cache_dir, model_dir).
- PowerProfile enum (FULL/BATTERY/POWER_SAVER), power_profile_changed signal.
  Uses OS.callv("get_power_info") to defer resolution to runtime — avoids
  compile errors on Godot 4.6 headless builds without power API.

HardwareDetector refactor:
- check_ram() now delegates to PlatformInfo.refresh_memory() + free_memory_mb.
  All direct OS.get_memory_info() calls removed.
- classify_power_state(int) and should_suspend_inference(int) delegate to
  PlatformInfo for single source of truth.
- check_power_state() → {power_state, classification, should_suspend}.
- Battery suspend/resume: on PowerProfile.BATTERY, stores pre-battery pref and
  sends ChangeSettings(false) to server. On FULL restore, sends ChangeSettings
  with saved pref if it was enabled. inference_suspended member tracks state.

Settings dialog:
- is_ai_inference_suspended() / set_ai_inference_suspended(bool) — testable API
  per Hoshe's test contract. Reads HardwareDetector.inference_suspended on open.
- Toggle now disabled when battery-suspended OR hardware fails (not only fail).
- get_ai_dialogue_label_text() wired to UIStrings ("settings.ai_dialogue_toggle")
  instead of hardcoded string.

Cleanup:
- Deleted ai_dialogue_detector.gd and .uid (orphaned duplicate, dead code).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 10:41:07 +01:00
jpmschweitzerandClaude Sonnet 4.6 01b0583265 feat(ui): AI-Enhanced Dialogue toggle + hardware detection (#646, D-138)
Implements the full AI-Enhanced Dialogue feature for Sprint 26:

- HardwareDetector autoload (extends Node): three-layer detection —
  Layer 1 RAM classification (pass/marginal/fail, thresholds 2GB/1.6GB),
  Layer 2 TPT benchmark cache (green/yellow/red, thresholds 6/3 t/s),
  Layer 3 degradation monitoring (>40% drop → yellow). load_ai_pref()
  restores toggle state from user://settings.cfg on startup.

- Settings dialog AI section: toggle, colored status dot, status message
  label, testable API (get_ai_dialogue_label_text, set_ai_dialogue_
  hardware_status, is_ai_dialogue_toggle_enabled). Only RAM "fail" greys
  out toggle — player always overrides yellow/red recommendations (D-138).

- GameState.ai_enhanced_dialogue_enabled (default true, opt-out model).
  GameState.settings_response (v20 one-shot settings dump from server).
  apply_snapshot() hydrates ai_enhanced_dialogue_enabled from full dump.

- Protocol v19→v20, settings_response decoding in decode_snapshot().
  Protocol converted to extends Node autoload (enables test has_method).
  encode_change_settings() helper for test inspection.

- InputMapper: CHANGE_SETTINGS, REQUEST_ALL_SETTINGS, DELETE_SETTING.
  SimBridge: wire mappings for all three. RequestAllSettings queued after
  handshake to hydrate client state from server SQLite on connect.
  settings_response carry-forward in receive_bytes().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 10:34:48 +01:00
jpmschweitzerandClaude Opus 4.6 accbe579c9 feat(simulation): SQLite settings storage with IPC protocol v20 (#627)
Per-player settings via rusqlite (bundled, zero runtime dep). Server
owns the settings DB; client sends ChangeSettings commands over IPC.
Extensible key-value with typed columns (String/Int/Float/Bool).
Protocol bumped to v20 with settings_response in ObserverSnapshot.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 09:11:53 +01:00
jpmschweitzerandClaude Opus 4.6 e0eb3cd35e fix(client): address PR #86 review — archetype validation, teleport clear, ticker layout
- protocol.gd: replace capitalize() with explicit match for archetype
  string mapping, push_error on unknown input with Detective fallback
- main.gd: clear _known_triangle_ids in _teleport_transition() alongside
  _known_recognition_ids so chime re-fires after room change
- news_ticker.gd: defer get_minimum_size() via call_deferred to run
  after layout pass, fixing first-frame scroll distance
- 3 new tests: unknown archetype fallback, triangle dedup per-id,
  independent triangle ID firing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 16:28:12 +01:00
jpmschweitzerandClaude Opus 4.6 7dbd3247d4 test(client): Sprint 24 signal tests
16 tests covering character select, triangle activation consumer,
news ticker, and protocol v19 bridge. Includes show/hide behavior
for ticker on null current_ticker.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 11:44:12 +01:00
jpmschweitzerandClaude Opus 4.6 61d454228d feat(client): character select, triangle activation consumer, news ticker
Sprint 24 Signal — three client tickets delivering the player-facing
storyteller feedback loop:

- #588: Character archetype select screen between New Game and session
  start. Two-card UI (Smuggler/Detective), keyboard+mouse, ESC cancels.
  GameState.character_archetype persisted and sent in StartupMessage.
  PROTOCOL_VERSION bumped to 19.
- #590: Triangle crisis event consumer. Decodes triangle_crisis_events
  from snapshot, fires sfx_monologue_chime_urgent once per triangle per
  session via AudioManager.CHIME_ACTIVATION.
- #592: News ticker HUD element. Scrolling marquee on UILayer, visible
  only when current_ticker is present in snapshot (Last Shift zone).
  Zero-arg update_from_state reads from GameState.current_snapshot.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 11:44:05 +01:00
jpmschweitzerandClaude Opus 4.6 37c38c0441 chore(simulation): regenerate msgpack fixtures for protocol v19
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 09:13:31 +01:00
jpmschweitzerandClaude Opus 4.6 fc24de6128 fix(client): test harness tile types, bug report screenshot, time_display maxf
TestHarness: remove deprecated tiles/visible_positions keys, add tile
type (floor/wall/door) to visible_tiles, expand radius to 5. Bug report
dialog: capture viewport screenshot before showing overlay, save as
screenshot.png in report bundle. time_display: use maxf() instead of
max() to match float argument types.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 08:41:18 +01:00
jpmschweitzerandClaude Opus 4.6 ac763fef97 feat(engine): live server visual tests and gauntlet snapshot replay
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>
2026-03-05 08:41:09 +01:00
jpmschweitzerandClaude Opus 4.6 2189b00c6f fix(client): move fog blur to CPU pipeline, fix GL compat bilinear on RGBA8
Replaces GPU 7×7/5×5 Gaussian blur (98 texture reads/px) with CPU-side
Gaussian blur (sigma 2.0) + 4× bilinear upscale + RGBA8 convert in
fog_state.gd. GL compatibility mode doesn't bilinear-filter R8 textures;
RGBA8 at 4× resolution resolves this. Squared exp_fade at the
explored/unexplored boundary keeps fog opaque near tile content edges,
fixing the staircase artifact. Shader now does 2 texture reads per pixel.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 08:40:57 +01:00
jpmschweitzerandClaude Opus 4.6 388df8000a fix(client): debug console review fixes — D-088 pause, settings state, response guard
- Add D-088 Overlay pause/unpause signals to DebugConsole, wire in main.gd
  so sim does not advance while typing debug commands
- Settings dialog reads live DebugConsole.is_enabled() instead of ConfigFile
  directly, preventing checkbox/state divergence
- append_response respects disabled state — no auto-open when user disabled
  console via settings
- tp command warns on invalid z value instead of silently defaulting to 0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 22:31:52 +01:00
jpmschweitzerandClaude Opus 4.6 1feec914b7 fix(client): bump PROTOCOL_VERSION 17 → 18 to match server
Server #580 bumped to 18 for debug_response field. Client was still
at 17, causing every snapshot to be rejected — game unplayable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 22:29:38 +01:00
jpmschweitzerandClaude Opus 4.6 33b26c1a15 test(client): add BoundaryWall fog tests and document tile_renderer behavior (#585)
4 new tests in test_fog_sprint22.gd verify BoundaryWall tiles populate
boundary_positions (not visible_positions), get VIS_FORWARD without
EXP_VISIBLE, stay EXP_UNEXPLORED after leaving LOS, and clear on new
snapshot. Comment in tile_renderer.gd documents implicit rendering path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 20:33:08 +01:00
jpmschweitzerandClaude Sonnet 4.6 475280191c fix(ui): render LOS boundary wall tiles through fog without marking explored (#585)
- game_state.gd: add boundary_positions Dictionary field; BoundaryWall tiles from
  visible_tiles go to boundary_positions instead of visible_positions — rendered by
  tile_renderer but not tracked as explored fog memory
- fog_state.gd: update_from_state() writes VIS_FORWARD for boundary_positions so fog
  lifts over margin wall content; boundary tiles excluded from exploration step so they
  don't persist as EXP_EXPLORED when player turns away
- tile_renderer.gd: no changes needed — renders all visible_tiles by type, sector-agnostic
- test_fog_shader.gd: 4 new tests — boundary excluded from visible_positions, tracked in
  boundary_positions, cleared each snapshot, fog lifts to VIS_FORWARD

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 20:32:32 +01:00
jpmschweitzerandClaude Sonnet 4.6 c3abf32185 feat(ui): add in-game debug console with tilde toggle and command dispatch (#581)
- debug_console.gd: new ModalLayer Control — tilde key toggles bottom-40% panel,
  command history (up/down), SimBridge dispatch for all DebugCommandKind variants:
  ticks, contaminate, tp, activate, triangle, npc, triangles, pop, status, help
- debug_console.tscn: minimal scene node; UI built programmatically in _ready()
- input_mapper.gd: DEBUG_COMMAND action added to Action enum
- sim_bridge.gd: DEBUG_COMMAND → "DebugCommand" wire mapping
- protocol.gd: v18 debug_response decode (command, text, success fields)
- game_state.gd: debug_response field + apply_snapshot one-shot handling
- main.gd: @onready ref, router registration, _consume_debug_response(), settings signal
- settings_dialog.gd: debug_console_toggled signal + CheckButton toggle row (+36px height),
  reads initial state from user://settings.cfg; CheckButton state loaded from PREFS_PATH
- main.tscn: DebugConsole node on ModalLayer, load_steps 27→28

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 09:50:23 +01:00
jpmschweitzerandClaude Sonnet 4.6 60d2c5bb90 fix(ui): correct Sprite2D/self_modulate assertions in P2 client tests (#574)
Same Sprite2D correction applied to test_client_p2.gd entity color tests
(Terrain, Player) — ColorRect was replaced with Sprite2D in entity_renderer.gd.
Minor comment clarification in test_rendering.gd rotation test.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 09:50:08 +01:00
jpmschweitzerandClaude Sonnet 4.6 d30ab62bc0 fix(ui): clear color registry on conversation end, add speaker color tests (#573)
- Reset _npc_entity_colors/_npc_entity_id/_next_npc_color in _end_player_conversation()
  to prevent palette exhaustion across long sessions with many unique NPCs
- Re-enforce contrast floor after passive desaturation (_enforce_contrast after _desaturate)
- Add TestDialogueSpeakerColors suite: palette allocation, entity reuse, reset, fallback

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 09:50:02 +01:00
jpmschweitzerandClaude Sonnet 4.6 974bb2b28e feat(ui): bind dialogue speaker colors to entity identity (#573)
Maintains Dict[entity_id → Color] in dialogue_box for player conversations.
On first encounter, assigns a round-robin palette color; reuses on subsequent lines.
Eliminates position-based name-hash coloring for player dialogue.

Changes:
- Add _npc_entity_colors dict, _npc_entity_id, _next_npc_color fields
- Add _assign_npc_color(entity_id) — registers palette color on first encounter
- show_dialogue: accept npc_entity_id param, register entity color
- append_line: optional speaker_entity_id/target_entity_id stored in log entries
- append_player_line: pass _npc_entity_id as target_entity_id
- append_dialogue_response: accept entity_id, register, pass to append_line
- _format_entry else branch: look up _npc_entity_colors before name-hash fallback
- main.gd: pass _last_dialogue_npc_id to show_dialogue, speaker_entity_id to append_dialogue_response

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 02:05:15 +01:00
jpmschweitzerandClaude Sonnet 4.6 87b5cbb6c2 fix(ui): correct entity renderer test assertions for Sprite2D and zero offsets (#574)
Fixes 7 pre-existing failures in test_entity_renderer tests:
- ColorRect → Sprite2D cast; .color → .self_modulate for D-033 color checks
- Position offset: (TILE_SIZE-24)/2 → EntityRenderer.ENTITY_OFFSET_{X,Y} (0.0)
- Rotation accuracy: expected values updated for raw un-normalised Godot rotation
Also adds SoundIndicatorRenderer to global_script_class_cache.cfg so test_rendering.gd parses.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 02:04:18 +01:00
jpmschweitzerandClaude Opus 4.6 c797a72fc2 chore(simulation): update tests and fixtures for Sprint 23
- Add debug_response: None to all ObserverSnapshot constructors in
  integration tests
- Bump PROTOCOL_VERSION assertion 17 → 18 in serialization tests
- Regenerate golden proof_room_tick_10.json (BoundaryWall tiles)
- Regenerate client msgpack fixtures for new snapshot fields
- Fix debug.rs resource optionality (Option<ResMut> for
  ContaminationActive/EventQueue)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 19:12:19 +01:00
jpmschweitzerandClaude Opus 4.6 7231b28850 chore(meta): release v0.1.22
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 17:25:31 +01:00
jpmschweitzerandClaude Opus 4.6 6bcdc48412 feat(client): add visual test harness with golden regression
Gives Claude eyes: `make screenshot` captures a rendered frame,
`make test-visual` compares against golden PNGs, `make visual-update`
regenerates goldens. Built to debug the Sprint 22 fog regression and
prevent future visual regressions across fog, HUD, dialogue, and UI.

Config-driven via tests/visual.json (11 scenarios, 2 flows).
Capture engine boots main.tscn with real GPU rendering (not --headless),
waits for NoiseTexture2D async gen, uses deterministic shader time.

Components:
- visual_capture.gd: SceneTree capture engine (scenario + movie modes)
- visual_scenarios.gd: per-scenario setup hooks
- tooling/visual-diff: pixel comparator (PIL primary, struct fallback)
- tooling/visual-thumbnail: contact sheet + crop tool
- tests/run-visual: suite script (xvfb wrapping, golden workflow)
- fog_state.gd: override_time for deterministic captures
- fog_shader.gd: fog_noise_ready signal for settle sequencing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 16:33:55 +01:00
jpmschweitzerandClaude Opus 4.6 8ac904fe69 fix(client): remove return statements from fog fragment shader
Godot 4.6 OpenGL3 compatibility mode does not support 'return' in
fragment(). The early returns on lines 68 and 82 caused silent shader
compilation failure, making the fog overlay render as a no-op — the
root cause of the Sprint 22 fog regression.

Restructured to if/else-if/else chain preserving identical logic.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 16:33:33 +01:00
jpmschweitzerandClaude Opus 4.6 6d416d144f fix(client): simplify fog shader to match D-015 — light fog only, blur exploration edge
The 5-layer fog model's deep fog sub-zone (alpha 0.55-0.70) was designed
for the old peripheral sector. After #569 removed peripheral, tiles behind
the player dropped straight to deep fog — indistinguishable from unexplored
black over dark scene tiles.

D-015 is explicit: behind = light fog overlay, art preserved, just "not
fresh." There is no deep fog sub-zone.

Changes:
- Remove dual light/deep fog alpha — all explored tiles use alpha 0.25-0.35
- Add 5x5 Gaussian blur on exploration texture to soften staircase boundary
- Use blurred exploration value for the visual transition (raw for anti-bleed)
- Remove DARK_OVERLAY constant (zone_tint handles all explored color)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 00:22:01 +01:00
jpmschweitzerandClaude Opus 4.6 95875cb92d fix(client): restore tiles variable for zone tint loop in fog_state
The merge of visual and client branches dropped the `tiles` variable
declaration. The client branch refactored bounds calculation to use
`visible_positions`, but the visual branch's zone tint loop still
iterates over `visible_tiles` for zone_id data.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 00:04:22 +01:00
jpmschweitzer f80b6c1aca Merge remote-tracking branch 'origin/visual'
# Conflicts:
#	CHANGELOG.md
#	client/scripts/autoloads/fog_state.gd
#	client/shaders/fog.gdshader
2026-02-28 23:43:26 +01:00
jpmschweitzerandClaude Opus 4.6 12c2d86771 fix(assets): deprecate VIS_PERIPHERAL and fix spec table label
Round 4 review: mark VIS_PERIPHERAL as deprecated (peripheral sector
removed in #569, constant retained for test compatibility). Fix spec
status table row from "peripheral sector" to "cone gradient".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 23:38:29 +01:00
jpmschweitzer 150faca5d9 Merge remote-tracking branch 'origin/client' 2026-02-28 23:34:36 +01:00
jpmschweitzerandClaude Opus 4.6 2f22fbe4c1 fix(assets): purge stale 5-layer/peripheral references from fog spec
Round 3 review fixes — thorough spec cleanup:
- Remove visibility_sectors from data flow (peripheral removed in #569)
- Remove player_pos uniform (cone center implicit in visibility_tex)
- Update FogState pseudocode: remove sector step, add zone tint step
- Update lifecycle diagram to match single update_from_state() call
- Fix "5-layer fog" → "3-state fog" in Files to Create and impl notes
- Mark zone tint open question as resolved (Sprint 22, D-077)
- Document filter_nearest rationale on zone_tint_tex (D-073 hard zones)
- Note low-saturation tint is intentional per D-046 Hopper test

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 23:26:30 +01:00
jpmschweitzerandClaude Opus 4.6 6fac224d55 fix(client): prevent signed overflow in world_seed generation and load
GDScript int is i64 — when randi() returns a value with bit 31 set,
left-shifting by 32 sets bit 63, producing a negative i64. MessagePack
encodes this as a negative integer, which Rust rmp_serde rejects when
deserializing as u64, causing ~50% startup failure rate.

Fix: mask bit 31 before shifting in new_game() to cap entropy at 63
bits. Also mask the sign bit in _read_seed_file() to handle save files
written before this fix.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 23:24:46 +01:00
jpmschweitzerandClaude Opus 4.6 b025fe8152 chore(db): remove db/connectors backwards-compat symlink (#568)
Remove the db/connectors → tooling/db/ symlink added in Sprint 21
(#274) and migrate all references to use tooling/db/ directly.

- Delete tracked symlink from db/connectors
- Remove duplicate db/connectors/* permission patterns from settings
- Update project-structure.md to reflect removal
- Move whatsinagame/static/db/connectors/ to whatsinagame/static/tooling/db/
- Update 20 whatsinagame template, skill, and test files
- Update comment references in client/tests/test_anti_tedium.gd
- Historical docs (old sprint briefings, changelog, discussions) left as-is

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 22:13:26 +01:00
jpmschweitzerandClaude Opus 4.6 b9b9c923a0 fix(assets): correct gradient radius comment from 6-8 to 3-4 tiles
The 7x7 Gaussian kernel (sigma 2.0) produces a 3-4 tile radius
gradient, not 6-8 tiles. Header comment now matches the function
comment and actual math.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 22:12:56 +01:00
jpmschweitzerandClaude Opus 4.6 50aba3adf6 fix(client): address PR #78 review comments
- Widen world_seed entropy from u32 to full u64 by combining two randi()
  calls (Hoshe warning #1)
- Persist world_seed to save directory and restore on resume_game() so
  loaded sessions maintain D-010 deterministic replay (Tyre warning #2)
- Constrain EntanglementConfig intrigue range based on flat value so
  mundane_ratio stays within D-029 spec [45,55]% (both reviewers)
- Remove dead VIS_PERIPHERAL constant and _grow_bounds() method
- Update test_client_p1 peripheral test for forward-only simplification
- Fix misleading exp_fade shader comment (filter_nearest = hard step)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 22:11:17 +01:00
jpmschweitzerandClaude Opus 4.6 552c90a264 fix(assets): review fixes — spec alpha ranges and noise symmetry
Sync fog-shader-spec.md with actual shader values after #563 tuning:
light fog 0.25-0.35 (was 0.26-0.34), deep fog 0.55-0.70 (was 0.54-0.70).
Pseudocode now uses symmetric noise remapping (noise*2-1)*amp to match
the shader. Added first-call guard comment on _tint_bytes in fog_state.gd.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 20:04:10 +01:00
jpmschweitzerandClaude Opus 4.6 d591f44b35 feat(simulation): add world_seed IPC and EntanglementConfig (#175, #178)
Implements the StartupMessage protocol: client generates world_seed in
SessionManager.new_game(), sends it after handshake, server uses it to
seed SimRng and sample EntanglementConfig.

EntanglementConfig samples flat ∈ [25,35]%, intrigue ∈ [15,25]%, mundane
as remainder (D-029). Same seed produces identical config (D-010
determinism). Different seeds produce distinct configs in ≥90% of pairs.

Protocol flow: HandshakeMessage (server→client) → StartupMessage with
world_seed (client→server) → SimRng initialization → tick loop.

10 Rust tests (determinism, variation, bounds, sum invariant).
9 GDScript test stubs + 2 encode tests for client-side pipeline.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 14:26:31 +01:00
jpmschweitzerandClaude Opus 4.6 ebc87d8e74 fix(client): fix fog system — blocky edges and zero explored visibility (#569)
Root cause: update_from_state() used visible_tiles (always empty in live
server mode) instead of visible_positions for bounds calculation. Bounds
never grew beyond 64x64, so tiles outside that area rendered as solid
unexplored black.

Fix: new _grow_bounds_from_positions() method reads visible_positions
(always populated from server snapshots). Shader fix: removed the
(explored < 0.01 && vis_raw < 0.01) guard that cut off the Gaussian
gradient at unexplored tile boundaries. Doubled blur step size for
D-066 compliant 6-8 tile soft gradient. Added debug_exploration mode
for diagnostic rendering of the exploration texture.

19 acceptance tests covering exploration persistence, bounds grow-only
invariant, gradient margin, Forward-only visibility writes, and
exploration data surviving texture resize.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 14:26:13 +01:00
jpmschweitzerandClaude Opus 4.6 dddfceeb5a fix(assets): tune fog shader alpha and add zone temperature tint per D-059
Ticket #563. Light fog alpha tuned to 0.25-0.35 range (was 0.25-0.55),
deep fog alpha set to 0.55-0.70 with zone temperature tint from
zone_tint_tex (bar=warm #2a1f15, hub=cool #1a1f2e, corridor=neutral
#1a1a1a). Two Perlin noise cycles: 8-10s light, 15-20s deep.
Zone tint texture now populated per-tile from server zone_id in
fog_state.gd with preservation across texture resizes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 14:11:56 +01:00
jpmschweitzerandClaude Opus 4.6 a862426f84 docs(docs): add Sprint 22 briefings and track Godot auto-generated files
Sprint 22 "Wire" briefings for server, client, visual, CI, and
planning teams. Also track Godot .import and .uid files that were
previously untracked.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 12:20:02 +01:00
jpmschweitzerandClaude Opus 4.6 1edc8bb1ec refactor(client): simplify fog shader to 3-layer model
Reduce from 5-layer to 3-layer fog: clear (forward cone), explored
(light overlay preserving art), and unexplored (solid near-black).
Remove peripheral sector handling from fog_state.gd.

Also preserve exploration data across texture resizes — previously,
resizing the fog texture lost all explored-tile state, causing tiles
behind the player to render as unexplored black instead of light fog.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 12:19:44 +01:00
jpmschweitzerandClaude Opus 4.6 a69e69e663 feat(perception): ground vision cone in human sensory physiology
- Visible half-angle 150° → 100° (200° arc), matching average human
  binocular field. Blind spot widens from 60° to 160° — genuine
  vulnerability behind the character.
- Forward half-angle stays at 60° (120° arc) — binocular overlap zone.
- Peripheral zone represents combined sensory awareness: visual
  periphery + subconscious sound/motion tracking, not just eyes.
- Per-character VisionConeConfig allows implants and perception modes
  (D-017) to widen beyond the unaugmented baseline.
- Fog shader: smooth back-edge gradient via smoothstep blend between
  Layer 2 (peripheral) and Layer 3 (deep fog), eliminating blocky
  stair-stepped tiles at the rear of the vision cone.
- D-015 updated with physiological basis and per-character config.
- D-017 updated with vision cone modification by perception modes.
- D-020 updated with protocol versioning policy: PROTOCOL_VERSION
  gates wire format, not gameplay parameters.
- DB backup after sprint 21 close.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 22:31:29 +01:00
jpmschweitzer dd0de2ff04 Merge remote-tracking branch 'origin/visual' 2026-02-27 21:50:36 +01:00
jpmschweitzerandClaude Opus 4.6 e28be513cd fix(assets): review fixes — fog noise speed and kernel UV clamping
Deep fog noise scroll speed 0.045/0.03 → 0.06/0.045 to match D-059
15-20s breathing cycle spec. Clamp sample_visibility() UV coordinates
to [0,1] to prevent sticky gradient at map edges.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 21:48:39 +01:00
jpmschweitzerandClaude Opus 4.6 93c9d2dcb4 fix(client): bump protocol version to 17 after server merge
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 21:36:32 +01:00