Remove the peripheral sector (100° half-angle, reduced range) and blind
spot classification. The server now sends only tiles within the 120°
forward cone; the client renders previously-explored tiles behind the
player with a light fog overlay instead.
This eliminates complexity in both the cone classifier and the snapshot
protocol while preserving the core information asymmetry — you still
can't see behind you, and the monologue system (D-016) still bridges
the perceptual gap.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. CRITICAL: spawn_template_npcs now inserts NpcVisionState, NpcMemory,
PlayerAwareness on template-spawned NPCs — matches spawn_npc() pattern
from PR #66. Without these, template NPCs were invisible to vision and
awareness systems.
2. WARNING: generate_intra_template_triangles now calls validate_triangle_def
before generating TriangleState — mirrors cross-template path. Updates
test TriangleDefs and logistics-hub.yaml to pass all three quality checks
(conflict viability, relationship coherence, interest divergence).
3. WARNING: state_hash in compute_observer_snapshot now uses FNV-1a instead
of DefaultHasher — consistent with D-010 principle 4 and the pattern in
TemplateId/TriangleId. Updates golden file for new hash value.
4. WARNING: TriangleCrisisEventWire.role_assignments now filtered against
observer KnowledgeGraph — unknown NPCs redacted from wire event per
D-010 principle 2 (information boundaries).
5. WARNING: ActiveTemplateInstances::insert now despawns previous instance
entities before overwriting — prevents orphaned ECS entities.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add FullTemplateDef integration tests: round-trip YAML serialization,
space spec validation, routine schedule, sightline zones, dialogue pool
refs, cross-template link specs, and logistics-hub template fixture.
Tests cover the full social site template document structure per D-023,
D-024, D-025, D-028.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Protocol v17: add state_hash (desync detection) and sim_errors
(structured error reporting) to ObserverSnapshot. Add SimError,
SimErrorKind, SimErrorBuffer types. Wrap main loop app.update() in
catch_unwind — on panic, send a final SimError snapshot before exit.
Report recoverable deserialization errors to client via SimErrorBuffer.
Compute per-tick state hash from player position + NPC count + tick.
Update all test fixtures and golden files for protocol v17.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Follow-up to b6a9b78: register TerminalInteractedQueue resource and
door/terminal interaction systems in SimulationPlugin; add door state
save/load in save_io (open doors round-trip through SaveStateV1);
make WalkabilityMap param optional in process_door_interaction so
plugin-only tests work without a loaded map; fix information_boundaries
test missing open_doors field.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add DoorState component tracking is_open and blocking_tile; add
DoorInteractRequest per-player component consumed by new
process_door_interaction system (toggles walkability each use)
- Add TerminalInteracted event, TerminalInteractedQueue resource,
TerminalInteractRequest component, and process_terminal_interaction
system (emits event on Use verb)
- Add ExamineText(String) component for authored object examine text;
extend process_examine_interaction with object examine path:
uses ExamineText if present, falls back to generic string if absent
- Fix: add Without<ObjectType> filter to npc_query in
process_examine_interaction — previously any entity with TilePosition
was mis-routed through the NPC text generator
- Add SaveStateV1.open_doors: Vec<StableId> with #[serde(default)]
for backward-compatible serialization
- Add "Open"/"Close" → DoorInteractRequest and "Use" →
TerminalInteractRequest dispatch in process_player_input
- 10 integration tests in tests/environmental_interaction.rs covering
all acceptance criteria: door toggle (both directions), open-to-close,
invalid target, readable examine (with/without ExamineText), out-of-range,
terminal event emission, request cleanup, and save state round-trip
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add ValidationError enum with three failure modes: ConflictViability
(missing Want axis), RelationshipCoherence (empty constraints),
InterestDivergence (duplicate interest axes)
- Add validate_triangle_def() pure function enforcing all three checks
in priority order (per D-087)
- Add generate_cross_template_triangles() function that combines NPC
pools from two templates, validates each TriangleDef before processing,
and assigns ownership to template_a
- 10 integration tests in tests/triangle_validation.rs covering all
validation failure modes, ordering guarantees, cross-template span,
invalid def skipping, determinism, and intra-template isolation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Triangle phase and tension were silently lost on save/load. Now
serialized as triangle_states vec in SaveStateV1, sorted by
triangle_id for determinism (D-010). Dedicated triangle entities
are respawned on load.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Updates all client-side msgpack test fixtures and server test
harnesses to include the new triangle_crisis_events field added
in protocol v16.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements #163 (RoleSchema), #164 (SpaceSpec), #165 (TemplateOwnership
+ TemplateReferenceMap), #106 (TriangleDef), #107 (intra-template
triangle generation), and #250 (triangle escalation system) as the
foundational Tier 2 template system per D-025.
New content/template module with YAML-deserializable schema types,
ECS components for ownership/triangle state, escalation system
running on game-minute boundaries, and TriangleCrisisEvent emission.
Sample YAML templates at server/data/templates/.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- gen_fixtures.rs: version comments now say PROTOCOL_VERSION instead
of hardcoded 14, so they stay correct across bumps
- run-ipc-benchmark: remove --iterations flag that was parsed but
never forwarded to the Rust test (compile-time constant governs)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
#556: HANDSHAKING state in sim_bridge.gd — decodes first framed message
as HandshakeMessage, validates vs Protocol.PROTOCOL_VERSION, 5s timeout,
handshake_complete/handshake_failed signals.
#342: IPC benchmark now reads and validates HandshakeMessage before
starting the timing loop.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Removed duplicate examine_result from ObserverSnapshot (old ExamineResultEvent
superseded by ExamineResultWire). Fixed serde_default test version assertion.
Regenerated golden file and all fixture .msgpack files. 1070 Rust tests passing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Five new .msgpack fixtures: snapshot_minimal, snapshot_full,
player_input_move, player_input_interact, malformed. Rust generator in
gen_fixtures.rs, 7 Rust validation tests in serialization.rs, GDScript
cross-language test in test_ipc_fixtures.gd (22 assertions).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Protocol handshake (#555): HandshakeMessage as first IPC frame,
HandshakeState resource, forward-compatible input handling.
State serialization (#96): serialize_npc_to_frozen/deserialize with
full D-024 axis coverage (10 new optional fields on NpcSaveState).
Scope tags (#98): ScopeTagKind enum, ScopePinned marker, automatic
assignment from KnowledgeGraph and RelationshipGraph.
Timestamp eviction (#97): LastInteractionTick, SimSpacePressure,
BinaryHeap LRU eviction respecting ScopePinned entities.
Save/load (#553): save_to_file/load_from_file via MessagePack,
SaveGame/LoadGame IPC commands, SaveLoadResultWire on snapshot.
Test infrastructure (#200): Layer 3 integration test entry point,
three-layer architecture documented per D-030.
Information boundary tests (#272): 4 negative tests proving no
passive KG leakage, LOS fog holds, tier boundary holds, save
isolation per NPC.
1063 tests passing, 0 failures.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Regenerated MsgPack fixtures for protocol v14 (examine_result and
character_pressure fields). Updated golden test, serialization
assertions, and cross-language fixture generator.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add three new ObserverSnapshot fields for client Sprint 18 tickets:
poi_list (Vec<PoiWire>) for minimap #151, examine_result
(Option<ExamineResultWire>) for #174, player_knowledge
(Option<PlayerKnowledgeWire>) for journal #264. POI list populated
live from KG-discovered PointOfInterest components. KG dump
serializes entity/fact knowledge with confidence, source, and state.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Version field round-trip, mismatch detection, serde_default migration
pattern, all TellCategory and VerbKind variant coverage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tyre #1: Extract run_dialogue_pipeline() shared helper — eliminates ~60
lines of duplication between process_talk_interaction and
process_dialogue_response (L1-L4 pipeline).
Hoshe #1: process_dialogue_response now updates ActiveDialogue with
current tick on follow-up selection — prevents stale started_tick.
Tyre #4: process_dialogue_response now updates InteractionMemory on
follow-up — multi-turn conversations are visible in history.
Hoshe #6 / Tyre #6: handle_dialogue_response adds server-side range
check (CLOSE_RANGE), matching Talk/Confront pattern (D-010 info
boundary).
Hoshe #2: Weighted selection fallback replaced with unreachable!() —
score_line always returns >= 1, so the fallback was dead code.
Hoshe #3: assert!(false, ...) → panic!() in serialization.rs (clippy).
Hoshe #4: SetFacing and TeleportToHub added to roundtrip test.
Hoshe #5: setup_dialogue_response_world inlined (trivial pass-through).
Tyre #2: Doc comment on DialogueCooldownTracker explains per-player-global
design choice (line IDs are NPC-scoped per D-035, no collision risk).
Tyre #3: CONFRONTATION_LINES comment updated with TODO for D-028/D-035
migration.
Tyre #5: DialogueResponse fixture added for cross-language GDScript
testing (input_dialogue_response.msgpack).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move dialogue system registrations from BridgePlugin to NpcPlugin (#538):
game logic that depends on NPC-layer resources now registers where it
belongs. BridgePlugin retains only wire protocol concerns.
Implement DialogueResponse verb handler (#539): new process_dialogue_response
system runs the full D-028 four-layer pipeline to select follow-up lines
when the player picks a dialogue option. Clears ActiveDialogue when no
candidates remain. Fix latent schedule ambiguity — emit_observation_events
now has explicit .before(advance_tick) constraint.
Verify trust-gated gossip pipeline (#171): confirmed process_talk_interaction
correctly passes KnowledgeConfidence through relationship_to_trust() per
D-075. Added integration tests for Secret-tier access (Friendly+KnowsDetails)
and Surface-only fallback (Friendly+Suspects).
Wire DialogueCooldownTracker into selection (#338): added regression test
confirming no line_id repeats within the 600-tick cooldown window across
10 consecutive Talk interactions.
Closes#538, #539, #171, #338
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Regenerate all msgpack test fixtures with tell_state and follow_state
fields. Update golden proof_room snapshot. Adjust serialization and
bridge tests for new ObserverSnapshot fields.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server-side infrastructure for information asymmetry in dialogue.
NPCs display role labels (Worker, Supervisor, Patron) instead of
real names until the player explicitly learns them via KG lookup.
NpcColorIndex (stable_id % 8) persists across name reveal.
ConversationEvent and DialogueResponseEvent carry display names +
color indices on the wire with serde(default) for compat.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Keep all new variants from both branches: Greeting (copy), FirstMeeting
and RepeatedVisit (server). Combine Mood doc comments.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three NPC profiles added by copy team content expansion. Updates
content_loading test expectations to match actual content directory.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements server-authoritative per-word occlusion for NPC conversations.
ConversationEventBuffer drains into ObserverSnapshot each tick so the client
receives only words audible from the player's position. Updates test fixtures
to include the new conversation_events and conversation_ended fields.
Co-Authored-By: Claude Sonnet 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>
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>
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>
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>
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>
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>
- 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>
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>