# Historical 2.0.3-alpha OTA and ISO procedure This is a version-specific record, not the current release procedure. The commands below name old tags and artifacts. Use the current [Release & Testing](../Release%20%26%20Testing/README.md) scope and exact release instructions before preparing or publishing a newer build. Historical target: **2.0.3-alpha**. The numeric patch had to exceed deployed `2.0.0-alpha+uat`: the updater ignores suffixes when comparing versions. The existing `v2.0.1-alpha` and `v2.0.2-alpha` source tags are retained unchanged. Administrator-recovery and target-specific manifest corrections belong to this successor source boundary. See `target-specific-release-manifests.md`: guarded target test deployments precede final release publication. ## 1. Lead-owned review and freeze Read unresolved entries in `docs/post-1.8.22-regressions-20261001.md` and the current operator acceptance ledger. Record every ngit proposal disposition and accepted merge commit. The original 20 proposals plus aggregate are applied at `c32a925647eab63ba0f1cac7e6bd135b857d5b7b`; subsequent dirty fixes need separate review and acceptance. Ref parity does not prove proposal disposition. Prepare version declarations, lockfiles, generated catalogs and curated release notes **before** the source freeze. Review/merge once on ngit and mirror the exact accepted commits to Gitea. The lead creates the annotated release tag on that immutable versioned commit, under separate publication authority. Never retarget a published tag. Use a fresh clean checkout (detached at the tag is supported). Record HEAD and the annotated tag object, not just its peeled commit. ```bash git status --short git rev-parse HEAD refs/tags/v2.0.3-alpha refs/tags/v2.0.3-alpha^{commit} python3 scripts/check-git-mirrors.py --local --ref refs/tags/v2.0.3-alpha python3 scripts/check-git-mirrors.py --local --all python3 scripts/release_payload.py source --version 2.0.3-alpha ``` Both reviewed main and annotated tag objects must match both mirrors before publication. Inventory unrelated advertised-history drift explicitly. No independent mirror merges, force pushes, or rewriting published history. ## 2. Prepare unsigned pending OTA artifacts Set `AAPT` and `APKSIGNER` to the installed Android SDK tools if they are not on PATH. Packaging checks the APK's actual version against node metadata, v1/v2/v3 signatures (including the min-SDK-21 v1 path), and existing certificate pin. Qualified code59 is `0.5.39-debug`, SHA256 `abaf9fe0e25f3bcad166790a7ad24b69cb7f9849bc20dc2210c88eec62a1ccaa`. ```bash bash scripts/create-release.sh 2.0.3-alpha --dry-run flock /tmp/opencode/release-heavy.lock bash scripts/create-release.sh 2.0.3-alpha ``` This runs the release harness, locked/offline native backend build, frontend, AIUI and radio builds, then stages artifacts under `releases/v2.0.3-alpha/` and an **unsigned** manifest under `releases/pending/v2.0.3-alpha/manifest.json`. There are no test bypass flags. Backend tests use the isolated runner. All full UI/Rust/ISO builds and heavy fixtures take the shared lock for the entire run. Preparation does not bump source versions, commit, create a tag, sign, or promote the public feed. It refuses existing candidate paths: retain failed attempts and investigate rather than overwrite possibly signed evidence. AIUI BUILD-INFO records the same clean commit as the manifest and annotated tag. Source mutation during builds is a failure, not permission to attribute dirty bytes to HEAD. The frontend archive is flat. It carries exact Companion APK/JSON bytes and all runtime scripts/configs, including newly added D09/C01/network/typed helpers. `archipelago-runtime/RELEASE-PAYLOAD.json` declares the version, source commit and per-file SHA256. Archive verification rejects missing, stale, duplicate, linked, mis-permissioned or nested payloads. Payload delivery is not privileged installation/admission authority. ## 3. Operator signing, then ISO build Only after artifact inputs exist, preparation prints the exact pending-manifest signing command. Run that command on the operator terminal. `sign-manifest.sh` requires an explicit pending path, validates staged bytes and frozen source, and uses the staged native verifier. Missing signers fail. Never provide mnemonic material to an agent, command line, report or file. The ISO wrapper consumes the signed **pending** manifest; publishing the live feed first is neither needed nor permitted as a build prerequisite. ```bash flock /tmp/opencode/release-heavy.lock bash scripts/build-iso-release.sh ``` The wrapper rechecks source/tag, manifest bytes/signature, release tests, catalog and Companion. It extracts the exact verified frontend archive for the builder, then compares its entire web payload against the ISO's extracted bytes. Only a newly created unambiguous ISO is accepted. Smoke and QEMU gates are mandatory. The successful build prints the exact ISO signing command once its input exists. The ISO signer refuses to overwrite an existing checksum document. Kernel-lane checks must prove the selected ISO boot kernel and installed kernel are fixed Debian `6.12.113-1` or later. Installed and **running** evidence are distinct; an installed update does not fix a still-running vulnerable kernel. QEMU boot is not physical install/reboot acceptance. ## 4. Upload and verify; lead promotes the feed separately After signing, artifact acceptance and explicit publication authority: ```bash flock /tmp/opencode/release-heavy.lock bash scripts/publish-release-assets.sh 2.0.3-alpha gitea-vps2 ``` The uploader checks clean tagged source, manifest source, exact mirrored refs, local hashes and cryptographic signatures. It uploads OTA and signed ISO assets, verifies public OTA downloads, release links, and full ISO/checksum/signature download hashes. It never merges branches, pushes tags, commits, or promotes the feed. Credentials stay in the credential helper. ISO signed JSON must describe the actual ISO, independently of the text checksum file. The lead retains the upload receipts and required installed/physical/UAT acceptance, then prepares a canonical reviewed feed-promotion commit containing the exact verified signed manifest in both feed paths. Mirror that exact accepted commit, keeping the immutable build tag unchanged. Recheck both mirrors and public downloads after promotion. Do not rebuild/tag from the feed-promotion commit. ## 5. Acceptance remains separate Source tests, synthetic artifacts and healthy services do not establish release acceptance. Retain independent evidence for immutable artifacts, normal native startup, guarded installed migration, OTA canary/reboot/rollback, clean ISO install, physical hardware and operator acceptance. Paid-file recovery must never repay; preserve wallets, persistent data and uninstall decisions. Record remaining deferrals honestly. No missing acceptance becomes a pass through this workflow.