This repository is the independently releasable MIT source of truth for Game Protocol 1: Protobuf schemas, normative QUIC/framing/value specifications, generated Go and Rust contracts, descriptors, and language-neutral fixtures. It is a new protocol and has no classic packet-ID, C/Python, MAP2, ADS, gRPC, or GPL compatibility path.
Game Protocol 1 is part of Atrinik's agentic next-generation reimplementation and improvement of Atrinik Classic. This fresh MIT-licensed Protobuf, specification, and Go/Rust support code is developed primarily through Codex-driven workflows under maintainer direction, review, provenance controls, tests, and validation. Direct human-written code and specification contributions are welcome under the same requirements; “agentic” describes the project's primary current software-development workflow, not every line, commit, or contributor.
The current implementation is a new independently authored contract supporting the replacement, not a mechanical translation of Classic packet IDs or code. That historical fact does not prohibit later exact historical reuse admitted under the provenance policy. See the replacement roadmap and the canonical project authorship statement for the wider technical and authorship context.
The Go and Rust bindings in this repository are deterministic outputs of the Protobuf toolchain. Protocol message instances can carry or refer to maps, quests, lore, dialogue, art, audio, and other game-world content. The schemas and bindings define how those values are represented; they do not author the game world.
proto/atrinik/game/v1owns gameplay schemas;proto/atrinik/metaserver/v2owns the current public directory model; v1 remains immutable historical baseline evidence.specowns bounds, units, ordering, state, authorization, privacy, framing, stream, close, and compatibility rules that Protobuf cannot express.gencontains reproducible generated Go bindings and descriptors. Generated Rust bindings live insidecrates/atrinik-protocol/src/generatedso the registry package is self-contained.framing,validation, andmetaserverare the small Go consumer support packages.crates/atrinik-protocolis the Rust consumer package.fixturesis language-neutral conformance input; negative cases must leave previously committed consumer state unchanged.compatibility/baseline.binpbis the M1 Buf breaking baseline. Never replace it to hide an incompatible change.
The current access-token contract defines Classic
publisher v3, Game publisher/directory v2, bounded code routing, and mandatory
GP1 1.1 access-policy negotiation. Current Go consumers import
github.com/atrinik/protocol/metaserver/v2; Rust uses metaserver::v2,
metaserver::directory_v2 and metaserver::access. Earlier versioned adapters
are historical contracts, not runtime fallbacks.
The current ALPN is atrinik-game/1. Frames use canonical unsigned LEB128
lengths and are capped at 1 MiB for gameplay/control or 4 MiB for resources.
See the transport specification and
common-value specification. Certificate-bound
metaserver publishers use the strict RFC 9421/RFC 9530 profile in
the publisher specification, including exact
canonical classic and Game Protocol 1 body fixtures and the Game publisher
JSON Schema. Classic publisher v1 remains frozen with human-password semantics;
the distinct signed Classic v2 profile, schema, Go codec, and conformance
fixtures use accessCodeRequired for the open/access-code-protected cutover.
The replacement server directory uses the independently versioned bounded
model and canonical static JSON contract in
the directory specification, with generated
Go/Rust model types and byte-identical conformance fixtures.
The supported tools are Go 1.26.6, Rust 1.97.1, Protobuf 35.0, Buf 1.72.0, protoc-gen-go 1.36.11, and protoc-gen-prost 0.5.0. The reusable Atrinik Linux devcontainer supplies them. A clean clone needs no sibling checkout.
tools/generate.sh
tools/validate.shtools/generate.sh is the only supported generated-output command. It checks
tool versions, formats/lints schemas, regenerates both languages, and rebuilds
the descriptor. tools/validate.sh additionally checks the breaking baseline,
generated drift, Go vet/unit/race/fuzz compilation, Rust format/Clippy/tests/doc
tests/Windows cross-build, dependency licenses, fixtures, and release dry-run.
Cargo resolves dependency versions from Cargo.lock; Go uses the requirements
in go.mod and minimal version selection, while go.sum authenticates module
content. policy/dependencies.json records ownership and review policy for
direct dependencies without duplicating versions; validation compares it with
the manifests, checks the resolved Cargo and Go graphs for forbidden sources,
and evaluates resolved Cargo license expressions against the SPDX policy.
The aggregate required check is Protocol validation. Release tags create a
source/bindings/schema archive, descriptor, fixtures, checksums, CycloneDX
SBOM, build provenance, notices, and MIT license. Every release asset is a flat
file covered by the outer SHA256SUMS. The deterministic
atrinik-protocol-contracts-VERSION.tar.gz additionally contains the complete
contract layout, both nested directory fixture trees, and its own checksum
manifest. Extract that bundle to validate nested fixtures; the GitHub asset
glob cannot upload directories. A Rust crate version has
exactly one policy-owned repository release, revision, asset name, and digest
in policy/rust-crate-release.json. Only that owning release may include the
self-contained registry-ready .crate; later repository releases omit it
until a separately reviewed policy assigns a new crate version. Provenance
records both coordinates and whether the crate is included, so a repository
release never silently regenerates a published crate version from a different
Git revision.
Protocol 0.2.0 is published. Future reviewed Cargo version bumps use the automatic library release contract. The manual procedure below records the original 0.2.0 publication and its pinned artifact; it does not govern later versions. The manifest allows only crates.io.
Crate atrinik-protocol version 0.1.0 is registered on crates.io with
SHA-256
413c4da6c1b304d4a622065efe0d36c3f591041972f1a5ee76c538926f3c0b6b.
That checksum is the reviewed asset from release v1.4.0, revision
47b821a16ba955bebc79fc31e3b3bada8d74b33e. The one-use bootstrap workflow
has been removed, its GitHub environment secret was deleted, and its API token
was revoked after the public registry checksum was independently verified.
Release v1.4.0 is the sole owning repository release for crate 0.1.0.
Release v1.5.0 predates the one-owner enforcement and contains a second,
noncanonical asset with the same crate version but different revision-derived
bytes. That historical asset must never be published or substituted for the
policy digest. It is retained as immutable release history; ordinary future
repository releases omit crate 0.1.0 rather than regenerating it.
policy/rust-crate-publishing.json records future publication as
reviewed-automatic-publication; policy/crate-release.json owns the current
allowlist and historical archive lineage. A reviewed Cargo version change,
merged to protected main with required checks, authorizes automatic publication.
One-time environment, Trusted Publisher and immutable-release setup remains
an owner operation coordinated through github-settings.
Read CONTRIBUTING.md and PROVENANCE.md before proposing contract material. The cross-repository roadmap is atrinik/atrinik#168.
Crate 0.2.0 was published by the separately authorized
publication run.
The public API, sparse index and downloaded archive agree on the checksum below.
policy/rust-crate-candidate.json retains its historical preparation declaration;
policy/rust-crate-next.json marks the reviewed artifact ready-for-publication
and pins its prepared source release v2.8.0,
revision a47537790f5ea8a08adf7e6dffee4fa794cf3665, asset
atrinik-protocol-0.2.0.crate and SHA-256
cda65c3c322993cfab378454fb9b1182df8a000216f4abd1170e53cdfdc3b3bb.
The approved preparation run
packaged that clean source twice, and an isolated local reproduction matched.
The immutable published 0.1.0 policy remains unchanged. Later source releases omit these historical registry crates; they cannot
regenerate or replace the prepared bytes. Future reviewed version bumps use
the automatic publication contract below.
The manual publish-crate.yml workflow has explicit prepare and publish
operations. Its default is prepare, which requests no OIDC token and only emits
an Actions artifact. A preparation approval never authorizes publication. Inputs
for publication must match the exact reviewed tag and revision above. Both
operations run only on main in repository ID 1327106950; checkout uses the fixed
workflow-run revision, while packaging uses the separately pinned source release.
Never package activation HEAD as a substitute for the prepared source.
The one-time publication attached the exact prepared archive to v2.8.0, then verify its public asset digest. The verifier refuses a missing or mismatched asset; it cannot substitute an Actions artifact. GitHub reports the source release as mutable, so repeated tag, provenance and asset-digest checks detect drift rather than claiming GitHub release immutability. Attaching a new asset also requires a separately reviewed complete checksum-inventory update; never leave an unchecked extra asset or silently alter an existing contract/source archive.
A credential-free verify job reproduces the pinned source twice and validates
its release asset, public package/owner identity and registry API/sparse-index
state. Missing or conflicting evidence stops before the protected publication
job. An already published identical version is an idempotent success; different
bytes or an indeterminate registry state stop without upload.
The publication job requires operation=publish, that successful preflight and
the crates-io-release environment. The automatic environment is main-only with zero required reviewers, zero wait
time, and no registry secrets or variables. Reviewed merges and successful
checks authorize each release after one-time owner setup.
Environment and crates.io Trusted Publisher setup are separately authorized owner
operations, tracked in github-settings#86.
Trusted Publishing binds atrinik/protocol, publish-crate.yml and that exact
environment. Only this job grants id-token: write, which gives every step OIDC
request authority. It never installs a toolchain or runs Cargo, package builds,
proc macros or dependency code. After environment admission, verify-upload fetches
the exact public release archive as inert bytes and checks its reviewed digest,
inventory and provenance. It freshly checks the workflow checkout, pinned source
ancestry, public tag/release, complete release inventory, owner and registry state
before token exchange. It writes the same checked archive snapshot for upload.
All reproduction remains in the credential-free jobs; packaging also refuses
OIDC request authority at runtime. Only the upload step receives the short-lived
token from the pinned official action; its post step revokes the token. No long-lived registry credential is allowed.
The bounded uploader verifies the archive snapshot and public state again, then
sends those exact archive bytes using the documented
Cargo registry publish API.
It does not invoke cargo publish, which would repackage the source. The request
uses a fixed HTTPS endpoint, refuses redirects, never retries an uncertain write,
and never logs the token or response body. After an attempted upload, the
credential-free verifier checks public package/owner identity and agreement
between the registry API and sparse-index checksum, including when the uploader
fails. It skips cancelled runs and skipped uploads; a matching checksum does not
turn a failed upload step into workflow success. An uncertain result requires
inspection before another separately authorized publication attempt.
The historical 0.2.0 publication is confirmed by the registry evidence above. Consumers still require the production registry release and normal dependency-lock validation; source workflow success alone does not establish registry readiness. See the official token action.
After one-time Trusted Publishing setup, a reviewed Cargo version bump publishes
without a second release approval. Repository semantic-release versions remain
independent. policy/crate-release.json defines the public crate allowlist,
required source checks, workflow/environment identity and historical pins.
policy/rust-crate-candidate.json accompanies a new source version in the same PR;
future candidates use reviewed-automatic-publication. No post-release policy PR
is needed to copy a checksum back into source.
The read-only source job plans the next repository version, runs the aggregate,
packages the public crate graph twice and builds the extracted archives. It emits
crate-release.json with actual source revision, source tag, inventory, registry
metadata, archive SHA-256 and a content checksum excluding only VCS metadata.
Changed package content with a reused Cargo version fails. Historical 0.1.0 and
0.2.0 retain their original bytes; unchanged versions are omitted from subsequent
source releases. A pending publish set forces at least a patch source release
even when ordinary commit rules would otherwise skip it.
Maintenance branches keep their ordinary source/binary releases, but their real
publication manifests contain no registry coordinates and omit registry crate
assets. Only mainline preparation may establish a crate's owning source release;
the inert finalizer independently rejects a nonempty maintenance manifest.
A separate write-enabled job reanalyzes the repository release and verifies the
complete prebuilt payload with the inert finalizer before publishing it. A separate
inert signing job verifies the same payload and attests crate-release.json with
the pinned official action. This job has OIDC and attestation-write permissions
but runs no npm, Cargo, installation or package code. Source
release immutability is enabled once through github-settings before activation.
The finalizer uses no administration credential: the settings endpoint cannot be
read using GITHUB_TOKEN. The pinned GitHub release plugin creates a draft, uploads
the complete asset inventory, and only then makes it public. Every registry path
requires the resulting public release to report immutable=true. Semantic-release
then explicitly dispatches publish-crate.yml with operation=automatic, exact
source_release_id, source_revision and manifest_sha256. This avoids GitHub's
suppression of release events created with GITHUB_TOKEN, and crates.io's rejection
of workflow_run OIDC exchanges.
The registry workflow checks protected-main ancestry, the exact source workflow
and required checks, complete release checksums, safe archive inventory and
metadata. It cryptographically verifies the manifest's attestation using the
preinstalled GitHub CLI (2.68 or later), an isolated empty config and no child
credentials. The certificate must identify this repository ID, main ref, exact
source and workflow commit, release.yml, and a successful producing run attempt.
The predicate's claimed run ID alone is insufficient. The attested manifest binds
every crate digest; manually forged releases cannot reuse an unrelated successful
workflow run. Immediately before upload it rechecks release and asset identities,
names, sizes and digests; download counters and editable release notes do not
constitute artifact drift. Its fresh upload job runs no Cargo or package code. It exchanges OIDC
immediately before sending exact verified archive bytes. Internal dependencies
publish first; API, sparse-index and downloaded checksums must agree before the
next crate proceeds. Matching existing versions are skipped and conflicting bytes
or yanked versions fail. Before each PUT, the inert upload job uses repository
contents-write authority to create an intent commit and atomically reserve refs/tags/crate-upload-intent/<crate>/<version>. The typed intent records
source/manifest/archive digests, producing run and a random nonce. Only an acknowledged
201 ref creation followed by matching readback permits the first PUT. This separate
tag namespace never edits main or creates an application release. The helper
restricts its GitHub writes to intent commits and this fixed namespace.
An existing reservation blocks every later PUT for that coordinate, including a new workflow, source release or changed digest. A lost reservation response, a crash before PUT, or an unresolved registry response remains blocked; no automatic reset is provided. Exact confirmed registry bytes can still be skipped safely. Owner-reviewed recovery must preserve the intent evidence and establish whether the registry accepted the write. Public absence alone is insufficient proof of a failed write. Only after authoritative confirmation of no accepted publication may an owner explicitly remove the reservation and authorize a fresh attempt. A matching published coordinate keeps its reservation permanently. Hourly reconciliation dispatches one incomplete source release through these same gates. It does not change versions, overwrite artifacts, yank crates or merge PRs.
If repository immutability is misconfigured, a source release can become public but bootstrap and OIDC publication both fail before any registry write. Enabling the setting does not retroactively make that release immutable. Stop automatic reconciliation for the affected lineage and use explicit owner-reviewed recovery: confirm that none of its crate coordinates were published, preserve its evidence, and replace the mutable source release/tag under the corrected setting. The automation never deletes or rewrites a release to recover. Resume only when the exact source, checksums and immutable public release pass the ordinary gates.
Local candidate verification is credential-free:
python3 tools/crate_prepare.py check-version --base BASE_COMMIT
python3 tools/crate_prepare.py prepare --dry-run --source-tag v0.0.0 --output /tmp/crate-proof
python3 -m unittest tools.test_crate_releasecheck-version counts a Cargo.lock-only change as package content only when it
changes the locked graph reachable from a published crate, so dependency updates
confined to unpublished workspace tools need no crate version bump. Preparation
still compares the complete packaged content with the owning archive.
The dry-run manifest is preparation evidence only. Live publication requires a clean reviewed revision, complete immutable source release and configured identity. New crate names in other families need a one-time first publication before crates.io Trusted Publishing can be registered; this does not introduce per-version approval.
The shared bootstrap helper is only for these previously absent library names.
An owner runs it from an interactive terminal on a clean reviewed main revision,
with exact --release-id, --revision, --manifest-sha256, --expected-owner
and --expected-owner-id arguments. It verifies the same immutable source and
registry evidence, requires a typed owner confirmation, and prompts privately for
a short-lived publish-new token. Create that token in the named owner's crates.io
account; the API cannot introspect its identity. The owner also needs a separate
existing gh login with repository contents-write permission for the atomic intent.
The helper checks that GitHub actor against the named owner before reserving; the
registry token never reaches the GitHub CLI. Never put it in chat, shell
arguments, environment variables or GitHub secrets. The helper checks ownership
after each confirmed first publication. Revoke the token and register Trusted
Publishing once the names exist. Established protocol names cannot use this path.
The protocol-specific extracted-package verifier intentionally checks exactly one archive, matching its one-crate policy. The shared preparation helper delegates verification to each physical repository: renderer and content-toolkit own their complete multi-crate graph verifiers. Adding another protocol crate requires a reviewed allowlist and protocol verifier change together.