Validation and releases - SocketSVC Docs
SocketSVC Docs

Validation and releases

Automated checks, how to run the full matrix, commit/review rules, release steps and Modrinth publishing

Automated checks

Each project's build runs its check, so these gates are enforced by a normal build:

CheckWhat it actually verifies
:client:fabric:testJUnit regressions for client/common: voice protocol, connection/reconnect, queues, audio state, translations, UI contracts, nametags, plus bytecode checks of the nametag hooks against the real game
:client:fabric:mixinTestStarts Fabric Loader in a separate JVM with the real game classes: confirms SocketSVC is loaded, the EntityRenderState storage interface is injected, and the nametag renderer and LAN hosting Mixins apply
:client:fabric:audioRegressionTestLoads and runs the current OS's native Opus/RNNoise JNI; synthetic regressions of the gate, jitter queue, limiter, echo handling and other existing audio flows
:client:<loader>:verifyClientArtifactThe final JAR's loader metadata, Minecraft/Java/loader constraints, class bytecode version, Mixin config and resources (icons/translations); Fabric additionally checks the WebSocket nested JAR and the JNI libraries for six platforms, NeoForge/Forge check that libraries are relocated and JNI is embedded with Jar-in-Jar
:server:fabric:testserver/common config: the mod's default config is identical to Paper's, YAML reading semantics
:server:<loader>:verifyServerArtifactThe server mod JAR's metadata, bundled libraries, no client or Paper content mixed in, bytecode
:server:paper:testRelay regressions: authentication, routing, commands, hot reload, speaker API, queues and malformed input (the relay is shared with the server mods through common/core)

For how to run these locally, see common builds and tests.

Test reports

ReportLocation
Client JUnit / Mixinclient/fabric/build/<version>/reports/tests/test/, .../mixinTest/
Server mod JUnitserver/fabric/build/<version>/reports/tests/test/
Paperserver/paper/build/reports/tests/test/
Synthetic audio resultsConsole output of audioRegressionTest

What to run for a change

  • For documentation-only changes, checking the content, commands, links and git diff --check is enough; there is no need to rerun unrelated audio tests.
  • When fixing a bug, prefer regression evidence that fails before the fix and passes after it. Do not add tests that merely restate the implementation.
  • When synthetic audio tests pass but real audio is wrong, check device routing, capture/playback settings and do a real two-player test; synthetic tests do not cover every acoustic condition (see audio validation).

There is no CI

Nothing in this repository runs automatically: there are no GitHub Actions workflows and no CI server. Every check and every release is a script in scripts/, run from a laptop, which is also why there is no "CI-only" step that can drift away from what you run locally.

CommandWhat it does
python3 scripts/build_matrix.pyBuilds and tests every client and server mod loader for every supported Minecraft version. Add a version argument (26.2) to do just one.
./gradlew :server:paper:build buildAllProxy -Ploaders=noneBuilds the Minecraft-independent JARs (Paper plugin, proxy relay).
python3 scripts/release.pyThe way to release. A guided terminal tool: checks, versions, release notes, build, GitHub, Modrinth and Discord in one run — see Releasing with release.py.
python3 scripts/publish_release.py --dry-runShows exactly what a publish would build and upload, without publishing.
python3 scripts/publish_release.pyThe full matrix, then a dev-<N> prerelease on GitHub and a Discord announcement. See updates.
python3 scripts/publish_release.py --channel releaseThe same with no version suffix, tagged v<client.version>.

You need JDK 21 and 25, Python 3.9+ and git; publishing additionally needs the GitHub CLI authenticated, and the Discord webhook in scripts/.env (verification needs no credentials at all). The matrix must run serially in one working tree — Loom, ModDevGradle and ForgeGradle share per-version state — so do not run two of them at once.

Because the matrix is read from the version catalog, adding a Minecraft version does not require editing any build script.

What the scripts do not do

