Files
settled-reach/docs/sprints/sprint-18/server.md
T
jpmschweitzerandClaude Opus 4.6 bccdcfcdcb docs(docs): add frontmatter to all sprint briefings
Standardized YAML frontmatter on all 115 sprint briefing files across
sprints 1-26 with title, description, type, status, sprint number, and
team fields.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 00:15:45 +01:00

185 lines
12 KiB
Markdown

---
title: "Sprint 18 — Server Briefing"
description: "Examine mechanic, NPC player-awareness, character goal framework, social propagation"
type: sprint
status: archived
sprint: 18
team: "server"
---
# Sprint 18: Touch — Server Tasks
**Goal:** The player can examine entities and objects to generate character-filtered observations; NPCs detect and react when watched; social actions propagate through the relationship graph; minimap renders POIs on the client.
**Branch:** `server`
**Agents:** Dudley (simulation), Tyre (architecture), Hoshe (QA)
## Carry-over from Sprint 17
None. Sprint 17 closed 19/19.
## New Tickets
| # | Title | Blocked by |
|---|-------|------------|
| #242 | Examine mechanic | #240 (done) |
| #244 | NPC player-awareness behavior | — |
| #248 | Character goal/pressure framework | — |
| #249 | Player-action social propagation | — |
| #337 | Tell state derivation system | #323 (done) |
| #91 | Skill system & combat flag | — |
| #115 | NPC vision system | — |
| #256 | Save state data model | — |
| #95 | Background tier state machines | — |
Use `db/connectors/ticket show <id>` for full details.
## Key Decisions
- `decisions/architecture.md` — D-010 (information boundaries), D-020 (IPC architecture), D-026 (simulation tiers), D-041 (knowledge graph data model)
- `decisions/perception.md` — D-011 (fog of perception — NPCs use same LOS), D-035 (symmetric shadowcasting)
- `decisions/content.md` — D-024 (NPC 10-axis model, skill set axis, combat component), D-028 (dialogue architecture — examine verb is a dialogue layer entry point)
- `decisions/scope.md` — D-027 (vertical slice criteria — character-specific observation)
## Notes
### #242 — Examine mechanic
The interaction dispatcher (`server/src/simulation/interaction.rs`) already computes `VerbKind::ExamineNpc` and `VerbKind::ExamineObject` in the `NearbyInteractionBuffer`. The examine verb appears at close range (≤2 tiles, `CLOSE_RANGE`). `PlayerAction` dispatch and `process_player_input` are the entry points in `server/src/simulation/input.rs`.
What this ticket must deliver:
- A `process_examine_interaction` system that handles `PlayerAction::Examine { entity_id }` (or equivalent)
- Generates a detailed `ObservationEvent` with low uncertainty for the target entity
- Applies character-specific filtering via the observer's `KnowledgeGraph` (same NPC looks different to smuggler vs detective — smuggler reads cargo-handling posture, detective reads procedural tells)
- Result is written to the observer's `KnowledgeGraph` via `KnowledgeEventQueue` as a `DirectObservation` entry with `KnowledgeConfidence::Direct`
- Emits an examine result field in `ObserverSnapshot` so the client can display character-filtered detail text
Integration points: `server/src/simulation/interaction.rs` (verb dispatch), `server/src/knowledge/graph.rs` (`KnowledgeGraph` write), `server/src/perception/observation.rs` (observation event pattern), `server/src/simulation/dialogue.rs` (examine result mirrors dialogue result pattern).
### #244 — NPC player-awareness behavior
NPCs use the same LOS system as the player (D-011). The awareness system detects when an NPC's LOS query includes the player's `TilePosition`, and generates a behavioral response.
What this ticket must deliver:
- A new `PlayerAwareness` component on Active-tier NPCs tracking: whether the player is in this NPC's LOS, for how many consecutive ticks, and accumulated suspicion level
- A `detect_player_awareness` system running after `compute_observer_snapshot` — iterate Active-tier NPCs, run a simplified LOS check or piggyback on existing shadowcast state
- When awareness crosses threshold: routine deviation behavior (NPC changes path or posture), fed into the `DerivedTellState` pipeline (already exists in `server/src/npc/tell_state.rs`)
- Feeds follow-verb suspicion in `server/src/simulation/follow.rs`
Key file: `server/src/simulation/follow.rs` already has proximity + attention logic for follow suspicion — awareness system reuses this infrastructure. New system lives in `server/src/simulation/` or `server/src/npc/`.
### #248 — Character goal/pressure framework
Defines systemic pressures per character that modulate monologue salience and observation priority. Not scripted arcs — emergent from interaction of existing axes (D-024).
What this ticket must deliver:
- A `CharacterPressure` component on the player character entity: `exposure_pressure: i32` (smuggler), `institutional_pressure: i32` (detective), `relationship_pressure: i32` (both)
- Pressure inputs: exposure rises when NPCs notice the player (feeds from #244), relationship pressure from trust changes in `server/src/npc/relationships.rs`, institutional pressure from detective-specific interaction patterns
- Pressure outputs: written into `ObserverSnapshot` HUD widget data; high pressure raises monologue trigger weight for anxiety-tagged lines
- Coordinate with copy team — monologue lines using `mood: [anxious]` or `mood: [frustrated]` tags (D-035) are the output surface
This is a design-and-implement ticket — start by defining the pressure struct, then wire inputs from existing systems. Monologue salience weighting is the primary v0.1 output.
### #249 — Player-action social propagation
Player actions toward one NPC ripple through the relationship graph at three decay orders (D-029 topology principle). The `RelationshipGraph` resource (`server/src/npc/relationships.rs`) and `TrustEventQueue` are the integration points.
What this ticket must deliver:
- A `propagate_social_actions` system triggered when a `TrustEventQueue` event fires from player action
- First-order: immediate full delta to the directly affected NPC
- Second-order: `delta * 0.4` to NPCs with strong relationships to the first-order NPC (trust > 3 in `RelationshipGraph`)
- Third-order: `delta * 0.15` to NPCs one further hop away, delayed by configurable ticks
- Propagation topology varies per seed (D-029 anti-metagaming) — the same action produces different cascades depending on who knows whom
- Write propagated trust changes back to `TrustEventQueue` or directly to `Relationships` components with a `PropagatedTrust` marker
Gotcha: propagation must not loop (A affects B affects A). Visited-entity set per propagation pass prevents cycles.
### #337 — Tell state derivation system
The `derive_tell_state` system already exists and is fully tested in `server/src/npc/tell_state.rs`. This ticket existed in the backlog because the mood state machine (#323) it depends on was not yet done. #323 is now done.
What this ticket must deliver:
- Verify `derive_tell_state` runs correctly in the current schedule (it is already registered in `server/src/npc/mod.rs` after `mood::update_mood`)
- Wire `DerivedTellState` into the observer snapshot output — confirm `ObserverSnapshot.entities[].tell_state` is populated for visible entities
- Integration test: NPC with Major secret + stress past midpoint shows `TellCategory::Nervous` in snapshot
- This ticket is mostly verification + integration wiring, not new code — the system is complete, the sprint task is closing the loop into the snapshot
### #91 — Skill system & combat flag
What this ticket must deliver:
- A `SkillSet` component: `BTreeMap<String, u8>` of named skills with level values (BTreeMap per D-010 determinism requirement)
- When a `SkillSet` contains `"combat_trained"` with value ≥ 1, the ECS system attaches a `CombatCapability` marker component to that NPC at spawn time
- `SkillSet` added to the NPC generation pipeline in `server/src/npc/generate.rs` (already sets other D-024 axes)
- The `CombatCapability` component is a zero-sized marker for now — future sprints add stats
NPC skill sets are generated from content YAML at startup. The content loader in `server/src/content/` reads NPC definitions — add `skills: {}` as a YAML field on NPC templates.
### #115 — NPC vision system
NPCs must use the same LOS shadowcasting system as the player (D-011 — "Applies to ALL entities"). The shadowcast machinery lives in `server/src/perception/shadowcast.rs`.
What this ticket must deliver:
- NPC vision is computed via `compute_los` (or equivalent call) for Active-tier NPCs each tick
- Results stored in an `NpcVisionState` component: set of `StableId` values currently visible to this NPC, plus the player entity if visible
- NPC memory: `NpcMemory` component tracking last-known-position of the player even after leaving LOS ("saw you enter building → knows you're inside" per D-011)
- Inference stub: if player was seen entering a room, NPC `KnowledgeGraph` records `DirectObservation` of player at that room's zone, degrading to `KnowsOf` after configurable ticks
This feeds #244 (awareness) — the `detect_player_awareness` system reads `NpcVisionState` rather than running its own LOS query.
Performance note: only run LOS for NPCs whose `TilePosition` is within `ACTIVE_RADIUS` (already guaranteed by `ActiveSim` marker). Full shadowcast per NPC per tick is feasible at 30-80 active NPCs — Tyre has confirmed the budget.
### #256 — Save state data model
Define the serialization format for full game state. Shares architecture with #96 (state serialization system, still backlog — this ticket is the data model design, not the save/load implementation).
What this ticket must deliver:
- A `SaveStateV1` struct (versioned from day one) covering: entity state, `KnowledgeGraph` per entity (already serializable via `serde` in `server/src/knowledge/graph.rs`), `RelationshipGraph`, game clock position (`SimulationTime`), seed value
- Write format: MessagePack (consistent with IPC protocol per D-020) or RON for human-readable debugging — decide and document
- The struct must roundtrip cleanly: serialize + deserialize produces identical ECS world state
- Stub tests proving the roundtrip; full save/load flow is #257 (future sprint)
The `KnowledgeGraph` is already `Serialize + Deserialize`. The main design work is enumerating which ECS components must be captured and in what order (deterministic serialization per D-010).
### #95 — Background tier state machines
Background-tier NPCs (marked `BackgroundSim` in `server/src/simulation/tier.rs`) currently receive no simulation — tier markers exist but no background tick systems run. This ticket adds the four D-026 state machines for background NPCs.
What this ticket must deliver:
- A `background_tick` system gated by `With<BackgroundSim>` that fires once per game-minute (every 10 ticks per D-031)
- Four mini state machines per background NPC:
1. **Schedule**: advance NPC to next routine activity based on `DayPhase` (reads `DayPhase` from `server/src/simulation/time.rs`, updates `Routine` component)
2. **Mood**: simple mood drift toward neutral; significant events (stress > threshold) can shift from neutral
3. **Relationships**: trust drift toward baseline over time; no events-driven trust changes for background NPCs
4. **Job**: job performance score drift based on contentment (lower contentment → lower performance)
- Background tick does NOT run pathfinding, LOS, or dialogue — those are Active-tier only
- Background NPCs promoted to Active receive their current state machine state (no reset on promotion)
## Dependency Chain
```
#95 (background tier state machines) → standalone, no blockers
#115 (NPC vision system) → #244 (player-awareness behavior)
#248 (character goal/pressure framework) ← feeds from awareness events
#337 (tell state wiring) → standalone, verify + wire into snapshot
#242 (examine mechanic) → standalone (dispatcher already exists)
#249 (social propagation) → standalone (relationships already exist)
#91 (skill system & combat flag) → standalone
#256 (save state data model) → standalone (design + stub)
```
Parallel tracks: #95, #91, #337, #256, #249, and #242 can all start in week 1. #244 starts after #115 is in review.
## PR Workflow
When ready to submit, create a PR with `tea` CLI. **All flags are required** to avoid TTY prompts (see CLAUDE.md "Gitea access" section):
```bash
tea pr create --repo jpmschweitzer/settled-reach --login schweitz --title "feat(simulation): description" --description "body" --base main --head server
```