# 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
29 KiB
title, description, type, status, workshop, agent, round, created
| title | description | type | status | workshop | agent | round | created |
|---|---|---|---|---|---|---|---|
| Round 2 — Tyre (Technical Architect) | Unified content directory structure and architectural reconciliation of Round 1 proposals | workshop | archived | wiki-review | tyre | 2 | 2026-02-12 |
Wiki Review Workshop — Round 2: Tyre (Technical Architect)
Cross-pollination synthesis. Responding to all Round 1 outputs with architectural reconciliation.
1. Unified Content Directory Structure
Gestalt proposed _global/ + districts/. I proposed _meta/ + _schema/ + global/ + districts/. The structures are 90% aligned. The 10% divergence matters because it signals moddability.
The principle: Underscore prefix = engine infrastructure (modders don't touch). No underscore = game content (modders override freely). Factions, technology, and contraband are game content. Schemas and manifests are infrastructure.
Reconciled Structure
content/
_meta/
manifest.yaml # Pack metadata: id, version, dependencies
load-order.yaml # Explicit ordering for multi-pack scenarios
_schema/
npc.schema.yaml # Per-type validation (see Section 3)
location.schema.yaml
faction.schema.yaml
template.schema.yaml
fact.schema.yaml
dialogue.schema.yaml
monologue.schema.yaml
district.schema.yaml
pool.schema.yaml # NEW: Pool definition validation
global/
factions/
concord-assembly.yaml
lattice-commission.yaml
syndics.yaml
the-ring.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 # All FactId definitions (24 for v0.1)
entity-attributes.yaml # 14 canonical EntityKnowledge keys
relationship-states.yaml # RelationshipState enum reference
enums/
situations.yaml # 13 situation values (from Gestalt's _global/schema/)
topics.yaml # 9 topic values
moods.yaml # 8 mood values
triggers.yaml # 9 monologue trigger types
access-tiers.yaml # public/peer/insider/authority/hostile
activities.yaml # NEW: canonical routine activity enum
regions/
van-maanens-star-system.yaml # Regional style reference (from Miri's brief)
districts/
sova-transit/
district.yaml # District metadata, location list, faction presence
pools.yaml # NEW: Pool definitions for seed-time selection
npcs/
kael-davan.yaml
sera-venn.yaml
voss.yaml
lera-sessik.yaml
torek-lintar.yaml
devra.yaml
maret-korr.yaml
resha.yaml
hael.yaml
renn.yaml
pell.yaml
harek.yaml
drin.yaml
sess.yaml
olin.yaml
sabel.yaml
tav.yaml
locations/
the-terminal.yaml
the-last-shift.yaml
maintenance-corridors.yaml
templates/
logistics-hub.yaml # Social site: roles, slot counts, NPC assignments
bar.yaml
smuggling-ring.yaml
triangles/ # NEW: Separated from templates (Gestalt's proposal)
hub-power.yaml
worried-knowledge.yaml
bar-tensions.yaml
worried-partner.yaml
informant-question.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
What changed from Round 1
| Change | Source | Rationale |
|---|---|---|
global/enums/ added |
Gestalt's _global/schema/ tag enums |
Enum definitions are game content (modders can extend), not schema infrastructure |
triangles/ separated from templates/ |
Gestalt's Round 1 structure | Triangles are relationship structures, templates are spatial/social structures. Separation lets mods add triangles without touching templates. |
pools.yaml added |
Nigel's pool_eligible concept + Gore's FRIEND pool |
Seed-time selection needs explicit pool definitions (see Section 2) |
global/enums/activities.yaml added |
Gestalt's routine YAML format | Routine activity values need a canonical enum (see Section 4) |
global/regions/ added |
Miri's Van Maanen's Star brief | Regional style data as engine-readable YAML, not just wiki docs |
| Underscore-prefix convention formalized | Tyre Round 1, refined | Clear signal: _foo = infrastructure, foo = content |
Location shortcodes (Mellanie's dependency)
Mellanie correctly identified that location shortcodes are ambiguous (hub vs terminal, bar vs last_shift). The canonical shortcodes are the directory names under lines/:
| Location | Wiki slug | Content directory | Line ID prefix | Rationale |
|---|---|---|---|---|
| The Terminal (Logistics Hub) | the-terminal |
lines/terminal/ |
terminal_ |
"Terminal" is what workers call it. Not "hub." |
| The Last Shift (Bar) | the-last-shift |
lines/bar/ |
bar_ |
"Bar" is the functional category. "Last Shift" is the proper name. Line IDs use function. |
| Maintenance Corridors / B-7 | maintenance-corridors |
lines/corridor/ |
corridor_ |
Workers call it "B-7" or "the back käik." Line IDs use generic. |
One name per location. Enforced in schema validation. The monologue guide should be updated to use these consistently — the current hub_m_010 vs terminal_m_001 inconsistency is a bug. terminal_m_ is canonical.
2. FRIEND Pool + Mod Overlay: Seed-Time Selection
Gore's principle is correct: THE FRIEND is never procedurally generated — but FRIEND selection from a pool of authored candidates is the right architecture for replayability. Nigel's pool_eligible flag is the mechanism.
How it works architecturally
districts/sova-transit/pools.yaml:
# Pool definitions for seed-time selection
# Engine draws from these at game start using seeded RNG
pools:
# THE FRIEND selection — exactly 1 per character per playthrough
friend_smuggler:
description: "Smuggler's Tier 1 FRIEND NPC"
select: 1
candidates:
- npc: kael-davan # v0.1: only candidate
weight: 1.0
# v0.2+: additional candidates added here
# - npc: renn
# weight: 1.0
friend_detective:
description: "Detective's Tier 1 FRIEND NPC"
select: 1
candidates:
- npc: sera-venn # v0.1: only candidate
weight: 1.0
# Social site population — variable count per seed
bar_regulars:
description: "Regular NPCs present at The Last Shift"
select: 3-5
required: [torek-lintar] # Always present (triangle dependency)
candidates:
- npc: torek-lintar
weight: 1.0
- npc: olin
weight: 1.0
- npc: harek
weight: 0.8
# Mods add candidates here via MERGE
# Contraband type (Nigel's moral shuffle)
primary_contraband:
description: "Primary contraband type for this playthrough"
select: 1
candidates:
- type: lattice-components
weight: 1.0
# v0.2+: additional types
# - type: medical-grade-replacements
# weight: 0.8
# - type: severance-equipment
# weight: 0.5
# Role assignment (Nigel's network shuffle)
compromised_inspector:
description: "Which NPC is the compromised inspector"
select: 1
candidates:
- npc: drin
weight: 1.0
# v0.2+: additional candidates
How mods extend pools
A mod adds candidates via the MERGE mechanic. The mod provides districts/sova-transit/pools.yaml with only the pools it extends:
# Mod: jax-the-veteran
# File: districts/sova-transit/pools.yaml
pools:
bar_regulars:
candidates:
- npc: jax-korrenson
weight: 0.8
The engine merges this with the base pool definition. jax-korrenson is now a candidate for bar regular slots. The select: 3-5 and required: [torek-lintar] from the base remain unchanged.
Seed-time resolution
1. Engine loads all pool definitions (base + DLC + mods, merged)
2. Initialize seeded RNG from game seed
3. For each pool:
a. Include all `required` candidates
b. Draw remaining candidates up to `select` count, weighted by `weight`
c. Non-selected candidates are either:
- Absent from the district (pool_eligible NPCs with no other role)
- Present but demoted to background (if they have non-pool roles)
4. Instantiate selected NPCs with full content
5. Validate: all triangle dependencies satisfied (all triangle members present)
6. If validation fails, re-draw with constraint satisfaction
FRIEND pool + content loading implications
When friend_smuggler selects kael-davan, the engine loads:
npcs/kael-davan.yaml(full 10-axis Tier 1 data)- All monologue lines with
subject: kael_davanas a FRIEND prerequisite - The specific contradiction arc content
When (in v0.2+) it selects renn instead, it loads Renn's Tier 1 data and Renn's contradiction arc content. Both sets of content exist on disk simultaneously. The pool selects which one activates.
This means content storage is larger than content runtime. A district with 3 FRIEND candidates stores 3x the FRIEND content, but only 1x runs per playthrough. That's cheap — YAML text is tiny. The expensive resource is authoring time, not disk space. Gore's point stands: each FRIEND candidate is ~70-100 hand-authored lines.
v0.1 scope
For v0.1, every pool has exactly 1 candidate. No randomization — deterministic. But the pool INFRASTRUCTURE exists. v0.2 adds candidates without restructuring. This follows the D-009/D-010 principle: design for it now, build the simple version.
Feasibility: Easy. Pool definition parsing is a YAML file read. Seed-time selection is a weighted random draw. Constraint validation is a graph check. Total implementation: <0.5 sprint on top of the base content loader.
3. Schema Validation: Gestalt's Tables as Validators
Gestalt's hard/soft requirement tables from Round 1 are exactly what I need. Let me map them to the validation pipeline.
Gestalt's hard requirements → JSON Schema required fields
| Gestalt requirement | Schema enforcement |
|---|---|
| Routine must specify hourly location presence | npc.schema.yaml: routine.schedule is required, items must have time, location, activity |
| Routine must reference canonical location slugs | Cross-reference validation: location value must exist in districts/{district}/locations/ |
Every NPC must have faction from canonical set |
npc.schema.yaml: faction is required, enum from global/enums/factions.yaml |
Every NPC must have role |
npc.schema.yaml: role is required, type: string |
| Secret must map to FactId | Cross-reference validation: secret.fact_id must exist in global/knowledge/facts.yaml |
Tell must map to behavior_flags value |
npc.schema.yaml: each tell entry requires flag field |
Contradiction must specify contradiction_flagged value |
Tier 1 conditional: if tier == 1, contradiction.flag is required |
| Relationships must reference existing NPCs | Cross-reference validation: all npc references resolve within district |
Gestalt's soft requirements → Schema warnings (non-blocking)
| Gestalt requirement | Validation behavior |
|---|---|
| Personality traits should use established vocabulary | Warning if trait not in global/enums/personality-traits.yaml |
| Voice samples should cover 2+ moods | Warning if voice_sample array length < tier-minimum |
| Information inventory must distinguish knows/doesn't-know | Warning if information.knows or information.unknown is empty |
| Contentment should use high/moderate/low vocabulary | Warning if value not in {high, moderate-high, moderate, moderate-low, low} |
Per-tier validation (Gestalt's checklists)
Rather than separate schema files per tier, I'd use a single schema with conditional validation:
# _schema/npc.schema.yaml (simplified)
type: object
required: [id, name, tier, role, faction, axes]
properties:
tier:
type: integer
enum: [1, 2, 3]
axes:
type: object
required: [want, routine, personality] # Tier 3 minimum
# Conditional: Tier 2+ requires all 10 axes
# Conditional: Tier 1 requires contradiction arc
allOf:
- if:
properties: { tier: { const: 2 } }
then:
properties:
axes:
required: [want, secret, relationships, tolerance, routine,
information, contentment, personality, tell, skills]
voice_sample:
minItems: 2
- if:
properties: { tier: { const: 1 } }
then:
properties:
axes:
required: [want, secret, relationships, tolerance, routine,
information, contentment, personality, tell, skills]
contradiction:
required: [phases, flag, tell_progression]
voice_sample:
minItems: 5
dual_lens:
required: [smuggler, detective]
This is one schema file, tier-aware. The validator reads the tier field and applies the right constraints.
Implementation cost (revised from Round 1)
| Component | Effort | Sprint |
|---|---|---|
| Schema definitions (from Gestalt's tables) | 2-3 days | v0.1 |
Structural validation (make validate-content) |
2-3 days | v0.1 |
| Cross-reference validation (FactId, NPC slug resolution) | 3-4 days | v0.2 |
| Per-tier conditional validation | 1-2 days | v0.1 |
| Warning-level soft validation | 1 day | v0.2 |
v0.1 total: ~1 sprint. Structural + tier-conditional validation. Cross-reference validation deferred to v0.2 — for v0.1, the human review catches reference errors (only 17 NPCs, 24 FactIds, manageable).
Mellanie's prerequisite validation (FactId typo detection) lands in the cross-reference sprint. Agreed it's critical — contraband.ring_exist vs contraband.ring_exists is the kind of bug that wastes hours. But for v0.1, a simple grep-based pre-commit check is cheaper than a full cross-reference validator. I'd do both: grep check in v0.1, schema cross-reference in v0.2.
4. Routine YAML Format + Cultural Schedule Patterns
Gestalt's structured routine block is the right format. Miri's cultural brief provides the content vocabulary. Here's how they connect.
Gestalt's format, canonicalized
# In npcs/kael-davan.yaml
routine:
schedule:
- time: "06:00-06:30"
location: terminal # Canonical shortcode
activity: shift_startup # Canonical activity enum
- time: "06:30-10:30"
location: terminal
activity: work_freight
- time: "10:30-11:00"
location: terminal
activity: social_break # Renamed from "social_lunch" for generality
- time: "11:00-14:00"
location: terminal
activity: work_freight
- time: "14:30-16:00"
location: bar
activity: social_offshift # The "shift-end" culture pattern (Miri)
- time: "16:00-22:00"
location: residential
activity: home
- time: "22:00-06:00"
location: residential
activity: sleep
deviations:
- trigger: ring_operation
replaces: "22:00-06:00" # Replaces sleep block
schedule:
- time: "22:00-23:30"
location: corridor
activity: ring_operation
- time: "23:30-06:00"
location: residential
activity: sleep
frequency: irregular # Storyteller-controlled
Canonical activity enum (global/enums/activities.yaml)
Derived from Gestalt's examples + Miri's cultural patterns:
# global/enums/activities.yaml
activities:
# Work activities
- shift_startup # Arriving, checking in, prep
- work_freight # Core logistics work
- work_maintenance # Maintenance/repair tasks
- work_admin # Office/scheduling work (Maret, Voss)
- work_inspection # Inspection rounds (Drin)
- work_commission # Commission field work (Sera)
# Social activities
- social_break # On-shift break (lunch, kuum)
- social_offshift # Post-shift bar visit (the "shift-end" pattern)
- social_evening # Evening socializing (card games, conversation)
- social_errand # Off-shift personal tasks
# Domestic
- home # At residential quarters
- sleep # Sleeping (low interaction priority)
# Ring activities (deviation-only, never in base schedule)
- ring_operation # Active smuggling work
- ring_meeting # Coordination with ring members
- ring_lookout # Watchpost duty (Tav)
# Special
- idle # No scheduled activity
- patrol # Security rounds (Harek on duty)
How Miri's cultural patterns inform schedule authoring
Miri's brief describes the 5+2 work cycle and shift-end bar migration as Van Maanen's Star cultural patterns. These aren't engine data — they're authoring guidance:
| Cultural pattern | Schedule implication | Authoring rule |
|---|---|---|
| 5+2 work cycle | NPCs work 5 shifts, then 2 off | Routine must define both on-cycle and off-cycle days (v0.2+, when multi-day cycles matter) |
| Shift-end bar migration | After shift, workers go to The Last Shift | Most Tier 2-3 hub NPCs should have social_offshift at bar |
| Kuum at transitions | Hot drink at shift boundaries | social_break activity at shift start/end = where the casual dialogue fires |
| Card game evenings | Kolm at the bar, Harek's regular game | Harek + 2-3 regulars with social_evening at bar overlapping |
The cultural brief lives in global/regions/van-maanens-star-system.yaml as reference data. It doesn't drive the engine directly — it drives the AUTHORS who fill in the routine YAML.
Engine consumption
The ScheduleSystem in the Rust server reads the routine YAML as:
struct ScheduleEntry {
start_tick: u64, // Converted from time string
end_tick: u64,
location: LocationId, // Resolved from shortcode
activity: Activity, // Enum from activities.yaml
}
struct NpcSchedule {
base: Vec<ScheduleEntry>,
deviations: Vec<ScheduleDeviation>,
}
Time strings ("06:00-14:00") are converted to tick ranges at load time using D-031's mapping (10 ticks = 1 game-minute). location shortcodes resolve against the district's location registry. activity values are validated against the canonical enum.
Deviation triggers (like ring_operation) are fired by the storyteller system, not the schedule system. The schedule system just needs to know "when trigger X fires, replace block Y with schedule Z." The storyteller decides when to fire the trigger.
Feasibility: Straightforward. This is a data-driven schedule with event-driven overrides. bevy_ecs handles this naturally — NpcSchedule is a component, the ScheduleSystem runs every tick, checks current time against entries, and moves NPCs. Deviations are applied when the storyteller emits the trigger event.
5. Wiki Taxonomy + Miri's canonical_id
Miri proposed two things I want to address: wiki/cultural-groups/ as a new directory, and canonical_id in YAML frontmatter for collision-safe cross-referencing.
cultural-groups/ — fits perfectly
wiki/cultural-groups/van-maanens-star-system.md is a flat directory. No nesting. Exactly like factions/, technology/, contraband/. This is a new top-level wiki category, not a nesting violation. Add it.
The wiki index should add:
### Cultural Groups (Regional Style Briefs)
- [Van Maanen's Star](cultural-groups/van-maanens-star-system.md) — Baltic-Nordic blend, logistics culture
canonical_id — endorsed with format refinement
Miri proposed: canonical_id: van-maanens-star.sova.transit.the-terminal. I'd standardize the format:
# Format: {system}.{station}.{district}.{entity-type}.{slug}
# Examples:
canonical_id: van-maanens-star.sova.transit.location.the-terminal
canonical_id: van-maanens-star.sova.transit.npc.kael-davan
canonical_id: global.faction.lattice-commission
canonical_id: global.technology.neural-lattice
Adding the entity type segment prevents collisions between, say, a location and an NPC with the same slug. It also makes the ID self-describing — you can parse the type from the ID without reading the file.
For the content directory, the canonical_id maps to file paths:
canonical_id |
Content path |
|---|---|
van-maanens-star.sova.transit.npc.kael-davan |
content/districts/sova-transit/npcs/kael-davan.yaml |
van-maanens-star.sova.transit.location.the-terminal |
content/districts/sova-transit/locations/the-terminal.yaml |
global.faction.lattice-commission |
content/global/factions/lattice-commission.yaml |
The mapping is derivable — content loader can resolve canonical_id to file path and vice versa. Cross-references in content YAML use canonical_id, not file paths. This is Miri's proposal, architecturally validated.
Miri's deeper nesting — gentle pushback
Miri's Round 1 shows a wiki structure with 4 levels of spatial nesting:
wiki/star-systems/van-maanens-star/station-sova/sova-transit-district/the-terminal.md
The current wiki uses 2 levels: locations/van-maanens-star-system/the-terminal.md. I maintain that 2 levels is the right cap for navigation paths. The canonical_id carries the full spatial address — the filesystem doesn't need to.
Compromise: Keep wiki paths at max 2 levels for locations. Use canonical_id in frontmatter for full spatial addressing. The wiki index provides the navigational hierarchy through cross-links, not directory depth. This gives Miri's disambiguation without my tab-completion nightmare.
6. Template Role Slots (Nigel's Request)
Nigel asked for explicit role slot definitions in social site templates. This is a direct question to me and the answer is: yes, and here's the spec.
Template role slot definition
# content/districts/sova-transit/templates/bar.yaml
template:
id: bar
name: "The Last Shift"
location: the-last-shift
role_slots:
owner:
count: 1
required: true # Must be filled every seed
default: lera-sessik # Base game assignment
staff:
count: 1-2
required: true
default: [sess]
regular:
count: 3-5 # Variable per seed
required: false
pool: bar_regulars # References pools.yaml
outsider:
count: 0-2 # May or may not appear
required: false
pool: bar_outsiders
# Triangle integration: which triangles must have all members present
triangle_constraints:
- triangle: bar-tensions
required_members: [lera-sessik, torek-lintar]
# olin can be absent — triangle fires differently without the outsider node
This tells the engine: "The bar has 1 owner (always Lera), 1-2 staff (always Sess in v0.1), 3-5 regulars drawn from a pool, and 0-2 outsiders drawn from a pool." The randomizer fills slots. Mods extend the pools.
Why this matters for mods: A modder adding Jax doesn't need to know the template internals. They add Jax to the bar_regulars pool (via MERGE on pools.yaml), and the template's slot system handles placement. The modder never touches templates/bar.yaml.
Why this matters for replayability: Different seeds populate the bar differently. Playthrough 1 has Torek, Harek, and Olin as regulars. Playthrough 2 has Torek, Harek, and Jax (mod). Playthrough 3 has Torek and Olin only (smaller bar night). The bar feels alive and different each time.
7. Paula's Smuggler-Specific Attributes
Paula identified a real architectural gap: the EntityKnowledge.known_attributes vocabulary is detective-biased. Her proposed smuggler attributes are mechanically sound:
| Key | Values | Engine use |
|---|---|---|
operational_reliability |
reliable, compromised, wavering |
Smuggler monologue tone, ring operation risk calculation |
exposure_risk |
low, escalating, critical |
Smuggler stress system, storyteller escalation trigger |
loyalty_assessment |
solid, uncertain, turning |
Smuggler dialogue access (who to trust with ring talk) |
leverage_held |
Free text (e.g., gambling_debt) |
Smuggler-specific confrontation options |
social_debt |
they_owe_me, i_owe_them, mutual, none |
Social manipulation mechanics |
Architecture impact: None. known_attributes is a BTreeMap<String, String> — any key-value pair works. Adding these keys requires zero engine changes. The content schema and monologue prerequisites just reference the new keys.
Add these to global/knowledge/entity-attributes.yaml and to the wiki's entity-attributes.md. Total canonical keys goes from 14 to 19. The Rust types don't change — it's all string keys in the BTreeMap.
Feasibility: Trivial. The hardest part is writing the monologue lines that use these as prerequisites — and that's Mellanie's job, not an engine task.
8. Cross-Cutting: What Needs to Happen
Summarizing everything into concrete outputs.
Decisions to record (new D-entries)
| ID | Decision | Source |
|---|---|---|
| D-042 | Content directory structure: _meta/ + _schema/ + global/ + districts/ with underscore = infrastructure, no-underscore = moddable content |
Tyre R1/R2 + Gestalt R1, reconciled |
| D-043 | canonical_id format: {system}.{station}.{district}.{type}.{slug} for collision-safe cross-referencing |
Miri R1 + Tyre R2 refinement |
| D-044 | Mod overlay mechanics: ADD (new files), REPLACE (entity definitions), MERGE (pool-type content, deduplicate by ID) | Tyre R1 + Nigel R1 pool integration |
| D-045 | Pool-based seed-time selection: FRIEND, social site population, contraband type, role assignment. pools.yaml per district. v0.1 ships with 1 candidate per pool; architecture supports N candidates. |
Nigel R1 + Gore R1 + Tyre R2 synthesis |
| D-046 | Schema-per-content-type validation with tier-conditional rules. Structural validation in v0.1, cross-reference validation in v0.2. | Gestalt R1 tables + Tyre R1/R2 implementation |
| D-047 | Template role slots: social site templates declare named slots with count ranges, required flags, and pool references. Modders extend pools, engine fills slots. | Nigel R1 request + Tyre R2 spec |
| D-048 | Canonical location shortcodes: terminal, bar, corridor. One name per location, enforced in schema, used in line ID prefixes. |
Mellanie R1 dependency + Tyre R2 formalization |
| D-049 | Smuggler-specific entity attributes added to canonical vocabulary: operational_reliability, exposure_risk, loyalty_assessment, leverage_held, social_debt. Total canonical keys: 19. |
Paula R1 proposal + Tyre R2 validation |
Documents to create
| Document | Owner | Blocks |
|---|---|---|
wiki/cultural-groups/van-maanens-star-system.md |
Miri | All environmental text authoring |
Cultural Groups section in wiki/index.md |
Miri/Qatux | Wiki navigation |
| Location shortcode table | Mellanie/Tyre | All YAML content authoring |
| Freeform tag vocabulary (living list) | Mellanie | Content consistency |
| Environmental text type catalog | Mellanie | v0.1 environmental text authoring |
| Voice cards per playable character | Mellanie | Monologue authoring consistency |
| NPC-format briefs for smuggler + detective PCs | Paula | PC-as-NPC concept |
| Tier 1/2/3 template as standalone style guide | Paula | All future NPC authoring |
Amendments to existing wiki pages
wiki/index.md: Add Cultural Groups section, add Thematic Core section (Gore's proposal)wiki/knowledge/entity-attributes.md: Add 5 smuggler-specific attribute keyswiki/knowledge/fact-catalog.md: Add smuggler-perspective progression text for all FactIds where smuggler starts at KnowsDetailswiki/authoring/monologue-guide.md: Standardize location shortcodes (terminal_m_nothub_m_); add situation overlap rules, mood exclusivity rules- NPC profiles (all): Add canonical full names for single-name NPCs; add
## Thematic Questionto Tier 1 template (Gore)
New tickets for SI
- Create
_schema/directory with schema definitions from Gestalt's tables - Implement
make validate-contentCLI (structural + tier-conditional) - Create
content/directory skeleton matching the unified structure above - Create
pools.yamltemplate with v0.1 single-candidate pools - Create
global/enums/YAML files from D-035 enum values - Add
global/knowledge/entity-attributes.yamlwith 19 canonical keys (14 existing + 5 smuggler) - Create
templates/YAML files with role slot definitions for 3 social sites - Create
triangles/YAML files for 5 v0.1 triangles - Stub NPC profiles for Nils Davan (off-stage, referenced in 5+ profiles)
- Add pre-commit grep check for FactId typos in YAML content
Tyre out. The architecture converges. The content team now has a concrete spec to write against, and the engine team has a concrete loading pipeline to build. Ready for Qatux to record and SI to ticket.