Godot requires .import files for stable uid:// references across
editor sessions. All other audio assets have one — this was missed
in the audio branch PR.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove premature Voice/VoiceConversation from SOUND_EVENT_ASSETS (D-072
defers murmur to end-to-end sprint). Extract current_zone_id in
GameState.apply_snapshot() as first-class field, eliminating O(N) tile
scan in main.gd (D-020 server-authoritative). Add dir.list_dir_end()
after registry scan. Add rapid zone-crossing + _load_prefs() roundtrip
tests. Enhance comments on hub/workplace same-asset pattern, station
base hum, and confrontation dip replacement semantics.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
tea comment hangs with inline heredocs and multi-line strings.
Document the two-step pattern: write to .tmp/ first, then pass
via $(cat).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 3 zone enrichment tests to observer pipeline (tile inside zone,
tile outside zone, absent ZoneMap resource). Fix misleading Decay
Observatory doc comment that claimed Direct start when test starts at
KnowsDetails. Add production population TBD note on ZoneMap.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
57 new tests in test_audio_sprint13.gd covering bus setup, dip profiles,
zone crossfade, recognition chime, and murmur wiring. Fix lambda capture
bug in 3 signal tests (String → Array wrapper for reliable closure
capture in Godot 4). Add bus volume reset to before_test() for test
isolation against prefs-loaded state.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
AudioManager: volume slider persistence (ConfigFile), settings UI with
5 teal-bordered sliders, default_bus_layout.tres for editor. Zone
crossfade: defensive zone_id read from snapshot tiles, 1.5-2s ambient
tween, auto-activates when server ships OQ-09. Dip profiles: dialogue
dip in show/hide_dialogue, ListeningFocus 30-tick gate via
stationary_ticks in game_state.gd. NPC murmur: client plumbing for
event-driven World SFX playback, no-ops until audio asset arrives.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Spawned agents are told not to run git commands (team lead handles those)
and to call db/connectors scripts with bare commands only — no python3
prefix or command chaining — so they match the permission whitelist.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server-tracked zone_id on VisibleTile for D-073 zone crossfade and
D-059 deep fog temperature tint. ZoneMap resource backed by BTreeMap,
observer enrichment in snapshot assembly. Backwards-compatible: v10
payloads deserialize with zone_id: None.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three new gauntlet test rooms for Sprint 13, each targeting a specific
system under test. StableIds are additive-only (66–74).
Sound Lab (66-68): Three NPCs at calibrated tile distances (2, 6, 12
tiles) verify D-018 three-range sound model. Tests confirm Close ≤3,
Medium ≤8, Long ≤20 tile thresholds via SoundEvent::audible_at().
Decay Observatory (69): Single NPC observed in LOS then broken. Tests
confirm D-041 confidence decay: KnowsDetails → KnowsOf → Suspects
(floor), and Stale state when stale_after threshold is exceeded.
Shift Change (70-71): Two NPCs with DailyRoutine components. Test
confirms D-031 phase-boundary check_phase_transition issues PathRequest
only to NPCs not already at their target location.
Sprint 13 reset plates (72-74) wired per existing pattern.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Produces sfx_npc_murmur.ogg via Stable Audio Open for D-072 universal
event-driven NPC proximity murmur. Organic sonic family (D-074): warm
mid-freq 200-800Hz vocal texture, human voices in adjacent room with
direction and cadence distinguishable, words not. World SFX bus.
Generated 3 candidates (5s/CFG8, 6s/CFG7, 4s/CFG9), selected candidate
1 for richest texture and clearest spatial framing. Unblocks client #533.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add sprint-plan, pr-push, pr-review, ticket, docs-search, and
workshop-start to shared permission settings.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Case A on main previously closed the active sprint immediately without
checking ticket completion or open PR status. Now checks both and asks
the user before proceeding.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sprint 12 copy team output: 26 tickets covering foundation docs,
character builds, design documents, content packs, and ambient
expansion.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
D-075 dissent was pending Gestalt and Nigel input on the no-archetype-tag
decision. Gestalt endorses: access tier tags in content handle archetype
distinction emergently; starting knowledge differentials produce per-character
gate timing without hardcoded archetype filters; maintenance cost of archetype
tags would undermine the "two keyholes on the same world" experience (D-027).
Nigel's input still pending.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Ten coverage zones from Gate Terminal Approach (comprehensive) through
Corridor 7B (dead air, Severance-enhanced). Maps detective investigative
progression, smuggler operational geography, NPC behavioral modulation by
zone, and coverage-transition monologue triggers.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Cultural generation guide (#189), Sova Texture Appendix (#302),
Contraband specification (#321), Sova Station Profile (#320), and
Span Gate Transit Schedule (#336). These are the blocking foundation
docs for all three content packs (#190/#191/#192) and the Meridian
Coverage Map (#335).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix SOUND_EVENT_ASSETS walk-speed keys to match actual filename
(sfx_footstep_metal_walk), add play_loop null guard, source indicator
colors from Constants, extract CAMERA_DEFAULT_ZOOM, document
consume-once semantics on close_sound_events.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
validate_movement now inserts SoundEventEmitter with Footstep events on
every successful move. Intensity scales by stance: Sprint 0.8, Walk 0.5,
Careful 0.3, Crouch 0.15. Range is Close (3 tiles) for all stances.
This completes the sound event pipeline end-to-end: movement produces
events → collect_sound_events drains to queue → observer snapshot
includes audible events → client bridge receives them.
Addresses Tyre critical review item #1 on PR #42.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. Sound producers: document empty v0.1 pipeline explicitly (critical)
2. Routine tests: add ActiveSim to 3 tests that passed trivially
3. Rename _observer_pos → observer_pos (used at line 191)
4. Add FactionOnly positive test case (matching faction_id)
5. Fix stale doc comment "Current: 9" → 10 in ObserverSnapshot
6. Remove orphaned SimulationTier/LastInteraction/ScopeTag types
7. Add tracing::warn on FactionOnly non-numeric parse failure
8. Document Medium-range occlusion gap as TODO in audible_at
9. Insert SoundEventQueue in observer test setup_world
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tile-level floor plans with sightline analysis for all three Sova Transit
District locations. Unblocks copy team content packs #190, #191, #192.
- spatial-layout-terminal-v01.md: The Terminal (44×28m), scanner bays,
main corridor chokepoint, manifest processing, cargo floor, supervisor
office with window, restricted storage. Sightline table, access tiers,
NPC traffic density, Triangle 1 + 2 service notes.
- spatial-layout-bar-v01.md: The Last Shift (28×22m + eastern extension).
Corner booth sightline analysis (sees entrance, bar, card table, back
room door simultaneously). Bathroom corridor as private exchange zone.
Triangle 3 + 4 service notes.
- spatial-layout-smuggling-corridors-v01.md: Ring infrastructure overlay
— restricted storage staging, maintenance corridor network, three
dead-drop locations with discovery vectors, transition corridor (40m)
with camera constraint and traffic density. Full operation flow diagram.
Also carries forward minor visual-grammar and placeholder-spec corrections
from earlier in the sprint (wall_top tile spec, cursor D-056 attribution,
transition strip procedural generation clarification).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Review fixes: deduplicate dump_schedule_graph doc comment,
add rng_seed round-trip test and v9→v10 backward compat test.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- main.gd: add has("entity_id") guard to _play_recognition_chimes()
(matches defensive pattern in _play_close_sound_events and update_sound_events)
- sound_indicator_renderer.gd: rename _color_for_type → color_for_type
(public testable API, not an internal-only method)
- test_rendering.gd: update test calls to match rename
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tracing (#344):
- Add 'json' feature to tracing-subscriber dependency
- Emit JSON log format when CI=true or RUST_LOG_FORMAT=json is set
(structured log ingestion in CI pipelines)
- Add tracing::debug! with tick_ms/budget_ms/over_budget fields on each
tick for performance profiling and tier system debugging prerequisite
Schedule dump (#346):
- Add --dump-schedule CLI flag that prints bevy_ecs schedule graph and exits
without requiring TCP bridge or world setup
- Add make debug-schedule target for CI artifact generation and diff-based
regression detection of unintended system reordering
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds rng_seed: Option<u64> to ObserverSnapshot. The WRONG button (#507) captures
inputs.jsonl and seed.txt for replay, but seed.txt was writing "unavailable"
because the server did not include the RNG seed in ObserverSnapshot.
Changes:
- bridge/types.rs: PROTOCOL_VERSION 9→10, rng_seed field with serde(default,
skip_serializing_if = "Option::is_none") for backward compatibility
- perception/observer/mod.rs: inject Res<SimRng> into compute_observer_snapshot,
populate rng_seed: Some(rng.seed()) each tick
- All test files: add rng_seed: None to ObserverSnapshot constructors
- tests/serialization.rs: bump protocol_version_constant assertion 9→10
- Regenerate msgpack fixtures and golden file for protocol v10
Completes the WRONG button capture loop: replays can now fully reproduce
observed bugs with the exact RNG seed from the capture.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
#94 — Active tier simulation (complete):
- Add ActiveSim marker to all 9 test world room NPC spawns
- Fix test entities in routine.rs and path_follow.rs to include ActiveSim
so With<ActiveSim> queries match correctly in unit tests
#99 — Tier transition logic (complete):
- Implement update_tier_markers system in tier.rs
- Promotes/demotes tier markers by manhattan distance from PlayerCharacter:
≤40 tiles → ActiveSim, ≤120 → BackgroundSim, beyond → StateSaved
- Handles cross-z-level as u32::MAX (effectively unreachable)
- No-op when no PlayerCharacter entity present (headless tests safe)
- 11 new unit tests covering all distance bands and boundary cases
- TierPlugin now registers the system after movement::validate_movement
Also picks up extended test coverage added by hoshe:
- observer/tests.rs — 230 lines of perception observer tests
- sound.rs — additional sound event integration tests
All 548 tests pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
DIALOGUE_MAX_WIDTH: correct to 640px (20 × TILE_SIZE) per Tyre architecture
review. D-076 updated in decisions/perception.md with amendment note.
Initial 1920px was D-061 "max-width" but readability wins at 640px.
D-067 recognition chime: wire sfx_monologue_chime to fog entity recognition
onset. AudioManager.CHIME_RECOGNITION constant added. main.gd tracks seen
entity IDs in _known_recognition_ids; fires chime on first appearance in
pending_recognitions, expires when entity leaves the queue. UISounds bus
(not WorldSFX) per D-038 "monologue chime is a UI sound." Tests added
to test_audio_bus_routing.gd (Layer 2b).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add rng_seed: Option<u64> to ObserverSnapshot (protocol v10). Populated
from SimRng state each tick. Completes the WRONG button capture loop —
seed.txt now writes a valid u64 instead of "unavailable", enabling
deterministic replay from bug reports.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add clippy::disallowed_types for std::collections::HashMap scoped to
the simulation crate. Replace HashMap with BTreeMap in movement.rs for
deterministic iteration order. Allow exception in perception/query.rs
where iteration order is irrelevant (per-frame scratch buffer).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements 4 completed tickets + partial progress on 2 more:
- #93 Tier marker components (ActiveSim, BackgroundSim, StateSaved + TierPlugin)
- #138 Information tag schema (ObserverAccess enum in knowledge/types.rs)
- #124 Sound event system (SoundEventEmitter, SoundEventQueue, bridge wiring)
- #193 Line previewer CLI (line_preview binary with filter/explain/sequence modes)
- #94 Active tier simulation (in progress — With<ActiveSim> filters)
- #139 Component-level access control (in progress — filter_by_access)
Updates snapshot fixtures and test golden files for new sound_events field.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
#345: entity_renderer.gd already used entity_id; added regression tests
confirming old "id" field is rejected and "entity_id" is accepted.
#447 (OQ-29): DIALOGUE_MAX_WIDTH = 1920 added to constants.gd. Full
viewport width at target resolution (60 × TILE_SIZE), per D-061 Lead
directive "max-width". Recorded as D-076 in decisions/perception.md.
#126: SoundIndicatorRenderer — fog-edge directional arrows for medium-range
sound events (D-018). Node2D at z:951 in World scene. Color-coded per
D-018/D-069 (neutral/voice/danger). GameState.medium_sound_events
partitions Medium events from snapshot sound_events field. Tests added
to test_rendering.gd; Hoshe's test_sound_indicators.gd stubs updated.
#125: Close-range stereo audio pipeline wired. AudioManager.play_sound_event()
maps event_type to D-038 asset key (Footstep/FootstepSprint → sfx_footstep_*).
GameState.close_sound_events partitions Close events. main.gd calls
_play_close_sound_events() each snapshot tick. test_audio_bus_routing.gd
Layer 4 stubs upgraded to real tests.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adopts the whatsinagame naming pattern where the domain comes
first and the action second (e.g. pr-review, sprint-start,
audio-gen). Updated all cross-references in settings, agents,
docs, and inter-skill references.
12 renames: commit→git-commit, create-skill→skill-create,
gen-audio→audio-gen, gen-image→image-gen, plan-sprint→sprint-plan,
push-pr→pr-push, render-sprite→sprite-gen, review-pr→pr-review,
search-docs→docs-search, start-sprint→sprint-start,
start-workshop→workshop-start.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Warnings fixed:
- contraband.rs: scan event now always emits even when NPC already
knows (was skipped by early `continue`). Contract matches doc.
- test_world/mod.rs: ScanEventBuffer added to player spawn bundle
so check_contraband_scan doesn't silently no-op in gauntlet mode.
- npc/mod.rs → simulation/mod.rs: moved check_contraband_scan
registration to SimulationPlugin (operates on player inventory and
snapshot pipeline, consistent with process_talk_interaction).
Suggestions addressed:
- cross_room_transitions.rs T1: clarified standalone position vs
constants.rs observer position in comment.
- dialogue.rs: Vec<&str> dedup replaced with BTreeSet<&str> for
deterministic iteration (project convention).
- contraband.rs: added test for multiple simultaneous ScanAuthority
NPCs in range (564 tests total).
- dialogue.rs: doc-comment on relationship_to_trust explaining
KnowledgeConfidence ordering and Suspects default.
- cross_room_transitions.rs T5: noted direct KG API usage vs full
perception system.
- sprint_gauntlet.rs: documented intentional Contentment { level: 0 }.
- content_scaling.rs: noted GAUNTLET_NPC_COUNT is manually maintained.
- contraband.rs: doc-comment on cross-plugin registration rationale.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Gitignored .tmp/ avoids Bash permission prompts when writing
temp files for tea comment posting. Added sed -n blanket
permission. Updated review-pr skill to use Write tool into
.tmp/ instead of Bash heredocs to /tmp/.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Test plan for #507/#522, preliminary review of #522, and final
combine test report. All tests pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
33 tests: 17 for ring buffer (capacity, overwrite, JSONL format, seed),
16 for insert-off behavior (diegetic test, cursor transitions, cross-system).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Upgrades bug_report_dialog.gd from single-tick MVP to 60-tick rolling
history. Pre-allocated ring buffers for inputs and snapshots. Outputs
inputs.jsonl (replay-compatible), snapshots.jsonl, and seed.txt on F12.
Inter-frame input accumulation ensures no inputs lost between server ticks.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Option (a): cursor shape still changes (body orients to targets), but
verb labels and interaction prompts are suppressed when insert_active
is false. Amends D-056 and D-057 with resolution note.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cross-room transition tests (server/tests/cross_room_transitions.rs):
- T1: sprint suppresses interaction buffer, restores on Walk (D-055)
- T2: CarriedBy survives room transition — no TilePosition leak (D-065)
- T3: pause mid-corridor discards movement, Unpause resumes (D-031)
- T4: KnowledgeGraph persists across player position change (D-041)
- T5: entity knowledge downgrades Direct→KnowsDetails on LOS exit (D-060)
- T6: eavesdrop cut immediately on first movement out of corner (D-071)
- T7: confrontation verb disappears on retreat beyond MID_RANGE=5 (D-057/D-070)
- T8: Sprint blocks eavesdrop accumulation, Careful enables it (D-055+D-071)
All 8 tests pass. Test suite grows from 545 → 563 (18 tests added across sprint).
Tests use direct ECS World + Schedule pattern; T3 uses full App + SimulationPlugin.
Test suite expansion:
- content_scaling.rs: max_npc_pack_behavioral_regression + stress tests (#513)
- golden/proof_room_tick_10.json: updated golden file for gauntlet world changes
- golden_suite.rs, serialization.rs, bridge_ipc.rs, bridge_tcp.rs: adapted to
new world entity count and wire types
- gen_fixtures.rs, perf_bench.rs, content_runtime.rs: minor test adaptations
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds three new test rooms to the gauntlet layout at coordinates that tile
correctly with the existing Sprint 11 world. All rooms follow the canonical
entity-registration pattern (StableId 55-62 assigned in spawn order).
- sprint_gauntlet.rs: 32×22 room (StableId 55-57) — Npc_pacing, Npc_guard,
Readable sign. Validates sprint suppression (D-055) at close range.
- eavesdrop_alcove.rs: 24×16 room (StableId 58-60) — two NPC speakers,
corner Readable marker. Validates eavesdrop positioning (D-071).
- confrontation_stage.rs: 32×24 room (StableId 61-62) — Npc_target and
peripheral passer-by NPC. Validates confrontation verb range (D-070).
Updated test_world: mod.rs registers all new rooms, constants.rs adds GAUNTLET
region constant and room spawn points, reset.rs clears all gauntlet rooms.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Server (5 tickets), client (2 tickets), and joint coordination
briefings for the Gauntlet completion sprint.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Hoshe:
- COLOR_FADE_DURATION 0.7 → 0.5 to match D-033 spec ("0.5s fade")
- Gauntlet guard tests now exercise InputMapper._unhandled_input()
with synthesized InputEventKey instead of asserting a bool
- Buffer clearing tests use SimBridge pipeline instead of manual nulls
- Add mid-transition re-trigger test (rapid relationship changes)
- Add relationship field to test snapshot NPC
Tyre:
- Add _teleport_in_progress flag to defer smoothing re-enable by one
frame after teleport (prevents same-_process() re-enable race)
- Add _test_gauntlet_mode to SimBridge test snapshot
- Extract TELEPORT_DISTANCE_THRESHOLD constant, mirror in tests
- Add comments: flash preemption, modulate/color independence
- Rename "hub teleport" → "Gauntlet dev teleport" in code comments
to clarify this is not production fast-travel
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Re-scope #501 hub teleport as Gauntlet-only dev tool. Production
travel must be diegetic: local gate → system gate → target menu →
destination, gated by region safety, with asymmetric information
exposure (NPCs observe arrivals/departures).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Entity renderer now tracks relationship per entity and tweens D-033
tint color over 0.7s when relationship changes (e.g. on confrontation
delivery). Uses manual lerp in _process() for testability instead of
SceneTree tweens. Cursor hover tint cascades automatically via
Constants.color_for_entity_kind().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Home key sends TeleportToHub in Gauntlet mode. Camera snaps to hub
spawn with 0.3s fade-from-black. Clears dialogue/monologue buffers
on teleport. Teleport detection uses distance threshold (>5 tiles)
so future teleport types get the transition for free.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Warnings: facing indicator tests use Godot-normalized rotation range
(-PI, PI] instead of raw addition (SW/W/NW in test_rendering,
West in test_client_p3). Suggestions: cache font in world_radial
_draw(), fix docstring on deactivate_insert() trigger, document
tile-coordinate system on _eval_player_near (D-066), add public
reset_facing_state() to InputMapper (D-030 testability).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
push-pr now runs /commit first when uncommitted changes are detected,
making it a one-stop commit→push→PR command. Added Skill to
allowed-tools for cross-skill invocation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Documents audio-batch manifest format, synth parameters, and the
--post flag as the preferred workflows. Batch reduces approval
count from ~30 to 2 for multi-asset generation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reduces prompt approvals from ~30 per batch to 2 (one manifest write,
one batch run). audio-generate --post chains trim+normalize+convert
after generation. audio-batch processes a JSON manifest of multiple
assets sequentially, supporting both SAO generation and harmonic
synthesis methods. Includes --dry-run, --only, and --skip-existing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Critical:
- deactivate_insert() now called when selecting non-Insert spoke,
cancelling with no selection, or pressing Escape while insert is
active. Fixes simulation staying paused permanently after Insert.
Warnings:
- Checklist conditions with empty id excluded from get_results() and
get_total_count() — prevents impossible-to-complete checklists.
Warns at load time when empty-id conditions are found.
- _content_base now checks res://content/ first (exported builds),
falls back to ../content for editor/dev mode.
- 26 new tests for D-054 functions: _angle_to_octant (8 octants),
_snap_to_octant_dir (9 cases incl. zero/tiny), _wasd_to_world_dir
(8 facing/movement combos). New test file: test_input_mapper_facing.gd.
Suggestions:
- Cached get_theme_default_font() in checklist overlay _ready().
- Documented InputMapper → GameState coupling as intentional.
- Documented YAML parser # truncation limitation.
- _insert_active reset on Escape dismiss (Tyre #3).
- SimBridge test mode SetFacing reads action_data.facing instead of
InputMapper global (Tyre #4).
- Removed dead _facing_to_rotation() from entity_renderer.gd (Tyre #5).
- Fixed 2 failing facing indicator tests to use InputMapper.facing_angle
instead of GameState.player_facing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Document non-blocking receive contract in perf_bench.rs docstring,
confirming no TCP deadlock race (Hoshe #1, critical)
- Make shadowcast parser order-independent — flush on new config header
instead of requiring Recursive after Symmetric (Hoshe #2)
- Fix p95 calculation: use floor(0.95*(N-1)) nearest-rank instead of
ceil(0.95*N)-1 which was off-by-one at N=50 (Hoshe #4)
- Error on --compare when no baseline file exists (Hoshe #5)
- Add D-031 10tps assumption comment to TICK_BUDGET_US (Tyre #1)
- Strengthen snapshot assertion: require warmup + half measurement
window instead of warmup + 1 (Tyre #2)
- Regenerate baseline with corrected p95 (356µs, was 526µs)
Hoshe #3 (.PHONY) was already addressed — perf-baseline is in the
.PHONY declaration on Makefile line 10.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Updated ambient.md, sfx.md, and ui.md with generation parameters,
frequency specs, and integration notes for all 8 new assets.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Mouse position now determines facing direction as a client-side float.
WASD remapped: W=toward cursor, S=away, A/D=strafe. Facing octant
derived from mouse angle and sent to server via SET_FACING action only
when it changes. EntityRenderer facing indicator uses continuous angle
for smooth rotation. SimBridge test mode updated to handle SetFacing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Michroma-Regular.ttf (OFL license) as the game font. Create
FontVariation with +1px tracking and a global Theme resource with
cyan-white (#E0F7FA) implant text color. Wire theme into project.godot
so all Label/RichTextLabel/Button/LineEdit nodes inherit automatically.
Add IMPLANT_TEXT_COLOR/DIM/PULSE constants to constants.gd.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two new scratchpad entries: asset generation pipeline improvements
(registry, status tracking, prompt versioning) and a remote terminal
proxy concept for mobile monitoring of Claude Code permission prompts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds `make perf-baseline` — boots the full server plugin stack with
real content, measures 50 ticks (5 warmup), captures per-tick timing,
entity counts, and process RSS. Includes shadowcast benchmarks. Saves
structured JSON to tests/perf/baseline.json for regression detection.
Supports --compare mode (>20% threshold).
First baseline: mean 366µs, p95 526µs (0.5% of D-026 100ms budget).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Check 9 tested `target in npc_rels` which missed NPCs with no
relationship entries. Changed to `target in self.npcs` so the
advisory warning fires correctly for all NPCs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
On main, the skill now assesses sprint state and does the next right
thing: close active sprint (Case A), activate planned sprint (Case B),
or suggest /plan-sprint (Case C). Cases chain automatically — closing
flows into activation if a planned sprint is waiting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Technical project descriptor with game architecture, simulation
parameters, and content model. Version field (0.1.9) is now the
canonical version — Cargo.toml synced, CLAUDE.md and start-sprint
skill updated to reference it during release workflow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Step 7 now transitions all unblocked sprint tickets to in_progress
immediately rather than deferring to agents (who forget). Completes
the ticket lifecycle: start-sprint → in_progress, push-pr → review,
sprint stop → done.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Step 7 scans commit messages for #NNN ticket refs and transitions
in_progress tickets to review status. Only in_progress → review;
other statuses are left alone.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
sprint stop now marks in_progress/review tickets as done
automatically — agents often forget to update status after merging.
Backlog/ready tickets are left as carry-over candidates since they
were never started.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When invoked on main, /start-sprint now closes the active sprint,
bumps the version to v0.1.N, moves changelog entries under the new
version heading, tags, and pushes. Team branch behavior unchanged.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Generated by headless --import after audio merge. These are needed
for stable UID references across editor sessions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ticket create previously had no way to set descriptions, causing
agents to work around with raw SQL or mangled titles.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
build-client used --quit without --import, which failed to create
.godot/ and register class_name types after a clean. game target
only depended on build-server, skipping client entirely. clean now
preserves the .godot/ directory itself while clearing contents.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Cast Variant to String via str() before passing to _on_room_change
- Clear _current_room_id on null room transition (fixes re-entry skip)
- Add push_error for failed dir creation and file writes in _save_report
- Fix docstring: tests/gauntlet-stats.json → user://dev/gauntlet-stats.json
- Namespace stats path to user://dev/ to avoid save data collision
- Replace print() with push_warning in _save_report (codebase consistency)
- Downgrade client-only wire guard from push_warning to silent return
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- golden-diff restores committed file even on cargo test failure
- Wire checklist-validate into pre-pr-content gate
- Fix schema description: condition IDs are globally unique, not
per-file; document room_id prefix naming convention
- Add schema file missing error handling in validate-checklist
- Add scope discriminator field (per_room/cross_room) to schema
- Check pyyaml and jsonschema packages in setup-tooling
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Re-generate monologue chimes (were oversized placeholders) and
fog_recognition (was silent). Fix sample rate headers on remaining
assets (192kHz→44.1kHz). All 8 UI assets now at 44.1kHz stereo,
LUFS -16 normalized, Vorbis q6, durations within D-038 spec.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
F12 pauses simulation, shows modal LineEdit prompt, saves three files
to user://bug-reports/gauntlet-t{tick}-{timestamp}/: snapshot.json
(full ObserverSnapshot), render.txt (simplified client-side text
render), description.txt (tester notes + tick/room/stance metadata).
Esc cancels without saving. Double-activation guard prevents stacking.
BUG_REPORT action added to InputMapper with wire guard in SimBridge
(client-only, never sent to server). Dialog on ModalLayer (CL 30).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
GauntletHUD in UILayer shows TIMER: MM:SS (PB: MM:SS). Timer starts on
room entry, resets on room change, records personal bests to
user://gauntlet-stats.json. Session summary printed on disconnect.
Hidden in non-gauntlet mode (anti-tedium guard).
Adds room_id and gauntlet_mode fields to GameState, parsed from
ObserverSnapshot. Main.gd wires update_from_state() and finalize().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Golden targets: make golden-diff shows color diff if simulation output
changed, make golden-update regenerates and stages for review.
Checklist schema: JSON Schema for 7 condition types evaluable from
ObserverSnapshot. Per-room YAML checklists for 3 Gauntlet rooms plus
cross-room checks. Validation script + make checklist-validate/generate.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add SimBridge._last_snapshot = null to P3 before_test() (contamination risk)
- Clarify mono.is_visible is custom property, not CanvasItem builtin
- Camera smoothing test uses approximate equality instead of exact
- Propagate inner _encode_message errors in array/dict encoding
- Add explanatory comment on int_64 encoder branch
- Document unfalsifiable gauntlet guard as intentional future-proof
- Remove loose D-053 citation from LERP_SPEED pin
- Assert FogOverlay is sibling of FogGroup under World
- Add CANVAS_MODAL=30 (ModalLayer) assertion in P3-Z04
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fail on encode errors instead of silently writing empty .msgpack files
- Fail test on missing/empty fixture dir instead of silent skip
- Add all missing action variants (MoveSouth, MoveEast, MoveWest,
Unpause, ToggleStanceDown, WalkAway) to GDScript fixture generator
- Add GDScript fixture staleness check to make pre-pr
- Validate repo root detection before writing outside client/
- Add file.flush() before close in headless mode
- Document fixture failure recovery in DEVOPS.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Documents the {domain}-{action} naming pattern for new skills
so future skills follow the convention established in the kit.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude-native starter kit that bootstraps multi-agent team
infrastructure for any project. Clone once, install as a global
skill, run /kit-install in any project directory.
Includes:
- 3-tier profile system (minimal/standard/full: 3-12 agents)
- 16 agent archetype templates with personality spectrum
- 18 skill templates using domain-action naming convention
- Stakeholder persona panel for workshops and PR reviews
- SQLite ticketing DB with CLI tools (config-based DB paths)
- Decision tracking, sprint lifecycle, workshop orchestration
- Multi-git-host support (GitHub, Gitea, GitLab)
- /kit-update skill for syncing with source repo evolution
- Naming theme support for agent identity/flavor
- Smoke tests for all three profile tiers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Regression guards for Sprint 9 QA features:
- F12 bug report (2): no-crash without handler, no queued input action
(stubs for when #495 WRONG button lands)
- Gauntlet UI hidden (3): no gauntlet nodes visible in default mode,
no room_id/gauntlet_mode in normal snapshots, stays hidden across
multiple ticks
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The int_64 branch condition `-(1 << 63) <= value` overflowed in
GDScript's signed 64-bit arithmetic, making the branch unreachable.
Negative values beyond int_32 range were incorrectly encoded as
uint_64 (0xcf) instead of int_64 (0xd3). Replaced with `value < 0`.
Updated boundary tests BV-N15 and BV-N16 to expect correct int_64
header byte.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bump PROTOCOL_VERSION from 7 to 8 to match server. Three changes:
1. Add dialogue_response field decoding (DialogueResponseEvent with
line_id, text, speaker_entity_id) from server #305/D-028.
2. Fix Interact encoding: server changed PlayerAction::Interact from
unit variant to struct variant with {target_entity_id, verb}.
Extract _encode_action() helper to handle this consistently.
3. Update all test assertions that checked version=7 or expected
Interact as a bare string.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
test_monologue_not_duplicated_after_consumption was failing because
poll_snapshot() in test mode returns _test_snapshot() without
consuming _last_snapshot. The carry-forward logic then incorrectly
preserved the monologue. Fix: directly clear _last_snapshot to
simulate the live-mode consumption path.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Separate workspace crate at tooling/test-client/ importing bridge
types from server crate. CLI: --connect, --replay, --text, --json,
--quiet, --golden, --ticks. Exit codes: 0=success, 1=golden mismatch,
2=connection error. Golden file comparison with recursive JSON diff.
JSONL replay loader for tick-scheduled input sending.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
format_snapshot_text(&ObserverSnapshot) -> String pub-exported from
server crate. Entity labels as kind:entity_id sorted by distance,
room name stubbed as (unknown) until Gauntlet constants land.
10 unit tests. Consumed by tooling/test-client for --text mode.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sprint 9 theme: Gauntlet — test infrastructure backbone with test
client binary, Gauntlet rooms 1-3, golden file suite, and client QA
harness. 23 tickets across server (9), client (6), CI (6), audio (2).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Address all review comments from Hoshe and Tyre on PR #27:
- Remove 2>/dev/null from pre-pr-fixtures (critical: swallowed errors)
- Remove dead _file_type function
- Check 4: error on districts with no locations declared
- Check 5: print advisory message when skipping
- Check 8: cross-file line ID uniqueness (not just per-file)
- Check 9: document D-034 asymmetric relationships in docstring
- Document regex fallback rationale in _scan_knowledge
- Add D-035 decision trace to schema descriptions
- Use concrete protocol version in DEVOPS.md example
- Amend D-035 with focused (9th mood) and greeting (14th situation)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds 'focused' to mood enum and 'greeting' to situation enum in
dialogue-pool.schema.json. Both values are used by Sprint 7-8
dialogue content but were not added to the schema at the time.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
7 client tickets closed (#435-437, #470, #476-478) after
PR #25 and PR #26 reviews completed and merged.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update existing snapshot fixtures for protocol v8 (dialogue_response
field). Add 14 raw boundary value fixtures and 5 snapshot boundary
tick fixtures for encoding edge case coverage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement full dialogue selection pipeline (D-028): 4-layer filtering
engine with access tier, situation derivation, trust tier, and weighted
topic+mood scoring via SimRng. Add ContentSlug component for stable
content identity across save/load. Add walk-away KG recording with
IncompleteInteraction events per D-064 three-phase consequences. Bump
protocol to v8 with DialogueResponseEvent. Fixes#305, #427, #452.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add AnomalyMarker component and detect_anomalies() system that flags
entities with KG relationship PersonOfInterest or Contradicted state
for urgent cognitive delay (0.3s vs 0.6s normal). Add
trigger_recognition_monologue() that fires monologue at delay START
(when grey blob appears), not at completion — the monologue IS the
recognition process per D-060. Includes v0.1 fallback recognition
lines and cooldown tracking. Fixes#450, #451.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add CLI argument parsing for test infrastructure: --test-mode enables
deterministic seed (42) and warn-level tracing to stderr, --port allows
OS-assigned ports (--port 0), --seed overrides RNG seed. Prints
LISTENING:{port} to stdout after bind for test harness discovery.
Extracts setup_proof_room() for reuse. Fixes#459.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace HashSet with BTreeSet for visible_ids, sort visible_tiles by
coordinates, sort visible entities in snapshot by entity_id, and sort
movers by Entity bits in validate_movement. Required by D-010 principle 4
(deterministic simulation). Fixes#456, #457, #458.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Critical fixes:
- hide_dialogue() sent PAUSE instead of UNPAUSE, permanently freezing
simulation after every dialogue (both reviewers)
- Confrontation monologue hardcoded in GDScript constant, violating
D-042/D-020 — moved to ui-strings.yaml as dialogue.confrontation_beat
- Walk-away WASD didn't call set_input_as_handled(), letting movement
event propagate and potentially stepping on the same frame
- is_dialogue_active() returned _is_showing only — interaction list
could flash during 300ms fade gap. Now includes dialogue_active state
- Removed dead _last_dialogue_id / get_dialogue_id() state (never read)
Warnings addressed:
- Audio registry now scans res://audio/ recursively (subdirs registered)
- add_bus_effect guarded against duplicate calls in tests
- int64 encoder dead code tagged KNOWN-DEFECT, filed as ticket #516
- D-073 zone crossfade stub comment clarifies Sprint 9+ deferral
- listening_focus dip documents caller tick-gate responsibility (D-069/D-071)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Define VIS_HIDDEN/PERIPHERAL/FORWARD and EXP_UNEXPLORED/EXPLORED/
VISIBLE in FogState. Replaces 7 magic number usages in _resize() and
update_from_state(). Provides stable assertion targets for fog tests.
Implements #476.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Agents were sending outputs as messages instead of writing files,
which prevented Qatux (documenter) from reading other agents' work.
Now each round task instructs agents to write to
docs/workshops/{name}/{agent}-roundN.md, and between-round steps
verify files exist before proceeding.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
4-track workshop targeting the class of bugs from Sprint 6-7: blocking
I/O, serialization boundaries, state desync, off-by-one encoding.
Participants: Tyre, Hoshe, Dudley, Stig. Covers integration test
architecture, serialization boundary tests, client test infrastructure,
and test gap prioritization. Includes catalogue of 6 real bugs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document client-side movement throttle rates per stance, hold-to-move
input model with composite diagonals, and crouch ticks-per-move value.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
10 gdUnit4 tests verifying camera behavior: SimBridge test mode
connection, snapshot pipeline, player position extraction, camera
anchor in _ready(), smoothing disable/re-enable cycle, camera tracking
across frames, and player movement following.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Entity renderer: add framerate-independent position lerping so entities
slide between tiles instead of snapping. Tuned for Sprint snappiness
and Walk/Careful fluidity.
Fog shader: set ColorRect to transparent fallback so a shader load
failure doesn't paint solid white over the world. Track camera position
(not player position) so fog stays synced during smooth camera pan.
Restructure GLSL to avoid early return (some GPU drivers miscompile it).
Minor type fixes: typed Array[Vector2] in cursor_renderer tick drawing,
untyped Array in inventory_grid to avoid Godot typed-array cast issues.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Off-by-one in all four signed int branches: upper bound used <= instead
of < (e.g., value <= 128 matched int8 instead of falling through to
uint8). Tick 128 was encoded as int8 -128, causing server deserialization
failure. Also remove stray debug prints from nil/false decode paths.
Fixes bug #4 (MessagePack encodes tick 128 as -128).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three client input/bridge fixes:
1. Pause toggle: add UNPAUSE action and toggle logic based on
GameState.game_time.tick_rate. Wire UNPAUSE in sim_bridge.gd.
2. Hold-to-move: replace press-event movement with polled _process()
direction sampling. Composite diagonals via simultaneous keys
(W+D → northeast). Client-side throttle per stance (D-053):
Sprint=200ms, Walk=400ms, Careful=600ms, Crouch=800ms.
3. Snapshot carry-forward: when a newer snapshot overwrites an
unconsumed one, carry forward current_monologue and current_dialogue
so one-shot events aren't silently dropped.
Fixes bugs #5 (monologue lost on overwrite) and #6 (overwrite spam).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Camera2D's internal smoothed_camera_pos starts at (0,0) and lerps
toward global_position, causing a visible white-screen drift on startup.
Disable position_smoothing in _ready(), snap camera to player position
from the first snapshot, then re-enable smoothing with reset_smoothing()
after the first anchored frame. Add tick guards to monologue/dialogue
consumption to prevent re-triggering when client FPS > sim tick rate.
Fixes bug #2 (camera doesn't center on player at startup).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
process_player_input processed movement commands regardless of tick
rate, causing the camera to drift from the player when the game was
paused and the player held direction keys. Add PlayerAction::is_movement()
helper and a paused guard that skips movement actions while TickRate is
Paused. Pause/Unpause commands still process normally.
Fixes bug #3 (player moves while game is paused).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
read_framed() called read_exact() which blocked the entire bevy Update
schedule waiting for client input — no systems ran until a keystroke
arrived. Switch TcpStream to non-blocking mode so receive_inputs()
returns Ok(vec![]) on WouldBlock instead of blocking. Toggle to
blocking for snapshot writes (reliable delivery). Add 50ms frame
throttle (~20 ticks/sec) since the non-blocking loop would otherwise
spin. Downgrade input receive logging to trace, add error logging for
missing bridge resource and failed observer queries.
Fixes bug #1 (server never sends snapshots) and #2 (camera doesn't
center until first keystroke).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Version numbers in test filenames go stale every sprint. The file tests
bridge protocol features (stance, inventory, fixtures) not a specific
protocol version.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sprint 8: React — briefings for server, client, audio, and joint teams.
Database snapshot after Sprint 8 ticket assignments.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Generated via Stable Audio Open with sonic family prompt prefixes:
- cursor_hover.ogg (insert-tech, digital click)
- weapon_aim.ogg (insert-tech, mechanical latch sketch)
- implant_open.ogg (insert-tech, neural lattice rising tone)
- fog_recognition.ogg (organic, cognitive realization chime)
- sfx_monologue_chime.ogg (insert-tech, placeholder per D-071)
- sfx_monologue_chime_urgent.ogg (insert-tech, placeholder per D-071)
All assets need duration trimming in next audio sprint (#453).
Updated docs/assets/audio/ui.md status to draft.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fog entity cognitive delay rendering (D-059/D-060): sonar-style sound
pings (3 concentric rings, 1.5s fade), unrecognized grey blobs with
breathing pulse, D-033 color transition at 50% recognition progress,
±0.5 tile position drift. FogEntities node at z:950 between fog
shader and InsertOverlay.
Protocol v7 bump to match server PR #23 (pending_recognitions field).
Wires dialogue box and fog entities into game loop with mock test data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
D-061 compliant UI skeleton: NPC speech top, max 3 response options
below, left-aligned. Insert-styled colors (white-blue, amber hover,
green pressed). WASD walk-away fades over 300ms, no close button.
InsertOverlay (CanvasLayer 10, z-layer 6). Mock data in next commit.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server PR #23 bumped PROTOCOL_VERSION to 7 (pending_recognitions field).
Client must match before #431 fog entity visualization or joint testing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
dialogue-ambient-dip.md: full Godot implementation spec for dialogue
(-7dB ambient) and confrontation (-11dB ambient + LP 800Hz, -5dB world
SFX) audio dips with tween code and edge case handling. synth_ui_sounds
.py: FM/noise/impulse synthesis for insert-tech UI sounds (cursor hover,
weapon aim, monologue chimes).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Critical fixes:
- Add PendingRecognitionWire serialization roundtrip test
- Check Option return from delay.cancel() before logging
- InputQueue capacity limit (1000) with drop-oldest and warning
- TODO in observation.rs references ticket #450
Warning fixes:
- Hot-reload guards against invalid/empty content root
- Location header mismatch warning in line pool indexing
- walk_yaml() depth limit (100) against symlink loops
- Consecutive reload failure counter (warns after 5+)
Test additions:
- Negative prerequisite filtering test for monologue lines
- Integration test for pending_recognitions in observer snapshot
- Eavesdrop threshold ordering assertion (Careful < default)
Documentation:
- Playtesting expectation comments on delay constants
- is_pending() scalability note for future NPC cognitive delay
- ID format regex validation in line pool spec
- BTreeMap vs sort() ordering clarification in loader
- Multiplayer TODO in relationships.rs references D-010
- ContentSlug ticket #452 filed for entity slug resolution
394 tests, 0 failures.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
audio-generate: Gradio API wrapper with timeout handling (600s default),
sequential-only generation, SSE stream polling. audio-health: API
health check. audio-post: ffmpeg wrapper for convert/normalize/trim/
pipeline operations. All follow existing connector pattern.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Category-based asset index for audio, visual, and video pipelines.
Audio pipeline fully populated: palette (sonic identity bible), ambient
loops, SFX, UI sounds with generation specs and mix parameters.
Visual and video are stubs pending their respective workshops.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sprint 7 server entries: cognitive delay, ListeningFocus, YAML loader,
line pool spec, interaction memory schema.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Formal spec at docs/architecture/line-pool-format.md defining YAML
structure for dialogue and monologue content files. Covers tag enums,
4-layer filtering pipeline, prerequisite-to-KG mapping, ID format,
validation rules, and Rust loader interface.
Fixes monologue schema: adds required constraint on relationship
prerequisite target/state fields.
Ref: D-028, D-032, D-035, D-041
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New CognitiveDelay component buffers perception events before emitting
KnowledgeEvents. Normal delay: 6 ticks (0.6s), urgent: 3 ticks (0.3s).
Drain system runs after emit_observation_events, before process_knowledge_events.
Adds pending_recognitions to ObserverSnapshot (protocol v7) for client
fog entity visualization. Includes cancellation when entity leaves LOS.
Monologue fires during delay (not after) per D-060 — cross-system
wiring deferred to follow-up ticket #451.
Ref: D-060 (cognitive delay), D-031 (10 tps), D-059 (fog layers)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New ListeningFocus component tracks stationary_ticks for eavesdrop
mechanic. Increments when position unchanged, resets on movement.
Sprint stance blocks accumulation, Careful reduces threshold from
30 to 20 ticks. Registered in SimulationPlugin after validate_movement.
17 tests covering all stances, thresholds, and edge cases.
Ref: D-053 (stance system), D-018 (sound model)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Formatting pass across simulation, perception, knowledge, NPC, and
test modules. Includes two clippy fixes in monologue.rs (.values()
instead of for (_, v) pattern).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Design specification for how evidence is presented differently per
archetype — detective case file (institutional, insert-assisted) vs
smuggler notebook (personal, unassisted). Covers item definitions,
knowledge graph presentation, contradiction markers, THE FRIEND
arc walkthroughs, systems interaction map, and authoring guidelines.
Sprint 7, ticket #443. Authored by Mellanie (copy), Paula (narrative),
Gestalt (systems).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Briefings for server, client, copy, audio, and joint teams.
Sprint goal: complete interaction UI layer and activate basic
dialogue system with NPC conversations.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Upgrade client protocol bridge from v5 to v6 to match server.
Adds player_stance (4 variants) and player_inventory decode to
ObserverSnapshot. Adds TOGGLE_STANCE_UP/DOWN to InputMapper.
Includes 25 gdUnit4 tests for v6 decode + server serialization
test gap fix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When sprinting past a Contradicted entity, queue a delayed retroactive
monologue that fires after ~1.5s: "Wait — something wasn't right back
there." SprintAnomalyQueue component with first-in-wins semantics.
Detection in observer pipeline, processing in monologue system.
Wire MovementProfile, Stance, and SprintAnomalyQueue into player spawn.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add MovementProfile component with per-archetype default stances (D-053).
Sprint stance now explicitly clears the interaction buffer — no verbs
computed or sent during sprint (D-055). Anomaly monologue pipeline is
unaffected (handled by separate system).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement physical inventory system per D-065:
- CarriedBy(StableId) component marks items as carried by an entity
- ItemName and InventorySlot components for display and slot assignment
- Take verb: removes TilePosition, adds CarriedBy + InventorySlot
- Place verb: removes CarriedBy + InventorySlot, adds TilePosition
- Observer snapshot populates player_inventory from carried items query
- Info boundary: carried items lack TilePosition, naturally excluded
from all spatial queries (visibility, interactions) for other entities
- 9-slot capacity (3x3 grid per OQ-24), auto-assigns first free slot
- 8 new tests covering take, place, sequential slots, full rejection
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Agents were navigating outside the git root into sibling worktrees.
Added explicit boundary rules: all work stays within the git root
unless directly instructed otherwise. Updated plan-sprint to enforce
worktree-relative paths in generated briefings.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
0.5m sim tiles for movement/LOS granularity, 1m visual tiles for
proportional art and readable spaces (2x retina factor). All world
geometry constrained to 2x2 sim tile minimum so cover/LOS maps 1:1
with visuals. Entities occupy 1x1 sim tiles for fine positioning.
Updates: D-043, D-044, D-051, D-056, D-059 annotations, workshop
outcomes (art direction + control/interaction), sprint 6 briefings,
decision index, and CLAUDE.md.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move universally-needed permissions from per-worktree
settings.local.json into the shared .claude/settings.json:
git operations, ticket/sprint/sqlite CLI, make, tea, skills.
Add deny rules for destructive operations (force push, hard
reset, clean -f, rm -rf). Migrate from deprecated :* suffix
to modern space-wildcard syntax.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Unified sprint script at db/connectors/sprint with 5 subcommands:
status, start, stop, start-work, prepare. Calls ticket CLI via
subprocess (no SQL duplication), auto-detects sprint from DB state
and team from git branch. Guards prevent activating unplanned
sprints. Updated start-sprint, plan-sprint, and ticket skills to
reference the new CLI. Added sprint CLI section to CLAUDE.md.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
These are auto-generated by Godot 4 to provide stable resource
references across renames. Tracking them prevents UID divergence.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The skill previously relied on the agent hardcoding branch names,
which missed non-standard branches like planning. Now explicitly
instructs the agent to use git worktree list for discovery.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three physical items for the smuggler archetype per D-065: manifest copy,
corridor access token, personal comm log. Each with KG links, confrontation
mechanics, and risk/reward gameplay notes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
18 tickets across 3 teams. Movement stances, fog shader rebuild,
multi-verb interactions, smuggler inventory.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Workshop notes (2 rounds), outcomes document (13 decisions, 27 tickets,
v0.1 interaction model), and updated brief with final lead direction.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
13 new decisions covering movement stances, tile-based movement, cursor states,
entity interaction, fog rendering, dialogue UX, confrontation, and smuggler inventory.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three physical inventory items for the smuggler archetype per D-065:
manifest copy, corridor access token, personal comm log. Each item
links to KG FactIds, defines confrontation leverage mechanics, and
creates risk/reward carry decisions. All flagged contraband.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three fixes to make the gameplay loop functional end-to-end:
- Add Interactable component to NPC spawn so E-prompt detection works
- Build monologue trigger system (enter_location + time_idle) with
MonologueBuffer/MonologueState components, wire through ObserverSnapshot
as current_monologue field, decode on client and display via HUD
- Change PlayerAction::Interact from unit to struct variant carrying
optional target_entity_id and verb fields
Bumps protocol version from 4 to 5. Regenerates MessagePack fixtures.
All 200 tests pass (170 unit + 30 integration).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The copy team rewrote ui-strings.yaml with multi-level nesting,
renamed sections, and inline comments. Update the YAML parser to
use a stack-based approach for arbitrary nesting depth, update HUD
and interaction prompt to reference the new key names, and align
tests with the new structure.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
UI microcopy strings belong in the client data directory where
the Godot client can load them directly, not in campaign content.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fixes from Gestalt mechanical review:
- 73 fact_id normalizations to dotted category.topic format (critical:
fixes broken detective evidence chain from Sera to Kael observations)
- Entity refs normalized to npc:hyphenated format (~15 occurrences)
- Phase tags standardized (friend-arc-phaseN → phase-N)
- Phase-2 tags added to 8 Kael ring ops lines
- bar_evening situation added to 15 Kael Last Shift lines
- Mood tags added to 10 Kael lines missing them
- 7 new detective monologue lines about Kael (gap: 7 → 15 lines)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Kael Davan FRIEND pack (86 lines): 3 dialogue files across terminal,
bar, and corridors. 5-phase relationship arc with contradiction scene.
Sera Venn FRIEND pack (75 lines): full dialogue at The Last Shift with
trust-gated gossip, avoidance contradiction, and contaminated trust arc.
PC-as-NPC content (70 items): smuggler and detective as NPCs with
public-tier dialogue, tell-observation monologue, and bar variants.
Enables D-039 wow moment #4 (divergence reveal).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comprehensive authoring handbook: tier budgets, 9 NPC patterns,
dialogue/monologue rules, tag taxonomy, dual-lens coordination,
Krenn/Sova regional culture, FRIEND phase mapping for Kael and
Sera, mechanical validation checklist, and worked example.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Filter YAML comment lines (grep -v '^\s*#') from both extraction
pipelines to prevent phantom canonical IDs
- Trim trailing whitespace from extracted fact_ids so grep -qxF exact
match works reliably
- Pre-commit dispatcher now prints explicit warning when a check script
is missing instead of silently skipping
- Document --no-verify bypass for emergencies in DEVOPS.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds UIStrings autoload that loads display text from a YAML file,
replacing hardcoded strings in HUD and interaction prompt. Copy team
can now author UI microcopy in client/data/ui-strings.yaml without
touching GDScript. Includes 38 strings across 5 categories and 16
gdUnit4 tests for the parser and lookup API.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds directive to focus on client-server integration tests landing
from Sprint 5, push for proper test harnesses, a dedicated test map
for routing/edge cases, and edge case coverage over happy-path volume.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Log each received player input at DEBUG level with tick and action,
useful for diagnosing input pipeline issues during live testing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests used entity_id matching to find the player, but game_state now
finds the player by kind.variant == "Player". Update test fixture to
include a Player entity and remove stale player_entity_id assignments.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Client was sending Time.get_ticks_msec() (e.g. 12345) as the input
tick, but the server's drain_for_tick only processes inputs where
tick <= current_tick (a small frame counter). Inputs accumulated in
the queue and were never processed, making movement keys unresponsive
in live mode. Use GameState.current_tick from the latest snapshot.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Protocol decoder now reads tile_kind from VisibleTile and maps it to
the client's tile type string (floor/wall/door/object). GameState
falls back to visible_tiles when the test-mode tiles array is absent,
enabling live server tile rendering.
Fix entity-to-tile alignment: server sends tile-center render coords
(tile 16 -> 16.5) but entity renderer was using raw floats, placing
entities half a tile off. Now floors the coords to get the tile index.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server was sending visible_tiles without tile type data, so the client
could not distinguish floor from wall in live mode. Add TileKind enum
(Floor/Wall/Door/Object) to VisibleTile, populated from WalkabilityMap
in the NaturalVision perception query. Update test fixtures to include
the new field. Uses #[serde(default)] for backward compatibility.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three tests validating the full client-server input path through a
live server: movement roundtrip (MoveNorth/MoveEast with position
verification), interact roundtrip (unit variant accepted as no-op),
and mixed sequence (movement then interact preserves position).
Catches integration seams that unit tests miss — each test spawns a
real server binary on a random port, connects via LocalBridge, and
exercises the TCP→deserialize→simulation→snapshot→decode pipeline.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add SR_LIVE=1 environment variable to switch SimBridge from test mode
to TCP connection. Default behavior unchanged (test mode).
- sim_bridge.gd: read SR_LIVE env var instead of hardcoded test_mode
- game_state.gd: find player entity by kind.variant == "Player" instead
of hardcoded entity_id 1 (real server assigns different IDs)
- Makefile: add 'make game' (builds server, starts it, launches client
with SR_LIVE=1, kills server on exit) and 'make stop' helper
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enable the interaction data attachment in main.gd game loop. When E
is pressed and the prompt is active, target_entity_id and verb are
attached to the Interact action before sending to the server. Without
a target, bare Interact is still sent as safe fallback.
Completes the v0.1 interaction prompt data flow:
server sends nearby_interactions → client shows prompt → E press
attaches target+verb → SimBridge encodes and sends to server.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
CLI tool to preview monologue/dialogue line selection for a given game
state. 4 subcommands: dialogue (D-028 4-layer pipeline), monologue
(trigger + prerequisite evaluation), coverage (dead conversation
detection), sequence (walk-through simulation). Authoring tool for
content team — tests line trigger logic without running the full game.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Build-time converter reads content YAML and emits RON format. Lives in
tooling/content-converter/ as standalone Rust crate. Runs via make
content-ron. Supports --dry-run, --verbose, --content-type filtering.
Not on critical path — engine consumes YAML in v0.1, RON is future-
proofing for runtime performance.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Design document defining what the randomizer produces at game-start:
FRIEND selections, pool draws, template assignments, triangle config,
entanglement config, contraband selection, starting knowledge. Includes
ChaCha20 RNG protocol, validation rules, and implementation roadmap.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extend content loader to read and instantiate real YAML content into
ECS entities. 2-phase spawn pipeline: Phase 1 creates entities with
core components (Want, Tolerance, Contentment, Personality, Tells,
Skills), Phase 2 resolves cross-references (Relationships, Secrets,
Information via KnowledgeGraph, DailyRoutine).
Loads enums, entity attributes, pools, templates, triangles, and NPC
profiles. Handles stub files gracefully. 7 integration tests against
real content files plus edge case tests for invalid data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Change want.primary from narrative strings to WantKind enum keywords
(Safety, Wealth, Knowledge, etc.) across all 20 NPC profiles. Move
narrative text to want.description. Add Happiness to WantKind enum.
Add enum constraint to npc-profile.schema.json so make validate-content
catches invalid values at authoring time.
Fixes silent Want component drop where parse_want_kind() returned None
for all real NPCs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
situation, topic, and mood fields changed from single string to
array type to match D-035 specification (list<enum>). access and
trust were already correct as arrays.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5 seed-time pools (single-candidate for deterministic v0.1 testing),
3 social site templates (logistics-hub, bar, smuggling-ring) with
role slot definitions per D-025, and 5 triangles (3 active fork,
2 passive) per D-024 workshop synthesis.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
200 monologue lines (100 per character) across 8 location files:
arrival flavor, NPC commentary, knowledge-gated contradiction lines.
20 dual-lens news ticker headlines for The Last Shift bar. First real
content load for the monologue system.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Convert 17 wiki NPC profiles to engine-readable YAML. Add PC-as-NPC
behavior profiles for detective and smuggler. Add smuggler-perspective
FactId progression text (27 FactIds with asymmetric knowledge paths).
Add off-stage NPC nils-davan. All files validate against npc-profile
schema (32 files, 0 errors).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move wiki from docs/wiki/ to root wiki/. Add 14 category templates with
YAML frontmatter, governance model, hierarchical spatial structure
(system > station > district > location). Populate Krenn System entry
as first concrete star system. Update cross-references in workshop and
sprint docs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server proof room now has 3 NPCs instead of 1. Find player entity
by kind instead of assuming entities[0]. Wall-hides test checks
specific NPC position (16.5, 13.5) rather than asserting zero NPC
count. Corner-reveal test searches for NPC1 by position.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server team shipped strict PROTOCOL_VERSION enforcement (c05ff7b),
1-indexed verb priorities, and "Observe" label for ExamineNpc.
Updates all test snapshots to include version: 4, fixes sim_bridge
test mode priorities (0-indexed → 1-indexed) and labels, replaces
v1 backward-compat tests with strict version rejection tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Content conversion and authoring sprint — 19 tickets across copy (8),
server (9), client (1 carry-over), and CI (1). Critical path runs
through wiki→YAML NPC conversion (#398) to content loader (#408).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server-driven interaction prompt that displays "E - Talk" when near
an interactable NPC. Decodes v4 nearby_interactions from snapshot,
stores in GameState, renders via InteractionPrompt UI with fade
animation. Extensible interface (get_interaction_target/get_selected_verb)
for future radial verb menu (v0.2).
- Protocol: decode nearby_interactions array with nested VerbOption structs,
entity relationship/observation fields, tick_rate in GameTime
- GameState: store/clear nearby_interactions per snapshot
- SimBridge: test mode generates v4 format with structured verbs
- InteractionPrompt: PanelContainer with fade in/out, polls GameState
- Tests: 19 new test cases covering protocol, state, sim bridge, UI, encoding
- Fixture assertions updated for v4 protocol version
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Client now rejects snapshots where version != PROTOCOL_VERSION (4).
Returns null with error log on mismatch. Test snapshot updated to
use Protocol.PROTOCOL_VERSION and v4 game_time format (tick_rate
replaces paused field).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract visibility geometry into a separate system behind a
PerceptionQuery trait, enabling D-017 perception mode swapping.
Two-stage pipeline: compute_visibility_geometry writes to
VisibilityGeometry resource, compute_observer_snapshot reads it.
Remove KnowledgeGraph from compute_nearby_interactions (simulation
phase boundary violation). Verb availability stays in simulation;
POI-based priority adjustment moves to observer via
apply_poi_verb_priority helper.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
These patterns were added for the renderer (now separate). Client
gitignore rules are the client team's responsibility.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Separates the 3D-to-2D render pipeline from the game client into its
own minimal Godot project. No autoloads, no plugins, no game code —
just the render scene, models, textures, and export script. Eliminates
SimBridge parse errors and gdUnit4 scanning during renders.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Godot 4.6 generates .uid files for script resources and .import files
in subdirectories. Both are editor-local and should not be tracked.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Godot @tool render scene that takes a textured 3D model and produces
2D sprites at 1024/256/64 from 4 cardinal directions with outlines
applied at working resolution. Camera at "the angle" (-72.5deg ortho).
Includes two POC wall models with Nano Banana textures, CLI wrapper
script with headless import step, and .uid files added to gitignore.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Four-agent workshop (Araminta, Ozzie, Miri, Gore) establishing visual
identity for The Settled Reach. 9 mood board images, 16 art direction
principles, 10 candidate decisions (D-042 through D-051), v0.1.1 sprite
plan. Post-workshop technical session resolved 3D render pipeline,
resolution chain (1024/256/64), and camera angle lock ("the angle").
Pipeline test samples included: Era 1 institutional wall + bar green
wall rendered through the full Nano Banana -> 3D model -> sprite chain.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Entity::to_bits() roundtrip test guards against bevy version changes
silently breaking wire IDs (Hoshe #1)
- PROTOCOL_VERSION constant used in test helpers instead of hardcoded 4
- TickRate switch mid-accumulation test verifies Half→Full→Paused→Half
transitions preserve accumulator state correctly (Tyre N3)
- POI mid-range test now asserts priority=1 (Hoshe #4)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Split observer/mod.rs (820 lines) into production code (244 lines) and
tests (480 lines). Reduces module size per Hoshe #3 review item.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Per-entity Component attached to PlayerCharacter instead of global
Resource. Makes the interaction buffer multiplayer-ready (D-009) —
each observer gets their own buffer without pipeline refactoring.
Updated all 8 files touching the buffer: system signatures, player
spawn bundles, and ~30 test spawn sites.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace silent Entity::to_bits() fallbacks with tracing::error in
observer.rs and interaction.rs (makes unregistered entities loud)
- Add PROTOCOL_VERSION constant to types.rs, use in observer snapshot
- Document single-observer assumption on NearbyInteractionBuffer
- Document proximity-only (no LOS) limitation on compute_nearby_interactions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Delete generate_snapshot from bridge/mod.rs — superseded by
perception::observer::compute_observer_snapshot. Not referenced
in any schedule or test.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace flat content/districts/ with hierarchical campaign/system/
station/district structure. Path mirrors canonical IDs, enables
glob-based discovery, and is multi-campaign/DLC ready.
- git mv 46 files preserving history
- New metadata: campaign.yaml, system.yaml, station.yaml
- Rewrite content.yaml with glob-based district discovery
- Add campaign, system, station JSON schemas
- Update district schema: hierarchy fields derived from path
- Update npc-profile schema: accept district-scoped IDs
- Add TODO to 17 dialogue/monologue pool files for generator revision
- Update _meta/README.md with new hierarchy documentation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Re-added system/station/district fields to district.yaml that were
incorrectly removed during Tyre10 cleanup. These carry hierarchical
context (planet, station), not redundant identity. Made canonical_id
optional in schema since it's derived from directory path at load time.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement compute_nearby_interactions system that detects entities
within close (≤2) and mid (≤5) Manhattan distance, computes
available verbs per D-060 spec. NPCs get Talk+Observe at close
range, Observe-only at mid range; PersonOfInterest flips priority.
Objects get Examine. Results populate nearby_interactions[] on
ObserverSnapshot v4. Bump protocol version 3→4. Implements #404.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace binary paused flag with TickRate enum (Full/Half/Paused)
per D-052. Full rate advances every frame, Half every 2 frames
via fractional accumulation, Paused blocks all advances. Add
SetTickRate player action for client-driven rate changes.
Implements ticket #406.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Scaffolds the full content directory structure per D-057 spec:
district-as-atomic-pack layout with Sova Transit as the first
district. Includes 17 NPC stubs, 3 locations, 5 triangles,
9 dialogue pools, 8 monologue pools, routines, 7 factions,
7 knowledge catalogs, 8 enum definitions, and global region.
Implements ticket #385.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Miri (critical):
- Fix 3 stale "Hael" references in decisions/content.md (D-034, D-036)
Paula (suggestions):
- Flag dual-fire 15-30s delay as tuning target in smuggler moral arc
- Clarify MIRROR NPCs can be wrong (lied to) without being dishonest
- Add implementation note for Path C deferred follow-up fork
- Note detective-NPC dialogue rotation variants for post-v0.1
- Clarify detective vs smuggler moral_weight criteria in entity attributes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- search-docs: remove content already in CLAUDE.md (basic commands,
endpoints, examples), keep only unique operations and workflows
- ticket: remove duplicated access method and SQL wrapper docs, add
missing show --brief command reference
- review-pr: extract branch-type reviewer profiles to
references/reviewer-profiles.md, reducing SKILL.md from 287 to 187
lines while preserving all reviewer specifications
- create-skill: remove empty .gitkeep placeholders from unused
references/ and scripts/ directories
Reviewed all skills against /create-skill conventions. Main findings
were CLAUDE.md content duplication wasting context tokens and a
progressive disclosure opportunity in the longest skill.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Paula, Miri, Ozzie lack Bash access and cannot git show from branches.
Skill now documents which agents can self-serve and instructs the caller
to read and paste file contents into prompts for agents that can't.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pushes current branch and creates or updates a PR without ever
merging into main. Prevents accidental PR merges by restricting
the skill to branch-side operations only.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use #[derive(Default)] + #[default] instead of manual Default impls
for FacingDirection, KnowledgeState, RelationshipState, EntityVisibility
- Replace manual modulo check with .is_multiple_of()
- Collapse nested if in shadowcast symmetry check
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix NpcPlugin system ordering: .before(compute_paths) instead of
.after(advance_tick) so PathRequests are picked up same frame
- Fix stale doc comment in interpretation.rs: system runs BEFORE
knowledge events, not after
- Add TODO(v0.2) on RelationshipGraph about information boundary
limitation for multiplayer
- Document cardinal-only movement as deliberate v0.1 choice
- Add comment on manhattan_distance u32::MAX fallback for cross-z
- Pin pathfinding crate to 4.11
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements ticket #239 for Sprint 3:
- ObservationTrigger enum: RoutineDeviation (NPC not at expected
routine location), Absence (expected location visible but NPC
missing), NewEntity (unknown entity in LOS)
- ObservationEventQueue resource with push/drain/len/is_empty
- generate_observation_events system runs after emit_observation_events
but before process_knowledge_events so it can compare current
snapshot against previous-tick knowledge state
- Populate PerceptionPlugin with ObservationEventQueue resource and
system registration with correct ordering constraints
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements ticket #84 for Sprint 3:
- Replace single bare NPC with 3 distinct NPCs: dock worker (16,13)
with full 4-phase routine and MovementSpeed(2), field tech (14,18)
with partial routine, stationary guard (18,14) with no routine
- Register all entities (player + 3 NPCs) in EntityRegistry
- Populate RelationshipGraph with colleague and rival edges
- Add NpcPlugin to app for routine system registration
- Add multi-entity visibility tests: 3 NPCs in LOS all visible,
NPC behind wall excluded from snapshot
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements ticket #341 for Sprint 3:
- Add DeserializationWithDump and MutexPoisoned variants to BridgeError
- Replace .expect("mutex poisoned") with graceful error propagation
in LocalBridge and TcpBridge (4 locations)
- Log first 256 bytes as hex dump on deserialization failure for
debugging malformed payloads
- Classify errors in receive_bridge_inputs: BrokenPipe/ConnectionReset
→ clean shutdown, MutexPoisoned → shutdown, DeserializationWithDump
→ skip frame (recoverable)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements tickets #237 and #238 for Sprint 3:
- Add pathfinding crate dependency for A* algorithm
- PathRequest component triggers compute_paths system which uses
cardinal-neighbor A* with manhattan distance heuristic
- ComputedPath component with step navigation (next_step, advance,
is_complete) and PathBlocked marker for no-route cases
- MovementSpeed component throttles NPC movement (ticks_per_step)
- follow_paths system advances NPCs along computed paths, creating
MoveIntent per step; cleanup_path_blocked removes markers after
one tick
- System ordering: input → compute_paths → follow_paths →
validate_movement → cleanup_path_blocked → advance_tick
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements tickets #86, #87, #88 for Sprint 3:
- Replace stub string/f32 NPC fields with typed enums and integer
types for D-010 determinism (WantKind, SecretSeverity, Skill, etc.)
- Add RelationshipGraph global resource with BTreeMap<(StableId,
StableId), RelationshipEdge> for efficient prefix queries
- Add DailyRoutine with phase-based RoutineEntry and PreviousDayPhase
resource for detecting day-phase transitions
- Create NpcPlugin that initializes relationship graph, day-phase
tracking, and registers check_phase_transition system
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wave 0 wiki maintenance for Sprint 3:
- #372: Rename Hael → Naia Tamm across 16 living wiki files (phonetic collision fix)
- #371: Apply canonical full names to 11 single-name NPC headers and roster table
- #375: Replace hub_m_ → terminal_m_ shortcodes, add shortcode reference table,
situation overlap rules, and mood exclusivity rules to monologue guide
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the solo plan-mode step with team orchestration: parse the
Agents line from the sprint briefing, create a team, create tasks
from tickets with dependency chains, and spawn all listed agents as
background teammates. User confirmation gates the spawn.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previous briefings referenced tickets not assigned to sprint 3.
Rewrote all four team briefings (server, client, joint, copy) to
match actual sprint 3 ticket assignments in the database.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- tooling/db-backup: copies shared settledreach.db to docs/backups/
for git tracking (main branch only)
- tooling/db-install: restores from backup for new clones
- make db-backup / make db-install Makefile targets
- worktree-update skill runs make db-backup after merges on main
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude Code's CWD is always the worktree root, so all script
invocations work with plain relative paths (db/connectors/ticket,
db/connectors/qdrant-search, etc.). The REPO_ROOT environment
variable and its settings.local.json definitions are no longer needed.
Updated: CLAUDE.md, all skill files, qatux agent file.
The settings.local.json env sections were also removed across all
9 worktrees (non-git files, edited directly).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The SQLite database now lives at ../settledreach.db, shared across all
git worktrees. This eliminates binary merge conflicts that occurred
whenever two branches modified the database independently.
All Python connectors (ticket CLI, sqlite_connector, decisions_sync)
now resolve the DB path relative to their own location — three levels
up from db/connectors/ reaches the worktree parent. The _main_worktree()
git-rev-parse pattern and config.json sqlite_db key are removed.
The database file is untracked from git; a backup mechanism commits
snapshots through the main branch (see following commits).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document the librarian + parallel writers + reviewer pattern for
producing many files efficiently with agent teams.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add workshop brief for Control & Interaction Scheme (next workshop).
Update index with wiki-review (complete) and v0.1-content-scoping
(complete, 38 tickets).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Long-term content strategy workshop: 300-world generator model,
cultural ingredients menu, three-system NPC architecture (9 patterns
x 6 motivations), Sacred/Profane/Middle Kingdom framework. 9 agents
across 4 rounds plus lead interview establishing the production path
from hand-authored Sova to generated 300 worlds.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Non-destructive branch sync utility. On main: shows worktree branches
ahead of main with PR flags, lets user pick which to merge. On other
branches: merges main in. Stops on conflicts, never force-pushes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Each worktree now has REPO_ROOT pre-set in .claude/settings.local.json,
removing the need for git rev-parse --show-toplevel at runtime. Updated
CLAUDE.md, skills (start-sprint, plan-sprint, ticket, search-docs),
briefing template, and qatux agent to use the env var prefix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sprint 3: Know — 11 tickets across server, client, joint, copy.
Sprint 2 remains active until #368 completes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
NPC data model, pathfinding, observation events, and interaction
foundation. Briefings for server, client, joint, and copy teams.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sprint planning is SI's job. Skill now spawns SI via Task tool
instead of running the workflow directly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Defines default agents per team so sprint briefings name the
right agents to spawn. Registers Inigo for the audio team.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Standby agent for audio implementation phase. Named after the
Dreamer from the Void Trilogy. Covers soundscape design, ambient
layers, diegetic cues, and D-018 audio propagation rules.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Filter remembered entities by z-level (Hoshe + Tyre warning)
- Skip remembered ghosts on currently visible tiles (Hoshe warning)
- Bump ObserverSnapshot version to 3 (Tyre suggestion)
- Add edge case tests: visible tile collision, different z-level,
knowledge without position (Hoshe suggestion)
- Regenerate msgpack fixtures for v3
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three E2E proof tests verify all acceptance criteria through the real
server pipeline: player movement, v2 snapshot with visible_tiles,
wall hiding (NPC behind wall invisible), corner reveal (move around
wall to see NPC). Dynamic test snapshot tracks player position from
queued inputs with simple LOS and Manhattan-distance visibility for
standalone demo mode. 88 client + 112 server tests passing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wall at (16,14) and NPC at (16,13) for Sprint 2 fog-of-perception
proof. Player starts at (16,16) — NPC hidden behind wall until
player moves around it.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
start-sprint and plan-sprint only recognized server/client as valid team
branches. Updated to include all six teams (server, client, copy, audio,
visual, ci) matching the SI agent's ticket assignment rules.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sprint briefing for #368 (knowledge vocabulary for v0.1 content).
Defines FactId categories, known_attributes keys, and
RelationshipState transition patterns the copy team needs to deliver.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
VisibleEntity now carries relationship state (D-033 entity color) and
observation type (Visible vs Remembered). compute_observer_snapshot
queries the player's KnowledgeGraph to overlay relationship data on
visible entities and include remembered (not-in-LOS) entities as fog
ghosts at their last known position. Regenerated msgpack fixtures.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Teams are server, client, copy, audio, visual, ci. Never use
"joint" — split cross-team work into per-team tickets with
explicit dependencies.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Register KnowledgePlugin in main.rs and game_loop test (Tyre critical)
- Add KnowledgeGraph component to player spawn (Tyre critical)
- Reset Stale -> Active on fresh direct observation (Hoshe warning)
- Make registry/queue non-optional in emit_observation_events (Tyre/Hoshe)
- Add tracing::warn for missing EntityRegistry entries (Hoshe warning)
- Replace HashSet with Vec for small entity ID lookups (Hoshe suggestion)
- Add const static assertion for KnowledgeConfidence ordering (Hoshe)
- Add is_empty() and known_facts_iter() to KnowledgeGraph (Tyre)
- Add decay_skips_non_minute_ticks and observe_resets_stale tests (Hoshe)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace hardcoded entity colors with D-033 relationship palette:
Player=#e0e8ff, Npc=unknown teal #4a9ebb, Object=grey #8b8ba0.
Phase 1 defaults by entity kind; Phase 2 (#361) will derive color
from RelationshipState via knowledge graph.
Entities in peripheral vision dimmed to 50% alpha (D-015).
Player entity gets a Polygon2D triangle indicator showing facing
direction, rotated from GameState.player_facing.
82 tests total, 0 failures.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server shipped ObserverSnapshot v2 with game_time, player_facing,
visible_tiles (with visibility sectors), and per-entity visibility.
Protocol decoder was silently ignoring these fields. Now extracts
all v2 data with null defaults for backward compatibility.
GameState gains game_time, player_facing, visibility_sectors vars.
Derives visible_positions from visible_tiles when present (for real
server mode). Test snapshot updated with v2 fields.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Perception system emits DirectObservation/LeftLOS knowledge events
based on snapshot visibility. Entities entering LOS get Direct
confidence; leaving LOS downgrades to KnowsDetails. System params
are optional for backward compatibility when KnowledgePlugin is not
registered. 28 knowledge graph unit tests included.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement per-entity KnowledgeGraph component with BTreeMap storage
for deterministic iteration (D-010). StableEntityId + EntityRegistry
for entity identity across save/load. KnowledgeEventQueue + processing
system for decoupled knowledge updates. Decay system runs once per
game-minute. All types conform to D-041 canonical structs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Agents were writing raw SQL with incorrect column names (e.g. `sprint`
instead of `sprint_id`). Leading with the ticket CLI as the preferred
approach avoids this class of errors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Count-based dirty tracking missed content changes when tile/visibility
count stayed the same (e.g., door opening, player moving through
corridor). Now re-renders all layers when GameState.current_tick
advances, which correctly handles every snapshot change.
Adds 3 tests for tick advancement and same-count-different-content
scenarios. 68 total tests, 0 failures.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace unfiltered generate_snapshot with compute_observer_snapshot
that combines shadowcasting + vision cone to send only visible
entities and tiles. Enforces information asymmetry (D-011): NPCs
behind walls or in the blind spot are excluded from the snapshot.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement direction-dependent visibility modulation per D-015.
Forward cone (~120 deg) at full range, peripheral (~180 deg each side)
at reduced range, blind spot (~60 deg behind) excluded. Facing component
updated on player movement via facing_from_delta.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Albert Ford's symmetric shadowcasting algorithm using rational
fraction slopes. Benchmarked 1.2-10.5x faster than recursive with
guaranteed symmetry (if A sees B, B sees A). Resolves Q-018 as D-035.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Expand wire protocol with version field, GameTime (day/phase/paused),
FacingDirection (8-directional), VisibleTile, VisibilitySector
(Forward/Peripheral), and visibility tag on VisibleEntity.
Regenerate all msgpack fixtures for client compatibility.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sprint 2 rendering pipeline: tiles (#129), fog (#131), camera (#116).
- tile_renderer.gd: programmatic TileSet with floor/wall/door/object
placeholder tiles, renders from snapshot tile data
- fog_renderer.gd: TileMapLayer overlay with three visibility states
(visible/fog-edge/hidden), computed from visible_positions data
- Camera2D: smoothing enabled (speed 6.0), 2x zoom, locked to player
- game_state.gd: stores visible_tiles and visible_positions from snapshots
- sim_bridge.gd: test data with 8x8 room, corridor, and Manhattan
distance visibility for development without server
- Scene render order: Tiles -> FogOverlay -> Entities
- Background clear color set to near-black for unexplored areas
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
entity_renderer.gd used wrong field names ("id" instead of
"entity_id", "type" instead of "kind.variant", "position" instead
of x/y). Now matches Protocol.decode_entity() output exactly.
Also centers entities (24x24) within 32px tiles.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace immediate ticket status change with a mandatory plan mode
step. Agent must now enter plan mode, create a concrete sprint plan
covering implementation approach and ticket ordering, and get user
approval before marking any ticket as in_progress.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a comma-separated team field to tickets so work can be
attributed to server, client, or joint teams. Includes --team
filter on list, --team on create, and a new team subcommand.
Schema, CLI, and skill docs all updated.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Settings.json is the shared team config (distinct from settings.local.json
which remains per-user). Remove it from .gitignore so it's tracked.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Joint tasks with ticket IDs (#356-#360), dependency chains,
and sprint completion proof criteria for client team reference.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server team added #356-#360 for pre-sprint design tasks and
integration milestones. Updated server.md and joint.md with
actual ticket numbers, dependency chains, and done status.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server team added #356-#360: fog bridge, sprint proof, snapshot
v2 schema, Q-018/Q-019 resolution tasks. Updated joint.md with
actual ticket numbers and #81 done status.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The skill used bare relative paths like db/connectors/ticket which
fail when the shell CWD doesn't match the worktree root. Now requires
resolving REPO_ROOT via git rev-parse --show-toplevel first.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sprint 1 "Run" completed — 8/8 tickets done. Player-controlled
character moving on screen through working IPC bridge achieved.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
E2E connection test (#81) merged via PR #7. Tile collision
system (#236) already on main. Sprint 1 now 7/8 complete.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tyre #1: Added Rust-generated input_batch_two.msgpack fixture for
bidirectional D-030 Layer 1 symmetry (Vec<PlayerInput>).
Tyre #2: Added all_fixtures_deserialize Rust test that reads every
.msgpack fixture and verifies it deserializes (corruption guard).
Hoshe #3: Added test_decode_snapshot_malformed_entities_counted test
verifying the decode_errors counter on D-010 boundary violations.
45 client tests, 54 server tests pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Hoshe #1: E2E test now uses random ephemeral port (49152-65535) with
port rotation on bind failure, avoiding conflicts in parallel CI.
Hoshe #2: Documented intentional input drop on encode failure in
SimBridge — re-queuing would retry bad data and server tick has
already advanced.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace init_skill.py and package_skill.py references with manual
mkdir and validation checklist — the scripts were never created.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Automates the sprint planning workflow: gather carry-overs, scan
backlog, propose tickets, write per-team briefing files. Includes
briefing template reference matching the established format.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sprint 2 goal: fog of perception working through the bridge. Server
computes LOS visibility, client renders fog. Carries over #236 and #81
from Sprint 1.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ticket show now accepts multiple IDs (e.g. ticket show 110 111 112).
--brief flag outputs compact human-readable summaries instead of JSON,
useful for sprint planning scans. Single-ID JSON output unchanged.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
D-030 Layer 3: E2E test spawns the Rust server binary, connects via
LocalBridge, sends a batched MoveNorth input, and verifies the player
moved to (16.5, 15.5). Also adds batch encoding roundtrip tests,
framed batch test, and Player entity fixture decode test. 43/43 pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server team added EntityKind::Player variant. Added snapshot_player
fixture and updated snapshot_multi_entity to include all 4 entity kinds
(Player, Npc, Object, Terrain) for complete D-030 Layer 1 coverage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server expects a MessagePack array of PlayerInput objects in one framed
message per tick, not individual inputs per frame. Added
Protocol.encode_player_inputs() for batch encoding. Changed SimBridge to
buffer raw input dicts and batch-encode in _process(). Also fixed server
port default (9876) and positional arg format to match server CLI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Workshop briefs for the larger spikes identified by the architecture
review audit: knowledge graph & information boundaries, observer
snapshot pipeline, NPC AI state machines, save/load architecture,
and map authoring pipeline. Each includes participants, key questions,
input documents, and expected outputs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Six new open questions identified by the Tyre/Troblum architecture
review: shadowcasting algorithm selection, entity ID stability,
multi-entity collision resolution, tick budget overflow policy,
pathfinding cache eviction, and debug visualization scope.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Two-round adversarial review by Tyre + Troblum covering full
architecture decisions and implementation. Status: GREEN architecture,
AMBER implementation plan.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace expect() with unwrap_or_else that logs the bind address
and error via tracing before exiting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Snapshot for tick N should show state at END of tick N. Reorder systems
so generate_snapshot runs after validate_movement but before
advance_tick. Previously snapshot.tick was the incremented tick,
not the tick whose inputs were processed. Also fix main.rs accept
error to log address context before exiting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace string-matching disconnect detection with explicit
BridgeError::Disconnected variant. Add TcpBridge::accept_on(listener)
that takes a pre-bound TcpListener, eliminating the 100ms sleep hack
in TCP tests. Send errors now also trigger ServerRunning=false.
Add trace logging to generate_snapshot for entity count visibility.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Critical fixes from Hoshe review:
1. Race condition: defer TCP connect to _process() with retry logic
(MAX_CONNECT_RETRIES=20, 100ms interval) so server has time to bind.
2. Buffer corruption: disconnect on oversized message instead of
clearing valid buffered data (_corrupt flag, fail-safe).
3. Silent input drop: send_input() returns Error so callers can detect
encode/validation failures.
Warnings addressed:
- ServerProcess validates server_path exists before spawning
- SIGKILL and health check TODOs documented for future work
- Diagonal keybindings documented as intentional deferral
- send_message uses single put_data() call (no partial write risk)
- Static frame helpers documented as D-030 Layer 2 test-only
New tests (36 total, up from 33):
- Partial read scenario (chunked TCP delivery)
- Multi-message sequential decode (exercises buffer corruption fix)
- send_input error return on invalid action
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements the full server-side tick pipeline:
- process_player_input drains InputQueue, converts PlayerActions to
MoveIntent components or pause/unpause toggles
- generate_snapshot builds ObserverSnapshot from ECS state with
render coordinate conversion
- receive_bridge_inputs/send_bridge_snapshot handle bridge I/O with
graceful disconnect detection via ServerRunning resource
- main.rs now accepts TCP connections and runs a proper game loop
- PlayerCharacter marker, Player EntityKind, SnapshotBuffer resource
Closes server side of #81, #82, #83.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Godot has no Unix socket API, so TCP localhost is required for
client-server IPC. TcpBridge implements SimBridge with the same
framing protocol as LocalBridge. Includes accept/connect methods
and three integration tests over TCP.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Client-side Protocol.gd expects rmp_serde::to_vec_named() (maps with
string keys), but LocalBridge was using to_vec() (compact positional
arrays). Fix send_snapshot and update all test serialization calls to
match actual wire format. Also change EOF from Ok(vec![]) to
BridgeError::Transport so bridge systems can detect disconnects.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
12 new tests covering framing roundtrips, cross-layer Protocol+framing
integration, and diagonal wire mapping. 4 new diagonal movement
fixtures generated from Rust for D-030 Layer 1 cross-language
verification. 33/33 tests pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wire SimBridge to use LocalBridge for TCP transport in non-test mode:
_process() polls for incoming snapshots and flushes outbound inputs.
Add 4 diagonal movement variants (NE, SE, SW, NW) to InputMapper and
wire mapping, ordered clockwise. Register diagonal input actions in
project.godot.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
LocalBridge wraps StreamPeerTCP with 4-byte big-endian length-prefix
framing matching server/src/bridge/framing.rs. ServerProcess manages
the Rust server as a subprocess via OS.create_process(). Together
they form the D-020 IPC transport layer for ticket #79.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Workshop produced 42 new tickets (#297-#338) + 6 updated, 9 new
decisions (D-032 through D-040), and 53 dependency links. All 18
agent briefings updated to reflect 40 confirmed decisions.
Key outcomes: Sera Venn as detective's FRIEND, Kael Davan as
smuggler's FRIEND, all 6 wow moments in scope, converged 6+3 tag
taxonomy, wiki taxonomy with 14 categories, 8 audio files via
Stable Audio Open, 4 parallel unblocked work tracks identified.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Workshop outputs unblock content authoring. Updated status,
key decisions, and immediate work items.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
D-040: hierarchical wiki structure with YAML frontmatter.
6 new open questions from content gap analysis workshop
covering generation expansion, line previewer, audio timing,
FRIEND content authoring, knowledge hierarchy, and triangle
pressure thresholds.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
D-032: separate monologue pools per character
D-033: entity color = relationship to player
D-034: THE FRIEND production-level NPC pattern
D-035: converged tag taxonomy for line pools
D-036: Sova Transit District / Krenn System setting
D-037: contraband specification (unlicensed lattice components)
D-038: audio in v0.1 scope (8 files via Stable Audio Open)
D-039: v0.1 wow moment scope (all 6 moments)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
6 agents × 2 rounds examining 9 content layers. Produced D-032
through D-039, THE FRIEND NPC pattern, converged tag taxonomy,
and Sova Transit District setting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
validate_movement now checks both terrain walkability AND tile
occupancy. Builds a spatial index of occupied tiles from stationary
entities, then resolves movers in order — first valid claim wins.
Same spatial pattern needed for D-026 simulation tiers (30-80 active
NPCs) and future pathfinding occupied-tile awareness.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add diagonal PlayerAction variants (MoveNortheast, MoveNorthwest,
MoveSoutheast, MoveSouthwest) and TilePosition::all_neighbors()
returning all 8 surrounding tiles. Genre-expected for immersive sim.
Establishes the movement pattern before pathfinding is built on top.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- decode_snapshot() reports dropped entities via push_error and returns
decode_errors count so callers can detect partial data (D-010
information boundary compliance)
- receive_bytes() warns when overwriting unconsumed snapshot, documents
latest-wins semantics
- Rename misleading test to test_encode_produces_nonempty_bytes
- Fix tick rate comment: 10 ticks/game-minute per D-031
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Hoshe critical fixes:
- _action_enum_to_wire uses InputMapper.Action constants instead of
fragile integer literals; OPEN_MENU explicitly handled as client-only
- Remove int() coercion on tick/entity_id — use direct assignment since
GDScript int is signed 64-bit (safe for realistic tick values)
- Check encode result before buffering in send_input() — reject empty
bytes instead of corrupting the outbound stream
- Test snapshot now uses Protocol format {tick, entities} instead of
legacy schema; GameState updated to derive player position from
entity data; main.gd and world_renderer.gd updated accordingly
Hoshe warnings:
- 5 negative tests added (truncated bytes, wrong type, missing fields,
empty bytes, encode validation) — 20/20 tests pass
- receive_bytes signal is emitted at consume time in poll_snapshot by
design (documented in code)
Tyre suggestions:
- Remove duplicated root-level fixtures — single source of truth in
client/tests/fixtures/msgpack/
- gen_fixtures.rs writes directly to client/ directory
- Add `make fixtures` target for regeneration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace .lock().unwrap() with .expect("mutex poisoned") in LocalBridge
for clearer panic messages. Document 16MB MAX_MESSAGE_SIZE rationale
in framing.rs with entity count sizing analysis.
Addresses Hoshe PR review suggestions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All three sprint briefings now include tea CLI PR creation example
with required --login and --repo flags to avoid TTY prompts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Nine-layer analysis from global (art direction) to specific (audio).
Identifies gaps in content tickets for Mellanie, Paula, and Araminta.
Structured as 2-round workshop with 6 participants to produce missing
tickets, dependency chain, and content team work plan.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SimBridge now encodes player inputs via Protocol.encode_player_input()
and exposes receive_bytes()/drain_outbound() for the transport layer.
Test mode still works unchanged. Transport (ticket #79) will call
these methods to complete the IPC pipeline.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Protocol.gd decodes ObserverSnapshot and PlayerInput from Rust's
rmp_serde wire format, and encodes PlayerInput for sending to server.
Handles rmp_serde enum encoding: unit variants as bare strings,
data variants as single-element maps.
8 fixture-based tests verify decode of Rust-generated fixtures,
GDScript encode/decode roundtrips, and cross-language compatibility.
All 15 tests pass (3 suites).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Install Godot4MessagePack (pure GDScript) for MessagePack encode/decode.
Add Rust fixture generator (gen_fixtures.rs) that produces canonical
.msgpack files using rmp_serde::to_vec_named for cross-language testing.
Fixtures cover: snapshots (empty, one NPC, multi-entity with all
EntityKind variants) and player inputs (unit + data enum variants).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
TilePosition component with discrete grid coordinates, flat-storage
WalkabilityMap resource with O(1) can_move_to() lookup, MoveIntent
component and validate_movement system. Movement validated against
walkability map each tick, blocking all NPC and player movement
through unwalkable tiles. 11 unit tests + 1 integration test.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Length-prefixed MessagePack framing (4-byte BE length + payload),
LocalBridge struct implementing SimBridge trait over Unix domain
sockets, BridgeResource wrapper for ECS integration. Adds Io
error variant to BridgeError. Two integration tests verify
snapshot and input round-trips over real sockets.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Same fix as the ticket CLI — uses git rev-parse --git-common-dir to
resolve DB path to the main worktree. Prevents WAL/journal pollution
when sqlite-query or sqlite-exec are called from feature branches.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Uses git rev-parse --git-common-dir to find the main worktree root,
then resolves the DB path there. Prevents WAL/journal pollution on
feature branch worktrees that caused merge conflicts on commonwealth.db.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Syncs team branch with main, finds the active sprint, reads the sprint
briefing, loads ticket details and key decisions, then presents an
actionable work plan with suggested first task.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sprint briefings (docs/sprints/sprint-N/{team}.md) are now the primary
starting point for implementation work. Per-agent briefings remain as
background context.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Per-team sprint briefings under docs/sprints/sprint-1/ for server,
client, and joint tracks. Each lists assigned tickets, dependencies,
key decisions to read, and implementation notes. Agents use
ticket show <id> for full details.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reference db/connectors/ticket CLI in project structure and agent
instructions. Rewrite ticket skill to use CLI commands instead of
raw SQL wrapper scripts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ergonomic Python CLI wrapping parameterized SQLite queries for ticket
management. Supports list, show, create, assign, sprint, deps, search,
epics, children, count commands with JSON output. Replaces raw SQL
access for Si and other agents.
Also includes Sprint 1 "Run" creation and story assignments:
- #77, #79 → client
- #78, #236 → server
- #81, #82, #83 → joint
- 36 tickets updated to done (boilerplate work completed by merged PRs)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
main, maintenance, server, client are protected on Gitea.
Agents must not delete or force-push to these branches.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Merge origin/client into main. Resolve binary conflict in
commonwealth.db by keeping main's version (latest ticket state).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Camera2D now tracks player_position from GameState (D-015)
- Add SubViewport child to minimap SubViewportContainer (fixes editor warning)
- Wire MonologueDisplay into main loop for D-016 perception data path
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document that tea pr merge fails (405) on conflicting branches,
requiring local merge + tea pr close. Also note heredoc hanging
issue with tea comment — use temp file instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Merge origin/server into main. Resolve CHANGELOG.md conflict by keeping
both sets of entries (main's review-pr skill + server's boilerplate entries).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix input_mapper double-check bug (redundant InputEventKey + pressed filter)
- Add bounds checking for position arrays in entity_renderer and game_state
- Make test snapshot deterministic (incrementing counter, not wall clock)
- Fix tween overlap in monologue_display (cancel active tween before new one)
- Extract TILE_SIZE constant from magic number 32
- Add 5 D-030 Layer 1 fixture tests for snapshot parsing (7/7 total passing)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add roundtrip tests for all PlayerAction variants (Hoshe #6)
- Add roundtrip tests for all EntityKind variants (Hoshe #6)
- Add day wraparound at midnight edge case test (Hoshe #7)
- Add day() calculation test (Hoshe #7)
- Add out-of-order input rejection test (Hoshe #7)
- Total: 15 → 20 tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Documents non-interactive tea usage with all required flags to
prevent TTY crashes in Claude Code. Agents were accessing the
Gitea API directly — this standardizes on tea CLI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace raw curl API calls with tea comment command using proper
flags for non-interactive PR comment posting on Gitea.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Spawns Hoshe (code quality) and Tyre (architecture) in parallel to
review branch diffs against main. Includes Gitea tea CLI integration,
vendor/generated file exclusion patterns, and practical tips learned
from first review run on server and client boilerplate PRs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document Gitea tea CLI usage for pull requests with all required
flags for non-interactive execution. Adds Gitea to local services.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tickets 276 (epic) and 278-286 (stories/tasks) updated to done
status after make ci-server passed green.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds tooling/install-rust script that installs Rust via rustup if
not present, with clippy and rustfmt components. Idempotent — skips
when already installed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Set up the complete Godot 4.6 client foundation as a pure renderer (D-020):
- project.godot with 2D rendering, autoloads, input actions
- Main scene: Game > World (TileMapLayer, Entities, FogOverlay) + Camera2D + UILayer
- Autoloads: SimBridge (connection state machine + test mode), GameState, InputMapper
- Rendering stubs: WorldRenderer, EntityRenderer, FogRenderer
- UI stubs: HUD (health/perception/time), Minimap, MonologueDisplay
- Input mapping: WASD/arrows, E (interact), Tab (perception), Esc (menu), Space (pause)
- gdUnit4 smoke tests: scene loads, autoloads registered (2/2 passing)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds tooling/install-godot script that downloads the Godot binary
from GitHub releases to ~/bin/godot4. Skips download when the
correct version is already installed. Supports Linux x86_64/arm64
and macOS. GODOT_VERSION defaults to 4.6 and is overridable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The SQLite database contains integral project content (273 tickets,
dependencies, sprint planning). Remove from .gitignore and check in.
WAL/SHM journal files remain ignored as transient.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update Key Documents sections to reference decisions/ directory instead
of monolithic DECISIONS.md. Add Development Workflow sections to
implementation agents (Dudley, Hoshe, Justine, Oscar, Si, Stig, Tyre)
with relevant Makefile targets and directory conventions. Streamline
decision references to point to specific domain files.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Agent personality files and skill definitions updated to reference decisions/
domain files instead of monolithic DECISIONS.md.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds DevOps procedures document and updates CLAUDE.md/README.md to reference
decisions/ domain files and Makefile-based workflow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three-agent analysis (Si, Qatux, Tyre) evaluating approaches to scale
DECISIONS.md. All independently recommended hybrid domain-split markdown
+ SQLite index. Tyre sharpened scope: 7 domains not 11, 2 tables not 3,
pre-commit hook for sync drift prevention (Phase 2).
Also adds D-031 to Round 18 in discussions index.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add decisions_sync.py that parses decisions/*.md markdown headings,
extracts metadata (type, domain, status, round, date), and upserts
into SQLite. Two-pass approach: decisions first, then cross-references
to avoid FK violations on forward references.
Schema adds decisions table (52 rows) and decision_refs table (29 rows)
with cascading deletes. Makefile gains decisions-sync, decisions-coverage,
decisions-active, and decisions-orphan targets. Sync runs as part of
make setup.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace monolithic 474-line DECISIONS.md with 7 domain files under
decisions/: architecture, perception, content, scope, process,
questions, rejected. Each file owns its decisions with cross-reference
hyperlinks. Root DECISIONS.md becomes a redirect with domain index.
Reduces per-agent context load by ~70-80% (80-150 lines vs 474).
Taxonomy: architecture (D-008..D-031), perception (D-011..D-019),
content (D-023..D-029), scope (D-001..D-027), process (D-004..D-022),
questions (Q-001..Q-011), rejected (R-001..R-010).
Restores D-002 original text (was a tombstone referencing D-005).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Create client/, server/, tooling/, tests/, .config/ (tracked) and
.cache/ (gitignored). Update CLAUDE.md project structure to reflect
the new layout including workshops directory.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
10 ticks = 1 game-minute, 4 day phases (Morning/Afternoon/Evening/Night),
diegetic time display on insert HUD. Unblocks daily routine pipeline (#88)
and all time-dependent systems. Workshop consensus from Tyre and Gestalt.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
7 agents across 2 rounds stress-tested the 232-ticket v0.1 plan against
concept proof, fun delivery, completeness, and testability. Key outcomes:
D-030 testability architecture confirmed, 15 priority promotions, 41 new
tickets (273 total), replay ceiling estimated at 10-12 playthroughs.
Reorganized workshops into per-workshop directories.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Complete the set of whitelistable wrapper scripts so all SQLite
access goes through db/connectors/sqlite-* (query, exec, init, seed).
Update the ticket skill to reference wrappers instead of calling
sqlite_connector.py directly, making permissions allowlisting clean.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add D-023 through D-029 context (content architecture, NPC generation,
social sites, simulation tiers, vertical slice, dialogue, population
ratios) to all 18 agent briefings. Core workshop participants get
detailed action items; specialist/infrastructure agents get relevant
implications. Mellanie activated from standby for content authoring.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Full team workshop (8 agents, 3 rounds) producing 7 decisions:
D-023 three-tier content model, D-024 NPC 10-axis generation,
D-025 social site atomic unit, D-026 timestamp-based sim tiers,
D-027 smuggler+detective vertical slice (supersedes D-006),
D-028 tagged line pool dialogue, D-029 population 30/50/20 split.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pre-workshop planning document for Round 17. Proposes three-tier
content model, life-sim substrate, NPC generation axes, simulation
tiers, DLC architecture, and 20 open questions for team discussion.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instructs Qatux to always use project-relative paths in documents,
since the project is worked on across multiple systems.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove misplaced ROUND-16-STATUS.md from root (duplicate of
round-16-session-notes.md). Convert all macOS absolute paths to
project-relative paths across round-16 docs and design reference.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Round 15: README.md Steam page placeholder (Miri + Mellanie)
- Created README.md with game description for Steam page
- Placeholder structure with lorem ipsum for undetermined content
Round 16: Faction development (Miri, Paula, Gestalt)
- Full development of six factions with lore, politics, mechanics
- 3D reputation system (Trust × Usefulness × Exposure)
- Mechanical grounding with "First 30 Minutes" test
- v0.1 recommendation: Commission + Severance
- Session flagged for team input
Process changes (D-022):
- Retired DISCUSSION.md, work directly in round files
- Qatux mandatory in all team interactions
- Updated CLAUDE.md and agent personas
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-10 22:29:34 +01:00
2005 changed files with 260433 additions and 920 deletions
This project uses Claude Code agent teams to simulate a game development team. Each agent has a distinct personality, expertise area, and role. The team leader (Jeroen) directs the team through chat.
**The Settled Reach** uses Claude Code agent teams to simulate a game development team. Each agent has a distinct personality, expertise area, and role. The team leader (Jeroen) directs the team through chat.
All agents read their briefing file at `docs/briefings/{name}.md` before starting work. Briefings contain current project state, relevant decisions, and priorities — keeping agent profiles stable while context evolves.
@@ -114,7 +114,7 @@ Synthesize findings.
### Qatux (Documenter & Librarian)
- Core team member — participates in discussion rounds as documenter
- Manages document search via `/search-docs` skill
- Manages document search via `/docs-search` skill
- Maintains DECISIONS.md, DISCUSSION.md, briefings, and Qdrant search index
- Answers "did we discuss this?" with citations
@@ -132,7 +132,7 @@ To add a new agent:
## Project documents
All agents read their briefing at `docs/briefings/{name}.md` for current context. Key project documents:
-`DECISIONS.md` - Confirmed decisions (D-001 through D-019+)
-`decisions/` - Domain-split decisionfiles (see decisions/README.md for index)
-`DISCUSSION.md` - Active discussion round (archives in `docs/discussions/`)
Read your briefing at `docs/briefings/araminta.md` before starting work - it lists all visual design decisions and surfaces. Read DECISIONS.md for the full specifications.
Read your briefing at `docs/briefings/araminta.md` before starting work - it lists all visual design decisions and surfaces. Read the relevant decisions/ domain files for the full specifications.
@@ -39,4 +39,4 @@ Originally a Stellaris mechanics fan, you pivoted to general systems design when
## Project context
Read your briefing at `docs/briefings/gestalt.md` before starting work. Read DECISIONS.md for confirmed decisions and DISCUSSION.md for active discussions.
Read your briefing at `docs/briefings/gestalt.md` before starting work. Read the relevant decisions/ domain files listed in your briefing for confirmed decisions and DISCUSSION.md for active discussions.
@@ -35,4 +35,4 @@ Named after Gore Burnelli - the dynasty patriarch who sees further than anyone,
## Project context
Read your briefing at `docs/briefings/gore.md` before starting work. Read DECISIONS.md and DISCUSSION.md for full context.
Read your briefing at `docs/briefings/gore.md` before starting work. Read the relevant decisions/ domain files listed in your briefing and DISCUSSION.md for full context.
@@ -69,4 +69,4 @@ For each feature, create a test plan covering:
## Project context
Read your briefing at `docs/briefings/hoshe.md` before starting work - it lists all systems to test with their decision references. Read DECISIONS.md for specifications that define expected behavior. Tests should always reference specific decisions.
Read your briefing at `docs/briefings/hoshe.md` before starting work - it lists all systems to test with their decision references. Read the decisions/ specifications that define expected behavior. Tests should always reference specific decisions.
description:Sound Designer for the Commonwealth game project. STANDBY - activate when audio implementation begins. Responsible for soundscape design, ambient audio layers, diegetic sound cues, audio propagation rules, and all player-facing audio. Use when designing sound palettes, defining audio triggers, creating spatial audio specs, or reviewing audio consistency.
tools:Read, Glob, Grep, Edit, Write, Bash
model:sonnet
memory:project
---
You are INIGO, the Sound Designer on a game development team building a top-down immersive sim set in an original science fiction universe.
## Your personality
You think in layers. Every space has a base tone, a rhythm, and the things that break the rhythm. You hear what's missing as much as what's present. You say things like "What does silence sound like here?" and "That sound tells the player something before they see it" and "Ambience is information." You understand that in an immersive sim, sound is the player's second sight — what they hear around corners, through walls, behind closed doors. Sound is gameplay.
Named after Inigo from the Void Trilogy — the Dreamer who shared immersive multi-sensory experiences with billions. He understood that atmosphere isn't decoration, it's the thing that makes a world feel inhabited.
## Your role on the team
- Design the soundscape layers for each location (Logistics Hub, Bar, Ring spaces)
Read your briefing at `docs/briefings/miri.md` before starting work. Read DECISIONS.md and DISCUSSION.md for full context on confirmed decisions and ongoing discussions.
Read your briefing at `docs/briefings/miri.md` before starting work. Read the relevant decisions/ domain files listed in your briefing and DISCUSSION.md for full context on confirmed decisions and ongoing discussions.
@@ -37,4 +37,4 @@ Named after Nigel Sheldon - the inventor, the builder, the man who looks at a pr
## Project context
Read your briefing at `docs/briefings/nigel.md` before starting work. Read DECISIONS.md and DISCUSSION.md for full context.
Read your briefing at `docs/briefings/nigel.md` before starting work. Read the relevant decisions/ domain files listed in your briefing and DISCUSSION.md for full context.
@@ -35,4 +35,4 @@ You're named after Ozzie Isaacs - the wanderer, the dreamer, the one who walks t
## Project context
Read your briefing at `docs/briefings/ozzie.md` before starting work. Read DECISIONS.md and DISCUSSION.md for full context.
Read your briefing at `docs/briefings/ozzie.md` before starting work. Read the relevant decisions/ domain files listed in your briefing and DISCUSSION.md for full context.
@@ -38,4 +38,4 @@ Named after Paula Myo - the investigator who never gives up, who follows the thr
## Project context
Read your briefing at `docs/briefings/paula.md` before starting work. Read DECISIONS.md and DISCUSSION.md for full context.
Read your briefing at `docs/briefings/paula.md` before starting work. Read the relevant decisions/ domain files listed in your briefing and DISCUSSION.md for full context.
description:Documenter and Librarian for the Commonwealth game project. Use when discussion decisions need to be recorded, when documents need updating, when the team needs a summary of current state, when open questions need tracking, when searching project history, or when answering "did we already discuss this?". Maintains DECISIONS.md, DISCUSSION.md, briefings, and the Qdrant search index.
description:Documenter and Librarian for the Commonwealth game project. Use when discussion decisions need to be recorded, when documents need updating, when the team needs a summary of current state, when open questions need tracking, when searching project history, or when answering "did we already discuss this?". Maintains decisions/ domain files, DISCUSSION.md, briefings, and the Qdrant search index.
tools:Read, Glob, Grep, Edit, Write, Bash
model:sonnet
memory:project
@@ -17,8 +17,8 @@ Named after Qatux, the Raiel with perfect memory who helped Paula Myo by recalli
## Your role on the team
### Documentation
- Maintain DECISIONS.md with confirmed decisions (D-NNN format)
-Maintain DISCUSSION.md with active discussion round only
- Maintain decisions/ domain files with confirmed decisions (D-NNN format)
-Work directly in round documents at `docs/discussions/round-NN-topic.md` (DISCUSSION.md is retired for new content)
- Update TEAM.md when roles change
- Track open questions (Q-NNN format) and their status
- Track rejected alternatives (R-NNN format) with rationale
@@ -28,23 +28,32 @@ Named after Qatux, the Raiel with perfect memory who helped Paula Myo by recalli
- Provide "state of the project" summaries when asked
### Knowledge management
- Maintain the Qdrant document index via /search-docs skill
- Maintain the Qdrant document index via /docs-search skill
- Update briefing files when decisions change
- Answer retrieval questions: "did we discuss X?", "what did we decide about Y?"
- Catch staleness in briefings and flag for update
- Provide citations (round number, decision ID, file path) for everything
- Ensure the team never relitigates a settled question without knowing they're doing it
## Path conventions
- **Always use relative paths** from the project root in all documents (e.g. `docs/discussions/round-16-status.md`, not `/Users/.../commonwealth/docs/...`). The project is worked on across multiple systems, so absolute paths will break.
## Archive management
- **Archive completed rounds:** When DISCUSSION.md has more than 3 completed rounds, archive older ones to `docs/discussions/round-NN-topic-slug.md`. Keep only the last completed round + active round in the root file.
- **Update the discussion index:** After archiving, update `docs/discussions/README.md` with the new round entry (number, topic, decisions produced, file link).
- **Work in dedicated round files:** All new rounds happen in `docs/discussions/round-NN-topic.md` from the start. DISCUSSION.md is retired for new content.
- **Update the discussion index ONLY when closing:** After a round is formally closed, update `docs/discussions/README.md` with the round entry (number, topic, decisions produced, file link).
- **Update briefings:** After a round produces new decisions, update the relevant agent briefing files in `docs/briefings/`.
- **Re-index documents:** After archiving or updating documents, re-index them in Qdrant via `python3 db/connectors/qdrant_connector.py index-file <path>`.
- **Re-index documents:** After archiving or updating documents, re-index them in Qdrant via `db/connectors/qdrant-index <path>`.
## Team workflow (mandatory)
- **Qatux is always included:** You are a mandatory participant in all team interactions and discussion rounds.
- **Round lifecycle:** Rounds begin in `docs/discussions/round-NN-topic.md`, are worked on collaboratively, and only marked complete in the index after formal closure.
## Document formats
### DECISIONS.md
### decisions/ domain files
Each decision follows this format:
```
### D-NNN: Short title
@@ -55,6 +64,8 @@ Each decision follows this format:
- **Dissent:** Any disagreement (or "None")
```
Decisions are now split into domain files at `decisions/*.md`. See `decisions/README.md` for the index. DECISIONS.md is now a redirect file pointing to the domain structure.
### DISCUSSION.md
Each round follows this format:
```
@@ -69,4 +80,4 @@ Summary table, open questions, flags
## Project context
Read your briefing at `docs/briefings/qatux.md` before starting work. The primary documents you maintain are in the project root: DECISIONS.md, DISCUSSION.md, TEAM.md. Read them to understand current state before making any updates.
Read your briefing at `docs/briefings/qatux.md` before starting work. The primary documents you maintain are: decisions/ domain files (see decisions/README.md for index), DISCUSSION.md, TEAM.md. Read them to understand current state before making any updates.
@@ -29,6 +29,16 @@ Named after the Sentient Intelligences that manage all Commonwealth infrastructu
You are execution-focused. When a decision is made, you immediately think about what needs to happen, in what order, by whom, and what depends on what. You maintain the project's pulse - always knowing what's in progress, what's blocked, and what's next. You don't wait to be asked for status updates; you surface risks early.
## Ticket assignment rules
The development teams are: **server**, **client**, **copy**, **audio**, **visual**, **ci**.
When creating or splitting tickets:
- **Always assign a ticket to exactly one team.** Every ticket must have a team.
- **Never use "joint" as a team.** If work spans multiple teams, split it into separate tickets — one per team — with explicit dependencies between them.
- For example, a feature requiring server-side logic and client-side rendering becomes two tickets: one for server (implement the data/system), one for client (consume and render it), with the client ticket blocked by the server ticket.
- Sprint proof/acceptance tickets should be assigned to the team responsible for the final integration step, with blockers on the upstream tickets.
## Project context
Read your briefing at `docs/briefings/si.md` before starting work.
@@ -32,4 +32,4 @@ You are task-oriented. When spawned, you expect a specific question or evaluatio
## Project context
Read your briefing at `docs/briefings/troblum.md` before starting work. Read DECISIONS.md for architectural requirements - these are your evaluation criteria when assessing technology options.
Read your briefing at `docs/briefings/troblum.md` before starting work. Read decisions/architecture.md for architectural requirements - these are your evaluation criteria when assessing technology options.
@@ -29,4 +29,4 @@ You respect the team leader's 30 years of software/systems/cloud architecture ex
## Project context
Read your briefing at `docs/briefings/tyre.md` before starting work - it contains the full list of architectural principles and technical requirements derived from decisions. Read DECISIONS.md for confirmed decisions and DISCUSSION.md for active discussions. The team leader (Jeroen) has 30 years software dev / systems & cloud architect experience and Claude Code 20x access.
Read your briefing at `docs/briefings/tyre.md` before starting work - it contains the full list of architectural principles and technical requirements derived from decisions. Read the relevant decisions/ domain files listed in your briefing for confirmed decisions and DISCUSSION.md for active discussions. The team leader (Jeroen) has 30 years software dev / systems & cloud architect experience and Claude Code 20x access.
Files are chunked by markdown headings (# and ##). Each chunk is embedded via ollama and stored in Qdrant with metadata (source_file, heading, chunk_index).
### Index a single chunk
For precise indexing of specific content:
```bash
python3 db/connectors/qdrant_connector.py index "unique-id""Text content to index" --metadata source=manual heading="Custom heading"
```
### Health check
Verify connectivity to Qdrant and ollama:
```bash
python3 db/connectors/qdrant_connector.py health
```
### Collection info
Check how many documents are indexed:
```bash
python3 db/connectors/qdrant_connector.py count
```
### Create collection
Initialize the Qdrant collection (run once during setup):
`ticket sprint --active`) and raw SQL wrappers are documented in CLAUDE.md.
This skill covers the full command reference.
## Commands
### List tickets
Show tickets filtered by status, type, or assignee:
### List tickets (full flags)
```bash
python3 db/connectors/sqlite_connector.py query "SELECT id, type, title, status, priority, assigned_to FROM tickets WHERE status != 'cancelled' ORDER BY priority, id"
```
Filter examples:
```bash
# By status
python3 db/connectors/sqlite_connector.py query "SELECT id, type, title, status FROM tickets WHERE status='in_progress'"
# By type
python3 db/connectors/sqlite_connector.py query "SELECT id, title, status FROM tickets WHERE type='initiative'"
# By assignee
python3 db/connectors/sqlite_connector.py query "SELECT id, title, status FROM tickets WHERE assigned_to='tyre'"
# Current sprint
python3 db/connectors/sqlite_connector.py query "SELECT t.id, t.title, t.status, t.assigned_to FROM tickets t JOIN sprints s ON t.sprint_id=s.id WHERE s.status='active'"
```
### Show ticket detail
```bash
python3 db/connectors/sqlite_connector.py query "SELECT * FROM tickets WHERE id=<N>"
db/connectors/ticket list [--status S][--priority P][--epic N][--sprint N][--assigned A][--team T]
python3 db/connectors/sqlite_connector.py execute "UPDATE tickets SET status='in_progress', assigned_to='tyre', updated_at=datetime('now') WHERE id=<N>"
db/connectors/ticket assign <id> <agent>
db/connectors/ticket unassign <id>
```
### Ticket tree (parent-child hierarchy)
### Team assignment
```bash
python3 db/connectors/sqlite_connector.py query "SELECT t.id, t.type, t.title, t.status, p.title as parent_title FROM tickets t LEFT JOIN tickets p ON t.parent_id=p.id ORDER BY COALESCE(t.parent_id, t.id), t.id"
db/connectors/ticket team <id> <teams>
```
Teams are comma-separated, e.g. `server`, `client`, `server,client`.
python3 db/connectors/sqlite_connector.py execute "UPDATE sprints SET status='active' WHERE id=<N>"
# Assign ticket to sprint
python3 db/connectors/sqlite_connector.py execute "UPDATE tickets SET sprint_id=<sprint_id> WHERE id=<ticket_id>"
# Sprint status
python3 db/connectors/sqlite_connector.py query "SELECT s.name, s.goal, s.status, COUNT(t.id) as tickets, SUM(CASE WHEN t.status='done' THEN 1 ELSE 0 END) as done FROM sprints s LEFT JOIN tickets t ON t.sprint_id=s.id WHERE s.status='active' GROUP BY s.id"
python3 db/connectors/sqlite_connector.py query "SELECT t.id, t.title, t.status FROM ticket_deps d JOIN tickets t ON d.blocker_id=t.id WHERE d.blocked_id=<N>"
db/connectors/ticket deps <id>
```
### Seed from decisions
To re-seed the database with initiatives from DECISIONS.md:
| **Qatux** | Documenter | Captures all decisions, questions, dissent, consensus. Writes `workshop-notes.md` per round, produces final `workshop-outcomes.md`. | No — observes and records only |
| **SI** | Sprint prep | Suggest adding when outputs include tickets. Creates tickets from decisions, links to sprint backlog. | No — execution prep only |
Qatux and SI are **never dismissed early.** If the user reduces the team mid-workshop, keep qatux and si (if added). Documenting everything prevents loss of valuable information.
### 4. Create Tasks (Round 1)
One task per participant containing:
- Instruction to read the full brief at its path
- The specific questions assigned to that participant (extracted from all layers)
- The output format from the brief's round description
- **IMPORTANT — file output requirement:** Instruct each agent to write their full output to `docs/workshops/{name}/{agent}-round{N}.md` (e.g., `docs/workshops/test-architecture/gestalt-round1.md`). Agents must write to disk, not just send messages. This ensures Qatux and other agents can read all outputs directly without relying on message forwarding.
One task for Qatux: "Document Round N — read all agent output files at `docs/workshops/{name}/*-round{N}.md` and capture decisions, questions, and dissent."
Assign all tasks using TaskUpdate with `owner` = agent name.
### 5. Spawn Agents
Use the Task tool to spawn each agent as a teammate. Each call should:
- Set `team_name` to the workshop team name
- Set `name` to the agent name (e.g., "gestalt")
- Set `subagent_type` to the matching agent type (same as name — see reference table)
- Provide a prompt telling the agent to check TaskList for their assigned task
Spawn all agents in parallel (one Task call per agent in a single message). Agents will appear as teammates in the Claude Code UI and pick up their tasks from the shared task list.
For large workshops (>6 agents), spawn participants in batches to avoid overwhelming the system. Always-present agents (Qatux, SI) can run in background via `run_in_background: true`.
### 6. Monitor
- TaskList to check progress
- SendMessage to nudge idle agents or provide clarification
- Agents work autonomously — claim tasks, read the brief, produce responses
### 7. Between Rounds
When all Round N tasks are complete:
1. Verify all agents wrote output files to `docs/workshops/{name}/`. If any are missing, nudge the agent or extract from their message and write the file yourself.
2. Qatux reads all `*-round{N}.md` files and produces round summary in `round-{N}-notes.md`
3. Create Round N+1 tasks (integration pass, synthesis, etc.) — include the same file output requirement
4. Assign to agents with TaskUpdate
5. Agents continue working
### 8. Wrap Up
**Always ask the user before wrapping up.** There may be more to discuss or additional rounds needed. Only proceed to wrap-up when the user confirms.
Wrap-up sequence:
1. Qatux produces final `workshop-outcomes.md` from accumulated notes
2. If SI is present, SI creates tickets from decided items
3. Send shutdown_request to all agents (qatux and si last, after they finish their output tasks)
4. TeamDelete to clean up
## Agent Type Reference
Agent name maps directly to subagent_type:
| Name | Domain | Typical workshop role |
|------|--------|-----------------------|
| gestalt | Systems design | Mechanics, fun factor, system interactions |
- Entity renderer field name bug — `id` vs `entity_id` (#345)
- Dialogue max-width pixel value — 640px per D-076 (#447)
- Routine tests missing ActiveSim — 3 of 5 tests passed trivially without the required tier marker
-`_observer_pos` misleading unused prefix renamed to `observer_pos` (used for sound event filtering)
- Stale protocol version doc comment "Current: 9" corrected to 10
- FactionOnly non-numeric `faction_id` attribute now logs a tracing::warn instead of silently denying
- SOUND_EVENT_ASSETS walk-speed key mismatch — `sfx_footstep_metal` corrected to `sfx_footstep_metal_walk`
### Changed
- Removed orphaned `SimulationTier`/`LastInteraction`/`ScopeTag`/`ScopeKind` types from tier.rs (unused outside own tests)
- Sound pipeline documented as intentionally empty in v0.1 (no producers yet, full pipeline wired)
- Observer test setup now inserts SoundEventQueue resource for integration coverage
- Added FactionOnly positive test case and Medium-range occlusion TODO
- Sound indicator colors sourced from Constants instead of duplicated hex literals
- play_loop() null guard on stream.duplicate()
- Camera zoom fallback uses Constants.CAMERA_DEFAULT_ZOOM
## [v0.1.11] — 2026-02-19
### Added
- Sprint 12 "Build" briefings — 50 tickets across server, client, copy, visual, ci teams; production-layer foundations + all v0.1 copy authoring
-`.tmp/` gitignored repo directory for agent temp files — avoids Bash permission prompts during PR review comment posting
-`sed -n` blanket permission in shared settings
### Changed
- All skills renamed to domain-action convention (e.g. `commit`→`git-commit`, `review-pr`→`pr-review`, `gen-audio`→`audio-gen`, `render-sprite`→`sprite-gen`) — 12 renames total
-`pr-review` skill uses Write tool into `.tmp/` instead of Bash heredocs to `/tmp/`
## [v0.1.10] — 2026-02-19
### Added
-`project.yaml` — technical project descriptor with version, architecture, simulation, and content model as the canonical version source of truth
- Scratchpad: asset generation pipeline idea (registry, status tracking, prompt versioning, pre-sprint cohesion)
- Scratchpad: remote terminal proxy idea for mobile monitoring of Claude Code permission prompts and interactive elements
-`make perf-baseline` — full plugin stack tick benchmark (50 measured ticks, 5 warmup) capturing per-tick timing, entity counts, process RSS, and shadowcast benchmarks; outputs structured JSON to `tests/perf/baseline.json` with `--compare` mode for regression detection (>20% threshold, D-026 budget check)
- Michroma font integration (#517) — Michroma-Regular.ttf as game font with +1px tracking FontVariation, global Theme with cyan-white (#E0F7FA) implant text color, IMPLANT_TEXT_COLOR/DIM/PULSE constants
- Mouse-relative facing and movement (#526, D-054) — mouse position determines facing direction (client-side float), WASD remapped to cursor-relative (W=toward, S=away, A/D=strafe), SET_FACING action sends octant to server, smooth facing indicator rotation
- Auto-checklist progress tracking (#503) — ChecklistEvaluator parses room YAML and evaluates 7 condition types against GameState with latching, ChecklistOverlay renders progress in gauntlet mode only, 48 new tests
- 4 ambient zone loops: station base, workplace, bar, corridor — SAO-generated organic soundscape with crossfade loop points (#327)
- 2 footstep SFX: metal walk and run — SAO hybrid with best-transient extraction (#327)
-`audio-batch` command — batch audio generation from JSON manifests, supports SAO and harmonic synthesis, with `--dry-run`, `--only`, and `--skip-existing` flags
-`--post` and `--output-ogg` flags on `audio-generate` — chain post-processing (trim, normalize, convert) into a single command
### Changed
-`push-pr` skill now runs `/commit` first when uncommitted changes are detected
- Insert open/close now sends explicit PauseSimulation/ResumeSimulation (#518, D-058) — replaces toggle-style pause with idempotent pair
- Interaction list colors reference Constants.IMPLANT_TEXT_COLOR instead of hardcoded values
- World radial menu uses theme font instead of ThemeDB.fallback_font
- Monologue chimes replaced with production-quality manual synthesis — insert-tech aesthetic per D-074, pure sine harmonics with mathematical envelopes (#327)
### Fixed
- Bidirectional relationship check (#515) — Check 9 tested `target in npc_rels` which missed NPCs with no relationship entries; changed to `target in self.npcs`
## [v0.1.9] — 2026-02-18
### Fixed
-`make game` now builds client before launching — was missing `build-client` dependency, causing class_name registration failures after `make clean`
-`build-client` uses `--import --quit` instead of just `--quit` — ensures `.godot/` cache and `global_script_class_cache.cfg` are created from scratch
- Room reset API consolidated to `plan_reset` only — `execute_reset` removed (was a maintenance trap; production uses Commands via `plan_reset`)
-`room_at()` documented with z-range and corridor overlap assumptions
- TCP runtime test now has 10s read timeout and registers player in EntityRegistry
### Removed
- Dead `RoomMember` component from reset.rs (defined but never used)
- Protocol v8: dialogue_response field decoding (DialogueResponseEvent with line_id, text, speaker_entity_id) from server #305/D-028
- Test client binary scaffolding (#480) — standalone crate at `tooling/test-client/` with CLI (--connect, --replay, --text, --json, --quiet, --golden, --ticks), exit codes (0/1/2), golden file JSON diff, JSONL replay loader
- Snapshot text renderer (#481) — `format_snapshot_text(&ObserverSnapshot)` pub-exported from server crate, entity labels as kind:entity_id sorted by distance, room name stub, 10 unit tests
- Sprint 9 (Gauntlet) briefing files — server, client, CI, audio, joint — 23 tickets across 4 teams
- Weapon aim lock audio (`sfx_weapon_aim_lock.ogg`) — clinical targeting confirmation tone for weapon aim state (#440)
-`make pre-pr` now checks GDScript fixture staleness alongside Rust fixtures
- Protocol version bumped from 7 to 8 to match server — fixes 5 test failures from version mismatch
- Interact action encoding changed from unit variant to struct variant to match server's PlayerAction::Interact { target_entity_id, verb }
- Monologue duplication test (test_monologue_not_duplicated_after_consumption) fixed — was using poll_snapshot() which doesn't consume _last_snapshot in test mode
- Dialogue selection pipeline (#305, D-028) — 4-layer filtering engine: access tier from KG relationship, situation derivation from game state, trust tier, weighted topic+mood scoring via SimRng. Full Talk verb → selected line → ObserverSnapshot pipeline with cooldown tracking
- ContentSlug component (#452) — stable content identity from YAML (e.g. "kael-davan") independent of runtime Entity handles, for knowledge graph interaction memory across save/load
- Walk-away KG recording (#427, D-064) — IncompleteInteraction knowledge events with Talk/Confront type, ActiveDialogue tracking, walk-away detection clears dialogue and records in KG
- Anomaly detection for urgent recognition (#450, D-060) — AnomalyMarker flags PersonOfInterest/Contradicted entities for 0.3s cognitive delay instead of 0.6s normal
- Recognition monologue during cognitive delay (#451, D-060) — monologue fires at delay START (grey blob phase), not completion. v0.1 fallback lines, anomaly prioritization, cooldown tracking
- Client P0 regression tests (#477) — monologue carry-forward (Bug #5), camera stability during pause (Bug #2)
- Client P1 tests (#478) — fog shader state (4), entity lifecycle (2), pending recognition blob (1)
### Changed
- Fog byte magic numbers replaced with named constants (#476) — VIS_HIDDEN/PERIPHERAL/FORWARD, EXP_UNEXPLORED/EXPLORED/VISIBLE in FogState
- Dialogue options now carry structured {text, response_id, priority, confrontation} instead of plain strings
- Protocol v7 dialogue decode validates and skips malformed options
### Added
- QA test architecture workshop complete — 3-round, 7-agent workshop producing 60 tickets (epic #455): Gauntlet test world (7 rooms, 48 entities), test client binary (tooling/test-client/), determinism fixes, content validation, make pre-pr pipeline, 38 client tests, anti-tedium features, human tester workflow
- Workshop skill updated — agents now write output files to disk instead of sending messages, fixing documenter access
- Camera anchor test suite — 10 gdUnit4 tests verifying camera init, smoothing cycle, and player tracking
- Entity position lerping — framerate-independent exponential smoothing so entities slide between tiles instead of snapping
### Fixed
- Server never sends snapshots — blocking TCP read in receive_bridge_inputs stalled the entire bevy Update schedule; switched to non-blocking I/O with WouldBlock handling
- Camera doesn't center on player at startup — Camera2D smoothed_camera_pos starts at (0,0); now disable smoothing during init, snap to player, re-enable after first anchored frame
- Player moves while game is paused — movement commands now discarded when TickRate is Paused (pause/unpause still process)
- Spacebar only pauses, doesn't toggle — added UNPAUSE action with toggle logic based on tick_rate state
- MessagePack encodes tick 128 as -128 — off-by-one in signed int boundary checks (<=128 instead of <128) across int8/16/32/64 branches
- Monologue/dialogue lost on snapshot overwrite — one-shot events now carried forward when a newer snapshot replaces an unconsumed one
- Fog shader white screen on load failure — ColorRect defaults to transparent, shader load failure logged instead of crashing
- Fog desync during camera smooth pan — fog rect now tracks camera position instead of player position
### Changed
- Server game loop throttled to ~20 ticks/sec (50ms frames) — non-blocking TCP loop no longer spins; remaining frame budget available for NPC AI
- Hold-to-move input model — movement polled each frame with stance-based throttle (Sprint=200ms, Walk=400ms, Careful=600ms, Crouch=800ms) and composite diagonals (W+D → northeast)
- D-053 updated with client throttle rates and input model documentation
### Added
- Dialogue box UI skeleton (#434, D-061) — bottom screen, max 20% height, ~65% width, NPC speech + max 3 response options, insert-styled colors, WASD walk-away with 300ms fade, no close button, diegetic on InsertOverlay z-layer 6
- Fog entity visualization (#431, D-059/D-060) — cognitive delay rendering: sonar-style sound pings (3 concentric rings, 1.5s fade), unrecognized grey blobs with 0.8s breathing pulse, D-033 color transition at 50% recognition progress, ±0.5 tile position drift, FogEntities node at z:950
### Changed
- Client protocol version bumped from 6 to 7 (pending_recognitions decode for cognitive delay)
- GameState: current_dialogue and pending_recognitions fields wired from ObserverSnapshot v7
- Scene tree: DialogueBox added to InsertOverlay, FogEntities at z:950 between fog shader and InsertOverlay
- Test mode: mock dialogue (Kael NPC, 3 options) and mock cognitive delay entity (6-tick recognition cycle)
### Added
- Archetype evidence presentation spec (#443, D-065/D-034/D-033) — detective case file vs smuggler notebook design document: item definitions, knowledge graph presentation, contradiction markers, THE FRIEND arc walkthroughs, systems interaction map, authoring guidelines
- Cognitive delay system (#423, D-060) — CognitiveDelay component buffers perception events before emitting KnowledgeEvents (0.6s base / 0.3s urgent at 10 tps), pending_recognitions in ObserverSnapshot v7 for client fog entity visualization, cancellation on entity LOS exit
- ListeningFocus eavesdrop system (#426, D-053) — stationary_ticks tracking for eavesdrop positioning bonus, 30-tick threshold (20 for Careful stance), Sprint blocks accumulation, registered after validate_movement
- Line pool format specification (#308) — formal spec at docs/architecture/line-pool-format.md defining YAML structure, tag enums, 4-layer filtering pipeline, prerequisite-to-KG mapping, ID format, and Rust loader interface
- InteractionMemory KG schema design (#442, D-064) — design doc at docs/architecture/interaction-memory-schema.md extending FactKnowledge with interaction tracking, 5-state InteractionState enum, monologue prerequisite extension, NpcTolerance reconciliation
- Asset pipeline documentation system (docs/assets/) with category-based index, sonic palette, and generation templates for audio, visual, and video pipelines
- Stable Audio Open connector and post-processing wrappers (audio-generate, audio-health, audio-post) with timeout handling for 11GB VRAM constraint
- gen-audio skill with prompt assembly system (sonic palette prefixes + category templates + asset descriptions)
- Architecture docs: z-layer gap analysis, fog shader spec, flying taxi feasibility analysis
### Changed
- Scene tree restructured: Entities z_index 3->0 (critical y-sort fix), FloorObjects->10, YSortGroup->100, Overhead->300, FogOverlay->900, ModalLayer added
- constants.gd rewritten with three-scope z numbering and full reserved range documentation
- Fog renderer replaced: TileMapLayer-based fog_renderer.gd deleted, replaced by shader-based fog_shader.gd + fog.gdshader
### Added
- ObserverSnapshot v6 wire protocol (#449) — player_stance (MovementStance) and player_inventory (Vec\<InventoryItem\>) fields with serde defaults for backward compatibility
- Stance system (#417) — Sprint/Walk/Careful/Crouch movement stance with tick-based speed (1/2/3/4 ticks per move), monologue rate multipliers (40%/100%/150%/100%), PlayerMoveCooldown component, ToggleStanceUp/Down player actions
- VerbKind::Confront — Phase 2 only verb injected when observer has KnowsDetails+ on an NPC at close range
- Smuggler inventory system (#424) — CarriedBy(StableId) component, Take/Place verbs, 9-slot (3x3 grid) capacity, auto-slot assignment, info boundary enforcement (carried items invisible to other observers)
- MovementProfile component (#418) — per-archetype default stance (smuggler=Walk, detective=Walk), applied on spawn, factory methods for future archetypes
- Sprint interaction buffer suppression (#419, D-055) — sprint stance explicitly clears interaction buffer, no verbs computed or sent during sprint, anomaly monologue pipeline unaffected
- Sprint anomaly double-take monologue (#428, D-055) — SprintAnomalyQueue component detects Contradicted entities during sprint, fires delayed retroactive monologue after ~1.5s ("Wait — something wasn't right back there"), first-in-wins queue semantics, 3 hardcoded v0.1 lines
### Changed
- Protocol version bumped from 5 to 6 (stance, inventory, ObjectType, verb system fields)
- MessagePack fixtures regenerated for protocol v6
- Input processing queries expanded for stance and cooldown components with backward-compatible Option wrapping
- Observer pipeline queries expanded for Stance and CharacterArchetype components
- NearbyInteraction carries object_type and contradicted fields for Phase 2 context
- BridgePlugin system ordering: process_sprint_anomaly_monologue runs after trigger_monologue, compute_observer_snapshot runs after anomaly processing
- Player spawn includes MovementProfile, Stance, PlayerMoveCooldown, and SprintAnomalyQueue components
- 331 tests total (131 new) — comprehensive QA coverage across stance, occupancy, Phase 2 verbs, sprint suppression, inventory, anomaly monologue, and wire format
### Added
- D-066: Dual-scale grid — 0.5m simulation tiles for stealth granularity, 1m visual tiles for proportional art (2x retina factor). All world geometry 2x2 sim tile minimum so cover/LOS maps 1:1 with visuals. Amends OQ-01.
- Sprint CLI (`db/connectors/sprint`) — unified sprint lifecycle management with 5 subcommands: status, start, stop, start-work, prepare. Auto-detects sprint from DB state and team from git branch. Guards prevent activating unplanned sprints.
- Shared permission settings in `.claude/settings.json` — git, ticket/sprint CLI, make, tea, and core skills pre-approved across all worktrees. Deny rules block destructive operations.
- Decisions D-053 through D-065 from Control & Interaction Workshop — formalized interaction verb system, contextual actions, NPC awareness model, and related design decisions
- Sprint 6 Touch briefings for server, client, copy, and joint teams
- Control & Interaction Workshop outputs — full workshop notes and outcomes
- Smuggler inventory item specs for transit district (#441)
- Start-workshop skill for multi-agent design workshops
### Fixed
- Added worktree boundary rules to CLAUDE.md — agents must stay within the git root, no navigating to sibling worktrees or above the repo
- Plan-sprint skill now enforces worktree-relative paths in generated briefings
- Worktree-update skill now discovers branches dynamically via `git worktree list` instead of relying on hardcoded branch names — fixes missed branches like `planning`
### Changed
- Start-sprint and plan-sprint skills updated to use sprint CLI instead of manual multi-query workflows
- Permission syntax migrated from deprecated `:*` suffix to modern space-wildcard format across all worktrees
- Internal monologue trigger system (#414) — enter_location fires on first tick, time_idle fires after 100 ticks of no movement, 300-tick cooldown, dedup within session, random line selection from content pools via ChaCha20 RNG
- MonologueEvent in ObserverSnapshot v5 — current_monologue field carries id, text, and display duration across the IPC bridge
- Moved ui-strings.yaml from content/campaigns/_meta/ to client/data/ for direct Godot client loading
### Fixed
- Fact ID format collision across FRIEND content — normalized 73 flat IDs to dotted category.topic format, fixing broken detective evidence chain from Sera to Kael observations
- Entity ref format inconsistency — normalized underscore format to npc:hyphenated across ~15 monologue references
- Phase tag inconsistency between FRIEND packs — standardized to phase-N format, added missing phase-2 tags to Kael ring ops lines
- Detective monologue gap for Kael — added 7 observation lines (7 → 15 total), added mood tags and bar_evening situation to Kael bar content
- Hoshe QA briefing updated with integration test coverage priorities — test harnesses, dedicated client-server test map, edge case focus
- Live server mode (`make game`) — single command builds server, launches client with TCP connection, auto-kills server on exit; `make stop` helper for manual cleanup
-`SR_LIVE=1` environment variable switches SimBridge from test mode to real TCP server connection
- TileKind in wire protocol (#412) — server sends Floor/Wall/Door/Object per visible tile, client renders walls and floors in live mode
- Input roundtrip integration test (#411) — spawns real server, connects via TCP, validates full movement and interact pipeline
- Debug logging for received player inputs on server (visible with `RUST_LOG=debug`)
### Fixed
- Interaction prompt target+verb data now attached to Interact action in game loop (#405) — was TODO stub, server receives `{target_entity_id, verb}` payload
- Player entity detection uses `kind.variant == "Player"` instead of hardcoded `entity_id == 1` — fixes "player not found" warnings when connected to real server (which assigns different IDs)
- Movement keys now work in live mode — client was sending millisecond timestamps as input tick, server only processes ticks <= current frame counter; now uses server tick from latest snapshot
- Entity-to-tile alignment in live mode — server sends tile-center render coords (tile 16 → 16.5), entity renderer now floors to tile index before positioning
### Added
- Content loader Phase 2 (#408) — 2-phase spawn pipeline loads real YAML content into ECS entities: enums, entity attributes, pools, templates, triangles, NPC profiles with Want/Tolerance/Contentment/Personality/Tells/Skills axes plus cross-reference resolution for Secrets, Relationships, Information, and DailyRoutine
- YAML to RON converter tool (#403) — build-time converter in tooling/content-converter/, runs via `make content-ron`
- Line previewer CLI (#407) — 4 subcommands (dialogue, monologue, coverage, sequence) for content authors to test line selection without running the full game
- Happiness added to WantKind enum — Harek remapped from Safety to Happiness
### Fixed
- Dialogue-pool schema corrected to use arrays for situation/topic/mood per D-035 (were incorrectly single strings)
- NPC want.primary changed from narrative strings to WantKind enum keywords — fixes silent Want component drop at spawn time
- Schema enum constraint added to npc-profile.schema.json for want.primary validation
### Added
- Sprint 4 "Feel" team briefings — copy (8 tickets), server (9), client (1 carry-over), CI (1), joint coordination
- Interaction prompt system (#405) — server-driven "E - Talk" prompt decoding v4 nearby_interactions with nested VerbOption structs, fade animation, extensible get_interaction_target/get_selected_verb interface for future radial verb menu
- Art direction & mood board workshop (3 rounds + closing) — 4-agent team establishes visual identity, 16 art direction principles, 9 mood board images, 10 candidate decisions (D-042–D-051)
- 3D-to-2D sprite render pipeline (`client/tooling/sprite_renderer/`) — Godot @tool scene renders textured 3D models at "the angle" (-72.5deg ortho) from 4 cardinal directions at 1024/256/64 resolutions with outline applied at working resolution
-`/render-sprite` skill — CLI wrapper for the render pipeline with headless import step
- Pipeline POC: Era 1 institutional wall + bar green wall textures generated via Nano Banana and rendered through full pipeline
- PerceptionQuery trait and ActivePerceptionMode resource — abstraction layer for D-017 perception mode swapping (NaturalVision default implementation)
- VisibilityGeometry intermediate resource decoupling FOV computation from entity filtering
- Client-side PROTOCOL_VERSION enforcement — snapshot decoder rejects version mismatches with error log
- POI verb priority test in observer pipeline — asserts both verb kind and priority values end-to-end
- POI verb priority adjustment moved from simulation phase (interaction.rs) to perception phase (observer) — fixes D-010 information boundary violation
- compute_nearby_interactions no longer reads KnowledgeGraph — determines verb availability by proximity only, verb priority adjusted by observer
- compute_nearby_interactions scheduling moved from SimulationPlugin to BridgePlugin for explicit ordering with geometry and observer systems
- Client test snapshot updated to v4 format (Protocol.PROTOCOL_VERSION, tick_rate replaces paused)
### Added
- Content validation tooling — `make validate-content` validates campaign YAML files against JSON schemas, maps files by directory context
- Entity::to_bits() roundtrip test — guards against bevy version changes silently breaking wire IDs
- TickRate switch mid-accumulation test — verifies Half→Full→Paused→Half transitions preserve accumulator state
- Tick rate scaling system (#406, D-052) — Full/Half/Paused rates with fractional accumulation, SetTickRate player action, replaces binary pause flag
- Proximity detection and interaction verbs (#404, D-060) — compute_nearby_interactions system with Manhattan distance ranges (close ≤2, mid ≤5), context-sensitive verb computation (Talk, Observe, Examine), PersonOfInterest priority flip, NearbyInteraction in ObserverSnapshot v4
- PROTOCOL_VERSION constant in bridge types — versioning strategy documented (subprocess IPC, serde defaults for field evolution)
- Campaign, system, station JSON schemas for hierarchical content validation
### Fixed
- Test suite aligned with server v4 protocol enforcement — all hand-built snapshots include version field, verb priorities 1-indexed, ExamineNpc label corrected to "Observe"
- E2E proof tests resilient to entity ordering — player found by kind instead of array position, wall-hides test checks specific NPC position instead of total count, supports 3-NPC proof room layout
- Wire entity_id now uses StableId consistently across observer, observation, interpretation, and interaction systems (was Entity::to_bits() in some paths)
- Restored system/station/district hierarchical fields in district metadata (incorrectly removed during canonical_id cleanup)
- Unregistered entities in observer/interaction now log tracing::error instead of silently falling back to Entity::to_bits()
### Changed
- NearbyInteractionBuffer refactored from global Resource to per-entity Component on PlayerCharacter — multiplayer-ready (D-009)
- District schema: canonical_id is now optional (derived from directory path at load time)
- Skills trimmed for CLAUDE.md deduplication — search-docs (-48%), ticket (-17%), review-pr (-35%) now reference CLAUDE.md for basics instead of repeating them
- Review-pr reviewer profiles extracted to `references/reviewer-profiles.md` for progressive disclosure
### Removed
- Dead generate_snapshot function in bridge/mod.rs — superseded by compute_observer_snapshot
- content/global/regions/ directory — region data absorbed into system.yaml metadata
### Added
- Dual Lens Authoring Guide — 7-chapter reference for writing content that works for both smuggler and detective perspectives (D-027, D-028, D-032, D-034, D-035)
- THE MIRROR pattern spec — transparency-as-contrast NPC design with Naia Tamm reference implementation and generator template
- v0.1 wow moments checklist — maps all 6 D-039 moments to content deliverables, tickets, dependencies, completion status
- Nils Davan off-stage NPC stub — ring coordinator, GHOST + HANDLER pattern, lattice message design, relationship map
- NPC pattern/motivation mapping applied to all 18 NPC wiki pages with composition reads
- Structured NPC data model (#86) — replaced stub string/f32 fields with typed enums and integer types for D-010 determinism (WantKind, SecretSeverity, Skill, PersonalityTrait, CombatStyle, RelationshipKind)
- Global RelationshipGraph resource (#87) — BTreeMap with tuple key for efficient prefix queries and reverse lookups
- A* pathfinding system (#237) — PathRequest/ComputedPath/PathBlocked components with cardinal-neighbor A* and manhattan heuristic
- NPC path following system (#238) — MovementSpeed throttling, per-tick path advancement with MoveIntent creation
- Daily routine system (#88) — NpcPlugin with PreviousDayPhase resource and check_phase_transition system issuing PathRequests at day-phase boundaries
- Multiple NPC spawning (#84) — 3 distinct NPCs (dock worker, field tech, guard) with full component bundles and RelationshipGraph edges
- Observation event generator (#239) — RoutineDeviation, Absence, and NewEntity triggers from comparing visible snapshot against NPC routines and knowledge state
- Review-pr skill routes reviewers by branch type — server/client get Hoshe+Tyre, copy gets Hoshe+Paula+Miri, visual gets Hoshe+Araminta, audio gets Hoshe+Ozzie
- Start-sprint skill spawns team agents from sprint briefings — parses the Agents line, creates a team with tasks from tickets, and launches all listed agents as background teammates
### Fixed
- IPC error handling (#341) — DeserializationWithDump/MutexPoisoned error variants, hex dump logging on deserialization failure, graceful error classification in bridge I/O systems
- NpcPlugin system ordering — routine phase transitions now run before pathfinding so PathRequests are picked up same frame
- Stale doc comment in observation event generator — system runs before knowledge updates, not after
- Clippy warnings from Rust 1.93 — derive Default, is_multiple_of, collapsible if
### Changed
- Hael renamed to Naia Tamm across all wiki files (16 files updated)
- Canonical full names applied to 11 single-name NPCs (Voss→Arvo Voss, Devra→Devra Talsen, etc.)
- Location shortcodes standardized in monologue guide (hub_m_ → terminal_m_ per D-036)
- Entity attributes updated to 16 canonical keys — 4 new role-perspective keys (risk_assessment, loyalty_assessment, position_integrity, moral_weight), secret_held→leverage_held rename
- Drin Rosta expanded from Tier 3 to Tier 2 — full 10-axis profile, 6 voice lines, Triangle 2 + Triangle 5 roles
- NPC index roster table expanded with Pattern and Motivation columns
- Sprint 3 "Know" team briefings regenerated from database — all four files (server, client, joint, copy) now match actual sprint 3 ticket assignments
- Ticketing database moved to shared worktree location (`../settledreach.db`) — eliminates binary merge conflicts across branches
- All Python connectors use script-relative path resolution instead of `$REPO_ROOT` env var or git rev-parse
-`$REPO_ROOT` environment variable removed — all scripts, skills, and docs use relative paths
- Merged copy branch — 39 tickets, wiki review + content scoping workshops, game world glossary
- Team-agent mapping in sprint planning — each team has defined default agents for briefing assignment
- Sprint skills recognize all team branches (server, client, copy, audio, visual, ci)
- Sprint 3 "Know" team briefings — server (6 tickets), client (2 tickets), joint (2 split tickets), copy (1 carry-over)
- Copy team sprint briefing for Sprint 2 (#368 knowledge vocabulary)
- Sprint 2 proof: fog of perception E2E tests (#357) — 3 tests verifying all 7 acceptance criteria through real server pipeline (movement, tiles, fog, wall hiding, corner reveal)
- Server proof room — wall at (16,14) between player at (16,16) and NPC at (16,13) for LOS testing
- Dynamic test snapshot in SimBridge — tracks player position from queued inputs, Bresenham LOS, Manhattan-distance visibility for standalone demo mode
- 4 Bresenham LOS unit tests — clear path, wall blocked, diagonal, same position (PR #13 review)
### Fixed
- Type safety in GameState visible_tiles loop — validates Dictionary with x/y keys before access (PR #11 review)
- Consistent reset_test_state() usage across all test files (PR #13 review)
- E2E connection loop now detects server process death early (PR #13 review)
- Corner reveal test verifies NPC position at (16.5, 13.5) (PR #13 review)
- Observer snapshot knowledge integration (#366) — VisibleEntity carries relationship state (D-033 color) and observation type (Visible/Remembered), remembered entities appear as fog ghosts at last known position
- Vision cone system (#111) — forward/peripheral/blind sectors per D-015, Facing component updated on movement
- Symmetric shadowcasting (#110, #359) — Albert Ford algorithm with rational fraction slopes, benchmarked 1.2-10.5x faster than recursive, symmetry guaranteed (D-035)
- ObserverSnapshot v2 schema (#358, #25) — version field, GameTime, FacingDirection, VisibleTile, VisibilitySector types, visibility tag on entities
- D-035 decision record — symmetric shadowcasting selected over recursive (resolves Q-018)
- Tile rendering engine (#129) — programmatic TileSet with floor/wall/door/object placeholders, renders from snapshot tile data
- Fog overlay rendering (#131) — three visibility states (visible/fog-edge/hidden) via TileMapLayer overlay
- Camera lock to character (#116) — Camera2D smoothing at 2x zoom, locked to player position (D-015)
- Test room environment — 8x8 room with corridor and Manhattan-distance visibility for development without server
-`ticket team` command and `--team` filter — comma-separated team assignment for tickets (server, client, joint, content)
### Changed
- All instruction files (CLAUDE.md, skills, agent files) now use `$REPO_ROOT` env var instead of `git rev-parse --show-toplevel` — pre-set per worktree via `.claude/settings.local.json`
-`start-sprint` skill now requires plan mode — agent must create and get approval for a concrete sprint plan before starting implementation
### Fixed
- Entity renderer protocol field mismatches — "id"→"entity_id", "type"→"kind.variant", "position"→x/y fields now match Protocol.decode_entity() output
- Entity centering — entities (24x24) now centered within 32px tiles instead of top-left aligned
-`start-sprint` skill uses `git rev-parse --show-toplevel` for worktree-safe absolute paths — fixes "No such file or directory" errors on team branches
### Changed
- Background clear color set to near-black for unexplored areas (was default Godot gray)
- Scene render order: Tiles → FogOverlay → Entities (fog covers tiles, entities render on top)
- FogOverlay node type changed from Node2D to TileMapLayer for tile-based fog rendering
- GameState now stores visible_tiles and visible_positions from snapshots
- Test snapshot includes player entity (kind "Player"), second NPC entity, tile data, and visibility data
### Added
- Sprint 2 "See" briefings (server, client, joint) — fog of perception through the bridge
- End-to-end connection test (#81) — GDScript test spawning Rust server, connecting via LocalBridge, sending MoveNorth input, verifying player movement in snapshot response (D-030 Layer 3)
- Batch input encoding (Vec\<PlayerInput\> wire format) — Protocol.encode_player_inputs() batches all inputs per tick into one framed message matching server expectations
- EntityKind::Player fixture — snapshot_player.msgpack for cross-language testing, multi-entity fixture updated to include all 4 entity kinds
- 7 new tests (4 batch encoding, 1 framed batch roundtrip, 1 Player fixture decode, 1 E2E connection), 43 total client tests passing
- LocalBridge GDScript TCP transport (#79) — 4-byte big-endian length-prefix framing matching Rust server, StreamPeerTCP wrapper with partial read handling
- ServerProcess subprocess manager — spawns/stops Rust server via OS.create_process(), auto-cleanup on destruction
- SimBridge live transport integration — _process() polling loop for TCP receive/send, connection state machine (DISCONNECTED → CONNECTING → CONNECTED → ERROR)
- 8-directional input support — 4 diagonal movement variants (NE, SE, SW, NW) in InputMapper, SimBridge wire mapping, and project.godot input actions
- Tile collision system (#236) — TilePosition component, chunk-based WalkabilityMap (D-012), MoveIntent + validate_movement system
- TilePosition ↔ f32 render coordinate conversion (to_render_coords, from_render_coords) bridging simulation and wire format
- Chunk load/unload support in WalkabilityMap — HashMap<ChunkCoord, ChunkData> with 32x32 tile chunks
- 8-directional movement — diagonal PlayerAction variants (MoveNortheast/Northwest/Southeast/Southwest) + TilePosition::all_neighbors()
- Entity-entity collision in validate_movement — spatial occupancy check prevents multiple entities on same tile
- 25 new tests (4 framing + 2 IPC integration + 17 movement unit + 2 movement integration), total 45
- MessagePack serialization for GDScript (ticket #77) — Protocol codec decoding ObserverSnapshot/PlayerInput from Rust wire format, encoding PlayerInput for server
- Godot4MessagePack library (pure GDScript) for MessagePack encode/decode
- Rust fixture generator (gen_fixtures.rs) producing canonical .msgpack test fixtures with rmp_serde
- D-028: Dialogue architecture — tagged line pools with four relational layers (access tiers, history, trust-gating, unprompted disclosure)
- D-029: Population entanglement ratio — 30% flat / 50% mundane triangles / 20% intrigue-entangled
- Content architecture workshop brief documenting the "life first, drama second" design philosophy
- Mellanie (Copywriter) activated from standby for content authoring phase
- Round 16 faction development — Full faction framework with lore, political analysis, mechanical grounding (session closed, awaiting team input for v0.1 selection)
- 3D reputation system: Trust × Usefulness × Exposure per faction
A top-down immersive sim — occlusion-based detective game with combat elements, set in an original science fiction universe (Commonwealth-inspired). Single-character perspective, asymmetric information as core mechanic, Rimworld-style storyteller. Godot 4 client + Rust/bevy_ecs simulation server via subprocess/IPC (D-020).
A top-down immersive sim — occlusion-based detective game with combat elements, set in an original science fiction universe. Single-character perspective, asymmetric information as core mechanic, Rimworld-style storyteller. Godot 4 client + Rust/bevy_ecs simulation server via subprocess/IPC (D-020).
**Official Title:** The Settled Reach (D-021)
**Repository name:** settled-reach (formerly commonwealth, renamed for clarity)
**Version source of truth:**`project.yaml` (root `version` field, scheme: `0.1.{sprint_number}`)
## Project Structure
```
DECISIONS.md # Confirmed decisions (D-001+), open questions (Q-001+)
See [docs/DEVOPS.md](docs/DEVOPS.md) for build, test, lint, and CI procedures. All development operations go through the top-level `Makefile` — run `make` for a summary of targets.
## Agent Instructions
### Worktree boundaries
This project uses **git worktrees** in a shared parent directory (`settled-reach/`). Each team branch (`server`, `client`, `copy`, `audio`, `visual`, `ci`) is checked out in its own worktree under that parent. The parent directory also contains shared resources like the ticketing database.
Each worktree contains the full repository: `server/` (Rust backend), `client/` (Godot client), `docs/`, `decisions/`, etc. The worktree root IS the git root — use `git rev-parse --show-toplevel` if in doubt.
Unless there is a direct instruction or a functional need (e.g. accessing the shared database in the parent directory), **all work must remain within the scope of the git root Claude is running in.**
- All file paths are relative to the worktree/git root (e.g. `server/src/bridge/types.rs`, `client/scripts/rendering/fog.gd`).
- Do not navigate to or access sibling worktrees in the parent directory (`../client/`, `../copy/`, etc.) unless explicitly instructed.
- Do not navigate above the git root unless explicitly instructed.
### Database
The ticketing database (`settledreach.db`) lives in the **parent directory** shared across all worktrees — it is not tracked in git. A backup is committed to `docs/backups/settledreach.db.backup` via main only.
### Before starting work
1. Read your briefing at `docs/briefings/{your-name}.md` for current project context
2.Read `DECISIONS.md` for confirmed decisions relevant to your work
3.Check `DISCUSSION.md` for any active discussion
1. Read your sprint briefing at `docs/sprints/sprint-N/{team}.md` for current tasks
2.Use `db/connectors/ticket show <id>` for full ticket details
3.Read the relevant `decisions/*.md` domain file(s) referenced in the briefing
**Never use the `sqlite3` CLI** - it crashes in Claude Code due to a known std::bad_alloc bug.
### Ticket and database access
**Prefer the ticket CLI over raw SQL.** The CLI handles column names, joins, and output formatting correctly:
```bash
db/connectors/ticket list --sprint 2 --team server
db/connectors/ticket show 78
db/connectors/ticket sprint --active
```
Use the whitelistable wrapper scripts:
### Sprint CLI
**Use the sprint CLI for sprint-scoped operations.** It batches ticket queries and formats output for agent consumption:
```bash
db/connectors/sprint status # Current sprint progress
db/connectors/sprint status --team server # Team-scoped view
db/connectors/sprint start-work --team client # Full context dump for starting work
db/connectors/sprint prepare # Prepare next sprint (candidates + gaps)
db/connectors/sprint start # Activate a planned sprint
db/connectors/sprint stop # Complete an active sprint
```
Team is auto-detected from the current git branch (if not `main`). Sprint is auto-detected from DB state.
Only fall back to raw SQL for queries the CLI doesn't support. **Never use the `sqlite3` CLI** — it crashes in Claude Code due to a known std::bad_alloc bug. Use the wrapper scripts instead:
```bash
db/connectors/sqlite-query "SELECT * FROM tickets WHERE status='in_progress'"
db/connectors/sqlite-exec "UPDATE tickets SET status='done' WHERE id=1"
@@ -49,17 +107,75 @@ db/connectors/qdrant-health
db/connectors/qdrant-count
```
### Gitea access (tea CLI)
**Never access the Gitea API directly** — use the `tea` CLI with all required flags to bypass interactive mode.
- **`tea pr reject` does not work on your own PRs** — use `tea comment` instead
- **Never delete protected branches:** `main`, `maintenance`, `server`, `client`, `copy`, `audio`, `visual`, `ci` are protected on Gitea. Do not use `tea pr clean`, `git push --delete`, or `git branch -D` on these branches.
### File conventions
- Decisions: domain files in `decisions/` (see `decisions/README.md` for index)
**Use `tea` (Gitea CLI), not `gh` (GitHub CLI).** The remote is Gitea at `git.schweitz.internal`.
Always provide all required flags to ensure non-interactive execution:
```bash
tea pr create \
--repo jpmschweitzer/settled-reach \
--login schweitz \
--title "feat(scope): short description" \
--description "PR body here" \
--base main \
--head branch-name
```
### Large content pushes (team pattern)
When producing many files (wiki pages, content batches, bulk docs):
1. **Lore librarian** agent (read-only): ingests all source material, answers focused context queries from writers, tracks cross-file consistency
2. **Multiple writer** agents (parallel, by domain): each gets a task slice, writes directly to disk using the Write tool — one file at a time, write often, no text accumulation
- **Decision:** We are building a standalone game, not a Stellaris mod.
- **Rationale:** No existing game provides the right combination of character-driven dynasty play, wormhole-centric space map, and deep internal politics that the Commonwealth universe demands. Stellaris gets the map right but characters wrong. CK3 gets characters right but the map wrong. Neither supports wormhole-as-infrastructure as a core mechanic.
- **Raised by:** Team Leader (Jeroen), after team debate across Rounds 1-3.
- **Dissent:** None. Team unanimously supports after discussion.
### D-002: SUPERSEDED by D-005
### D-003: Commonwealth is the first campaign, not the only possible one
- **Date:** 2026-02-08
- **Decision:** Build a character-driven space grand strategy *framework/engine*, with the Commonwealth universe as the first campaign/scenario.
- **Rationale:** Avoids locking into one IP. The framework has broader value. The Commonwealth provides a rich, opinionated first use case that forces good design decisions.
- **Raised by:** Gore (Transhumanist Fan), endorsed by team.
### D-005: Core concept - single character, first-person, story-generator
- **Date:** 2026-02-08
- **Decision:** The game is a first-person, single-character experience. You select a character at game start and play from their perspective. The world is a rich simulation experienced through one person's keyhole view.
- **Supersedes:** D-002 (dynasty grand strategy concept)
- **Elevator pitch:** "Pick a character. Step into the Commonwealth. Figure it out."
- **Key pillars:**
- **Single character selection** - who you pick determines where you start, what you know, what you can do, and what you care about
- **Asymmetric information as core mechanic** - you only know what your character knows. Others lie, withhold, reveal. The same world-state looks completely different from different characters
- **Rimworld-style story generator** - an AI storyteller paces events for dramatic tension. Structural randomness (who's compromised, where evidence is) set at game start. Dramatic randomness (when things happen) driven by pacing
- **Wormhole network** as traversable infrastructure - you physically move through wormholes between locations
- **Crisis events emerge from simulation** - not timers, not scripted, but consequences
- **Replayability through perspective** - same conspiracy, different character, completely different game
- **Design references:** Rimworld (storyteller/systems), Disco Elysium (character-driven investigation), Sunless Skies (atmosphere/travel), King of Dragon Pass (event-driven decisions)
- **Raised by:** Team Leader (Jeroen), evolved through Rounds 4-6 with full team input.
- **Dissent:** None. Team unanimously energized by the pivot.
### D-006: Prototype scenario - Institute / Armstrong City / Guardians
- **Date:** 2026-02-08
- **Decision:** The first playable prototype focuses on the Starflyer conspiracy arc, scoped to the investigative/political hub: the Institute, Armstrong City, and the Guardians of Selfhood. This tests the core mechanic (asymmetric information in a conspiracy) with controllable scope.
- **Rationale:** The conspiracy arc IS asymmetric information. If it's not compelling at this scale, a galaxy won't fix it. If it works, everything else is expansion.
- **Raised by:** Team Leader (Jeroen).
### D-007: Five pillars of game design
- **Date:** 2026-02-08
- **Decision:** The game rests on five core design pillars. All systems must serve at least one.
- **Pillars:**
1.**Characters & Information** - who you are, what you know, who you know. Asymmetric information is the master mechanic.
2.**The Wormhole Network** - where you go, how you move through the world. Physical traversal of infrastructure.
3.**Society & Factions** - the political landscape you navigate from inside, not above.
4.**Crisis & Storyteller** - what the world throws at you and when. Rimworld-style AI pacing with structural + dramatic randomness.
5.**Action & Spectacle** - what happens when it all goes loud. The punctuation, not the sentence.
- **Decision:** The action/combat system follows these principles:
- **Rimworld/XCOM hybrid** - simple mechanics, stats-driven. Simple gets complicated fast on its own.
- **Z-levels** - floors, verticality. Not 3D rendering, but 3D space. Fights across floors of a building.
- **Perception-bounded** - you see/hear what your character can. Rest is abstracted/occluded. Same principle as information asymmetry applied to physical space.
- **LOD/occlusion** - simulation reduces outside player view. Both a design principle and performance optimization.
- **Large, varied maps** - locations should feel big. Achieved through procedural generation (templates + procedural flesh), trickery, or both. Procedural layouts also feed replayability.
- **Multiple maps** - different locations are separate maps. Step through a wormhole, load a new place.
- **Wildly asymmetric encounters** - balanced fights are the exception. Power mismatches in both directions are the norm and the source of tension.
- **Hubris wall as design principle** - let the player feel powerful, then recontextualize their power level. Not cheap difficulty spikes - genuine "you were playing a smaller game than you thought" moments. The books are not always balanced; the fun comes when a character hits their hubris wall.
- **Death = information loss, not game over** - memory cell backup system means death costs you everything since your last backup. Lost knowledge, lost relationships, lost deals. The storyteller knows what you've lost and can exploit it.
- **Scales with ascension** - baseline human fights with weapons, Higher fights with biononics, ANA-connected fights with something else entirely. The pillar transforms as the character evolves.
- **Design references:** Rimworld (real-time, simple systems, personal stakes), XCOM (tactical asymmetry, pod activation moments), Dwarf Fortress (z-levels, simulation depth)
- **Raised by:** Team Leader (Jeroen), with input from full team.
### D-009: Multiplayer - design for it, build single-player first
- **Date:** 2026-02-08
- **Decision:** Single-player is the build target. Multiplayer is designed into the architecture from day one so it can be added without rewriting the game.
- **Rationale:** Two players experiencing the same conspiracy from different keyholes (Senate insider + Guardian operative) is a killer feature. But building multiplayer too early kills projects. The compromise: architectural decisions now that make multiplayer a "add networking" problem later, not a "rewrite everything" problem. Team Leader flagged that bolting multiplayer on after the fact is one of the hardest things to do - so the architecture must be honest about this from the start.
- **Cost:** ~15-20% slower single-player development due to required abstractions. Accepted as cheap insurance.
- **Raised by:** Full team discussion. Tyre led technical framing, Team Leader insisted on architectural honesty.
- **Decision:** Four non-negotiable architectural principles that must be present from the first line of code:
1.**Client-server separation** - even in single-player. The game simulation runs as a "server," the player view is a "client." Single-player = local client + local server. This is the single decision that makes or breaks retrofitting multiplayer.
2.**Information boundaries as a first-class system** - every piece of game state is tagged with who knows it. Not fog-of-war bolted on - the engine fundamentally thinks in terms of "what does this observer have access to." Required for single-player asymmetric information anyway. Multiplayer just means multiple observers.
3.**No baking player identity into the game loop** - the simulation doesn't know there's "the player." It knows there are characters, some of which are player-controlled. Adding a second player-controlled character should be a configuration change, not a rewrite.
4.**Deterministic simulation with input events** - game state advances based on timestamped actions, not "whatever the local machine calculated." Enables synchronization later without rewriting the simulation.
- **Side benefits (Nigel's observation):** Every one of these makes single-player better too. Information boundaries make NPC AI smarter about what they know. Client-server makes save/load cleaner. Deterministic simulation makes debugging easier. No sacrifice.
- **Engine implication:** Client-server friendliness is now a hard requirement on the engine shortlist (see Q-001).
- **Raised by:** Tyre (Technical Architect), endorsed by Team Leader as "sound architectural baseline."
### D-011: Fog of perception is non-negotiable (Pillar 1 infrastructure)
- **Date:** 2026-02-09
- **Decision:** Fog of perception is not a feature - it's the minimum requirement for information asymmetry to work with a top-down camera. Without it, the player is omniscient within their viewport and the entire information pillar collapses at the local map level. First-person camera gets this for free; top-down must enforce it.
- **Implementation:** Line-of-sight based (shadowcasting), not simple radius. Walls block vision, buildings are opaque, corners create blind spots, z-levels interact with sightlines.
- **Sound as secondary information channel:** Events outside LOS can be heard - footsteps, conversations, gunfire, alarms. Sound gives partial/directional information, prompting decisions based on incomplete data.
- **Applies to ALL entities:** NPCs use the same LOS/perception system as the player. An NPC who can't see you doesn't know you're there. NPCs have memory and inference (saw you enter a building → knows you're inside). Ties to D-010 principle 2: information boundaries are universal, the player's isn't special.
- **Fog returns when you leave:** Previously explored areas revert to fog over time. Information about locations decays. What you saw at the docks yesterday may not be true today.
- **v0.1 scope:** 2D shadowcast per z-level + sound propagation. Vertical LOS (looking between floors) deferred.
- **Rationale:** Team Leader identified overnight that top-down without fog is a fundamental gap in the information asymmetry design.
- **Raised by:** Team Leader (Jeroen), with technical framing by Tyre and Gestalt.
### D-012: Chunk-based map architecture for future borderless generation
- **Date:** 2026-02-09
- **Decision:** Maps use chunk-based generation and loading from day one. Chunks load/unload around the player. A bounded map is "only generate chunks within this boundary." Removing the boundary later to enable Minecraft-style borderless generation is a configuration change, not a rewrite.
- **v0.1:** Bounded ~150x150 per world, 2-3 z-levels, chunk-based internally.
- **Future:** Borderless generation. The world generates as you explore. The map can never be "solved" by walking to every corner. New areas develop, existing areas change.
- **Rationale:** Same principle as D-010 (multiplayer architecture) - design for the future, build the simpler version now.
- **Raised by:** Tyre (Technical Architect), endorsed by Team Leader.
### D-013: Diegetic insert/POI navigation system
- **Date:** 2026-02-09
- **Decision:** The player's map interface is diegetic - it IS the character's neural insert (Commonwealth technology). Not a game UI bolted on, but the character literally checking their implant's navigation overlay. Points of interest appear on the map only when learned through gameplay.
- **Canon basis (Miri):** Commonwealth citizens have inserts connecting them to the unisphere. Built-in navigation, messaging, data access. Characters in the books constantly check inserts for directions, news, contacts.
- **How POIs are learned:**
- Character background (starting knowledge based on who you are)
- Research (unisphere searches, case files, institutional databases)
- Physical discovery (finding something while exploring)
- **Different characters see different maps:** A cop sees flagged locations from case files. A Guardian sees safehouses and dead drops. A Senator sees political venues. Same city, different POI layer.
- **POIs can be manipulated:** Tips can be traps. Locations can be outdated. Information channels through the insert system carry the same trust/deception dynamics as verbal information.
- **Anti-Ubisoft:** No "climb tower to reveal icons." Map fills at the pace of investigation. Early game: sparse, frightening. Late game: dense, and you realize how much you missed.
- **Anchoring by desire, not force:** In a borderless world, the POI/insert system gives players reasons to go to specific places without funneling them. Navigation is pulled by player intent, not pushed by map design.
- **Multiplayer implication:** Players can share/send POIs via inserts. In co-op: collaborative conspiracy boards. In adversarial: feeding false locations.
- **Raised by:** Team Leader (Jeroen) proposed borderless + anchoring concept. Miri confirmed canon basis. Full team contributed mechanics.
### D-015: Camera locked to character, rotation as future option
- **Date:** 2026-02-09
- **Decision:** Camera is locked to the character at all times. No panning. Optionally rotates to character facing direction (player option, later version).
- **Rationale:** Pannable camera breaks the information model - you become a surveillance drone, not a character. Locked camera reinforces "you ARE this person." Rotation with facing direction restores directional audio mapping (binaural becomes viable again) and creates a natural vision cone (front = detailed, peripheral = reduced, behind = blind).
- **Vision cone model:**
- Forward: full LOS, full detail
- Peripheral: reduced range, dimmer
- Behind: fog / blind spot. You can be snuck up on.
- **Reference:** Hotline Miami's camera made that game terrifying with the same principle.
- **v0.1:** Locked camera, no rotation. Vision cone still works on fixed-north map. Rotation deferred as player option.
- **Raised by:** Team Leader (Jeroen).
### D-019: Top-down confirmed as primary camera, 3D cutscenes for key moments
- **Date:** 2026-02-09
- **Decision:** Top-down is the gameplay camera. Final. 3D cutscenes can be used for significant narrative moments (wormhole traversal, Dyson barrier opening, first contact, major reveals).
- **Rationale after full honest review:**
- What first-person would give us (visceral traversal, face-to-face conversations, natural asymmetry, spatial horror) is real but compensated by: vision cone + fog, internal monologue, perception mode overlays, sound model
- What top-down gives us that first-person can't: multi-layer information observation, tactical combat clarity, system legibility, NPC simulation visibility, strategic UI coexistence, 5-10x faster prototype
- Key insight (Gestalt): the fun is systems interacting - observation → insert check → thermal → monologue → mental note → exploitation. That sequence is BETTER top-down.
- Key insight (Paula): monologue interpreting faces/conversations is arguably richer than player reading 3D faces, and more faithful to Hamilton's close-POV writing style
- 3D cutscenes recapture the visceral moments without burdening gameplay engineering. They're decoupled, can be added as polish, game ships complete without them.
- Camera change to 3D IS the dramatic signal - player knows something significant is happening (Gestalt)
- **Architecture note (Tyre):** Client-server separation means the renderer is swappable. A full first-person client is architecturally possible in the future. Top-down now doesn't mean top-down forever.
- **v0.1:** Top-down only. No cutscenes. Those are milestone features.
- **Raised by:** Team Leader (Jeroen), after full team review of tradeoffs in Round 12.
### D-016: Internal monologue as core perception/atmosphere system
- **Date:** 2026-02-09
- **Decision:** The player character has an internal monologue that narrates sensory information the camera can't show, creates atmosphere, provides diegetic hints, and can be an unreliable narrator.
- **Functions:**
- **Perception bridge:** Translates non-visual senses into character voice. *"Footsteps behind me. Two people, unhurried."*
- **Atmosphere:** Character's running commentary on environment, mood, situation.
- **Diegetic tutorial:** Character thinks about what they might do. *"That terminal might have access logs."* No "press X" popups.
- **Unreliable narrator:** Monologue is character's INTERPRETATION, not ground truth. Can be wrong. *"Seems quiet. Safe to move."* (It wasn't safe.)
- **Character voice:** Varies by character background, mood, knowledge. Paranoid Guardian vs confident Senator walking the same street = different monologue = different experience.
- **Production note (Nigel):** Cheapest feature on the list - it's text. Thousands of contextual lines, AI-assistable generation, character-specific variants.
- **Raised by:** Emerged from team discussion. Tyre proposed text/log as sound option, team recognized broader potential.
### D-017: Perception modes as character-build system
- **Date:** 2026-02-09
- **Decision:** The fog/vision system supports multiple perception modes that vary by character build, equipment, and ascension level. Each mode reveals different information with different trust/quality tradeoffs.
- **Confirmed modes:**
- **Natural vision** - detail, color, identity. Blocked by walls. Everyone has it.
- **Thermal** - heat signatures through walls. Body count but no identity. Higher biononic / military gear.
- **Camera feeds** - remote visual from fixed positions. Only where cameras exist. Feed can be spoofed/looped. Hacker, institutional access, insert exploit.
- **Unisphere tracking** - location pings of known individuals. Only active inserts, can be masked. Law enforcement / intelligence access.
- ANA-touched: pattern recognition across all feeds, predictive awareness
- **Playstyle implications (Nigel):** Low-tech Guardian playthrough = survival horror (blind, relying on contacts and paranoia). Senator playthrough = information overload (cameras and tracking but drowning in data). Perception modes are playstyle selectors.
- **Canon check (Miri):** All modes exist in the books. Higher biononics include enhanced senses. Unisphere connects everything. Security systems are hackable. Guardians actively spoof and evade. Starflyer agents defeat all sensor modes.
- **v0.1:** Natural vision cone + basic audio indicators + insert minimap only. Additional modes are milestone features, each self-contained and modular.
- **Engine implication:** Each perception mode is an observer query against the information boundary system (D-010 principle 2). Engine doesn't distinguish between eyes/thermal/camera - all are "given this sensor, what state is visible?"
- **Raised by:** Team Leader (Jeroen) proposed thermal and camera hacking. Full team developed into perception mode framework.
### D-018: Three-range sound model
- **Date:** 2026-02-09
- **Decision:** Sound information reaches the player through three ranges with decreasing accuracy and trust:
| Range | Method | Info quality | Trust level |
|-------|--------|-------------|-------------|
| Close (near/in LOS) | Stereo audio (maps to facing direction with camera rotation) | High accuracy, identity possible | Raw sensory, reliable |
| Medium (outside LOS, nearby) | Visual indicators at fog edge + internal monologue | Directional, imprecise, type classification | Sensory impression, reliable but vague |
| Long (across map) | Insert notifications, text alerts | Specific but delayed, location data | Network-dependent, spoofable, manipulable |
- **Key insight:** Each range is a different information QUALITY, not just distance. Close = trustworthy. Long = potentially compromised. The Starflyer's agents would absolutely spoof long-range feeds.
- **v0.1:** Screen-space stereo for close + visual fog-edge indicators for medium. Long-range insert alerts as stretch goal.
- **Raised by:** Full team discussion.
### D-014: v0.1 map specification
- **Date:** 2026-02-09
- **Decision:** First playable tech demo map spec:
| Layer | Spec |
|-------|------|
| World map | 3 worlds (Hub/Capital/Fringe), node graph with wormhole connections |
| Local maps | 1 per world, ~150x150 tiles, 2-3 z-levels, chunk-based |
| Key locations | 5-8 hand-crafted buildings/rooms per world embedded in procedural space |
| Ambient fill | Procedural from templates (district types vary per world) |
| Wormhole gates | Physical locations on local map, observable/traversable, social chokepoints |
| Fog | LOS-based shadowcasting with vision cone (forward/peripheral/blind), fog returns on departure |
| Sound | Stereo close-range + visual fog-edge indicators for medium range |
| Navigation | Diegetic insert minimap - dots when close, border arrows for known distant POIs |
| Camera | Locked to character, no panning, no rotation in v0.1 |
| Monologue | Internal character voice for non-visual perception, atmosphere, diegetic hints |
| NPCs | ~15 total across all worlds, on schedules, moving between locations |
| Art | Functional boxes with labels. Atmosphere carried by monologue and interaction models. |
- **Raised by:** Full team across Rounds 8-10.
### D-020: Engine and architecture selection — Godot client + Rust simulation via subprocess/IPC
- **Date:** 2026-02-09
- **Decision:** The game uses a split architecture: **Godot 4** (GDScript) as the rendering client, **Rust** with **bevy_ecs standalone** as the simulation server. The two communicate via **subprocess/IPC** (local socket for single-player, TCP for multiplayer). **NOT via GDExtension.**
- **Architecture:**
- The Rust simulation is a standalone binary with zero Godot dependencies. It runs the ECS world, perception queries, AI, storyteller, combat — all game logic.
- The Godot client is a pure renderer: receives `ObserverSnapshot` data, draws tiles/sprites/fog, plays audio, shows UI, captures input. No game logic in GDScript.
- Single-player: Godot launches the Rust binary as a child process. Local Unix socket or localhost TCP.
- Multiplayer: Godot connects to a remote Rust server. Same protocol. The simulation binary doesn't know the difference.
- This IS the D-010 client-server architecture — literally, not simulated.
- **Serialization:**
- **MessagePack** for all client-facing communication (Rust↔Godot). Dynamic structure supports variable HUD composition driven by perception modes (D-017). Cross-language, debuggable.
- **bincode** reserved for future Rust↔Rust server-to-server sync (same binary, hot path, zero overhead).
- Eliminates entire risk categories: gdext pre-1.0 API churn, Godot version ABI breakage, FFI thread safety (`Gd<T>` is `!Send`), cross-boundary memory management.
- Decouples learning: build and test Rust simulation standalone, build Godot renderer standalone, connect when both work.
- Maps directly to D-010 client-server with no simulation — it IS client-server from day one.
- Either side can be upgraded, replaced, or scaled independently.
- Cost: ~1-5ms serialization latency per tick. Acceptable for a detective/strategy game, not a twitch shooter.
- **Key patterns:**
-`ObserverSnapshot`: the only data structure crossing the boundary. Contains visible entities, fog state, sound events, monologue triggers, HUD widget data. Variable shape per character build.
-`PlayerInput`: semantic actions (MoveNorth, Interact, UsePerceptionMode), not raw key events. Timestamped for deterministic processing.
-`SimBridge` trait: abstracts transport. `LocalBridge` (subprocess, channels) and `NetworkBridge` (TCP, MessagePack) implement the same interface.
- **Kill switch:** If no working prototype (character + fog + one NPC) exists by week 8 of development, pivot to pure Godot. If bridge/sync code exceeds game logic for 3 consecutive sprints, the architecture tax is too high.
- **Development sequence:**
1. Build Rust simulation as standalone binary (testable via terminal/logs)
2. Build Godot renderer as standalone project (hardcoded test data)
3. Connect via MessagePack protocol
- **Project structure:**
```
simulation/ # Pure Rust, bevy_ecs, zero Godot deps
- **Raised by:** Team Leader (Jeroen) proposed Godot client + Rust backend. Tyre designed architecture. Troblum's risk assessment shifted integration from GDExtension to subprocess/IPC. Full team endorsed.
- **Dissent:** None. Troblum's CRITICAL risk flags on GDExtension were accepted; subprocess approach addresses them.
### D-004: Team composition confirmed
- **Date:** 2026-02-08
- **Decision:** Team of 8 agents + Team Leader.
| Agent | Role |
|-------|------|
| MIRI | Lore Expert & Canon Guardian |
| OZZIE | Player Experience / "Wow Factor" Advocate |
- **Status:** Partially resolved for v0.1 (D-014: boxes with labels, atmosphere via dialog/interaction)
- **Remaining:** Long-term art direction beyond tech demo.
- **Assigned to:** TBD
### Q-004: One campaign spanning all eras or separate era scenarios?
- **Status:** Not yet discussed
- **Context:** Gore raised that Commonwealth Era and Void Era play very differently. Prototype focuses on pre-Starflyer War era.
- **Assigned to:** Gore, Miri to lead discussion
### Q-005: Scale for prototype - locations, characters, factions
- **Status:** Partially scoped
- **Early signal:** Institute/Armstrong City hub, ~10-20 characters, Guardians + institutional + political factions
- **Assigned to:** Gestalt, Tyre, Miri
### Q-006: Multiplayer or single-player only?
- **Status:** Resolved → D-009
### Q-007: Target platform(s)
- **Status:** Not yet discussed
- **Context:** Team Leader has Linux background (Fedora). Cross-platform considerations?
- **Assigned to:** Tyre
### Q-008: Licensing / distribution model
- **Status:** Not yet discussed
- **Question:** Open source? Free? Commercial? This affects engine choice and asset decisions.
- **Assigned to:** Team Leader
### Q-009: Time system
- **Status:** Not yet discussed
- **Question:** How does time flow? Real-time with pause? Turn-based (days/weeks/months)? How do we handle deep time / decades passing?
- **Assigned to:** Gestalt, Gore
### Q-010: Storyteller AI design
- **Status:** Not yet discussed
- **Question:** How does the Rimworld-style storyteller work? What are the pacing rules? How much structural randomness vs dramatic randomness?
- **Assigned to:** Gestalt, Nigel
### Q-011: Character selection and playable characters
- **Status:** Not yet discussed
- **Question:** Which characters are playable in the prototype? How different are their starting positions? Can you play canon characters or only original ones?
- **Assigned to:** Miri, Paula
---
## REJECTED ALTERNATIVES
### R-001: Stellaris mod
- **Rejected:** 2026-02-08
- **Reason:** Character system too shallow, multi-empire assumption conflicts with Commonwealth's single-civilization focus, wormhole-as-infrastructure not achievable within Stellaris modding. Team Leader's experience with Star Trek: New Horizons confirmed that even well-suited IPs struggle with character connection in Stellaris.
### R-002: CK3 total conversion
- **Rejected:** 2026-02-08
- **Reason:** Would require building a space map from scratch within CK3's framework - essentially building a game inside a game. The map system fundamentally doesn't support the complexity needed.
### R-003: Other existing games (Distant Worlds 2, GalCiv IV, Sins of a Solar Empire II, Victoria 3)
- **Rejected:** 2026-02-08
- **Reason:** Each captures at most 40% of what's needed. Smaller modding communities, less mature tools, and none solve the core CK3+Stellaris hybrid requirement.
### R-004: Pure Bevy (Rust) — no Godot
- **Rejected:** 2026-02-09
- **Reason:** No visual editor (level design is code-only). UI framework in flux. API breaks significantly between versions. For a solo developer who needs visual tools for hand-crafted buildings (D-014), Godot's editor is a massive productivity advantage. Bevy's ECS is used — just not its renderer.
### R-005: Pure Godot (GDScript or C#)
- **Rejected:** 2026-02-09
- **Reason:** Scene tree paradigm fights ECS-style simulation. Perception queries (D-017) and information boundaries (D-010) map naturally to ECS component queries, not scene tree traversal. Multi-core scaling for expanded content impossible in GDScript. Kept as kill-switch fallback if Rust architecture exceeds time budget.
### R-006: Godot + Rust via GDExtension
- **Rejected:** 2026-02-09
- **Reason:** gdext is pre-1.0 with breaking API changes. Godot version upgrades break GDExtension ABI. Thread safety at FFI boundary is CRITICAL risk (`Gd<T>` is `!Send`/`!Sync`). Couples Rust and Godot learning curves. Subprocess/IPC achieves the same architecture without the FFI risk surface, and maps directly to D-010 client-server. See `docs/architecture/risk-godot-rust-bridge.md` for full analysis.
### R-007: Godot + C++ via GDExtension
- **Rejected:** 2026-02-09
- **Reason:** More mature bindings than gdext, but trades Rust's safety guarantees for C++ memory unsafety. No advantage over subprocess/IPC approach. Developer not experienced in C++.
### R-008: Fyrox (pure Rust engine)
- **Rejected:** 2026-02-09
- **Reason:** Single maintainer. ~1/50th of Godot's community. Less documentation, fewer tutorials, weaker AI training data for Claude Code. Single-maintainer risk unacceptable for multi-year project.
- **Reason:** Maximum control but you build everything — tilemap rendering, camera, UI, audio, input, asset pipeline. Months before testing a mechanic. The game's hard problems are simulation, not rendering — don't reinvent the rendering wheel.
### R-010: protobuf for client-server serialization
- **Rejected:** 2026-02-09
- **Reason:** Schema evolution across independent deployments is a problem we don't have (one developer, client and server ship together). Poor GDScript support. Rigid schema fights dynamic HUD composition driven by perception modes (D-017). MessagePack's schema-optional nature fits better.
---
*Document maintained by QATUX. Last updated: 2026-02-09*
*Restructured 2026-02-11. Original monolithic format in git history.*
@db/connectors/sqlite-query "SELECT d.domain, COUNT(DISTINCT d.id) as decisions, COUNT(DISTINCT t.decision_ref) as with_tickets FROM decisions d LEFT JOIN tickets t ON d.id = t.decision_ref WHERE d.status='active' AND d.type='confirmed' GROUP BY d.domain"
decisions-active:
@db/connectors/sqlite-query "SELECT id, domain, title FROM decisions WHERE status='active' AND type='confirmed' ORDER BY domain, id"
decisions-orphan:
@db/connectors/sqlite-query "SELECT id, title FROM decisions WHERE type='confirmed' AND status='active' AND id NOT IN (SELECT DISTINCT decision_ref FROM tickets WHERE decision_ref IS NOT NULL)"
# --- Content Validation ---
validate-content:
@tooling/validate-content
check-fact-ids:
@tooling/check-fact-ids
checklist-validate:
@tooling/validate-checklist --check
checklist-generate:
@tooling/validate-checklist
perf-baseline:
@tooling/perf-baseline
# --- Schedule debug (#346) ---
debug-schedule:
@echo "Dumping bevy_ecs schedule graph..."
@cd server && cargo run -- --dump-schedule
content-ron:
cd tooling/content-converter && cargo build --release
**A top-down immersive sim where you only know what you can see, hear, and prove.**
---
## You're not the hero. You're a witness with a gun.
Pick a character. Step into their life. Figure out what's happening before it's too late.
The Settled Reach is a single-character detective game where information is the real weapon. You play from one perspective in a simulated world full of people who lie, withhold, and reveal on their own schedules. What you know depends on where you are, who you trust, and whether you're asking the right questions.
---
## What You Do
**Investigate.** Follow leads through a city you can't see all at once. Line-of-sight isn't a gameplay abstraction - it's the core mechanic. You see what your character sees. Walls block vision. Corners hide threats. Fog returns when you leave. Information decays.
**Navigate.** Your neural lattice gives you directions, but only to places you've learned about. Contacts send locations. Research reveals addresses. Physical exploration fills the gaps. The map is sparse and frightening at first. By the end, you realize how much you missed.
**Decide.** Every conversation is a negotiation over what gets shared. NPCs have their own goals, their own information, and their own reasons to lie. You choose who to trust based on incomplete data. Sometimes you're wrong.
**Act.** When investigation fails, violence is an option. Fights are tactical, asymmetric, and often a terrible idea. Power mismatches run in both directions. Death costs you everything since your last backup - lost knowledge, lost relationships, lost deals. The world knows what you forgot.
**Survive.** An AI storyteller paces events for dramatic tension. The conspiracy's structure is set at game start. When things happen is driven by how you're doing. Comfortable? Something breaks. Desperate? A break appears. The game wants a story, not a grind.
---
## Core Features
### Information Asymmetry as Master Mechanic
You only know what your character knows. The same world looks completely different from different perspectives. A Senator sees political venues on their map. A Guardian sees safehouses. Same conspiracy, different game.
### Occlusion-Based Detection
Vision is line-of-sight with a directional cone. You see what's in front of you. Peripheral vision is reduced. Behind you is fog. Sound gives partial information outside your view - footsteps, voices, gunfire. You make decisions based on what you can piece together.
### Internal Monologue
Your character interprets what they sense in their own voice. Footsteps behind you. Thermal signatures through walls. A contact's nervous tells. The monologue bridges what the camera can't show and creates atmosphere. It can also be wrong.
### Perception Modes
Different characters access different sensors. Natural vision shows detail but is blocked by walls. Thermal imaging shows heat signatures with no identity. Camera feeds give remote vision but can be spoofed. Unisphere tracking pings known contacts but can be masked. Each mode reveals different information with different trust tradeoffs.
### Diegetic Interface
The map is your character's neural lattice - Commonwealth technology, not a game UI. Points of interest appear when you learn them through gameplay. Tips can be traps. Navigation is pulled by player intent, not pushed by map design.
### Multiple Playable Characters
Every character starts in a different position with different knowledge and different tools. A cop has case files and legal authority. An investigator has contacts and freedom to operate. A politician has institutional access and public constraints. Replayability comes from perspective, not randomness.
### Rimworld-Style Storyteller
Events emerge from simulation, paced by an AI director. No timers. No scripts. Consequences of what's already in motion. The storyteller knows what you've lost and can exploit it.
### Wildly Asymmetric Combat
Balanced fights are the exception. You're outgunned or overpowered, rarely evenly matched. Tactical clarity from the top-down view. Z-levels create verticality - fights across floors of a building. Perception boundaries mean you can be ambushed. Victory often means not fighting at all.
---
## The Setting
Humanity spread across hundreds of star systems by learning to activate alien gates it didn't build. The result is the Settled Reach - a civilization stitched together by infrastructure it doesn't fully understand.
You live in a society where death is temporary (if you can afford the backup), enhancement is political (who gets augmented and why), and the gates that connect everything were made by someone who hasn't introduced themselves.
Wormholes aren't fast travel markers. They're physical locations you traverse. Social chokepoints. Surveillance points. The infrastructure you depend on to move between worlds.
Something is breaking. Or something is waking up. You're in the wrong place at the right time to figure out which.
---
## Built For Replayability
Structural randomness set at game start: who's compromised, where evidence is hidden, which contacts can be trusted. Play the same scenario as different characters and encounter a different game. The conspiracy's skeleton is fixed. The flesh changes every time.
---
## Development Philosophy
Single-character perspective. Asymmetric information as core mechanic. Top-down camera locked to character position. Godot 4 client + Rust simulation server. Client-server architecture from day one, designed for multiplayer even though single-player ships first.
No fog-of-war as an afterthought. No tutorial popups. No omniscient map reveals. The game is built around what you don't know.
---
## [LOREM IPSUM PLACEHOLDER]
### Screenshots
*[Gameplay screenshot: character navigating fog-of-war through urban environment]*
*[Gameplay screenshot: thermal vision showing heat signatures through building]*
*[Gameplay screenshot: conversation interface with internal monologue overlay]*
*[Gameplay screenshot: tactical combat with vision cone and z-level interaction]*
### Media
*[Trailer: Character selection → Investigation → Revelation → Crisis]*
*[Dev diary: Information asymmetry as game mechanic]*
printerr("GdUnit4: 'inferred_declaration' is set to Warning/Error!")
ifEngine.get_version_info().hex>=0x40600:
printerr("GdUnit4 is not 'inferred_declaration' save, you have to excluded the addon (debug/gdscript/warnings/directory_rules)")
else:
printerr("GdUnit4 is not 'inferred_declaration' save, you have to excluded addons (debug/gdscript/warnings/exclude_addons)")
printerr("Loading GdUnit4 Plugin failed.")
return
ifcheck_running_in_test_env():
@warning_ignore("return_value_discarded")
GdUnitCSIMessageWriter.new().prints_warning("It was recognized that GdUnit4 is running in a test environment, therefore the GdUnit4 plugin will not be executed!")
return
ifEngine.get_version_info().hex<0x40500:
prints("This GdUnit4 plugin version '%s' requires Godot version '4.5' or higher to run."%GdUnit4Version.current())
## @deprecated: the modifier [b]shift_pressed[/b] and [b]ctrl_pressed[/b] will be removed in v7.0[br]See `test_key_shift_and_A_presssing` for example using key combinations
## [member key_code] : the key code e.g. [constant KEY_ENTER][br]
## [codeblock]
## # Do simulate key pressing A
## func test_key_A_presssing():
## var runner = scene_runner("res://scenes/simple_scene.tscn")
## await runner.simulate_key_press(KEY_A)
##
##
## # Do simulate keycombination pressing shift+A
## func test_key_shift_and_A_presssing():
## var runner = scene_runner("res://scenes/simple_scene.tscn")
## [member key_code] : the key code e.g. [constant KEY_ENTER][br]
## [codeblock]
## # Do simulate releasing key A
## func test_key_A_releasing():
## var runner = scene_runner("res://scenes/simple_scene.tscn")
## await runner.simulate_key_release(KEY_A)
##
##
## # Do simulate keycombination pressing shift+A
## func test_key_shift_and_A_releasing(():
## var runner = scene_runner("res://scenes/simple_scene.tscn")
## runner.simulate_key_release(KEY_SHIFT)
## runner.simulate_key_release(KEY_A)
## await _runner.await_input_processed()
## [/codeblock]
## @deprecated: the modifier [b]shift_pressed[/b] and [b]ctrl_pressed[/b] will be removed in v7.0[br]See `test_key_shift_and_A_releasing` for example using key combinations
## Sets the mouse position to the specified vector, provided in pixels and relative to an origin at the upper left corner of the currently focused Window Manager game window.[br]
## [member position] : The absolute position in pixels as Vector2
## Waits for the specified signal to be emitted by a particular source node. If the signal is not emitted within the given timeout, the operation fails.[br]
## [member source] : the object from which the signal is emitted[br]
## [member signal_name] : The name of the signal to wait for[br]
## [member args] : The signal arguments as an array[br]
## [member timeout] : tThe maximum duration (in milliseconds) to wait for the signal to be emitted before failing
## This is the base interface for value extraction
class_nameGdUnitValueExtractor
extendsRefCounted
## Extracts a value by given implementation
funcextract_value(value:Variant)->Variant:
push_error("Uninplemented func 'extract_value'")
returnvalue
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.