Move wiki from docs/wiki/ to root wiki/. Add 14 category templates with YAML frontmatter, governance model, hierarchical spatial structure (system > station > district > location). Populate Krenn System entry as first concrete star system. Update cross-references in workshop and sprint docs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
420 lines
21 KiB
Markdown
420 lines
21 KiB
Markdown
---
|
|
title: "Entity Knowledge Attributes"
|
|
slug: entity-attributes
|
|
category: concept
|
|
status: canonical
|
|
created: 2026-02-12
|
|
updated: 2026-02-13
|
|
concept_type: mechanical
|
|
tags: []
|
|
decision_refs: [D-041]
|
|
cross_refs: []
|
|
---
|
|
|
|
# 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 leverage or contradictions are discovered
|
|
- How role-perspective assessments shape the observer's internal narrative
|
|
|
|
---
|
|
|
|
## 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"` — Naia 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). This key encompasses both the read action (what the observer can observe about trust dynamics) and the state (what level of trust currently exists between observer and target). There is no separate `trust_read` key — the observation and the conclusion are stored together as a single assessment.
|
|
|
|
**Values**: `trusted`, `reliable`, `uncertain`, `suspicious`, `compromised`.
|
|
|
|
**Examples**:
|
|
- `"trusted"` — high trust, shares sensitive information
|
|
- `"reliable"` — professional trust, predictable behavior
|
|
- `"uncertain"` — cautiously neutral, still reading the relationship
|
|
- `"suspicious"` — flagged for observation, inconsistencies detected
|
|
- `"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. Smuggler uses trust levels to gauge operational reliability. The trust read (what the observer notices) and the trust state (what the observer concludes) are one assessment — the observer watches, interprets, and assigns a level in the same cognitive step.
|
|
|
|
---
|
|
|
|
## 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.
|
|
|
|
---
|
|
|
|
## Leverage Attributes
|
|
|
|
### `leverage_held`
|
|
|
|
**Value format**: What the observer believes gives them (or could give them) power over this entity. This covers secrets, debts, promises, obligations, and compromising positions — not just secrets. Any information or relationship that creates asymmetric power over the target qualifies as leverage.
|
|
|
|
**Examples**:
|
|
- `"ring membership"` — detective's suspicion about Kael (secret)
|
|
- `"unreported evidence"` — smuggler's read on Sera (concealed information)
|
|
- `"gambling debt"` — if Drin's vulnerability is discovered (financial obligation)
|
|
- `"exit attempt"` — if Kael's unauthorized contact is discovered (betrayal)
|
|
- `"owes favor to Voss"` — social obligation
|
|
- `"witnessed the handoff"` — compromising position
|
|
|
|
**Usage**: Drives PersonOfInterest state. Gates confrontation dialogue. Smuggler and detective track different leverage about the same NPCs. The broader scope (beyond secrets) allows content authors to capture debts, promises, and obligations that create power dynamics without requiring additional keys.
|
|
|
|
---
|
|
|
|
### `leverage_confidence`
|
|
|
|
**Value format**: How certain the observer is about the leverage.
|
|
|
|
**Examples**:
|
|
- `"suspected"` — behavioral flags suggest something, no proof
|
|
- `"likely"` — multiple indicators align
|
|
- `"confirmed"` — direct evidence or confession
|
|
|
|
**Usage**: Dialogue tone. "Suspected" leverage allows fishing questions. "Confirmed" leverage enables direct confrontation or exploitation.
|
|
|
|
---
|
|
|
|
## Investigation Attributes
|
|
|
|
### `tell_observed`
|
|
|
|
**Value format**: Specific tell noted by the observer.
|
|
|
|
**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.
|
|
|
|
> **Implementation note**: The server may track tells via `behavior_flags` internally, since tells are a subset of behavioral observations. `tell_observed` is retained as a documented content-authoring key because it serves a distinct narrative purpose: `behavior_flags` accumulates raw observations ("nervous,lattice_checking"), while `tell_observed` captures the observer's interpretive conclusion ("looks left when lying"). Content authors reference `tell_observed` for monologue prerequisites that require the observer to have formed a specific read on the target. The server implementation may store both, or derive `tell_observed` from `behavior_flags` pattern matching.
|
|
|
|
---
|
|
|
|
### `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.
|
|
|
|
> **Implementation note**: Like `tell_observed`, the server may track contradictions via `behavior_flags` (e.g., a flag with a `contradiction:` prefix). `contradiction_flagged` is retained as a documented key because it serves as a distinct narrative trigger — content authors check for its presence to gate arc transitions and monologue shifts. The separation keeps the content authoring interface clean even if the server implementation unifies storage.
|
|
|
|
---
|
|
|
|
## Role-Perspective Attributes
|
|
|
|
These four keys capture the observer's subjective assessment of the target through the lens of their own role, goals, and ethical framework. The same key with the same value reads differently depending on the observer's archetype — interpretation lives in the content layer (monologue pools, voice registers, archetype briefs), not in the schema. See [Archetype Interpretation Note](#archetype-interpretation-note) below.
|
|
|
|
### `risk_assessment`
|
|
|
|
**Value format**: Observer's assessment of how much danger this entity poses or attracts.
|
|
|
|
**Values**: `none`, `low`, `moderate`, `high`, `critical`.
|
|
|
|
**Examples**:
|
|
- Smuggler's assessment of Pell (wavering member) = `"high"` (unpredictable, could expose the ring)
|
|
- Detective's assessment of Voss = `"moderate"` (obstructive but not directly dangerous)
|
|
- Smuggler's assessment of Naia = `"low"` (uninvolved, unlikely to cause exposure)
|
|
|
|
**Usage**: Gates operational monologue. High-risk targets trigger cautionary internal dialogue. Critical-risk targets may trigger evasion or preemptive action. The nature of "risk" depends on the archetype (see interpretation note).
|
|
|
|
---
|
|
|
|
### `loyalty_assessment`
|
|
|
|
**Value format**: Observer's assessment of this entity's reliability and loyalty.
|
|
|
|
**Values**: `solid`, `dependable`, `uncertain`, `wavering`, `hostile`.
|
|
|
|
**Examples**:
|
|
- Smuggler's assessment of Renn (courier) = `"dependable"` (reliable, follows instructions)
|
|
- Smuggler's assessment of Kael (mid-game) = `"wavering"` (showing signs of doubt)
|
|
- Detective's assessment of Sera = `"solid"` (committed to the investigation)
|
|
|
|
**Usage**: Determines how much the observer relies on or confides in the target. Wavering loyalty triggers monitoring behavior. Hostile loyalty triggers defensive or adversarial posture.
|
|
|
|
---
|
|
|
|
### `position_integrity`
|
|
|
|
**Value format**: Observer's assessment of this entity's cover, position stability, or facade status.
|
|
|
|
**Values**: `solid`, `thin`, `cracking`, `blown`, `N/A`.
|
|
|
|
**Examples**:
|
|
- Ring member's assessment of Kael = `"thin"` (behavior changes are visible to anyone watching)
|
|
- Smuggler's self-assessment near the detective = `"cracking"` (too many close calls)
|
|
- Detective's assessment of a civilian witness = `"N/A"` (no cover to assess)
|
|
|
|
**Usage**: Tracks active deception status. When position_integrity degrades, the observer's monologue reflects increasing anxiety or strategic recalculation. `N/A` is used when the concept of cover/facade does not apply to the target.
|
|
|
|
---
|
|
|
|
### `moral_weight`
|
|
|
|
**Value format**: Observer's assessment of this entity's moral involvement in the situation.
|
|
|
|
**Values**: `innocent`, `peripheral`, `complicit`, `compromised`, `willing`.
|
|
|
|
**Examples**:
|
|
- Detective's assessment of Naia = `"innocent"` (uninvolved partner caught in the fallout)
|
|
- Smuggler's assessment of Drin = `"compromised"` (dragged in by debt, not by choice)
|
|
- Smuggler's assessment of Torek = `"willing"` (fully aware, actively participating)
|
|
|
|
**Usage**: Shapes the observer's moral arc and internal conflict. Monologue tone shifts when the observer assigns moral weight — guilt, justification, and rationalization are driven by this key. The Comfort-Doubt-Reckoning-Compromise arc references `moral_weight` to determine which phase the observer occupies relative to specific NPCs.
|
|
|
|
**Archetype note**: Both smuggler and detective use `moral_weight` with the same enum values but different criteria. The smuggler assesses complicity in the ring's operations ("how dirty are their hands?") — see [Smuggler Moral Arc](../../design/smuggler-moral-arc.md). The detective assesses culpability in the crime ("how responsible are they for the harm?"). Same scale, different lens. A smuggler might mark Drin as `"compromised"` (dragged in, not choosing) while the detective marks Drin as `"complicit"` (he knew and did nothing). The detective's moral arc spec is unwritten in v0.1 but follows the same key.
|
|
|
|
---
|
|
|
|
### Archetype Interpretation Note
|
|
|
|
Role-perspective keys use the same value enums across all archetypes, but their meaning is archetype-dependent. The schema stores data; the content layer provides interpretation.
|
|
|
|
| Key | Smuggler reads as... | Detective reads as... |
|
|
|-----|---------------------|----------------------|
|
|
| `risk_assessment` | Operational risk to the ring (exposure, interdiction, betrayal) | Threat to public safety or obstruction of the investigation |
|
|
| `loyalty_assessment` | Loyalty to the smuggling operation | Cooperation with the investigation or institutional loyalty |
|
|
| `position_integrity` | Cover identity stability (can I still pass as legitimate?) | Authority and credibility (does my badge still open doors here?) |
|
|
| `moral_weight` | Complicity in the ring's operations (how dirty are their hands?) | Culpability in the crime (how responsible are they?) |
|
|
|
|
This pattern scales to all 8 planned archetypes without schema modification. An administrator reads `risk_assessment` as political liability; a newcomer reads it as personal vulnerability; a merchant reads it as commercial exposure. Same keys, same enums, different meaning — the archetype brief and voice register provide the lens.
|
|
|
|
---
|
|
|
|
## 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()),
|
|
("risk_assessment".to_string(), "low".to_string()), // Kael is reliable, no exposure concern
|
|
("loyalty_assessment".to_string(), "solid".to_string()), // loyal to the ring
|
|
("position_integrity".to_string(), "solid".to_string()), // cover is intact
|
|
("moral_weight".to_string(), "willing".to_string()), // fully aware, active participant
|
|
]),
|
|
}
|
|
```
|
|
|
|
### 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()),
|
|
("leverage_held".to_string(), "unauthorized meetings".to_string()),
|
|
("leverage_confidence".to_string(), "confirmed".to_string()),
|
|
("contradiction_flagged".to_string(), "meeting_unknown_contact".to_string()),
|
|
("risk_assessment".to_string(), "high".to_string()), // obstructing investigation, potential flight risk
|
|
("loyalty_assessment".to_string(), "hostile".to_string()), // uncooperative, evasive
|
|
("position_integrity".to_string(), "cracking".to_string()), // his story is falling apart
|
|
("moral_weight".to_string(), "complicit".to_string()), // involved, degree of responsibility unclear
|
|
]),
|
|
}
|
|
```
|
|
|
|
### 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()),
|
|
("leverage_held".to_string(), "knows something about Torek or Naia".to_string()),
|
|
("leverage_confidence".to_string(), "suspected".to_string()),
|
|
("risk_assessment".to_string(), "moderate".to_string()), // Commission presence is inherently risky
|
|
("loyalty_assessment".to_string(), "uncertain".to_string()), // unknown allegiance
|
|
("position_integrity".to_string(), "N/A".to_string()), // Sera isn't maintaining a cover
|
|
("moral_weight".to_string(), "peripheral".to_string()), // not involved in ring, but near it
|
|
]),
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 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. Initial `risk_assessment` and `moral_weight` may be set to defaults (`none` and `innocent` respectively) or left absent until the observer forms an opinion.
|
|
3. **Repeated interaction** (KnowsOf): `relationship_type` evolves, `trust_level` set, `behavior_flags` accumulate. `loyalty_assessment` and `position_integrity` become meaningful as the observer builds a model of the target's reliability and stability.
|
|
4. **Investigation depth** (KnowsDetails): `leverage_held`, `tell_observed`, `contradiction_flagged` added by detective. Smuggler gains `faction` clarity. Role-perspective keys (`risk_assessment`, `loyalty_assessment`, `position_integrity`, `moral_weight`) shift as the observer's understanding deepens — a target initially assessed as `risk_assessment: "low"` may escalate to `"high"` after contradictions surface.
|
|
5. **Knowledge decay**: Attributes persist even as confidence decays. A KnowsOf entry retains all attributes; only positional certainty degrades. Role-perspective assessments are particularly sticky — once the observer has formed a judgment, it takes strong counter-evidence to revise it.
|
|
|
|
---
|
|
|
|
## Content Authoring Guidance
|
|
|
|
- **Monologue prerequisites** can reference specific attributes: `known_attributes["leverage_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`.
|
|
- **Role-perspective prerequisites** can gate monologue lines by assessment: `known_attributes["risk_assessment"] == "high"` triggers different monologue pools depending on the observer's archetype (smuggler hears operational caution; detective hears investigative urgency).
|
|
- **Leverage-based confrontation** uses `leverage_held` + `leverage_confidence` together: a "suspected" leverage allows indirect probing dialogue, while "confirmed" leverage enables direct confrontation or exploitation moves.
|
|
- **Moral arc tracking** uses `moral_weight` to determine which phase of the observer's arc (Comfort/Doubt/Reckoning/Compromise) is active relative to each NPC.
|
|
|
|
---
|
|
|
|
**Total canonical keys**: 16 (4 identity, 2 social, 2 behavioral, 2 leverage, 2 investigation, 4 role-perspective). The 12 shared keys cover entity facts and relational dynamics; the 4 role-perspective keys capture the observer's subjective assessment. This schema scales to all 8 planned archetypes without modification — interpretation lives in content (monologue pools, voice registers, archetype briefs), not in the key definitions.
|