There is no in-game client launch and no multiplayer acceptance in any of this. NeoForge/Forge clients are only verified for compilation and packaging. Automated checks are not in-game acceptance; see the per-version acceptance list.

Commit and review

Commits follow Conventional Commits, e.g. feat(client): add device selection, fix(audio): preserve speech endings, docs: document development workflow. The subject focuses on the purpose; unrelated features, resource updates or cleanups go into separate commits. Breaking changes and rollbacks should include the reason and compatibility notes.

Before committing, check git status, git diff, git diff --cached and git diff --check. Commit only files related to the current requirement; never commit build/, .gradle/, IDE settings, game run data, credentials or real authentication details.

A PR description should include the problem and result, the affected modules/Minecraft versions, the test commands and their results, and any in-game acceptance still outstanding; protocol or config changes also describe mixed-version behaviour and rollback.

These are development rules. The repository does not currently declare branch protection or a required number of reviewers.

Publishing

Releasing with release.py

python3 scripts/release.py does a whole release from one command, asking only what it has to, with arrow keys:

  1. Checks that the tree is clean, on main, in step with origin (and offers to fast-forward), and that the GitHub CLI, the Discord webhook and the Modrinth token are all there.
  2. Asks what to publish: a dev build, a stable release, or plan only, which shows everything a release would do and does none of it.
  3. Works out the versions. A stable release proposes the next version from the commits since the last one — a breaking change (feat!: or BREAKING CHANGE) is minor before 1.0 and major after, a feature minor after 1.0, anything else a patch. Client, server and proxy move together; an addon (cinema.version) moves only if its own code changed. A dev build of a version that is already released moves to the next patch first, since 0.2.1-dev.12 would sort below 0.2.1 and nobody on the dev channel would be offered it.
  4. Writes the release notes from those commits, grouped into New, Fixes, Performance and Changes, with a compare link — used for GitHub, Discord and Modrinth. Keep them, edit them in $EDITOR, or write your own.
  5. Steps to include: quick tests before the long build, the GitHub release, Modrinth (stable only), Discord, and — after a stable release — moving the catalog on to the next version, so dev builds keep sorting above it.
  6. Runs it, with every step live on screen and the last lines of Gradle's output under the one running. The version bump is only committed once the build has succeeded; a failed build puts the catalog back. The full output goes to build/release-logs/.

If a run stops partway — a failed upload, a closed laptop — running it again offers to resume, skipping every step that already finished.

--channel dev|release skips the first question, --yes takes every default without asking, and --plan only shows the plan. Standard library only: there is nothing to install.

Before a release

Bump versions. In gradle/socketsvc.properties, update the side(s) that actually changed: client.version, server.version (shared by Paper and the server mods) or proxy.version. New content must never overwrite a published JAR with the same name.

Build the full matrix. Run buildAll, or python scripts/build_matrix.py plus Paper/proxy. Confirm every matrix entry actually succeeded; a skipped or failed entry is not a release.

Accept in-game. With the test artifacts, test two-player voice, mute/deafen, joining/leaving servers and reconnecting, device switching, UI/keybinds, F1 HUD, and nametags with scoreboards/sneaking/occlusion. Native device compatibility must be accepted per OS. See the full per-version checklist.

Record and publish. Check each artifact's origin and Minecraft version, record the verified environments, known limitations and upgrade/rollback method (see release records), then submit the release notes and publish.

Artifacts

ArtifactInstall fileModrinth version number
Client (per version × loader)client/<loader>/build/<MC>/libs/socketsvc-client-<loader>-<client>+mc<MC>.jar<client>+mc<MC>-<loader>@client
Server mod (per version × loader)server/<loader>/build/<MC>/libs/socketsvc-server-<loader>-<server>+mc<MC>.jar<server>+mc<MC>-<loader>@server
Paper pluginserver/paper/build/libs/socketsvc-server-paper-<server>.jar<server>-paper@server
Proxy relay plugin (optional, see Proxy)proxy/plugin/build/libs/socketsvc-proxy-<proxy>.jar; the same jar installs on Velocity or BungeeCord/Waterfall<proxy>@proxy

