# Simplification gap analysis

## Finding

Forge did not yet achieve the requested drastic release-system simplification.
The core per-project boundary remains sound:

```text
main event
  -> affected-project production build
  -> immutable ready Worker version
  -> one project publication lane
  -> expected-current publish
  -> generic health
  -> receipt or guarded restore
```

However, a small ProductionDeployer is insufficient if the surrounding system
retains or recreates controller behavior. Complexity has migrated into the
builder, provider broker, private host lifecycle, bootstrap, synthetic preview
validation, merge handoff, evidence records, token sharing, and legacy command
and schema surfaces.

The goal is not to make each of those subsystems robust. The goal is to delete
most of them and leave one obvious normal lifecycle.

## Remaining structural conflicts

### 1. A private host deployment can become a second release lane

The private host needs one provider deployment before its Durable Object and
container are usable. That is acceptable only as immutable build preparation:
one attempt-derived Worker, one version, one deployment, forever. Forge must
never change traffic among versions of that host, persist a current-host
pointer, or give ProductionDeployer host rollback behavior. Any host change
creates a new host identity and a new stable Worker version.

### 2. Provider identity joins remain fragile

Cloudflare intentionally pairs Beta Worker/Version resources with the existing
script-name Deployment API. The builder must preserve this exact join:

```text
immutable Worker UUID
  -> exact attempt-derived current Worker name
  -> immutable version UUID owned by that Worker
  -> explicit deployment under that exact name
```

Before deployment, read the UUID and exact name again. After deployment, prove
the deployed version belongs to that Worker UUID. Name lookup must never replace
the UUID as root identity.

### 3. The Wrangler-to-Beta JSON converter is a custom packaging system

Converting a Wrangler multipart dry run to Beta JSON can silently drop generated
chunks, WASM, text/data blobs, assets, or other module types. Either the runner
host is explicitly restricted to exactly one module and fails on every other
part, or the converter copies every emitted part deterministically. Synthetic
`export default {}` tests are insufficient; test the real compiled host output.

### 4. The broker can become broad account authority

A path-shaped allowlist for `/workers/workers/{uuid}/versions` is not enough.
Before forwarding a version mutation, the broker must prove the signed build
attempt owns the attempt-derived name and provider truth maps that exact name to
the requested UUID. Otherwise a compromised builder can upload to another
account Worker with a syntactically valid UUID.

### 5. Ambiguous-mutation evidence can become a controller

An immutable dispatch claim plus one bounded provider readback is appropriate.
Durable phases that later resume Worker creation, version upload, host
deployment, application creation, or readiness are not. Evidence may survive;
execution resumption must not. A mismatching, partial, or unresolved artifact
fails that attempt rather than entering a repair lifecycle.

### 6. Bootstrap remains an alternate production builder

Pure identity, request-construction, and readback functions may be shared.
Operational orchestration must not be. After the cutover window, delete or make
the bootstrap unconditionally inert. It must not remain callable for arbitrary
future generations or become the practical repair path whenever normal builds
fail.

### 7. Preview and production share too much runner-host machinery

Shared code is safe; shared authority is not. Preview must use distinct account
or resource namespaces, tokens, registry paths, application names, Durable
Object namespaces, evidence, and publication surfaces. A preview-controlled
request must be structurally unable to name a production resource.

### 8. The merge queue still speaks the language of a production release

Commands and schemas such as `release enqueue`, `release attempt`, global
`components`, and a global `receipt` preserve the legacy mental model even when
fields are empty. The merge queue should do only preview validation and a main
CAS. Its output is a merged main generation. Independent project builds begin
from the ordinary main event afterward. Remove legacy-empty fields rather than
keeping compatibility schema.

### 9. Synthetic validation refs introduce another delivery subsystem

A validation event must link durably to exact Platform CI and Platform Preview
run IDs. A request stuck in `validating` with empty evidence is a delivery defect,
not permission to seed a generation or wake a controller. Repair only the
idempotent event-to-workflow handoff. Validation events and real main events
must have explicit different kinds; ref-name pattern inference is insufficient.

### 10. Main independence needs precise scope

Main is independent of production provider readiness, production build success,
and publication. Main may still require complete PR preview validation. This
distinction must remain explicit so a preview outage is not “repaired” by making
main wait for production or by silently dropping preview requirements.

### 11. Project impact can recreate history-dependent cumulative diffing

Affected projects should be computed at the main CAS, where prior and new main
SHAs are both authoritative, and persisted as immutable build requests. A
history-free production builder must consume those requests; it must not
rediscover impact from local Git history or reconstruct a cumulative production
baseline.

### 12. Newer failed builds need an explicit ordering rule

