diff --git a/dag/extdeps/cloudflare/r2.dag b/dag/extdeps/cloudflare/r2.dag index e9130ee5d30..20789ee10ac 100644 --- a/dag/extdeps/cloudflare/r2.dag +++ b/dag/extdeps/cloudflare/r2.dag @@ -31,6 +31,41 @@ data r2_s3_api_citation: ExternalAuthority = ExternalAuthority { } } +data r2_data_location_authority: ExternalAuthority = ExternalAuthority { + uri: Uri { + scheme: Https + locator: "developers.cloudflare.com/r2/reference/data-location" + } +} + +data r2_how_r2_works_authority: ExternalAuthority = ExternalAuthority { + uri: Uri { + scheme: Https + locator: "developers.cloudflare.com/r2/how-r2-works" + } +} + +data r2_us_jurisdiction_changelog_authority: ExternalAuthority = ExternalAuthority { + uri: Uri { + scheme: Https + locator: "developers.cloudflare.com/changelog/post/2026-08-17-r2-us-jurisdiction" + } +} + +data r2_create_bucket_authority: ExternalAuthority = ExternalAuthority { + uri: Uri { + scheme: Https + locator: "developers.cloudflare.com/api/resources/r2/subresources/buckets/methods/create" + } +} + +data r2_get_bucket_authority: ExternalAuthority = ExternalAuthority { + uri: Uri { + scheme: Https + locator: "developers.cloudflare.com/api/resources/r2/subresources/buckets/methods/get" + } +} + data r2_tokens_doc_as_of: Timestamp = "2026-08-18" // THE READ ID IS THE ONE PERMISSION GROUP ID THIS MODULE PINS, AND THE WRITE ID IS DELIBERATELY NOT @@ -99,12 +134,22 @@ data extdeps_model_scope: ExternalModelScope = ExternalModelScope { } }, first_citation: extdeps_external_authority_anchor, - further_citations: [r2_s3_api_citation] + further_citations: [ + r2_s3_api_citation, + r2_data_location_authority, + r2_how_r2_works_authority, + r2_us_jurisdiction_changelog_authority, + r2_create_bucket_authority, + r2_get_bucket_authority, + ] } +// THE FIVE ARMS ARE THE CREATE/GET BUCKET JURISDICTION VALUE SET (r2_create_bucket_location_hint_reading, +// r2_get_bucket_location_reading). Host suffixes follow the same wire token as eu/us/fedramp. type R2Jurisdiction = R2JurisdictionDefault | R2JurisdictionEu | R2JurisdictionFedramp + | R2JurisdictionFedrampHigh | R2JurisdictionUs fn r2_jurisdiction_wire(jurisdiction: R2Jurisdiction) -> String { @@ -112,6 +157,7 @@ fn r2_jurisdiction_wire(jurisdiction: R2Jurisdiction) -> String { R2JurisdictionDefault => "default" R2JurisdictionEu => "eu" R2JurisdictionFedramp => "fedramp" + R2JurisdictionFedrampHigh => "fedramp-high" R2JurisdictionUs => "us" } } @@ -126,6 +172,7 @@ fn r2_s3_endpoint_host(endpoint: R2S3Endpoint) -> String { R2JurisdictionDefault => join([endpoint.account_id, ".r2.cloudflarestorage.com"], "") R2JurisdictionEu => join([endpoint.account_id, ".eu.r2.cloudflarestorage.com"], "") R2JurisdictionFedramp => join([endpoint.account_id, ".fedramp.r2.cloudflarestorage.com"], "") + R2JurisdictionFedrampHigh => join([endpoint.account_id, ".fedramp-high.r2.cloudflarestorage.com"], "") R2JurisdictionUs => join([endpoint.account_id, ".us.r2.cloudflarestorage.com"], "") } } @@ -329,9 +376,116 @@ fn r2_object_url(locator: R2ObjectLocator) -> String { ) } +// LOCATION AND RESIDENCY TRANSCRIPTIONS FOR THIS SAME PRODUCT. They were briefly a second module +// (extdeps.cloudflare.r2_data_location) whose subject was a wrapper around one reading. R2 is one +// independently versioned product; DESIGN section 3's external-upstream rule does not mint a +// second module authority per documentation page. The tokens-page default-jurisdiction sentence +// cites this module's existing anchor rather than a parallel ExternalAuthority for the same URI. +// +// THERE IS NO CloudflarePublishedReading. Dated attestation is FactCitation (fact + authority); +// the transcription is the cited NonEmptyStr. A second as-of record would remint the carrier +// r2_tokens_doc_as_of's frontier already named. Company DPA and subprocessors live on +// extdeps.vendor.cloudflare, not under R2S3Endpoint. +data r2_data_location_reading: NonEmptyStr = "When you create a new bucket, the data location is set to Automatic by default. Currently, this option chooses a bucket location in the closest available region to the create bucket request based on the location of the caller. Location Hints are optional parameters you can provide during bucket creation to indicate the primary geographical location you expect data will be accessed from. Location Hints are a best effort and not a guarantee, and they should only be used as a way to optimize performance. Available hints: wnam Western North America, enam Eastern North America, weur Western Europe, eeur Eastern Europe, apac Asia-Pacific, oc Oceania. Jurisdictional Restrictions guarantee objects in a bucket are stored within a specific jurisdiction. Use Jurisdictional Restrictions when you need to ensure data is stored and processed within a jurisdiction to meet data residency requirements. Available jurisdictions: eu European Union, fedramp FedRAMP, us United States. The following services do not interact with R2 resources with assigned jurisdictions: Logpush. Once an R2 bucket is created, the jurisdiction cannot be changed. Page last updated Aug 19, 2026. Read 2026-09-12." + +data r2_data_location_citation: FactCitation = FactCitation { + fact: DeclarationRef { + module_path: "extdeps.cloudflare.r2", + decl_name: "r2_data_location_reading", + field: WholeDeclaration + }, + authority: r2_data_location_authority, +} + +data r2_how_r2_works_reading: NonEmptyStr = "R2 Gateway: The entry point for all API requests that handles authentication and routing logic. This service is deployed across Cloudflare's global network via Cloudflare Workers. Metadata Service: A distributed layer built on Durable Objects used to store and manage object metadata. Distributed Storage Infrastructure: The underlying infrastructure that persistently stores encrypted object data. On write, the Gateway determines which storage cluster to write the encrypted data to within the location set for the bucket. The encrypted data is written and stored in the distributed storage infrastructure, and replicated within the region (e.g. ENAM) for durability. On read, if the object is not in the tiered read cache, it retrieves the object from one of the distributed storage data centers within the region that holds the object data. Page last updated Apr 21, 2026. Read 2026-09-12." + +data r2_how_r2_works_citation: FactCitation = FactCitation { + fact: DeclarationRef { + module_path: "extdeps.cloudflare.r2", + decl_name: "r2_how_r2_works_reading", + field: WholeDeclaration + }, + authority: r2_how_r2_works_authority, +} + +data r2_us_jurisdiction_changelog_reading: NonEmptyStr = "New us jurisdiction for R2. R2 now supports a us jurisdiction, which guarantees that bucket data is stored and processed within the United States. Use this jurisdiction when you need explicit US data residency guarantees. Use the jurisdiction-specific S3 endpoint https://.us.r2.cloudflarestorage.com. Once an R2 bucket is created, its jurisdiction cannot be changed. Posted 2026-08-17. Read 2026-09-12." + +data r2_us_jurisdiction_changelog_citation: FactCitation = FactCitation { + fact: DeclarationRef { + module_path: "extdeps.cloudflare.r2", + decl_name: "r2_us_jurisdiction_changelog_reading", + field: WholeDeclaration + }, + authority: r2_us_jurisdiction_changelog_authority, +} + +data r2_tokens_default_jurisdiction_reading: NonEmptyStr = "A specific bucket is represented as com.cloudflare.edge.r2.bucket.__. JURISDICTION: The jurisdiction where the R2 bucket lives. For buckets not created in a specific jurisdiction this value will be default. Read 2026-09-12." + +data r2_tokens_default_jurisdiction_citation: FactCitation = FactCitation { + fact: DeclarationRef { + module_path: "extdeps.cloudflare.r2", + decl_name: "r2_tokens_default_jurisdiction_reading", + field: WholeDeclaration + }, + authority: extdeps_external_authority_anchor, +} + +data r2_create_bucket_location_hint_reading: NonEmptyStr = "Create Bucket POST /accounts/\{account_id\}/r2/buckets. Body parameter locationHint, optional, one of apac, eeur, enam, weur, wnam, oc, described as Location of the bucket. Header cf-r2-jurisdiction, optional, one of default, eu, us, fedramp, fedramp-high, described as Jurisdiction where objects in this bucket are guaranteed to be stored. Read 2026-09-13." + +data r2_create_bucket_location_hint_citation: FactCitation = FactCitation { + fact: DeclarationRef { + module_path: "extdeps.cloudflare.r2", + decl_name: "r2_create_bucket_location_hint_reading", + field: WholeDeclaration + }, + authority: r2_create_bucket_authority, +} + +data r2_get_bucket_location_reading: NonEmptyStr = "Get Bucket GET /accounts/\{account_id\}/r2/buckets/\{bucket_name\}. Result field location, optional, one of apac, eeur, enam, weur, wnam, oc, described as Location of the bucket. Result field jurisdiction, optional, one of default, eu, us, fedramp, fedramp-high, described as Jurisdiction where objects in this bucket are guaranteed to be stored. Read 2026-09-13." + +data r2_get_bucket_location_citation: FactCitation = FactCitation { + fact: DeclarationRef { + module_path: "extdeps.cloudflare.r2", + decl_name: "r2_get_bucket_location_reading", + field: WholeDeclaration + }, + authority: r2_get_bucket_authority, +} + +// THE READINGS ARE ONE CLOSURE. product.supplier.cloudflare_r2 hashes these lists (and +// r2_tokens_doc_as_of) into ProviderRouteFacts.facts_revision, so a changed transcription would +// be a different facts row rather than a silent edit behind a pinned string. That hash is not +// a production consumer of the pin: no origin ProviderRoute is minted, so the as-of frontier +// row remains. Automatic placement is recorded IN r2_data_location_reading; it is not a second +// model-scope subject and not a value of ProviderRoute.region. +fn r2_published_location_readings() -> List { + [ + r2_data_location_reading, + r2_how_r2_works_reading, + r2_us_jurisdiction_changelog_reading, + r2_tokens_default_jurisdiction_reading, + r2_create_bucket_location_hint_reading, + r2_get_bucket_location_reading, + ] +} + +fn r2_published_location_citations() -> List { + [ + r2_data_location_citation, + r2_how_r2_works_citation, + r2_us_jurisdiction_changelog_citation, + r2_tokens_default_jurisdiction_citation, + r2_create_bucket_location_hint_citation, + r2_get_bucket_location_citation, + ] +} + + // THE r2_s3_endpoint_url ROW IS RETIRED: gunbc.cloudflare.r2_origin_object reaches it through // r2_object_url on the executing put_origin_object and fetch_origin_object entries, which is the -// consumer the row named. The list is the membership of what remains. +// consumer the row named. The list is the membership of what remains. r2_tokens_doc_as_of stays: +// the digest that cites it is reached only from the dead ProviderRouteObserved arm and the claim +// witness, which is the unread-outside-witness condition the row already recorded. data cloudflare_r2_frontier_rows: List = [ frontier_row_decl( ref: decl_ref(module_path: "extdeps.cloudflare.r2", decl_name: "r2_account_resource_name"), diff --git a/dag/extdeps/vendor/cloudflare.dag b/dag/extdeps/vendor/cloudflare.dag index 7f7eb6e7317..03abdacb9d1 100644 --- a/dag/extdeps/vendor/cloudflare.dag +++ b/dag/extdeps/vendor/cloudflare.dag @@ -1,10 +1,11 @@ module extdeps.vendor.cloudflare +import std.types { NonEmptyStr, List } import std.decl_ref { DeclarationRef, WholeDeclaration } import extdeps.vendor { Vendor } import extdeps.securities { Securities } -import extdeps.external_authority { ExternalAuthority, ExternalModelScope, ExternalSubjectRef } +import extdeps.external_authority { ExternalAuthority, ExternalModelScope, ExternalSubjectRef, FactCitation } import extdeps.uri { Uri, Https } data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { @@ -14,6 +15,20 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } +data cloudflare_subprocessors_authority: ExternalAuthority = ExternalAuthority { + uri: Uri { + scheme: Https + locator: "www.cloudflare.com/gdpr/subprocessors/cloudflare-services" + } +} + +data cloudflare_customer_dpa_authority: ExternalAuthority = ExternalAuthority { + uri: Uri { + scheme: Https + locator: "cf-assets.www.cloudflare.com/slt3lc6tev37/1TTgT35GoUNlKZYGuKWBFy/4e7dfc8cf402419a9b1cf624291fc69f/cloudflare_customer_dpa-v6.4_april_3_2026.pdf" + } +} + data extdeps_model_scope: ExternalModelScope = ExternalModelScope { subject: ExternalSubjectRef { declaration: DeclarationRef { @@ -23,7 +38,44 @@ data extdeps_model_scope: ExternalModelScope = ExternalModelScope { } }, first_citation: extdeps.vendor.cloudflare.extdeps_external_authority_anchor, - further_citations: [] + further_citations: [ + cloudflare_subprocessors_authority, + cloudflare_customer_dpa_authority, + ] } data cloudflare: Vendor = Vendor { legal_name: "Cloudflare, Inc." } + +// COMPANY DOCUMENTS, NOT R2 PRODUCT FACTS. The Customer DPA and the subprocessors table are +// independently versioned on Cloudflare's company cadence. They sit on this vendor subject so a +// Workers or Zero Trust module does not import extdeps.cloudflare.r2 for a company fact, and so an +// R2 change does not rewrite them. +data cloudflare_subprocessors_reading: NonEmptyStr = "Last Updated: October 1, 2025. Cloudflare uses a handful of sub-processors to support the Cloudflare service. Some of these sub-processors are members of the Cloudflare Group (Cloudflare, Inc. and its subsidiaries) and some are third parties. Third-party entities include Slack Technologies, Inc. (Customer support communications, United States); Zendesk, Inc. (Customer support and account management, United States, the European Economic Area, Japan, and Australia); Salesforce, Inc. (Customer support and account management, United States); Google LLC (Cloudflare Developer Platform, Cloudflare Zero Trust and AI Gateway; European Economic Area, United States, Australia, India); Oracle America, Inc. (Cloudflare Developer Platform and Cache Reserve; United States, European Economic Area, UK, Japan, Australia, Canada, Singapore); Amazon Web Services (Cloudflare Email Security; United States, European Economic Area); CoreWeave, Inc., Nebius BV (Workers AI); Anthropic PBC, OpenAI, Inc., X.AI Corp., Groq, Inc. (AI Gateway). The page lists Cloudflare Group subsidiaries by location." + +data cloudflare_subprocessors_citation: FactCitation = FactCitation { + fact: DeclarationRef { + module_path: "extdeps.vendor.cloudflare", + decl_name: "cloudflare_subprocessors_reading", + field: WholeDeclaration + }, + authority: cloudflare_subprocessors_authority, +} + +data cloudflare_customer_dpa_reading: NonEmptyStr = "Cloudflare, Inc. Data Processing Addendum, Version 6.4 April 3, 2026. The Customer grants a general written authorization: (a) to Cloudflare to appoint other members of the Cloudflare Group as sub-Processors, and (b) to Cloudflare and other members of the Cloudflare Group to appoint third party data center operators, and business, engineering and customer support providers as sub-Processors to support the performance of the Service. Cloudflare will maintain a list of sub-Processors at https://www.cloudflare.com/gdpr/subprocessors/. This DPA and any action related thereto shall be governed by and construed in accordance with the laws as specified in the Main Agreement, and the parties consent to the personal jurisdiction of, and venue in, the courts specified in the Main Agreement." + +data cloudflare_customer_dpa_citation: FactCitation = FactCitation { + fact: DeclarationRef { + module_path: "extdeps.vendor.cloudflare", + decl_name: "cloudflare_customer_dpa_reading", + field: WholeDeclaration + }, + authority: cloudflare_customer_dpa_authority, +} + +fn cloudflare_company_document_readings() -> List { + [cloudflare_subprocessors_reading, cloudflare_customer_dpa_reading] +} + +fn cloudflare_company_document_citations() -> List { + [cloudflare_subprocessors_citation, cloudflare_customer_dpa_citation] +} diff --git a/dag/gunbc/census_closure_frontier.dag b/dag/gunbc/census_closure_frontier.dag index 0d1e53c80cd..bd82ba47269 100644 --- a/dag/gunbc/census_closure_frontier.dag +++ b/dag/gunbc/census_closure_frontier.dag @@ -38,6 +38,7 @@ import extdeps.tools.sha256sum { sha256_verify_native_transport_frontier_rows } import gunbc.cloudflare.r2_token_mint { cloudflare_r2_token_mint_frontier_rows } import extdeps.cloudflare.account_api_tokens { cloudflare_account_api_tokens_frontier_rows } import extdeps.cloudflare.r2 { cloudflare_r2_frontier_rows } +import product.supplier.cloudflare_r2 { cloudflare_r2_supplier_frontier_rows } import extdeps.backblaze.b2 { backblaze_b2_frontier_rows } import extdeps.cloud.gcp.storage { gcs_storage_frontier_rows } import extdeps.ebay.browse { ebay_browse_frontier_rows } @@ -75,6 +76,7 @@ fn census_closure_frontier_row_groups() -> List> { cloudflare_r2_token_mint_frontier_rows, cloudflare_account_api_tokens_frontier_rows, cloudflare_r2_frontier_rows, + cloudflare_r2_supplier_frontier_rows, backblaze_b2_frontier_rows, gcs_storage_frontier_rows, ebay_browse_frontier_rows, diff --git a/dag/gunbc/cloudflare/r2_origin.dag b/dag/gunbc/cloudflare/r2_origin.dag index 1077d2b10cc..3400ec2cb39 100644 --- a/dag/gunbc/cloudflare/r2_origin.dag +++ b/dag/gunbc/cloudflare/r2_origin.dag @@ -204,7 +204,7 @@ type DurableOriginStanding = DurableOriginAllocated { bucket: DurableOriginBucket } | DurableOriginUnallocated { purpose: BucketPurpose } -// DEFAULT JURISDICTION, STATED RATHER THAN DEFAULTED. R2JurisdictionEu and R2JurisdictionFedramp are +// DEFAULT JURISDICTION, STATED RATHER THAN DEFAULTED. Eu, Us, Fedramp, and FedrampHigh are // data-residency commitments this fleet has not made and cannot honour, and picking one would assert // a compliance boundary nothing enforces. fn fabric_durable_origin_standing() -> DurableOriginStanding { diff --git a/dag/gunbc/product/fabric/provider_route.dag b/dag/gunbc/product/fabric/provider_route.dag index 009e7fc6a40..e04c6c041f5 100644 --- a/dag/gunbc/product/fabric/provider_route.dag +++ b/dag/gunbc/product/fabric/provider_route.dag @@ -55,6 +55,46 @@ fn provider_route_eq(a: ProviderRoute, b: ProviderRoute) -> Bool { && declaration_ref_eq(a: a.region, b: b.region) } +// A REGION IS OBSERVED OR THE ROUTE DOES NOT EXIST. product.supplier.ubicloud wrote this +// coproduct first (UbicloudRegionObservation / UbicloudRouteStanding); product.supplier.cloudflare_r2 +// was the proven coincidence (DESIGN section 6). The minting law lives here so a third supplier +// cannot independently edit it. A ProviderRoute is minted ONLY in the read arm: there is no +// value of ProviderRegionObservation that yields a route with an unobserved region. +// +// NOT A MEMBER: gunbc.spark.serving_offer SparkServingRoute. The reason it is not this coproduct +// is stated at that type's declaration (DESIGN section 3b: diverges with a stated reason). +// +// OBLIGATION IS DeclarationRef, NOT NonEmptyStr. That is the grain ProviderPathUnread already +// uses, so a refusal can locate the named row. Ubicloud's first instance carried the sentence +// itself; the coincidence is the reason that form is retired rather than kept as a stated +// divergence. +type ProviderRegionObservation + = ProviderRegionRead { region: DeclarationRef } + | ProviderRegionUnread { obligation: DeclarationRef } + +type ProviderRouteStanding + = ProviderRouteObserved { route: ProviderRoute } + | ProviderRouteRegionUnobserved { obligation: DeclarationRef } + +fn provider_route_from_region( + provider: DeclarationRef, + service: DeclarationRef, + region: ProviderRegionObservation, +) -> ProviderRouteStanding { + match region { + ProviderRegionUnread { obligation } => + ProviderRouteRegionUnobserved { obligation: obligation }, + ProviderRegionRead { region: observed } => + ProviderRouteObserved { + route: ProviderRoute { + provider: provider, + service: service, + region: observed, + }, + }, + } +} + // The posture is a REVISION, never an ambient "current". A permit records the exact revision it // was evaluated against, so a posture change makes standing permits STALE rather than silently // tolerated - the difference between a decision that can be re-derived and one that merely diff --git a/dag/gunbc/product/supplier/cloudflare_r2.dag b/dag/gunbc/product/supplier/cloudflare_r2.dag new file mode 100644 index 00000000000..128d9505193 --- /dev/null +++ b/dag/gunbc/product/supplier/cloudflare_r2.dag @@ -0,0 +1,200 @@ +module product.supplier.cloudflare_r2 + +import std.types { List, NonEmptyStr } +import std.decl_ref { DeclarationRef, decl_ref } +import std.roster_frontier { FrontierRow, frontier_row_decl } +import std.dissolution { unbound_dissolution } +import std.content_hash { as_content_hash_structural, content_hash_atom, content_hash_combine_structural, Fnv1a64Structural } +import product.fabric.provider_route { + ProviderRoute, ProviderRouteFacts, + ProviderDataPathClosure, ProviderPathUnread, + DownstreamProviderPopulation, DownstreamProvidersUnread, + ProviderRegionObservation, ProviderRegionUnread, + ProviderRouteStanding, ProviderRouteObserved, ProviderRouteRegionUnobserved, + provider_route_from_region, +} +import extdeps.cloudflare.r2 { + r2_published_location_readings, + r2_published_location_citations, + r2_tokens_doc_as_of, +} +import extdeps.vendor.cloudflare { + cloudflare_company_document_readings, + cloudflare_company_document_citations, +} + +// THE DURABLE-ORIGIN THIS REPOSITORY ANSWERS THE NINE-PATH CLOSURE FOR. PRODUCTION DOES NOT MINT A ROUTE. +// +// WHAT WAS READ. Cloudflare's R2 data-location page, how-R2-works page, us-jurisdiction changelog, +// tokens page, subprocessors list, Customer DPA v6.4 (2026-09-12), and the Create Bucket / +// Get Bucket API method pages (2026-09-13) were transcribed in +// extdeps.cloudflare.r2. The durable origin in this fleet +// (gunbc.cloudflare.r2_origin fabric_durable_origin_standing, bucket gunbai-fabric-origin) carries +// R2JurisdictionDefault. That module already states that Default is not a data-residency +// commitment this fleet has made. Create Bucket's locationHint is a requested placement; Get +// Bucket's location is a reported location; cf-r2-jurisdiction / Jurisdictional Restrictions are +// the residency guarantee. Those three are not one field. This repository has not queried +// gunbai-fabric-origin's Get Bucket location, so no reported-location observation is minted here. +// +// WHAT PRODUCTION EXECUTES. cloudflare_r2_durable_origin_route_standing is +// ProviderRouteRegionUnobserved carrying cloudflare_r2_region_unread_obligation. +// cloudflare_r2_route_facts_population is therefore empty: there is no origin ProviderRoute, so +// there is no origin row for admit_provider_use. The nine-path closure and downstream population +// are still answered (every path Unread; Absent taken zero times). The admit_provider_use pair +// lives only in the witness, over a route minted in the ProviderRegionRead arm of the same +// coproduct — a synthetic observed region, not this origin. +// +// THE REGION SLOT IS NOT A PLACE TO RECORD AUTOMATIC. product.fabric.provider_route says the +// cited region is where the work actually runs, observed at a declared boundary and never +// fabricated. Automatic placement, as transcribed in r2_data_location_reading, is a CHOICE MECHANISM. product.supplier.ubicloud already +// ruled that shape out: a ProviderRoute is minted ONLY from a read region. + +fn cloudflare_r2_provider_ref() -> DeclarationRef { + decl_ref(module_path: "extdeps.vendor.cloudflare", decl_name: "cloudflare") +} + +fn cloudflare_r2_service_ref() -> DeclarationRef { + decl_ref(module_path: "extdeps.cloudflare.r2", decl_name: "R2S3Endpoint") +} + +data cloudflare_r2_region_unread_obligation: NonEmptyStr = "Where this fleet's durable origin actually runs is UNREAD. gunbc.cloudflare.r2_origin fabric_durable_origin_standing places bucket gunbai-fabric-origin under R2JurisdictionDefault. Create Bucket locationHint (r2_create_bucket_location_hint_reading, read 2026-09-13) is a requested placement. Get Bucket location (r2_get_bucket_location_reading, read 2026-09-13) is a reported location. Those are two upstream fields that share location tokens; collapsing them is a section 3 meaning-fork. This repository has not queried gunbai-fabric-origin, so no Get Bucket location is an observation of ours. Automatic and R2JurisdictionDefault are not values of ProviderRoute.region. RESOLVED BY a Get Bucket (or equivalent) observation of this bucket's location field sufficient to name the operating region, or by recreating the origin under a Jurisdictional Restriction that names a jurisdiction — at which point this standing takes ProviderRegionRead with that named location as region. A reported location is not a residency guarantee and is not the nine-path closure. It is NOT resolved by citing r2_placement_automatic, R2JurisdictionDefault, a dashboard Location label, or Create Bucket locationHint." + +fn cloudflare_r2_durable_origin_region() -> ProviderRegionObservation { + ProviderRegionUnread { + obligation: decl_ref(module_path: "product.supplier.cloudflare_r2", decl_name: "cloudflare_r2_region_unread_obligation"), + } +} + +fn cloudflare_r2_route(region: ProviderRegionObservation) -> ProviderRouteStanding { + provider_route_from_region( + provider: cloudflare_r2_provider_ref(), + service: cloudflare_r2_service_ref(), + region: region, + ) +} + +fn cloudflare_r2_durable_origin_route_standing() -> ProviderRouteStanding { + cloudflare_r2_route(region: cloudflare_r2_durable_origin_region()) +} + +// A LOCATION PATH IS CLOSED ONLY BY OPERATOR AND JURISDICTION TOGETHER (DESIGN section 4b(3)). +// Naming an operating entity leaves the jurisdiction unknown; naming a jurisdiction without who +// operates it leaves the operator unknown. Either conjunct can be fully satisfied while the +// question this obligation exists to close stays open — the same defect as a trigger retired by +// affordability alone when the real requirement was affordability AND a passing check. Either +// alone is therefore not a resolution. +data cloudflare_r2_execution_location_obligation: NonEmptyStr = "Where R2 executes object operations for a default-jurisdiction bucket is UNREAD. extdeps.cloudflare.r2 r2_how_r2_works_reading states that the R2 Gateway is deployed across Cloudflare's global network via Cloudflare Workers, close to the user, and that the Gateway then writes to a storage cluster within the location set for the bucket. That is an architecture of a CHOICE, not a location of this fleet's bucket. RESOLVED BY evidence sufficient for this path's OPERATOR AND JURISDICTION both — a Cloudflare statement that names who handles requests for a named default-jurisdiction bucket and the jurisdiction of that handling. Naming an operating entity without a jurisdiction, or a jurisdiction without an operator, does not close this path. It is NOT resolved by R2JurisdictionDefault, by Automatic placement, by Create Bucket locationHint, or by an unqueried Get Bucket location." + +data cloudflare_r2_durable_storage_location_obligation: NonEmptyStr = "Where objects in this fleet's durable origin are stored is UNREAD. gunbc.cloudflare.r2_origin fabric_durable_origin_standing places bucket gunbai-fabric-origin under R2JurisdictionDefault. Requested placement, reported location, and residency guarantee are three facts: Create Bucket locationHint (r2_create_bucket_location_hint_reading) is requested placement; Get Bucket location (r2_get_bucket_location_reading) is reported location; Jurisdictional Restrictions / the Get Bucket jurisdiction field are the guarantee that objects are stored and processed within a jurisdiction. This repository has not queried gunbai-fabric-origin, so no Get Bucket location is an observation of ours. RESOLVED BY evidence sufficient for this path's OPERATOR AND JURISDICTION both — recreating the origin under a Jurisdictional Restriction that names a jurisdiction, or a Cloudflare statement that objects in gunbai-fabric-origin are stored and processed within a named jurisdiction by a named operator. A reported location is not that guarantee and is not the nine-path closure. It is NOT resolved by Create Bucket locationHint, by treating Get Bucket location as a hint, or by treating R2JurisdictionDefault as residency." + +data cloudflare_r2_backups_location_obligation: NonEmptyStr = "Where R2 replicates objects for durability on a default-jurisdiction bucket is UNREAD. extdeps.cloudflare.r2 r2_how_r2_works_reading states that encrypted data is replicated within the region (e.g. ENAM) for durability, and it names no region for a default-jurisdiction bucket and no country for that replication. RESOLVED BY evidence sufficient for this path's OPERATOR AND JURISDICTION both — a Cloudflare statement of the operator and the region or jurisdiction inside which objects of a named default-jurisdiction bucket are replicated. It is NOT resolved by the example token ENAM in that sentence." + +data cloudflare_r2_logs_location_obligation: NonEmptyStr = "Where R2 or the Cloudflare platform stores logs of access to a default-jurisdiction bucket is UNREAD. extdeps.cloudflare.r2 r2_data_location_reading states that Logpush does not interact with R2 resources with assigned jurisdictions, which is a fact about jurisdictional buckets and does not say where logs of a default-jurisdiction bucket go, nor that no such logs exist. THE ABSENT ARM IS DELIBERATELY NOT TAKEN. RESOLVED BY a Cloudflare statement about logging of R2 object access, in either direction: an explicit none makes this path Absent with that document as evidence, and a described store makes it Located with evidence sufficient for OPERATOR AND JURISDICTION both." + +data cloudflare_r2_telemetry_location_obligation: NonEmptyStr = "Whether Cloudflare collects telemetry about a default-jurisdiction R2 bucket, what it carries, and where it goes, is UNREAD. Nothing in the documents read on 2026-09-12 describes a telemetry or usage-reporting path for R2 object storage as a located destination. THE ABSENT ARM IS DELIBERATELY NOT TAKEN: silence is not a denial. RESOLVED BY a Cloudflare statement about R2 telemetry, in either direction, sufficient for OPERATOR AND JURISDICTION both when the arm is Located." + +data cloudflare_r2_control_plane_location_obligation: NonEmptyStr = "Where the R2 control plane -- the Dashboard, the S3 API, the REST API that powers Wrangler, and the Metadata Service -- runs for a default-jurisdiction bucket, and under whose jurisdiction, is UNREAD. r2_how_r2_works_reading places the Gateway on the global network and the Metadata Service on Durable Objects and names no country for either. RESOLVED BY evidence sufficient for this path's OPERATOR AND JURISDICTION both. Naming an operating entity without a jurisdiction, or a jurisdiction without an operator, does not close this path." + +data cloudflare_r2_support_access_obligation: NonEmptyStr = "From which jurisdiction Cloudflare support reaches a default-jurisdiction R2 bucket is UNREAD. extdeps.vendor.cloudflare cloudflare_subprocessors_reading names Slack, Zendesk and Salesforce for customer support, with locations that include the United States and, for Zendesk, also the EEA, Japan and Australia. That is a company-wide support-tool list, not a statement that support access to THIS bucket's objects is exercised from those places or that it is not. RESOLVED BY evidence sufficient for this path's OPERATOR AND JURISDICTION both — a Cloudflare statement of where support access to a given R2 bucket's objects is exercised from and by whom." + +data cloudflare_r2_administrative_access_obligation: NonEmptyStr = "From which jurisdiction administrative access to a default-jurisdiction R2 bucket is exercised is UNREAD. The subprocessors page states that Cloudflare Group companies may be sub-processors because employees of those affiliates may need to provide account and engineering support, and it lists subsidiaries in the United Kingdom, Singapore, Australia, Germany, Portugal, France, Japan, Canada, the Netherlands, the U.A.E., India, the United States, South Korea, Mexico, Malaysia, Sweden and Switzerland. That names WHO may provide support, not FROM WHERE administrative access to this bucket is exercised, and it does not locate this bucket. RESOLVED BY evidence sufficient for this path's OPERATOR AND JURISDICTION both." + +data cloudflare_r2_spill_location_obligation: NonEmptyStr = "Where customer material may SPILL on an R2 default-jurisdiction route -- caches, diagnostic captures, undeleted replicas, Local Uploads, tiered read cache -- is UNREAD. r2_how_r2_works_reading describes a Tiered Read Cache and Local Uploads and names no country for either, and it does not say that no other spill surface exists. THE ABSENT ARM IS DELIBERATELY NOT TAKEN. RESOLVED BY a Cloudflare statement about host-side or cache-side copies of R2 object bytes for default-jurisdiction buckets, which may resolve this path in either direction, with Located requiring OPERATOR AND JURISDICTION both." + +data cloudflare_r2_downstream_obligation: NonEmptyStr = "Which parties process objects stored in a default-jurisdiction R2 bucket on Cloudflare's behalf is UNREAD. The Customer DPA v6.4 (read 2026-09-12) authorizes Cloudflare Group members and third-party data center operators as sub-Processors, and cloudflare_subprocessors_reading transcribes the company-wide table. READER FINDING, not a Cloudflare sentence: that table is not keyed to a named R2 bucket or to the default jurisdiction, so it does not cover gunbai-fabric-origin and it does not establish an empty downstream population. Enumerating it as this route's downstream population would claim coverage the table does not give, and reporting none would claim the negative the table also does not give. RESOLVED BY a Cloudflare statement that names which subprocessors process objects in a named default-jurisdiction R2 bucket -- at which point this population takes Enumerated with that document as coverage -- or an explicit none for that bucket, which takes NoDownstreamProviders with that document as evidence." + +fn cloudflare_r2_data_paths() -> ProviderDataPathClosure { + ProviderDataPathClosure { + execution: ProviderPathUnread { + obligation: decl_ref(module_path: "product.supplier.cloudflare_r2", decl_name: "cloudflare_r2_execution_location_obligation"), + }, + durable_storage: ProviderPathUnread { + obligation: decl_ref(module_path: "product.supplier.cloudflare_r2", decl_name: "cloudflare_r2_durable_storage_location_obligation"), + }, + backups: ProviderPathUnread { + obligation: decl_ref(module_path: "product.supplier.cloudflare_r2", decl_name: "cloudflare_r2_backups_location_obligation"), + }, + logs: ProviderPathUnread { + obligation: decl_ref(module_path: "product.supplier.cloudflare_r2", decl_name: "cloudflare_r2_logs_location_obligation"), + }, + telemetry: ProviderPathUnread { + obligation: decl_ref(module_path: "product.supplier.cloudflare_r2", decl_name: "cloudflare_r2_telemetry_location_obligation"), + }, + control_plane: ProviderPathUnread { + obligation: decl_ref(module_path: "product.supplier.cloudflare_r2", decl_name: "cloudflare_r2_control_plane_location_obligation"), + }, + support_access: ProviderPathUnread { + obligation: decl_ref(module_path: "product.supplier.cloudflare_r2", decl_name: "cloudflare_r2_support_access_obligation"), + }, + administrative_access: ProviderPathUnread { + obligation: decl_ref(module_path: "product.supplier.cloudflare_r2", decl_name: "cloudflare_r2_administrative_access_obligation"), + }, + spill: ProviderPathUnread { + obligation: decl_ref(module_path: "product.supplier.cloudflare_r2", decl_name: "cloudflare_r2_spill_location_obligation"), + }, + } +} + +fn cloudflare_r2_downstream() -> DownstreamProviderPopulation { + DownstreamProvidersUnread { + obligation: decl_ref(module_path: "product.supplier.cloudflare_r2", decl_name: "cloudflare_r2_downstream_obligation"), + } +} + +fn cloudflare_r2_location_readings_digest() -> Fnv1a64Structural { + let after_statements = fold( + concat(r2_published_location_readings(), cloudflare_company_document_readings()), + init: content_hash_atom(value: "product.supplier.cloudflare_r2.location-readings" as NonEmptyStr), + f: fn(acc, statement) { + content_hash_combine_structural(left: acc, right: content_hash_atom(value: statement)) + }, + ) + let after_citations = fold( + concat(r2_published_location_citations(), cloudflare_company_document_citations()), + init: after_statements, + f: fn(acc, citation) { + content_hash_combine_structural( + left: acc, + right: content_hash_atom(value: citation.authority.uri.locator as NonEmptyStr), + ) + }, + ) + content_hash_combine_structural( + left: after_citations, + right: content_hash_atom(value: r2_tokens_doc_as_of as NonEmptyStr), + ) +} + +fn cloudflare_r2_facts(route: ProviderRoute) -> ProviderRouteFacts { + ProviderRouteFacts { + route: route, + contract_terms: decl_ref(module_path: "extdeps.vendor.cloudflare", decl_name: "cloudflare_customer_dpa_reading"), + data_paths: cloudflare_r2_data_paths(), + downstream: cloudflare_r2_downstream(), + observed_at: "2026-09-12T00:00:00Z", + facts_revision: as_content_hash_structural(structural: cloudflare_r2_location_readings_digest()), + } +} + +// THIS MODULE DECLARES NO SANCTION ROSTER AND NO POSTURE REVISION. Nobody has stated that we are +// willing to place work on this vendor's default-jurisdiction R2 under a named posture. Writing a +// roster row here to make the module look complete would be the fabricated authority the gate exists +// to close. Production standing is ProviderRouteRegionUnobserved; this function projects that +// standing to an empty facts list. admit_provider_use is not invoked here. The witness mints a +// synthetic ProviderRegionRead route and calls admit_provider_use on that pair. +data cloudflare_r2_supplier_frontier_rows: List = [ + frontier_row_decl( + ref: decl_ref(module_path: "product.supplier.cloudflare_r2", decl_name: "cloudflare_r2_route_facts_population"), + reason: "production does not consume this population; the executing consumer of the admission pair is the witness", + dissolution: unbound_dissolution( + description: "TRIGGER: a posture producer that mints a CompliancePostureRevision whose permitted_jurisdictions include or omit this origin by matching these facts. SUFFICIENT FOR: this population is read on an executing production path, not only by a witness." + ) + ) +] + +fn cloudflare_r2_route_facts_population() -> List { + match cloudflare_r2_durable_origin_route_standing() { + ProviderRouteRegionUnobserved { obligation } => [], + ProviderRouteObserved { route } => [cloudflare_r2_facts(route: route)], + } +} diff --git a/dag/gunbc/product/supplier/ubicloud.dag b/dag/gunbc/product/supplier/ubicloud.dag index d02f4d60c5c..872ca05d3df 100644 --- a/dag/gunbc/product/supplier/ubicloud.dag +++ b/dag/gunbc/product/supplier/ubicloud.dag @@ -9,7 +9,12 @@ import product.fabric.work { Shape, HardRequirements, CapabilityManifestRef, Tru import product.fabric.envelope { cpu_memory_envelope } import product.fabric.isolation { IsolationProfile } import product.fabric.supply { SupplierOffer, OfferQuote, QuotedPerMinute, OfferEvidence, QuotedSupply } -import product.fabric.provider_route { ProviderRoute } +import product.fabric.provider_route { + ProviderRoute, + ProviderRegionObservation, ProviderRegionUnread, + ProviderRouteStanding, ProviderRouteObserved, ProviderRouteRegionUnobserved, + provider_route_from_region, +} import std.decl_ref { decl_ref, DeclarationRef } import extdeps.pricing.ubicloud { UbicloudRunnerPriceRow, ubicloud_runner_price_catalog, @@ -122,15 +127,17 @@ fn ubicloud_unobserved_isolation() -> IsolationProfile { // UNWRITABLE, not for the currently-empty set of writers to be pointed at. // // So the observation is its own coproduct and a ProviderRoute is minted ONLY in the read arm. -// There is no value of UbicloudRegionObservation that yields a route with an unobserved region, -// which is what makes this construction rather than validation. -type UbicloudRegionObservation - = UbicloudRegionRead { region: DeclarationRef } - | UbicloudRegionUnread { obligation: NonEmptyStr } +// There is no value of ProviderRegionObservation that yields a route with an unobserved region, +// which is what makes this construction rather than validation. The coproduct itself lives in +// product.fabric.provider_route (review 65274): this module was the first instance, and the +// Cloudflare R2 coincidence is why it moved rather than being copied. +fn ubicloud_provider_ref() -> DeclarationRef { + decl_ref(module_path: "extdeps.cloud.ubicloud", decl_name: "extdeps_external_authority_anchor") +} -type UbicloudRouteStanding - = UbicloudRouteObserved { route: ProviderRoute } - | UbicloudRouteRegionUnobserved { obligation: NonEmptyStr } +fn ubicloud_service_ref() -> DeclarationRef { + decl_ref(module_path: "extdeps.cloud.ubicloud", decl_name: "ubicloud_runner_types_authority") +} // NOBODY HAS READ THIS VENDOR'S REGIONS, stated as the standing production observation. Nothing // in the cited catalog names a location, so any region written here would be invented. This is @@ -138,23 +145,18 @@ type UbicloudRouteStanding // obligation is one named thing rather than a sentence repeated per caller. data ubicloud_region_unread_obligation: NonEmptyStr = "No cited Ubicloud row names a region for a runner. Until one is read and cited, this vendor's offers cannot be placed on a route, and binding refuses rather than inventing a location." -fn ubicloud_region_unread() -> UbicloudRegionObservation { - UbicloudRegionUnread { obligation: ubicloud_region_unread_obligation } +fn ubicloud_region_unread() -> ProviderRegionObservation { + ProviderRegionUnread { + obligation: decl_ref(module_path: "product.supplier.ubicloud", decl_name: "ubicloud_region_unread_obligation"), + } } -fn ubicloud_route(region: UbicloudRegionObservation) -> UbicloudRouteStanding { - match region { - UbicloudRegionUnread { obligation } => - UbicloudRouteRegionUnobserved { obligation: obligation }, - UbicloudRegionRead { region: observed } => - UbicloudRouteObserved { - route: ProviderRoute { - provider: decl_ref(module_path: "extdeps.cloud.ubicloud", decl_name: "extdeps_external_authority_anchor"), - service: decl_ref(module_path: "extdeps.cloud.ubicloud", decl_name: "ubicloud_runner_types_authority"), - region: observed, - }, - }, - } +fn ubicloud_route(region: ProviderRegionObservation) -> ProviderRouteStanding { + provider_route_from_region( + provider: ubicloud_provider_ref(), + service: ubicloud_service_ref(), + region: region, + ) } fn ubicloud_unexpressed(catalog: UbicloudRunnerCatalogRow) -> List { @@ -190,15 +192,17 @@ data placement_concurrency_bound: Int = 64 // than binding an offer that would rank on a fabricated number. type ReadinessObservation = ReadinessMeasured { ready_at: Timestamp, receipt: ObservationReceiptRef } - | ReadinessUnmeasured { obligation: NonEmptyStr } + | ReadinessUnmeasured { obligation: DeclarationRef } + +data ubicloud_readiness_unread_obligation: NonEmptyStr = "Provisioning delay from job dispatch to a Ubicloud runner accepting work has not been measured. Start one job per shape, record dispatch and first-heartbeat timestamps, and land the receipt. Until then no Ubicloud offer may be ranked by a delay-valuing policy." data ubicloud_readiness: ReadinessObservation = ReadinessUnmeasured { - obligation: "Provisioning delay from job dispatch to a Ubicloud runner accepting work has not been measured. Start one job per shape, record dispatch and first-heartbeat timestamps, and land the receipt. Until then no Ubicloud offer may be ranked by a delay-valuing policy.", + obligation: decl_ref(module_path: "product.supplier.ubicloud", decl_name: "ubicloud_readiness_unread_obligation"), } type OfferBinding

= OfferBound { bound: SupplierOfferProjection

} - | OfferBindingRefused { runs_on_label: NonEmptyStr, cause: NonEmptyStr } + | OfferBindingRefused { runs_on_label: NonEmptyStr, cause: DeclarationRef } fn bind_ubicloud_offer

( principal: P, @@ -207,15 +211,15 @@ fn bind_ubicloud_offer

( capabilities: CapabilityManifestRef, trust_domain: TrustDomainRef, readiness: ReadinessObservation, - region: UbicloudRegionObservation, + region: ProviderRegionObservation, quoted_at: Timestamp, valid_until: Timestamp, receipt: ObservationReceiptRef, ) -> OfferBinding

{ match ubicloud_route(region: region) { - UbicloudRouteRegionUnobserved { obligation } => + ProviderRouteRegionUnobserved { obligation } => OfferBindingRefused { runs_on_label: row.catalog.runs_on_label, cause: obligation }, - UbicloudRouteObserved { route: bound_route } => + ProviderRouteObserved { route: bound_route } => match readiness { ReadinessUnmeasured { obligation } => OfferBindingRefused { runs_on_label: row.catalog.runs_on_label, cause: obligation }, diff --git a/dag/gunbc/spark/serving_offer.dag b/dag/gunbc/spark/serving_offer.dag index be157b4c116..9d75bd569f5 100644 --- a/dag/gunbc/spark/serving_offer.dag +++ b/dag/gunbc/spark/serving_offer.dag @@ -104,8 +104,8 @@ type SparkServingReadiness // // SupplierOffer carries a ProviderRoute because admission is decided over provider x service x // region and never over a company. A route's region is therefore an OBSERVATION, exactly as -// product.supplier.ubicloud ubicloud_route treats it: unread, it refuses as -// UbicloudRouteRegionUnobserved rather than filling the slot. This module has the same obligation +// product.fabric.provider_route provider_route_from_region treats it: unread, it refuses as +// ProviderRouteRegionUnobserved rather than filling the slot. This module has the same obligation // and, today, no observer -- so it refuses for the same reason the readiness arm above refuses. // Binding an offer whose route nothing established would put a candidate in front of selection // carrying a region no one measured, and every admission decision downstream would be taken diff --git a/dag/test/claim/cloudflare_r2_origin_object_witness_test.dag b/dag/test/claim/cloudflare_r2_origin_object_witness_test.dag index f19ecac4d16..7aad2cdde32 100644 --- a/dag/test/claim/cloudflare_r2_origin_object_witness_test.dag +++ b/dag/test/claim/cloudflare_r2_origin_object_witness_test.dag @@ -10,6 +10,9 @@ import extdeps.cloudflare.r2 { R2S3Endpoint, R2JurisdictionDefault, R2JurisdictionEu, + R2JurisdictionFedramp, + R2JurisdictionFedrampHigh, + R2JurisdictionUs, R2ObjectLocator, r2_object_url, r2_s3_sigv4_region, @@ -39,6 +42,7 @@ import gunbc.cloudflare.r2_permission_group_observe { cloudflare_permission_group_observation_frontier_rows, } import gunbc.cloudflare.r2_token_mint { cloudflare_r2_token_mint_frontier_rows } +import product.supplier.cloudflare_r2 { cloudflare_r2_supplier_frontier_rows } import gunbc.cloudflare.r2_origin_object { S3TransferAnswer, S3Answered, @@ -108,6 +112,21 @@ test fn r2_object_url_is_path_style_under_the_jurisdiction_host() -> Bool { bucket_name: "a-bucket", key: "k", }) == "https://4793d734c0b8e484dfc37ec392b5fa8a.eu.r2.cloudflarestorage.com/a-bucket/k" + && r2_object_url(locator: R2ObjectLocator { + endpoint: R2S3Endpoint { account_id: "4793d734c0b8e484dfc37ec392b5fa8a", jurisdiction: R2JurisdictionUs }, + bucket_name: "a-bucket", + key: "k", + }) == "https://4793d734c0b8e484dfc37ec392b5fa8a.us.r2.cloudflarestorage.com/a-bucket/k" + && r2_object_url(locator: R2ObjectLocator { + endpoint: R2S3Endpoint { account_id: "4793d734c0b8e484dfc37ec392b5fa8a", jurisdiction: R2JurisdictionFedramp }, + bucket_name: "a-bucket", + key: "k", + }) == "https://4793d734c0b8e484dfc37ec392b5fa8a.fedramp.r2.cloudflarestorage.com/a-bucket/k" + && r2_object_url(locator: R2ObjectLocator { + endpoint: R2S3Endpoint { account_id: "4793d734c0b8e484dfc37ec392b5fa8a", jurisdiction: R2JurisdictionFedrampHigh }, + bucket_name: "a-bucket", + key: "k", + }) == "https://4793d734c0b8e484dfc37ec392b5fa8a.fedramp-high.r2.cloudflarestorage.com/a-bucket/k" && (r2_s3_sigv4_region as String) == "auto" && curl_aws_sigv4_s3_provider(region: r2_s3_sigv4_region) == "aws:amz:auto:s3" } @@ -386,8 +405,11 @@ fn frontier_row_names_decl(row: FrontierRow, ref: DeclarationRef) -> Bool { // the observed-write-id row is still open for the same reason. test fn r2_origin_object_frontier_rows_reflect_the_executed_evidence() -> Bool { frontier_rows_well_formed(rows: cloudflare_r2_frontier_rows) + && frontier_rows_well_formed(rows: cloudflare_r2_supplier_frontier_rows) && !any(cloudflare_r2_frontier_rows, row => frontier_row_names_decl( row: row, ref: decl_ref(module_path: "extdeps.cloudflare.r2", decl_name: "r2_s3_endpoint_url"))) + && any(cloudflare_r2_frontier_rows, row => frontier_row_names_decl( + row: row, ref: decl_ref(module_path: "extdeps.cloudflare.r2", decl_name: "r2_tokens_doc_as_of"))) && frontier_rows_well_formed(rows: cloudflare_r2_token_mint_frontier_rows) && any(cloudflare_r2_token_mint_frontier_rows, row => frontier_row_names_decl( row: row, ref: decl_ref(module_path: "gunbc.cloudflare.r2_token_mint", decl_name: "admit_r2_object_write_api_mint"))) diff --git a/dag/test/claim/cloudflare_r2_token_witness_test.dag b/dag/test/claim/cloudflare_r2_token_witness_test.dag index 80e023825f4..d9ab495d953 100644 --- a/dag/test/claim/cloudflare_r2_token_witness_test.dag +++ b/dag/test/claim/cloudflare_r2_token_witness_test.dag @@ -42,6 +42,9 @@ import extdeps.cloudflare.r2 { R2S3Endpoint, R2JurisdictionDefault, R2JurisdictionEu, + R2JurisdictionFedramp, + R2JurisdictionFedrampHigh, + R2JurisdictionUs, r2_s3_endpoint_url, r2_bucket_resource_name, r2_account_resource_name, @@ -52,6 +55,7 @@ import extdeps.cloudflare.r2 { r2_object_read_grant, cloudflare_r2_frontier_rows } +import product.supplier.cloudflare_r2 { cloudflare_r2_supplier_frontier_rows } import std.roster_frontier { FrontierRow, DeclSubject, PathSubject, frontier_rows_well_formed, frontier_subject_eq } import std.decl_ref { DeclarationRef, decl_ref, declaration_ref_eq } import std.human_intervention { @@ -166,6 +170,24 @@ test fn r2_endpoints_and_iam_resource_names_follow_the_r2_token_docs() -> Bool { jurisdiction: R2JurisdictionEu } ) == "https://4793d734c0b8e484dfc37ec392b5fa8a.eu.r2.cloudflarestorage.com" + && r2_s3_endpoint_url( + endpoint: R2S3Endpoint { + account_id: "4793d734c0b8e484dfc37ec392b5fa8a", + jurisdiction: R2JurisdictionUs + } + ) == "https://4793d734c0b8e484dfc37ec392b5fa8a.us.r2.cloudflarestorage.com" + && r2_s3_endpoint_url( + endpoint: R2S3Endpoint { + account_id: "4793d734c0b8e484dfc37ec392b5fa8a", + jurisdiction: R2JurisdictionFedramp + } + ) == "https://4793d734c0b8e484dfc37ec392b5fa8a.fedramp.r2.cloudflarestorage.com" + && r2_s3_endpoint_url( + endpoint: R2S3Endpoint { + account_id: "4793d734c0b8e484dfc37ec392b5fa8a", + jurisdiction: R2JurisdictionFedrampHigh + } + ) == "https://4793d734c0b8e484dfc37ec392b5fa8a.fedramp-high.r2.cloudflarestorage.com" && r2_bucket_resource_name( account_id: "4793d734c0b8e484dfc37ec392b5fa8a", jurisdiction: R2JurisdictionDefault, @@ -418,4 +440,5 @@ test fn cloudflare_frontier_rows_are_in_the_census() -> Bool { all(cloudflare_r2_token_mint_frontier_rows, row => census_contains_frontier_subject(row: row)) && all(cloudflare_account_api_tokens_frontier_rows, row => census_contains_frontier_subject(row: row)) && all(cloudflare_r2_frontier_rows, row => census_contains_frontier_subject(row: row)) + && all(cloudflare_r2_supplier_frontier_rows, row => census_contains_frontier_subject(row: row)) } diff --git a/dag/test/claim/fabric/ubicloud_binding_witness_test.dag b/dag/test/claim/fabric/ubicloud_binding_witness_test.dag index c39ace7d641..980adc387dd 100644 --- a/dag/test/claim/fabric/ubicloud_binding_witness_test.dag +++ b/dag/test/claim/fabric/ubicloud_binding_witness_test.dag @@ -3,11 +3,13 @@ module test.claim.fabric.ubicloud_binding_witness import std.types { NonEmptyStr } import std.logic { Bool } import std.decl_ref { decl_ref, declaration_ref_eq } -import product.fabric.provider_route { provider_route_eq, ProviderRoute } +import product.fabric.provider_route { + provider_route_eq, ProviderRoute, + ProviderRegionObservation, ProviderRegionRead, +} import product.supplier.ubicloud { bind_ubicloud_offer, ReadinessMeasured, OfferBound, OfferBindingRefused, - UbicloudRegionObservation, UbicloudRegionRead, ubicloud_region_unread, - ubicloud_region_unread_obligation, + ubicloud_region_unread, ubicloud_region_unread_obligation, } import extdeps.pricing.ubicloud { ubicloud_premium_standard_2_price } @@ -25,15 +27,15 @@ import extdeps.pricing.ubicloud { ubicloud_premium_standard_2_price } // observation someone made, and a fixture standing in for that observation belongs to the fixture. data observed_region: NonEmptyStr = "observed-region-for-this-witness" -fn a_read_region() -> UbicloudRegionObservation { - UbicloudRegionRead { +fn a_read_region() -> ProviderRegionObservation { + ProviderRegionRead { region: decl_ref( module_path: "test.claim.fabric.ubicloud_binding_witness", decl_name: "observed_region"), } } -fn bind(region: UbicloudRegionObservation) -> NonEmptyStr { +fn bind(region: ProviderRegionObservation) -> NonEmptyStr { match bind_ubicloud_offer( principal: "gunbc", executor: "gunbc", @@ -54,7 +56,7 @@ fn bind(region: UbicloudRegionObservation) -> NonEmptyStr { } } -fn bound_region_matches(region: UbicloudRegionObservation, expected: ProviderRoute) -> Bool { +fn bound_region_matches(region: ProviderRegionObservation, expected: ProviderRoute) -> Bool { match bind_ubicloud_offer( principal: "gunbc", executor: "gunbc", diff --git a/dag/test/claim/supplier/cloudflare_r2_route_witness_test.dag b/dag/test/claim/supplier/cloudflare_r2_route_witness_test.dag new file mode 100644 index 00000000000..12b10fce145 --- /dev/null +++ b/dag/test/claim/supplier/cloudflare_r2_route_witness_test.dag @@ -0,0 +1,308 @@ +module test.claim.supplier.cloudflare_r2_route_witness + +import std.types { Bool, List, NonEmptyStr, String } +import std.decl_ref { DeclarationRef, decl_ref, declaration_ref_eq } +import std.content_hash { as_content_hash_structural, content_hash_atom } +import product.fabric.identity { FabricIdentity, DemandKey, WorkKey, OfferKey } +import product.fabric.provider_route { + ProviderRoute, CompliancePostureRevision, ProviderRouteFacts, + ProviderDataPathClosure, ProviderPathStanding, ProviderPathLocated, ProviderPathAbsent, + ProviderPathUnread, DownstreamProviderPopulation, NoDownstreamProviders, + ProviderRegionObservation, ProviderRegionRead, + ProviderRouteObserved, ProviderRouteRegionUnobserved, + PermittedJurisdictionsEnumerated, +} +import product.fabric.provider_admission { + RouteScopeSanction, ProviderUseScope, ProviderUseAdmission, + ProviderUseAdmitted, ProviderUseDenied, ProviderUseRefusal, + ProviderRouteUnclassified, ProviderRouteFactsIncomplete, DownstreamProviderUnassessed, + PostureRevisionStale, CustomerScopeUnsupported, DataHandlingUnsupported, + RequiredAgreementAuthorityAbsent, ProhibitedUseNotCleared, SanctionsNotCleared, ExportNotCleared, + PostureJurisdictionsUnread, TransferOrLocationUnresolved, ProviderAccessPathUnsupported, + DispositionCleared, + admit_provider_use, +} +import product.supplier.cloudflare_r2 { + cloudflare_r2_route, + cloudflare_r2_durable_origin_route_standing, + cloudflare_r2_route_facts_population, + cloudflare_r2_data_paths, + cloudflare_r2_facts, +} + +data r2_witness_customer_profile: NonEmptyStr = "r2-witness-customer-profile" +data r2_witness_data_handling_profile: NonEmptyStr = "r2-witness-data-handling-profile" +data r2_witness_agreement: NonEmptyStr = "r2-witness-agreement" +data r2_witness_posture_authority: NonEmptyStr = "r2-witness-posture-authority" +data r2_witness_decision_receipt: NonEmptyStr = "r2-witness-decision-receipt" +data r2_witness_prohibited_use_cleared: NonEmptyStr = "r2-witness-prohibited-use-cleared" +data r2_witness_sanctions_cleared: NonEmptyStr = "r2-witness-sanctions-cleared" +data r2_witness_export_cleared: NonEmptyStr = "r2-witness-export-cleared" +data r2_witness_resolved_operator: NonEmptyStr = "r2-witness-resolved-operator" +data r2_witness_resolved_jurisdiction: NonEmptyStr = "r2-witness-resolved-jurisdiction" +data r2_witness_resolved_evidence: NonEmptyStr = "r2-witness-resolved-evidence" +data r2_witness_no_downstream: NonEmptyStr = "r2-witness-no-downstream" +data r2_witness_synthetic_region: NonEmptyStr = "r2-witness-synthetic-region" + +fn t_resolved() -> ProviderPathStanding { + ProviderPathLocated { + operator: decl_ref(module_path: "test.claim.supplier.cloudflare_r2_route_witness", decl_name: "r2_witness_resolved_operator"), + jurisdiction: decl_ref(module_path: "test.claim.supplier.cloudflare_r2_route_witness", decl_name: "r2_witness_resolved_jurisdiction"), + evidence: decl_ref(module_path: "test.claim.supplier.cloudflare_r2_route_witness", decl_name: "r2_witness_resolved_evidence"), + } +} + +fn t_posture() -> CompliancePostureRevision { + CompliancePostureRevision { + authority: decl_ref(module_path: "test.claim.supplier.cloudflare_r2_route_witness", decl_name: "r2_witness_posture_authority"), + revision: as_content_hash_structural(structural: content_hash_atom(value: "r2-witness-posture-r1" as NonEmptyStr)), + permitted_jurisdictions: PermittedJurisdictionsEnumerated { + first: decl_ref(module_path: "test.claim.supplier.cloudflare_r2_route_witness", decl_name: "r2_witness_resolved_jurisdiction"), + further: [], + }, + jurisdiction_drop_enrollments: [], + } +} + +fn t_customer_profile() -> DeclarationRef { + decl_ref(module_path: "test.claim.supplier.cloudflare_r2_route_witness", decl_name: "r2_witness_customer_profile") +} + +fn t_data_handling_profile() -> DeclarationRef { + decl_ref(module_path: "test.claim.supplier.cloudflare_r2_route_witness", decl_name: "r2_witness_data_handling_profile") +} + +fn t_agreement() -> DeclarationRef { + decl_ref(module_path: "test.claim.supplier.cloudflare_r2_route_witness", decl_name: "r2_witness_agreement") +} + +// THE DISCRIMINATOR ROUTE IS MINTED ONLY IN THE READ ARM, SAME CONSTRUCTION AS PRODUCTION. +// It is not gunbai-fabric-origin: that standing is Unobserved, so no origin route exists to +// admit. The pair below asks whether admit_provider_use still refuses an unread path and +// admits once that path is resolved, on a route the coproduct is allowed to mint. +fn t_read_region() -> ProviderRegionObservation { + ProviderRegionRead { + region: decl_ref(module_path: "test.claim.supplier.cloudflare_r2_route_witness", decl_name: "r2_witness_synthetic_region"), + } +} + +fn t_sanction(route: ProviderRoute) -> RouteScopeSanction { + RouteScopeSanction { + route: route, + posture: t_posture(), + customer_profile: t_customer_profile(), + data_handling_profile: t_data_handling_profile(), + requires_agreement: t_agreement(), + } +} + +fn t_roster(route: ProviderRoute) -> List { + [t_sanction(route: route)] +} + +fn t_scope() -> ProviderUseScope { + ProviderUseScope { + demand: FabricIdentity { principal: "gunbc" as NonEmptyStr, key: "r2-witness-demand-1" as DemandKey }, + work: FabricIdentity { principal: "gunbc" as NonEmptyStr, key: "r2-witness-work-1" as WorkKey }, + customer_profile: t_customer_profile(), + data_handling_profile: t_data_handling_profile(), + agreement: t_agreement(), + prohibited_use_disposition: DispositionCleared { + evidence: decl_ref(module_path: "test.claim.supplier.cloudflare_r2_route_witness", decl_name: "r2_witness_prohibited_use_cleared"), + }, + sanctions_disposition: DispositionCleared { + evidence: decl_ref(module_path: "test.claim.supplier.cloudflare_r2_route_witness", decl_name: "r2_witness_sanctions_cleared"), + }, + export_disposition: DispositionCleared { + evidence: decl_ref(module_path: "test.claim.supplier.cloudflare_r2_route_witness", decl_name: "r2_witness_export_cleared"), + }, + } +} + +fn t_offer() -> FabricIdentity { + FabricIdentity { principal: "gunbc" as NonEmptyStr, key: "r2-witness-offer-1" as OfferKey } +} + +fn t_decide(route: ProviderRoute, facts: ProviderRouteFacts) -> ProviderUseAdmission { + admit_provider_use( + roster: t_roster(route: route), + facts: facts, + active: t_posture(), + scope: t_scope(), + offer: t_offer(), + decision_receipt: decl_ref(module_path: "test.claim.supplier.cloudflare_r2_route_witness", decl_name: "r2_witness_decision_receipt"), + ) +} + +fn t_refusal_tag(c: ProviderUseRefusal) -> String { + match c { + ProviderRouteUnclassified { route } => "route-unclassified", + ProviderRouteFactsIncomplete { route, obligation } => "facts-incomplete", + DownstreamProviderUnassessed { obligation } => "downstream-unassessed", + PostureJurisdictionsUnread { obligation } => "posture-jurisdictions-unread", + TransferOrLocationUnresolved { route, jurisdiction } => "transfer-or-location-unresolved", + ProviderAccessPathUnsupported { route, operator, jurisdiction } => "provider-access-path-unsupported", + PostureRevisionStale { evaluated, active } => "posture-stale", + CustomerScopeUnsupported { cause } => "customer-unsupported", + DataHandlingUnsupported { cause } => "data-handling-unsupported", + RequiredAgreementAuthorityAbsent { accepted } => "agreement-absent", + ProhibitedUseNotCleared { obligation } => "prohibited-use-not-cleared", + SanctionsNotCleared { obligation } => "sanctions-not-cleared", + ExportNotCleared { obligation } => "export-not-cleared", + } +} + +fn t_refusal_located(c: ProviderUseRefusal) -> List { + match c { + ProviderRouteUnclassified { route } => [], + ProviderRouteFactsIncomplete { route, obligation } => [obligation], + DownstreamProviderUnassessed { obligation } => [obligation], + PostureJurisdictionsUnread { obligation } => [obligation], + TransferOrLocationUnresolved { route, jurisdiction } => [jurisdiction], + ProviderAccessPathUnsupported { route, operator, jurisdiction } => [operator, jurisdiction], + PostureRevisionStale { evaluated, active } => [], + CustomerScopeUnsupported { cause } => [cause], + DataHandlingUnsupported { cause } => [cause], + RequiredAgreementAuthorityAbsent { accepted } => accepted, + ProhibitedUseNotCleared { obligation } => [obligation], + SanctionsNotCleared { obligation } => [obligation], + ExportNotCleared { obligation } => [obligation], + } +} + +fn t_denied_with(a: ProviderUseAdmission, tag: String, located: DeclarationRef) -> Bool { + match a { + ProviderUseAdmitted { permit } => false, + ProviderUseDenied { decision, cause } => + t_refusal_tag(c: cause) == tag + && count(filter(t_refusal_located(c: cause), r => declaration_ref_eq(a: r, b: located))) == 1, + } +} + +test fn the_durable_origin_has_no_admissible_facts() -> Bool { + match cloudflare_r2_durable_origin_route_standing() { + ProviderRouteObserved { route } => false, + ProviderRouteRegionUnobserved { obligation } => declaration_ref_eq( + a: obligation, + b: decl_ref( + module_path: "product.supplier.cloudflare_r2", + decl_name: "cloudflare_r2_region_unread_obligation", + ), + ) + && count(cloudflare_r2_route_facts_population()) == 0, + } +} + +test fn the_durable_storage_path_is_unread_with_the_location_obligation() -> Bool { + match cloudflare_r2_data_paths().durable_storage { + ProviderPathLocated { operator, jurisdiction, evidence } => false, + ProviderPathAbsent { evidence } => false, + ProviderPathUnread { obligation } => declaration_ref_eq( + a: obligation, + b: decl_ref( + module_path: "product.supplier.cloudflare_r2", + decl_name: "cloudflare_r2_durable_storage_location_obligation", + ), + ), + } +} + +test fn every_production_path_is_unread() -> Bool { + let c = cloudflare_r2_data_paths() + let paths = [ + c.execution, c.durable_storage, c.backups, c.logs, c.telemetry, + c.control_plane, c.support_access, c.administrative_access, c.spill, + ] + count(filter(paths, p => match p { + ProviderPathUnread { obligation } => true, + ProviderPathLocated { operator, jurisdiction, evidence } => false, + ProviderPathAbsent { evidence } => false, + })) == 9 +} + +fn t_paths_with_durable_storage(storage: ProviderPathStanding) -> ProviderDataPathClosure { + ProviderDataPathClosure { + execution: t_resolved(), + durable_storage: storage, + backups: t_resolved(), + logs: t_resolved(), + telemetry: t_resolved(), + control_plane: t_resolved(), + support_access: t_resolved(), + administrative_access: t_resolved(), + spill: t_resolved(), + } +} + +fn t_synthetic_downstream() -> DownstreamProviderPopulation { + NoDownstreamProviders { + evidence: decl_ref(module_path: "test.claim.supplier.cloudflare_r2_route_witness", decl_name: "r2_witness_no_downstream"), + } +} + +fn t_facts_with_durable_storage(route: ProviderRoute, storage: ProviderPathStanding) -> ProviderRouteFacts { + ProviderRouteFacts { + route: route, + contract_terms: decl_ref(module_path: "extdeps.vendor.cloudflare", decl_name: "cloudflare_customer_dpa_reading"), + data_paths: t_paths_with_durable_storage(storage: storage), + downstream: t_synthetic_downstream(), + observed_at: "2026-09-12T00:00:00Z", + facts_revision: as_content_hash_structural(structural: content_hash_atom(value: "r2-witness-discriminator" as NonEmptyStr)), + } +} + +test fn one_unread_durable_storage_path_refuses_with_that_paths_obligation() -> Bool { + match cloudflare_r2_route(region: t_read_region()) { + ProviderRouteRegionUnobserved { obligation } => false, + ProviderRouteObserved { route } => t_denied_with( + a: t_decide( + route: route, + facts: t_facts_with_durable_storage(route: route, storage: ProviderPathUnread { + obligation: decl_ref(module_path: "product.supplier.cloudflare_r2", decl_name: "cloudflare_r2_durable_storage_location_obligation"), + }), + ), + tag: "facts-incomplete", + located: decl_ref(module_path: "product.supplier.cloudflare_r2", decl_name: "cloudflare_r2_durable_storage_location_obligation"), + ), + } +} + +test fn a_read_region_route_admits_once_that_path_is_resolved() -> Bool { + match cloudflare_r2_route(region: t_read_region()) { + ProviderRouteRegionUnobserved { obligation } => false, + ProviderRouteObserved { route } => match t_decide( + route: route, + facts: t_facts_with_durable_storage(route: route, storage: t_resolved()), + ) { + ProviderUseDenied { decision, cause } => false, + ProviderUseAdmitted { permit } => + declaration_ref_eq( + a: permit.route.provider, + b: decl_ref(module_path: "extdeps.vendor.cloudflare", decl_name: "cloudflare"), + ) + && declaration_ref_eq( + a: permit.route.service, + b: decl_ref(module_path: "extdeps.cloudflare.r2", decl_name: "R2S3Endpoint"), + ) + && declaration_ref_eq( + a: permit.route.region, + b: decl_ref(module_path: "test.claim.supplier.cloudflare_r2_route_witness", decl_name: "r2_witness_synthetic_region"), + ) + && declaration_ref_eq( + a: permit.evidence.customer_profile, + b: t_customer_profile(), + ), + }, + } +} + +test fn production_unread_paths_on_a_read_region_route_still_refuse() -> Bool { + match cloudflare_r2_route(region: t_read_region()) { + ProviderRouteRegionUnobserved { obligation } => false, + ProviderRouteObserved { route } => t_denied_with( + a: t_decide(route: route, facts: cloudflare_r2_facts(route: route)), + tag: "downstream-unassessed", + located: decl_ref(module_path: "product.supplier.cloudflare_r2", decl_name: "cloudflare_r2_downstream_obligation"), + ), + } +}