Skip to content

2026-04-25-mission-shape-grammar

Mission Shape Grammar — Topology Library for the MCG Composer

Section titled “Mission Shape Grammar — Topology Library for the MCG Composer”

Status: Draft design for post-v0.1 wave (Notion: GWP-279, sub-task of GWP-277) Date: 2026-04-25 Owner: Gameplay Design / PM (GWP-277) Scope: Defines the mission shape grammar — the eight phase-graph topologies the Mission Composition Grammar (MCG) composer can instantiate (MONO, CHAIN, BRANCH, PARALLEL, EPISODIC, NESTED, ESCALATION, ECHO). For each shape: phase-graph notation, fire-decision heuristic, payout topology multiplier, 256-byte phase_chain serialization, and fallback rules when the operator’s library is too thin. Plus cross-shape composition rules and a forward-compatibility sweep. Non-scope: No C, no Lisp runtime changes, no emulator source edits. The composition algorithm reference implementation lives in the engineering sub-task (Notion: GWP-277 → “Engineering: MCG composition algorithm”). The genre template library (HEIST/EXPOSE/ELIMINATE/…) lives in its own sub-task (GWP-280, sibling of this one).

Hardware spec references — this design targets the canonical 80×25 amber grid, 31-key input system, CIPHER-LINE auxiliary OLED, and Pi Zero 2 W firmware described in CLAUDE.md → “Canonical Hardware Specification”. Nothing in this doc restates those values.

Augments, does not supersede. This plan extends 2026-04-25-mission-composition-grammar.md (the MCG addendum — verb vocabulary, affinity tags, mission-contributions cart contribution block) and 2026-04-21-mission-board.md (the Mission Board generator design — MissionInstance shape, refresh lifecycle, phase_chain serialization). The MCG addendum’s §4 algorithm sketch references “topology shapes” as a deferred concern; this document is what fills that pointer.


The MCG addendum (§4 step 5) lists topology multipliers as a multiplicative factor in the payout formula, with parenthetical examples (1.0 for MONO, 1.2 for 2-CHAIN, 1.5 for 3-CHAIN, 2.0 for 4-CHAIN, +0.3 per BRANCH path). It does not specify what the shapes actually are, when the composer picks one over another, how branched/parallel/episodic structures encode into the existing phase_chain[256] slot, or what happens when the operator’s library cannot satisfy a chosen shape.

This document fills those gaps. Without it, the composition algorithm has a payout multiplier table but no way to instantiate the topologies it claims to support — and no recourse when a 4-CHAIN cannot be built from a 3-cart library.

The eight shapes were drawn from a survey of how cyberpunk fiction (and existing tabletop / video-game heist designs) structure multi-objective contracts. They are intended to be small, distinct, and serializable. The set is closed for v1; new shapes require an ADR.


Design constraints (carried in from upstream)

Section titled “Design constraints (carried in from upstream)”

These are the load-bearing constraints from the MCG addendum, the mission-board plan, and orchestration.md that every shape must respect:

  1. All shapes must serialize into the existing 256-byte phase_chain deck-state slot (deck-state.md §“What Each Field Does”). No deck-state schema changes for v1.
  2. All shapes must admit at least one fallback path. The composer must never deadlock on “I rolled this shape but cannot build it.” A degrade-to-smaller-shape rule is mandatory for every multi-phase shape.
  3. Single-cartridge career is complete. Every shape must be instantiable from a single-cart library — even if as a degenerate case (e.g., BRANCH with both branches anchored on the same cart). orchestration.md § “The Capability Curve → One Cartridge”.
  4. Cross-program integration is always additive, never subtractive. No shape demands a multi-cart minimum to roll; the composer downgrades the shape rather than skipping the contract. MCG addendum §“Design constraints” item 1.
  5. CIPHER-LINE narrates; the main grid renders mission state. Each shape emits structured mission_* events into the Cipher event stream; no shape introduces main-grid Cipher overlays. Mission Board plan § “Cross-capability hooks → Cipher voice”.
  6. Phase Chain is opaque to cartridges. Cartridges do not write the phase_chain slot directly (deck-state.md §phase_chain). Shape encoding is nOSh-runtime-owned; cart code reads phase context via FFI, not by parsing the chain.

The eight shapes form a small lattice along two axes: phase count (1, 2, 3, 4) and branching topology (linear / fan-out / fan-in / repeating / nested). The composer picks a shape based on reputation tier, library size, and recent-history bias (no two consecutive contracts share a shape unless the operator is at rep-tier 4 Legend, where high-variety boards are tolerated).

ShapePhase countBranchingTypical fiction beat
MONO1noneSingle-objective contract — “compromise the node”.
CHAIN2–4linearMulti-domain progression — “intrude, then audit”.
BRANCH2–3fan-outOperator picks a path at a decision point — “stealth or sabotage”.
PARALLEL2–3fan-inBoth must complete; order doesn’t matter — “two simultaneous extractions”.
EPISODIC3–6repeatingSame shape, multiple instances over a timeframe — “weekly courier run”.
NESTED3–4hierarchicalSub-contract within a contract — “audit reveals a deeper data dump”.
ESCALATION2–4linear with rising threatEach phase is harder than the last — “chase up the food chain”.
ECHO2callbackSequel to a past completed contract — “they came back for the ledger”.