The surviving rule should be newest successful eligible ready deployment per
project. A newer requested or failed-before-ready build must not permanently
block an older ready generation. A newer ready row wins. Once a generation
publishes, all lower generations are permanently below the published floor.
Finishing last never wins.

### 13. Expected-current is both deployment and version identity

The lane must compare the immediate current deployment ID and its exact 100%
version ID. A restore creates a new deployment selecting the historical prior
version. Receipts explain observed provider truth; they must not become a D1
active pointer.

### 14. Public dependency health must not replace direct identity proof

Edge `/health/dependencies` is useful public behavior evidence, but it cannot be
the sole proof of an independently deployed downstream Worker. The publisher
must first read the exact Cloudflare deployment, version, and bindings directly.
Project manifests may declare generic direct health, dependency health, and
public behavior probes without feature-name heuristics.

### 15. Token separation may exist only on paper

Builder, deployer, preview, migration operator, and runtime must have upstream
Cloudflare permissions that are actually disjoint. Internal URL allowlists are
defense in depth, not least-privilege evidence. Prove separation with one
forbidden upstream operation per token role.

### 16. One growing artifact record recreates mutable lifecycle state

Prefer immutable, digest-linked records:

```text
image receipt
private-host receipt
application receipt
stable-version ready evidence
publication attempt
terminal publication receipt
```

Do not update one artifact-set mega-row from image build through publication.
That is another state machine and weakens forensic evidence.

### 17. Source implementation is not provider readiness

API documentation and local tests prove only the intended request contract.
Until a disposable real-provider proof succeeds, status is “implemented locally,
provider contract unverified.” Never call the host ready based on fixtures or
Wrangler output.

### 18. A release-system PR is not one of the product proofs

The release-system merge can prove preview, main, and builder mechanics. It does
not count as Better Auth plus NOMOREGIT or either of the two independent product
feature proofs. Those must traverse the already-live ordinary path afterward.

### 19. Dormant old PRs are alternate authority waiting to reactivate

Close obsolete release-system PRs. Held product and migration PRs must be
rebased and reviewed against current main and live schema before enqueue.
No pre-cutover candidate metadata, controller attempt, or old queue entry may
become runnable merely because validation delivery starts working.

### 20. Migration documentation and live ledger may disagree

Historical documents and open PR bodies disagree about whether migrations 0024
and 0025 are applied. Live D1 ledger, exact DDL, integrity checks, and protected
row counts are authoritative. Never apply, adopt, or replay a migration from a
stale checklist. Preserve product data; delete release authority separately.

## The smaller target

The future system should contain only:

1. PR checks and complete preview deployment.
2. A main CAS that appends a generation and exact affected-project requests.
3. One production builder implementation that produces immutable ready Worker
   versions and immutable evidence.
4. One tiny project-lane ProductionDeployer that publishes a stable Worker
   version, checks generic health, and receipts or restores.
5. Cloudflare active stable Worker deployment as runtime truth.

Delete or make unreachable:

- legacy controller wake/adopt/resume/reconcile/retry paths;
- production candidates, global components, dependency waves, and cumulative
  baseline diffing;
- empty compatibility fields and commands that preserve the old release model;
- bootstrap execution after the cutover proof window;
- manual generation seed paths;
- synthetic preview-cutover authority switching after ordinary required checks
  are installed;
- host/application current pointers, rollout controllers, and repair phases;
- runner-side global materialization;
- D1 active-version authority;
- feature-specific publisher probes.

## Required proof before another production mutation

1. Re-read exact main, PR, workflow, D1 ledger, Cloudflare deployments,
   bindings, tokens, and rollback targets.
2. Fix the normal validation event-to-workflow delivery without invoking legacy
   release machinery.
3. Merge source through ordinary Platform CI and complete Platform Preview.
4. Prove the ordinary main event creates exact affected-project build requests
   with zero legacy attempts, candidates, components, or controller actions.
5. Prove the real compiled runner host against a disposable attempt-named
   Cloudflare Worker through exact Beta JSON upload and readback.
6. Prove upstream token-role separation.
7. Perform one bounded exact-main bootstrap attempt with recorded restore
   targets and the ten-minute stop-loss.
8. Verify exact live provider identity, bindings, generic health, dependency
   health, and public behavior.
9. Ship three independent product proofs through the ordinary path.
10. Delete bootstrap, manual seed, synthetic cutover, and legacy runtime paths;
    remove the historical local runner only in a later bounded cleanup.

## Final forensic conclusion

The repeated mistake was not insufficient safety. It was applying safety to too
many durable operational units. Each ambiguity acquired a claim, phase,
reconciliation rule, or recovery path until the surrounding system behaved like
the controller it was meant to replace.

The next implementation should be judged primarily by deletion count and the
number of authorities that cease to exist—not by how robustly another bootstrap
or broker workflow can resume.

