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>
110 lines
7.8 KiB
Markdown
110 lines
7.8 KiB
Markdown
---
|
|
title: "Sprint 16 — Server Briefing"
|
|
description: "Dialogue response handler, trust-gated gossip, line variety tracker"
|
|
type: sprint
|
|
status: archived
|
|
sprint: 16
|
|
team: "server"
|
|
---
|
|
|
|
# Sprint 16: Converse — Server Tasks
|
|
|
|
**Goal:** Dialogue becomes a two-way exchange — players pick options and the server responds; NPC information-giving deepens through trust and trait-shaped delivery; the sprite pipeline gets its correct art-direction angle; and housekeeping fixes land across all three active teams.
|
|
|
|
**Branch:** `server`
|
|
**Agents:** Dudley (simulation), Tyre (arch), Hoshe (QA)
|
|
|
|
## Carry-over from Sprint 15
|
|
|
|
None. Sprint 15 was 100% complete (16/16 done).
|
|
|
|
## New Tickets
|
|
|
|
| # | Title | Blocked by |
|
|
|---|-------|------------|
|
|
| #538 | Arch: Move dialogue systems from BridgePlugin to NpcPlugin | — |
|
|
| #539 | Server: implement DialogueResponse verb handler | #538 |
|
|
| #171 | Layer 3: Trust-gated gossip | — |
|
|
| #338 | Line variety tracker — prevent repeat dialogue | — (unblocked: #305 done) |
|
|
|
|
Use `db/connectors/ticket show <id>` for full details.
|
|
|
|
## Key Decisions
|
|
|
|
- `decisions/content.md` — D-028 (dialogue architecture, four relational layers), D-035 (tag taxonomy, trust/access tiers), D-075 (layered confidence gate on trust tier)
|
|
- `decisions/architecture.md` — D-041 (knowledge graph data model, KnowledgeConfidence hierarchy), D-010 (no baking player identity into game loop)
|
|
|
|
## Notes
|
|
|
|
### #538 — Arch: Move dialogue systems from BridgePlugin to NpcPlugin
|
|
|
|
**What exists:** `server/src/bridge/mod.rs` (lines 181-187) registers `process_talk_interaction`, `process_walk_away`, and `process_confrontation_response` inside `BridgePlugin::build()`. These systems depend on NPC-layer resources (`TrustEventQueue`, `KnowledgeGraph`, `KnowledgeEventQueue`) but live in the bridge module, which is supposed to own only wire protocol concerns.
|
|
|
|
**What to deliver:** Move the three `.add_systems()` calls from `BridgePlugin::build()` to `NpcPlugin::build()` in `server/src/npc/mod.rs`. The function implementations in `server/src/simulation/dialogue.rs` do not move — only their registration site changes. The scheduling constraints (`.after(process_player_input)`, `.before(compute_observer_snapshot)`) must be preserved exactly. `NpcPlugin` already has access to `TrustEventQueue` and other NPC resources (it `init_resource`s them), so no new resource registration is needed.
|
|
|
|
**Gotcha:** The `game_loop` integration tests in `dialogue.rs` that manually set up `TrustEventQueue` were the signal that this was misplaced. After the move, those tests should no longer need the manual init. Verify no test breaks.
|
|
|
|
**Integration point for #539:** This must merge before #539 starts, since #539 adds a new dialogue system that should register in `NpcPlugin` from the start.
|
|
|
|
### #539 — Server: implement DialogueResponse verb handler
|
|
|
|
**What exists:** `process_talk_interaction` in `server/src/simulation/dialogue.rs` handles the initial `Talk` verb. It selects a line via the 4-layer pipeline and writes to `DialogueResponseBuffer`. The client sends `DialogueResponse { response_id }` when the player picks an option, but no server system consumes it. `PlayerAction::DialogueResponse` is already defined in the bridge types.
|
|
|
|
**What to deliver:** A new system `process_dialogue_response` in `server/src/simulation/dialogue.rs` that:
|
|
1. Reads `DialogueResponse` actions from the player input queue
|
|
2. Looks up the NPC's `DialogueProfile` (location, role) and active `KnowledgeGraph` state
|
|
3. Runs the same 4-layer filtering pipeline (`query_dialogue` on `LinePoolIndexResource`) to select a follow-up line based on the response_id context
|
|
4. Writes the result to `DialogueResponseBuffer` for snapshot inclusion
|
|
5. For conversations that have ended (no follow-up lines), clears `ActiveDialogue`
|
|
|
|
**Key design constraints from D-028 + D-062:** Dialogue options the player hasn't unlocked are invisible — so `response_id` will only arrive for options that were legitimately sent. No validation needed beyond confirming the response_id maps to a known dialogue context. The server does not need to validate "was this a valid choice?" — if the client sent it, it was shown.
|
|
|
|
**Integration with #171:** If trust-gated gossip (#171) is complete in the same sprint, this system should also route `Real`/`Secret` tier responses through the trust-gated pipeline. If #171 lands after, stub with `Surface`-only for now.
|
|
|
|
**Register in NpcPlugin** (after #538 lands).
|
|
|
|
### #171 — Layer 3: Trust-gated gossip
|
|
|
|
**What exists:** The trust tier gate is already fully implemented. `relationship_to_trust()` in `server/src/simulation/dialogue.rs` (lines 199-216) takes `RelationshipState` and `KnowledgeConfidence` and returns `TrustTier` per D-075. The `LinePoolIndexResource` query pipeline in `content/mod.rs` accepts a `TrustTier` and filters lines accordingly. The content YAML files already carry `trust: real` and `trust: secret` tags on authored lines.
|
|
|
|
**What to deliver:** Three disclosure tiers per NPC role (surface / real / secret). The engine is ready — the gap is that `process_talk_interaction` may not be passing the correct `KnowledgeConfidence` from the observer's `KnowledgeGraph` to `relationship_to_trust()`. Verify in `process_talk_interaction` that:
|
|
1. The observer's `KnowledgeGraph` is queried for the NPC's `StableId`
|
|
2. `confidence_of(&target_sid)` is passed as the second arg to `relationship_to_trust()`
|
|
3. The resulting `TrustTier` filters lines in `query_dialogue`
|
|
|
|
If this path is already wired (check near line 345 in `dialogue.rs`), the ticket may be a content validation: confirm that authored lines with `trust: real` and `trust: secret` actually surface for a player with `KnowsOf+` / `KnowsDetails+` knowledge. Write a test that initializes a player KG with `KnowsDetails` on a target NPC, runs `process_talk_interaction`, and asserts a `Secret`-tier line was selected.
|
|
|
|
**Progressive revelation:** The same NPC gives different answers on first meeting (Surface only) vs. after investigation (Real/Secret unlocked). This is not a UI change — it is already handled by D-062's invisible locks. The engine must simply populate `DialogueResponseBuffer` with the tier-appropriate line.
|
|
|
|
### #338 — Line variety tracker — prevent repeat dialogue
|
|
|
|
**What exists:** `DialogueCooldownTracker` is already implemented as a `Component` in `server/src/simulation/dialogue.rs` (lines 78-105). It tracks `line_id → tick_used` in a `BTreeMap<String, u64>` with a 600-tick (1 game-hour) cooldown. `record()`, `is_on_cooldown()`, and `prune()` methods exist.
|
|
|
|
**What to deliver:** Wire the tracker into `process_talk_interaction`:
|
|
1. Query `DialogueCooldownTracker` on the player entity (it may already be queried — check the system signature near line 345)
|
|
2. After the 4-layer pipeline returns candidates, filter out lines where `tracker.is_on_cooldown(line_id, current_tick)` returns true
|
|
3. Call `tracker.record(selected_line_id, current_tick)` after selection
|
|
4. Call `tracker.prune(current_tick)` each time to prevent unbounded growth
|
|
|
|
If the tracker is already being queried but not used to filter, this is a 10-line change. If it is not queried at all, add it to the system signature and wire it in. Write a test that sends `Talk` repeatedly to the same NPC and asserts no line_id appears twice within `LINE_COOLDOWN_TICKS`.
|
|
|
|
## Dependency Chain
|
|
|
|
```
|
|
#538 (BridgePlugin → NpcPlugin refactor)
|
|
→ #539 (DialogueResponse verb handler)
|
|
|
|
#171 (Layer 3: Trust-gated gossip) → standalone, parallel track
|
|
[may inform #539 if both land same sprint]
|
|
|
|
#338 (Line variety tracker wiring) → standalone, parallel track
|
|
```
|
|
|
|
## 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): sprint 16 dialogue server" --description "body" --base main --head server
|
|
```
|