# Milestone 6 instability regression and migration check (#73) This is the release-slice acceptance record for instability, not a promise of general old-save compatibility. The latter remains issue #60. Run the focused archive with `./gradlew build runGameTestServer -ParchivedGameTestSuites=instability`; it includes the default smoke suite. For 0.5.8.10 on 2026-10-10, that dedicated GameTest server passed all 55 required tests with no optional content/client integrations installed (the required Dynamic Dimensions and Bad Packets dependencies were present). The full archive was not run; it has a previously documented storage stall, so do not count it as passing. The 0.5.8.11 run with live block profiling stalled in its initial batch and was stopped; it is **not** a passing result. The live profiling scenario is handed to the player in [the block-profile checklist](LIVE_BLOCK_INSTABILITY.md). ## Automated coverage | Requirement | Existing default test or focused archive | | --- | --- | | Stable writing, defective writing, score explanations, repeated use of the same book | `AgePersistenceGameTests.instabilitySeparatesStableAndDefectiveWriting` | | Frozen score, age-scoped writing cost, random baseline | `AgePersistenceGameTests.randomBaselineAndBrightBalanceAreFrozen`, `auditedSymbolCostsAreCountedAndAgeScoped` | | Complete Age definition, score and provider-plan save/load | `AgePersistenceGameTests.authoredPlanRetainsResolvedMeaningAndAgeIdentity`; `AgeInstabilityRuntimeGameTests.selectionIsDeterministicAndFrozen` | | Old pre-scoring Ages, score-only saves, removed symbols, unavailable handlers | `AgePersistenceGameTests.missingRegistryEntryDoesNotReinterpretAnOldAge`, `instabilitySeparatesStableAndDefectiveWriting`; `AgeInstabilityRuntimeGameTests.savedPlanSurvivesAgeUpdatesAndMissingHandlers` | | Per-Age controls and changed config without score/plan reroll | `AgeInstabilityRuntimeGameTests.perAgeControlsPersistWithoutChangingScoresOrOtherAges`; `Milestone6RegressionGameTests.disablingEffectsCannotRerollFrozenPlan` | | Hazard cooldown and attempt sequence across saved-state reload | `AgeInstabilityRuntimeGameTests.hazardCooldownAndAttemptSequenceSurviveReload` | | Active-Age rotation, action/tick budget | `AgeInstabilityRuntimeGameTests.ageScopeRotationAndActionBudgetAreBounded` | | Multiplayer loaded-chunk-only candidate selection, deduplication and cap | `Milestone6RegressionGameTests.multiplayerCandidatesStayLoadedDeduplicatedAndCapped` | | Decay loaded-chunk target and spawn protection | `AgeDecayGameTests.targetMustRemainInChosenLoadedChunk`, `savedSpawnAndPlatformAreProtected` | | Explosion policy gates and protected blocks | `Milestone6RegressionGameTests.disabledGriefAndProtectedBlocksStayUntouched` | | No Overworld status or decay provider | `AgeStatusEffectGameTests.overworldCannotRunAnAgeStatusProvider`; `AgeDecayGameTests.overworldCannotRunDecayProvider` | | Optional-mod material weights, block overrides, and old profile migration | `Milestone6RegressionGameTests.commonModdedMaterialWeightsStayBounded`, `blockProfileSamplesPersistWithoutDoubleCounting` | | Ordered celestial modifier consumption, repeated modifiers, and dangling +100 per kind | `WritingGrammarGameTests.orderedGrammarAcceptsPartialWritingAndDiagnosesInvalidSequences`; `EnvironmentWritingGameTests.celestialModifiersFollowWrittenOrder` | These tests exercise saved-data serialization and deterministic policies. They do **not** simulate a complete process restart, an actual multiplayer server, optional-mod installation, or real terrain and hazard visuals. The three new checks live only in the `instability` archive to avoid duplicating default tests. ## Migration outcome and known gaps - Pre-scoring Milestone 5 Ages load with a neutral score and no effects; they are not retroactively rescored under current writing rules. - Score-only Ages receive a deterministic provider plan once from their saved score and Age seed. An already-saved score and plan retain their meaning when pages, handlers, or runtime config change. Unknown but syntactically valid provider IDs are preserved and skipped if their handler is unavailable. - Missing symbol definitions do not reinterpret a frozen instability score. That check is narrower than arbitrary missing biome, block, or worldgen registry entries: loading a world with removed data packs is not guaranteed. Broad save compatibility and migration remain tracked in #60. - Version-3 plans keep their previous stage-sorted celestial interpretation and frozen writing cost. Only new version-4 plans consume period/phase modifiers in authored order and charge a trailing modifier once per pending kind. - In-process roundtrips cannot prove that Age dimensions reload correctly after a full stop/start. Check that in a real client/server world. Do not add another GameTest for it if it hits the documented storage stall; hand the exact scenario to the player instead. - The dedicated GameTest run establishes classloading with no optional runtime flags. It does not establish classloading with every optional integration installed, nor the reverse of removing one from an existing save. ## Manual in-game matrix Use a fresh test world, then keep one save for the restart and data-pack checks. Record the seed, mod list, age name, and `/rivencraft age instability` output before and after each change. Do not deliberately remove a required registry entry from a valued world; copy the test save first. 1. Bind a low-instability book and a deliberately unstable book. Reuse each book and verify the Age name, dimension ID, score, selected providers and provider levels remain unchanged. Exit the Ages, stop Minecraft completely, restart and re-enter; compare the same diagnostic values. 2. With two survival players in one unstable Age and a third player in the Overworld, verify effects stay in the Age, follow the Age players, and do not appear in the Overworld. Move both Age players away, let old chunks unload, and confirm hazards do not keep remote chunks loaded or operate there. Confirm controls on one Age do not alter a second Age. 3. Disable global instability, then world mutation, then one provider. Verify the suppressed effect stops and the frozen score/plan do not change after re-enabling or restarting. With block destruction disabled, trigger an explosion in an expendable Age; check that arrival platforms, portals, block entities and protected blocks survive. Check lightning, explosion, decay, status-effect, burning, meteor and erosion visuals where selected. 4. With Biomes O' Plenty or another TerraBlender biome mod, confirm recognized biome pages still author an Age and the instability diagnostics remain stable after restart. Repeat with Serene Seasons installed, then absent in a disposable copy; confirm its Age season behavior and that Rivencraft itself still loads. JEI should display the relevant pages and recipes when installed, while the mod works without it. Separately, install a mod with common-tagged ores/storage blocks or source fluids. Compare a material-rich Age with an ordinary Age after the profile thresholds are reached; the installed mod's recognized blocks should affect the result without a Rivencraft allowlist. Then remove that optional mod in a disposable copy and confirm Rivencraft still starts. Test a single `block_weight_overrides` entry and a zero-weight exclusion. This remains a player-run scenario, not an automated pass. 5. Check the book preview separately with its fallback animation, Ponder/Create, and Immersive Portals when available. Opening a book should not change player location, instability diagnostics, or ambient audio in the actual Age. Do not install both season mods together for this matrix. 6. On a copied save, remove or alter a **nonessential** data pack providing a writing symbol or optional handler, then reload. Existing saved scores and provider plans must not reroll. If a referenced worldgen registry entry prevents load, record it against issue #60 rather than treating #73's frozen-instability guarantee as general missing-registry support. The matrix is guidance for a player-run pass; none of these six scenarios is claimed as completed by the automated result above. The player reported an in-game pass for the 0.5.8.18 candidate on 2026-10-12. That is a release-slice acceptance report, not a claim that every expanded matrix row below was individually exercised. ### Regression run record For each row, record pass/fail, world seed, Age name, Rivencraft version, optional-mod versions, and a short observation. "Not run" is intentional until a player completes the in-game check; a successful build is not a pass. | Area | Specific manual observation | Status | | --- | --- | --- | | New vs reused book | Dimension ID, score, and providers do not reroll | Not run | | Full process restart | Re-enter two Ages; saved traits, score, plan, and cooldowns persist | Not run | | Multiplayer isolation | Two Age players receive effects; Overworld player does not | Not run | | Loaded-chunk scope | Departing players permit unloading; hazards do not reach old chunks | Not run | | Controls | Global, per-Age, mutation, and provider toggles suppress effects without reroll | Not run | | Protected blocks | Explosion/decay/erosion spare arrival platforms, portals, and block entities | Not run | | Hazard visuals | Lightning, explosions, decay, status, burning, meteor, and erosion each behave when selected | Not run | | Third-party biomes | TerraBlender biome pages and cave classification survive Age creation/restart | Not run | | Optional integrations absent | Mod launches without JEI, Create/Ponder, Immersive Portals, Serene Seasons, or biome mods | Not run | | Optional integrations present | JEI pages/recipes, preview backends, seasonal behavior, and ambient sound work | Not run | | Optional-mod materials | Tagged ore/storage/source-fluid samples change live profile automatically | Not run | | Material overrides | Positive and zero `block_weight_overrides` values affect only named blocks | Not run | | Removed optional mod | Disposable copy launches without the mod; unknown sampled IDs stay serialized | Not run | | Removed symbol/handler | Frozen score and provider plan survive when nonessential data is removed | Not run | | Ordered modifiers | Five book-order cases below produce expected time and dangling costs | Not run | ### Focused ordered-writing and optional-material checks for 0.5.8.18 Use `/rivencraft age instability` in each newly bound Age; old Ages retain their original plan and score. Record each row as pass/fail with the Age name, world seed, installed optional mods, and the command output. The ordered modifier assertions are archived, not a claim that the stalled GameTest suite ran. | Book pages after Link Panel, in exact order | Expected result | Result | | --- | --- | --- | | Half Length, Double Length, Normal Time | Length combines to 1.25×, no dangling cost | Not run in game | | Normal Time, Zero Length | Sun keeps normal motion; one dangling +100 | Not run in game | | Rising, Normal Time, Setting | Rising start phase; Setting dangles +100 | Not run in game | | Half Length, Double Length, no celestial page | One combined pending length dangles +100; seeded clock remains | Not run in game | | Normal Time, Zero Length, Normal Time | Last sun consumes Zero Length; duplicate celestial cost remains separate | Not run in game | With a common-tagged ore/storage-block or source-fluid mod installed, bind comparable material-rich and ordinary Ages and wait for profiling thresholds. Verify the modded material contributes automatically, then restart and confirm the score/profile remains consistent. On a disposable copy, remove the mod and confirm Rivencraft launches without it; restore the mod before judging the world's registry-dependent terrain. Also check a zero-weight override and a positive override. These are optional-mod compatibility checks, not a new required dependency.