Local precompiled deployment candidate
Target reader: server deployment and maintenance operators.
R1 / G6A provides deployment preparation and isolated local acceptance for Contracts 0.4.0-alpha.1, schema 000025. This remains a development/evaluation candidate. Real servers, HTTPS, production mail and formal R1 release require a separately started G6B.
Game developers still install the fixed SDK package. Operators use Infra release/rc.py to lock seven repository commits/trees, run check and build, and obtain a standalone bundle/ with input, image identity, SDK provenance and checksums. Runtime containers mount no application checkout and do not compile Go or install npm packages. The same inputs can be rebuilt; byte-identical Docker tar archives are not claimed. Platform support must follow the actual acceptance manifest.
Minimal example
Run inside the delivered bundle/ as an unprivileged host user. Docker/Compose, Python 3.12+ and Bash are required. Use a new dedicated project name; published ports bind only to loopback. init creates random, distinct credentials and private configuration without overwriting an existing file.
python3 deploy.py --env ./private.env --project echo-g6a-example init
python3 deploy.py --env ./private.env --project echo-g6a-example load
python3 deploy.py --env ./private.env --project echo-g6a-example validate
python3 deploy.py --env ./private.env --project echo-g6a-example deps
python3 deploy.py --env ./private.env --project echo-g6a-example migrate
python3 deploy.py --env ./private.env --project echo-g6a-example initialize
python3 deploy.py --env ./private.env --project echo-g6a-example up
Migration is separate from API startup. The migrator owns schema objects; application and operator use different restricted database credentials and cannot modify migration records or execute DDL. Application startup and maintenance of an initialized database verify complete schema checksums. Archive/admission checks on an empty target verify the independent backup and latest seal. Storage administrator, Public, Admin and operator have separate S3 identities; application credentials cannot administer storage. Server consent/feature gates and current membership/session authorization remain unchanged.
Common mistakes
Configuration contains secrets: never share it or full docker compose config output. Console receives only public Admin API, game Public API and Docs origins. CONSOLE_URL controls Admin CORS; S3_PUBLIC_ENDPOINT controls attachment signing. Change runtime configuration and restart the same images. Never put Keys, JWTs, SMTP credentials or signed URLs into frontend configuration.
Local acceptance uses HTTP and synthetic Mailpit capture. A future reverse proxy can route the five public origins to loopback ports. G6B must verify real domains, certificate trust/renewal, actual Godot HTTPS and production SMTP. Public API ignores Forwarded/X-Forwarded-For; a real proxy remains responsible for client-level ingress rate limits.
Operations and recovery
datactl and accountctl are precompiled, default to dry-run and require --apply for changes. observe makes bounded one-shot health/readiness checks, emits local JSON and returns nonzero on failure. It sends no external notification and installs no scheduler.
python3 deploy.py --env ./private.env --project echo-g6a-example datactl --action inspect
python3 deploy.py --env ./private.env --project echo-g6a-example observe
COMPOSE_ENV_FILE=./private.env COMPOSE_PROJECT_NAME=echo-g6a-example python3 scripts/backup-local.py --root ./private-backups --apply
Retention remains 90 days for feedback/comments/attachments, 7 days for backups, 180 days for sanitized audit, and 7 days for SDK local data. Retain PostgreSQL, objects, independent recovery-journal, separately latest recovery-witness, private backup root and current recovery control directory. Candidate authority files live in an authority/ subdirectory of each persistent volume. Journal/witness are excluded from DB/object backups. Multiple volumes on one host are not off-host disaster recovery.
Restore requires an independently empty target, an approved backup and the latest cutover seal. Keep source applications fenced/stopped; bind the target to the original independent authority. Correct deletion/revocation and physically clean objects before access. Old passwords, sessions, codes and pending invitations become invalid. Repeating a completed restore verifies current data without replaying an old dump. Missing/stale authority, wrong ownership or cleanup failure keeps access closed. See the bundle README and data lifecycle for exact commands and bounded retries.
stop stops applications; down retains persistent volumes. Never remove source authority with down -v while a target still uses it. Application replacement/rollback must stay within an explicitly tested contracts/schema/recovery protocol window; database migrations remain forward-only.
Next step
Module checks, headless browsers and real dependency acceptance are separate evidence. Real Godot editor/OS input is a distinct gate: never fabricate native acknowledgements. Source canonical clean-stack and artifact acceptance are distinct. Artifact tests must inspect actual images, mounts, programs and checksums; all required browser suites must have zero failures, skips and retries.
G6B still needs server/architecture, Git/CI/registry, certificates, production SMTP, independent backup/authority storage and alert recipients, plus production capacity/project cost limits, actual RPO/RTO, licensing and support/export matrices. MinIO has ended maintenance of its open-source distribution; the pinned image remains local evaluation only, pending a maintained production storage choice. The SDK license remains development/evaluation. A working local candidate is not a formal release.
Authorized test deployments
A separately authorized test deployment may freeze release/images.amd64.lock.json using rc.py lock --images release/images.amd64.lock.json; the original ARM64 candidate stays unchanged. The target must load and run the exact AMD64 images and pass its own HTTPS, mail, SDK and operator checks. A build or cross-compilation does not establish support.
For an explicit project directory, set CANDIDATE_DATA_ROOT in the private bundle environment to a private absolute directory named for the Compose project. Its parent must already exist with mode 0700. deps creates only a new owned directory and named volumes bound to its separate PostgreSQL, object, journal and witness directories. Existing unmarked data or conflicting volume bindings are refused. The packaged deploy, backup and restore commands select the same layout. A restore target keeps its own DB/object directories but binds the source journal/witness as external authority; retain that source authority. This remains single-host recovery.
The test namespace is echo-g6b-<name>. Non-local test configuration requires SMTP_RECIPIENT_ALLOWLIST to contain exactly the one authorized recipient. The Admin API checks this restriction before any SMTP envelope/message; other recipients receive the existing generic API response without mail being sent. Also restrict the mail-triggering ingress routes to authorized testers, bound the number of messages, and verify actual inbox receipt separately from SMTP acceptance. Addresses and credentials stay in private configuration. These controls do not bypass verification or establish production readiness.
SMTP uses a 2-second connection deadline and a 10-second conversation deadline, shortened by any earlier request deadline. This allows bounded STARTTLS/authentication round trips; it does not prove inbox receipt.
Account-code requests allow up to 5 seconds for shared transport setup before any eligibility lookup. Then both eligible and ineligible addresses use the same 3-second delivery deadline and response floor. The maximum 8 seconds fits the existing 10-second Console timeout and hides eligibility-dependent mail latency.