# Dual-version release workflow Maintain Minecraft 1.21.1 and 26.3 independently. The 1.21.1 line retains Dynamic Dimensions AR Edition and Bad Packets. The 26.3 line uses its first-party backend. Do not widen either artifact's Minecraft dependency range or import saves between the tracks. ## Version identity From 26.3.0.1 onward, prefix the Minecraft version and append the milestone/release slice and iteration: Minecraft.release-slice.iteration. Example: `26.3.0.1` -> `rivencraft-26.3.0.1.jar`, Gitea tag `V26.3.0.1`. An explicitly selected prerelease uses a suffix such as `-beta.1`. The existing 1.21.1 release keeps its published version until its next code update; then use the corresponding `1.21.1..` convention. The user authorized regular release status for 26.3.0.1. Release-channel status does not close unfinished parity or multiplayer issues automatically. ## Build and publish For 26.3, update `ports/mc263/gradle.properties`, then run `./gradlew -p ports/mc263 build --console=plain` with Java 25 available. Use the exact built/player-validated artifact; naming/metadata-only changes do not change generation or save behavior. Write release notes, audit the guide/wiki/project description, commit and push the changes, then create and push the matching annotated tag. Preview the `scripts/publish_mod_sites.py release` command with the JAR, changelog, version, display name, Minecraft version, Java version and channel; add `--publish` to upload to Gitea, Modrinth and CurseForge. Tokens stay in the system keyring. Verify published metadata and downloaded artifact hashes. CurseForge approval may remain pending after a successful upload. The publisher accepts legacy Minecraft-prefixed archive filenames and beta tags for already numbered historical uploads; new releases use the identity above. ## Validation gates and issue audit Run appropriate builds and targeted server checks for changed behavior. The user performs visual/gameplay validation. Keep temporary test fixtures out of shipped JARs; use new worlds and remove them regardless of pass/fail. Stop test processes. If generation stalls, hand the test to the user. Before closing a port umbrella issue, compare its acceptance criteria and comments to actual evidence. The expanded-catalog matrix and manual restart/return handoff completed in #100. See [the final parity review](MC263_PARITY_REVIEW.md) for evidence and limits. Shared issues need both versions resolved before closure. For each release, document tested optional versions and no-optional fallbacks, match client/server JARs, preserve the independent 1.21.1 support line, update wiki and platform descriptions, and keep known bugs linked in the release notes. ## Changed-target validation policy Only test a Minecraft target when its code/resources changed. Select targets with `python3 scripts/changed_targets.py --base `. Shared assets can select both; temporary servers must run sequentially. Earlier gameplay sign-off remains valid for unchanged 1.21.1 code. Repeatable local checks: - Java 21 / 1.21.1: `./gradlew build --console=plain`. - Java 25 / 26.3: `./gradlew -p ports/mc263 build --console=plain`. - Smoke one changed target: `python3 scripts/smoke_server.py --target mc1211` or `--target mc263`. - Two-client 26.3 acceptance: `python3 scripts/regression_multiplayer_263.py`. Fixture sources remain outside the shipping JAR. If a test stalls, stop it, preserve logs, delete temporary worlds and hand the remaining check to the user. Do not automatically retry. GitHub and Gitea workflow definitions select changed targets and use `max-parallel: 1`. Hosted execution is not yet verified. Repository runner inventory alone does not establish availability of instance-wide runners. The publisher checks embedded version/Minecraft metadata, Java selection, filename identity, absence of test fixtures and required 1.21.1 dependencies. Apply relevant fixes to both supported lines, with separate implementation and validation per target. Keep version-specific fixes on the affected line. Advancing the newer Minecraft/NeoForge target requires a compatibility audit and must not silently replace 1.21.1 support or widen an existing JAR dependency range. ## Current acceptance evidence (2026-11-14) 26.3.0.3 builds and the user passed book-window mouse-look, right-click return and re-entry. Beta branding is removed. The release collects these changes, the workflow tools and the final parity review. The expanded-catalog dedicated matrix ran with two real clients. Both received runtime-created Ages and authored environment data, traveled using normal books, and passed stale-ack rejection/recovery, occupied-unload refusal, empty-Age reload/reseed and retirement checks. After full server restart both reconnected in the surviving Age with its saved seed and presentation, without the retired Age. The run stalled at the final post-restart return Linking Book step (phase 22). It was stopped, temporary worlds deleted, and the last check handed off rather than retried. Singleplayer preview sign-off does not replace that dedicated check. The player completed the manual dedicated-server restart/return check on 2026-11-14 and explicitly accepted #100. This was one player-operated client, complementing the automated two-client evidence; it is not described as a new automated two-client pass. The test server was stopped, logs retained under build/verification/issue100-manual, and its temporary world removed. See [the final parity review](MC263_PARITY_REVIEW.md). Renderer bug #116 remains separately tracked. #103/#104 and parent #96 close after release verification.