docs(wiki): establish Sova Transit District game world glossary

45 files covering the v0.1 vertical slice content: 17 NPC profiles
across 3 tiers, 5 triangles, 3 social sites, 7 factions, 6 technology
entries, 3 contraband types, knowledge vocabulary (FactIds, entity
attributes, relationship states), and monologue authoring guide.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-12 16:18:49 +01:00
co-authored by Claude Opus 4.6
parent 84b3035945
commit 3776443e8a
45 changed files with 7981 additions and 0 deletions
+301
View File
@@ -0,0 +1,301 @@
# Entity Knowledge Attributes
Canonical keys for the `EntityKnowledge.known_attributes` BTreeMap (defined in `server/src/knowledge/types.rs`). These keys structure what one entity knows about another.
## Overview
`EntityKnowledge.known_attributes` is a `BTreeMap<String, String>` — key-value pairs where:
- **Key**: Structured attribute name (defined below)
- **Value**: String representation of the attribute
The knowledge graph uses these attributes to determine:
- What the observer's monologue says about the target
- Which dialogue lines are available
- How the target renders in the observer snapshot (name vs. description)
- Whether secrets or contradictions are discovered
---
## Identity Attributes
### `name`
**Value format**: Full name as known to the observer.
**Examples**:
- `"Kael Davan"` — observer knows full name
- `"Kael"` — observer knows first name only
- `"the dock worker"` — observer doesn't know name, only role
**Usage**: Monologue and dialogue rendering. If `name` is absent or generic, monologue says "the dock worker" instead of "Kael."
---
### `role`
**Value format**: Occupational or social role.
**Examples**:
- `"dock worker"`
- `"shift supervisor"`
- `"bartender"`
- `"off-duty security"`
- `"ring coordinator"` (if known)
**Usage**: Default descriptor when name is unknown. Access tier calculation (authority figures get different treatment).
---
### `faction`
**Value format**: Institutional or organizational allegiance.
**Examples**:
- `"Commission"` — Sera, Torek, Detective
- `"civilian"` — most NPCs
- `"ring member"` — if discovered
- `"unknown"` — not yet determined
**Usage**: Access tier logic. Commission-tagged individuals trigger different NPC behavior. Dialogue selection uses this for authority/peer filtering.
---
### `species`
**Value format**: Species identifier (future-proofing — v0.1 is all human).
**Examples**:
- `"human"` (default)
- (Future: other species as defined)
**Usage**: Not load-bearing in v0.1. Placeholder for future non-human NPCs.
---
## Social Attributes
### `relationship_type`
**Value format**: Relationship category from observer's perspective.
**Examples**:
- `"colleague"` — Kael to smuggler
- `"friend"` — Sera to detective
- `"authority figure"` — Voss to subordinates
- `"suspect"` — Kael to detective (post-discovery)
- `"partner"` — Hael to Kael
- `"stranger"` — new NPCs
**Usage**: Drives `RelationshipState` calculation (Unknown/Known/Friendly/PersonOfInterest/Hostile). Determines emotional tone of monologue.
---
### `trust_level`
**Value format**: Trust assessment (subjective, observer's judgment).
**Examples**:
- `"trusted"` — high trust, shares sensitive information
- `"reliable"` — professional trust
- `"uncertain"` — cautiously neutral
- `"suspicious"` — flagged for observation
- `"compromised"` — known to be under pressure or bought
**Usage**: Gates trust-tier dialogue (surface/real/secret). Detective tracking trust levels determines which NPCs can be turned.
---
## Behavioral Attributes
### `routine_pattern`
**Value format**: Observed routine description.
**Examples**:
- `"morning shift at logistics hub, bar after shift"`
- `"arrives 06:00, break 10:30, departs 14:00"`
- `"irregular schedule, seen at odd hours"`
**Usage**: Deviation detection. When current behavior doesn't match known `routine_pattern`, monologue flags it.
---
### `behavior_flags`
**Value format**: Comma-separated behavioral observations.
**Examples**:
- `"nervous,lattice_checking"` — Kael during contradiction arc
- `"avoidance_pattern,evasive"` — Sera avoiding Torek
- `"spending_beyond_means"` — Torek buying rounds
- `"reliable,punctual"` — baseline normal behavior
**Usage**: Tell system. Multiple flags accumulate as evidence. Detective's analytical lattice auto-flags some behaviors.
---
## Secret Attributes
### `secret_held`
**Value format**: What the observer believes this entity is hiding.
**Examples**:
- `"ring membership"` — detective's suspicion about Kael
- `"unreported evidence"` — smuggler's read on Sera (if observant)
- `"gambling debt"` — if Drin's vulnerability is discovered
- `"exit attempt"` — if Kael's unauthorized contact is discovered
**Usage**: Drives PersonOfInterest state. Gates confrontation dialogue. Smuggler and detective track different secrets about the same NPCs.
---
### `secret_confidence`
**Value format**: How certain the observer is about the secret.
**Examples**:
- `"suspected"` — behavioral flags suggest something, no proof
- `"likely"` — multiple indicators align
- `"confirmed"` — direct evidence or confession
**Usage**: Dialogue tone. "Suspected" secrets allow fishing questions. "Confirmed" secrets enable direct confrontation.
---
## Investigation Attributes (Detective-Specific)
### `tell_observed`
**Value format**: Specific tell noted by the detective.
**Examples**:
- `"looks left when lying"` — Kael's tell
- `"leaves when Torek arrives"` — Sera's avoidance
- `"checks lattice before answering"` — nervous behavior
- `"forced casualness after shift supervisor passes"` — hypervigilance
**Usage**: Behavioral profiling. Accumulated tells build case strength. Monologue references specific tells when they recur.
---
### `contradiction_flagged`
**Value format**: Boolean-ish flag (presence of key = true).
**Examples**:
- `"meeting_unknown_contact"` — Kael contradiction
- `"avoidance_inconsistency"` — Sera contradiction
- `"manifest_access_mismatch"` — Maret handling cargo she shouldn't process
**Usage**: THE FRIEND arc trigger. When this attribute is set, monologue tone shifts. Dialogue options change. RelationshipState moves toward PersonOfInterest.
---
## Examples: Full EntityKnowledge Entries
### Smuggler's knowledge of Kael (early game, pre-contradiction)
```rust
EntityKnowledge {
last_known_position: Some(TilePosition { x: 45, y: 12 }), // logistics hub dock
last_observed_tick: 1200,
last_updated_tick: 1200,
confidence: KnowledgeConfidence::Direct, // currently in LOS
source: KnowledgeSource::DirectObservation { tick: 1200 },
state: KnowledgeState::Active,
relationship: RelationshipState::Friendly,
known_attributes: BTreeMap::from([
("name".to_string(), "Kael Davan".to_string()),
("role".to_string(), "dock worker".to_string()),
("faction".to_string(), "ring member".to_string()), // smuggler knows
("species".to_string(), "human".to_string()),
("relationship_type".to_string(), "close colleague".to_string()),
("trust_level".to_string(), "trusted".to_string()),
("routine_pattern".to_string(), "morning shift 06:00-14:00, bar after shift".to_string()),
("behavior_flags".to_string(), "reliable,punctual".to_string()),
]),
}
```
### Detective's knowledge of Kael (mid-game, post-contradiction discovery)
```rust
EntityKnowledge {
last_known_position: Some(TilePosition { x: 45, y: 12 }),
last_observed_tick: 2400,
last_updated_tick: 2600, // updated via inference after observation
confidence: KnowledgeConfidence::KnowsDetails, // not currently in LOS, but detailed knowledge
source: KnowledgeSource::Inferred {
basis: vec![
FactId("investigation.manifest_discrepancy".to_string()),
FactId("investigation.shift_mismatch".to_string()),
],
},
state: KnowledgeState::Active,
relationship: RelationshipState::PersonOfInterest, // flagged
known_attributes: BTreeMap::from([
("name".to_string(), "Kael Davan".to_string()),
("role".to_string(), "dock worker".to_string()),
("faction".to_string(), "civilian".to_string()), // detective doesn't know ring membership yet
("species".to_string(), "human".to_string()),
("relationship_type".to_string(), "suspect".to_string()),
("trust_level".to_string(), "suspicious".to_string()),
("routine_pattern".to_string(), "morning shift, frequent late departures".to_string()),
("behavior_flags".to_string(), "nervous,lattice_checking,evasive".to_string()),
("tell_observed".to_string(), "looks left when lying".to_string()),
("secret_held".to_string(), "unauthorized meetings".to_string()),
("secret_confidence".to_string(), "confirmed".to_string()),
("contradiction_flagged".to_string(), "meeting_unknown_contact".to_string()),
]),
}
```
### Smuggler's knowledge of Sera (if observant, mid-game)
```rust
EntityKnowledge {
last_known_position: Some(TilePosition { x: 78, y: 34 }), // bar
last_observed_tick: 1800,
last_updated_tick: 2100,
confidence: KnowledgeConfidence::KnowsOf,
source: KnowledgeSource::DirectObservation { tick: 1800 },
state: KnowledgeState::Active,
relationship: RelationshipState::Known, // not Friendly -- smuggler doesn't know Sera well
known_attributes: BTreeMap::from([
("name".to_string(), "Sera Venn".to_string()),
("role".to_string(), "Commission field tech".to_string()),
("faction".to_string(), "Commission".to_string()),
("species".to_string(), "human".to_string()),
("relationship_type".to_string(), "institutional presence".to_string()),
("trust_level".to_string(), "uncertain".to_string()),
("routine_pattern".to_string(), "bar regular, off-duty evenings".to_string()),
("behavior_flags".to_string(), "observant,avoidance_pattern".to_string()),
("secret_held".to_string(), "knows something about Torek or Hael".to_string()),
("secret_confidence".to_string(), "suspected".to_string()),
]),
}
```
---
## Attribute Lifecycle
1. **Initial state** (Unknown NPC): No attributes. EntityKnowledge doesn't exist yet.
2. **First observation** (Direct confidence): `name` (if visible via lattice query or introduction), `role` (inferred from context), `species`, `routine_pattern` starts accumulating.
3. **Repeated interaction** (KnowsOf): `relationship_type` evolves, `trust_level` set, `behavior_flags` accumulate.
4. **Investigation depth** (KnowsDetails): `secret_held`, `tell_observed`, `contradiction_flagged` added by detective. Smuggler gains `faction` clarity.
5. **Knowledge decay**: Attributes persist even as confidence decays. A KnowsOf entry retains all attributes; only positional certainty degrades.
---
## Content Authoring Guidance
- **Monologue prerequisites** can reference specific attributes: `known_attributes["secret_held"] == "ring membership"`.
- **Dialogue access tiers** can check `faction` or `relationship_type`.
- **Tell system observations** append to `behavior_flags` as comma-separated values.
- **THE FRIEND contradiction** is triggered by setting `contradiction_flagged`.
---
**Total canonical keys**: 14 (4 identity, 2 social, 2 behavioral, 2 secret, 2 investigation, 2 detective-specific). Additional keys can be added as needed, but these 14 cover v0.1 requirements.
+311
View File
@@ -0,0 +1,311 @@
# Knowledge Fact Catalog
Canonical FactIds for the v0.1 vertical slice. All facts follow the `category.topic` format defined in `server/src/knowledge/types.rs`.
## Format
- **FactId**: String identifier (e.g., `"contraband.ring_exists"`)
- **Progression**: Text descriptions at each KnowledgeConfidence level
- **Mechanical Purpose**: What this fact gates in dialogue, monologue, or investigation
---
## Contraband Facts
### `contraband.ring_exists`
**Suspects**: "Something's going on with the cargo schedules. Too many off-manifest deliveries."
**KnowsOf**: "There's a smuggling operation running through the logistics hub."
**KnowsDetails**: "The ring moves unlicensed lattice components during shift transitions. Voss manages the timing."
**Direct**: N/A (abstract knowledge — never directly observed)
**Mechanical Purpose**: Gates investigation dialogue trees. Required for ring-specific monologue. The detective starts at Suspects and escalates. The smuggler (if playing the ring member path) starts at KnowsDetails.
---
### `contraband.lattice_components`
**Suspects**: "That container's marked as standard components, but the mass is wrong."
**KnowsOf**: "Unlicensed lattice components. Aftermarket mods that bypass Commission certification."
**KnowsDetails**: "Medical-grade neural lattice replacements diverted from Syndic supply chains, plus enhanced capability mods."
**Direct**: "I'm looking at a crate of lattice components right now. Serial numbers don't match any certified batch."
**Mechanical Purpose**: Contraband identification. Detective needs KnowsOf to correctly interpret manifest discrepancies. Smuggler needs KnowsDetails to handle cargo safely.
---
### `contraband.medical_grade`
**Suspects**: "Some of this cargo doesn't feel like luxury goods."
**KnowsOf**: "Medical-grade lattice replacements. For people whose lattices are degrading and who can't afford Syndic pricing."
**KnowsDetails**: "The ring moves medical replacements for people locked out of the institutional system. It's not just profit — it's healthcare."
**Direct**: N/A (conceptual understanding)
**Mechanical Purpose**: Moral complexity gate. Smuggler monologue shifts tone when this reaches KnowsDetails. Detective dialogue with humanitarian-focused NPCs requires KnowsOf.
---
### `contraband.severance_tech`
**Suspects**: "Sealed containers Nils won't discuss. Heavier than lattice components."
**KnowsOf**: "Severance equipment. Counter-surveillance tech. Illegal across most of the Reach."
**KnowsDetails**: "Guardians of Severance supply chain. This isn't local — it's connected to something bigger."
**Direct**: N/A (not directly visible in v0.1)
**Mechanical Purpose**: Contamination seed for storyteller expansion. The thing that makes the smuggler question how deep the ring goes.
---
### `contraband.supply_chain`
**Suspects**: "The cargo doesn't originate on this station."
**KnowsOf**: "Off-station coordinator manages incoming shipments. Someone named Sabel."
**KnowsDetails**: "Supply chain: aftermarket manufacturers (Syndic-adjacent) -> freight networks -> Sabel (off-station) -> ring coordinator (Devra or Nils) -> local distribution."
**Direct**: N/A (network knowledge)
**Mechanical Purpose**: Investigation depth. Detective at KnowsDetails can map the full chain. Smuggler at KnowsDetails understands their position in the network.
---
## Location Facts
### `location.corridor_b7_restricted`
**Suspects**: "Corridor B-7 should see foot traffic during shift change. It's empty."
**KnowsOf**: "Maintenance corridor used for smuggling operations. Access requires hub clearance."
**KnowsDetails**: "Corridor B-7 is between old and new prefab sections. Service hatch from break room. The ring routes shipments through here during shift transitions."
**Direct**: "I'm in Corridor B-7 right now. Old construction smell, minimal Meridian coverage, no surveillance."
**Mechanical Purpose**: Spatial knowledge. Required for investigation progression (detective) and operational planning (smuggler). Direct confidence gates monologue about current surroundings.
---
### `location.smuggling_route`
**Suspects**: "Cargo movements don't match the official routing."
**KnowsOf**: "The ring uses a specific path: freight bay -> service corridor -> temporary storage -> bar district back room."
**KnowsDetails**: "Timing is critical. The route only works during shift transition when patrol coverage thins. Lera provides the final handoff point."
**Direct**: "Watching the route right now. Kosse moving a container through the service hatch."
**Mechanical Purpose**: Investigation mechanics. Detective needs KnowsOf to predict NPC movements. Smuggler needs KnowsDetails for operational participation.
---
### `location.surveillance_gaps`
**Suspects**: "Some areas feel less monitored than others."
**KnowsOf**: "Meridian coverage degrades in older sections. Maintenance corridors have minimal surveillance."
**KnowsDetails**: "Corridor B-7, break room service hatch, bar back room — all Meridian dead spots. The ring exploits these systematically."
**Direct**: "Checking my lattice overlay now. Zero Meridian signal in this section."
**Mechanical Purpose**: Stealth and observation mechanics. Detective's augmented lattice can detect coverage gaps (requires KnowsOf). Smuggler uses gaps operationally (requires KnowsDetails).
---
### `location.dead_drop_location`
**Suspects**: "Kael leaves things in the break room locker area. Not his own locker."
**KnowsOf**: "Locker 47 in the hub break room. Unofficial dead drop for small items."
**KnowsDetails**: "Locker 47 is registered to a worker who transferred off-station 18 months ago. Never reassigned. The ring has used it ever since."
**Direct**: "Locker 47 is open. There's a sealed packet inside."
**Mechanical Purpose**: Discovery mechanic. Detective can discover through observation (Suspects -> KnowsOf). Smuggler knows from background (starts at KnowsDetails).
---
## Investigation Facts
### `investigation.manifest_discrepancy`
**Suspects**: "Cargo manifests have inconsistencies. Weight doesn't match volume."
**KnowsOf**: "Systematic manifest doctoring. Someone with freight scheduler access is altering records."
**KnowsDetails**: "Maret Korr processes manifests. She's noticed the discrepancies but hasn't reported them. She's either complicit or terrified."
**Direct**: "Comparing the manifest right now. Container 4471 — logged weight 240kg, actual weight closer to 310kg."
**Mechanical Purpose**: Core investigation mechanic. Detective's analytical lattice flags discrepancies at Suspects. Full understanding requires KnowsDetails. Smuggler knows Maret's position from background.
---
### `investigation.shift_mismatch`
**Suspects**: "Night shift schedules don't align with freight volume."
**KnowsOf**: "Voss adjusts shift schedules to create coverage gaps. Deliberate understaffing during high-risk windows."
**KnowsDetails**: "Shift mismatches occur every third rotation. Coincides exactly with off-station shipment arrivals. Voss takes a cut."
**Direct**: "Checking the current schedule. Night shift is short two workers — again."
**Mechanical Purpose**: Pattern recognition. Detective needs KnowsOf to connect schedule to smuggling. Smuggler knows the pattern operationally.
---
### `investigation.cargo_anomaly`
**Suspects**: "That container sat in temporary storage for 18 hours. Standard procedure is 4-6 hours max."
**KnowsOf**: "Delayed processing indicates off-manifest handling. Someone's buying time to repackage cargo."
**KnowsDetails**: "Nils coordinates timing. Container arrives, sits in temp storage during shift A, gets repackaged during shift B transition, moves out during shift C startup."
**Direct**: "Container 4471 has been sitting here for 14 hours. No movement orders logged."
**Mechanical Purpose**: Observation-based discovery. Detective builds case from Suspects upward. Smuggler knows the workflow (starts KnowsDetails).
---
### `investigation.evidence_collected`
**Suspects**: N/A (binary fact — you either have evidence or you don't)
**KnowsOf**: "I have documented manifest discrepancies, shift schedule anomalies, and witness testimony from Drin."
**KnowsDetails**: "Full case file: manifest logs, Drin's testimony under pressure, Maret's reluctant cooperation, surveillance footage from observation gallery showing Corridor B-7 access."
**Direct**: N/A (abstract accumulation)
**Mechanical Purpose**: Investigation state tracker. Gates confrontation dialogue. Detective-specific — smuggler doesn't collect evidence against themselves.
---
## World Facts
### `world.commission_regulations`
**Suspects**: "The Commission regulates lattice technology. That's why people want aftermarket mods."
**KnowsOf**: "Commission certification is expensive and slow. Category 3 violation for unauthorized lattice modification carries fines and potential lattice restriction."
**KnowsDetails**: "Commission monopoly prices most citizens out of enhanced capability. Medical-grade replacements require 6-12 month approval cycles. The black market exists because the legitimate system fails."
**Direct**: N/A (regulatory knowledge)
**Mechanical Purpose**: Moral framing. Smuggler at KnowsDetails has ideological justification. Detective at KnowsDetails understands why the ring has community support.
---
### `world.syndic_supply_chain`
**Suspects**: "The cargo originates from Syndic-controlled systems."
**KnowsOf**: "Syndics manufacture medical-grade lattice components. Diverted shipments end up on the black market."
**KnowsDetails**: "Specific Syndic: unclear, but the serial number patterns suggest two sources. The ring doesn't control the supply chain — they're downstream distributors."
**Direct**: N/A (network knowledge)
**Mechanical Purpose**: Political context. Detective at KnowsDetails realizes the ring is small-scale. Smuggler at KnowsDetails understands their position in the larger economy.
---
### `world.sova_district_layout`
**Suspects**: "The district is a mix of old and new construction."
**KnowsOf**: "40-year-old prefab base with retrofitted partitions. Logistics hub, bar district, residential sections. Meridian coverage is uneven."
**KnowsDetails**: "Older sections have hidden spaces between wall layers. Service corridors from original construction still exist but aren't on current maps. The ring exploits architectural legacy."
**Direct**: "I'm looking at the district map overlay right now. Official layout vs. actual structure don't match in Section 3."
**Mechanical Purpose**: Navigation and investigation. Detective needs KnowsDetails to find hidden spaces. Smuggler starts with KnowsOf (knows layout from living here).
---
### `world.shift_schedule`
**Suspects**: "Logistics hub runs three shifts: morning, day, night."
**KnowsOf**: "Shift transitions are 30-minute windows with reduced oversight. Ring operations happen during transitions."
**KnowsDetails**: "Shift A: 06:00-14:00. Shift B: 14:00-22:00. Shift C: 22:00-06:00. Transition windows: 13:30-14:30, 21:30-22:30, 05:30-06:30. Voss manages the schedule."
**Direct**: "Current time: 21:45. Shift transition active. Observing movement patterns."
**Mechanical Purpose**: Temporal mechanics. Required for NPC routine prediction and investigation timing. Smuggler starts KnowsDetails. Detective learns through observation.
---
## Relationship Facts
### `relationship.ring_membership`
**Suspects**: "Kael's behavior suggests involvement in something off-book."
**KnowsOf**: "Kael is a ring member. Mid-level, handles physical cargo."
**KnowsDetails**: "Ring structure: Devra or Nils coordinate, Voss provides scheduling cover, Kael and Kosse handle cargo, Lera provides handoff point, Pell is wavering."
**Direct**: "Watching Kael move a container right now. Ring operation in progress."
**Mechanical Purpose**: Social knowledge. Detective builds this through investigation. Smuggler knows from shared membership (if on that path) or observation.
---
### `relationship.kael_hael_connection`
**Suspects**: "Kael mentions a partner. Someone named Hael."
**KnowsOf**: "Kael's partner is Hael, a teacher. They're worried about Kael's late nights."
**KnowsDetails**: "Hael confides in Sera Venn. Sera knows something is wrong but hasn't reported it. The worry is contaminating Kael's operational security."
**Direct**: N/A (relationship knowledge)
**Mechanical Purpose**: Emotional leverage. Detective can use Hael as pressure point. Smuggler (if Kael's friend) must protect Hael from knowledge.
---
### `relationship.trust_network`
**Suspects**: "People here know each other. Tight social bonds."
**KnowsOf**: "The ring depends on trust networks: Kael trusts Nils (sibling), Lera trusts the regulars, Drin is compromised by debt to Harek."
**KnowsDetails**: "Trust map: Kael <-> Nils (blood), Kael <-> Hael (partnership), Hael <-> Sera (friendship), Sera <-> Detective (professional/personal), Drin -> Harek (debt), Voss -> Devra/Nils (financial)."
**Direct**: N/A (social network knowledge)
**Mechanical Purpose**: Social manipulation mechanics. Detective at KnowsDetails can exploit trust fractures. Smuggler at KnowsDetails knows whom to protect.
---
### `relationship.faction_allegiance`
**Suspects**: "Some people here are Commission-aligned. Others resent the Commission."
**KnowsOf**: "Sera is Commission. Torek Lintar is nominally Commission but lives here. The detective represents institutional authority. Everyone else is civilian."
**KnowsDetails**: "Faction tensions: Commission (Sera, Torek, Detective) vs. ring (Kael, Nils, Kosse, Voss, Lera) vs. civilians (Hael, Maret, Drin, Resha). Drin is compromised between civilian and Commission."
**Direct**: N/A (political knowledge)
**Mechanical Purpose**: Access tier logic. Explains why NPCs treat characters differently. Detective at KnowsDetails understands institutional barriers.
---
## Progress Facts (Arc State Tracking)
### `progress.initial_suspicion`
**Suspects**: "Something feels off about this place."
**KnowsOf**: "There's a pattern here. Cargo discrepancies, nervous NPCs, evasive answers."
**KnowsDetails**: "Smuggling operation confirmed. Now I need to identify the participants and build a case."
**Direct**: N/A (meta-knowledge)
**Mechanical Purpose**: Detective arc state. Gates monologue tone shifts. Smuggler doesn't track this (they start knowing the operation exists).
---
### `progress.active_investigation`
**Suspects**: N/A (binary — investigation is active or it isn't)
**KnowsOf**: "I'm building a case. Evidence collected, witnesses identified, patterns mapped."
**KnowsDetails**: "Case file: manifest logs, Drin testimony, Maret's reluctant cooperation, surveillance data, NPC behavioral analysis. Ready to escalate."
**Direct**: N/A (meta-knowledge)
**Mechanical Purpose**: Detective arc state. Gates confrontation options. Changes NPC dialogue (they know they're being investigated).
---
### `progress.confrontation_ready`
**Suspects**: N/A
**KnowsOf**: "I have enough to confront specific NPCs. Kael, Voss, or Lera."
**KnowsDetails**: "Full case built. Can confront the ring, turn an informant, or escalate to Commission enforcement."
**Direct**: N/A (meta-knowledge)
**Mechanical Purpose**: Detective endgame gate. Smuggler equivalent: `progress.operation_compromised` (not listed here — detective-specific arc).
---
### `progress.arc_resolved`
**Suspects**: N/A
**KnowsOf**: N/A
**KnowsDetails**: "The arc has concluded. Ring dismantled, informant turned, or operation escaped. Outcome determined."
**Direct**: N/A (meta-knowledge)
**Mechanical Purpose**: Arc completion tracker. Used by storyteller to determine whether new modules can activate.
---
## Usage Notes
- **FactId strings** must match exactly. `"contraband.ring_exists"` not `"contraband.ring_exist"` or `"Ring Exists"`.
- **Confidence levels** are ordered: Suspects < KnowsOf < KnowsDetails < Direct. Use `KnowledgeConfidence::decayed()` for time-based degradation.
- **Direct confidence** is perception-system-managed. Content authors rarely set this manually — it's automatically assigned when an entity/location is in the observer's LOS.
- **Abstract facts** (e.g., `contraband.ring_exists`, `world.commission_regulations`) never reach Direct — they're conceptual, not observable.
- **Spatial facts** (e.g., `location.corridor_b7_restricted`) can reach Direct when the observer is physically present.
- **Progression text** is for content authoring reference, not runtime display. Monologue lines reference these facts as prerequisites; they don't display the progression text directly.
---
**Total FactIds**: 24 (5 contraband, 4 location, 4 investigation, 4 world, 4 relationship, 4 progress). Sufficient for v0.1 vertical slice. Expandable by adding new categories or topics within existing categories.
+332
View File
@@ -0,0 +1,332 @@
# Relationship States and Transitions
How `RelationshipState` (defined in `server/src/knowledge/types.rs`) evolves during gameplay, with specific patterns for THE FRIEND contradictions and KnowledgeState integration.
## Canonical States
From `server/src/knowledge/types.rs`:
```rust
pub enum RelationshipState {
Unknown, // Teal #4a9ebb
Known, // Soft green #6bc9a6
Friendly, // Soft green #6bc9a6 (same color, different semantics)
PersonOfInterest, // Amber #e8c547
Hostile, // Red #d45d5d
}
```
**Visual rendering**: D-033 entity color system. The client maps these states to colors. The knowledge graph determines the state.
---
## State Semantics
### Unknown
**What it means**: No prior knowledge of this entity. First encounter.
**Monologue tone**: Observational, neutral. "Who's that?"
**Dialogue availability**: Public-tier only. No trust-gated content.
**Color**: Teal — visually distinct from all other states.
**Typical duration**: First 30 seconds to 2 minutes of gameplay (until first direct interaction or lattice query).
---
### Known
**What it means**: Recognized, neutral-to-positive. Not a threat, not a close ally.
**Monologue tone**: Casual acknowledgment. "There's Drin. Maintenance tech."
**Dialogue availability**: Public + peer-tier (if appropriate). No insider/secret content yet.
**Color**: Soft green — "safe enough."
**Typical entities**: Coworkers (smuggler), routine contacts (detective), flat NPCs, bar regulars.
---
### Friendly
**What it means**: Positive relationship, trusted. Emotional connection or reliable professional rapport.
**Monologue tone**: Warm, personal. "Good to see Kael. Always reliable."
**Dialogue availability**: Public + peer + insider-tier. Trust-gated content unlocks. Some secret-tier content if relationship deepens.
**Color**: Soft green (same as Known — the distinction is semantic, not visual).
**Typical entities**: THE FRIEND NPCs (Kael to smuggler, Sera to detective), close colleagues, trusted contacts.
**Why same color as Known**: Visual simplicity for v0.1. Future refinement could add subtle shader variation (warmth, pulse, saturation).
---
### PersonOfInterest
**What it means**: Flagged. Something's wrong. Under observation or suspicion.
**Monologue tone**: Analytical, cautious. "Kael's meeting someone I don't recognize. That's not normal."
**Dialogue availability**: Shifts. Trust-gated content may become unavailable. Confrontation options unlock.
**Color**: Amber — "pay attention."
**Typical entities**: NPCs caught in contradictions, suspects under investigation, people who've triggered tells.
**THE FRIEND trigger**: When THE FRIEND's contradiction is discovered, they transition from Friendly → PersonOfInterest. This is the emotional gut-punch moment.
---
### Hostile
**What it means**: Character KNOWS there is danger. Threat confirmed.
**Monologue tone**: Alarm, threat assessment. "That's security. They're moving toward me."
**Dialogue availability**: Hostile-tier only (threats, demands, final warnings). All trust content locked.
**Color**: Red — "danger."
**Typical entities**: NPCs who've turned on the player, authority figures during a confrontation gone bad, exposed ring members cornered by the detective.
**Rare in v0.1**: Most NPCs don't reach Hostile. It's the endgame state for failed social maneuvering.
---
## Transition Paths
### Standard Progression (No Contradiction)
```
Unknown → Known → Friendly
```
**Triggers**:
- Unknown → Known: First direct interaction OR lattice query identifies them.
- Known → Friendly: Repeated positive interactions, shared drinks at bar, successful cooperation, trust-building dialogue.
**Example**: Detective meets a bar regular. Unknown (first visit) → Known (second visit, exchanged names) → Friendly (third visit, regular offers unprompted gossip).
---
### Investigation Progression (Detective)
```
Unknown → Known → PersonOfInterest → Hostile (if confrontation fails)
```
**Triggers**:
- Unknown → Known: Lattice query, case file match, first observation.
- Known → PersonOfInterest: Behavioral flags accumulate, tells observed, manifest discrepancy linked to this NPC.
- PersonOfInterest → Hostile: Confrontation attempt rejected, NPC realizes they're under investigation, escalation.
**Example**: Detective observes Kael. Unknown (first sight) → Known (lattice query: "Davan, K., dock worker") → PersonOfInterest (observed in restricted corridor, evasive answers) → Hostile (confrontation: "I know you're involved. You need to cooperate." / Kael: "Stay away from me.").
---
### THE FRIEND Contradiction Arc (Kael — Smuggler's Perspective)
```
Friendly → PersonOfInterest → [resolution: Friendly-but-contaminated OR Hostile]
```
**Phase 1: Friendly (baseline)**
- Kael is the smuggler's trusted colleague.
- Monologue: fond, casual.
- Color: soft green.
- Dialogue: insider-tier, warm.
**Phase 2: First Crack (still Friendly, but flags accumulating)**
- Behavioral flags: `lattice_checking,distracted`.
- Monologue shifts slightly: "Kael's been quiet lately."
- State unchanged (still Friendly), but `EntityKnowledge.known_attributes["behavior_flags"]` updates.
**Phase 3: The Contradiction (Friendly → PersonOfInterest)**
- Trigger: Direct observation of Kael meeting unknown contact in Corridor B-7.
- `EntityKnowledge.known_attributes["contradiction_flagged"] = "meeting_unknown_contact"`.
- `RelationshipState` transitions to `PersonOfInterest`.
- Color shifts: soft green → amber.
- Monologue: "That wasn't anyone from our rotation. Kael, what are you doing?"
- Dialogue options change: confrontation unlocks, trust-tier content locks (Kael is evasive).
**Phase 4: Post-Confrontation**
- **Path A (understanding)**: Smuggler confronts Kael gently. Kael confesses: trying to exit the ring to protect Hael. `RelationshipState` remains `PersonOfInterest` but monologue tone shifts to conflicted sympathy. Color stays amber (still a problem), but dialogue reflects empathy.
- **Path B (betrayal)**: Smuggler reports Kael to Nils or pressures Kael harshly. Kael turns defensive. `RelationshipState` → `Hostile`. Color → red. Kael avoids the smuggler, might actively obstruct.
**THE FRIEND pattern**: Friendly → PersonOfInterest is the emotional core. The player trusted Kael. Now Kael is amber. That color shift IS the narrative moment.
---
### THE FRIEND Contradiction Arc (Sera — Detective's Perspective)
```
Friendly → PersonOfInterest → [resolution: Friendly-but-contaminated OR Known-distanced OR Hostile]
```
**Phase 1: Friendly (baseline)**
- Sera is the detective's institutional contact and social anchor.
- Monologue: professional warmth, relief.
- Color: soft green.
- Dialogue: peer-tier, cooperative, helpful.
**Phase 2: Pattern Observation (still Friendly, but flags accumulating)**
- Behavioral flags: `avoidance_pattern` (Sera leaves when Torek arrives).
- Monologue: "That's the third time. Sera leaves when Torek shows up."
- State unchanged (still Friendly), but `EntityKnowledge.known_attributes["behavior_flags"]` updates.
**Phase 3: The Contradiction (Friendly → PersonOfInterest)**
- Trigger: Detective asks Sera directly about Torek. Sera deflects unconvincingly.
- `EntityKnowledge.known_attributes["contradiction_flagged"] = "avoidance_inconsistency"`.
- `EntityKnowledge.known_attributes["secret_held"] = "unreported evidence"` (detective's inference).
- `RelationshipState` transitions to `PersonOfInterest`.
- Color shifts: soft green → amber.
- Monologue: "She's not lying. But she's not telling me everything. Sera, what do you know?"
- Dialogue options change: pressing questions unlock, casual warmth diminishes.
**Phase 4: Post-Confrontation**
- **Path A (loyalty test)**: Detective confronts Sera about concealment. Sera confesses: sitting on evidence to protect Hael (friend of Sera, partner of Kael). Detective can choose: report Sera (Hostile), use the information without reporting her (PersonOfInterest → Known, relationship damaged), or protect Sera and accept the information gap (PersonOfInterest → Friendly-but-contaminated).
- **Path B (institutional)**: Detective reports Sera immediately. `RelationshipState` → `Hostile`. Sera is reprimanded or reassigned. Color → red. The detective loses their only local ally.
**THE FRIEND pattern**: The detective's trust in Sera is tested. Amber means "my friend is hiding something." The resolution determines whether the friendship survives.
---
## Contradiction Patterns: Kael + Sera
Both THE FRIEND NPCs follow the same structural arc, but the **nature of the contradiction differs**:
| Dimension | Kael (Smuggler's FRIEND) | Sera (Detective's FRIEND) |
|-----------|--------------------------|---------------------------|
| **Contradiction type** | Spatial deviation (meeting unknown contact) | Behavioral avoidance (leaving when Torek arrives) |
| **Discovery method** | Direct observation in restricted area | Pattern recognition over multiple visits |
| **What they're hiding** | Attempt to exit the ring (protect Hael) | Unreported evidence (protect Hael) |
| **Sympathetic motivation** | Family protection (Hael is Kael's partner) | Friendship loyalty (Hael is Sera's friend) |
| **Hael as connection** | Kael's personal life | Sera's social network |
| **Color shift timing** | Single observation event (immediate) | Third occurrence (cumulative) |
| **Confrontation stakes** | Ring security vs. personal loyalty | Institutional duty vs. personal loyalty |
| **Resolution spectrum** | Understanding ↔ Betrayal | Protect friend ↔ Report corruption |
**Common structure**: Both contradictions involve **Hael** as the emotional anchor. Hael is worried about Kael. Sera knows why (unreported evidence). Kael is trying to protect Hael (exit attempt). The smuggler and detective approach the same NPC web from opposite sides. THE FRIEND, in both cases, is the person caught in the middle trying to protect someone they care about.
---
## KnowledgeState Integration
`RelationshipState` (social assessment) is **orthogonal to** `KnowledgeState` (logical validity).
### Active (default)
**What it means**: The knowledge is currently believed true.
**Effect on relationship**: None directly. A Friendly NPC with Active knowledge remains Friendly.
**Example**: Smuggler's knowledge of Kael as "trusted colleague" is Active until the contradiction.
---
### Contradicted
**What it means**: Conflicting information exists. Both the original belief and the contradiction receive this state.
**Effect on relationship**: **This is the trigger for Friendly → PersonOfInterest.**
When `KnowledgeState` becomes `Contradicted`, the system:
1. Sets `EntityKnowledge.state = KnowledgeState::Contradicted` on the conflicting knowledge entries.
2. Triggers a monologue event: "Wait, that doesn't match what I thought I knew."
3. Evaluates `RelationshipState` transition. If the contradicted knowledge is about a Friendly NPC, transition to PersonOfInterest.
**Example**: Smuggler's knowledge "Kael operates within ring protocol" contradicts with new observation "Kael meeting unauthorized contact." Both entries become `Contradicted`. Monologue fires. Kael's `RelationshipState` → `PersonOfInterest`.
---
### Stale
**What it means**: Knowledge has aged beyond the stale threshold (default 3600 ticks = 6 game-hours).
**Effect on relationship**: Degrades confidence but doesn't change relationship state. A Friendly NPC remains Friendly, but positional knowledge becomes unreliable.
**Example**: Smuggler last saw Kael at the hub 7 hours ago. `last_known_position` becomes Stale. Monologue: "Kael should be off-shift by now. Probably at the bar, but I haven't seen him."
---
## Relationship State and Dialogue Selection
The dialogue system (D-028, D-035) uses `RelationshipState` as a filter:
| Dialogue `access` tag | Unknown | Known | Friendly | PersonOfInterest | Hostile |
|-----------------------|---------|-------|----------|------------------|---------|
| `public` | ✓ | ✓ | ✓ | ✓ | ✓ |
| `peer` | ✗ | ✓ | ✓ | ✗ | ✗ |
| `insider` | ✗ | ✗ | ✓ | ✗ | ✗ |
| `authority` | ✓ (if detective) | ✓ (if detective) | ✗ | ✓ (if detective) | ✗ |
| `hostile` | ✗ | ✗ | ✗ | ✗ | ✓ |
**Key insight**: `PersonOfInterest` **locks out peer and insider content**. When THE FRIEND transitions to PersonOfInterest, trust-gated dialogue disappears. The NPC becomes guarded. This is mechanically expressed through access-tier filtering.
---
## Monologue Tone Shifts per State
### Unknown → Known
- **Before**: "Who's that?"
- **After**: "That's Drin, the maintenance tech."
**Shift**: Identification. Observer now has context.
---
### Known → Friendly
- **Before**: "Drin's over there."
- **After**: "Good to see Drin. Always fixes things without making a fuss."
**Shift**: Warmth. Personal regard.
---
### Friendly → PersonOfInterest (THE FRIEND)
- **Before**: "There's Kael. Good — I was starting to worry."
- **After**: "Kael's here. But he's been acting strange. What's going on?"
**Shift**: Doubt contaminates warmth. The fond observation is now analytical.
---
### PersonOfInterest → Hostile
- **Before**: "Kael's avoiding me. Something's wrong."
- **After**: "Kael just signaled security. He's turned on me."
**Shift**: Assessment → alarm.
---
## Implementation Notes for Content Authors
- **Contradiction discovery** sets `EntityKnowledge.state = KnowledgeState::Contradicted` AND triggers `RelationshipState` transition if applicable.
- **Monologue lines** should reference `RelationshipState` in prerequisites:
```yaml
prerequisite:
relationship_state: PersonOfInterest
subject: kael_davan
```
- **Dialogue lines** filter on `access` tier, which is derived from `RelationshipState` + character type (smuggler/detective/NPC role).
- **Color shifts** are client-side rendering, but the knowledge graph determines the state. Content authors write to the state; the client handles the color.
- **THE FRIEND arc** requires:
- Friendly baseline (relationship history)
- Observable contradiction (spatial deviation or behavioral pattern)
- `contradiction_flagged` attribute set
- Monologue shift (analytical doubt)
- Dialogue shift (confrontation options unlock, trust options lock)
- Resolution paths (multiple endings based on player choice)
---
**Total states**: 5. **Load-bearing transitions for v0.1**: Unknown → Known (universal), Known/Friendly → PersonOfInterest (THE FRIEND), PersonOfInterest → Hostile (confrontation failure). Other transitions exist but are less structurally critical.