# Knowledge Flow & NPC Information Boundaries Workshop Brief **Goal:** Design the knowledge grant mechanism, NPC-to-NPC knowledge propagation, unprompted disclosure mechanics, NPC information boundaries, and contradiction detection algorithm -- resolving the functional gap between the mature D-041 data model and the Sprint 17 tickets that depend on it. **Sprint context:** Between Sprint 16 (closing) and Sprint 17 (planned) **Priority:** CRITICAL -- Sprint 17 blocker (6 tickets depend on these answers) **Participants:** Tyre (architecture lead), Gestalt (systems design), Dudley (server implementation), Paula (narrative), Qatux (documenter) **Source:** Tyre architecture audit 2026-02-23, Sprint 17 planning dependency analysis ## Context The Knowledge Graph data model (D-041) shipped in Sprint 2 and is mature. The Rust types are solid (`server/src/knowledge/types.rs`), the per-entity `KnowledgeGraph` component works (`server/src/knowledge/graph.rs`), the event queue drains correctly (`server/src/knowledge/events.rs`), and the `filter_by_access` system is implemented with 14 passing tests. Player-facing information boundaries function. The NPC-facing side is functionally empty. NPCs run on ground truth, gossip does not transfer knowledge, contradiction detection does not fire, and dialogue cannot grant facts. Sprint 17 introduces tickets that build on this unfinished foundation. ### Audit Findings (Tyre, 2026-02-23) **Q-024 (Gossip timing) -- Still open.** The `ToldBy` source variant (`KnowledgeSource::ToldBy { source_id: StableId, tick: u64 }`, `server/src/knowledge/types.rs` line 97) is defined but never constructed anywhere in the codebase. NPC conversations (`run_npc_conversations` in `server/src/simulation/conversation.rs`, line 278+) are cosmetic -- they emit voice `SoundEvent`s and `ConversationEvent`s for the player's snapshot, but no knowledge flows between the participating NPCs. The conversation system IS the natural "routine intersection" hook the original workshop preferred. It already has proximity detection, cooldown management, and deterministic pairing via `StableId` sorting (D-010 principle 4). **Q-025 (KG cap/eviction) -- Close.** Memory analysis shows ~30KB total at current NPC count. Not needed for v0.1/v0.2. Formal closure recommended. **Q-026 (Contradiction detection) -- Downstream consumers fully built and tested, detection algorithm not implemented.** Anomaly marking in `server/src/perception/anomaly.rs` fires on `KnowledgeState::Contradicted`. Snapshot flags in `server/src/perception/observer/mod.rs` propagate it. Sprint double-take monologue in `server/src/simulation/monologue.rs` handles it. All tests manually set `Contradicted` on KG entries. The detection algorithm that would SET `Contradicted` based on comparing sources does not exist. Prerequisite: `ToldBy` sources must exist, which requires Topics 1 and 2 to be resolved first. **#141 (Player info gating) -- Mostly done.** `filter_by_access` in `server/src/knowledge/graph.rs` is implemented and tested (14 tests). The dialogue pipeline enforces KG gating (layers 1-3 in `server/src/simulation/dialogue.rs`). Gap: the `knowledge_grant` field on `IndexedDialogueLine` (`server/src/content/line_pool.rs` line 297) is stubbed -- `Option`, always `None`. The YAML schema defines `KnowledgeGrant { fact_id: String, confidence: String }` (`server/src/content/types.rs` lines 495-498). Dialogue lines cannot currently grant facts to the player's KnowledgeGraph. **#142 (NPC info boundaries) -- Still open.** No NPC system queries its own `KnowledgeGraph`. `server/src/npc/tell_state.rs` uses axis values directly (Secret, ToleranceThreshold, Contentment, MoodState, Relationships). `server/src/npc/routine.rs` uses `DailyRoutine` directly. `server/src/simulation/path_follow.rs` uses ground truth. `server/src/simulation/conversation.rs` uses proximity + probability, not knowledge. ### Sprint 17 Tickets That Depend on These Answers | Ticket | Title | Dependency | |--------|-------|------------| | **#172** | Layer 4: Unprompted disclosure | Knowledge propagation model (what can NPCs share?), NPC KG awareness (what does the NPC know to share?) | | **#173** | Trait modifier system | Do traits reshape WHAT NPCs disclose (filtering) or HOW they say it (delivery)? Or both? | | **#148** | POI data model | How do POIs enter the knowledge graph? New FactId category? Or separate system? | | **#149** | POI discovery system | This IS knowledge flow -- it needs the grant mechanism | | **#141** | Knowledge-based information gating | Wire `knowledge_grant`, complete the loop | | **#142** | NPC information boundaries | NPCs use own KG for decisions | ## Key Code to Reference Participants should read these files before Round 1: | File | What to read | Why | |------|-------------|-----| | `server/src/knowledge/types.rs` | Full file | Core types: `KnowledgeSource::ToldBy` (line 97), `KnowledgeConfidence` hierarchy, `KnowledgeState::Contradicted`, `EntityKnowledge` struct, `FactKnowledge` struct | | `server/src/knowledge/graph.rs` | Full file | `KnowledgeGraph` component, `filter_by_access` (14 tests), entity/fact queries, `observe_entity`, `observe_entity_leaving_los` | | `server/src/knowledge/events.rs` | Full file | `KnowledgeEventQueue`, `KnowledgeEventType` variants (currently: `DirectObservation`, `LeftLOS`, `IncompleteInteraction`), `process_knowledge_events` system | | `server/src/knowledge/registry.rs` | Full file | `EntityRegistry` -- `StableId <-> Entity` bidirectional mapping | | `server/src/simulation/conversation.rs` (line 278+) | `run_npc_conversations` | NPC proximity pairing, conversation lifecycle, `SoundEvent`/`ConversationEvent` emission -- the hook for knowledge transfer | | `server/src/simulation/dialogue.rs` | Full file | D-028 four-layer pipeline: access tier (from KG), situations, trust tier (from KG), topic+mood scoring | | `server/src/npc/tell_state.rs` | Full file | `TellCategory` derivation from axis values -- currently bypasses KG entirely | | `server/src/npc/relationships.rs` | Full file | `TrustEvent` queue, relationship state transitions, trust derivation | | `server/src/content/line_pool.rs` (line 297) | `IndexedDialogueLine` | `knowledge_grant: Option` stub | | `server/src/content/types.rs` (lines 495-498) | `KnowledgeGrant` | YAML-parsed schema: `{ fact_id: String, confidence: String }` | | `server/src/perception/anomaly.rs` | Full file | `detect_anomalies` system -- marks entities with `AnomalyMarker` based on KG `Contradicted`/`PersonOfInterest` | | `server/src/simulation/monologue.rs` | Lines 1-60, sprint double-take | Anomaly monologue, recognition lines -- downstream consumer of contradiction | ## Decisions to Reference | Decision | Topic | Relevance | |----------|-------|-----------| | **D-010** | Multiplayer-ready info boundaries | Non-negotiable: every design must respect info boundaries, deterministic iteration (BTreeMap), no player-special-casing | | **D-011** | Fog of perception | NPCs use the same LOS/perception system as player -- information boundaries are universal | | **D-024** | NPC 10 axes | Tell system, Secret, Contentment, Tolerance -- the axes that should be KG-aware but currently are not | | **D-028** | Dialogue architecture (four layers) | Layer 4 (unprompted disclosure) is the immediate Sprint 17 target. Knowledge grants must integrate with this pipeline | | **D-033** | Entity color from relationship | Color shifts on `RelationshipState` change -- downstream of contradiction detection | | **D-034** | THE FRIEND arc | The canonical contradiction sequence that drives the emotional centerpiece of v0.1 | | **D-035** | Tag taxonomy with prerequisites | Monologue prerequisite tags gate on knowledge state -- must align with grant mechanism | | **D-041** | Knowledge graph data model | The foundation -- data model is stable, this workshop fills the behavioral gaps | | **D-071** | Eavesdropping / ListeningFocus | Overheard info enters KG at lower confidence -- informs NPC overhearing rules | | **D-078** | Overheard NPC conversation | Server-authoritative occlusion filter, passive dialogue panel -- player-side of NPC conversations | --- ## Workshop Topics ### Topic 1: Knowledge Flow -- The Grant Mechanism When an NPC tells the player something (dialogue) or the player discovers something (POI, evidence, overheard conversation), how does the knowledge graph get updated? **Sub-questions:** 1. **Wire `knowledge_grant` on dialogue lines.** The YAML schema exists (`KnowledgeGrant { fact_id, confidence }`). The `IndexedDialogueLine` field exists but is always `None`. What triggers the grant -- line selection? Line display on client? Separate post-dialogue system? Who constructs the `KnowledgeEvent` and what `KnowledgeEventType` variant does it use? 2. **Entity knowledge vs fact knowledge in grants.** Current `KnowledgeGrant` only has `fact_id` (a string). Should grants also update `EntityKnowledge` entries? Example: Sera tells the detective "Kael handles cargo at Dock 7" -- this should create/update an `EntityKnowledge` entry for Kael with `source: ToldBy { source_id: sera_sid }`, not just a fact. Does `KnowledgeGrant` need an `entity_grant` variant? 3. **POI discovery as knowledge flow.** `PointOfInterest` (#148) needs to enter the KG. Options: (a) new `FactId` category "poi.*" (e.g., `FactId("poi.dock_7_restricted")`), (b) extend `EntityKnowledge` to cover locations, (c) separate POI knowledge type. Which integrates cleanest with existing `filter_by_access` and dialogue prerequisite checks? 4. **Physical evidence discovery** (terminals, documents, cargo manifests). Same grant mechanism as dialogue? Or a separate `KnowledgeEventType::EvidenceDiscovered`? 5. **Content author guardrails.** What knowledge should NPCs be ABLE to grant? A content validation rule that prevents authors from accidentally making NPCs omniscient. Example: NPC can only grant facts that exist in their own KG. Authoring-time validation or runtime enforcement? **Feasibility note (Tyre):** The event queue architecture (`KnowledgeEventQueue`) already handles this pattern cleanly. Adding a new `KnowledgeEventType::KnowledgeGranted` variant and a system that fires it post-dialogue-selection is a ~2-day task. The harder question is the schema design for multi-type grants (entity + fact). ### Topic 2: NPC-to-NPC Knowledge Propagation (resolves Q-024) When NPCs talk to each other, what knowledge transfers? **Sub-questions:** 1. **Confirm queued approach or revise.** Q-024 preferred direction: queued at routine intersections. The conversation system (`run_npc_conversations`, `server/src/simulation/conversation.rs` line 278+) IS a routine intersection -- NPCs start conversations when proximate during their routines. It already has proximity detection, cooldown timers, and deterministic pairing. Does this satisfy "queued at routine intersections" or do we need a separate system? 2. **Trust-gated filtering.** NPC A has trust level T toward NPC B. What knowledge does A share at each trust level? Proposed mapping to D-028 trust tiers: `surface` trust = share publicly-known facts only, `real` trust = share observations and rumors, `secret` trust = share sensitive knowledge. How does this map to the `KnowledgeConfidence` hierarchy? 3. **Confidence downgrade on transfer.** When NPC A tells NPC B something, B's entry should be at a lower confidence than A's. Proposed: `ToldBy` confidence = `min(source_confidence, KnowsOf)`. Direct observation downgrades to KnowsOf when transferred. `Suspects` stays `Suspects`. This prevents gossip chains from producing `KnowsDetails` knowledge. 4. **Rate limiting.** How much knowledge per conversation? All eligible entries? Random subset? Fixed cap (e.g., 1-3 facts per conversation)? Cap prevents knowledge-explosion from a single NPC-NPC meeting. 5. **Observable by player.** If the player overhears an NPC-NPC conversation (D-078, occlusion filter), what do they learn? The player gets per-word-occluded text. Should the grant mechanism fire for the player based on what words survived occlusion? Or is overheard knowledge always at `Suspects` confidence regardless of fidelity? 6. **ToldBy source construction.** The `KnowledgeSource::ToldBy { source_id: StableId, tick: u64 }` variant is defined but never constructed. This topic must produce the system that creates it. The source entity's `StableId` is already available in the conversation system (line 321: `sid.map(|s| s.0.0).unwrap_or(u64::MAX)`). **Feasibility note (Tyre):** Tier 1 difficulty -- the conversation system already does the hard part (pairing, lifecycle, events). Adding a knowledge transfer phase between conversation start and conversation end is architecturally clean. The trust-gated filtering adds a query against both NPCs' KGs, which is O(log N) per entry. At ~50 entries per NPC and 1-3 transfers per conversation, this is sub-microsecond per conversation tick. ### Topic 3: Unprompted Disclosure Design (#172) NPCs volunteer information to the player without being asked. D-028 Layer 4. **Sub-questions:** 1. **Connection to NPC KG.** `tell_state.rs` currently derives tell category from raw axis values (Secret, Tolerance, Contentment, Mood). #172 needs NPCs to volunteer INFORMATION, which requires knowing what they know. How does the tell derivation system connect to the NPC's `KnowledgeGraph`? Does `DerivedTellState` gain a `disclosure_candidates: Vec` field? 2. **"Do I know something you don't?"** Does the NPC check whether the player already knows a fact before volunteering it? Option A: NPC only checks own KG (simpler, may repeat known info -- but the NPC does not know what the player knows). Option B: NPC checks own KG vs player KG (requires cross-entity KG query, but prevents redundant disclosure). Option A is more realistic (NPCs do not know what you know). Option B is better UX. Which do we choose, or is there a middle ground? 3. **Trait filtering (#173).** Do personality/culture traits affect WHAT is disclosed (filtering -- a cautious NPC withholds certain facts) or HOW it is delivered (delivery -- same facts, different phrasing)? Or both? If "what": traits become a KG filter. If "how": traits become a line-pool modifier. If both: traits filter candidate facts, then modify the delivery of surviving candidates. 4. **Trigger conditions.** When does unprompted disclosure fire? Proposed: trust threshold met + mood permits + location appropriate + rate limit not exceeded. Which axes contribute? Contentment, trust toward player, mood state, presence of other NPCs (witnesses)? 5. **Rate limiting.** How often can an NPC volunteer info? Per-NPC cooldown? Per-fact cooldown (do not repeat the same fact)? Global rate limit across all NPCs (prevent disclosure spam)? Interaction with D-028 Layer 4 line cooldown (`LINE_COOLDOWN_TICKS` = 600 ticks in `server/src/simulation/dialogue.rs` line 39)? **Feasibility note (Tyre):** Tier 2 difficulty. The dialogue pipeline exists and handles line selection well. The challenge is the "what to disclose" derivation -- this is new logic that sits between the KG and the line pool, and it needs to be both mechanically sound and narratively satisfying. Paula and Gestalt need to co-design the disclosure candidate selection before Dudley can implement. ### Topic 4: NPC Information Boundaries (#142) NPCs should use their own `KnowledgeGraph` for decisions, not ground truth. **Sub-questions:** 1. **Which NPC systems should be retrofitted? Priority order.** Candidates: - `npc/tell_state.rs` -- tell derivation (currently uses axes directly, not KG) - `simulation/conversation.rs` -- conversation partner selection (currently uses proximity, not knowledge of who is nearby) - `npc/routine.rs` -- routine execution (currently uses `DailyRoutine` directly) - `simulation/path_follow.rs` -- pathfinding (currently uses ground truth walkability) 2. **Minimum viable boundary.** What is the smallest retrofit that makes a gameplay-visible difference? Proposed: just `tell_state.rs` + unprompted disclosure (#172). An NPC that only reveals what it knows (via KG) is a meaningful boundary even if its pathfinding still uses ground truth. 3. **Simulation tier interaction (D-026).** Background-tier NPCs (500-2000) have minimal KGs. Do they get simplified boundaries? Option: Background NPCs have no KG-based boundaries (they run state machines, not full AI). Only Active-tier NPCs (30-80) get KG-driven behavior. This is consistent with D-026's tiered simulation model. 4. **What breaks?** If `tell_state.rs` reads from KG instead of raw axes: nothing breaks -- KG reflects observed state, which for an NPC's own axes is always up-to-date. If `path_follow.rs` reads from KG: NPCs might "forget" where things are after decay, leading to stuck NPCs or nonsensical pathfinding. The fallback behavior matters. 5. **Fallback behavior.** When an NPC's KG has no relevant information for a decision, what happens? Options: (a) fall through to ground truth (safe but breaks immersion), (b) use last-known state from KG (realistic but may cause stuck behavior), (c) trigger "ask around" behavior (NPC seeks information, creates emergent scenes). v0.1 recommendation: option (a) with logging, option (c) as future enhancement. **Feasibility note (Tyre):** Tier 1 for minimum viable (tell_state + disclosure). Tier 3 for full retrofit (pathfinding + routine). Recommend starting with the MVP and expanding per sprint. The conversation system retrofit is Tier 2 -- it needs to check whether NPC A knows NPC B exists before initiating conversation, which adds a KG query to the pairing loop. ### Topic 5: Contradiction Detection Pipeline (resolves Q-026) The downstream consumers are built and tested. Design the detection algorithm. **Prerequisite:** Topics 1 and 2 must produce `ToldBy` sources. Without `ToldBy` entries in KGs, there is nothing to contradict. **Sub-questions:** 1. **Location contradiction (simplest case).** NPC says "X was at location A at time T" (`ToldBy` source). Player observes X at location B at time T (`DirectObservation` source). System detects: same entity, overlapping time window, different locations. Both entries receive `Contradicted` state. 2. **Attribute contradiction.** NPC says "X is trustworthy" (attribute in `known_attributes`). Player discovers X is a smuggler (different attribute value for same key). How are attribute keys structured to enable comparison? Current `known_attributes: BTreeMap` is untyped -- does contradiction detection need typed attribute keys? 3. **Content-authored vs automatic detection.** Which contradictions are hand-authored ("fact A contradicts fact B" in content files) and which are algorithmic (same-subject different-value)? Proposed: location contradictions are automatic (algorithmic, based on position + time). Attribute contradictions are content-authored (explicit contradiction pairs in YAML). Fact contradictions are hybrid (some automatic categories, some authored). 4. **Detection timing.** When does contradiction detection run? Per-tick (expensive but immediate)? Per-game-minute (matches decay frequency)? On KG write (event-driven, only checks new entries against existing)? The event-driven approach is most efficient -- only fire detection when a `KnowledgeEvent` modifies a relevant entry. 5. **Event emission chain.** Detection fires `ContradictionDetected` event containing: observer entity, contradicting entries (A, B), contradiction type. Downstream: monologue system triggers "Wait -- that does not add up" line. Relationship system shifts to `PersonOfInterest`. Anomaly marker set. D-033 color transitions amber. What is the exact event flow? 6. **THE FRIEND arc mechanical sequence.** The canonical example from D-034: Sera tells detective "Kael was at the dock during second shift" -> detective observes Kael in corridor B-7 at that time -> location contradiction detected -> both entries Contradicted -> monologue: "Sera said Kael was at the dock. I just saw him in B-7." -> Sera shifts to PersonOfInterest -> amber color. Walk through this sequence and confirm every system fires correctly with the proposed design. **Feasibility note (Tyre):** Location contradiction detection is Tier 1 -- BTreeMap lookup by `StableId`, compare positions within a time window. Attribute contradiction is Tier 2 -- needs typed attribute keys or content-authored pairs. The event-driven approach (check on KG write) keeps it off the per-tick hot path. Estimated: ~3 days for location detection + event chain, ~2 additional days for attribute detection. --- ## What This Workshop Is NOT - **Not redesigning D-041.** The data model is stable and works. Types, BTreeMap mandate, event queue, decay -- all ship-tested. This workshop fills behavioral gaps, not structural ones. - **Not full gossip implementation.** The propagation design is Sprint 17+ dev work. This workshop produces the specification, not the code. - **Not resolving Q-017** (triangle pressure thresholds). Still deferred -- requires gameplay data. - **Not designing the full FRIEND arc narrative.** That is Paula + Mellanie content work. This workshop defines the mechanical sequence that enables the narrative. - **Not addressing Q-025 in depth.** Recommendation: close formally (not needed at current scale). If the workshop agrees, Qatux records the closure. ## Expected Outputs 1. **Decision: D-0XX -- Knowledge Flow & NPC Information Boundaries.** Comprehensive decision covering: grant mechanism schema, NPC-to-NPC propagation model, NPC boundary scope, contradiction detection algorithm. Resolves Q-024 and Q-026. 2. **Formal closure of Q-025** (not needed at current scale, re-evaluate at 500+ Active NPCs). 3. **Implementation scope for #141** -- remaining work list: wire `knowledge_grant` field through dialogue pipeline, construct `KnowledgeEvent` on line selection, verify `filter_by_access` integration. 4. **Implementation scope for #142** -- which systems to retrofit, priority order, minimum viable boundary, fallback behavior spec. 5. **Updated ticket descriptions for #172 and #173** -- mechanical specifications from the workshop: disclosure candidate selection algorithm, trait filter vs modifier decision, trigger conditions, rate limits. 6. **New tickets as needed** -- knowledge propagation system, contradiction detection system, POI-KG integration, `KnowledgeEventType` variants. ## Workshop Format Two rounds, following project convention: - **Round 1:** Each participant independently analyzes all 5 topics from their domain perspective. Reference specific code files and line numbers. Tyre: system architecture, ECS patterns, performance budgets. Gestalt: mechanical interactions, "is this fun?", knowledge as gameplay lever. Dudley: Rust implementation feasibility, integration with existing systems, edge cases. Paula: what NPCs should say/know, THE FRIEND arc sequence, narrative consequences of design choices. - **Round 2:** Cross-review, debate, synthesis into concrete decisions. Produce D-record(s), close Q-024/Q-025/Q-026, and generate implementation tickets with mechanical specifications.