Repository navigation
S135 — The replay oracle crosses content epochs - #594
Merged
Merged
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The replay oracle now crosses content epochs (07 §2, §3, §6; 16 §5.6).
SubmissionisActionSubmission | AdoptionSubmission{adopt}, andDecisionisActionDecision | AdoptionDecision. Every existing fixture and outcome reads unchanged.buildReplayOutcomechecks every version a fixture names before anything runs:campaign_withdrawn;engine.contentto a campaign at that exact version →campaign_version_missing.campaignVersion, which is the starting epoch.engine.adoptContent:{index, seq, adopt, accepted: true}at the content entry'sseq;seq: nullwith the reason, andfindDivergencereports a mismatch at that index.acceptedActionscounts actions only.findDivergencetreats an adoption recorded where an action was, or the other way round, as a divergence.bureaucracy-epoch-crossing:wait, then adopt 2.1.0, thenregistry_route_listen. It runs against an archive holding 2.0.0 and a 2.1.0 derived in the test.Criteria
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 — every version the fixture names resolves through the engine's content first(4 tests).campaign_version_missing.campaign_withdrawn.S135.3 — an adoption runs through adoptContent, counts in decisions, never in acceptedActions(6 tests).seq1, andacceptedActionsis 3 of 4 decisions.seq: nullwith its reason, and the replay continues on the pinned epoch.divergedat 1, and a crossing fixture matches itself.findDivergencetells an adoption from an action at the same index.bureaucracy-epoch-crossingmatches 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
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.tsis unchanged.migrateState. Adoption runs the target campaign'smigrateStatefrom the source version, and the shipped bureaucracy one migrates only from 1.0.0, so an inheriting epoch is refused withmigration_failed. This is recorded as a decision: a real next epoch of an adventure-builder campaign needs amigrateStatethat accepts its predecessor.scripts/capture-save-fixtures.tsand its test, which are not on the Touches list, read actions throughactionSubmissionsto keep the scripts typecheck green.The judgement calls are in
90-decisions.md, 2026-10-09.Verified
npm run typecheck(both configs),npm run lint: clean.npm test: 119 files, 2345 of 2345 passed. The long-horizon deserialize timeout noted on S133 — Running sessions pick up new content #591 and S134 — Saves and branches carry their epochs #592 did not recur in this run../build/Test-Documentation.ps1: passed (19 generated pages, 135 Markdown files).git diff --check: clean../docs.ps1 -BuildOnlywas not run because it is not installed locally. CI's Verify Documentation Build covers it.Revert verification: each fix was reverted alone, and
runner.test.tsplusbulgaria-bureaucracy.replay.test.tswere run (40 tests).createGameon the starting versionadoptContentacceptedActionscounts actions onlyfindDivergencecomparesadopt/actionId