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>
178 lines
10 KiB
Markdown
178 lines
10 KiB
Markdown
---
|
|
title: "Sprint 8 — Server Briefing"
|
|
description: "Dialogue selection pipeline, walk-away KG recording, anomaly detection, monologue timing"
|
|
type: sprint
|
|
status: archived
|
|
sprint: 8
|
|
team: "server"
|
|
---
|
|
|
|
# Sprint 8: React — Server Tasks
|
|
|
|
**Goal:** Activate the dialogue pipeline end-to-end — player talks to NPCs, NPCs respond, the world reacts.
|
|
|
|
**Branch:** `server`
|
|
**Agents:** Dudley (dev), Tyre (arch), Hoshe (QA)
|
|
|
|
## Carry-over from Sprint 7
|
|
|
|
None. Sprint 7 server tickets (#308, #326, #427 partial) completed.
|
|
|
|
## New Tickets
|
|
|
|
| # | Title | Blocked by |
|
|
|---|-------|------------|
|
|
| #305 | Dialogue selection pipeline — 4-layer filtering engine | — |
|
|
| #427 | Walk-away KG recording | — |
|
|
| #450 | Wire RecognitionTrigger::Urgent to anomaly detection | — |
|
|
| #451 | Monologue fires during cognitive delay window | — |
|
|
| #452 | Add ContentSlug component | — |
|
|
|
|
Use `db/connectors/ticket show <id>` for full details.
|
|
|
|
## Key Decisions
|
|
|
|
- `decisions/content.md` — D-028 (dialogue architecture: tagged line pools with 4 relational layers), D-035 (tag taxonomy), D-062 (invisible locked options), D-063 (confrontation same box), D-064 (walk-away 3-phase consequences)
|
|
- `decisions/architecture.md` — D-041 (knowledge graph data model)
|
|
- `decisions/perception.md` — D-060 (cognitive delay for fog recognition), D-061 (dialogue box layout)
|
|
|
|
## Open Questions to Resolve Early
|
|
|
|
None.
|
|
|
|
## Notes
|
|
|
|
### #305: Dialogue selection pipeline — 4-layer filtering engine (CRITICAL)
|
|
**What exists:**
|
|
- `server/src/content/line_pool.rs` — LinePoolIndex with full D-028 Layer 1-3 filtering already implemented:
|
|
- `query_dialogue()` filters by access tier, situation, and trust
|
|
- All tag enums defined (AccessTier, TrustTier, Situation, Topic, Mood, Trigger, Character)
|
|
- Indexed pools built from ContentStore at startup
|
|
- `server/src/content/mod.rs` — ContentPlugin loads YAML content and builds LinePoolIndex resource
|
|
- `server/src/simulation/interaction.rs` — compute_nearby_interactions() generates verb options but doesn't yet invoke dialogue selection
|
|
|
|
**What the ticket needs to deliver:**
|
|
- **Layer 4 (topic + mood weighted selection):** New system `select_dialogue_line()` that takes the filtered lines from `query_dialogue()` and scores them by topic/mood match
|
|
- **NPC mood component:** Add `CurrentMood(Mood)` component to NPCs, computed from NPC axes (Tolerance, Contentment, recent events)
|
|
- **Situation derivation:** Map current game state (time of day, location, NPC routine phase, interaction history) → active Situation tags
|
|
- **Integration with Talk verb:** When player selects Talk from interaction list, trigger dialogue pipeline: access tier (from KG RelationshipState) → situations (from context) → trust tier (from KG) → topic+mood scoring → select line → send to client via ObserverSnapshot.dialogue_response
|
|
- **Deliverable:** Full pipeline from Talk verb → selected line text on client dialogue box. Test with 1 NPC (Kael or Sera), 3-5 lines per situation.
|
|
|
|
**Integration points:**
|
|
- Reads LinePoolIndex resource (already exists)
|
|
- Reads KnowledgeGraph component for access/trust tier
|
|
- Writes to new DialogueResponse buffer component for snapshot inclusion
|
|
- Pairs with client #435 (dialogue response selection UI)
|
|
|
|
**Non-obvious gotchas:**
|
|
- Access tier mapping: RelationshipState → AccessTier needs a lookup table (Unknown=public, Known=peer, PersonOfInterest=peer+authority for detective, Friend=insider)
|
|
- Situation activation: NPC's current RoutinePhase + game time (D-031 phases) + location → 1-3 active situations. Don't hardcode — use a mapping table/function.
|
|
- Layer 4 is weighted, not hard filter. Empty topic/mood tags on lines should NOT exclude them — they're topic-neutral.
|
|
- Cooldown tracking per line ID to prevent repeating the same line within a session (MonologueState pattern, but for dialogue)
|
|
|
|
---
|
|
|
|
### #427: Walk-away KG recording (medium)
|
|
**What exists:**
|
|
- `server/src/knowledge/graph.rs` — KnowledgeGraph component with entity/fact maps
|
|
- Client #437 detects WASD during dialogue, sends WalkAway input event
|
|
- D-064 specifies 3-phase consequence model
|
|
|
|
**What the ticket needs to deliver:**
|
|
- **KnowledgeEvent::IncompleteInteraction:** New event type carrying NPC stable_id, interaction_type (Talk/Confront), tick
|
|
- **process_walk_away_input():** System that handles PlayerInput::WalkAway during active dialogue. Emits IncompleteInteraction event, clears dialogue state.
|
|
- **KG recording:** process_knowledge_events() adds entry to entities[npc_id].known_attributes["incomplete_interactions"] = array of {tick, type}
|
|
- **Future query hook:** Stub function `has_incomplete_interaction(npc_id) -> bool` for dialogue/monologue to check (not called in v0.1, but scaffolds D-064 phase 3)
|
|
|
|
**Integration points:**
|
|
- Pairs with client #437 (WASD detect during dialogue)
|
|
- Builds on KnowledgeGraph infrastructure from Sprint 2
|
|
- Future: monologue system (#451) will check this for post-conversation triggers
|
|
|
|
**Non-obvious gotchas:**
|
|
- Walk-away during confrontation vs casual talk should both record, but the `interaction_type` field differentiates them (future dialogue may react differently)
|
|
- Don't emit KnowledgeEvent if no dialogue was active (player hits WASD while near NPC but not talking)
|
|
|
|
---
|
|
|
|
### #450: Wire RecognitionTrigger::Urgent to anomaly detection (medium)
|
|
**What exists:**
|
|
- `server/src/perception/cognitive_delay.rs` — Full cognitive delay system with RecognitionTrigger enum (Normal = 0.6s, Urgent = 0.3s)
|
|
- `server/src/perception/observation.rs` — emit_observation_events() queues PendingRecognition but hardcodes RecognitionTrigger::Normal (line 82: `// TODO(#450)`)
|
|
- ObserveAnomaly monologue trigger defined in line_pool.rs Trigger enum
|
|
|
|
**What the ticket needs to deliver:**
|
|
- **Anomaly detection:** Add system `detect_anomalies()` that marks entities as anomalous when KG.relationship == PersonOfInterest OR KG.state == Contradicted
|
|
- **Component:** `AnomalyMarker` — transient marker on entities flagged as anomalous this tick (cleared each tick)
|
|
- **Wire to cognitive delay:** In emit_observation_events(), if target has AnomalyMarker, use RecognitionTrigger::Urgent instead of Normal
|
|
- **Verify:** Contradicted entity in fog resolves in 0.3s (3 ticks) instead of 0.6s (6 ticks)
|
|
|
|
**Integration points:**
|
|
- Builds on Sprint 7 cognitive delay system (#423 done)
|
|
- Future: monologue system will also check AnomalyMarker for ObserveAnomaly trigger priority
|
|
|
|
**Non-obvious gotchas:**
|
|
- AnomalyMarker is per-tick — clear it at tick start, recompute each tick based on KG state
|
|
- Don't mark Player entity as anomalous (causes unnecessary self-checks)
|
|
- Sprint double-take (#428 done) already fires monologue for sprint-past anomalies; this ticket affects fog recognition timing only
|
|
|
|
---
|
|
|
|
### #451: Monologue fires during cognitive delay window (medium)
|
|
**What exists:**
|
|
- `server/src/simulation/monologue.rs` — Trigger enum includes ObserveAnomaly
|
|
- `server/src/perception/cognitive_delay.rs` — CognitiveDelay component tracks pending recognitions with tick countdown
|
|
|
|
**What the ticket needs to deliver:**
|
|
- **Trigger during delay:** When a PendingRecognition is queued (entity enters fog), immediately check monologue pools for `trigger: observe_anomaly` + character match
|
|
- **Recognition monologue:** New system `trigger_recognition_monologue()` that fires when cognitive delay starts (NOT when it completes). Line text should match D-060 spec: "Those footsteps... that's Kael's walk" — character is thinking during the delay.
|
|
- **Pair with visual:** Monologue appears DURING the grey-blob → color+silhouette transition (client shows both simultaneously)
|
|
|
|
**Integration points:**
|
|
- Reads CognitiveDelay.pending() to detect new recognitions
|
|
- Writes to MonologueBuffer (existing pattern from #414)
|
|
- Pairs with client #431 (fog entity visualization with delay animation)
|
|
|
|
**Non-obvious gotchas:**
|
|
- Fire monologue at delay START (when grey blob appears), not at delay END (when color resolves). The D-060 design is "monologue IS the recognition process."
|
|
- Don't fire recognition monologue for entities already in KG (only for new entities entering perception)
|
|
- Cooldown still applies — don't spam recognition monologue every tick if the same entity blinks in/out of fog
|
|
|
|
---
|
|
|
|
### #452: Add ContentSlug component (medium)
|
|
**What exists:**
|
|
- Content loading in `server/src/content/spawn.rs` spawns NPCs from YAML but doesn't attach content IDs
|
|
- KnowledgeGraph interaction memory (#427) will need to reference "which NPC" for dialogue history
|
|
|
|
**What the ticket needs to deliver:**
|
|
- **Component:** `ContentSlug(String)` — stable content identifier from YAML (e.g. "kael-davan", "sera-venn")
|
|
- **Attach during spawn:** content/spawn.rs reads `npc.slug` field from YAML and attaches ContentSlug component to spawned NPC entity
|
|
- **Use in KG:** Interaction memory records ContentSlug instead of Entity (Entity is unstable across save/load; ContentSlug is stable)
|
|
|
|
**Integration points:**
|
|
- Used by #427 (walk-away recording)
|
|
- Future: dialogue Layer 2 (relationship history) will query past interactions by ContentSlug
|
|
|
|
**Non-obvious gotchas:**
|
|
- ContentSlug is independent of StableId. StableId is runtime entity tracking (KG references). ContentSlug is authoring/content identity (which authored NPC template).
|
|
- Not all entities have ContentSlugs (e.g., procedurally spawned NPCs, furniture). Component is optional.
|
|
|
|
## Dependency Chain
|
|
|
|
```
|
|
#450 (anomaly detection) → standalone, enables urgent recognition
|
|
#451 (monologue during delay) → depends on #450 for anomaly context
|
|
#452 (ContentSlug) → #427 (walk-away KG) depends on this
|
|
#305 (dialogue pipeline) → standalone, headline feature
|
|
#427 (walk-away KG) → depends on #452, pairs with client #437
|
|
```
|
|
|
|
## 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(content): dialogue selection pipeline (Sprint 8 server)" --description "Implements #305 #427 #450 #451 #452 — dialogue 4-layer filtering, walk-away KG, urgent recognition, delay monologue, ContentSlug component" --base main --head server
|
|
```
|