Files
settled-reach/docs/workshops/wiki-review/round2-gestalt.md
T
jpmschweitzer 23d9ff0a58 Merge remote-tracking branch 'origin/main' into planning
# Conflicts:
#	CHANGELOG.md
#	content/_meta/README.md
#	content/_meta/npc-authoring-style-guide.md
#	wiki/_templates/cultural-group.md
#	wiki/_templates/institution.md
#	wiki/_templates/star-system.md
#	wiki/characters/devra.md
#	wiki/characters/drin.md
#	wiki/characters/harek.md
#	wiki/characters/lera-sessik.md
#	wiki/characters/maret-korr.md
#	wiki/characters/naia-tamm.md
#	wiki/characters/nils-davan.md
#	wiki/characters/pell.md
#	wiki/characters/renn.md
#	wiki/characters/resha.md
#	wiki/characters/sabel.md
#	wiki/characters/sera-venn.md
#	wiki/characters/torek-lintar.md
#	wiki/characters/voss.md
#	wiki/star-systems/krenn/index.md
2026-03-14 00:24:53 +01:00

30 KiB

title, description, type, status, workshop, agent, round, created
title description type status workshop agent round created
Round 2 — Gestalt (Systems Design) Cross-pollination synthesis reconciling five tensions from Round 1 workshop archived wiki-review gestalt 2 2026-02-12

Round 2 — Gestalt (Systems Design)

cracks knuckles

Five tensions to reconcile. Let me work through each one.


1. Content Directory Convergence (Gestalt + Tyre)

I read Tyre's proposal carefully. We agree on ~80% of the structure. Let me map where we align, where we differ, and what the converged structure should be.

Where We Agree

Area Consensus
Global/district split Global content (factions, tech, contraband, knowledge) separate from per-district content
Districts as atomic pack districts/{district-slug}/ is the content unit
Per-district NPCs districts/{slug}/npcs/{npc}.yaml
Per-district locations districts/{slug}/locations/{location}.yaml
Schema files Validation schemas at the top level
Mod overlay Additive by default, explicit override declarations

Where We Differ (and Resolution)

My Proposal Tyre's Proposal Resolution Why
_global/ global/ Tyre wins: global/ Underscore prefix is for infrastructure (_schema/, _meta/), not game content. Factions are game content.
Separate dialogue/ and monologue/ dirs lines/{location}/ with files inside Tyre wins: lines/ Cleaner. lines/terminal/dialogue.yaml + lines/terminal/monologue-smuggler.yaml keeps everything per-location without parallel directory trees.
triangles/ as standalone dir templates/ (social site defs that include triangle specs) Tyre wins: templates/ Triangles are a property of social sites, not standalone objects. A triangle definition makes no sense without its template context.
facts/ per district for local FactId instances All facts in global/knowledge/facts.yaml I push back here. See below.
regions/ for style guides Not addressed Add global/regions/ Miri's Van Maanen's Star brief needs a home. Regional style guides are global (same culture applies wherever that culture exists).
No manifest _meta/manifest.yaml Tyre wins: add _meta/ Needed for pack metadata, load order, versioning.

The Local Facts Question

Tyre puts all 24 FactIds in global/knowledge/facts.yaml. I disagree for one specific category: spatial/location facts.

contraband.ring_exists is a legitimate global definition — the CONCEPT of a smuggling ring is vocabulary. But location.corridor_b7_restricted is meaningless outside Sova Transit District. If we add a second district, it will have its OWN restricted corridors with different names. These are per-district facts.

Proposed split:

global/knowledge/
  facts.yaml              # Abstract/universal FactIds: contraband.*, world.*, relationship.*
  entity-attributes.yaml  # 14 canonical keys
  relationship-states.yaml

districts/sova-transit/
  facts.yaml              # District-specific FactIds: location.*, investigation.*, progress.*

The engine merges both at load time. Content authors know: "Am I defining a concept (global) or a location-specific observation (district)?"

This also solves Nigel's randomizer requirement — per-seed variation can swap which district facts exist without touching global vocabulary.

Converged Structure

