# Release-system reconciliation after the runner-host failure

For the cross-document forensic analysis of why this design still failed to
produce drastic simplification, start at
[`../forensics/2026-08-11-release-simplification-failure/README.md`](../forensics/2026-08-11-release-simplification-failure/README.md).

Status: source gate. No production mutation is authorized by this document.

## Decision

The surviving release system remains:

```text
exact main event
  -> affected project build request
  -> immutable zero-traffic provider version
  -> ready evidence
  -> one environment/project publication lane
  -> expected-current read/check/publish/read
  -> generic health
  -> receipt or guarded restore
```

There is no global release, controller attempt, cumulative production baseline,
runner target pointer, or host/application publication lane. Cloudflare's active
stable Worker deployment is runtime truth. D1 is a build, evidence, attempt, and
receipt read model.

## What the last failure proved

The private runner-host bootstrap created a Worker through the Beta Worker
resource endpoint and then tried to upload its version through the legacy
script-name endpoint. The resulting authorization failure was not evidence that
the token merely needed broader permissions. It exposed a mixed provider model:

```text
POST /workers/workers
POST /workers/scripts/{name}/versions
```

Cloudflare documents the resource-oriented Beta API as a coherent Worker and
version model:

```text
POST /workers/workers
POST /workers/workers/{worker_id}/versions
GET  /workers/workers/{worker_id}/versions/{version_id}
```

The private host will use that model consistently. The ordinary script-name
version/deployment API remains the supported model for stable public Workers.
The implementation must not bridge the two by name or widen a token until the
old call succeeds.

Before another production attempt, a disposable, attempt-named Worker must
prove the exact Beta create-version request, `deploy` semantics, declarative
Durable Object/container export, provider-created namespace, private surface,
and readback. The disposable proof must be deleted or retained as explicit
canary evidence; it may not become runtime state or a resumable controller.

## Project-scoped ordering

Eligibility is scoped to `(environment, project)`.

- A generation matters to a project only when that generation requested a build
  for that project.
- The highest eligible ready generation in that lane wins, regardless of build
  completion order.
- A newer failed build does not publish and does not change traffic.
- A late older ready build remains truthful evidence. It may publish only while
  no newer generation for that project has published or is the selected ready
  row; after a newer publication it becomes explicitly superseded.
- A generation affecting runner does not make an older deploy-control
  publication stale. Each project's receipt exposes its own source SHA and
  generation.

The repository-wide `MAX(generation)` used to allocate the next main generation
is source ordering, not production eligibility. Publication queries must always
include environment and project.

## Expected-current boundary

Build evidence may record the current stable deployment observed when the build
finished, but that observation is not the publication precondition. The
publisher captures and rechecks expected-current only after it owns the
project lane and immediately before mutation. That same observed deployment and
version are the rollback target. A dashboard or foreign API mutation causes a
conflict and halts the lane; it is never overwritten.

Ready evidence, publication attempts, and terminal receipts are distinct:

- ready evidence proves one immutable zero-traffic version and its bindings;
- a publication attempt records fence, immediate expected-current, provider
  calls, readbacks, and health observations;
- a terminal receipt records published, failed-without-traffic, restored, or
  unresolved outcome without rewriting prior evidence.

Tables introduced without D1 triggers are **application-enforced append-only**.
No documentation may claim that D1 itself rejects every update or delete unless
the deployed schema demonstrably does so.

## Normal main lifecycle acceptance

The cutover is not normal until one ordinary merged PR performs all of the
following without `seed-generation`, manually exchanged SHAs, provider IDs,
fences, or lane-clear messages:

1. required Platform CI and complete Platform Preview checks pass;
2. main CAS appends one immutable generation;
3. the repository event requests builds only for affected projects;
4. no legacy release attempt, production candidate, operation/component, or
   controller wake/adoption row is created;
5. the builder obtains the registry marker and trusted egress replaces it with
   a short-lived upstream credential without persisting or logging the secret;
6. the builder writes ready evidence;
7. the per-project publisher selects, publishes, verifies, and receipts it.

The first real proof remains Better Auth plus NOMOREGIT invite flow. Two more
independent feature releases follow through the same path.

## Token roles

| Role | Permitted authority |
| --- | --- |
| Production builder | Read exact build identity; create/read attempt-named immutable private artifacts; push the exact image; upload zero-traffic stable versions; append build/ready evidence. No stable traffic mutation. |
| ProductionDeployer | Read stable versions/deployments; create one stable deployment under the project lane; verify bindings and health; append attempt/receipt evidence; guarded restore. No source build, registry, host, or application mutation. |
| Migration operator | Apply the exact reviewed D1 migration and perform Time Travel/schema/data readback. No Worker traffic mutation. |
| Runtime Worker | Product bindings only. No general provider mutation credential. |

## Partial artifacts and cleanup

Every attempt-derived artifact set is classified as building, ready, failed,
superseded, or published. A failed set records every provider object known to
exist and the operation that failed. Existing matching write-once objects may
be adopted only after exact readback; partial, ambiguous, or mismatching sets
fail closed and are never repaired in place.

Garbage collection is separate from build, publish, restore, and bootstrap. It
may delete only terminal, never-published objects after a retention interval and
after proving they are not referenced by current traffic, rollback targets,
ready rows, in-flight attempts, or unresolved evidence. The historical local
runner container remains untouched through bootstrap and three normal proofs.

## Legacy and bootstrap deletion gates

Before calling the system simplified, prove by code search, tests, runtime
routes, bindings, and database deltas that the normal event cannot enqueue,
wake, adopt, resume, reconcile, or retry the legacy controller system.
Historical product migrations may remain for protected production data, but
legacy release authority must be unreachable.

After the three normal proofs and rollback-compatibility window:

- delete or permanently disable `bootstrap-production-release-cutover.mjs`;
- delete manual generation seeding;
- delete the synthetic preview-cutover state machine after the two required
  checks are ordinary configuration;
- delete remaining legacy release/controller runtime paths and bindings;
- schedule removal of the old local runner container as a separate cleanup.

## Stop conditions for the next attempt

No production mutation occurs until all are true:

- disposable Beta Worker/version/container proof passes from provider readback;
- the runner builder uses one resource family consistently;
- reverse-completion and per-project independence tests pass;
- an ordinary main event creates project build requests with zero legacy rows;
- token roles are independently configured and read back;
- the exact prior stable deployment/version and data rollback evidence are
  recorded;
- one ten-minute, one-attempt bootstrap checklist is prepared from clean exact
  main.
