The ARMv5 matrix entry could only fail: the build refuses GOARM=5 before compilation and the candidate set never contains an ARMv5 archive. Drop it and its allowed-failure setting so a failed job always means a real failure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
22 KiB
Release Process
The maintainer procedure for building, accepting and publishing a release.
Release Packages
Release packages must include the separate User Guide entry, all current user guides and their required local attachments. Architecture, research, contributor rules and developer validation stay in the repository. Packaging uses an explicit allowlist rather than copying the whole tree; update that list in build.sh and its validation whenever the user documentation set changes. Required user procedures must work from the extracted package; optional implementation references may link to the exact release's public source.
Release SOP
Run this procedure for every release. The release workflow enforces the automatic gates below; source review and physical acceptance retain their own explicit decisions.
-
Review scope and repository content. Compare the public baseline with the final source by Files/Locations, Identical, Jobs, Preview, installation/migration and API/CLI. Map retained capabilities to their consumers and meaningful tests; resolve unclear removals before freezing source. Check Demo coverage, including large results and real licensed media where relevant. Review terminology and affected operator/architecture instructions against actual commands and behavior. Update the existing owner, remove superseded claims and close verified issue records. Check the Tape script compatibility contract against the published adapters: run unchanged historical scripts through the current caller, and verify that upgrade preserves customized scripts/helpers. For an explicitly approved incompatibility, check the actionable installer notice and the adapted script boundary. Cover the Tape lifecycle, including empty cartridge memory barcode FORMAT, subsequent identity checks, APPEND and Restore. Keep these checks in the automated suite; a new-template hardware pass alone does not cover upgrades. Inspect modules, tools and temporary files for a current runtime, generator, test or packaging consumer before deleting them. Review ignored local directories separately; CI cannot inspect workstation leftovers. Accepted limitations remain documented and do not become release blockers.
-
Audit the history and prepare a reviewed commit stack. Scan the development range before restructuring it, including intermediate source and commit messages. Review credentials, internal services, personal paths, real data, configuration and private notes manually as well as with the pinned scanner. Rotate an exposed real credential before attempting public-history cleanup; history rewriting needs separate authorization. Recheck the public branch tip and retain a local backup. Re-slice only unpublished development, from its final source, into a stack whose parent is that tip: each commit introduces the final form of one concern with its tests, later fixes and renames belong to the commit they correct, and commits follow dependency order. An incompatible contract change lands with all of its callers. Documentation lands with its concern, or in one final documentation commit when new documents and the index link to each other. Every commit must build and pass its Go and frontend tests on its own, and the stack's final tree must equal the reviewed source. Do not publish the backup branch or rewrite already public history. Review every commit and message again; restructuring does not sanitize content. Finish required dependency releases and update their pins before freezing YATM.
-
Complete review and fixes with affected checks. Review the stack and finish focused fixes/verification until no unresolved, unaccepted finding remains. Fold each fix into the stack commit that owns the change and recheck the affected commits. Use Evidence Reuse; do not run a full preflight per fix. Complete the performance acceptance before source-push approval, retaining unaffected measurements and checking only changed operations again. Start affected hardware verification from a reviewed local build as soon as its source and nonphysical checks pass, following Evidence Reuse. Do not wait for GitHub or the full release matrix to investigate or verify a hardware fix. For workflow edits, validate GitHub syntax and expression contexts before pushing with
go run github.com/rhysd/actionlint/cmd/actionlint@v1.7.12 -shellcheck= -pyflakes=; script diagnostics remain covered by the existing shell checks. -
Run the final source preflight on the clean stack tip. Go commands in release gates and package builders use
GOWORK=offso dependencies resolve from committed module files. Development checks can still use a local workspace. The candidate workflow owns the final full run before its platform matrix. A local full run is available for an intentional integration check or diagnosis, but is not a prerequisite that CI must then repeat. Put Bash 4.4 or newer onPATHfor the Linux installer unit tests; macOS's bundled Bash 3.2 is insufficient. Install the frozen frontend dependencies, pinned scanner and the protobuf tools used by current generated source: protoc 26.0, protoc-gen-go 1.33.0 and protoc-gen-go-grpc 1.3.0. Preview acceptance also requires a separate FFmpeg fixture generator with libx264, 10-bit libx265, PNG, lavfi and display-rotation support. Native release CI also prepares the checksum-pinned CC0 camera samples from the worker fixture inventory, so real-camera acceptance runs for every advertised RAW family instead of skipping for missing local data.node build/release/check-preview-fixtures.mjsgenerates tiny real inputs and fails on missing tools or features. Linux CI builds the pinned generator withbash build/release/build-test-ffmpeg.sh OUTPUT_DIRECTORYafter installing pkg-config, libx264-dev, libx265-dev and zlib1g-dev, and adds itsbindirectory toPATH. This is a test dependency; installed YATM and its packaged helper do not need it. Use a complete Git checkout and run:RELEASE_VERSION=vX.Y.Z RELEASE_COMMIT="$(git rev-parse HEAD)" \ GITLEAKS_BIN=/path/to/scanner/gitleaks make release-checkThe preflight rejects dirty or mismatched inputs, incomplete history, unowned source paths, runtime databases/logs, local configuration, compiled output, archives and scratch files. It scans current source and all history reachable from HEAD, then runs documentation/IDL, Go/frontend/build-tool checks, full race checks, both SQLite paths and two clean generations. Native Preview race tests and vet run with its private libraries during each runnable helper build. Its corresponding-source archive has a separate inventory that retains required vendor/native sources. Filename gates do not prove that a module is used or documentation is semantically correct.
-
Build and accept one candidate set. GitHub Actions requires the exact reviewed commit to exist in this repository's remote. Obtain explicit authorization for that source push before dispatch; this does not authorize a tag, Release or asset upload. Dispatch the Release candidate workflow with
publish=false. Its platform matrix waits formake release-check. Candidate CI validates the complete package set, public archive content, packaged documents, licenses, identities and checksums. Check the exact extracted bytes at affected package boundaries for installation/upgrade, supportedv0.1.xmigration, Archive, Restore, Scan, Volume/LTFS and native Preview. Apply Evidence Reuse to retain valid earlier behavior and hardware evidence instead of repeating every workflow after a rebuild. Use the local package controller with the exact Linux main/Preview archives,--ltfsand a new private evidence directory for its named workflows. Its report does not replace separate browser, legacy-backup or physical-media acceptance. Complete the Media and migration gates, including separately authorized scratch Tape acceptance. A skipped or unavailable required check remains open. -
Approve and publish the accepted bytes. Review the final public source, commit message, Release text and all assets. Obtain publication approval before tag or Release creation and asset upload; any further source push also needs explicit authorization. Follow the existing upload procedure with the successful candidate run ID; it rechecks provenance, content and checksums without rebuilding. Verify public asset checksums against the accepted files after upload.
-
Record evidence and clean owned resources. Report passes, failures, accepted limitations and unrun checks accurately. Keep raw verification output in CI artifacts and sensitive evidence private. Remove only temporary processes, directories and test resources owned by that run.
Release Backend Builds
Linux backend builds require Zig 0.15.2 and always enable CGO, selecting the existing mattn C SQLite driver. build/backend/build.sh preserves version/commit metadata and uses external static musl linking. build/backend/cross-linux.sh defaults to amd64; set GOARCH and, for ARM, GOARM explicitly. Non-Linux release builds retain their existing CGO_ENABLED=0 strategy.
| Go target | Zig target | CPU selection |
|---|---|---|
| linux/amd64 | x86_64-linux-musl | default |
| linux/386 | x86-linux-musl | default |
| linux/arm64 | aarch64-linux-musl | default |
| linux/arm, GOARM=5 | unsupported | Zig 0.15.2 lacks the ARMv5 __sync atomics required by Go CGO |
| linux/arm, GOARM=6 | arm-linux-musleabihf | arm1176jzf_s |
| linux/arm, GOARM=7 | arm-linux-musleabihf | cortex_a7 |
| linux/s390x | s390x-linux-musl | default |
ARMv5 and other unmapped Linux targets or ARM values fail before compilation. CI does not build ARMv5, and the candidate set contains no ARMv5 archive. There is no automatic pure-Go fallback. Every built Linux program passes build/release/check-static-linux.mjs: ELF program headers must have no interpreter or dynamic segment, Go build metadata must enable CGO, and no native Preview module may enter the main dependency graph. This excludes shared libc/SQLite/FFmpeg dependencies. Runtime acceptance remains Linux amd64; other mapped release targets are experimental until exercised on matching hardware.
Distributed main binaries omit Go debug data and strip native debug data at the Linux external link, so compiler and cache paths do not become public package content. Package scanning checks the final executable strings as well as text files; trimming Go source paths alone is insufficient.
GOARCH=amd64 ./build/backend/cross-linux.sh
node build/release/check-static-linux.mjs output/yatm-httpd
The optional native Preview helper has its own module, build, platform baseline and private native libraries. Its native dependencies are never linked into the main binaries.
The source-check job builds the frontend once and collects its locked production dependency
notices. The internal shared-frontend artifact records version, commit, lockfile hash and every
file checksum. Each main-platform build validates its identity and exact file inventory, then
copies the same frontend and Node notices and adds its own Go/native notices. Source maps, private
configuration, missing files and extra files are rejected. The internal manifest is never copied
into a release archive. Local make release calls the same collector; set
FRONTEND_ARTIFACT_DIRECTORY to reuse a previously collected artifact with matching inputs.
Preview native-object caching follows the native build guide.
Release validation requires exactly nine main archives, three optional helper archives and three matching source archives. Each main archive still passes build/release/check-release.mjs; build/release/check-candidate-set.mjs additionally verifies the complete platform set, matching identities, helper file boundaries and corresponding-source checksums. Linux E2E receives the extracted helper through YATM_TEST_PREVIEW_HELPER so native Preview acceptance cannot silently skip.
Release builds require clean committed source and a matching RELEASE_COMMIT. Inputs are exported
from that commit, so ignored workstation files cannot enter recursive copies. The platform matrix
starts only after the source checks, full race suite and both SQLite paths pass. Frontend tests use
two workers to bound local and CI resource use.
Content Scanning
Public content checks use checksum-pinned Gitleaks 8.30.1 with its default credential rules and
additional personal-path/private-service checks. The installer also pins the default rule source;
scans retain its credential rules while removing global dependency/generated-file exclusions.
Install it with
bash build/release/install-gitleaks.sh /path/to/scanner, set GITLEAKS_BIN to that directory's
gitleaks, and run node build/release/check-content.mjs source . HEAD. A different revision range
can inspect unpublished development before restructuring it. node build/release/check-content.mjs artifacts /path/to/candidates checks
nested archives and embedded executable/library strings, normalizing npm .tgz names in a private
scan copy so the scanner opens them. Source maps and dependency sources are
included; the only project exception is the exact deterministic physical-Tape fixture seed at its
owned path. A repository's .gitleaksignore may contain explicitly approved historical fingerprints
in full commit:file:rule:line form. Only the Git history scan reads them; current source and package
scans always use an empty ignore file. Commit-free, wildcard and path/rule-wide exceptions are
rejected. Additions require a separate decision about the specific already published finding;
new commits remain fully scanned. Checksum-validated dependency sources have rule-specific exceptions for public source
identifiers, deterministic test values and recorded upstream build/sample paths. Each is restricted
to its exact nested member and matched value; other credentials or paths in those members still fail. Failures
report rule counts without match snippets, and temporary scanner reports are
deleted instead of uploaded as public CI evidence. Scanner regression tests use the same executable.
Candidate and Publication
The Release candidate workflow runs only through workflow_dispatch. Set version and leave
publish=false to build the candidate set at the selected commit, validate every package and run the
full Linux E2E suite against extracted candidate binaries and the native helper. A successful run
retains the complete accepted set, companion checksums and SHA256SUMS in accepted-candidates.
Build completion establishes neither performance acceptance nor publication approval.
Creating a GitHub Release does not start a build or upload.
For local or remote package acceptance, download only the selected platform's artifacts into one directory identified by the candidate run. For example, Linux amd64 acceptance uses:
gh run download "$CANDIDATE_RUN_ID" --repo samuelncui/yatm \
--name candidate-linux-amd64 --name candidate-preview-linux-amd64 \
--dir "$CANDIDATE_DIRECTORY"
Multiple selected artifacts are extracted into per-artifact subdirectories. The Preview artifact
includes its helper and matching corresponding-source archive. Verify the
downloaded checksums and expected commit, and retain these files for subsequent cases and physical
acceptance. Record the final successful run and artifact IDs; tests started before candidate CI
finishes remain provisional until that same run succeeds. Do not download the complete
accepted-candidates merely to repeat passed CI inventory, content or checksum checks locally.
The publication job retrieves that complete artifact on GitHub when it needs all release assets.
To deliver those accepted bytes, explicitly create the matching Release and tag first, then dispatch
with the same version, publish=true and its successful build candidate_run_id. Publishing runs
no builds or E2E; it downloads that run's immutable artifact by ID. The run must belong to this
repository and the Release candidate workflow (by workflow ID and path), identify a manual build of
that version, and have completed successfully. Its accepted artifact must still be available and unexpired. The release
tag, including an annotated tag, must resolve to the run's exact commit, and the Release prerelease
flag must match the version. Candidate identity comes from run metadata and package contents rather
than the upload checkout. Release tools come from v1, pinned to the same commit for preflight and
upload; no code from the candidate artifact is executed during upload.
Upload repeats provenance and public-content checks, validates the exact 9+3+3 set and every checksum
with the existing package validator, and sends the unchanged archives and checksum files to that
existing Release.
Only the upload job has contents: write; candidate lookup and download use scoped actions: read.
The workflow neither creates a Release or tag nor replaces existing assets. An expired artifact needs
a new build and acceptance run before publication. Mocked provenance and upload tests run through
node --test build/release/publish-candidate.test.mjs without publishing anything.
Evidence Reuse
Finish review and fixes before the final full source and package acceptance. The candidate CI
runs make release-check once before its platform matrix; a duplicate local full preflight is
not required. Use make check for an intentional full integration check, not after every edit.
If a final check finds a defect, verify the fix locally at its affected boundaries before
starting the replacement candidate. Changes to shared contracts or infrastructure may justify
wider checks; record the reason instead of automatically repeating everything.
Retain passing evidence for unaffected components when their implementation, relevant dependencies, configuration, fixtures, harness and environment remain unchanged. Record the old and final source identities and the reviewed diff that establishes this. New archives still need their own content, identity and checksum checks. Rebuilt binaries require relevant package smoke tests; changed behavior requires its package workflows. Acceptance of earlier bytes alone cannot certify a new archive, but a new archive does not require repeating unrelated benchmarks or every exploratory/manual check.
Hardware verification may use locally built binaries after the affected source checks pass; GitHub availability and completion of the full platform matrix are not prerequisites. Build from the reviewed commit with the repository's existing scripts and record the source, toolchain, build flags, binary checksums and runtime adapters. Use the release package when installation or package layout is part of the check. Follow the physical Tape execution procedure for host context, absolute LTFS adapter paths, the scoped two-partition file-backend precheck and durable staged execution. Hardware work can start independently of CI's final release-byte acceptance; that acceptance remains required for release delivery. Source CI and other platform builds can run in parallel. Keep the final artifacts' identity, content and affected package smoke checks; reuse expensive hardware results, including a full Tape write, when comparison confirms that the relevant source, dependencies, build configuration and runtime inputs are unchanged. If those inputs differ or cannot be established, repeat the affected checks and explain why.
Reuse downloaded candidate files for subsequent checks when their run, commit and checksums match. Transfer only the packages and fixtures needed by the selected host and cases. A new report or another case selection does not require another download. Complete-set validation belongs to candidate CI; use its run and artifact records for checks already completed there.
Media and Migration Safety
- Run mounted Volume and LTFS file-backend E2E for affected copy/publication behavior. Use the official LTFS file backend on the isolated Linux acceptance host through packaged binaries and local orchestration; Volume tests use isolated already-mounted directories.
- Run physical Tape E2E only with explicitly assigned scratch media and isolated databases/configuration. A documentation update is not authorization to format, write, or test a cartridge.
- Test migration only on timestamped
cp -acopies of explicitly approved source backups. Keep private source paths and detailed reports outside the public repository. Never modify source backups or production installations during validation. - Compare every migrated Job item-by-item, including non-empty historical Jobs, not only catalog counts. Cover prepare, abort, repeat prepare, commit, and separately confirmed cleanup.
- Clean only validated temporary test media, mounts, databases, Job bundles, and migration copies after validation. Never use production paths as cleanup targets.
- Batch confirmed review fixes before expensive E2E rather than repeating the full suite after each comment. Record actual results and unrun checks accurately; do not claim planned tests passed.
Delivery Gates
The candidate preserves independent format identities and legacy migration/import. Record acceptance for the exact candidate bytes, reusing unaffected source-level evidence under Evidence Reuse; earlier development results alone do not certify a rebuilt release. Preserve a forward path for supported published data. Before the first stable v1 release, replace the pre-stable compatibility policy with the published stable API/upgrade policy.
Branch, push and publication gates follow Delivery and Authorization. Release packages include only the operator documents allowlisted in Release Packages; development and architecture documents remain in the repository checkout.