Repository navigation
S130 — A game can move onto new content, and replays exactly across it - #588
Merged
Merged
Conversation
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
A running game can now move onto another published version of its campaign.
Engine.adoptContent(state, to)runs 16 §5.4's steps 0–8. On success it appends aLoggedContententry, restampscampaignVersionand moves the envelope toformatVersion: 2. On refusal it returns a reason and leaves the state as it was.actionLogis nowLoggedEntry[], and an epoch entry consumes aseq.deserializereads both envelope shapes and refuses a stamp the log contradicts (C26). The §14 harness replays content entries throughadoptContent. A game that never adopts still serializes asformatVersion: 1, byte for byte.Criteria
S130.1 — met:
engine.test.ts› S130.1: an action after an adoption takes seq 2, and its stream equals the one an uncrossed log of the same length derives. A third test coversstartingCampaignVersion.S130.2 — met:
engine.test.ts› S130.2. One test per pinned reason:session_ended;unknown_campaignfor the target and for the source;content_kind_changed;content_not_adoptable;migration_failed(fails and throws);content_incompatible(refuses and throws);invalid_state. Each asserts nostatekey and a deep-unchanged input. A further test shows the kind judges the target campaign's migrated state.S130.3 — met:
engine.test.ts› S130.3: the entry is appended and the envelope restamped; onecore.content.adoptedand onecore.content.pinned, each with versions and reason; the same version returns the same object and emits nothing; a second adoption chains from the first.S130.4 — met:
engine.test.ts› S130.4. 8 negative cases, eachinvalid_state:tothat is notcampaignVersion;formatVersion3;actionId;system;to;seq.2 positive cases: a valid v2 state round-trips byte-identically, and a migration entry whose
fromno archive holds is accepted without being resolved.S130.5 — met:
harness.test.ts› S130.5. A fixture crossing1 → 2on a test kind that declaresadoptContentproduces identicaltraceFixtureoutput, oneserialize()per entry, across two runs. Three fixtures fail: one whose content entry now refuses, one whose entry moves from an epoch the replay is not on, and one carrying a migration entry.S130.6 — met:
engine.test.ts› S130.4 › S130.6 (an unepoched state stays atformatVersion: 1). No golden file or replay-corpus fixture changed, and the full suite passes unchanged.S130.7 — met:
engine.test.tsimportsLoggedEntry,LoggedContent,LoggedMigration,AdoptionResultandAdoptDecisionfrom the package root. S130.7 asserts the three new base reason codes and their messages.Differs from design
branchSessionrefuses a crossed log, as an interim measure. It refuses any source whose log carries an epoch entry withinvalid_stateand writes nothing (store.test.ts: refuses a log that crossed an epoch). Branching across epochs is S134's job; without this guard, a branch would silently replay a crossed log onto the default epoch. Recorded in90-decisions.md.90-decisions.md:frombefore adopting.content_not_adoptable.traceFixture.runFixtureserializes once, because a per-entry trace pushed the long-horizon fixture past its 5 s timeout. The harness is not a package-root export.Verified
npm run typecheck,npm run lint,npm test: 115 files, 2257 tests passing../build/ConvertTo-HumanDocumentation.ps1and./build/Test-Documentation.ps1pass.git diff --checkis clean.branchSessionguard: its test fails;fromcheck: the mismatch test fails../docs.ps1 -BuildOnly(no installeddocs.ps1); the Verify Documentation Build check covers it.