The shapes are not exclusive — an ECHO can be a CHAIN under the hood (the callback contract may itself have multiple phases), and a NESTED contract’s outer chain may run BRANCH-shape sub-contracts. See §10 for cross-shape composition rules.


[P1]

A single phase. One verb satisfied by one cart. The default shape and the floor of the grammar.

  • Always eligible. MONO is the universal fallback — every other shape can degrade to it.
  • Weighted up at rep tier 0–1 (Apprentice / Operator). New operators see a board of mostly MONO contracts; the rare CHAIN highlights the curve.
  • Weighted down at rep tier 3–4 (Veteran / Legend). High-rep boards show MONO as a recovery option after a hard contract, not the default.
  • Library-size irrelevant. A 1-cart library and a 14-cart library both roll MONO at every tier (the weighting changes, not the eligibility).

Recent-history bias: if the last 4 generated contracts were all MONO and rep ≥ 2, the composer rejects an additional MONO and re-rolls toward CHAIN/BRANCH.

topology_multiplier(MONO) = 1.0

Baseline. Per the MCG addendum’s §4 payout formula, this is the canonical floor against which all other shapes are scaled.

A MONO contract does not require persistence into phase_chain between phases (there is no “between”). However, when a MONO contract is in flight (the operator has accepted but not completed it), the runtime serializes its identity into phase_chain so that a power cycle or cart-eject does not lose the contract. The encoding is the minimum viable header:

Offset Bytes Field Notes
0 1 shape_tag = 0x01 (MONO)
1 1 version = 0x01
2 2 contract_id little-endian uint16, MissionInstance.contract_id
4 2 template_handle little-endian uint16
6 1 current_phase = 0x01 MONO is always phase 1 of 1
7 1 total_phases = 0x01
8 4 narrative_seed little-endian uint32
12 4 board_seed_at_accept little-endian uint32 — for replay/QA
16 ... intermediate_state opaque cart-supplied bytes (≤ 240)

phase_chain_len = 16 + intermediate_state_len. Total budget remains within the 256-byte slot.

MONO is the fallback for everything else; it has no fallback of its own. The only way MONO fails to instantiate is if the operator’s library cannot satisfy any verb at all — in which case the board is empty (per Mission Board plan § “Empty / degenerate states”) and the issue is library size, not topology choice. No MISSING_CART_HOOK for MONO; the genre roll either succeeds or the board reports empty.


§3. CHAIN — linear multi-phase progression

Section titled “§3. CHAIN — linear multi-phase progression”
[P1] → [P2] → [P3] → [P4]

Up to 4 phases, sequential, no branching. Each phase’s exit triggers the next phase’s start. Phase n+1 is gated on phase n’s success.

This is the most common multi-phase shape and the only one explicitly modeled in the MCG addendum’s §4 sketch (the 1.2 / 1.5 / 2.0 multiplier example).

  • Eligible at rep tier ≥ 1 for 2-CHAIN.
  • Eligible at rep tier ≥ 2 for 3-CHAIN.
  • Eligible at rep tier ≥ 3 for 4-CHAIN.
  • Library size gate: N-CHAIN requires a verb-coherent path through at least N phases — but the same cart can satisfy multiple phases (e.g., ICE Breaker’s PENETRATE → OBTAIN). Single-cart 2-CHAIN is allowed; multi-cart preferred.
  • Recent-history bias: avoid back-to-back N-CHAIN of the same length when N ≥ 3. Penalty re-roll triggers if the last 2 generated contracts were both 4-CHAIN.

Per the MCG addendum §4:

topology_multiplier(2-CHAIN) = 1.2
topology_multiplier(3-CHAIN) = 1.5
topology_multiplier(4-CHAIN) = 2.0

Notes on the curve: roughly +0.3 per added phase, with a small bonus at the 4-phase ceiling for the “epic” feel. This curve is intentionally below linear-additive — players see the topology multiplier on top of the cross-cart multiplier (also from §4), so a 4-CHAIN spanning four distinct carts compounds to ~2.8× before threat scaling. That ceiling is a deliberate gameplay invariant; tuning happens by adjusting these multipliers, not by adding new shapes.

Offset Bytes Field Notes
0 1 shape_tag = 0x02 (CHAIN)
1 1 version = 0x01
2 2 contract_id
4 2 template_handle
6 1 current_phase 1-indexed; advances on phase completion
7 1 total_phases 2..4
8 4 narrative_seed
12 4 board_seed_at_accept
16 N per_phase_meta N = total_phases × 8 bytes per phase:
4 bytes capability_bit (which cart satisfies this phase)
1 byte verb (interned per §1 of MCG addendum, 10 verbs fit in 4 bits but byte-padded)
1 byte status (0=pending, 1=in-flight, 2=complete, 3=failed)
2 bytes phase-base-payout snapshot (used for partial-payout calc on abort)
16+N ... intermediate_state opaque cart-supplied bytes

