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.
Context
Section titled “Context”An audit (GWP-648 follow-up) found three mission generators in the tree:
mission_board.c— a working LFSR/template procgen (deck-state tiers → instance count, capability-mask filter, threat clamp, payout formula). Live — it’s whatboard_screen.crenders.nosh_mcg.c— the Mission Composition Grammar (GWP-281, ~April): a richer genre/shape/verb/payout pipeline, ~39 KB, behindMCG_ENABLED, 8 unit tests passing but zero callers — never wired into the board (it was built ahead of an “upstreamMissionInstancemerge” that never happened).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 substrateworld-engine.mddefines.
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.
Decision
Section titled “Decision”Mission generation feeds off the central World Engine; nosh_mcg’s standalone code is retired and its grammar salvaged. Two phases:
Phase 1 (this ADR — implemented)
Section titled “Phase 1 (this ADR — implemented)”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 incontract_idwhen 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.
Phase 2 (scoped — follow-on)
Section titled “Phase 2 (scoped — follow-on)”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.
Retire nosh_mcg, salvage the grammar
Section titled “Retire nosh_mcg, salvage the grammar”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.
Consequences
Section titled “Consequences”- 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:
runtime128/128 green (− 8nosh_mcgtests, +test_mission_world); emulator host builds +--sys-screen-smokeaccepts 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.h—missionpayload gainsdomain_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_*.c— removed; CMake (runtime + both hosts) cleaned -
hosts/emulator/src/main.c— boot wire (world_engine_init+mission_world_init)
No Canonical Hardware Specification value changes.