Skip to content

ADR-0051: Mission generation feeds off the World Engine (retire nosh_mcg)

Builds on: world-engine.md (§7 “the Mission Board is a feed off this engine”), ADR-0049 (the live :world handle), ADR-0043 (the :hold/TTL/heat objective model), ADR-0028 (Mission Control) Supersedes: the standalone nosh_mcg.c Mission Composition Grammar composer (GWP-281) — removed by this ADR.


An audit (GWP-648 follow-up) found three mission generators in the tree:

  1. mission_board.c — a working LFSR/template procgen (deck-state tiers → instance count, capability-mask filter, threat clamp, payout formula). Live — it’s what board_screen.c renders.
  2. nosh_mcg.c — the Mission Composition Grammar (GWP-281, ~April): a richer genre/shape/verb/payout pipeline, ~39 KB, behind MCG_ENABLED, 8 unit tests passing but zero callers — never wired into the board (it was built ahead of an “upstream MissionInstance merge” that never happened).
  3. world_engine.c — the central World Engine (GWP-631, 2026-06-27): one coherent world per mission + the World Clock + the typed-event bus the first-party programs read. The canonical substrate world-engine.md defines.

world_generate() was called only by tests and the recorder — nothing connected mission acceptance to the World Engine. And nosh_mcg does not use the World Engine schema at all (it predates it). So mission generation was fragmented and the richest piece was orphaned.

world-engine.md already resolves the direction: §7 “The Mission Board is a feed off this engine” — contracts arrive on the World Clock’s mail-arrived stream, seeded by deck state, rendered as a feed-reader (the board + kn9 share one feed library). The board redesign (ADR-0050) already made the board a feed-reader, so the render is ready.

Mission generation feeds off the central World Engine; nosh_mcg’s standalone code is retired and its grammar salvaged. Two phases:

Accepted missions are world-backed. A new mission_world.c subscribes to NOSH_EVENT_MISSION_ACCEPTED and generates the accepted contract’s coherent world via world_generate(seed, archetype, WORLD_CLASS_LIVE):

  • archetype ← the contract’s primary domain (mission_world_archetype_for_domain): NETWORK→NETWORK, FORENSIC→LEDGER, STREET→ORG, OCEAN→NETWORK (a dedicated maritime archetype is a follow-on).
  • seed ← the contract’s narrative_seed (deterministic per contract; folds in contract_id when unset).
  • The prior mission’s region is reset at the boundary (ADR-0049 N4 generation guard).

The MISSION_ACCEPTED event payload gains domain_tag + world_seed (filled in mission_board.c). The wire is initialized in the emulator host boot after nosh_event_bus_init(). This is the first time the live runtime connects a mission to the World Engine — every accepted mission now is a World Engine world the first-party programs can read via their :world handle.

The board’s contract offers become a World-Clock mail-arrived feed (world-engine.md §7): offers arrive over time, seeded by deck state, replacing mission_board.c’s LFSR pick. This needs the deferred feed-engine extraction (the shared mail-arrived stream + the board/kn9 tabulated-list library) and the World Engine wired into the live boot of all hosts. Tracked as a follow-on; mission_board.c’s generator stays the placeholder until it lands.

The standalone module + its 8 unit tests are deleted (orphaned, no World-Engine coupling, superseded by this direction). Its grammar is the salvage — the design input for Phase 2’s mission-shape layer, recorded here:

  • Verbs (10): PENETRATE OBTAIN ANALYZE DELIVER DESTROY OBSERVE COMMUNICATE MANUFACTURE NEGOTIATE DECIDE.
  • Genres → phase skeletons (10): HEIST (OBSERVE→PENETRATE→OBTAIN→DELIVER) · EXPOSE (OBSERVE→ANALYZE→COMMUNICATE) · ELIMINATE (OBSERVE→PENETRATE→DESTROY) · EMPIRE (OBTAIN→MANUFACTURE→DECIDE→DELIVER) · GHOST (OBSERVE→PENETRATE→OBSERVE) · REVENGE (OBSERVE→MANUFACTURE→DELIVER→ANALYZE) · DISCOVERY (OBSERVE→ANALYZE→DECIDE) · CONTAGION (OBSERVE→OBSERVE→ANALYZE→DESTROY) · COURIER (OBTAIN→DELIVER→DELIVER) · AUDIT (OBSERVE→ANALYZE→COMMUNICATE).
  • Topologies (8): MONO, CHAIN (implemented) + BRANCH, PARALLEL, EPISODIC, NESTED, ESCALATION, ECHO (were reserved).
  • Payout classes (4): SMALL / MEDIUM / LARGE / WHALE.

In Phase 2 these become the world-archetype + mission-shape selection (genre→archetype + skeleton→phase chain), generated off the World Engine — not a parallel composer.

  • Positive: missions are world-backed for the first time on the live path; one canonical generation direction (the World Engine), no orphaned composer; the board redesign’s feed-reader render is ready for the Phase-2 feed.
  • Costs / scope: Phase 2 (board offers as a timed feed) is not built — mission_board.c’s LFSR remains the offer generator for now. The OCEAN→NETWORK archetype is a stopgap. Full live activation on the device host rides on the World Engine boot-integration (the device boot does not yet init the bus/engine); the emulator host is wired + verified.
  • Tests: runtime 128/128 green (− 8 nosh_mcg tests, + test_mission_world); emulator host builds + --sys-screen-smoke accepts a contract through the wire.

Documentation Updates (REQUIRED — Spec Hygiene Rule 3)

Section titled “Documentation Updates (REQUIRED — Spec Hygiene Rule 3)”
  • docs/adr/ADR-0051-missions-feed-off-world-engine.md — this file
  • docs/adr/README.md — index entry
  • runtime/src/mission_world.{c,h} + test_mission_world.c — the wire + test
  • runtime/src/nosh_event_bus.hmission payload gains domain_tag + world_seed
  • runtime/src/{mission_board.c} — fills the new payload fields on accept
  • runtime/src/nosh_mcg.{c,h} + runtime/tests/test_mcg_*.cremoved; CMake (runtime + both hosts) cleaned
  • hosts/emulator/src/main.c — boot wire (world_engine_init + mission_world_init)

No Canonical Hardware Specification value changes.