From 93190d5e0ccde1097086d3483c5f0bbeafcf8ec0 Mon Sep 17 00:00:00 2001 From: codex Date: Mon, 27 Jul 2026 16:34:54 +0000 Subject: [PATCH] docs(prd): define complete release flow --- docs/prds/0083-packaged-infra-artifacts.md | 152 ++++++++++++++++++++- 1 file changed, 146 insertions(+), 6 deletions(-) diff --git a/docs/prds/0083-packaged-infra-artifacts.md b/docs/prds/0083-packaged-infra-artifacts.md index ed10ee21..7541a124 100644 --- a/docs/prds/0083-packaged-infra-artifacts.md +++ b/docs/prds/0083-packaged-infra-artifacts.md @@ -1,6 +1,6 @@ # PRD 0083: Packaged infrastructure artifacts -- **Status:** Active +- **Status:** Draft - **Author:** Codex - **Created:** 2026-07-27 - **Issue:** #536 @@ -63,6 +63,15 @@ supply-chain boundary between release production and runtime. - Source-checkout development retains an explicit local-build mode. - Publishing produces the infrastructure first and the installable Python package last, so the package cannot name artifacts that were not published. +- Any branch, tag, or commit can be resolved once to a full source SHA and + published as one immutable, commit-addressed artifact bundle. +- The installer defaults to the production channel, can select staging or an + exact commit, and warns for commit snapshots that have not been qualified as + a release. +- Staging and production releases promote the same tested artifact bytes; + promotion never rebuilds them. +- A release is published only after the complete pre-release suite and a clean + install from the published bundle succeed. ## Non-goals @@ -76,6 +85,8 @@ supply-chain boundary between release production and runtime. cached locally. "Pull" means acquire the packaged identity, with safe cache reuse. - Supporting live source overlays in packaged production installs. +- Defining the project's version-numbering policy beyond stable + `vX.Y.Z` and staging `vX.Y.Z-rc.N` tag shapes. ## Design @@ -138,6 +149,116 @@ The build hook receives the manifest as a file input. It must not query a registry or choose versions itself: package builds stay deterministic and network-independent once their release inputs exist. +### Commit-addressed bundle index + +Every publication resolves its requested branch, tag, or commit to one +40-character source SHA before doing any work. The publisher writes an +immutable external bundle index under that SHA. The index contains: + +- schema version and source SHA; +- wheel URL and SHA-256; +- orchestrator and gateway OCI digest references; +- Firecracker package versions and compressed-file SHA-256 values; +- producing workflow/run identity and publication timestamp; and +- qualification records, if any, naming the test workflow and release tag. + +The embedded wheel manifest contains the runtime subset of the same identities. +Publication fails if the embedded manifest and external index differ. + +Bundle coordinates are immutable. Re-running publication for a SHA verifies +and reuses a byte-identical complete bundle; it never replaces one artifact or +mixes outputs from different runs. A partial existing bundle is an error and +requires an explicit administrative cleanup before retrying. + +Commit bundles are durable release inputs, not expiring CI artifacts. The +project may garbage-collect unqualified snapshots only under a documented +retention policy; qualified staging and production bundles are retained. + +### Branches, tags, and promotion + +The protected promotion topology is: + +```text +feature -> main -> staging -> production + | | + vX.Y.Z-rc.N vX.Y.Z +``` + +Changes reach `staging` and `production` through promotion pull requests; those +branches do not accept direct development commits. A staging tag must point to +a commit reachable from `staging` and uses `vX.Y.Z-rc.N`. A production tag must +point to a commit reachable from `production` and uses `vX.Y.Z`. + +Channels are small, mutable pointers to immutable qualified bundles: + +- `production` points to the newest promoted stable tag; +- `staging` points to the newest promoted release-candidate tag; and +- `main` is not a release channel; its commits are installable snapshots. + +Channel updates are serialized and monotonic. Moving a channel to an older +release requires a distinct, explicit rollback operation that records the +reason and target. Deleting or moving a Git tag does not mutate a published +bundle or channel silently. + +Promotion reuses the exact bundle selected by source SHA. It does not rebuild +the wheel, OCI images, or Firecracker artifacts. Thus production runs the same +bytes qualified in staging. + +### Publication workflows + +`publish-artifacts` is manually dispatchable for any branch, tag, or commit. +It resolves the input to a source SHA, checks out that SHA, builds and publishes +all infrastructure artifacts, generates the bundle index and embedded +manifest, builds the wheel, installs the wheel in a clean environment, and +publishes the verified wheel. It does not create a release or update staging or +production. Its output is an unqualified snapshot and publication is +serialized per source SHA. + +After required CI succeeds, `main` may invoke the same publication operation +automatically. Manual publication remains available so a branch can be tested +before merge. Automatic and manual runs converge on the same idempotent bundle. + +The release workflow is triggered by an eligible staging or production tag: + +1. Resolve and validate the tag, source SHA, tag shape, and branch reachability. +2. Run the complete pre-release suite against that SHA, including Docker, + Firecracker, and Apple Container. +3. After the suite passes, ensure the immutable commit bundle exists. Build it + then if absent; otherwise verify every existing identity and checksum. +4. Install using the published installer and bundle index on clean supported + hosts, and run the post-install smoke test against the acquired artifacts. +5. Attach a qualification record to the bundle, create the Gitea release, and + advance the matching channel pointer. + +No release artifact or channel update occurs before qualification succeeds. +Jobs use per-SHA and per-channel concurrency locks so concurrent dispatches +cannot publish twice or race a promotion. + +### Installer selection and warnings + +The installer installs the latest `production` channel by default. It accepts: + +- `BOT_BOTTLE_CHANNEL=production` or `staging` to select the latest release in + that channel; +- `BOT_BOTTLE_REF=<40-character-sha>` to install an exact commit bundle; and +- `BOT_BOTTLE_VERSION=` to install an exact qualified release. + +Selectors are mutually exclusive. Branch names are accepted by the publication +workflow but not by the installer because they are mutable; callers resolve +and publish them first, then install the reported SHA. + +An exact-commit install prints a prominent warning that the snapshot may not +have passed release qualification, even if the same SHA is later associated +with a tag. A tag or channel install suppresses that warning only when the +external index contains a successful qualification record for that tag and +the tag selects the same bundle SHA. + +The installer downloads the wheel named by the external index, verifies its +SHA-256 before invoking pipx or pip, and reports the selected channel/tag, +source SHA, and bundle identity. It never builds a Git checkout for a packaged +install and never trusts a mutable channel response without resolving it to an +immutable bundle index. + ### Backend-neutral lifecycle Rename the host-side control-plane lifecycle operation from `ensure_built()` to @@ -215,11 +336,30 @@ backend catches an acquisition failure and rebuilds from local source. - Extend wheel-install coverage to inspect the installed manifest. - Run the full unit and Docker integration gates; run advisory Firecracker and macOS integration before publishing a release. +- Test ref resolution, tag-shape and branch-reachability enforcement, bundle + idempotency, partial-publication rejection, and per-SHA concurrency. +- Test installer channel, tag, and exact-commit selection; checksum rejection; + mutually exclusive selectors; and snapshot warning behavior. +- Test that release qualification happens before publication and that a failed + suite or clean-install smoke test cannot create a release or move a channel. +- Test promotion reuses the qualified bundle byte-for-byte and that monotonic + channel movement rejects an accidental rollback. ## Rollout -Land runtime and publishing support together, but do not publish an installable -release until its infrastructure artifacts have been published and the -generated manifest has passed clean-install validation. Existing source -checkouts use explicit local mode. Existing mutable local images are ignored by -production acquisition and may be pruned independently. +Land runtime, installer, bundle publication, and release qualification support +together, but do not move the production installer away from its current +source-install path until an end-to-end staging release has passed on Docker, +Firecracker, and Apple Container. + +Create and protect `staging` and `production`, then promote one commit from +`main` through both branches. Publish its commit bundle, qualify an RC tag, +perform clean installs through the staging channel, promote the same SHA, +qualify a stable tag, and only then make the production channel the installer's +default. The stable promotion must demonstrate that every production artifact +identity matches the staging-qualified bundle. + +Existing source checkouts use explicit local mode. Existing mutable local +images are ignored by production acquisition and may be pruned independently. +Snapshot retention and rollback procedures must be documented before automatic +publication from every successful `main` commit is enabled.