Files
settled-reach/docs/workshops/knowledge-flow-npc-boundaries/workshop-brief.md
T
jpmschweitzerandClaude Opus 4.6 abff69a632 chore(meta): Sprint 17 planning — briefings, workshop brief, close Q-025
- Write sprint 17 briefings for server, client, copy, visual, joint
- Add Knowledge Flow & NPC Boundaries workshop brief
- Close Q-025 (KG cap/eviction not needed at current scale)
- Assign 9 tickets to Sprint 17: Tell

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 23:25:08 +01:00

23 KiB

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 SoundEvents and ConversationEvents 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<KnowledgeGrant>, 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<KnowledgeGrant> 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<FactId> 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<String, String> 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.