--- title: "Sprint 15 — Server Briefing" description: "Monologue event generation, NPC generation pipeline, follow mechanic" type: sprint status: archived sprint: 15 team: "server" --- # Sprint 15: React — Server Tasks **Goal:** The player acts and the world reacts — follow and examine mechanics connect the player to the living NPC simulation; the dialogue system's first two access layers open up information gating; server-side monologue events fire in context; and the personality/tell system completes the NPC data model. **Branch:** `server` **Agents:** Dudley (simulation dev), Tyre (architect), Hoshe (QA) ## New Tickets | # | Title | Blocked by | |---|-------|------------| | #119 | Monologue event generation — server | #239 (done) | | #92 | NPC generation pipeline | #86 (done) | | #90 | Personality & tell system | #89 (cancelled — blocker resolved) | | #241 | Follow mechanic | #240 (done) | | #243 | Routine deviation detection | #88 (done) | | #105 | Tolerance threshold triggers | — | | #340 | Define SpatialIndex trait with naive Vec implementation | — | Use `db/connectors/ticket show ` for full details. ## Key Decisions - `decisions/perception.md` — D-011 (fog of perception universal to all entities), D-016 (internal monologue as perception bridge), D-060 (cognitive delay), D-067 (recognition chime onset) - `decisions/content.md` — D-024 (10-axis NPC generation model + tell system), D-028 (dialogue 4-layer architecture), D-035 (converged tag taxonomy, 9 mood states), D-075 (dialogue filtering: confidence gates trust tier, not access tier) - `decisions/architecture.md` — D-010 (information boundaries first-class), D-026 (simulation tiers), D-041 (knowledge graph: KnowsOf / KnowsDetails confidence levels) ## Notes - **#119 Monologue event generation — server:** `server/src/simulation/monologue.rs` already handles `enter_location` and `time_idle` triggers. This ticket extends the system to fire on `observe_npc`, `hear_sound`, `observe_anomaly`, `witness_interaction`, and `post_conversation` triggers — all enumerated in D-035 tag taxonomy. The `ObservationEvent` struct from `server/src/simulation/interaction.rs` (completed in #239) is the input source. Each trigger must emit a `MonologueEvent` into `MonologueBuffer` with context tags (`location`, `situation`, `character_state`) so the content pool selector can match against D-035 structural tags. Respect the `COOLDOWN_TICKS = 300` anti-spam guard already in the file. The `witness_interaction` trigger (D-078) fires after overheard NPC-to-NPC conversation is displayed — coordinate with the passive dialogue system in `server/src/simulation/conversation.rs` and `server/src/simulation/listening.rs`. - **#92 NPC generation pipeline:** Core NPC ECS components (Want, Secret, Relationships, Tolerance, Routine, Contentment) are done in `server/src/npc/mod.rs` (#86). This ticket wires procedural generation: takes a role definition as input, seeds all 10 axes using the sim RNG (`server/src/simulation/rng.rs`), applies constraint validation, and spawns a fully-populated NPC entity. Use the `SimRng` resource for all randomness — determinism is non-negotiable (D-010 principle 4). Constraint validation must catch: relationship graph cycles, tolerance values that would immediately trigger, routines that conflict spatially. Output: a function `generate_npc(role: &RoleDefinition, world: &mut World, rng: &mut SimRng)` or equivalent ECS command. Personality traits (2-3 per NPC) must be populated — they feed #90. - **#90 Personality & tell system:** The blocker (#89, Information inventory) was cancelled; the knowledge graph (D-041, completed in Sprint 12) supersedes it. `PersonalityTraits` component holds 2-3 traits drawn from a trait set. `TellSystem` covers 5 categories: `nervous`, `angry`, `friendly`, `guarded`, `routine_deviation`. Tell state is derived each tick from NPC axis values — not authored per NPC. Derivation rules: `Secret + low Tolerance → nervous`, `low Contentment + Hostile mood → angry`, `high Contentment + Friendly relationship → friendly`, `high Secret weight → guarded`, deviation from routine → `routine_deviation`. `NpcMood` is already available from `server/src/npc/mood.rs` (#323). The `mood.rs` header comment explicitly flags `Tell system (#337, deferred to Sprint 15) → reads MoodState`. The v0.1 renderer for tells is **monologue text**, not visual animation — emit tell state into `ObserverSnapshot` as a field on the entity's tell status; the client reads it for future use. `server/src/npc/` is the correct home for new components. - **#241 Follow mechanic:** Player uses Interact verb on an NPC to designate a follow target. The interaction dispatcher in `server/src/simulation/interaction.rs` (#240, done) must be extended with a `Follow` verb. Server tracks: target NPC entity ID, current distance (tile-based), LOS state (from the existing shadowcasting system in `server/src/perception/`). Observation events (`observe_npc` trigger) fire at double frequency while following. NPC suspicion increases via `ToleranceThreshold` stress if the player maintains close proximity + LOS for sustained ticks. Define "too close too long" as a configurable threshold (start: within 2 tiles for 60+ ticks). Follow ends when: target enters deep fog (LOS lost for N ticks), target detects player (suspicion threshold crossed, feeds `NpcPlayerAwareness`), or player issues a different action. Emit follow-state events into `ObserverSnapshot` so the client can show follow-mode UI state. - **#243 Routine deviation detection:** `server/src/npc/routine.rs` tracks `ActivityState` (set when NPC arrives at routine destination) and `DailyRoutine` (schedule of phase → location). Compare the NPC's current `TilePosition` and `ActivityState` against what `DailyRoutine` specifies for the current `DayPhase`. Emit `RoutineDeviationEvent` when: NPC is in wrong location for phase, NPC is absent from expected location (has been out of expected zone for N ticks), NPC is performing wrong activity. Absence detection covers the case where the player expects an NPC at a known location and they are not there. `RoutineDeviationEvent` feeds the observation event generator (#239, done), which will route it to `observe_anomaly` monologue triggers (#119, this sprint). This is the primary detective mechanic per D-027 criterion 4. - **#105 Tolerance threshold triggers:** `ToleranceThreshold` component exists (part of NPC data model). This ticket adds the monitoring system: each tick, check all Active-tier NPCs' tolerance against accumulated stress. When stress exceeds threshold, emit a `ToleranceBreachEvent` and apply behavioral state changes (mood shift, potential confrontation-initiation, avoidance behavior). Threshold value varies per NPC seed — do not hardcode. This unblocks #250 (Triangle escalation system) in a later sprint, which needs tolerance breach events as input. Integrate with `server/src/npc/mood.rs` — a tolerance breach should push mood toward `Hostile` or `Anxious` per the FSM. - **#340 SpatialIndex trait:** XS effort task. Define a trait in `server/src/` (suggest `server/src/simulation/spatial.rs`) with three methods: `entities_in_range(position, radius)`, `entities_at(position)`, `update(entity_id, position)`. Implement a naive `Vec`-backed backend (`NaiveSpatialIndex`). This is called from the follow mechanic (#241) for proximity queries and from the NPC vision system (#115, deferred). The trait abstraction means a grid/quadtree can replace the naive impl later without touching callers. Register as a Bevy resource. ## Dependency Chain ``` #340 (SpatialIndex) ─────────────────────────────────┐ ↓ #92 (NPC generation pipeline) → #90 (Personality & tell) → future: #337 (tell state derivation) #243 (Routine deviation detection) ──────────────────┐ ↓ #119 (Monologue event generation) ← also feeds from #241 (Follow mechanic) ↑ #241 (Follow mechanic) → feeds NPC suspicion → future: #115 (NPC vision) #105 (Tolerance threshold triggers) → future: #250 (Triangle escalation) ``` ## PR Workflow When ready to submit, create a PR with the `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): sprint 15 react — server deliverables" --description "body" --base main --head server ```