A release in this family is three things that must meet in the right order: the addons (versioned by tag), the lock in dot-server-deploy that names the tag each server installs, and the web shell, the client that frames a game in the browser. Get the order wrong and the failure is either a CI error or, worse, a player on a client that cannot fetch what the server runs.
The orders
| Releasing | Order |
|---|---|
| an addon | tag the addon → the site publishes its pack (hourly, or “Pull now”) → bump addons.lock in dot-server-deploy and push → restart the servers |
| a game | tag every addon it needs → lock them and push → wait for the web-shell workflow’s tag → tag the game |
| a new shell | nothing by hand: push the lock (or a client/ change) and the web-shell workflow exports, uploads, pins and tags |
- Push the lock only after the packs are on the origin. A client that cannot fetch an addon pack joins on its own addons and does not retry that server this session. Check with
curl <origin>/<owner>/<repo>/<version>/manifest.json. - Publish content before the build that needs it. A build published without its packs is a client that can mount no game.
- Each skipped step fails in CI, not on a player’s machine: the CI of dot-server-deploy parses every script against the lock at the locked refs, and a game’s release refuses a pack that no released server tool can run.
Tagging, and what CI does with the tag
Every repository calls the shared dot-ci workflows, pinned to the major tag. The current line is v1 (at the time of writing, v1.3.5), so @v1 follows compatible fixes without you editing each repository.
- On every push,
validateruns the two-step check from Installing. - On a
v*tag,releaseattaches the artifact and aSHA256SUMSfile, and for a game builds its content pack. It signs nothing: the signature is made by the site when it publishes the pack. - The pack is published as
<site username>/<repository>, and the owner segment is the site username, not the GitHub owner.
addons.lock
The lock names a release tag per addon repository. setup.sh clones at it and moves its own clones there on --update. Before the lock, every install took each addon’s newest main while shells were exported whenever, and a server ahead of the shell refused the join.
tools/addons-lock.sh checkbefore an export: a shell exported from a tree that is not at the lock matches no locked server.tools/addons-lock.sh writelocks every repository to its newestv*tag (by version order, not by date), orwrite v0.1.3to one tag. It refuses a lock with a hole in it, because a missing entry would install that addon atmain.- Only clones that
setup.showns are ever moved. A developer’s sibling checkout is never detached onto a tag.
What needs a new shell
An addon release reaches players by a server restart. A new shell is needed for a change to the engine version, to the boot stage, to the shell’s own client/ code (admin menu, loading screen, notices, party and friends UI), to the signon revision (an older shell is refused with “This server needs a different build of the game client”), to files an addon puts outside its own folder, or to the page the engine runs in.
The shell publishes itself
Nobody exports, uploads or pins a shell by hand. A push to main that touches a shell input starts the web-shell workflow, which:
- compares the tree’s fingerprint with the one recorded for the pinned shell and stops if they match;
- otherwise sets up fresh addon clones at the lock and exports the web build;
- uploads it, writes
web/shell-build, commits “Pin the web shell”, tags the nextv0.1.xand pushes both together; - dispatches the release workflow on that tag.
Servers then pick the new shell up on their next start, and the site registers the build the first time one reports it. A release refuses to go out with a shell that is not its own, which is why you do not tag a lock bump by hand: push it and release the workflow’s tag.
Check the deployed bytes, not the export
An export that was never published looks identical to a fix that did not work, because the browser runs the previous build and prints the previous errors byte for byte. Believe nothing about client behaviour until you have checked what the page actually loaded.