Not release artifacts

Do not install -plain.jar or -slim.jar; they are not complete artifacts. Do not use leftover artifacts in the old client/build/, server/build/ or proxy-plugin/build/ directories.

Modrinth release script

Publishing to Modrinth uses scripts/modrinth_release.py (Python 3, standard library only). It builds and publishes every client loader, every server loader, the Paper plugin and the proxy plugin, each as its own Modrinth version whose version number carries its side.

# Show the release plan; builds and uploads nothing (no token needed)
python3 scripts/modrinth_release.py --dry-run

# Build everything and publish versions that do not exist yet
python3 scripts/modrinth_release.py --changelog-file CHANGELOG.md

# Only NeoForge clients for 26.2, reusing jars already built
python3 scripts/modrinth_release.py --side client --loaders neoforge --minecraft 26.2 --skip-build
OptionEffect
--dry-runPrint the release plan without building or uploading; no token needed (if a token is available, versions already on Modrinth are shown as skipped)
--skip-buildReuse jars already under */build/; the script stops if an artifact is missing
--side client|server|paper|proxyRelease only these sides (repeatable; default: all)
--loadersComma-separated mod loaders (fabric, neoforge, forge; default: all)
--minecraftComma-separated Minecraft versions for client/server mods (default: all supported); unsupported versions are rejected
--changelog "text" / --changelog-file FILEChangelog text attached to every version
--version-type release|beta|alphaForce every artifact to this type (default: release, or beta for beta loaders)
--replaceDelete and re-publish versions whose number already exists, instead of skipping them; this loses that version's download stats

How it behaves:

  • Token: MODRINTH_TOKEN in scripts/.env (gitignored) or the environment; required for everything except --dry-run.
  • Configuration: scripts/modrinth.json holds the project id and slug, the version name prefix, and the loader tags and dependencies per side and loader.
  • Building: unless --skip-build, client/server mods are built through build_matrix.py for the selected versions and loaders, and Paper/proxy with :server:paper:build and buildAllProxy.
  • Skipping existing versions: a Modrinth version with the same version number is skipped by default, so re-running after bumping only one side's version publishes only that side.
  • Beta loaders: artifacts built against a beta loader (a NeoForge version containing -beta) are published as beta automatically.
  • Version number limit: Modrinth limits version numbers to 32 characters from a restricted character set; the script stops before uploading if a number breaks that, in which case shorten the side version in gradle/socketsvc.properties.

What each side is published with (from scripts/modrinth.json and the script):

SideModrinth loadersGame versionsDependenciesEnvironment
Client, Fabricfabric, quiltThat Minecraft versionFabric API (required), Mod Menu (optional)client only
Client, NeoForge / Forgeneoforge / forgeThat Minecraft versionnoneclient only
Server mod, Fabricfabric, quiltThat Minecraft versionFabric API (required)server only
Server mod, NeoForge / Forgeneoforge / forgeThat Minecraft versionnoneserver only
Paper pluginpaper, purpur, foliaAll supported versionsnoneserver only
Proxy pluginvelocity, bungeecord, waterfallAll supported versionsnoneserver only, not featured

Store listing

The Modrinth project page text lives in the Modrinth listing, beside the release script: a short description (under the Short Desc marker) and the long description (under Long Desc), covering why WebSocket instead of UDP, voice chat features, the spatial speaker API, requirements, installation, server configuration highlights and servers using SocketSVC. The release script only creates versions and does not update the project description, so edits to it have to be applied to the Modrinth project page separately. Keep it consistent with the overview when features or requirements change.

Rollback

  • Roll back to a known-good artifact and keep player settings.
  • For source rollback, prefer a revert with a stated reason; avoid rewriting shared branch history.
  • When withdrawing support for a Minecraft version, update supported and adjust default if needed (see withdrawing a version or loader).
  • Verify protocol rollbacks using the mixed-version mechanism described in the voice protocol.