Workshop outputs from Knowledge Flow & NPC Information Boundaries workshop (2026-02-24): Decisions registered in decisions/perception.md: - D-079: Knowledge Grant Architecture (unified KnowledgeGranted event, Fact+Entity enum, ContentEntityRegistry) - D-080: NPC-to-NPC Knowledge Propagation (transfer_npc_knowledge system, trust-tier gating, ToldBy source) - D-081: Unprompted Disclosure Design (DisclosureCandidates component, two-stage trait filter, trigger gates) - D-082: NPC Information Boundaries MVP Scope (tell_state + disclosure; pathfinding KG integration explicitly not planned) - D-083: Contradiction Detection Pipeline (event-driven at observe_entity, ContradictionClaim struct, downstream chain) Questions closed in decisions/questions.md: - Q-024: closed by D-080 (immediate during conversation, not queued) - Q-025: confirmed closed (gossip propagation ships Sprint 17; ~12MB peak, no cap needed before v0.3) - Q-026: closed by D-083 (event-driven at KG write time, ContradictionClaim struct) Tickets created (#545–#551, Sprint 17, team server): - #545 KnowledgeGrant schema + ContentEntityRegistry (critical, blocks all downstream) - #546 KnowledgeGranted event + process_knowledge_events handler - #547 ContradictionClaim struct + detection in observe_entity - #548 NPC-to-NPC knowledge transfer system - #549 tell_state.rs KG awareness — MVP information boundary - #550 Contradiction monologue + event chain completion - #551 DisclosureCandidates + unprompted disclosure Existing tickets updated: #141, #142 (sprint 17 + team assigned, descriptions updated); #172, #173 (full mechanical spec from D-081). Workshop source files committed: all round docs + workshop-outcomes.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
310 lines
26 KiB
Markdown
310 lines
26 KiB
Markdown
# Paula — Round 1: Narrative Analysis
|
|
## Knowledge Flow & NPC Information Boundaries Workshop
|
|
|
|
**Date:** 2026-02-23
|
|
**Role:** Narrative and Political Depth
|
|
|
|
---
|
|
|
|
## Framing
|
|
|
|
The technical gap this workshop addresses — NPCs running on ground truth, gossip not transferring knowledge, contradiction detection not firing — is not just a systems problem. It is a narrative problem. Every one of these missing pieces corresponds to a moment in THE FRIEND arc that cannot yet land.
|
|
|
|
Sera Venn volunteers information that the detective doesn't yet know. That's unprompted disclosure (#172). The detective later observes something that contradicts Sera's account. That's contradiction detection (Q-026). The monologue that fires ("Sera said Kael was at the dock. I just saw him in B-7.") is the emotional centerpiece of v0.1 — and it currently cannot happen because the `ToldBy` source that would tie Sera's testimony to that contradiction was never constructed.
|
|
|
|
This workshop is asking what it means for an NPC to *know* something. My job is to make sure the answers we reach don't just pass technical review — they have to feel true to how people actually hold information, share it, and get caught in contradictions.
|
|
|
|
---
|
|
|
|
## Topic 1: Knowledge Flow — The Grant Mechanism
|
|
|
|
### The authoring philosophy question underneath the schema question
|
|
|
|
Before discussing whether `KnowledgeGrant` needs an `entity_grant` variant, there is a prior question: *What does it mean for an NPC to "tell" the player something?*
|
|
|
|
In the current system, dialogue lines are content artifacts. They sit in line pools, get scored and selected, get displayed. They don't *do* anything to the world's information state. The player reads "Kael runs the cargo intake" and nothing changes in the KG. The dialogue was informative in the sense that a book is informative — it delivered text — but it didn't create a knowledge relationship between the observer and the subject.
|
|
|
|
Testimony is not just text delivery. When Sera says "Kael was at the dock during second shift," she is creating a *source-attributed claim about a specific person at a specific time*. That claim has provenance (Sera, tick N), it has a confidence level (KnowsOf — she's not guessing, she observed), and it can later be contradicted. The grant mechanism is what makes the claim real in the system.
|
|
|
|
### Position: `KnowledgeGrant` needs two variants
|
|
|
|
The current schema (`KnowledgeGrant { fact_id: String, confidence: String }`) only covers fact knowledge — entries in `facts: BTreeMap<FactId, FactKnowledge>`. But Sera's claim about Kael creates **EntityKnowledge**, not just a fact. It should update `entities: BTreeMap<StableId, EntityKnowledge>` with a new entry for Kael, sourced `ToldBy { source_id: sera_sid, tick }`.
|
|
|
|
I propose `KnowledgeGrant` be extended to a sum type:
|
|
|
|
```
|
|
enum KnowledgeGrantTarget {
|
|
Fact { fact_id: FactId },
|
|
Entity { entity_sid: StableId, attribute_key: String, attribute_value: String },
|
|
EntityPosition { entity_sid: StableId, location_description: String },
|
|
}
|
|
```
|
|
|
|
This is not just a schema preference. The downstream consequences are:
|
|
- **Contradiction detection requires EntityKnowledge**, not just facts. The canonical contradiction (Sera says "dock", player observes "B-7") operates on `EntityKnowledge.last_known_position` and `known_attributes`. If Sera's testimony only creates a `FactKnowledge` entry, the contradiction detector has nothing to compare against the `DirectObservation` that updates `EntityKnowledge`.
|
|
- **Source attribution requires the grant to create a `ToldBy` entry.** If the detective's KG entry for Kael is created `source: ToldBy { source_id: sera_sid, tick }`, the contradiction later marks BOTH the DirectObservation entry AND the ToldBy entry as `Contradicted`. The system can then surface: "Sera told you X. You observed Y. These conflict." Without the entity grant, you lose the source chain.
|
|
|
|
### Content authoring guardrail: what NPCs can grant = what they know
|
|
|
|
The workshop brief raises the question of content validation. My position: **NPCs should only be able to grant knowledge they hold in their own KnowledgeGraph.**
|
|
|
|
This is not merely an authoring convenience. It is a narrative truth constraint. If Sera's own KG doesn't contain an EntityKnowledge entry for Kael-at-the-dock, she cannot have told the detective about it — because she doesn't know. An author who writes a dialogue line with `knowledge_grant: { entity: kael_sid, position: "dock 7" }` on Sera's line has asserted that Sera knows this. The validator should check: does Sera's authored initial KG state include this entry? If not, flag it.
|
|
|
|
Runtime enforcement is harder (NPC KGs evolve during play), but the authoring-time check catches the obvious cases and forces authors to make NPC knowledge explicit.
|
|
|
|
### POI discovery as knowledge flow
|
|
|
|
For POI knowledge, I prefer option (a): a `FactId` category "poi.*" (e.g., `poi.dock_7_restricted`). The reasons are narrative:
|
|
|
|
- POI knowledge is *about a location*, not about a person. It fits the `FactKnowledge` model cleanly.
|
|
- The player "discovering" a POI is precisely a `DirectObservation` event, just targeted at a location rather than an entity.
|
|
- Dialogue-granted POI knowledge (an NPC saying "there's a restricted cargo bay off corridor B-7") should create a `ToldBy` FactKnowledge entry at `Suspects` or `KnowsOf` confidence — lower than direct discovery.
|
|
- This integrates cleanly with `filter_by_access`: a player needs `poi.dock_7_restricted` in their KG at KnowsOf+ to get dialogue options about that location.
|
|
|
|
### Physical evidence vs dialogue grants
|
|
|
|
I see these as the *same grant mechanism* but with different triggering events:
|
|
- Dialogue-triggered: post-line-selection, the dialogue system constructs a `KnowledgeEvent` and pushes it to the queue
|
|
- Evidence-triggered: player "reads" a document or examines evidence, a similar event fires
|
|
|
|
The difference is the `source` field: dialogue creates `ToldBy`, evidence examination creates `DirectObservation` (you're directly observing the document's contents). A new `KnowledgeEventType::KnowledgeGranted { source: KnowledgeSource, target: KnowledgeGrantTarget }` covers both cases cleanly without a separate variant for evidence.
|
|
|
|
---
|
|
|
|
## Topic 2: NPC-to-NPC Knowledge Propagation (Q-024)
|
|
|
|
### The routine intersection hook is narratively correct
|
|
|
|
The existing `run_npc_conversations` system pairing NPCs by proximity is *already* modeling something true about information flow in a community: people share information when they're in physical proximity, during routine overlap, not via some abstract information broadcast. This is the right hook. No separate system needed.
|
|
|
|
What I want to advocate for is the *content* of what transfers, not just the mechanism.
|
|
|
|
### Trust-gated filtering: not just tiers, but relationship character
|
|
|
|
The proposed mapping (surface trust = public facts, real trust = observations/rumors, secret trust = sensitive knowledge) is correct in structure, but misses something. The *character* of what NPC A shares with NPC B depends not just on trust level but on *subject matter*:
|
|
|
|
- Voss will share public knowledge about cargo schedules with anyone. He'll share his suspicions about manifest discrepancies only with people he trusts. He'll never share that he knows about the ring — regardless of trust tier — because he's terrified.
|
|
- Kael will share warmth freely. His secret (trying to exit the ring) is not something he'd share even at the highest trust tier, because sharing it is dangerous.
|
|
|
|
This suggests trust-gated filtering should be necessary-but-not-sufficient. Alongside trust tier, NPCs should have a `disclosure_threshold_override` on individual KG entries — a flag that says "even at maximum trust, don't share this." This is how Major secrets should behave: they are withheld at the KG entry level, not filtered by trust tier.
|
|
|
|
### Confidence downgrade on transfer: the proposed rule works
|
|
|
|
The proposed rule (`ToldBy` confidence = `min(source_confidence, KnowsOf)`) is right. When NPC A tells NPC B something, B doesn't have A's direct observation — B has A's report. That's `KnowsOf` at best. `Direct` observation never transfers through gossip; you can't tell someone else what it's like to *see* something and have them receive that experience.
|
|
|
|
The narrative effect is important: gossip chains dilute information. By the time the fifth NPC in a chain hears something, it's `Suspects`-level, not `KnowsDetails`. This is accurate to how communities work.
|
|
|
|
### Rate limiting: 1-3 facts per conversation, but weighted by relationship
|
|
|
|
A fixed cap of 1-3 facts per conversation works mechanically. But I'd weight by trust level:
|
|
- Surface trust: 0-1 facts (pleasantries and public knowledge only)
|
|
- Real trust: 1-2 facts
|
|
- Secret trust: up to 3 facts, but only if NPC has relevant high-trust entries
|
|
|
|
The goal is to prevent knowledge-explosion (correctly identified in the brief) while also preventing "people with deep trust never share anything." The weighting makes NPCs feel like they're calibrated to the relationship.
|
|
|
|
### Overheard NPC conversations: always Suspects, no exceptions
|
|
|
|
If the player overhears an NPC-NPC conversation (D-078), the player's KG entry should always be at `Suspects` confidence, regardless of how much of the conversation survived occlusion. Here's why:
|
|
|
|
1. **The player lacks context.** They heard words, not an explanation. "He said Kael was at the dock" means nothing without knowing who "he" is, what "the dock" refers to, whether this is past or present.
|
|
2. **Suspicion is the correct epistemic state.** You overheard something. You don't know if it's true. `Suspects` is honest.
|
|
3. **It creates investigative motivation.** You need to confirm. You seek out sources. You build the case. `KnowsOf` for overheard information would shortcut this.
|
|
|
|
The source variant should be `KnowledgeSource::Heard { tick, range: Close }` — not `ToldBy`, because the NPC didn't tell *you* anything; you were eavesdropping. This distinction matters for contradiction detection: an overheard claim is harder to attribute for contradiction purposes than a direct testimony.
|
|
|
|
---
|
|
|
|
## Topic 3: Unprompted Disclosure Design (#172)
|
|
|
|
This is where I have the strongest opinions, because this is where THE FRIEND arc's emotional setup lives.
|
|
|
|
### The setup that has to work
|
|
|
|
Sera Venn's relationship with the detective follows this arc (from D-034):
|
|
- Phase 1 (trust): Commission tech, bar regular, warm and informative, socially comfortable
|
|
- Phase 2 (data): Begins volunteering information about cargo processes, casually — this is unprompted disclosure
|
|
- Phase 3 (recognition): Player observes a behavioral tell — Sera avoids Torek Lintar
|
|
- Phase 4 (question): Player realizes Sera is sitting on unreported evidence
|
|
- Phase 5 (contamination): Trust is re-evaluated
|
|
|
|
The whole arc *requires* that Phase 2 actually happen mechanically. Sera must volunteer information to the player before the contradiction. If she only speaks when spoken to (dialogue tree), the player has no expectation of Sera as a source — and when the contradiction lands, it doesn't mean anything. The sense of betrayal requires prior gift-giving.
|
|
|
|
This is the narrative case for getting unprompted disclosure right: without it, there is no FRIEND arc. There is only an NPC who sometimes lies.
|
|
|
|
### "Do I know something you don't?" — Option A, firmly
|
|
|
|
NPCs should NOT check the player's KG before deciding to disclose. Option A (NPC checks own KG only) is the right choice, for narrative reasons that I think are non-negotiable:
|
|
|
|
1. **Dramatic irony requires asymmetric knowledge.** When Sera tells the detective "Kael runs a tight intake process — never a discrepancy on his watch" in Phase 2 — and the player has already found manifest discrepancies — the dramatic irony is crushing. Sera *doesn't know* the player already knows. She's praising someone whose cover is already partially blown. If Sera checked the player's KG and saw KnowsOf for manifest discrepancies, she might not say this. You've lost the moment.
|
|
|
|
2. **NPCs not knowing what you know is a feature, not a bug.** It's the source of almost all the interesting social texture. Characters talk at cross-purposes. People are still defending someone the player has already made a case against. The community is behind the detective.
|
|
|
|
3. **Option B creates a surveillance panopticon.** If NPCs know what the player knows, they're behaving as if they have access to the player's cognitive state. That's not a knowledge boundary — that's a boundary violation.
|
|
|
|
The result is that NPCs may repeat information the player already has. This is fine. The player has heard this before — but hearing it from THIS person, at THIS trust level, after THIS much has been discovered, has different weight. Authors should lean into it: "She's still defending him. Doesn't she know?"
|
|
|
|
### Trait filtering: both, with specific meaning for each
|
|
|
|
The brief asks: do traits affect WHAT is disclosed (filtering) or HOW (delivery)? The answer must be both, but they operate at different layers:
|
|
|
|
- **What (filtering):** Cautious NPCs have a higher disclosure threshold — they need more trust and more of their specific mood conditions before any fact makes it to the disclosure candidates list. This is a KG-level filter. A cautious Sera might have 40 facts in her KG but only 2 that would clear her disclosure threshold at any given trust level.
|
|
- **How (delivery):** Once a fact clears the threshold, Sera's specific personality shapes the line. Her warmth, her slight formality, her tendency to frame things in terms of professional competence. This is the line pool scoring modifier — same facts, different pool weighting.
|
|
|
|
The two-layer model means: trait changes "how many things Sera would ever say unprompted" (filtering) AND "how she says the things she does say" (delivery). This is richer than either alone and avoids the edge case where a cautious NPC with a Major secret that must be disclosed has no way to shape the delivery.
|
|
|
|
### Trigger conditions
|
|
|
|
Proposed trigger set for unprompted disclosure:
|
|
1. **Trust threshold met** (RelationshipState: Friendly minimum)
|
|
2. **Contentment above neutral** (> 0 on the Contentment axis)
|
|
3. **Mood compatible** (not Hostile, Anxious above threshold, or Frustrated) — use the 8-mood vocabulary from D-035/D-035 Amendment Sprint 14
|
|
4. **Location appropriate** — this condition is missing from the brief and I want to argue for it explicitly (see below)
|
|
5. **Rate limit not exceeded** (the existing `LINE_COOLDOWN_TICKS: u64 = 600` from dialogue.rs line 39 should apply)
|
|
|
|
**Location appropriateness as a disclosure gate:**
|
|
|
|
Sera won't confide sensitive information at the Terminal (too many witnesses, professional context). She will at The Last Shift in a quiet corner. This maps to D-025's public/private spatial distinction — "functional cluster defines spatial identity including public/private."
|
|
|
|
Content authors should be able to tag disclosure candidates with a `location_privacy: [private, semi-private, any]` field. The disclosure trigger checks the NPC's current location against this. A `private`-tagged disclosure won't fire at The Terminal. This is not just realism — it creates spatial behavior patterns the player can learn: "If I want Sera to talk, I need to catch her at Lera's, not at work."
|
|
|
|
### Rate limiting structure
|
|
|
|
Three-layer rate limiting:
|
|
1. **Per-fact cooldown** (highest priority): once a fact has been disclosed, mark it in the NPC's disclosure state. Don't repeat it. The player has heard it. Repeating it is noise.
|
|
2. **Per-NPC cooldown** (second): prevents disclosure spam in a single interaction. The `LINE_COOLDOWN_TICKS` (600 ticks) seems right as a floor.
|
|
3. **Global rate limit across all NPCs** (third, lightest): exists mainly to prevent a degenerate case where the player visits 8 NPCs in rapid succession and gets flooded with disclosures in one game-hour.
|
|
|
|
The per-fact cooldown is the most important narratively: an NPC who says the same thing twice is a quest marker, not a person.
|
|
|
|
---
|
|
|
|
## Topic 4: NPC Information Boundaries (#142)
|
|
|
|
### The narrative argument for minimum viable first
|
|
|
|
The workshop brief correctly identifies minimum viable boundary as `tell_state.rs` + unprompted disclosure. I want to reinforce *why* this is the right order from a narrative standpoint — not just a feasibility standpoint.
|
|
|
|
`tell_state.rs` currently derives tell category from raw axes: Secret severity, stress vs. threshold, contentment, mood, relationships. This produces behaviors like "NPC is Guarded because they have a Major secret." That's correct. But what if the NPC's *knowledge* of their secret's exposure changes their behavior? Sera's `Guarded` tell should intensify if she *knows* the detective is investigating Kael — not just because her Secret severity is Major, but because her KG contains entries showing investigation proximity.
|
|
|
|
The minimum viable boundary retrofit for `tell_state.rs` is: **allow KG-derived knowledge to influence the Secret's effective stress level.** If the NPC knows someone is getting close to their secret, the threat multiplier on `current_stress` increases. This doesn't require a full KG query — just a check: "does my KG contain entries related to the entities/facts that my Secret references, at PersonOfInterest or higher?"
|
|
|
|
This is a very small addition that produces a very meaningful behavioral change: NPCs who *know they're being watched* act more stressed. NPCs who are unaware remain calm.
|
|
|
|
### Priority order for system retrofits
|
|
|
|
From a narrative impact standpoint, I'd prioritize:
|
|
|
|
| Priority | System | Narrative Payoff |
|
|
|----------|--------|-----------------|
|
|
| 1 | `tell_state.rs` | Direct: NPC observable behavior reflects what they know. Every investigation interaction benefits. |
|
|
| 2 | Unprompted disclosure (#172) | Direct: Enables Phase 2 of THE FRIEND arc. Without this, Sera is mute pre-contradiction. |
|
|
| 3 | `conversation.rs` | Medium: NPC-to-NPC conversations become information events, not just ambient noise. |
|
|
| 4 | `routine.rs` | Low for v0.1: routine deviation is already a tell signal (D-027). Whether the routine query uses KG is less impactful initially. |
|
|
| 5 | `path_follow.rs` | Very low / deferred: KG-based pathfinding creates stuck-NPC risk (noted in brief). For v0.1, ground truth pathfinding with KG-based decisions is the right split. |
|
|
|
|
### Fallback behavior: ground truth with logging, not silent
|
|
|
|
For all retrofitted systems, when the NPC's KG has no relevant information, **fall through to ground truth with structured logging** (not silent). The logging serves two purposes:
|
|
1. QA visibility: we can see which systems are still operating on ground truth and why
|
|
2. Design signal: if we see many log entries for a specific NPC/system, it indicates an authoring gap (NPC's initial KG state is missing entries that should be there)
|
|
|
|
Option (c) — "ask around" behavior — is compelling for future sprints. An NPC who doesn't know something seeking out information creates exactly the emergent scenes D-029 needs for the mundane 80%. But it's correctly deferred for v0.1.
|
|
|
|
---
|
|
|
|
## Topic 5: Contradiction Detection Pipeline (Q-026)
|
|
|
|
This is where the mechanical and narrative come into direct contact, and I have specific things to say about the emotional sequence.
|
|
|
|
### The THE FRIEND arc — full mechanical sequence
|
|
|
|
The brief asks for a complete walkthrough confirming every system fires correctly. Here is the canonical version from my narrative perspective:
|
|
|
|
**Precondition:** Sera's KG contains `EntityKnowledge` for Kael: `last_known_position: Some(DockTile)`, `source: DirectObservation { tick: T0 }`, confidence: `KnowsDetails`. She observed Kael at the dock during second shift.
|
|
|
|
**Step 1: The testimony**
|
|
- Detective initiates Talk with Sera. Dialogue pipeline selects a line with `knowledge_grant: { entity: kael_sid, position: "dock intake, second shift", confidence: KnowsOf }`.
|
|
- `KnowledgeEvent::KnowledgeGranted` fires. Player's KG gains `EntityKnowledge` for Kael: `source: ToldBy { source_id: sera_sid, tick: T1 }`, confidence: `KnowsOf`, position claim: dock, time window: second shift.
|
|
|
|
**Step 2: The observation**
|
|
- At tick T2 (same game-shift or overlapping time window), player's LOS includes Kael in corridor B-7.
|
|
- `KnowledgeEvent::DirectObservation` fires. Player's KG entry for Kael: `source: DirectObservation { tick: T2 }`, confidence: `Direct`, position: B-7.
|
|
|
|
**Step 3: Contradiction detection fires**
|
|
- Event-driven: on KG write (T2), contradiction detector runs against the new `DirectObservation` entry.
|
|
- Check: same entity (Kael_sid), overlapping time window (T1 and T2 within second-shift window), different positions (dock vs B-7).
|
|
- Both entries receive `KnowledgeState::Contradicted`.
|
|
- `ContradictionDetected` event emits: observer = detective, entries = [ToldBy(Sera, dock), DirectObservation(B-7)], type = location.
|
|
|
|
**Step 4: Downstream cascade**
|
|
- Monologue system picks up `ContradictionDetected`. Fires contradiction monologue line — **must be authored to name Sera specifically**. Generic "wait, that doesn't add up" is not sufficient here. The line must say: *"Sera said Kael was at the dock during second shift. I'm looking at him in B-7 right now. One of them is wrong."*
|
|
- Anomaly system marks Kael AND Sera as `PersonOfInterest` (both entities are implicated — Kael by being in the wrong place, Sera by the testimony that is now contradicted).
|
|
- D-033: both entities shift to amber.
|
|
- Available dialogue with Sera unlocks Confrontation option.
|
|
|
|
**Step 5: The ambiguity**
|
|
- The monologue fires `Contradicted` — not "Sera lied." The player doesn't know if Sera is lying, mistaken, or manipulated. The engine is correct to be epistemically neutral. The content must be too.
|
|
|
|
### On the "both entries Contradicted" design
|
|
|
|
I want to explicitly endorse the design choice that *both* entries receive `Contradicted` state. This is narratively correct. When you have contradictory sources, you can't know which is wrong. The testimony might be wrong (Sera lied/was confused). The observation might be wrong (Kael has a double? Player misidentified?). The engine marks both as uncertain, which is the honest epistemic state.
|
|
|
|
Authors writing Sera's post-contradiction dialogue must NOT have Sera behave as if she knows she's been caught. She doesn't know the player has contradicted her testimony. Her behavior changes only if the player CONFRONTS her. This is the "no player-special-casing" principle (D-010) expressed in character psychology.
|
|
|
|
### Contradiction content authoring requirements
|
|
|
|
This is a gap in the current framework that I want to surface for Round 2 discussion:
|
|
|
|
**Contradiction monologue lines must be authored with source attribution.** A generic `trigger: contradiction_detected` monologue line ("that doesn't add up") is insufficient. The player needs to understand WHO provided the contradicted claim. This requires the monologue system to receive the source entity's `StableId` and map it to a displayable name.
|
|
|
|
Options:
|
|
1. **Templated monologue lines** with entity name substitution: `"{source_name} said {entity_name} was at {claimed_location}. I just saw {entity_name} at {actual_location}."` — clean but requires template string support in the monologue system
|
|
2. **Pre-authored lines per relationship phase** — for THE FRIEND NPCs (Kael, Sera), write specific lines for each phase of the relationship that fire on contradiction. This is hand-authored, but THE FRIEND NPCs are already "no generation expansion, all hand-authored" per D-034.
|
|
3. **Generic fallback + authored override** — generic template for auto-generated NPCs, hand-authored lines for FRIEND-pattern NPCs
|
|
|
|
My preference is option 3. For v0.1 with only two FRIEND NPCs, the hand-authored lines (option 2 flavored content in the generic system) are achievable. The template system is the right long-term architecture.
|
|
|
|
### Attribute contradiction — typed keys vs authored pairs
|
|
|
|
The brief notes that `known_attributes: BTreeMap<String, String>` is untyped. For contradiction detection on attributes, I'd prefer **content-authored pairs with structured key conventions over a full typing system**.
|
|
|
|
Reasoning: attribute contradiction is rare and narratively significant. You don't want the engine silently marking two minor attribute discrepancies as contradicted. You want the author to say "this specific attribute combination is a contradiction that the player should notice."
|
|
|
|
Proposed approach: YAML schema extension with an optional `contradicts` field on `KnowledgeGrant`:
|
|
```yaml
|
|
knowledge_grant:
|
|
entity: kael_sid
|
|
attribute_key: "occupation_status"
|
|
attribute_value: "legitimate_cargo_handler"
|
|
# authored contradiction pair:
|
|
contradicts_attribute_value: "ring_member"
|
|
```
|
|
|
|
This surfaces the contradictions that *matter narratively* and keeps the detection system from firing on attribute mismatches that are informationally trivial.
|
|
|
|
---
|
|
|
|
## Summary: Narrative Requirements for Round 2 Decisions
|
|
|
|
The decisions this workshop produces need to satisfy the following narrative requirements to make THE FRIEND arc work:
|
|
|
|
| Requirement | Topic | System | Priority |
|
|
|-------------|-------|--------|----------|
|
|
| Testimony creates EntityKnowledge with ToldBy source | 1 | KnowledgeGrant schema | Critical — blocks contradiction detection |
|
|
| NPCs cannot grant knowledge they don't hold | 1 | Content validation | High — authoring integrity |
|
|
| POI knowledge via `poi.*` FactId | 1 | KnowledgeGrant schema | Medium |
|
|
| Trust-gated NPC-to-NPC sharing with Major secret override | 2 | Propagation model | High — prevents secret leakage |
|
|
| Overheard conversations always grant Suspects confidence | 2 | Event model | High — preserves investigation motivation |
|
|
| Unprompted disclosure uses Option A (NPC checks own KG only) | 3 | Disclosure algorithm | Critical — enables dramatic irony |
|
|
| Location privacy gates unprompted disclosure | 3 | Trigger conditions | High — spatial behavior patterns |
|
|
| Per-fact cooldown prevents disclosure repetition | 3 | Rate limiting | High — NPC authenticity |
|
|
| tell_state KG awareness (secret exposure intensity) | 4 | tell_state.rs retrofit | High — behavioral authenticity |
|
|
| Contradiction monologue names the source entity | 5 | Content system | Critical — emotional payoff |
|
|
| Both contradiction entries marked (epistemic neutrality) | 5 | Detection algorithm | Critical — no premature accusation |
|
|
| Authored attribute contradiction pairs | 5 | Schema | Medium |
|
|
|
|
The three "Critical" items are preconditions for D-027 success criterion #3 ("player names an NPC they felt conflicted about"). If testimony doesn't create ToldBy EntityKnowledge, contradiction detection cannot fire on THE FRIEND arc. If Option B is chosen for unprompted disclosure, the dramatic irony that makes Sera's contradiction land is destroyed. If the contradiction monologue is generic and nameless, the emotional moment dissipates into noise.
|
|
|
|
Everything else can be iterated. These three cannot.
|