Skip to content

S135 — The replay oracle crosses content epochs - #594

Merged
The-Running-Dev merged 2 commits into
mainfrom
slice/S135-replay-epochs
Oct 11, 2026
Merged

The-Running-Dev merged 2 commits into
mainfrom
slice/S135-replay-epochs

Conversation

@The-Running-Dev

Copy link
Copy Markdown
Owner

What

The replay oracle now crosses content epochs (07 §2, §3, §6; 16 §5.6).

  • Submission is ActionSubmission | AdoptionSubmission{adopt}, and Decision is ActionDecision | AdoptionDecision. Every existing fixture and outcome reads unchanged.
  • buildReplayOutcome checks every version a fixture names before anything runs:
    • an id the registry no longer has → campaign_withdrawn;
    • a starting or adopted version that does not resolve through engine.content to a campaign at that exact version → campaign_version_missing.
  • The game is created on the fixture's campaignVersion, which is the starting epoch.
  • An adoption runs through engine.adoptContent:
    • accepted, it records {index, seq, adopt, accepted: true} at the content entry's seq;
    • refused, it records seq: null with the reason, and findDivergence reports a mismatch at that index.
  • acceptedActions counts actions only.
  • findDivergence treats an adoption recorded where an action was, or the other way round, as a divergence.
  • An adoption naming the version the game is already on is a malformed fixture, and the runner throws.
  • New corpus fixture bureaucracy-epoch-crossing: wait, then adopt 2.1.0, then registry_route_listen. It runs against an archive holding 2.0.0 and a 2.1.0 derived in the test.

Criteria

  • S135.1 — met: S135.1 — Submission and Decision are unions; an action-only fixture reads unchanged (2 tests). Every committed corpus fixture still matches its outcome.
  • S135.2 — met: S135.2 — every version the fixture names resolves through the engine's content first (4 tests).
    • The game starts on a held, non-registry version.
    • A missing adopted version or starting version → campaign_version_missing.
    • An id that is gone → campaign_withdrawn.
  • S135.3 — met: S135.3 — an adoption runs through adoptContent, counts in decisions, never in acceptedActions (6 tests).
    • An accepted decision appears at seq 1, and acceptedActions is 3 of 4 decisions.
    • A refusal records seq: null with its reason, and the replay continues on the pinned epoch.
    • A run the kind now refuses is diverged at 1, and a crossing fixture matches itself.
    • findDivergence tells an adoption from an action at the same index.
    • A same-version adoption throws.
  • S135.4 — met: bureaucracy-epoch-crossing matches its committed outcome in the corpus loop. A mechanics test pins its adoption decision, and the S126 deserialize check covers every state it reaches.

Differs from design

  • The slice's Touches lists src/index.ts. The new types are exported from /authoring (src/authoring.ts), beside the replay types already there, per 20-contract §19. src/index.ts is unchanged.
  • The derived 2.1.0 epoch carries its own migrateState. Adoption runs the target campaign's migrateState from the source version, and the shipped bureaucracy one migrates only from 1.0.0, so an inheriting epoch is refused with migration_failed. This is recorded as a decision: a real next epoch of an adventure-builder campaign needs a migrateState that accepts its predecessor.
  • scripts/capture-save-fixtures.ts and its test, which are not on the Touches list, read actions through actionSubmissions to keep the scripts typecheck green.

The judgement calls are in 90-decisions.md, 2026-10-09.

Verified

Revert verification: each fix was reverted alone, and runner.test.ts plus bulgaria-bureaucracy.replay.test.ts were run (40 tests).

Reverted Failing tests
pre-check resolves every named version 2
createGame on the starting version 1
adoption runs through adoptContent 6
acceptedActions counts actions only 3
findDivergence compares adopt/actionId 1
same-version adoption throws 1
corpus engine holds the next epoch 2

A fixture's submissions may now record adoptions. The runner resolves every named
version through engine.content before starting, creates the game on the fixture's
starting epoch, and replays each adoption through adoptContent, so a refusal is a
divergence at that index. One bureaucracy fixture crosses 2.0.0 -> 2.1.0.
@The-Running-Dev
The-Running-Dev merged commit d87eabf into main Oct 11, 2026
9 checks passed
@The-Running-Dev
The-Running-Dev deleted the slice/S135-replay-epochs branch October 11, 2026 09:29
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