Worst case (4-CHAIN): 16 header + 32 per-phase = 48 bytes; leaves 208 bytes for intermediate_state. Comfortably within budget.

If the composer cannot find a verb-coherent path of length N:

  1. Try shorter chains. 4-CHAIN → 3-CHAIN → 2-CHAIN → MONO. Each downgrade re-runs the affinity coherence check from scratch with the shorter genre skeleton.
  2. Emit MISSING_CART_HOOK if the genre template demands a specific cart that’s not in the library. Per MCG addendum §4 step 2d, the contract appears greyed out on the board with hint PHASE N REQUIRES: <CART>. The operator can bookmark it for when they acquire the cart.
  3. Abort and re-roll if both shortening and the missing-cart hint fail (e.g., the genre template is fundamentally incompatible with the operator’s library). Fall through to MONO under a different genre.

§4. BRANCH — fan-out with operator choice

Section titled “§4. BRANCH — fan-out with operator choice”
┌→ [P2a]
[P1] ──┤
└→ [P2b]

After phase 1, the operator chooses one of two paths. Only one branch is executed; the other is forfeited. Optionally, a 3-phase BRANCH joins back:

┌→ [P2a] ──┐
[P1] ──┤ ├→ [P3]
└→ [P2b] ──┘

The branch decision is made at the inspector or at the phase-1 debrief surface — UX is deferred to the engineering sub-task. Branches are operator-visible: the inspector copy enumerates both paths with their rough threat/payout tradeoffs.

  • Eligible at rep tier ≥ 2. Branch decisions are an intermediate-skill mechanic; new operators do not see them.
  • Library size gate: requires at least one cart per branch path (the two branches must be satisfiable by different verbs OR by the same verb with affinity divergence — e.g., one branch DIGITAL, the other PHYSICAL). Single-cart BRANCH is allowed only when the cart’s verb set is broad enough that the two branches read as distinct (e.g., ICE Breaker’s PENETRATE branch vs. DESTROY branch on the same target).
  • Cross-affinity application: BRANCH is the shape where the per-genre :allowed-transitions extension (per the MCG addendum’s Q3 resolution — see §11 below) most often kicks in. Genre templates declare which (FROM TO) pairs are legal across the branch fork.
  • Recent-history bias: weighted up if the last 3 contracts were all CHAIN (operators want a decision after a string of forced sequences).
topology_multiplier(2-BRANCH) = 1.0 + 0.3 (per branch path actually taken)
topology_multiplier(3-BRANCH) = 1.2 + 0.3 (per branch path actually taken)

Per the MCG addendum’s +0.3 per BRANCH path parenthetical. Note that the multiplier scales by paths taken, not paths offered — choosing one of two offered branches yields base + 0.3 × 1 = 1.3 for a 2-BRANCH. This rewards the player for making the choice (small premium over MONO) but does not double-count the branch they didn’t run.

For 3-BRANCH (with rejoin), the base is higher because the joined phase 3 adds its own work. The +0.3 still applies for the chosen branch.

The BRANCH header records both branches at accept-time, then writes the chosen branch when the player commits at the fork:

Offset Bytes Field Notes
0 1 shape_tag = 0x03 (BRANCH)
1 1 version = 0x01
2 2 contract_id
4 2 template_handle
6 1 current_phase
7 1 total_phases 2 or 3 (2 for fork-only, 3 for fork+rejoin)
8 4 narrative_seed
12 4 board_seed_at_accept
16 1 branch_count always 2 in v1 (3+ branches deferred to v2)
17 1 chosen_branch 0xFF before fork; 0x00 or 0x01 after
18 8 phase1_meta standard phase block (see CHAIN encoding)
26 8 branch0_meta phase block for branch 0
34 8 branch1_meta phase block for branch 1
42 8 phase3_meta only present if total_phases == 3
50 ... intermediate_state opaque cart-supplied bytes

Worst case (3-BRANCH): 50 header bytes; leaves 206 bytes for intermediate state. Within budget.

The chosen_branch == 0xFF sentinel handles the “fork pending” state — the runtime knows phase 1 completed but the branch decision hasn’t been made. This is the only case where a phase chain encodes a choice gap.

  1. Cannot satisfy both branches: downgrade to CHAIN of equivalent length (2-BRANCH → 2-CHAIN, 3-BRANCH → 3-CHAIN). The player loses the choice but keeps the multi-phase contract.
  2. Cannot satisfy any branch: downgrade to MONO under a different genre roll.
  3. Genre template declares :allowed-transitions that no library cart can fulfill: drop the genre template from the eligible pool for this composition cycle and re-roll.
  4. Cross-affinity adjacency at the fork is incoherent (e.g., genre template allows DIGITAL → AERIAL across the branch but operator’s library has no :bridge cart): emit MISSING_CART_HOOK with the bridge requirement and leave the contract greyed out per §3 fallback rule 2.

§5. PARALLEL — fan-in, both must complete

Section titled “§5. PARALLEL — fan-in, both must complete”
[P1a] ──┐
├→ [P3] (P3 optional; pure fan-in is [P1a]+[P1b])
[P1b] ──┘

