Control-plane structural review #
Reviewed the uncommitted Effect migration against branch base 3d3e35c, then
refactored it under the thermo-nuclear code-quality review standard. The initial
implementation did not meet the structural approval bar. The findings below
describe the problems found and the changes applied.
1. Deployment transport and policy had accumulated in one class #
Blocking. deployment-api.ts was already 1,034 lines at the branch base and
grew to 1,201 during migration. Account gateway setup, Worker uploads, container
rollouts, wire-format normalization and cross-resource upgrade checks shared one
class. Adding Effect did not resolve that ownership problem.
Removed the class and file. WorkerAPI and ContainerAPI own their respective
provider operations. CloudflareAccount owns credentials, bounded transport and
SDK error translation. Deployment performs observations spanning both resources
and verifies upgrade baselines. Gateway reconciliation is an independent
account operation; provider setup no longer constructs an entire deployment
client. There is no forwarding facade retaining the old API.
The generated SDK still cannot represent every required Cloudflare contract.
Raw observations retain unknown wire fields where fingerprints and preservation
checks require them. Container observations now declare only the fields actually
validated instead of asserting the entire document as Application.
2. Execution plumbing obscured state transitions #
Blocking. Registry methods embedded lifecycle rules inside nested Effect and storage callbacks. The migration expanded the registry from 664 to 809 lines. Domain retries reconstructed individual fields through repeated nullable branches, making preservation of uncertain attachment state difficult to check.
Moved installation and domain transitions into storage-independent functions. Domain startup dispatches directly on attach, retry and remove; retry retains the existing domain evidence. The native registry continues to own authorization, replay and atomic writes. Its owner check and owned-record reads are centralized behind private methods, so the helpers cannot become public RPC entry points. HTTP callers use the registry's validated contracts instead of parsing the same records again.
Tests now cover preservation and explicit clearance of ambiguous write intents, promotion of a release only after verified completion, and domain removal being blocked until uncertain attachment evidence is resolved. Persisted schemas, keys, revision checks and transaction boundaries remain unchanged.
3. The migration retained circular dependencies #
Blocking missed simplification. OAuth and bridge routing imported each other. The installation router imported setup handlers that imported owner lookup from that same router. These existing cycles made helper reuse pull routing policy back into lower-level modules.
Moved HTTP primitives, OAuth authorization startup and installation access into their own cohesive modules. An import-graph check of direct runtime imports among backend TypeScript modules found two cyclic groups before this review and none afterward. Type-only imports are excluded from that check.
4. Effect and mode contracts added avoidable indirection #
Blocking. The one-off WorkerDeployment Context service and Layer simply
wrapped a client already constructed inside each Workflow attempt. Other backend
programs passed their dependencies directly. The Workflow also decided whether
configuration existed by comparing a persisted step-name string, then exposed
that configuration as unknown.
Removed the Context service and Layer. Worker orchestration takes its typed client
directly. Origin preparation and configured deployment steps are explicit, and
configured steps receive InstallationConfig. Durable step names and their order
are unchanged. Redundant generator wrappers around vault transactions were removed.
Installation commands now distinguish start, recover and upgrade, with a target
required only for upgrade. Worker upload bindings distinguish bootstrap credentials
from inheritance. Source-code observation uses an explicit mode instead of giving
undefined, null and strings different hidden meanings. Compile-time checks
reject mixed command and binding modes. Request options are named, and the unused
credential-override parameters were removed.
Measurements #
These compare the working tree immediately before and after this review, excluding the frontend and declaration files.
| Measure | Before | After |
|---|---|---|
| Largest backend file | 1,201 lines | 613 lines |
| Installation registry | 809 lines | 613 lines |
| Installation Workflow | 465 lines | 447 lines |
| Runtime import cycles, as cyclic groups | 2 | 0 |
| Backend source files | 38 | 48 |
| Total backend lines | 7,189 | 7,361 |
The refactor adds 172 lines overall. Its gains are explicit responsibilities, fewer dependency cycles and fewer invalid input combinations. Provider ordering, reconciliation checks and fingerprint rules remain substantial because they protect installed resources after ambiguous writes; collapsing those checks would change behavior.
Validation #
Passed after the refactor:
- Typecheck, formatting checks and
git diff --check. - Control-plane fixture build and Wrangler dry run.
- Focused Effect, metadata and lifecycle tests: 30 tests.
- Native deployment orchestration: 21 tests, including upgrades, ambiguous provider replies, authorization expiry and process restart.
- Domain provisioning, recovery and browser setup: 16 tests.
- OAuth: 4 tests; ownership and registry: 17 tests.
- Deployment artifacts and Effect tests: 14 tests; native network and gateway tests: 9 tests.
- Independent publisher bridge server test; update-on-visit tests; complete installation status UI test.
Some named suites include the same focused tests; these counts are not additive. No persisted-data migration, remote deployment, dependency change or SDK patch was part of this review. The pre-existing browser bridge timeout was not rerun during this structural pass, and Docker is unavailable for the golden-path suite; those limits are described in the migration notes.