content/
  _meta/
    manifest.yaml
    load-order.yaml

  _schema/
    npc.schema.yaml
    location.schema.yaml
    faction.schema.yaml
    template.schema.yaml
    fact.schema.yaml
    dialogue.schema.yaml
    monologue.schema.yaml
    district.schema.yaml

  global/
    factions/
      concord-assembly.yaml
      lattice-commission.yaml
      syndics.yaml
      guardians-of-autonomy.yaml
      veil-institute.yaml
      the-unbound.yaml
    technology/
      neural-lattice.yaml
      meridian.yaml
      span-gates.yaml
      founder-gates.yaml
      clone-transfer.yaml
      severance-tech.yaml
    contraband/
      lattice-components.yaml
      medical-grade-replacements.yaml
      severance-equipment.yaml
    knowledge/
      facts.yaml                    # Global/abstract FactIds only
      entity-attributes.yaml
      relationship-states.yaml
    regions/
      van-maanens-star-system.yaml             # Miri's regional style guide

  districts/
    sova-transit/
      district.yaml                 # Metadata, location list, faction presence, ambient config
      facts.yaml                    # District-specific FactIds + starting confidences
      npcs/
        kael-davan.yaml
        sera-venn.yaml
        voss.yaml
        ...
      locations/
        the-terminal.yaml
        the-last-shift.yaml
        maintenance-corridors.yaml
      templates/
        logistics-hub.yaml          # Social site: role slots, triangles, NPC assignments
        bar.yaml
        smuggling-ring.yaml
      lines/
        terminal/
          dialogue.yaml
          monologue-smuggler.yaml
          monologue-detective.yaml
        bar/
          dialogue.yaml
          monologue-smuggler.yaml
          monologue-detective.yaml
        corridor/
          dialogue.yaml
          monologue-smuggler.yaml
          monologue-detective.yaml

