Skip to content

worker: deploy account-directory without R2 binding until the subscription is enabled - #1126

Merged
arul28 merged 1 commit into
mainfrom
worker-deploy-no-r2
Aug 19, 2026
Merged

worker: deploy account-directory without R2 binding until the subscription is enabled#1126
arul28 merged 1 commit into
mainfrom
worker-deploy-no-r2

Conversation

@arul28

@arul28 arul28 commented Aug 19, 2026

Copy link
Copy Markdown
Owner

Why

Phase 5.5 of the v1.2.61 release could not deploy the account-directory Worker. Creating the diagnostics buckets fails:

Please enable R2 through the Cloudflare Dashboard. [code: 10042]

This is account-level product enablement, not a token scope. The same API token lists Workers scripts, reads Worker settings, queries D1, and deployed Pages successfully. Independently, the account's own S3 endpoint (<acct>.r2.cloudflarestorage.com) rejects the TLS handshake with SSLV3_ALERT_HANDSHAKE_FAILURE — the R2 endpoint is not provisioned at all. Enabling it requires adding the R2 subscription in the dashboard, which is a billing decision for the account owner.

A Worker bound to a bucket that cannot exist fails to start. Deploying wrangler.jsonc as-is would take down machine registration, pairing, and heartbeat for every user in order to ship a route nobody can reach yet.

What

Comment out both r2_buckets blocks (top-level and env.production), leaving the exact bindings and the re-enable steps inline.

This is the degradation the code was already written for:

  • DiagnosticsEnv = Env & { DIAGNOSTICS?: R2Bucket } — the binding is optional
  • POST /diagnostics/upload answers 503 {"error":"diagnostics upload unavailable"} when unbound
  • the in-app "Send to ADE" button reports that sending is unavailable

Every other route deploys unchanged. That matters here: production is currently running #1115-era code against the 0008 schema, so two-phase pairing-grant reservation, supersede-by-hardware-anchor dedup, and refusal logging are not live. This unblocks them.

Verification

  • npm test — 145 passed / 7 files. Nothing asserts r2_buckets; verifyDeploymentConfig.test.ts reads the committed wrangler.jsonc and still accepts it.
  • npm run verify:deploy-config -- production and -- default — both complete (DIRECTORY_AUTH_SECRET + PUSH_RELAY_URL configured).
  • npm run build:production dry-run — 121.17 KiB / 28.30 KiB gzip; resolved bindings are DB, ONLINE_WINDOW_MS, WEB_CLIENT_ORIGIN, PUSH_RELAY_URL, with no R2 entry.

Re-enable path

Once the R2 subscription is added: revert this commit, create ade-diagnostics + ade-diagnostics-production, add the 90-day expiry lifecycle rule to both (nothing in the Worker ever deletes a report), redeploy, then run the fail-closed probes (garbage Bearer → 401, >512 KiB → 413).

🤖 Generated with Claude Code

…ption is enabled

R2 is not enabled on the Cloudflare account. Creating either diagnostics
bucket fails with "Please enable R2 through the Cloudflare Dashboard
[code: 10042]" — from the REST API and from the account's own S3 endpoint,
which rejects the TLS handshake outright. That is an account-level product
enablement, not a token scope: the same token lists Workers, reads D1, and
deploys Pages.

A Worker bound to a bucket that cannot exist fails to start, so shipping
wrangler.jsonc as-is would take down machine registration, pairing, and
heartbeat for every user in order to deliver a route nobody can reach yet.
Leaving DIAGNOSTICS unbound is the degradation the code was written for:
`DiagnosticsEnv` types it `DIAGNOSTICS?: R2Bucket`, /diagnostics/upload
answers 503, and the in-app "Send to ADE" button reports that sending is
unavailable. Every other route deploys unchanged — including the two-phase
pairing-grant reservation, supersede-by-hardware-anchor dedup, and refusal
logging that production is currently missing.

Both `r2_buckets` blocks are preserved verbatim in comments next to the
re-enable steps, so restoring them is a revert plus bucket creation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
ade Ignored Ignored Preview Aug 19, 2026 2:08pm

