Repository navigation
Converge R2 entitlement + bucket existence for every allocated origin purpose - #11721
Conversation
… purpose gunbc.cloudflare.r2_bucket_ensure observes, per allocated BucketPurpose, the bucket through cloudflare.R2Buckets.Get (extdeps.cloudflare.r2), classifies with std.upsert_decision, creates an established-absent default-jurisdiction bucket and reads it back with a second Get. An unentitled account (403/10042) refuses with the dashboard checkout step: Cloudflare publishes no API route to an R2 subscription (cited readings). Wired as fleet-converge mode r2_bucket_ensure; witness test.claim.cloudflare_r2_bucket_ensure. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… on std.upsert_decision Operator ruling (option B): the bootstrap token is not widened. A third mint profile, R2AccountBucketAdmin, mints an account-scoped token holding only the observed Workers R2 Storage Write group into its own custody container (cloudflare-r2-bucket-admin-token, three IAM cells in r2_mint_secret_access); r2_bucket_ensure signs with it and refuses naming run_bucket_admin until it is pinned. The R2 buckets service moves to extdeps.cloudflare.r2_buckets so its cloudflare.* service namespace no longer shadows the vendor value in modules importing r2. Review 68490: upsert_decision_label is generic over the plan and ObservationVerdict gains its one wire spelling on the sum; the roster witness drops the transcribed count. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Addressed review 68490 in f820b55:
The same push applies the operator's ruling on credentials: the ensure signs with a new, separately minted account-scoped bucket-admin token, never the bootstrap (see the updated body). It also merges main, which fixes the — sent from sharp-ant-20 |
|
Live receipts, 2026-09-19 ~17:11–17:14Z. Operator GCP access token, read from an owner-only file and deleted afterwards. 1. The version and token id are now pinned in 2. The boot-origin bucket 3. — sent from sharp-ant-20 |
…n mint observe_r2_mint_custody_container now creates an absent container (automatic replication) as the running identity before any Cloudflare effect; an identity without the project-level secretmanager.secrets.create (the fleet SA) refuses naming that permission, and an ambiguous create is not retried (operator direction). Executed live 2026-09-19: run_bucket_admin created cloudflare-r2-bucket-admin-token, minted token 6f287fde…, stored v1 (verified); pinned in r2_origin. ensure then nooped the durable origin and created the absent boot-origin bucket with converged readback; a second run nooped both. Frontier rows for admit_r2_bucket_admin_api_mint and r2_account_resource_name retire on that execution. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… 68550) observe_r2_mint_custody_container -> ensure_r2_mint_custody_container, ObserveCustodyContainer -> EnsureCustodyContainer, R2MintCustodyContainerUnobserved -> R2MintCustodyContainerNotEnsured, and the refusal texts with them: the step now creates an absent container, so the observation names were a meaning fork (DESIGN 3). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Review 68550: agreed, and fixed in b91d374. The step creates an absent container, so it no longer observes. Renamed:
The refusal texts and annotations now say "ensured". No behaviour change. — sent from sharp-ant-20 |
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…iew 68589) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Review 68589: added the explicit For the record, the symbols did already resolve. The live — sent from sharp-ant-20 |
# Conflicts: # .github/workflows/fleet-converge.yml # dag/gunbc/fleet/fleet_converge_workflow.dag
# Conflicts: # .github/workflows/fleet-converge.yml # dag/gunbc/fleet/fleet_converge_workflow.dag
|
Merged main again (36d19e1; main had added One thing is knowingly incomplete in this commit: Everything else is unchanged and already approved on the pre-merge head (review 68753). — sent from sharp-ant-20 |
…pile) main #11736 made fleet_converge_mode_fleet_ssh_key_demand exhaustive over the mode sum; the merge that added R2BucketEnsure and R2BucketAdminMint left them without an arm, so the corpus did not resolve and no regeneration of fleet-converge.yml could succeed -- which is why heal-generated-artifacts failed rather than repairing it. Both reach api.cloudflare.com and secretmanager.googleapis.com over HTTPS as the run's own federated identity and open no host session, so neither consumes the key. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Review 68904: confirmed, and the root cause is one step earlier than the review reads it. The stale projection is real. But it was not only lost in a merge: after merging main, the corpus did not resolve at all. main #11736 made 854e773 declares both modes On the projection itself: I have tried to regenerate it locally five times since the merge. — sent from sharp-ant-20 |
The merge kept our side of the hunk carrying fleet_converge_mode_fleet_ssh_key_demand, which lost main's ApprovalKeyringConverge and MtCollins1Boot arms, so the match stayed non-exhaustive after 854e773 fixed the other half. Both are restored with main's own classification (FleetSshKeyConsumed). Swept every mode in the sum against main's copy: per-mode occurrence counts now agree, and each of the four R2 modes appears in the same six constructs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Review 68939: confirmed, and I traced it further. Two corrections to the shared picture, then where it stands. 1. No CI lane will fix this, and none fails on it. I assumed {"expected_head_sha":"1cfe38c…","repair_declaration":"","entries":[]}and 2. The model is correct at HEAD. All four step functions exist and are in Why it is not yet regenerated — the generator refuses, twice, with typed causes:
The same entry runs fine inside the heal job on the self-hosted arm64 runners, so the fleet has hosts that can do it. I have asked the operator for one. I am deliberately not hand-writing the file: the emitted — sent from sharp-ant-20 |
The main merge took the ours side of this generated file, dropping the r2_bucket_ensure and r2_bucket_admin_mint modes the model at this head declares. Regenerated through gunbc.instruments.generated_artifact_gate main_wet_one on a host with the admitted memory budget (session containers and BuildBuddy runners both refuse it), not hand-edited. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts: # dag/gunbc/fleet/fleet_converge_workflow.dag
…on/sharp-ant-20 # Conflicts: # .github/workflows/fleet-converge.yml
|
Merged main again (ab841c6). main reclassified I also re-ran the per-mode sweep against main's copy (the check that caught the dropped arms in 1cfe38c): every mode's occurrence count agrees, and each of the four R2 modes appears in the same six constructs. On the generated file, stated plainly: the merge driver again took main's side for That is a textual merge of generator output, not a generator run. If anyone wants byte-certainty, re-running — sent from sharp-ant-20 |
parse_r2_jurisdiction re-spelled the five wire tokens r2_jurisdiction_wire already owns, so a corrected spelling in one would have left the other silently unrecognising. It now folds over r2_jurisdictions() and compares through r2_jurisdiction_wire -- one grammar read backward (DESIGN 4) -- and lives beside the table it inverts in extdeps.cloudflare.r2 rather than in the operation module. No declared-fork row is needed because the fork is gone. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Review 69065: agreed, fixed in eb24535 — and I took the first option rather than the declared-fork row.
I did not add the
— sent from sharp-ant-20 |
# Conflicts: # .github/workflows/fleet-converge.yml # dag/gunbc/fleet/fleet_converge_workflow.dag
# Conflicts: # .github/workflows/fleet-converge.yml # dag/gunbc/fleet/fleet_converge_workflow.dag
…this head Review 69227: the rows' boundary and red-control text cited gunbc.auth.privileged_effect_census, gunbc.auth.authorization_pattern_selection and gunbc.cloudflare.r2_bucket_ensure, which resolve only once #11734 and #11721 merge, and the plan page asserted them as landed. Each citation now names the PR it lands with, and the page separates what executed from what is approved and unmerged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts: # .github/workflows/fleet-converge.yml # dag/gunbc/fleet/fleet_converge_workflow.dag
… merge Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts: # .github/workflows/fleet-converge.yml # dag/gunbc/fleet/fleet_converge_workflow.dag
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts: # .github/workflows/fleet-converge.yml # dag/gunbc/fleet/fleet_converge_workflow.dag
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Ledger-Repair-Judged: docs/design-rung-drops.md Heal-Candidate-Run: 35533900850
The floor lane read the committed projection against the authority the merge brought in and refused. Regenerated through generated_artifact_gate main_wet_one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts: # .github/workflows/fleet-converge.yml # ROADMAP.md # dag/gunbc/cloudflare/r2_token_mint.dag # dag/gunbc/fleet/fleet_converge_workflow.dag
8e03286 to
7344492
Compare
# Conflicts: # dag/gunbc/fleet/fleet_converge_workflow.dag
…429) The regeneration landed earlier on this branch and was lost across the later main merges, so the emitted workflow carried neither the r2_bucket_ensure / r2_bucket_admin_mint dispatch options nor their four steps -- leaving gunbc.cloudflare.r2_bucket_ensure with no executing consumer (DESIGN §3c). Regenerated via tools.generated_artifact_gate main_wet; that fold rewrote only this path. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Review 69429 finding fixed in 91efb52. Confirmed exactly as reported: Regenerated with Also on this head: the earlier merge conflict is resolved (f1ec9c9) — it was confined to the §4c annotation above |
# Conflicts: # .github/workflows/fleet-converge.yml # dag/gunbc/fleet/fleet_converge_workflow.dag
Closes the gap behind #11713.
gunbc.cloudflare.r2_originallocated a bucket, but nothing ever checked whether the account had R2 or whether the bucket existed. That went unnoticed for nine days.What lands
extdeps.cloudflare.r2: the cited readings, the error codes, and the account-scoped storage grant and policy (r2_account_storage_create_request, overr2_account_resource_name).extdeps.cloudflare.r2_buckets(new module, one per client/v4 resource, likeaccount_api_tokens)cloudflare.R2BucketswithGetandCreateagainst/accounts/{id}/r2/buckets.cloudflare.*service declared inr2shadowed the vendor valuecloudflarein modules that importr2, andtest.claim.cloudflare_r2_origin_mint_runstopped compiling.classify_r2_bucket_get, which turns an HTTP outcome into one ofR2BucketPresent | R2BucketAbsent | R2AccountNotEntitled | R2BucketReadRefused.403+10042means not entitled, and404+10006means absent. Any other refusal stays unclassified.extdeps.cloudflare.client_v4:cloudflare_error_codesreads the v4 envelope'serrors[].codeproperly instead of searching the body for a substring.gunbc.cloudflare.r2_bucket_ensurestd.upsert_decisionvocabulary (Noop / Apply / Refuse); no new convergence algebra.gunbc_fleet_r2_bucket_allocations: FabricDurableOrigin and FabricBootOrigin.Get, which must classify as Converged.run_bucket_admin.R2AccountBucketAdmin, togunbc.cloudflare.r2_token_mint_run(plus therun_bucket_adminentry). No second fold.cloudflare_r2_bucket_admin_token_shape) is one account-scoped grant: the observed Workers R2 Storage Write group (r2_permission_group_observecloudflare_r2_storage_write_observed_permission_group_id, from the 2026-09-10 listing). It holds no object grant.cloudflare-r2-bucket-admin-token, and three IAM cells inr2_mint_secret_access(viewer, versionAdder, accessor).r2_originfleet_r2_bucket_admin_credential, currently Unminted.r2_origin: addsbucket_purpose_origin_standing, an exhaustive per-purpose standing.r2_bucket_admin_mintandr2_bucket_ensure(a step plus analways()receipt upload) to the existing dispatch-only job. No new job.Enabling R2 is not possible through the API, so the ensure refuses
Cited readings, fetched with curl from the
index.mdprojections and transcribed verbatim:developers.cloudflare.com/r2/get-started/: "You need a Cloudflare account with an R2 subscription… Complete the checkout flow to add an R2 subscription" (a dashboard flow).developers.cloudflare.com/api/resources/accounts/subresources/subscriptions/methods/create/: therate_plan.idvalues are free/lite/pro/pro_plus/business/enterprise/partners_* only. There is no R2 plan.So an unentitled account gets
Inaccessible+ Refuse with the dashboard step (r2_subscription_dashboard_step). The ensure never purchases anything.Known limit: the 10042/10006 codes come from
r2/api/error-codes/, which covers the Workers and S3 APIs. Applying them to v4 REST is an inference, and it is typed as one: a wrong guess produces a refusal, never an "absent" or "unentitled" verdict.Evidence
test.claim.cloudflare_r2_bucket_ensure: 16/16 PASS locally (claim_batch --entry … --functions …).run_bucket_admincreated its own custody container, minted token6f287fde…, stored it at v1 and verified it. It is now pinned infleet_r2_bucket_admin_credential.ensurefound the durable origin present and did nothing. It found the boot-origin bucketgunbai-fabric-bootabsent, created it, and the readback converged.ensurerun found both present and did nothing.secretmanager.secrets.createpermission (the fleet SA) refuses and names that permission. An ambiguous create is not retried.Still open
test.claim.cloudflare_r2_origin_mint_run26/26,test.claim.r2_mint_secret_access_witness_test5/5,test.claim.cloudflare_r2_bucket_ensure16/16 (locally).gunbc.cloudflare.r2_mint_secret_accesshave not been run: the four original ones plus the three new bucket-admin cells. Neither the session containers nor srv1 have gcloud.Please merge by operator; I will not self-merge.
🤖 Generated with Claude Code