Skip to content

W120 — One Campaign Can Include Another - #568

Merged
The-Running-Dev merged 2 commits into
mainfrom
slice/W120-campaign-composition
Oct 7, 2026
Merged

The-Running-Dev merged 2 commits into
mainfrom
slice/W120-campaign-composition

Conversation

@The-Running-Dev

Copy link
Copy Markdown
Owner

What

Builds W120: campaign composition as contracted in #561 (04 §10.4, 11 §3a, 03 §1.1, §5, §8.3).

  • Core (core/registry/compose.ts): checks includes, authored-version pins, kind match, cycles, aliases and attachment hosts, using seven codes. It composes depth-first, each campaign once, and hands modules and attachments to Kind.composeContent. Both buildValidatedContentRegistry and buildValidatedPackRegistry compose before validation runs.
  • Packs: resolvePacks returns authoredVersions and attachments. A pack's digest gains includes and attachments only when they are non-empty.
  • Story-graph (kinds/story-graph/compose.ts):
    • merges modules under alias:: ids;
    • synthesizes auto entry and exit nodes;
    • maps exits and bindings, using six codes;
    • appends attachment choices.
  • Other story-graph changes:
    • new copy consequence;
    • alias-scoped interpolation;
    • Tier 1 checks for copy and for composed ids.

Criteria

  • W120.1: types declared; exported from the package root and /authoring.
  • W120.2: both registry builders compose first.
  • W120.3: all seven core codes are rejected with paths. Tested in core/registry/compose.test.ts.
  • W120.4: all six story-graph codes are rejected with paths. Tested in kinds/story-graph/compose.test.ts.
  • W120.5: an authored : id is still invalid_identifier (node, var, achievement, alias, composed-shaped host id).
  • W120.6: copy reads from as the batch left it, and clamps once. Tier 1 rejects an undeclared from, a type mismatch, a non-subset enum and an undeclared var.
  • W120.7: a host played through a module entry, the module, and out again:
    • deterministic on repeat;
    • a save/load cut equals the uncut run;
    • entry and exit cost one turn each;
    • visited.<alias> counts entries;
    • the input is copied in and the output copied out;
    • interpolation is alias-scoped;
    • module achievements arrive prefixed.
  • W120.8: an attachment appends one choice after the authored ones. Multiple attachments keep their order, and an attachment on a module reaches every host.
  • W120.9: no fixture or golden changed. The digest moves only for an include or an attachment.
  • W120.10: the human docs are regenerated and the guide is restamped.

Differs from design

  • get-next-slice.ts reports the plan "Finished" because it parses only ## S<n> headings. This ledger uses ### [ ] W<n>, so W120 was picked by hand.
  • Implementation calls not fixed by the contract are recorded in 90-decisions.md, 2026-10-07 — W120: composition is built as contracted. These are:
    • validation stops at composition errors;
    • bindings check against the host's own variables;
    • the entry node interpolates in the host's scope;
    • module strings come first in the validation union;
    • merge collisions are raised by composeContent.
  • 20-contract.md §12's note that composition's codes "are not in reasons.ts until W120" is updated.

Verified

  • npm run typecheck, npm run lint: clean.
  • npm test: 112 files, 2104 tests passed.
  • 64 new tests: 35 rejecting, 29 passing. All 13 composition codes have rejected at least one fixture.
  • Mutation-checked: reverting each of the following made its tests fail, and each was restored:
    • the enum-subset rule in isAssignable;
    • alias-scoped interpolationScope;
    • the compose memo;
    • attachments reading the composed host's nodes.
  • ./build/Test-Documentation.ps1: drift check passed (18 pages plus the guide), 131 Markdown files.
  • git diff --check: clean.
  • Not run locally:
    • ./docs.ps1 -BuildOnly. Rely on the Verify Documentation Build check.
    • The advisory test-design.ts reports 49 findings, all pre-existing path-fragment false positives (/authoring, /contract); none were introduced here.

Builds the campaign composition contracted in #561: the core checks includes, pins,
cycles, aliases and attachment hosts (seven codes) and composes depth-first, each campaign
once; story-graph merges modules under alias:: ids through Kind.composeContent (six codes),
with entry and exit as synthesized auto nodes and bindings carried by the new copy
consequence. Pack attachments append one choice to a host node after the fold, and a pack's
digest moves only when it carries includes or attachments, so every committed
campaignVersion is unchanged.
@The-Running-Dev
The-Running-Dev merged commit 7081402 into main Oct 7, 2026
8 checks passed
@The-Running-Dev
The-Running-Dev deleted the slice/W120-campaign-composition branch October 7, 2026 20:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant