Files
settled-reach/wiki/concepts/entity-attributes.md
T
jpmschweitzerandClaude Fable 5 b4919c659b chore(meta): wiki sweep — 2,131 dead heightmap links, nav refresh, GOVERNANCE reality (T-1070, T-1071)
- T-1070: scaffold_bodies.py heightmap link now conditional (bake criteria
  per import_heightmaps.py); surgical removal of the dead image line from
  all 2,131 body pages lacking the file (267 with the file keep theirs)
- T-1071: 26 real link breaks fixed (knowledge/→concepts/, pre-governance
  decision anchors, 9 phantom catalog companions unlinked, cygni relink to
  the corporation page, wrong design-doc path); wiki/index.md counts fixed
  (301 systems) + Economics nav section; corporations/index.md regenerated
  from frontmatter (all 155, tier1.toml grouping — corrects 4 misfiled
  tier-1 corps); 25 orphaned station GTTRs linked from 11 system pages
  (own ##-heading so atlas sync cannot absorb it); GOVERNANCE.md +
  star-system template rewritten to the generated model (DB owns
  structured fields, wiki owns prose); triangles/index.md added
- Sol markers conversion REVERTED before commit: atlas_viewer.gd:433 still
  renders the legacy geometry schema, so conversion would drop Sol's Atlas
  overlays — split to T-1073 (convert together with the client read path)

Broken relative links: 2,180 → 25 (all remaining are intentional
_templates/ placeholders).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 16:23:16 +02:00

22 KiB

title, description, slug, category, status, created, updated, concept_type, tags, decision_refs, cross_refs
title description slug category status created updated concept_type tags decision_refs cross_refs
Entity Knowledge Attributes Canonical keys for EntityKnowledge.known_attributes — 16 keys covering identity, social, behavioral, leverage, investigation, and role-perspective data entity-attributes concept canonical 2026-02-12 2026-02-13 mechanical
D-041

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:

  • "{NPC Full Name}" — observer knows full name
  • "{First Name}" — 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 uses role description.


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" — institutional contacts, inspectors, 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.

Examples:

  • "human" (default)
  • (Future: other species as defined)

Usage: Future-proofing for non-human NPCs.


Social Attributes

relationship_type

Value format: Relationship category from observer's perspective.

Examples:

  • "colleague" — ring member to fellow ring member
  • "friend" — institutional contact to detective
  • "authority figure" — shift supervisor to subordinates
  • "suspect" — ring member to detective (post-discovery)
  • "partner" — non-ring partner to ring member
  • "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" — ring member showing stress during contradiction arc
  • "avoidance_pattern,evasive" — contact avoiding a suspect
  • "spending_beyond_means" — inspector buying rounds on a dock worker's income
  • "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 a cargo handler (secret)
  • "unreported evidence" — smuggler's read on an institutional contact (concealed information)
  • "gambling debt" — if a peripheral member's vulnerability is discovered (financial obligation)
  • "exit attempt" — if a ring member's unauthorized contact is discovered (betrayal)
  • "owes favor to supervisor" — 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" — ring member's tell
  • "leaves when inspector arrives" — contact'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" — {THE FRIEND} smuggler path contradiction
  • "avoidance_inconsistency" — {THE FRIEND} detective path contradiction
  • "manifest_access_mismatch" — manifest clerk handling cargo they 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 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 a wavering ring member = "high" (unpredictable, could expose the ring)
  • Detective's assessment of the shift supervisor = "moderate" (obstructive but not directly dangerous)
  • Smuggler's assessment of an uninvolved partner = "low" (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 the courier = "dependable" (reliable, follows instructions)
  • Smuggler's assessment of {THE FRIEND} mid-game = "wavering" (showing signs of doubt)
  • Detective's assessment of their institutional contact = "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 a compromised colleague = "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 an uninvolved partner = "innocent" (caught in the fallout)
  • Smuggler's assessment of a debt-dragged peripheral = "compromised" (dragged in by debt, not by choice)
  • Smuggler's assessment of the compromised inspector = "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. The detective assesses culpability in the crime ("how responsible are they for the harm?"). Same scale, different lens. A smuggler might mark a debt-driven peripheral as "compromised" (dragged in, not choosing) while the detective marks the same NPC as "complicit" (they knew and did nothing).


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 {THE FRIEND} (early game, pre-contradiction)

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(), "{NPC Full Name}".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()), // 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 a suspect (mid-game, post-contradiction discovery)

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(), "{NPC Full Name}".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()), // their story is falling apart
        ("moral_weight".to_string(), "complicit".to_string()), // involved, degree of responsibility unclear
    ]),
}

Smuggler's knowledge of the institutional contact (if observant, mid-game)

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 them well
    known_attributes: BTreeMap::from([
        ("name".to_string(), "{Institutional Contact Name}".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 the inspector or someone close to the ring".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()), // not 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.