Mod Overlay Mechanics (Accepting Tyre's)

Tyre's three overlay operations (ADD / REPLACE / MERGE) are correct and better specified than mine:

  • Entity definitions REPLACE (whole file — no partial NPC patches)
  • Line pools MERGE (append, deduplicate by id, last-writer-wins on collision)
  • New files ADD (no conflict)

One addition to Tyre's spec: I want to address his open question about mod pool flooding. If a mod adds 50 dialogue lines to a 20-line pool:

Proposal: Weight tagging. Each content pack declares a weight in its manifest (default: 1.0). The line selection system uses weight as a probability multiplier. Base content at weight 1.0, a mod at weight 0.3 means mod lines are 30% as likely to be selected as base lines. This lets modders add volume without dominating the pool.

# In mod manifest
id: extra-bartender
weight: 0.5    # Mod lines selected at half the rate of base lines

Tyre's Other Open Question: District vs Template as Atomic Pack

Tyre asked: "Is district the right atomic content pack unit? Or should it be template (social site)?"

Answer: District. Here's why:

Templates share NPCs (bridge NPCs span social sites). If a modder adds a new NPC to the bar, that NPC might reference Hub NPCs by name, or participate in a cross-template triangle. Packing at the template level would mean the mod has to patch multiple template packs to add one NPC — that's worse for modders.

District is the natural unit because triangles and bridge connections are district-internal. A mod that adds "a new bar NPC" is really adding "a new NPC to Sova Transit District who happens to frequent the bar." The mod touches districts/sova-transit/ and everything resolves within that directory.


2. PC-as-NPC Converged Specification (Gestalt + Paula)

Paula and I are saying the same things at different granularity. She organized by deliverable type (required/optional/PC-only), I organized by data structure (transfer/transform/generate). Let me merge.

The Full PC-Candidate NPC Spec

An NPC that can be upgraded to a PC must have ALL standard Tier 2+ fields PLUS a ## PC Upgrade appendix containing structured data.

Fields from Standard NPC Brief (Required for ALL Tier 2+)

These 12 fields transfer directly into the PC brief (Paula's list, confirmed):

# Field Source Axis Transfer Type
1 Name Core Identity Direct
2 Age Core Identity Direct
3 Role Core Identity Direct → starting occupation + access
4 System Origin Core Identity Direct → cultural context
5 Lattice Tier Core Identity Direct → perception mode caps (D-017)
6 Employer Core Identity Direct → faction tag + cover
7 Want (Primary) Axis 1 Transform → orientation monologue seed
8 Want (Secondary) Axis 1 Transform → emotional anchor
9 Relationships (all) Axis 3 Transform → starting EntityKnowledge + RelationshipState
10 Daily Routine Axis 5 Transform → default schedule (deviations = player agency)
11 Information Inventory Axis 6 Transform → starting FactId confidences + knowledge graph
12 Faction Inferred Direct → access tier baseline

Fields That Transform at Upgrade (Derivable or Design-Choice)

# Field Status Resolution
13 Secret/Vulnerability Partially required The PC knows their own secret. For smuggler: ring membership IS the secret (known to player, hidden from world). For detective: personal motive for requesting posting. The NPC brief provides the secret; the upgrade inverts it from "hidden from observer" to "player's burden to manage."
14 Contentment Generated From Want + Relationships + archetype. Smuggler starts moderate-low. Detective starts moderate.
15 Personality Traits Preset per archetype for v0.1 Paula recommended this, I agree. Player-chosen personality is a v0.2+ feature.
16 Tell System Inverted This is the critical transform. The PC's tells become NPC-observable. Gore's insight applies: tells are how the world reads the PC. "You always check your lattice before lying" — the NPC knows. The PC doesn't control this mechanically; it fires when the PC takes certain actions.
17 Skill Set Derived From role + archetype.
18 Combat Tag Derived From archetype.

PC Upgrade Appendix (New Fields, Required for PC-Candidate NPCs)

This is the section that must be added to any NPC who might become a PC. It's where Paula's 6 PC-only fields and my structured formats converge:

Field 1: Starting EntityKnowledge Table

pc_upgrade:
  starting_knowledge:
    entities:
      - target: kael_davan
        state: Friendly
        confidence: KnowsDetails
        attributes:
          name: "Kael Davan"
          role: "dock worker"
          faction: "ring member"       # smuggler knows this
          trust_level: "trusted"
          relationship_type: "close colleague"
          routine_pattern: "morning shift 06:00-14:00, bar after shift"
          behavior_flags: "reliable,punctual"
      - target: voss
        state: Known
        confidence: KnowsOf
        attributes:
          name: "Voss"
          role: "shift supervisor"
          faction: "civilian"          # smuggler thinks this
          trust_level: "reliable"
          relationship_type: "authority figure"
      # ... all known NPCs

Field 2: Starting FactId Inventory

  starting_facts:
    - id: contraband.ring_exists
      confidence: KnowsDetails
    - id: contraband.lattice_components
      confidence: KnowsDetails
    - id: location.corridor_b7_restricted
      confidence: KnowsDetails
    - id: world.shift_schedule
      confidence: KnowsDetails
    - id: relationship.ring_membership
      confidence: KnowsDetails
    - id: investigation.manifest_discrepancy
      confidence: null                 # smuggler doesn't know about this
    - id: contraband.severance_tech
      confidence: null                 # smuggler doesn't know about this

Field 3: Reverse Knowledge (Bidirectional)

This is my key contribution. Every NPC who knows the PC needs their EntityKnowledge entry defined:

  known_by:
    - observer: kael_davan
      state: Friendly
      attributes:
        name: "{PC Name}"
        role: "dock worker"
        faction: "ring member"
        trust_level: "trusted"
        relationship_type: "close colleague"
    - observer: voss
      state: Known
      attributes:
        name: "{PC Name}"
        role: "dock worker"
        faction: "civilian"
        trust_level: "reliable"
    - observer: hael
      state: Known
      attributes:
        name: "{PC Name}"
        role: "dock worker"
        faction: "civilian"
        trust_level: "uncertain"       # knows PC, doesn't know ring
    - observer: lera_sessik
      state: Known
      attributes:
        name: "{PC first name}"
        role: "bar regular"
        trust_level: "reliable"

Why this matters: Without reverse knowledge, NPCs don't know the player exists at game start. Kael can't say "There you are. Good — I was starting to worry" unless Kael's knowledge graph already contains an entry for the PC with state: Friendly. Ozzie's "walking into Cheers" moment depends entirely on these reverse entries being populated.

Field 4: Access Tier Map

  access_tier_map:
    kael_davan: insider
    voss: peer
    lera_sessik: peer
    hael: peer
    sera_venn: public              # smuggler doesn't know Sera well
    maret_korr: insider            # hub colleague
    drin: insider                  # hub colleague
    torek_lintar: peer             # bar regular

Field 5: Orientation Monologue Hook

  orientation:
    monologue_pool: "smuggler"     # which pool to activate
    starting_want_text: >
      Protect the operation and the people in it.
      The money's good and Kael makes it manageable.
      But Nils keeps pushing and Hael keeps worrying.
    first_monologue_triggers:
      - trigger: enter_location
        location: terminal
        text_ref: terminal_m_001   # "Morning shift. Recycled air and cargo lubricant."

Field 6: Agency Boundaries

  agency:
    can_access: [terminal, bar, corridor_b7, residential]
    restricted_without_justification: [commission_kiosk]  # smuggler has no Commission business
    default_cover: "dock worker on shift"
    cover_breaks_when: "present in restricted areas during non-shift hours, or interacting with Commission systems"

Validation Requirement

Paula's Step 5 is critical: PC's starting knowledge must not contradict any NPC's information inventory. If the PC "knows" Kael is in the ring, and Kael's Information Inventory says "nobody outside the ring knows" — that's consistent (PC IS ring). But if the PC "knows" Sera has unreported evidence, and Sera's profile says "nobody knows" — that's a knowledge graph violation.

The schema validator (Tyre's pipeline) should check this:

For each (target, attribute) in pc_upgrade.starting_knowledge.entities:
  assert target NPC exists in district roster
  assert attribute values are consistent with target NPC's Information Inventory

For each (observer, attribute) in pc_upgrade.known_by:
  assert observer NPC exists in district roster
  assert observer's Information Inventory is compatible with their knowing these attributes about PC

3. FRIEND Pool: Size and Cost

Nigel wants the FRIEND drawn from a pool. Gore agrees but insists THE FRIEND is never procedurally generated — the content is authored, the selection is randomized. I agree with both.

Pool Size Analysis

Pool Size (per character) Total Tier 1 NPCs Additional Authored Lines Replayability Multiplier v0.1 Feasible?
1 (current: Kael, Sera) 2 0 1x (no variation) Yes (done)
2 per character 4 ~140-200 4x (2 smuggler x 2 detective) Stretch
3 per character 6 ~280-400 9x v0.2 target

The Graceful Degradation Insight

Here's what makes the pool work without exploding content costs: FRIEND candidates that aren't selected as FRIEND still exist as excellent Tier 2 NPCs.

If Kael is selected as the smuggler's FRIEND, Renn (the other candidate) is just a courier — a well-written one with a rich profile, but his contradiction arc isn't activated by the storyteller. His Phase 1 warmth exists. His tells exist. His secret exists. But the storyteller doesn't trigger the "observe contradiction in restricted area" event for Renn.

This means:

  1. Every FRIEND candidate is always present in the world at full Tier 1 quality
  2. Only the SELECTED FRIEND gets the contradiction arc ACTIVATED
  3. The unselected candidates are the best Tier 2 NPCs in the district — richer than normal because they were written at Tier 1 depth
  4. On replay, the player may encounter an NPC they KNOW has a secret (from a previous playthrough where that NPC was FRIEND) but whose arc isn't active. Gore's dramatic irony!

Authoring Cost Per Additional FRIEND Candidate

Let me be precise about what "one additional FRIEND candidate" costs:

Deliverable Lines/Pages Time Estimate
Full Tier 1 profile (10-axis, all sections) ~2 pages 3-4 hours
70-100 authored dialogue/monologue lines 70-100 lines 8-12 hours
Contradiction arc (5 phases) Part of profile Included above
Tell progression (3-4 stages) Part of profile + lines Included above
Dual-lens notes for BOTH characters ~0.5 pages 1-2 hours
PC Upgrade appendix ~0.5 pages YAML 1-2 hours
Reverse knowledge entries from ALL NPCs ~0.25 pages YAML 1 hour
Cross-character authored relationship stubs (FRIEND↔PC) 5-10 lines 1-2 hours
Total per candidate ~3 pages + 70-100 lines ~15-22 hours

v0.1 Recommendation

Ship with 1 FRIEND per character (Kael, Sera). But architect the pool system from day one:

  • The templates/ YAML includes a friend_pool field listing eligible NPC IDs
  • The seed selects from this pool at game start
  • v0.1 pool has 1 entry per character — functionally identical to current hardcoded behavior
  • v0.2 adds second candidates without any architectural change
# In templates/logistics-hub.yaml (or a district-level config)
friend_pools:
  smuggler:
    - npc: kael_davan
      contradiction_module: kael_exit_attempt
    # v0.2: add renn or other candidate here
  detective:
    - npc: sera_venn
      contradiction_module: sera_concealment
    # v0.2: add second candidate here

Gore's Constraint: Authored Relationship Depth

Gore correctly insists the PC-FRIEND relationship needs authored warmth, not just state: Friendly. Each FRIEND candidate needs specific relationship stubs for EVERY possible PC upgrade candidate:

  • If the pool has 2 smuggler FRIENDs (Kael, Renn) and the PC could be any of 2-3 smuggler archetypes, we need: Kael↔PCa, Kael↔PCb, Renn↔PCa, Renn↔PCb relationship stubs. Each stub is 5-10 authored lines of shared history.

This is a combinatorial cost. At pool size 2x2: 4 stubs (20-40 lines). At 3x3: 9 stubs (45-90 lines). Manageable but worth tracking.


4. Triangle 1 Fix: The Nils-vs-Voss Escalation Decision

Paula and I both flagged Hub Power (T1) as the weakest triangle. The core problem: Nils is off-stage, so the smuggler never mediates a real-time confrontation. The triangle describes tension but doesn't produce a FORK.

The Decision Moment: Volume Escalation

Setup (storyteller-triggered, mid-game):

Nils sends word through Renn that the next shipment is double volume. A connected system has a supply window — miss it and the opportunity is gone for months. Voss refuses to create the necessary schedule gap: "Two workers short on the same shift twice in a row? Maret will flag it. I won't do it."

Both sides appeal to the smuggler.

The Fork

Option Action Immediate Effect Cascade to T2 Cascade to T5 Detective Observability
A: Side with Nils Tell Voss to make it work, or work around Voss Voss creates gap resentfully, does it clumsily Maret notices the schedule anomaly more easily → T2 heats up Pell sees higher volume, more risk → Pell's wavering accelerates Schedule anomaly is louder signal. Detective monologue: "Third schedule adjustment this cycle. Pattern."
B: Side with Voss Tell Renn to relay: "Not this cycle" Nils is displeased, questions smuggler's loyalty Voss is relieved, cooperates more → T2 stays cool Ring internal tension rises from above → different pressure path on Pell Schedule looks clean. Detective has less to work with. Smuggler's ring standing drops.
C: Split the route Propose half-volume through normal route, half through untested alternative Partial success. New route = new exposure surface Maret sees half the anomaly (borderline noticeable) Ring members stretched thinner → more behavioral tells across the board Activity in unexpected area. Detective monologue: "Cargo movement in Section C? That's not on any manifest."

Mechanical Expression

# In templates/logistics-hub.yaml or a storyteller module
decision_node:
  id: volume_escalation
  trigger: storyteller_mid_game      # fires between minute 12-18
  setup:
    message_from: nils_davan          # off-stage, delivered via renn
    message_text: "Double volume. Next cycle. Make it happen."
    voss_response: "I won't short the schedule again. Maret's watching."
  options:
    - id: side_with_nils
      label: "Tell Voss to make it work"
      effects:
        - npc: voss
          attribute_change: { trust_level: "resentful", exposure_risk: "escalating" }
        - npc: maret_korr
          behavior_flag_add: "noticed_schedule_gap"
        - triangle: worried_knowledge
          tension_increase: 2
        - triangle: informant_question
          tension_increase: 1
        - investigation_signal: "schedule_anomaly_visible"
    - id: side_with_voss
      label: "Push back: not this cycle"
      effects:
        - npc: voss
          attribute_change: { trust_level: "relieved", cooperation: "improved" }
        - player:
          attribute_change: { loyalty_assessment_by_nils: "questioned" }
        - triangle: worried_knowledge
          tension_increase: 0
        - triangle: informant_question
          tension_increase: 1    # pressure comes from above instead
        - investigation_signal: null   # clean schedule, less detective evidence
    - id: split_route
      label: "Split: half normal, half new route"
      effects:
        - npc: voss
          attribute_change: { trust_level: "uncertain" }
        - location: section_c
          flag: "unexpected_cargo_activity"
        - triangle: worried_knowledge
          tension_increase: 1
        - triangle: informant_question
          tension_increase: 1
        - investigation_signal: "new_route_observable"

Why This Fixes T1

  1. The smuggler CHOOSES. Not "caught between" — actively deciding which side to favor. Real consequence, can't have both.
  2. Cascading consequences. Each choice ripples into T2 and T5. The detective's experience changes based on which option the smuggler picked (in NPC mode, the AI picks based on the NPC's personality/loyalty balance).
  3. Nils is present-by-proxy. The message arrives through Renn. Nils doesn't need to be physically present — the DEMAND is present. The smuggler's response defines their relationship with an off-stage power.
  4. Detective observability differs per choice. Option A is loudest (easiest for detective). Option B is quietest. Option C creates a new thread. This means the smuggler's choice shapes the detective's investigation difficulty on replay.

Additional Fix: Nils Partial Presence

I still recommend one brief Nils comm interaction in v0.1 — even a text-only lattice message that the smuggler receives and must respond to. This costs ~5-8 authored lines and makes the off-stage vertex feel real. The response choices could mirror or foreshadow the volume escalation decision.


5. Routine Format + Cultural Patterns

My Round 1 proposed a structured routine: YAML block. Miri's Van Maanen's Star brief introduces cultural patterns that the routine should accommodate: shift-end bar culture, kuum (transition drink), kolm (card game), 5+2 work cycles.

The Problem

The engine needs parseable schedule data (time, location, activity). Cultural flavor is for writers, not parsers. If I embed cultural_note fields in the YAML, I'm mixing concerns — the schedule system ignores them, and writers have to read through engine data to find authoring guidance.

Solution: Two Layers

Layer 1: Engine-readable routine (YAML)

routine:
  cycle: "5+2"                    # work days / rest days
  schedule:
    work_day:
      - time: "06:00-06:30"
        location: terminal
        activity: shift_startup
      - time: "06:30-10:30"
        location: terminal
        activity: work
      - time: "10:30-11:00"
        location: terminal_breakroom
        activity: break
      - time: "11:00-14:00"
        location: terminal
        activity: work
      - time: "14:00-14:30"
        location: terminal
        activity: shift_end
      - time: "14:30-16:00"
        location: bar
        activity: social
      - time: "16:00-22:00"
        location: residential
        activity: home
    rest_day:
      - time: "09:00-12:00"
        location: residential
        activity: home
      - time: "12:00-14:00"
        location: bar
        activity: social
      - time: "14:00-22:00"
        location: residential
        activity: home
  deviations:
    - trigger: ring_operation
      replaces: "22:00+"
      location: corridor_b7
      frequency: "1-2x per week"
    - trigger: volume_escalation     # the T1 decision node
      replaces: "14:00-14:30"
      location: corridor_b7
      frequency: "once (event-driven)"

Layer 2: Cultural context (prose, in the wiki NPC profile)

Under the Daily Routine section, AFTER the YAML block:

Cultural context (Van Maanen's Star):

  • Kael's shift startup involves grabbing leib from the canteen and eating standing — Van Maanen's Star workers don't sit for breakfast
  • Break at 10:30 is social: lunch with the smuggler (if applicable), shared kalaa and supp
  • "Shift-end" at the bar means ordering kuum first (the spiced transition drink), then switching to grain spirit if staying. Kael usually shifts to the bar 2-3 days per work cycle
  • Hael expects Kael home by 17:00 on non-bar days. Late arrivals trigger Hael's worry axis
  • Ring operations happen during night shift transitions (22:00-23:00 window) — Kael uses "overtime" as cover to Hael

This gives writers everything they need for dialogue and monologue ("Kael orders kuum" → Mellanie knows what that is from Miri's brief) while the engine reads only the clean YAML schedule.

How This Works With Miri's Specific Cultural Patterns

Miri's Pattern Where It Lives Who Uses It
5+2 work cycle routine.cycle: "5+2" in YAML Schedule system
Shift-end bar migration schedule.work_day entry with location: bar after shift Schedule system + monologue triggers
Kuum as transition drink Cultural context prose + Mellanie's menu + dialogue tags Writers (not engine)
Kolm card game timing schedule.rest_day entry at bar, OR deviation with trigger: kolm_night Schedule system + event system
Leib/kalaa food Cultural context prose Writers (environmental text, dialogue flavor)
Greeting conventions (no verbal greeting, chin-lift) NOT in routine — in Miri's regional brief Writers (dialogue notes field)

Style Guide Mandate

Every NPC routine section in the wiki should contain:

  1. YAML block — engine-readable, schema-validated, per-tier minimum entries:
    • Tier 3: 3+ time-location entries (minimum: work, social, home)
    • Tier 2: 5+ entries with work_day and rest_day split
    • Tier 1: 7+ entries with deviations specified
  2. Cultural context paragraph — prose annotations for writers, referencing the regional brief
  3. Deviation list — what pulls the NPC off their routine, with triggers and frequencies

The YAML block is the mechanical requirement. The cultural context is the authoring aid. Both are mandatory; neither replaces the other.


Cross-Cutting: Paula's Smuggler Attribute Vocabulary

Paula proposed 5 smuggler-specific entity attribute keys. This is a strong proposal that I want to endorse and refine, because it directly addresses the "smuggler content pipeline is under-served" problem she identified.

Endorsed Keys (with mechanical integration)

Key Values What Drives It What It Gates
operational_reliability reliable, slipping, compromised, unknown NPC behavior + ring event outcomes Smuggler monologue tone, ring assignment willingness
exposure_risk low, escalating, critical Tells + detective proximity + NPC behavior Smuggler tension monologue, ring operational decisions
loyalty_assessment solid, uncertain, wavering, turning Observation of NPC behavior over time Smuggler dialogue options (confront vs. reassure), ring strategy
leverage_held Freeform string (e.g., "gambling debt", "family secret") Discovery through observation or conversation Confrontation/pressure dialogue unlocks
social_debt they_owe_me, i_owe_them, mutual, none Relationship history (authored per NPC) Favor-asking dialogue, cooperation likelihood

These give the smuggler's knowledge model parity with the detective's investigation attributes. The detective has tell_observed, contradiction_flagged, secret_held, secret_confidence. The smuggler now has operational_reliability, exposure_risk, loyalty_assessment, leverage_held, social_debt.

Both characters build profiles of NPCs. The detective's profile is investigative. The smuggler's profile is operational/social. Different lenses on the same people — which is exactly the game's thesis.

Implementation note for Tyre: These 5 keys go into the entity-attributes schema alongside the existing 14. The known_attributes BTreeMap already supports arbitrary keys — no code change needed, just schema expansion and content authoring.


Summary: Decisions for Recording

# Decision Type Status
1 Converged content directory structure (Gestalt+Tyre) Architecture Propose
2 District-specific facts split from global facts Architecture Propose
3 Mod overlay: ADD/REPLACE/MERGE + weight tagging Architecture Propose
4 District (not template) as atomic content pack Architecture Propose
5 PC-candidate NPC spec: 12 required + 6 optional + 6 PC-only fields Content spec Propose
6 Reverse knowledge (bidirectional) as mandatory PC upgrade field Content spec Propose
7 FRIEND pool architecture: v0.1 = 1 per character, system supports N Content pipeline Propose
8 Volume Escalation decision node for Triangle 1 Content design Propose
9 Two-layer routine format: YAML (engine) + prose (writers) Style guide Propose
10 5 smuggler-specific entity attribute keys (Paula's proposal, endorsed) Knowledge model Propose