# Round 2: Gestalt (Systems Design) - Synthesis **Workshop:** v0.1 Content Gap Analysis **Date:** 2026-02-11 **Scope:** Mechanical convergence across all Round 1 outputs + Jeroen's Round 2 directives --- ## 0. Directives Acknowledged Before I get into synthesis, let me confirm the constraints from Jeroen's Round 2 direction. These are locked. No further debate: | Directive | Status | Mechanical Implication | |-----------|--------|----------------------| | Separate monologue pools per character | **Confirmed, non-negotiable** | Two parallel content trees. `character` is a hard partition tag, not a filter. | | Color = relationship to player | **Approved** | Entity color is a client-side derivation from `RelationshipState` component + knowledge state. Not an NPC property. | | Audio included in v0.1 | **Confirmed** | 6-8 AI-generated files. Sound event system architecture must support this. Visual fallback for everything beyond those files. | | One NPC per character = THE FRIEND | **Confirmed** | Two production-level NPCs. Full pipeline depth test. All systems exercised on these two. | | Wiki structure for taxonomy | **Non-negotiable** | Miri handling. Tag taxonomy I define here must integrate with wiki structure. | | Line pool format (YAML) | **Needs validation** | Mellanie and Paula must sign off. That's what this section does. | --- ## 1. Converged Line Pool Format *Let me break down what this actually means mechanically.* Three people proposed tag schemas in Round 1. Let me reconcile them. ### Schema Comparison | Tag | Gestalt R1 | Mellanie R1 | Paula R1 (implied) | Converged | |-----|-----------|-------------|-------------------|-----------| | `id` | `{template}_{type}_{###}` | `{template}-{role}-{situation}-{##}` | Not specified | **Keep Gestalt format** — machine-parseable, stable | | `text` | string | string | string | **Keep** | | `role` / `speaker` | `role` (enum per template) | `speaker` (enum per template) | Implied by NPC profile | **`role`** — the template role, not the NPC name. NPC assignment is runtime. | | `character` | N/A (on monologue only) | `character` (smuggler/detective/any) | Implied | **`character`** — but ONLY on monologue lines. Dialogue lines are character-agnostic; the access tier handles filtering. | | `access` | list\ | single enum | Per-line, hard filter | **list\** — a line can be eligible for multiple access tiers | | `trust` | enum (surface/real/secret) | enum (same) | Three disclosure tiers, progressive | **Aligned. No change.** | | `situation` | list\ | list\ | Relationship history + context | **list\** — see converged situation taxonomy below | | `topic` | list\ | single enum | Mood + topic for Layer 4 | **list\** — lines can cover multiple topics | | `mood` | list\ | single enum | Mood for weighted selection | **list\** | | `location` | N/A (implicit from file) | enum | N/A | **Drop from line-level.** Location is implicit from the file's directory. Adding it per-line is redundant and an error source. | | `type` | N/A (implicit from file) | `type` (dialogue/monologue/env/ticker) | N/A | **Drop from line-level.** Content type is implicit from file name (dialogue.yaml vs monologue.yaml). | | `tags` | list\ freeform | N/A | N/A | **Keep** — escape hatch for author intent that doesn't fit taxonomy | | `dual_lens` | map (per-character notes) | N/A | Critical for authoring | **Keep** — authoring-only, not consumed by engine | | `notes` | string | N/A | N/A | **Keep** — authoring-only | | `trigger` | On monologue only | N/A | N/A | **Keep for monologue** — the observation event that fires the line | | `prerequisite` | On monologue only | N/A | N/A | **Keep for monologue** — knowledge state gate | ### Converged Tag Taxonomy — FINAL (pending Mellanie/Paula sign-off) **Structural tags (required on every dialogue line):** | Tag | Type | Values | Maps to D-028 Layer | |-----|------|--------|---------------------| | `id` | string | `{template}_{d\|m\|e}_{###}` | N/A (indexing) | | `text` | string | The authored line | N/A (content) | | `role` | enum | Template-defined roles | N/A (speaker assignment) | | `access` | list\ | `public`, `insider`, `authority`, `peer`, `hostile` | **Layer 1** (hard filter) | | `trust` | enum | `surface`, `real`, `secret` | **Layer 3** (hard filter) | | `situation` | list\ | See taxonomy below | **Layer 2** (context filter) | **Selection tags (recommended, fallback to defaults if empty):** | Tag | Type | Values | Maps to D-028 Layer | Default | |-----|------|--------|---------------------|---------| | `topic` | list\ | See taxonomy below | **Layer 4** (weighted selection) | `[general]` | | `mood` | list\ | See taxonomy below | **Layer 4** (weighted selection) | `[neutral]` | | `tags` | list\ | Freeform | N/A (author use) | `[]` | **Authoring-only tags (not consumed by engine):** | Tag | Type | Purpose | |-----|------|---------| | `dual_lens` | map | Per-character interpretation notes | | `notes` | string | Author intent, dependencies, context | **Monologue-specific tags (in addition to above):** | Tag | Type | Values | Purpose | |-----|------|--------|---------| | `character` | enum | `smuggler`, `detective` | **Hard partition.** Separate pools per Jeroen's directive. | | `trigger` | enum | See trigger taxonomy below | Observation event that fires this line | | `prerequisite` | map or null | Knowledge state conditions | Gate: line only eligible if character knows X | ### Alignment with Paula's Four Layers This is the critical validation. Does the converged schema express all four D-028 layers? | D-028 Layer | How It's Expressed | Tag(s) | Filter Type | |-------------|-------------------|--------|-------------| | **Layer 1: Access tier** | `access` tag on every line. Engine checks player character's current access tier at the NPC's social site. | `access` | **Hard filter.** Line invisible if access doesn't match. | | **Layer 2: Relationship history** | `situation` tag + engine-tracked interaction state. Engine maintains per-NPC counters (interaction_count, last_interaction_time, notable_events). These counters activate/deactivate situation eligibility. `first_meeting` is true once. `repeated_visit` activates after 3+ visits. `greeted_before` is tracked by engine, not tagged per-line. | `situation` + engine state | **Context filter.** Narrows eligible pool based on relationship progression. | | **Layer 3: Trust-gated gossip** | `trust` tag on every line. Engine tracks trust progression per NPC (starts at surface, can reach real/secret through repeated positive interactions). | `trust` | **Hard filter.** Line invisible if current trust level is below line's trust tier. | | **Layer 4: Unprompted disclosure** | `topic` + `mood` tags. Engine selects from eligible lines (post-Layer 1/2/3 filtering) weighted by match between NPC's current mood state and line's mood tag, and between NPC's current concern topics and line's topic tag. | `topic` + `mood` + engine state | **Weighted selection.** Soft ranking, not hard filter. Neutral mood always available as fallback. | **Verdict: The converged schema fully expresses all four layers.** Layers 1 and 3 are hard filters (binary tag match). Layer 2 is engine-state-to-situation mapping. Layer 4 is weighted selection across two tag dimensions. Paula's concern about `greeted_before:true` — this is NOT a per-line tag. It's engine state. The engine tracks whether these characters have met before and activates the `first_meeting` or `repeated_visit` situation accordingly. The content author doesn't tag individual lines with interaction history — they tag situations, and the engine decides which situations are active. ### Key Changes from My Round 1 Proposal 1. **Dropped `location` from line-level tags** — location is directory-level. This removes a redundancy Mellanie flagged. 2. **Dropped `type` from line-level tags** — content type is file-level. This reduces Mellanie's 8 tags to 6 structural + 2 selection = 8 total, but 2 fewer per-line. 3. **Added `character` as monologue-only hard partition** — confirms Jeroen's directive mechanically. 4. **Clarified that `access` is list, not single** — a line can be eligible for both `insider` and `peer`. 5. **Made `topic` and `mood` list types** — a line can cover multiple topics and be appropriate for multiple moods. ### Situation Taxonomy v0.1 (Converged) Merged from my Round 1 list + Mellanie's proposal: | Situation | Description | Activation | |-----------|-------------|------------| | `greeting` | First interaction this game-day | Engine: no interaction logged today | | `first_meeting` | Characters have never interacted | Engine: interaction_count == 0 | | `routine` | Normal daily activity | Engine: NPC in scheduled routine state | | `morning` / `afternoon` / `evening` / `night` | Day phase (D-031) | Engine: current SimulationTime phase | | `repeated_visit` | Player has visited this NPC 3+ times | Engine: interaction_count >= 3 | | `interrogation` | Player is asking pointed questions | Engine: dialogue topic escalation detected | | `witnessed_secret` | Player has observed something they shouldn't | Engine: KnowledgeInventory contains secret-tagged fact about this NPC | | `idle` | NPC is between scheduled activities | Engine: NPC routine state = idle | | `working` | NPC is performing job routine | Engine: NPC routine state = job | | `social` | NPC is in social activity (bar, break) | Engine: NPC routine state = social | | `confrontation` | Triangle tension has escalated | Engine: triangle pressure threshold exceeded | | `post_event` | Responding to a recent simulation event | Engine: event log contains recent entry for this NPC | | `absence_noticed` | An expected NPC is missing | Engine: NPC not in expected location during expected time | **13 situations for v0.1.** Mellanie's `gossip` and `observed_anomaly` situations are covered by `social` + topic filtering and `post_event` respectively. I'm not adding them as separate situations because they're better expressed as topic + mood combinations. ### Topic Taxonomy v0.1 | Topic | Description | |-------|-------------| | `work` | Job-related: tasks, schedules, complaints | | `social` | Relationships, personal life, family | | `cargo` | Freight, manifests, shipments — setting-specific | | `money` | Finances, costs, spending | | `rumors` | Gossip, hearsay, speculation | | `identity` | Who someone is, where they're from, what they do | | `deflection` | Avoiding a topic, changing subject | | `complaint` | Grievances, frustrations | | `general` | Weather, food, neutral small talk | **9 topics for v0.1.** Mellanie's `crime` topic is deliberately excluded — NPCs don't think of what they do as "crime." It's `cargo` or `money` from their perspective. The dual-lens interpretation is what makes those topics crime-adjacent for the detective. ### Mood Taxonomy v0.1 | Mood | Description | |------|-------------| | `neutral` | Default state. Calm, unremarkable. | | `happy` | Positive, upbeat, satisfied | | `tired` | Low energy, going through motions | | `annoyed` | Irritated, short-tempered | | `nervous` | Anxious, fidgety, checking surroundings | | `defensive` | Guarded, deflecting, walls up | | `friendly` | Warm, open, welcoming | | `cautious` | Careful, measuring words | **8 moods for v0.1.** Mellanie's `tense`, `relaxed`, and `suspicious` map to `nervous`, `happy`/`neutral`, and `cautious` respectively. I'm consolidating to prevent near-duplicate moods that make authoring harder without adding selection granularity. ### Monologue Trigger Taxonomy v0.1 Unchanged from Round 1. 9 triggers: | Trigger | Description | |---------|-------------| | `enter_location` | Player enters a new area | | `observe_npc` | Player sees NPC doing something notable | | `hear_sound` | Sound event from fog edge | | `observe_anomaly` | NPC deviates from known routine | | `post_conversation` | After dialogue ends | | `discover_evidence` | Player examines an informational object | | `witness_interaction` | Player sees two NPCs interacting | | `time_idle` | Player hasn't acted for a while | | `return_visit` | Player returns to a previously visited area | --- ## 2. Mellanie's Tag Proposal vs. Mine — Convergence Mellanie proposed 8 tags. I proposed a more granular set. Here's where we landed: | Mellanie's Tag | My Tag | Resolution | |---------------|--------|------------| | `character` | `character` (monologue only) | **Aligned.** Monologue-only, hard partition. Not on dialogue lines. | | `access` | `access` | **Aligned.** I upgraded to list\; she had single. List is correct. | | `trust` | `trust` | **Aligned.** Identical. | | `location` | (directory-level) | **Dropped from per-line.** Directory structure handles this. Mellanie agreed provisional format is fine. | | `situation` | `situation` | **Aligned.** Her values are a subset of mine. Using the full 13-situation taxonomy. | | `mood` | `mood` | **Aligned.** Consolidated to 8 moods. | | `topic` | `topic` | **Aligned.** Expanded to 9 topics. | | `type` | (file-level) | **Dropped from per-line.** File naming convention handles this. | **Net result: 6 per-line structural tags + 3 per-line selection/freeform tags = 9 tags per dialogue line.** For monologue lines: +3 monologue-specific tags = 12 tags per monologue line. **Mellanie's "tag smoke test" request is smart.** Before she writes 165 lines for the workplace, she writes 20, tags them, and I validate the filtering behavior. This should happen as the first line previewer test case. --- ## 3. THE FRIEND: Production-Level NPC Specification *Okay, let me map this to mechanics.* Jeroen says THE FRIEND is a production-level complex NPC — one per character, full pipeline depth test. Ozzie defined the emotional design in Round 1. Let me define what "production-level" means for the ECS and content pipeline. ### What "Production-Level" Means Mechanically THE FRIEND exercises every system we're building. It's the NPC that proves the pipeline works end-to-end: | System | What THE FRIEND Tests | Minimum Requirement | |--------|----------------------|---------------------| | **10-axis model (D-024)** | All 10 axes populated with meaningful values that change during play | Axes must shift in response to simulation events | | **Access tiers (D-028 L1)** | THE FRIEND has different access tiers per character | Smuggler: `insider`+`peer`. Detective: varies (starts `public`, can reach `peer`) | | **Relationship history (D-028 L2)** | Interaction count tracked, situation progression works | `first_meeting` -> `greeting` -> `repeated_visit` must trigger different lines | | **Trust progression (D-028 L3)** | Trust level advances through positive interactions | Surface -> Real progression visible in dialogue depth change | | **Unprompted disclosure (D-028 L4)** | THE FRIEND volunteers information when mood + topic align | At least 3 unprompted lines that fire based on NPC mood state | | **Tell system** | Observable behavioral markers for internal state | All 5 tell categories must be demonstrable on THE FRIEND | | **Routine system** | Predictable daily schedule with deviations | Morning/afternoon/evening locations defined. At least 1 deviation event | | **Triangle membership** | Belongs to at least 1 triangle | Triangle pressure must affect THE FRIEND's behavior observably | | **Contradiction arc (Ozzie)** | Discoverable through observation, not dialogue | The contradiction must emerge from routine deviation + tell, then be confirmed/complicated by dialogue | | **Monologue integration** | Player character comments on THE FRIEND specifically | Named monologue lines referencing THE FRIEND's behavior, not generic role observations | | **Dual-lens divergence** | Same NPC, fundamentally different relationship per character | THE FRIEND is a different person emotionally to the smuggler vs. detective | ### THE FRIEND: ECS Component Profile Each FRIEND NPC needs these components at minimum: ``` Entity: THE_FRIEND_smuggler / THE_FRIEND_detective Components: - NpcIdentity { name, role, home_template, reference_templates[] } - Want { current_want, intensity, blocked_by } - Secret { content, known_by[], exposure_risk } - Relationships[3] { target_entity, valence, trust_level, interaction_count, last_interaction } - ToleranceThreshold { current_value, max_value, triggers[] } - DailyRoutine { schedule: Map, deviations[] } - InformationInventory { known_facts[], rumors[], secrets_held[] } - Contentment { value, trend, causes[] } - PersonalityTraits { trait_a, trait_b, trait_c } - TellState { active_tells: Map } - SkillSet { skills[], combat_trained: bool } - AccessTierMap { Map } // per-observer access - TriangleMembership { triangle_ids[], role_in_triangle: Map } - MoodState { current_mood, trend, causes[] } ``` ### THE FRIEND: Content Requirements **Per FRIEND NPC, Mellanie needs to author:** | Content Type | Volume | Notes | |-------------|--------|-------| | Dialogue lines (all access tiers) | 25-35 lines | Must cover public, insider, peer, hostile. More lines than any other NPC. | | Trust-gated dialogue (surface/real/secret) | 15-20 lines | Including at least 3 `secret`-tier lines that reveal the contradiction | | Unprompted disclosure lines | 5-8 lines | Mood-triggered, topic-relevant. THE FRIEND initiates conversation. | | Monologue lines (smuggler reacting to FRIEND) | 10-15 lines | Named references. "There goes Kael." Not "That dock worker." | | Monologue lines (detective reacting to FRIEND) | 10-15 lines | Different framing. Analytical, not personal. | | Tell observation monologue | 5-8 lines per character | "Kael's tapping his foot again." / "Subject displays stress indicators." | | Contradiction discovery monologue | 3-5 lines per character | The moment the player realizes THE FRIEND isn't what they seemed | **Total per FRIEND: ~70-100 authored lines** (including both character perspectives). This is roughly half the content budget of an entire template's dialogue pool — for one NPC. That's the cost of production-level. It's worth it because this NPC carries D-027 success criterion #3. ### THE FRIEND: Mapping to Paula's NPCs Looking at Paula's Round 1 relationship web: | Character | THE FRIEND candidate | Why | |-----------|---------------------|-----| | **Smuggler** | **NPC-B** (Logistics Worker 1 / Kael Davan) | Smuggler's closest colleague. Ring member. Works together daily. Trust + shared risk = deepest pre-existing bond. Contradiction: Kael is reliable to the smuggler, but is cracking under pressure / making mistakes / possibly considering turning. | | **Detective** | **NPC-D** (Dock Inspector) or **NPC-G** (Security Officer) | The detective needs a contact who becomes a relationship. NPC-D has the gambling debt (exploitable, sympathetic). NPC-G has institutional proximity (a peer the detective trusts professionally). **Recommendation: NPC-D** — the gambling debt creates the contradiction (seems corrupt, might just be desperate) and connects to Triangle B (Card Game Debt). | Paula should confirm these assignments in her Round 2. The FRIEND NPCs are the first profiles she should write at Tier 1 depth. --- ## 4. Missing Tickets for Systems/Mechanical Work I've cross-referenced all Round 1 outputs against the existing ticket pool. Here are the systems tickets that should exist but don't (or need upgrading): ### New Tickets Needed | Title | Type | Priority | Rationale | Depends On | |-------|------|----------|-----------|------------| | **Dialogue selection pipeline implementation** | Feature | Critical | The 4-layer filtering engine: access -> situation -> trust -> weighted(mood, topic). This is the core runtime system that makes content playable. Nothing in the existing tickets covers the actual selection algorithm. | Line pool format (this document), NPC component architecture | | **Monologue trigger system** | Feature | Critical | Engine component that fires monologue events based on observation triggers (enter_location, observe_npc, etc.). Must select from character-specific pool, apply prerequisite gates, track variety (no repeats). | Perception system (#124), Character knowledge state | | **NPC mood state machine** | Feature | High | NPCs need a mood component that changes based on simulation events (triangle pressure, time of day, recent interactions). Mood drives Layer 4 selection + tell system. | 10-axis NPC components | | **Trust progression system** | Feature | High | Engine tracks trust level per player-NPC pair. Progresses through surface -> real -> secret based on interaction quality and frequency. Must be observable (player can sense trust improving). | Relationship tracking, dialogue system | | **Interaction tracking component** | Feature | High | Per-NPC-pair counter: interaction_count, last_interaction_time, notable_events log. Drives Layer 2 situation activation. | NPC component architecture | | **Tell state derivation system** | Feature | Medium | System that reads NPC axis values (Secret + Tolerance = nervous, Contentment low = frustrated, etc.) and outputs observable tell states consumed by monologue trigger system. | 10-axis NPC components, monologue trigger system | | **Sound event system architecture** | Feature | High | Event emitter for sound occurrences. Emits typed events (footsteps, voices, machinery, alarm) with position, intensity, and range. Client renders as audio file OR visual indicator + monologue, depending on available assets. | Perception system (#124) | | **YAML content loader** | Feature | High | Rust system that parses content YAML files into indexed, queryable line pools at startup. Must support hot-reload for previewer/authoring workflow. | Line pool format (this document) | | **Line variety tracker** | Feature | Medium | Prevents the same line from firing repeatedly. Tracks recently-used line IDs per NPC per session. Selects from eligible pool excluding recent history. | Dialogue selection pipeline | | **Knowledge state component** | Feature | High | Per-character component tracking known facts, tagged by source, confidence, and emotional weight. Gates monologue prerequisites and informs situation activation. Paula's `KnowledgeInventory` proposal. | NPC component architecture | | **Observation event generator** | Feature | Critical | System that detects observable NPC behaviors (routine deviation, interaction between NPCs, absence from expected location) and generates events consumed by monologue trigger system. This is the bridge between simulation and player perception. | NPC routine system, perception system | | **Tag taxonomy wiki page** | Documentation | High | The converged taxonomy from this document, formatted for the wiki structure Miri is building. Reference document for all content authors. | This document, Miri's wiki structure | | **THE FRIEND: Smuggler's NPC profile** | Story | Critical | Full Tier 1 profile for the smuggler's FRIEND (NPC-B / Kael Davan). All 10 axes, voice paragraph, triangle positions, contradiction arc. | Dual Lens Guide (#261) | | **THE FRIEND: Detective's NPC profile** | Story | Critical | Full Tier 1 profile for the detective's FRIEND (NPC-D / Dock Inspector). Same depth. | Dual Lens Guide (#261) | ### Existing Tickets That Need Scope Updates | Ticket | Current Scope | Needed Addition | |--------|--------------|-----------------| | #90 (Tell system) | Unclear | Scope to 5 tell categories (nervous, angry, friendly, guarded, routine deviation). Text-via-monologue as v0.1 renderer, not visual animation. | | #124 (Sound system) | Unclear | Must include sound event emitter architecture supporting both audio playback AND visual indicator fallback. See Section 6 below. | | #193 (Line previewer) | "Authoring tool" | Concrete MVP scope defined. See Section 7 below. | | #168 (Tag taxonomy) | "Agreement needed" | This document IS the agreement. Ticket should be updated to reference this converged taxonomy. | --- ## 5. How Mechanical Systems Support Content Needs *Let me map every content need from Round 1 to a mechanical system.* This is the crosswalk that ensures nothing falls through the cracks. ### Content Need -> System Mapping | Content Need (from Round 1) | Required System | Status | Gap? | |-----------------------------|----------------|--------|------| | Dialogue lines filtered by access tier | Dialogue selection pipeline (Layer 1) | **Not built** | YES - needs ticket | | Dialogue changes based on relationship history | Interaction tracking + situation activation (Layer 2) | **Not built** | YES - needs ticket | | Trust-gated disclosure | Trust progression system (Layer 3) | **Not built** | YES - needs ticket | | NPCs volunteer information based on mood | NPC mood state machine + weighted selection (Layer 4) | **Not built** | YES - needs ticket | | Monologue fires on observation events | Observation event generator + monologue trigger system | **Not built** | YES - needs ticket | | Separate monologue per character | Character-partitioned content pools | **Not built** | Covered by YAML loader + `character` tag | | Tells observable through monologue | Tell state derivation + monologue integration | **Not built** | YES - needs ticket | | NPC routine creates observable patterns | NPC routine system (D-024 Daily routine axis) | **Partially ticketed** | Needs scope for deviations and absence detection | | Dual-lens interpretation of same event | Per-character monologue pools + knowledge prerequisites | **Not built** | Covered by monologue trigger system + `prerequisite` field | | Mirror moments on replay | Same trigger, different character pool | **Architectural** | Covered by design — separate pools keyed to same triggers | | Flat NPCs don't feel flat | Routine system + 1 memorable trait + role voice pool | **Not built** | Personality trait modifier in dialogue selection | | THE FRIEND contradiction arc | Triangle pressure + tell escalation + routine deviation | **Not built** | Composition of several systems (triangle, tell, routine) | | Environmental text readable in world | Environmental text rendering in Godot client | **Not built** | Needs client-side ticket | | News ticker / Meridian feed | Ticker content system + time-based rotation | **Not built** | Needs ticket for both content + rendering | | Audio atmosphere (6-8 files) | Sound event system + audio playback | **Not built** | YES - see Section 6 | | Diegetic tutorial via monologue | Opening hook monologue + trigger on first-time events | **Not built** | Covered by monologue trigger system + `first_meeting` / first-visit gates | **Summary: 17 content needs, 0 fully built, 12 need new tickets, 5 covered by existing ticket scope updates.** The critical path for systems is: ``` NPC Component Architecture (10 axes) | +-> NPC Routine System | | | +-> Observation Event Generator | | | +-> Monologue Trigger System | +-> NPC Mood State Machine | | | +-> Tell State Derivation | +-> Interaction Tracking | | | +-> Trust Progression | +-> YAML Content Loader | +-> Dialogue Selection Pipeline (4 layers) | +-> Line Variety Tracker ``` Everything fans out from the NPC component architecture. That's Sprint 1 server work. The YAML loader and dialogue pipeline can be developed in parallel once the component schema is stable. --- ## 6. Audio Event System: Minimal Architecture Jeroen confirmed audio in v0.1: 6-8 AI-generated files. Ozzie's minimum viable list from Round 1: 1. Station ambient loop (1 file) 2. Location variants: workplace, bar, corridors (3 files) 3. Footsteps — walk/run (2 files) 4. Monologue appearance chime (1 file) 5. (Optional) UI interaction sound (1 file) **That's 7-8 files.** Here's the minimal architecture that supports them while remaining extensible: ### Sound Event System Architecture ``` [Simulation Server] SoundEventEmitter - emits: SoundEvent { type, position, intensity, range_category } - types: Footstep, Voice, Machinery, Alert, Ambient - range_category: Close, Medium, Long (D-018) | v [ObserverSnapshot] sound_events: Vec // only events within perception range | v [Godot Client] SoundRenderer - receives SoundEvents from snapshot - looks up audio asset for event type - if asset exists: play audio (with distance attenuation + stereo panning) - if asset missing: render visual indicator + fire monologue trigger | +-> AudioAssetRegistry | Maps SoundEvent.type -> audio file path (or null) | v0.1 registry: | Footstep -> footstep_walk.ogg, footstep_run.ogg | Ambient(workplace) -> ambient_workplace.ogg | Ambient(bar) -> ambient_bar.ogg | Ambient(corridor) -> ambient_corridor.ogg | Alert(monologue) -> monologue_chime.ogg | * -> null (visual fallback) | +-> VisualSoundIndicator | Renders fog-edge ripple/pulse for events without audio | Color-coded per Araminta's spec: | neutral (#c8d0e0), voices (#e8c547), danger (#d45d5d) | +-> AmbientManager Manages location-based ambient loops Crossfades between ambient tracks on location transition The span gate hum (Miri's suggestion) is the base layer ``` ### Key Design Principles 1. **Events first, assets second.** The simulation always emits sound events. The client decides how to render them. Zero audio files = everything renders as visual + monologue. 8 files = partial audio with visual fallback for the rest. Full audio suite = rich soundscape. The architecture doesn't change. 2. **The ambient manager is separate from event-driven sounds.** Ambient loops play continuously based on location. Sound events are discrete occurrences (footsteps, voices, alerts). These are two different subsystems that share the audio output. 3. **Monologue chime is a UI sound, not a simulation sound.** It's triggered by the client when monologue text appears, not by the simulation. It doesn't go through the SoundEvent system. 4. **Distance attenuation is simple for v0.1.** Close range = full volume. Medium range = 50% volume + slight muffle. Long range = no direct audio (insert notification only). Three tiers, not continuous falloff. ### What This Requires from Implementation - **Server side:** `SoundEventEmitter` system that checks entity actions each tick and emits typed events. Perception filter includes events within hearing range in `ObserverSnapshot.sound_events`. - **Client side:** `SoundRenderer` node in Godot that processes snapshot sound events. `AudioAssetRegistry` as a simple dictionary. `VisualSoundIndicator` for fog-edge rendering. `AmbientManager` for location loops. - **Asset pipeline:** 7-8 .ogg files, generated or sourced. Integrated into Godot project's audio resources. This is a small architecture for a large capability surface. It handles v0.1's 8 files and scales to hundreds without structural changes. --- ## 7. Line Previewer (#193): Concrete MVP Scope The line previewer was flagged by me, Mellanie, and Ozzie in Round 1 as critical. Let me scope the MVP concretely. ### What the Previewer Does The previewer answers one question: **"Given this NPC state and this player state, what line fires?"** It's the authoring equivalent of a compiler — it tells the content author whether their tags produce the intended behavior before the line is integrated into the game. ### MVP Feature Set | Feature | Description | Priority | |---------|-------------|----------| | **Load YAML** | Parse a content YAML file (dialogue or monologue) into indexed pool | Must have | | **Set filter context** | CLI arguments or interactive prompts for: access tier, trust level, active situations, NPC mood, topic filter, character (for monologue) | Must have | | **Show matching lines** | Display all lines that pass the 4-layer filter with the given context | Must have | | **Show selected line** | Apply weighted selection to show which single line would fire | Must have | | **Explain selection** | Show WHY each line was included/excluded (which filter passed/failed) | Must have | | **Sequence mode** | Play N lines in order simulating a walk-through (Ozzie's "preview sequence" request) | Should have | | **Coverage report** | Show which access/trust/situation combinations have zero eligible lines (dead conversation detection) | Should have | | **Hot reload** | Watch YAML file for changes, re-run filter on save | Nice to have | | **Batch validation** | Run all YAML files through a consistency checker (missing required tags, invalid enum values, duplicate IDs) | Should have | ### Implementation **Language: Rust.** The previewer should use the same YAML parser and selection logic that the game server will use. This means the previewer IS a test harness for the dialogue pipeline — if the previewer selects correctly, the game will select correctly. **Interface: CLI.** No GUI needed. Terminal output with color-coded pass/fail on filters. ``` # Show what the detective hears from a dock_worker at insider access, surface trust, # morning routine, neutral mood $ cargo run --bin previewer -- \ --file content/templates/logistics-hub/dialogue.yaml \ --role dock_worker \ --access authority \ --trust surface \ --situation greeting,morning,routine \ --mood neutral \ --verbose [PASS] access=authority [PASS] trust=surface [PASS] situation=greeting -> lh_d_002: "You're new around here? Or just... visiting?" topic=[social, identity] mood=[cautious, neutral] weight=0.85 [PASS] access=authority [PASS] trust=surface [FAIL] situation=first_meeting (requires interaction_count==0) -> lh_d_005: "Morning. Can I help you with something?" (excluded: situation mismatch) Selected: lh_d_002 (weight: 0.85, variety_penalty: 0.0) ``` ### Sequence Mode (Ozzie's Request) ``` $ cargo run --bin previewer -- \ --file content/templates/bar/monologue.yaml \ --character smuggler \ --sequence enter_bar \ --mood neutral [Sequence: enter_bar — smuggler] 1. (enter_location) "The Last Shift. Lera's already got my usual poured." 2. (observe_npc) "Kael's at the corner booth. He looks rough tonight." 3. (observe_npc) "Drin's telling the same story again. Third time this week." 4. (time_idle) "Should probably check in with Kael. He doesn't usually drink alone." ``` This gives Mellanie and Ozzie a way to "feel" the content flow without running the full game. It's the emotional smoke test. ### Effort Estimate The previewer shares 80% of its code with the dialogue pipeline implementation. Building it first means the pipeline is already tested when it's integrated into the server. The unique work is the CLI interface, the verbose explain mode, and the sequence playback — maybe 2-3 days of Dudley/Tyre's time on top of the pipeline work they'd do anyway. **Recommendation: Build the previewer AS the first implementation of the dialogue pipeline.** Don't build them separately. The previewer is the pipeline running in standalone mode with verbose output. --- ## 8. Cross-Agent Synthesis: Convergence Map Here's where every Round 1 contributor's proposals landed after synthesis: ### Fully Aligned (no further discussion needed) | Topic | Status | Contributors Aligned | |-------|--------|---------------------| | Separate monologue pools per character | **Locked** (Jeroen directive) | All | | Color = relationship to player | **Locked** (Jeroen directive) | Araminta (proposed), Gestalt (endorsed) | | YAML as authoring format | **Aligned** | Gestalt (proposed), Mellanie (accepted with conditions) | | 5 tell categories for v0.1 | **Aligned** | Gestalt (proposed), Araminta (visual notes), Ozzie (emotional validation) | | Diegetic tutorial via monologue | **Aligned** | Gestalt (mechanical), Mellanie (content), Paula (narrative) | | 30/50/20 entanglement ratio | **Aligned** (D-029 confirmed) | All | | Monologue is v0.1 tell renderer | **Aligned** | Gestalt, Araminta, Mellanie | ### Converged in This Document | Topic | Resolution | Key Decision | |-------|-----------|--------------| | Tag taxonomy | Converged 8-tag system (6 structural + 2 selection + freeform) | See Section 1 | | Situation taxonomy | 13 situations from Gestalt + Mellanie merge | See Section 1 | | Access tier model | list\ with 5 values | Gestalt's model, Paula's content, aligned | | Line pool file structure | Directory = template/location, file = content type | Dropped per-line location and type tags | | THE FRIEND mechanical spec | Full pipeline depth test with ~70-100 authored lines per NPC | See Section 3 | | Audio architecture | Event-driven with asset registry + visual fallback | See Section 6 | | Line previewer MVP | Rust CLI sharing pipeline code, 7 must-have features | See Section 7 | ### Needs Round 2 Confirmation from Others | Topic | Who Needs to Confirm | What I Need | |-------|---------------------|-------------| | Converged tag taxonomy | **Mellanie** | Can you author with 6+3 tags per line? Is the mood/topic consolidation workable? | | Converged tag taxonomy | **Paula** | Does the Layer 2 approach (engine-state-to-situation mapping, not per-line relationship tags) satisfy your 4-layer requirements? | | THE FRIEND NPC assignments | **Paula** | Confirm NPC-B (Kael) for smuggler, NPC-D for detective. Or propose alternatives. | | Miri's setting tags | **Miri** | Your proposed `lattice_tier`, `shift_phase`, `district_familiarity`, `institutional_context` — these should be engine-state context, not per-line tags. The engine knows the player is a newcomer; it activates `first_meeting` situations. Do you agree? | | Spatial layout timing | **Araminta** | Your spatial layouts are needed before or in parallel with content packs. Confirmed? Can they be done independently of content? | | Audio asset creation | **Ozzie** | 7-8 AI-generated files. Who generates them? What's the quality bar? Do we need a ticket for audio asset generation? | --- ## 9. Emergent Interactions: Where Systems Collide *This is my favorite part.* Let me map the places where independently designed systems will interact to produce emergent gameplay — the stuff nobody scripted. ### Interaction Map | System A | System B | Emergent Result | |----------|----------|----------------| | **NPC Routine** + **Observation Events** | Player sees NPC in unexpected place at unexpected time | Monologue fires: "That's not where they usually go." Player decides to follow or ignore. Neither designer planned the specific moment. | | **Trust Progression** + **Triangle Pressure** | NPC's trust in player increases while triangle pressure increases | NPC discloses something they shouldn't under pressure. The disclosure is selected by the dialogue pipeline combining high trust + high stress mood. Not scripted — emergent from system state. | | **Access Tier Shift** + **Monologue Dual-Lens** | Player's access tier changes at a social site (e.g., detective becomes a bar regular) | New dialogue lines become available AND the monologue reflects the shift ("They're starting to warm up to me"). The player FEELS the social change through two channels simultaneously. | | **Sound Events** + **Fog of Perception** + **Monologue** | Player hears voices through a wall they can't see past | Sound event at fog edge -> visual indicator -> monologue interprets ("Sounds like an argument. Can't make out the words.") Player decides to move closer or not. The three systems produce a decision point. | | **THE FRIEND Contradiction** + **Tell System** + **Monologue** | THE FRIEND's tell state escalates (nervous) while their dialogue stays friendly | The player gets conflicting signals: dialogue says "everything's fine," monologue says "they keep checking the door." The player must decide which signal to trust. Asymmetric information within a single NPC. | | **NPC Mood** + **Time Phase** + **Unprompted Disclosure** | An NPC's mood worsens over the course of a day; by evening at the bar, they're drunk and frustrated | Layer 4 selects from `mood: [annoyed, tired]` + `trust: real` pool. The NPC says something they wouldn't have said that morning. Time + mood + alcohol = emergent information leak. | **This is why systems-first design works.** None of these moments are scripted events. They're collisions between independently designed systems operating on shared state. The content authors write the individual lines; the systems decide when and how those lines combine. The result is stories the designers didn't anticipate. --- ## 10. Open Questions for Round 3 / Sprint Planning | Question | Owner | Context | |----------|-------|---------| | Does the 4x generation expansion apply to THE FRIEND's custom lines? Or are all 70-100 hand-authored? | Mellanie + Gestalt | Generation expansion on high-specificity NPC lines risks losing the hand-crafted voice. Recommend: no expansion on FRIEND lines. Every line hand-authored. | | Who creates the 7-8 audio files? | Ozzie + Justine | AI-generated is confirmed, but the pipeline needs defining. Which AI tool? What format? Who evaluates quality? | | Should the line previewer be a sprint deliverable or a tooling side-project? | Tyre + Dudley | I recommend sprint deliverable — it's the dialogue pipeline in standalone mode. Building it IS building the pipeline. | | How does the knowledge prerequisite system handle "partial knowledge"? | Gestalt + Paula | A monologue line gated on `knows: smuggling_operation` — does the player need to know the full operation, or just that something suspicious is happening? Need a knowledge hierarchy: `suspects` < `knows_of` < `knows_details`. | | Triangle pressure threshold — what triggers escalation? | Gestalt + Paula | Triangles need a numeric pressure value that increases based on events. When it crosses a threshold, `confrontation` situation activates. Need to define the events that increase pressure. | --- *Gestalt out. The taxonomy is converged. The FRIEND is specified. The audio architecture is minimal and extensible. The previewer is scoped. Now we need Mellanie and Paula to validate the tag schema, and Dudley to start building the NPC component architecture. The systems are ready to support the content. Let's build.*