docs(prd): define complete release flow
prd-number-check / require-numbered-prds (pull_request) Successful in 10s
tracker-policy-pr / check-pr (pull_request) Successful in 18s
test / coverage (pull_request) Successful in 50s
test / image-input-builds (pull_request) Successful in 46s
test / integration-docker (pull_request) Successful in 1m6s
test / unit (pull_request) Successful in 58s

This commit is contained in:
2026-07-27 16:34:54 +00:00
parent a2113b7f43
commit 93190d5e0c
+146 -6
View File
@@ -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=<tag>` 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.