# ADR 0004: Build Once in Staging, Promote the Same Candidate Bytes

**Status:** Retired with the Classic Candidate lane; retained as history

**Decision date:** 2026-07-27

## Decision

Formal Staging is the only build boundary for an ordinary release. After its
runtime and release gates pass, it emits one deterministic
`deployment-bundle/v1` artifact. Formal Staging retains a pre-mutation,
version-bound S3 copy and publishes the same bundle in its release-manifest
artifact. The Classic v3 publisher verified both before creating the annotated
Tag. Prod downloads the exact Tag-selected Staging artifact, verifies outer and
inner SHA-256 identities, and materializes it
without compiling, fetching from a network repository, or regenerating release
content. ADR 0005 generalizes the byte contract for Test and Formal Staging;
release eligibility remains external Staging and Tag evidence.

The bundle contains:

- the exact backend and setup executables built by Staging;
- the exact frontend distribution used by Staging;
- the exact generated final pack;
- immutable downstream, upstream, and official app-pack source snapshots needed
  by the runtime and read-only release checks; and
- a manifest-hashed offline Git bundle for the exact official app-pack HEAD,
  used to materialize historical per-pack revisions required by
  `official_repo`; and
- the Connect CLI and plugin built during Staging for the fixed Prod MCP URL.

The environment-specific Connect endpoint is known before promotion. Building
those two Prod-targeted files in the Staging workflow makes their build and
hash validation part of candidate creation; Prod still consumes the recorded
bytes and does not rebuild them.

## Required Identity Chain

One fact has one read path:

```text
Staging run/attempt
  -> pre-mutation incoming S3 seal
  -> deployment bundle archive SHA-256
  -> internal manifest SHA-256 and per-file SHA-256
  -> eligible release manifest
  -> annotated release-candidate/v3 Tag
  -> Prod exact Staging-artifact download and full rehash
```

The release manifest and tag bind the exact downstream, upstream, and official
app-pack commits, final-pack tree hash, source Staging run, artifact name,
bundle archive hash, bundle manifest hash, and Prod Connect MCP URL. A missing,
expired, extra, or mismatched byte blocks before candidate startup.

## Prod Capability Boundary

The Prod path does not need Go, npm, source repository credentials, or network
repository access to assemble a release. It materializes one pristine,
release-local Git checkout from the signed offline bundle so `official_repo`
can resolve the exact tag-bound per-pack revisions. It may execute the
already-bundled, tag-bound release helpers for admission, controlled
shared-state convergence, and runtime activation, but only after the exact
active baseline matches and while Blue continues serving. It cannot derive new
executable content or use a maintenance-route fallback.

Runtime-generated state such as logs, service files, environment files, and
the filesystem object-store copies of the bundled Connect artifacts lives
outside the immutable bundle. Those files are deployment state, not rebuilt
release payload.

## Why

The former path used a Staging tag as an input to a second build in Prod. Even
with exact refs, that made Prod another build and integration environment:
toolchain drift, package availability, generated-output drift, and current host
state could fail only after promotion began. Hashing a Prod rebuild proved
equivalent source selection, not promotion of the bytes Staging actually ran.

This decision makes Staging the final integration, build, and shared-state
setup gate. Prod verifies candidate identity and shared-state equality, starts
the already-built candidate in global standby, and performs only the bounded
runtime cutover defined by ADR 0003.

## Consequences

- Ordinary Prod success no longer depends on Go/npm caches or source download.
- The release candidate is larger because it includes runtime source snapshots.
- The incoming S3 seal proves the Staging bundle was retained before mutation;
  the Tag-selected Staging artifact is the v3 promotion source.
- A source, frontend, backend, setup, final-pack, or Connect build change
  requires a new Staging candidate.
- Live proof remains required before claiming the operational objective is met.
