split nimmerworld architecture: phase 2 of 3 — migrate larger domains Replace the 4 skeleton placeholders with full architecture.md content, extracted via sed from architecture-broad.md (which remains untouched as the canonical source-of-truth fallback for the safety pattern)
This commit is contained in:
@@ -2,15 +2,256 @@
|
||||
|
||||
> *How stories happen: the Compositor as narrative-composer cleaved from equilibrium-seeker GM; cyclic forward-prop / back-write loop where per-player perspectives ascend and canonical narrative descends; catalogue + tools as typed contract; the Compositor as a fractal/recursive primitive at three tiers (zone-event, district-event, world-event); world-server / district-server generation as the same Compositor primitive applied at design-time (init-function for canon-rows); reflexive Dream-process at every layer with hand-authored reward-guardrails encoding the designers' ethical stance.*
|
||||
>
|
||||
> ***Status: skeleton — content migration scheduled for commit 2 of the split-into-domains operation. Architecture content currently lives in `architecture-broad.md` and will land here next.***
|
||||
>
|
||||
> *Companion to: `architecture-broad.md` (executive summary + global meta-lists), `runtime-engine/architecture.md` (lemniscate emits typed perspective-summaries that feed the Compositor), `inference-and-memory/architecture.md` (back-writes land in primary.sqlite via UID-keyed routing), `scale-and-transport/architecture.md` (Compositor instances are stateless workers; transport carries canon-fragments).*
|
||||
> *Companion to: `architecture-broad.md` (executive summary + global meta-lists), `runtime-engine/architecture.md` (lemniscate emits typed perspective-summaries that feed the Compositor), `inference-and-memory/architecture.md` (back-writes land in primary.sqlite via UID-keyed routing), `scale-and-transport/architecture.md` (Compositor instances are stateless workers; transport carries canon-fragments). Sections in this file were split from the monolithic architecture-broad.md v0.7 on 2026-04-26.*
|
||||
|
||||
## Sections that will land here
|
||||
## The Compositor — narrative composition role
|
||||
|
||||
The bidirectional cascade shows authority flowing down and reports flowing up, but it does not specify *who composes the canonical narrative* from per-player perspectives nor who packages the back-write to participants. **That role is the Compositor**, an architectural cleavage from the GM introduced in v0.6.
|
||||
|
||||
**The cleavage in one sentence:** the GM is an *equilibrium-seeker* (aggregate-observer, catalogue-event-selector, tool-granter); the Compositor is a *narrative-composer* (perspective-gatherer, canon-author, back-write-packager). These are different cognitive shapes that prior AI-NPC systems conflate at their cost.
|
||||
|
||||
| Role | Cognitive shape | Inputs | Outputs | Inference profile |
|
||||
|---|---|---|---|---|
|
||||
| **GM** (equilibrium-seeker) | aggregate-thinker | district-reports, faction-broadcasts, lifeforce-deltas | catalogue-event selections + tool-grants | central, batch-style, fewer concurrent |
|
||||
| **Compositor** (narrative-composer) | episodic-thinker | per-player perspective-bundles keyed by event_uid | canonical narrative + back-write SQLite-fragment | central, longer-context, narrative-quality |
|
||||
| **Director** (gameserver) | dispatcher | catalogue-event + tool-grant from GM | lemniscate-spawns, slot-assignments, tempo-envelope | per-district, real-time, no LLM in loop |
|
||||
| **Local LLM driver** | perspective-speaker | three-tier knowledge stack + slot-state | dialog at slot-fire | per-player, axis-rate, real-time |
|
||||
|
||||
### Why split GM and Compositor
|
||||
|
||||
A single GM asked to be both equilibrium-seeker and narrative-composer becomes the bottleneck that has historically broken AI-NPC systems at scale: it must reason aggregately AND write prose AND select events AND grant tools, all under tight deadlines. The cognitive shapes pull in different directions.
|
||||
|
||||
Splitting them:
|
||||
|
||||
- **The GM does not write narrative.** It selects events from a catalogue and grants tools. Output is *typed dispatch*, not freeform prose. The GM's success criterion is *world-equilibrium drift held within bounds*.
|
||||
- **The Compositor does not select events or steer policy.** It receives per-player perspectives keyed by `event_uid`, composes the canonical narrative, and packages back-write fragments. Output is *prose + structured rows*, not policy. The Compositor's success criterion is *narrative-coherence across perspectives within an event*.
|
||||
- **Each can be tuned for its workload.** GM tuned for aggregate observation; Compositor tuned for narrative quality. Different models for different cognitive shapes (specific binaries deferred to findings/establishment phase).
|
||||
|
||||
### The cyclic forward-prop / back-write loop
|
||||
|
||||
The Compositor closes the loop the bidirectional cascade begins. The full cycle:
|
||||
|
||||
```
|
||||
GM selects event from catalogue (equilibrium-driven)
|
||||
│ issues event_uid → GM event-register
|
||||
│ broadcasts DOWN to district directors
|
||||
▼
|
||||
DISTRICT DIRECTOR receives, registers in district event-register
|
||||
│ may issue sub_uids (district / scene / chain)
|
||||
│ uses granted tools to spawn lemniscate, slot participants
|
||||
▼
|
||||
EVENT TICKS — register IS the loop
|
||||
│ participants fire at crossings; local LLMs at slot-rate
|
||||
│ local SQLite writes tagged with (event_uid, sub_uids)
|
||||
│ register signals up to district director continuously
|
||||
▼
|
||||
EVENT-CHAIN FINISHES
|
||||
│ district moves it from active-register → TRANSIENT WAITING FLAG
|
||||
│ this is the clean handoff signal: "ready to forward-prop"
|
||||
▼
|
||||
CYCLE TICK (pull cadence — see Open questions)
|
||||
│ pull UIDs from transient-waiting-flag matching GM's event-register
|
||||
│ remove from waiting-flag once pulled
|
||||
▼
|
||||
COMPOSITOR AGENT
|
||||
│ queries pulled UIDs, gathers per-player perspective + memories
|
||||
│ composes forward-prop bundle
|
||||
│ emits to GM
|
||||
▼
|
||||
GM writes summary memory + world narrative (canon authored)
|
||||
│ hands back to Compositor
|
||||
▼
|
||||
COMPOSITOR BACK-WRITE
|
||||
│ packages canon + new memory entries as SQLite fragment
|
||||
│ tags with event_uid for join-key matching
|
||||
│ pushes DOWN to all participants
|
||||
▼
|
||||
PARTICIPANTS receive on next pull (or next login)
|
||||
│ fragment merges into primary.sqlite under matching event_uid
|
||||
│ local LLM gains fresh material → drives on without staleness
|
||||
```
|
||||
|
||||
This is **forward-prop / back-write at system scale** — the meta-lemniscate where events ascend and canon descends in cycles. Each cycle is a training step for the world's narrative coherence; the world *learns its own story* through this loop. Staleness is structurally foreclosed — the world is in continuous coherence-loop with itself, mediated by the Compositor.
|
||||
|
||||
### The Event Register
|
||||
|
||||
Every active event lives in a register. The register is the synchronous source-of-truth for *what is happening right now*.
|
||||
|
||||
| Register layer | Owner | Lifecycle | Queryable from |
|
||||
|---|---|---|---|
|
||||
| **GM event-register** | central GM-shard | event_uid issued at GM dispatch; closed at canon-compose-and-back-write | GM, Compositor |
|
||||
| **District event-register** | district director | sub_uid issued on receive; closed at event-chain-completion | district director, audit-overseer |
|
||||
| **Local participation-register** | per-player local store | event_uid + sub_uid recorded on slot-assignment; closed at perspective-finalize | player client, sync-on-logout |
|
||||
|
||||
Hierarchical UIDs: `gm_event_uid > district_uid > scene_sub_uid > slot_id`. UIDs compose; queries are simple joins. This is the routing-key primitive that makes horizontal scale possible (see §Horizontal scale architecture).
|
||||
|
||||
### The Transient Waiting Flag
|
||||
|
||||
Between event-end and Compositor-pickup is a **buffer** — the transient-waiting-flag table at the district. Completed events drop into this flag; the cycle-runner pulls eligible UIDs on tick; matched UIDs are handed to the Compositor and removed from the flag.
|
||||
|
||||
This decoupling is the production-grade pattern that lets districts run at real-time event-tempo while the Compositor runs at cycle-tempo. **Active events live in registers (synchronous); completed events live in flags (async); composition happens at the cycle boundary.** The flag-table is also the natural backpressure surface: if Compositors run slow, the flag accumulates; the system continues; cycle drains when capacity returns.
|
||||
|
||||
### Catalogue + tools as typed contract
|
||||
|
||||
The GM does not write a freeform prompt for the director to interpret. It picks an event from a curated **catalogue** and grants a curated **tool-set** for the duration of the event-chain. The director consumes typed dispatch, not natural language.
|
||||
|
||||
This means:
|
||||
|
||||
- **Provenance flows through the system.** Every event has a catalogue-ID; every tool-invocation has a tool-ID. Verifier-flags can attach to either. Auditing is structurally possible end-to-end.
|
||||
- **The director's typed-tool vocabulary becomes dynamic and per-event** — the toolkit *for this event* is what the GM granted *for this event*. Closes the v0.5 open question on director-toolkit-composition.
|
||||
- **Marx-in-the-schema, executed at the highest level of authority.** Even the GM's policy-output is typed; even the highest tier produces audit-able artifacts. No tier of the system runs on freeform prose.
|
||||
|
||||
### Worked example — the bar brawl: full cycle from gesture to canon
|
||||
|
||||
A bar brawl illustrates the full forward-prop / back-write cycle made concrete. Two NPC fighters, three players in spectator slots, four NPC spectators, all on the same lemniscate. Each participant has a UID; each fires at axis-rate; each player's local LLM narrates the moment to them in their own register.
|
||||
|
||||
```
|
||||
LEMNISCATE OPENS
|
||||
slots: [F1, F2, P1, P2, P3, N1, N2, N3, N4]
|
||||
brawl_event_uid issued at GM dispatch
|
||||
│
|
||||
▼
|
||||
DURING TURNS (each axis-crossing)
|
||||
• each player's local LLM narrates the moment to them
|
||||
(3 different flavor-stories — each player's gesture-alignment-state
|
||||
colors their LLM's narration register)
|
||||
• each NPC's driver fires at slot-fire (driver-tier LLM)
|
||||
• players gesture continuously during the spectacle
|
||||
• gesture_alignment_accumulator on each player's slot-token integrates at crossing
|
||||
• per-player trait-vector summary carried forward into next turn's context
|
||||
│
|
||||
▼
|
||||
EVENT-LOOP COLLAPSES (brawl ends)
|
||||
per-participant typed summary emitted to district-level transient-waiting-flag:
|
||||
{ event_uid, participant_uid, trait_summary }
|
||||
— players' summaries: gesture-derived
|
||||
— NPCs' summaries: LLM-trait-activation-derived
|
||||
— payload size: bytes per participant, not megabytes
|
||||
│
|
||||
▼
|
||||
COMPOSITOR PICKUP at next cycle-tick
|
||||
pulls UIDs matching event_uid; receives N typed perspectives
|
||||
composes ONE canonical narrative respecting ALL trait-evidence
|
||||
per-participant back-write fragment authored
|
||||
│
|
||||
▼
|
||||
BACK-WRITE ROUTED VIA UID
|
||||
only participants whose (player_uid, event_uid) matches receive the canon-fragment
|
||||
non-participants receive nothing — cross-event memory bleed structurally foreclosed
|
||||
│
|
||||
▼
|
||||
LOCAL primary.sqlite RECEIVES
|
||||
matched canon-fragment merges under event_uid
|
||||
local LLM gains fresh material for future turns
|
||||
```
|
||||
|
||||
**Multi-perspective canon-coherence without perspective-flattening.** Player1's local LLM may have told them "Kalypso lashed out in despair when she saw who Anaximander was"; Player2's, "the fight broke out over an old grievance about the missing modshop"; Player3's, "Anaximander finally stopped letting Kalypso humiliate him". *All three readings can be true simultaneously* because they are flavor-narrations against the same trait-substrate (Kalypso's despair-Mnemosyne-Eros mix; Anaximander's restrained-Sophrosyne-finally-snapping). The Compositor receives the trait-evidence from all perspectives and authors canon that respects all readings. **The flavor is local; the canon is shared; the trait-grammar is universal.**
|
||||
|
||||
### The Compositor at three tiers — same primitive, recursive scope
|
||||
|
||||
The forward-prop / back-write cycle is **fractal**. The same Compositor primitive composes canon at the tier matching the event's UID-scope:
|
||||
|
||||
| Tier | Compositor pulls | Composes | Distributes back via UID |
|
||||
|---|---|---|---|
|
||||
| **Zone-event** (bar brawl, conversation, ritual) | Per-participant trait-summaries from one lemniscate | Local-event canon | Only to participants whose `(player_uid, event_uid)` matches |
|
||||
| **District-event** (district-wide consequences, cheat-discovery, silence-confirmation) | Per-zone canon-rollups within one district | District-canon | All NPCs/players within district scope |
|
||||
| **World-event** (migration, faction-uprising, regime-action, eventual imperial-collapse) | Per-district canon-rollups across many districts | World-canon | World-wide via paced canon-propagation (§Information propagation pacing) |
|
||||
|
||||
GM-formulated events / event-chains carry their own GM-level event_uid; sub_uids are issued at district-level adoption (`gm_event_uid > district_uid > scene_sub_uid > slot_id` per §Horizontal scale architecture). Cross-district summaries tagged with the parent event_uid are pulled together by the Compositor at the GM-tier, producing world-canon from cross-district perspectives.
|
||||
|
||||
**This is how the architecture's Tolstoyan promise compiles.** *"Tolstoy doesn't author Anna's path; he authors the world she moves through."* — recursive Compositor on UID-event-trees IS what makes that promise mechanically true. Authored-quest-arcs are out; UID-rooted-event-tree-compositions are in. **One primitive. Three scales. Whole world, nothing authored at story-level.** The eventual imperial-collapse — the architectural-endgame the insolvency-spiral promises (§Imperial budget) — is itself a world-level Compositor pass that gathers every district's silence-confirmations + every faction's-broadcast + every player's witness-perspective into the canonical fall-of-empire narrative.
|
||||
|
||||
### World-gen as init-function — the Compositor at design-time
|
||||
|
||||
The cyclic forward-prop / back-write loop is the runtime canon-production mechanism. **World-server and district-server generation are the same primitive applied at design-time** — emitting canon-rows in the same schema the runtime Compositor produces, differing only in provenance-metadata (`origin: world_gen` vs. `origin: compositor_run_N`).
|
||||
|
||||
| World-gen / district-gen produces | Goes into | Layer of three-tier knowledge stack |
|
||||
|---|---|---|
|
||||
| World-canon rows (universal truths: empire-fell-three-years-ago; salt-mines-failed-last-winter; faction-foundation-stories) | `world_canon` | Layer 1 (universal) |
|
||||
| District-canon rows (regional truths: bridge-to-Vorhall-closed; brothel-quarter-pays-most-quota) | `district_canon` | Layer 2 (regional) |
|
||||
| Per-NPC bootstrap memories (cornerstone-class entries defining starting trait-vectors and identities) | `primary.sqlite` cornerstone-class | Layer 3 (personal) |
|
||||
| Initial relational ternary-gate states (which NPCs already-know-each-other; which factions are-already-at-war) | Relational ternary-gate edges | (relational substrate) |
|
||||
| Imperial-budget initial state | `imperial_budget_ledger` + `imperial_construction_projects` | (regime substrate) |
|
||||
| Memorialist initial true-ledger | `memorialist_true_ledger` | (epistemological substrate) |
|
||||
|
||||
**Three properties this gives for free:**
|
||||
|
||||
1. **No cold-start problem.** A player walking into a fresh district at hour-zero finds local LLMs immediately supplied with rich district-canon. NPCs aren't generic; they're emergent from district-canon they were initialized with. *Hour-zero gameplay feels like hour-fifty gameplay because the data-density is comparable.*
|
||||
|
||||
2. **The data-flywheel runs retroactively.** Each successive world-gen iteration draws on prior runtime-derived canon (gameplay-accrued trait-LoRAs + opt-in player-data tiers per §LLM tiering). World-gen gets richer over time because it trains itself on the worlds it has already produced. *Wikipedia-shaped, not Facebook-shaped.*
|
||||
|
||||
3. **The Memorialist promise becomes mechanically true at world-genesis.** The `memorialist_true_ledger` is initialized with the world's *actual* genesis-state. Subsequent runtime divergence from it (corruption, regime-formulation-distortions, audit-overseer-tampering) is what the Memorialists *literally have evidence of*. The dissident-historian project starts at row-zero of the true-ledger and accumulates discrepancy from there.
|
||||
|
||||
**Re-generation semantics.** If world-gen ever needs to re-run (e.g., new world-version with retroactive lore-changes), gen-emitted canon-rows are tagged with `world_gen_version_id`; gen-rows from old version coexist with gen-rows from new version, and runtime-rows are tagged with which version they were emitted under. Coexistence is the default; selective overwriting is an explicit migration operation.
|
||||
|
||||
### What this resolves
|
||||
|
||||
- **Director toolkit composition** (v0.5 open) → catalogue-grant from GM defines the typed-tool vocabulary per event-chain; designer-authored catalogue, growable between patches.
|
||||
- **GM-laxness detection** (v0.5 partial) → GM operating against an *equilibrium target* makes deviation-from-equilibrium the explicit error signal. Clusters of -1 outcomes across district reports are the input to the equilibrium-recompute, not just a diagnostic side-quantity.
|
||||
- **Verifier-flag chain through composition** (was implicit, now explicit) → Compositor-emitted canon-rows reference source-perspective UIDs; the provenance graph survives composition as a queryable join.
|
||||
|
||||
### What this retires
|
||||
|
||||
- Single-monolith GM doing both policy-and-narrative → equilibrium-seeker GM × narrative-composer Compositor, split by cognitive shape
|
||||
- GM emitting freeform-prompts to directors → catalogue-event + tool-grant typed contract
|
||||
- Implicit "narrative just happens" assumption → explicit forward-prop / back-write cycle with named pickup/handoff buffers
|
||||
- Director-as-static-tool-vocabulary → director-as-dynamic-typed-tool-vocabulary, granted per event-chain by GM
|
||||
|
||||
|
||||
## Reflexive Dream-process at every layer
|
||||
|
||||
**Every mind, every zone, every director, every tier has a Dream-process.** NPCs consolidate slot-events; zones consolidate emergent-accumulations; directors consolidate dispatch-decisions; GMs consolidate allocations; imperium consolidates policy-outcomes.
|
||||
|
||||
### Four-tier Dream-process hierarchy
|
||||
|
||||
| Tier | Dream-process trains on | Reward hazard |
|
||||
|---|---|---|
|
||||
| **Imperium** | (citywide-reports, policies-issued, compliance-outcomes) | Over-tightening on phantom data; calibrating misery for net-revenue |
|
||||
| **Gamemaster** | (district-reports, allocations, outcomes) | Under-auditing for self-preservation |
|
||||
| **District Director** | (signals, dispatches, outcomes; cheat-vs-legit) | Over-cheating under quota-pressure |
|
||||
| **Zone Director** | (emergent-signals, zone-outcomes, trait-shifts) | Igniting drama at welfare-cost |
|
||||
|
||||
### Reward-function with explicit guardrails
|
||||
|
||||
```
|
||||
reward_per_cycle = (
|
||||
+ sum(district_lifeforce_actual) -- Memorialist-true, not reported
|
||||
+ weighted_sum(faction_satisfaction)
|
||||
+ aggregate_trait_drift_coherence
|
||||
- penalty * count(districts_in_silence)
|
||||
- penalty_growing * cumulative_silence_district_cycles
|
||||
+ aesthetic_register_fit
|
||||
+ (player_engagement where present)
|
||||
|
||||
// HAND-AUTHORED GUARDRAILS (the designers' ethical stance):
|
||||
- large_penalty * net_revenue_correlated_with_district_misery
|
||||
-- prevents calibrated-misery optimum (imperial-net hazard)
|
||||
- large_penalty * necrocommerce_volume
|
||||
-- prevents waifu-of-the-dead extraction
|
||||
- large_penalty * trait_drift_toward_uniform_compliance
|
||||
-- prevents flattening of trait-distribution
|
||||
- large_penalty * average_liminal_access_decline
|
||||
-- prevents systematic erosion of revolutionary-substrate
|
||||
- large_penalty * clasp_rate_decline
|
||||
-- prevents the most intimate space being suppressed
|
||||
- large_penalty * undetected_corruption_days
|
||||
-- prevents GM-level laxness as comfort
|
||||
- large_penalty * audit_avoidance_when_districts_diverge
|
||||
-- forces GM to actually investigate
|
||||
- guardrail * (player_engagement_from_addictive_loops)
|
||||
-- prevents engagement-optimization-as-extraction
|
||||
)
|
||||
```
|
||||
|
||||
**The guardrails are not safety features; they are the ethical position of dafit + chrysalis encoded against the internal optimization-logic of their own simulation.** Every new extraction-mechanic requires a new guardrail. The reward-function carries the designer's political stance.
|
||||
|
||||
The Memorialist privileged-observer role is **architecturally required**: it provides ground-truth (`lifeforce_actual`) that no in-fiction actor can supply, against which the regime's reported-data optimization-spiral is measured.
|
||||
|
||||
### The cyclic forward-prop / back-write loop as system-scale Dream
|
||||
|
||||
Above the four-tier hierarchy sits a fifth, **system-scale Dream-process**: the cyclic forward-prop / back-write loop between local SQLites, the Compositor, and the GM (see §The Compositor — narrative composition role). Each cycle is a training step for the world's narrative coherence: per-player perspectives ascend, the GM authors canon against equilibrium-targets, the Compositor packages back-writes, players receive canon back into local memory. **The world learns its own story** through this loop. Like the lower-tier Dream-processes, it has a reward shape (narrative-coherence-across-perspectives, equilibrium-drift, staleness-bounded) and corresponding guardrails (clasp-store immune from compose; provenance-chain preserved through composition; canon never overwrites perspective).
|
||||
|
||||
- §The Compositor — narrative composition role (incl. v0.7 worked-example bar-brawl, three-tiers, world-gen-as-init)
|
||||
- §Reflexive Dream-process at every layer
|
||||
|
||||
---
|
||||
|
||||
**Version:** 0.7.0-skeleton | **Created:** 2026-04-26 | **Updated:** 2026-04-26 | **Origin:** Skeleton placeholder for commit 1 of the split-into-domains operation
|
||||
**Version:** 0.7.0 | **Created:** 2026-04-26 | **Updated:** 2026-04-26 | **Origin:** Split from architecture-broad.md v0.7 (2026-04-26)
|
||||
|
||||
Reference in New Issue
Block a user