Two phases must both complete; order is operator-chosen. Optionally a converging phase 3 ties the results together. This is structurally the inverse of BRANCH — fan-in instead of fan-out.

PARALLEL phases are not simultaneous in the wall-clock sense (the deck is single-cart-active). The operator runs them in sequence but the contract does not gate either on the other’s completion. Either order works; the contract closes when both are done.

  • Eligible at rep tier ≥ 2.
  • Library size gate: requires two carts that satisfy disjoint verbs OR the same verb with disjoint affinity sets. Single-cart PARALLEL is forbidden — the structural value of PARALLEL is “two operations that don’t depend on each other,” which collapses on a single cart.
  • Recent-history bias: weighted up at rep tier ≥ 3 when the operator has been doing CHAIN-heavy boards. Veterans appreciate the “do these two however you want” structure.
topology_multiplier(2-PARALLEL) = 1.4 (slightly higher than 2-CHAIN's 1.2 — both phases, less guidance)
topology_multiplier(3-PARALLEL) = 1.7 (the +1 converging phase adds work)

PARALLEL is more profitable than CHAIN at equal phase count because the operator does not get the linear-narrative scaffolding — they have to plan their own order. A small premium for self-direction.

Offset Bytes Field Notes
0 1 shape_tag = 0x04 (PARALLEL)
1 1 version = 0x01
2 2 contract_id
4 2 template_handle
6 1 current_phase for PARALLEL, this is a count of completed phases (0..2 or 0..3)
7 1 total_phases 2 or 3
8 4 narrative_seed
12 4 board_seed_at_accept
16 1 parallel_count always 2 in v1
17 1 converging_phase_present 0 or 1
18 8 parallel_phase_a_meta
26 8 parallel_phase_b_meta
34 8 converging_phase_meta only if converging_phase_present
42 ... intermediate_state

Worst case (3-PARALLEL): 42 header bytes; leaves 214 bytes for intermediate state.

The current_phase field in PARALLEL has different semantics than in CHAIN — for CHAIN it’s the index of the active phase, for PARALLEL it’s the count of completed phases. The shape_tag differentiates so the runtime dispatcher knows which interpretation to use.

  1. Cannot satisfy both parallel phases with verb-disjoint carts: downgrade to 2-CHAIN (sequential, gated). Loses the “any order” property but keeps the dual objective.
  2. Cannot satisfy converging phase 3: strip phase 3, fall back to 2-PARALLEL.
  3. Operator’s library has only one cart that can satisfy either parallel phase: abort PARALLEL roll, re-roll under MONO or CHAIN.

§6. EPISODIC — repeating instance over a timeframe

Section titled “§6. EPISODIC — repeating instance over a timeframe”
[P1] ─ ─ ─→ [P2] ─ ─ ─→ [P3] ─ ─ ─→ [P4] ─ ─ ─→ [P5] ─ ─ ─→ [P6]
│ │ │ │ │
in-game in-game in-game in-game in-game
timeframe timeframe timeframe timeframe timeframe

Same template, multiple instances, gated by an in-game timeframe rather than immediate succession. The classic “weekly courier run” or “monthly audit” structure. Each instance is a small phase that closes; the next instance unlocks after a gameplay-time delay (which the runtime tracks via session-time-elapsed, not wall-clock).

EPISODIC is the only shape where total_phases exceeds 4 — it can run up to 6 instances (total_phases ≤ 6 is a hard ceiling for v1, gated by phase_chain budget; see fallback rules).

  • Eligible at rep tier ≥ 2. EPISODIC is a reputation-builder mechanic — steady income over time at known threat — and shows up most often in mid-tier boards.
  • Library size gate: EPISODIC requires only one cart (the same template runs each episode). Library breadth doesn’t help; it just changes which template anchors.
  • Recent-history bias: at most 1 EPISODIC contract on the board at any time. The composer rejects a second EPISODIC roll until the existing one closes. (Two concurrent weekly-runs would feel redundant.)
  • :persistence-duration interaction: EPISODIC shape is the procedural equivalent of the :persistence-duration non-nil flag in the existing template-shape (Mission Board plan § “Template shape (cartridge side)”). When a hand-authored template declares :persistence-duration, the composer treats it as an EPISODIC anchor and may extend it with additional episodes.
topology_multiplier(EPISODIC) = 0.8 × N_episodes

Per-episode payout is lower than equivalent-threat MONO (the 0.8 multiplier reflects that EPISODIC is steady income, not adventure) but the cumulative payout is higher. A 4-episode run pays 3.2× a single MONO of the same template. Players rationally choose EPISODIC for income smoothing and MONO for big-payout swings.

Offset Bytes Field Notes
0 1 shape_tag = 0x05 (EPISODIC)
1 1 version = 0x01
2 2 contract_id
4 2 template_handle
6 1 current_phase 1-indexed: which episode is active or about to start
7 1 total_phases 2..6
8 4 narrative_seed
12 4 board_seed_at_accept
16 4 episode_unlock_time in-game-seconds when next episode unlocks (if 0, available now)
20 1 episode_status[6] per-episode status byte (0=pending, 1=in-flight, 2=complete)
26 ... intermediate_state

Header: 26 bytes. Leaves 230 bytes for intermediate state.

episode_status[] is a fixed 6-byte array regardless of total_phases; bytes past total_phases are zero. This keeps the encoding cheap and the parser branch-free.

  1. total_phases > 6: capped at 6 by the encoding. Genre templates that ask for more episodes are clamped silently.
  2. No cart in library satisfies the verb after the first episode (e.g., the cart was ejected and the operator has no other satisfier): pause the EPISODIC contract — episode_status[current] becomes status 3 (paused), Cipher pushes a mission_episodic_paused event into the stream, and the contract sits dormant until the cart returns. EPISODIC is the only shape that admits a paused status.
  3. phase_chain budget exhaustion (intermediate state grows past 230 bytes): the runtime trims the oldest episode’s intermediate state to a hash and frees the bytes. This is destructive for intra-episode reproducibility but acceptable — episodes are independently scored.

§7. NESTED — sub-contract within a contract

Section titled “§7. NESTED — sub-contract within a contract”
[P1] → [P2: ┌────────────────────┐] → [P3]
│ [SubP1] → [SubP2] │
└────────────────────┘

Phase 2 of the outer contract opens a sub-contract with its own internal phases. The sub-contract must close before the outer phase 3 unlocks. Sub-contracts are discovered, not pre-declared at accept-time — the composer rolls the sub-contract during phase 2 execution, based on that phase’s outcome.

This is the only shape where new mission scope appears mid-flight. It is also the shape closest to traditional cyberpunk fiction — “the audit reveals a deeper data dump” — and the most narratively load-bearing.

  • Eligible at rep tier ≥ 3. NESTED is a high-tier mechanic; the composer needs to roll for a sub-contract surprise, and that surprise should land on operators who can handle the threat escalation.
  • Library size gate: requires at least 3 carts in the library OR 1 cart with a verb set ≥ 4. The sub-contract needs its own coherent verb sequence.
  • Cross-affinity application: NESTED is the second shape (after BRANCH) where per-genre :allowed-transitions shows up. The transition between the outer chain and the sub-contract often crosses affinity domains (e.g., outer FINANCIAL chain spawns a SOCIAL sub-contract during interrogation).
  • Recent-history bias: at most 1 NESTED on the board at any time; the surprise mechanic loses force if the operator can predict it.
topology_multiplier(NESTED) = (outer_multiplier + sub_contract_multiplier) × 1.15

Where outer_multiplier is whatever the outer chain’s shape multiplier is (typically 3-CHAIN = 1.5) and sub_contract_multiplier is the sub-contract’s own shape multiplier (typically MONO or 2-CHAIN). The × 1.15 premium rewards the operator for handling the surprise scope expansion without abandoning.

A typical NESTED (outer 3-CHAIN with a 2-CHAIN sub-contract) yields (1.5 + 1.2) × 1.15 = 3.10 topology multiplier. This is the highest multiplier in the grammar — NESTED is intentionally the most lucrative shape per phase-of-work.

NESTED is the only shape whose serialization changes shape mid-flight (the sub-contract gets appended when it spawns).

Offset Bytes Field Notes
0 1 shape_tag = 0x06 (NESTED)
1 1 version = 0x01
2 2 contract_id
4 2 template_handle outer contract template
6 1 current_phase outer phase index (1..total_outer_phases); when in sub-contract, this is the outer phase that hosts it
7 1 total_phases outer total (2..4)
8 4 narrative_seed
12 4 board_seed_at_accept
16 N outer_per_phase_meta N = total_phases × 8 bytes (CHAIN-style)
16+N 1 sub_contract_active 0 = no sub-contract yet, 1 = sub-contract in flight, 2 = sub-contract closed
17+N 2 sub_template_handle only present if sub_contract_active >= 1
19+N 1 sub_current_phase
20+N 1 sub_total_phases 1..2 (NESTED sub-contracts are always shorter than outer)
21+N 4 sub_narrative_seed
25+N M sub_per_phase_meta M = sub_total_phases × 8 bytes
25+N+M ... intermediate_state shared across outer and sub

Worst case (4-CHAIN outer with 2-CHAIN sub): 16 + 32 + 1 + 2 + 1 + 1 + 4 + 16 = 73 bytes. Leaves 183 bytes for intermediate state. Within budget.

The header grows when the sub-contract spawns — the runtime memmoves intermediate state down to make room. This is the only shape that requires a header re-layout mid-flight; the runtime performs it during the inter-phase debrief moment when no cart code is running.

  1. Sub-contract verb cannot be satisfied at spawn time: the sub-contract is downgraded to a single phase (MONO sub-contract) using whatever cart can satisfy any verb in the sub-contract’s genre allowed-transitions list.
  2. phase_chain budget exhaustion at sub-contract spawn (intermediate state has grown past ~180 bytes): the runtime pushes a mission_sub_contract_skipped event into the Cipher stream and proceeds without the sub-contract. The outer contract closes normally with its base multiplier; the player loses the NESTED bonus.
  3. No cart in the library can satisfy the sub-contract at all: same as case 2 — skip the sub-contract, close the outer normally. NESTED degrades to its outer shape, which is whatever was rolled (typically 3-CHAIN).
  4. Outer contract abandoned during sub-contract: the sub-contract is forfeited along with the outer; partial payout is computed against the outer phases completed (per per_phase_meta.phase-base-payout), no payout for sub-contract phases.

§8. ESCALATION — linear with rising threat

Section titled “§8. ESCALATION — linear with rising threat”
[P1: T-1] → [P2: T] → [P3: T+1] → [P4: T+2]

Structurally identical to CHAIN, but with a hard rule: each phase’s threat level is strictly higher than the prior phase. The composer enforces this at instantiation; the runtime enforces it at phase-handler dispatch.

  • Eligible at rep tier ≥ 2.
  • Library size gate: ESCALATION requires the same cart pool as CHAIN of equivalent length. Threat scaling does not require new carts; it requires that the genre template’s threat curve fit within the operator’s tier (max threat at top of escalation must not exceed rep_tier + 2).
  • Recent-history bias: weighted up after a string of MONO/CHAIN contracts that landed at the same threat level. Operators looking to push their ceiling get an ESCALATION offer.
topology_multiplier(2-ESCALATION) = 1.3 (CHAIN 1.2 + 0.1 escalation premium)
topology_multiplier(3-ESCALATION) = 1.7 (CHAIN 1.5 + 0.2)
topology_multiplier(4-ESCALATION) = 2.4 (CHAIN 2.0 + 0.4)

The escalation premium grows superlinearly because the highest-threat phase compounds against threat_multiplier (per MCG addendum §4) — a 4-ESCALATION ending at threat 6 vs. a 4-CHAIN ending at threat 4 has a meaningful payout swing on top of the topology premium.

Identical structure to CHAIN, with one additional invariant validated at serialization:

Offset Bytes Field Notes
0 1 shape_tag = 0x07 (ESCALATION)
1 1 version = 0x01
2..15 .. (identical to CHAIN header)
16 N per_phase_meta CHAIN-style; runtime asserts threat[i] < threat[i+1]
on every phase advance. Violation logs an error and
re-rolls the next phase's threat upward (corrective).

shape_tag = 0x07 lets the dispatcher invoke the escalation invariant check on every phase boundary. Other than that byte, the on-disk encoding is the same as CHAIN.

  1. Genre template’s threat curve exceeds operator tier: clamp the highest-threat phase to rep_tier + 2 (the standard threat ceiling). This may compress the escalation curve — a 4-ESCALATION at rep tier 1 would offer threats 1,2,3,3 instead of 1,2,3,4. Below that ceiling, the strict-increase rule is relaxed to non-decrease.
  2. Cannot find verb-coherent path of the requested length at the requested threat curve: downgrade to plain CHAIN of the same length. Lose the escalation premium; keep the contract.
  3. Insufficient library to satisfy any phase at the top of the curve: emit MISSING_CART_HOOK for the top phase’s cart (per CHAIN fallback rule 2).

[Past contract: completed N sessions ago]
[P1] → [P2] (current contract; references past)

A 2-phase contract whose narrative seed and threat scaling are derived from a previously-completed contract in the operator’s mission history. The first phase recapitulates context from the past contract (Cipher fragment chains across the gap); the second phase is the resolution of the unfinished business.

ECHO is the most narratively distinctive shape — it gives the deck a memory beyond cartridge_history. It is also the rarest shape; the composer rolls ECHO with a low base weight, and only when there is a suitable echo target in mission history.

  • Eligible at rep tier ≥ 3. ECHO requires the operator to have a non-trivial mission history; new operators don’t have completed contracts to echo.
  • Library size gate: requires the cart that anchored the original contract to still be in the operator’s library (not necessarily inserted — the contract can prompt a cart-swap). If the original cart has been forgotten by the deck (cleared from cartridge_history, which is currently a never-cleared bitfield — but reserve room for future cart-deletion), ECHO is ineligible against that contract.
  • History gate: the original contract must have completed (not abandoned) at least 5 sessions ago. ECHO is a callback, not a sequel — too-recent contracts feel like CHAIN.
  • Recent-history bias: at most 1 ECHO per board. Cipher coherence-stack tone shifts when an ECHO is on the board; the echo is meant to feel singular.
topology_multiplier(ECHO) = 1.4 × (1 + 0.05 × sessions_since_original)
capped at 1.4 × 2.0 = 2.8

The base 1.4 is the 2-CHAIN multiplier of 1.2 plus a 0.2 narrative premium. The sessions_since_original term rewards long-deferred callbacks (the deck remembers what the operator did six months ago) — capped so a callback after 50 sessions doesn’t dwarf threat scaling. The cap is reached at sessions_since_original = 20.

ECHO needs one extra field — the original contract’s narrative seed, used to seed Cipher’s recall fragments:

Offset Bytes Field Notes
0 1 shape_tag = 0x08 (ECHO)
1 1 version = 0x01
2 2 contract_id current contract
4 2 template_handle current template
6 1 current_phase 1 or 2
7 1 total_phases = 2 always
8 4 narrative_seed current contract's seed
12 4 board_seed_at_accept
16 4 original_narrative_seed the past contract this echoes
20 2 original_contract_id for QA/debug; not load-bearing for narrative
22 2 sessions_since_original uint16, max 65535 (functional cap is the topology cap at 20)
24 16 per_phase_meta 2 × 8 bytes
40 ... intermediate_state

Header: 40 bytes. Leaves 216 bytes for intermediate state.

The original_narrative_seed is what makes the Cipher coherence chain feel like a callback — the engine seeds its scratch LFSR from this value when generating phase 1’s brief, producing fragment phrasing that rhymes with the original contract’s narration.

  1. No suitable echo target in mission history: ECHO is silently ineligible; the composer re-rolls the genre.
  2. Original-contract cart no longer in operator’s library: ECHO is ineligible against that target; composer searches for another echo target.
  3. Multiple echo candidates within session-distance: pick the candidate with the highest (payout × sessions_since_original) product. This biases toward “memorable past contracts.”

Position: shapes nest, but only narrowly. NESTED is the only sanctioned cross-shape composition primitive.

The grammar admits exactly one form of cross-shape composition: a NESTED contract’s outer chain runs as a CHAIN, and its sub-contract may itself be MONO or 2-CHAIN. No other compositions are legal in v1:

OuterInnerStatusRationale
NESTEDMONO✅ legalStandard NESTED case.
NESTED2-CHAIN✅ legalThe “deeper data dump” form.
NESTEDBRANCH❌ forbiddenTwo layers of operator choice mid-mission overwhelms the inspector UX and saturates phase_chain.
NESTEDPARALLEL❌ forbiddenSame UX/budget issue as above.
NESTEDESCALATION❌ forbiddenThreat curves are designed against the outer chain; nested escalation breaks the gameplay invariant.
NESTEDNESTED❌ forbiddenRecursive sub-contracts cannot fit phase_chain budget.
ECHO(any inner)❌ forbiddenECHO is structurally a 2-CHAIN with narrative dressing; not a host for sub-contracts.
EPISODIC(any inner)❌ forbiddenPer-episode statelessness is the whole point of EPISODIC.
BRANCH-of-CHAIN⚠️ partialA BRANCH whose branches are themselves CHAINs is structurally allowed but counts as a single BRANCH for serialization (the inner sequencing is just multi-phase branches). The shape tag stays 0x03 BRANCH.
CHAIN-with-PARALLEL-segment❌ forbiddenMixing topologies inside a single chain breaks the per-phase-meta encoding.

Practical consequence: the composer’s shape roll is single-stage. It picks one shape from the eight; if NESTED, it then rolls the inner shape from {MONO, 2-CHAIN}. There is no recursive shape grammar.

The cross-shape forbidance list is a deliberate design choice to keep the phase_chain encoding tractable and the operator-facing inspector readable. v2 may revisit (e.g., to allow BRANCH-inside-NESTED if phase_chain budget grows), but only via ADR.


§11. Cross-affinity transitions and per-genre :allowed-transitions

Section titled “§11. Cross-affinity transitions and per-genre :allowed-transitions”

The MCG addendum’s open question Q3 asked whether indirect cross-affinity transitions (like AERIAL → FINANCIAL via PHYSICAL, demonstrated in the §5 worked example) should expand the §2 transition table or be declared per-genre-template.

PM resolution: per genre template. Genre templates declare an :allowed-transitions field listing extra (FROM TO) pairs sanctioned for that genre. The composition algorithm uses the union of (§2 transition tablegenre.allowed-transitions) when checking adjacency.

;; Example genre template excerpt — REVENGE genre
(defgenre REVENGE
:verb-skeleton (OBSERVE MANUFACTURE DELIVER ANALYZE)
:allowed-transitions ((AERIAL FINANCIAL) ; drone-drop dossier triggers panic-sale
(IDENTITY AERIAL)) ; forged dossier delivered by drone
:complication-pool (...))

This resolution applies most often in:

  • BRANCH (§4): the two branches commonly diverge across affinity boundaries. Genre :allowed-transitions defines the legal divergences.
  • NESTED (§7): the outer-to-sub transition often crosses affinity. Genre :allowed-transitions covers it.

It applies less often in CHAIN, PARALLEL, EPISODIC, and ESCALATION — which tend to stay within a single affinity neighborhood — and not at all in MONO or ECHO.

The algorithm change is small: in MCG addendum §4 step 2b, the affinity coherence check becomes:

if (shared_affinity(prev_phase, current_phase) ||
transition_in_table(§2_table, prev_affinity, current_affinity) ||
transition_in_genre(current_genre.allowed_transitions, prev_affinity, current_affinity)):
accept
else:
reject and re-roll

Genre templates that overuse :allowed-transitions (more than ~4 extra pairs) are considered a smell — the genre is too permissive and will produce incoherent compositions. The genre template library sub-task (GWP-280) will codify a soft cap and a lint check.


§12. Forward compatibility / spec hygiene

Section titled “§12. Forward compatibility / spec hygiene”

Per CLAUDE.md Spec Hygiene Rule 3, this plan adds new vocabulary (eight shape names, a serialized shape_tag byte enumeration, the per-genre :allowed-transitions field, the MISSING_CART_HOOK extension to ECHO and EPISODIC) used elsewhere in the corpus. Tracked sweep:

  • docs/plans/post-v0.1/2026-04-25-mission-composition-grammar.md §6 forward-compatibility sweep — this PR adds a checked entry noting shape grammar landed; updates §4 algorithm sketch with a forward pointer to this doc.
  • docs/plans/post-v0.1/2026-04-21-mission-board.mdMissionInstance.flags field already carries multi-cart and bookmarked flags; a future revision should add a shape_tag accessor or expose it via the Mission Board peek API. Deferred until engineering sub-task lands.
  • docs/software/runtime/orchestration.md § “Multi-Phase Missions & Cartridge Swapping → Phase Chain Protocol” — the worked example shows a 2-CHAIN ICE Breaker → Black Ledger contract; should be revisited to mention the eight shapes once this plan graduates. Deferred until graduation.
  • docs/software/runtime/deck-state.md phase_chain field documentation — should reference the shape_tag encoding once this plan graduates. Deferred until graduation.
  • docs/software/runtime/cartridge-lifecycle.md — phase-chain serialization at cart-swap moments should reference shape-aware semantics (e.g., NESTED’s mid-flight header growth happens during inter-phase debrief, not during cart-swap). Deferred until graduation.
  • docs/_meta/definitive-articles.md — no change required; WORKING tier docs are not enumerated. Will register on graduation to DEFINITIVE alongside the parent MCG plan.

When this plan graduates (jointly with the MCG addendum, expected via ADR after the engineering sub-task lands), the deferred items become hard requirements per Spec Hygiene Rule 3.


Q1 — Shape selection bias as a cartridge contribution. Should carts declare a shape-bias in mission-contributions (e.g., NeonGrid biases CHAIN, Cipher Garden biases NESTED)? Currently the composer selects shape independent of the anchoring cart. Cart-driven bias would deepen the per-cart feel of generated boards but adds a tuning surface that may be easy to over-fit. Defer to engineering sub-task; collect playtest data first.

Q2 — ECHO target selection deterministic vs. memory-store-driven. The spec picks ECHO targets by (payout × sessions_since_original). An alternative is to read the Cipher coherence stack and pick a target whose narrative seed has fragments still in coherence. The latter would tie ECHO selection to whatever Cipher has been “thinking about,” which is more diegetic but harder to test. Defer to gameplay design after first playtest.

Q3 — phase_chain budget for very-long EPISODIC contracts. The §6 fallback rule trims oldest-episode intermediate state to a hash when budget is exhausted. This is destructive for replay; QA reproducibility for an EPISODIC contract that spans 6 episodes is gated on the trim-point. Consider whether EPISODIC should serialize episode state into the cart’s per-cartridge save file (ADR-0019) instead of the deck’s phase_chain. Deferred — needs ADR if direction is chosen.

Q4 — NESTED sub-contract spawn fairness. The composer rolls the sub-contract during phase 2 execution. If the operator has already spent considerable time on phase 2, a sudden scope expansion may feel punitive. Should the spawn happen at phase 2 start instead of mid-phase, with the sub-contract teased in the inspector? Trade-off is dramatic-surprise vs. operator-fairness. Defer to first playtest.

Q5 — BRANCH visibility before accept. Currently the inspector enumerates both branches at accept time (per §4 when-to-fire heuristic). An alternative is to hide the branch fork until phase 1 completes — the operator commits to the contract not knowing what the choice will be. This is more dramatically interesting but breaks the “informed bid” contract operators expect. Defer to Josh’s call after a paper prototype.

Q6 — Should :allowed-transitions also support per-shape qualification? A genre template might want to allow AERIAL → FINANCIAL only inside a BRANCH, not inside a CHAIN (where the bridge would feel forced). Currently the field is global per genre. Likely defer to v2; flagged as a smell to watch.

Q7 — ECHO and the cartridge_history width contradiction. ECHO ineligibility checks whether the original cart is still in cartridge_history. Per the Mission Board plan’s open question 1, the canonical width of cartridge_history is contested between two specs (16 vs. 32 bits). ECHO doesn’t care about width per se, but it does care that the bit isn’t cleared. Track jointly with the parent contradiction; no independent resolution needed.


  • Eight shape topologies defined with phase-graph notation (§2–§9)
  • Per-shape when-to-fire heuristic specified
  • Per-shape payout topology multiplier specified, extending MCG addendum §4
  • Per-shape phase_chain serialization specified, total ≤ 256 bytes per shape
  • Per-shape fallback rules specified
  • Cross-shape composition position taken (§10)
  • PM resolution of MCG addendum Q3 baked in (§11 — per-genre :allowed-transitions)
  • Forward compatibility sweep enumerated (§12)
  • Open questions captured (§13)
  • Cross-references added to the MCG addendum in same PR (§4 algorithm sketch forward pointer + §6 sweep entry)