@arul28
arul28 merged commit bf434f4 into main Aug 19, 2026
15 of 16 checks passed
@arul28
arul28 deleted the worker-deploy-no-r2 branch August 19, 2026 14:09
arul28 added a commit that referenced this pull request Aug 19, 2026
…s created with 30-day lifecycle (#1127)

Reverts #1126. ade-diagnostics + ade-diagnostics-production exist with
expire-reports-30d lifecycle rules.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
arul28 added a commit that referenced this pull request Aug 19, 2026
…rkers (#1131)

* skill(release): own every Cloudflare surface, not just "deploy the changed Workers"

The old Phase 5.5 knew one failure mode: a changed Worker sitting undeployed.
It was blind to the class that actually bit us twice this week, because that
class lives in account state and no test in this repo can fail on it.

A Cloudflare surface has two halves and only one is in git. The code half is
wrangler.jsonc plus src/. The account half — whether the R2 bucket exists,
whether it carries a lifecycle rule, whether a D1 migration was applied,
whether a secret is bound for that environment — lives in the Cloudflare
account and in no repository file.

Phase 5.5 is now a 7-step phase: scope (verify the deploy-web.yml run for the
release SHA — CI already deploys these, so the normal case is verification,
not deployment), a factual per-surface binding inventory, a bindings-vs-account
drift preflight, an un-codeable account-state checklist, guarded deploy,
per-surface post-deploy verification, and rollback/blocker discipline.

Three incidents cited: R2 not enabled on the account (#1126/#1127), buckets
created without lifecycle rules, and the 2026-08-06 pending-migration/unbound-
secret 500s. All three shipped green /health.

Sharpened throughout: /health is the floor, not the check — this repo has four
health endpoints proving four different things and not one of them checks
migration state. Every command verified against the pinned wrangler 4.105.0,
and the R2 public-access check uses `r2 bucket dev-url get` / `domain list`,
which actually report posture, rather than `bucket info`, which does not.

State schema gains a cloudflare section; the final report now requires a
per-surface decision and verification line.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* review: address CodeRabbit — deployment-derived Cloudflare baseline, honest coverage gaps

- Scope no longer keys off the desktop tag. Each surface's baseline is the
  newest deploy-web.yml run whose job for that surface concluded success;
  UNKNOWN means reconcile, never "unchanged". Desktop-tag diff demoted to a
  secondary signal. Verified live against the repo (webhook/tunnel/push-relay
  currently resolve UNKNOWN — exactly the drift the old check hid).
- RUN_ID is now resolved from the release SHA and fails loudly with no match,
  instead of being referenced unassigned.
- Wrangler invocations wrapped in their owning app directory after npm ci; the
  repo-root Pages deploy pinned to 4.105.0, with CI's floating wrangler@4
  called out rather than papered over.
- R2 public-access posture checked for both diagnostics buckets, not just
  production. Verified live: both report dev URL disabled, no custom domains.
- push-relay gains a read-only sqlite_master trigger check — d1 migrations list
  is blind to the attention_triggers.sql sidecar. Verified live against remote
  D1; both triggers present.
- account-directory preflight's real coverage stated: 1 of 4 secrets, 1 of 4
  vars, /health checks none of them. Unconfirmed values get named, not implied.
- Rollback stated as an attempt (refused on missing bindings or DO lifecycle
  changes) with fix-forward defined. Pages has no rollback subcommand —
  verified on 4.105.0; record the deployment id and restore via dashboard.
- accountState replaced aggregate booleans with evidence keyed by resource and
  environment; final report updated to match.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* skill(release): tag only a commit with a green ci-pass

release-core's verify job is fail-closed on the tagged SHA having a green
ci-pass check run. Merging the release-docs PR and tagging immediately hits
it every time — the squash-merge creates a new commit on main whose CI has
not started. This just cost the v1.2.62 run.

Documents the wait, and the recovery: the tag is still correct and nothing
was published, so wait for ci-pass on the same SHA and rerun only the failed
job rather than deleting or moving the tag.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant