Last verified: 28 September 2026
Data-Space Federation
A data space lives in one environment on one deployment. When a grant must reach a grantee on another deployment, the substrate honours it by snapshot-push — NOT by reaching across the boundary at read time. The donor issues a signed, filter-scoped grant-snapshot manifest; the operator transports the bytes out of band; the recipient verifies the signature, admits the donor key as a retired trust anchor, and ingests into a read-only mirror data space where reads resolve through local RLS. This rides the §ZB backup + §ZC fork-handoff signed-bundle wire family (JCS + Ed25519); it introduces no new architectural concept.
Why snapshot-push
UIC-P6a (V009/V012) enforces data_space_grants at query time within a single environment, and the RESTRICTIVE *_environment_match overlay deliberately blocks any grant that reaches across an environment or deployment boundary. B3 (§ZCR) honours a grant from a data space in deployment D1 to a grantee operating in deployment D2 by snapshot-push: copying a verified, signed, point-in-time corpus into a local read-only mirror, rather than proxying a live read across the boundary.
Live-proxied read (Shape B) is rejected. An outbound content request at query time is impossible against an air-gapped donor and a phone-home smell on the recipient (Rule 20 / §CC sovereign no-phone-home), and it injects cross-deployment latency + partial-failure into what is today a pure local RLS read path. Snapshot-push moves bytes operator-to-operator, out of band — the same posture §ZB backup and §ZC fork already take ("substrate signs digests; operator stores bytes", H17). By copying rather than proxying, B3 never has to weaken the environment overlay and every read stays local.
Envelopes-only (Shape C) is insufficient on its own — a notification cannot deliver a corpus — but it is folded in as the optional control plane (offer / accept / revoke notifications; see below).
Data plane — the signed grant-snapshot
The data plane reuses the §ZB/§ZC JCS+Ed25519 envelope family verbatim (cross-reference: /trust/backup-restore · /trust/right-to-fork). The donor signs the manifest with the cluster backup_bundle_signing key (no new key purpose); the operator stores the actual snapshot bytes in operator-controlled object storage (S3 / GCS / Azure Blob / on-prem MinIO / local FS for air-gap). Wire format: JCS-canonical JSON payload → SHA-256 → Ed25519 sign → base64url signature. The substrate never stores, proxies, or transports raw corpus bytes — it persists only the manifest JCS, the signature, the storage_uri, and the storage_content_sha256.
Closed 1-value DataSpaceGrantSnapshotKind — "data-space-grant-snapshot-manifest", disjoint from BackupBundleKind (§ZB), ForkHandoffEnvelope.bundle_kind (§ZC), and the §CC BundleKind per the H2 / F1 Option-C precedent. It ships a dedicated verifier and never calls the generic §CC verifyBundle().
Snapshot kinds
Generated from lib/registry/data-space-grant-snapshot-kinds-registry.ts · 1 closed kind(s) (adding a 2nd kind requires a §ZCR amendment + coordinator gate — mirrors the §ZB H2 / §ZC F12 closed-enum cadence)
data-space-grant-snapshot-manifest — Data-Space Grant Snapshot Manifest
Substrate-attested, filter-scoped, point-in-time export of a data space's governed node corpus (and, per operator decision B3.2b, optionally the raw org_files bytes), destined for a read-only mirror data space on a recipient deployment. The snapshot row-set is computed with the SAME pure RLS matcher (_data_space_filter_matches) the V012 grant predicate uses, so the snapshot scope EQUALS the grant scope by construction (no widening is possible). The substrate signs the corpus + storage digests; the operator stores the actual bytes in operator-controlled object storage (H17). Verification: download bytes from storage_uri, recompute SHA-256, verify the manifest Ed25519 signature against the admitted donor signing key. Re-sync issues a new snapshot with an incremented snapshot_version linked via prior_snapshot_id; Citation Freshness (CF-1/2/3) marks dependent mirror citations stale.
default retention: medium · since: ZCR-1
Invariant §11.1 — snapshot scope equals grant scope
The single most important invariant: the snapshot scope is the grant scope — no widening is structurally possible. The donor computes the snapshot row-set with the same pure RLS matcher — _data_space_filter_matches — that the V012 grant predicate uses to enforce reads in-deployment. Because the export replays the exact filter predicate the RLS floor uses, the snapshot can never contain a node the grant does not admit. The grant_filter (the closed UIC-B1 grammar — nodeTier / labelPrefix / metadata, AND-combined) is carried verbatim in the manifest. This invariant was proven before any UX was built, via a live-PG integration test (a §11 rejection criterion — the feature is unsafe if scope-equality wobbles).
Invariant §11.2 — read-only mirror
The recipient ingests the verified snapshot into a read-only mirror data space — a new spaces row flagged as a federated-snapshot origin. Mirror nodes are ingested lifecycle_state='committed' with a federated provenance stamp; the mirror is non-editable (no staging, no commit, no relation-suggest). This is enforced at the RLS layer, not just the service layer: the V015 _is_federated_mirror_space helper backs RESTRICTIVE write-deny policies so a mirror data space is genuinely write-denied to authenticated users — mirroring how §ZC fork-imported trust anchors are status='retired' (verification-only, never active). Corrections come only via a donor re-sync, never via local edits. RLS-layer enforceability was proven by a live-PG integration test (the second §11 rejection criterion).
Because the data now lives locally in the recipient's environment, reads on the mirror resolve through the unchanged V009/V012 local RLS — the grantee org's membership + the mirror space → normal in-deployment grant enforcement. No *_environment_match relaxation is needed. This is the elegant part: by copying rather than proxying, B3 never weakens the environment overlay.
Admission ceremony
Recipient admission is a 2-of-2 distinct-actor ceremony mirroring the §ZB backup-verify + §ZC fork-ratify pattern. The custody-operator and the resolution-operator must co-sign, and the requester participant ID must differ from the cosigner participant ID (C-EE-PRE-7 distinct-actor rejection). Admission downloads the bytes from storage_uri, recomputes the SHA-256 against storage_content_sha256, and verifies the manifest Ed25519 signature against the admitted donor key before creating the mirror.
Issuance (donor side) — issueDataSpaceGrantSnapshot() (ecosystem.custody.grant_snapshot_issued): recompute the grant's admitted node/relation set with the V012 filter predicate, canonicalise, derive corpus_digest, build + sign the manifest, persist the data_space_grant_snapshots row, emit an attestation-backed audit trail + typed event.
Admission (recipient side) — admitDataSpaceGrantSnapshot() (ecosystem.custody.grant_snapshot_admitted + ecosystem.resolution.grant_snapshot_ratified): verify bytes + signature, admit the donor key, create the read-only mirror, ingest nodes/relations (re-embed locally if the embedding profile differs — honest degradation, P8.1/P8.2).
Donor trust-anchor admission — ecosystem.custody.grant_snapshot_trust_anchor_admitted: the donor's public signing key is registered on the recipient with provenance='fork-imported-trust-anchor' + status='retired' (the §ZC pattern), so the recipient can verify the next re-sync without a new key exchange. Imported anchors are verification-only — never used for active signing.
Raw files + Citation Freshness
Raw original files (B3.2b): per the operator's v1 scope decision, the snapshot federates not only the governed node corpus (the AI-readable layer) but also — optionally — the raw org_files bytes the nodes derive from. The files ride the same signs-digests / operator-stores-bytes posture: the manifest carries the file digests, the operator transports the bytes, the recipient verifies and stores them against the mirror.
Citation Freshness across the boundary (B3.3): a re-sync (resyncDataSpaceGrantSnapshot()) issues a new snapshot with an incremented snapshot_version linked via prior_snapshot_id, and flips the affected mirror nodes' versions. The existing Citation Freshness resolver (CF-1/2/3) then marks dependent mirror citations stale — the exact staleness primitive already shipped in-deployment, now spanning deployments. No new freshness machinery is required.
Control plane — notification events
The control plane is the Rule 15 federation CloudEvents path, and it carries notifications, never corpora. Three closed, schema-validated, notification-only event types let a recipient learn a grant was offered / accepted / revoked and trigger the operator to pull (or tear down) a snapshot:
· dev.sovern.federation.dataspace.grant.offered.v1 (donor → recipient)
· dev.sovern.federation.dataspace.grant.accepted.v1 (recipient → donor)
· dev.sovern.federation.dataspace.grant.revoked.v1 (donor → recipient)
These are small notifications (grant id, data-space slug, filter summary, donor cluster) — no corpus. The control plane is a UX/automation convenience layered on top of the data plane, not a correctness dependency: snapshot-push works with a fully manual operator handoff (exactly like §ZC fork today). The consumer is inform-only.
Sovereignty & revocation
Both sides work air-gapped: issuance is purely local (compute digests, sign, write bytes to operator storage) and admission is purely local (verify signature, ingest). Neither side calls the other at read time, so guard:no-phone-home-in-sovereign-modes stays green by construction (cross-reference: /trust/right-to-fork).
Revocation is honest about its limit. A donor revoking a grant issues a revocation (control-plane event when connected, or an out-of-band signed revocation when air-gapped); the recipient tears down the mirror, with an audit trail. But because the mirror is a copy, truly un-sharing already-delivered bytes across a sovereign boundary is impossible — identical to the §ZC fork reality and to physical reality: you cannot recall a copy you handed someone. The mirror teardown + audit trail is the enforceable part.
Coordination roles
(cross-reference: /trust/coordination-roles)
The grant-federation ceremony involves two §Y coordination roles. These rows are generated from the closed 16-role ECOSYSTEM_COORDINATION_ROLES registry — the §ZCR capability keys are substrate-natural additive extensions; the closed 16-role canon is untouched.
custody-operator — Custody Operator
Holds substrate signing keys (cluster signing keys per B.sub1; signed-bundle keys per §CC). Issues key rotations + signed-bundle ceremonies. Substantively distinct from Deployment Operator: Custody Operator SIGNS bundles, Deployment Operator APPLIES bundles. Per C-Y-3, UU-ii retargets release-bundle.service.ts SIGNING call-sites to this role.
Grant-federation capabilities: ecosystem.custody.grant_snapshot_issued (donor issuance) · ecosystem.custody.grant_snapshot_admitted (recipient admission) · ecosystem.custody.grant_snapshot_trust_anchor_admitted (donor signing-key admission)
since: Y-1
resolution-operator — Resolution Operator
Substrate-attested dispute-resolution authority. Issues substrate-attested rulings on disputes that cannot be resolved at the participant or org level. Independence requirement: cannot be a party-of-interest to a dispute being resolved.
Grant-federation capability: ecosystem.resolution.grant_snapshot_ratified (2-of-2 admission co-sign)
since: Y-1
Related substrate trust pages: /trust/data-spaces (§SS data-space governed-knowledge discipline) · /trust/right-to-fork + /trust/backup-restore (the shared JCS+Ed25519 signed-bundle wire family)
Registry sources: lib/registry/data-space-grant-snapshot-kinds-registry.ts (1 kind) · lib/registry/ecosystem-coordination-roles-registry.ts (ECOSYSTEM_COORDINATION_ROLES — custody + resolution role rows)
C-GG-23 trust-page-no-i18n — inline English literals · CONTRACT §ZCR · AGENTS.md Rule 30
guard:grant-snapshot-manifest-shape (BLOCKING) · guard:trust-data-space-federation-page-matches-registry (BLOCKING)