Bitspark constellation
accepted source ↗

ADR 0021 — adstrate access is space-governed: reach the payload only through its spaced binding

  • Status: accepted
  • Date: 2026-06-14
  • Builds on: 0017 (the adstrate — interface in facts, payload off-record), 0018 (the adstrate layer)
  • Relates: 0013 (federation as the leading open outsider — the property this protects), 0016 (the CAS port whose read model this fixes), theory/0001 (late-bound use; the search/check split)

An adstrate payload is reached only through its space-scoped binding fact — never around it. The bytes (or state, or stream) are off-record and placeless; the binding that names them is an ordinary fact, and facts live in spaces. So access is keyed on (space, identity), resolved by projection (the binding must be visible at that space or an ancestor) and gated by the same projection's grants. This dissolves the one asymmetry in the substrate — a placeless global store that opted out of the space model — and it is what makes adstrate content delegable and federable like everything else. The bare content identity (a hash) still names what the payload is; (space, identity) is the capability to reach it.

Context

0017 defined an adstrate as "interface in facts, payload off-record." The first implementation (corpus, the content adstrate, ported from arche/services/cas per 0016) inherited arche's read model: a blob was addressed by its bare content hash, and the store had to rediscover which space(s) bound it (a subtree-scoped scan over discovery roots) before it could check entitlement. That bare-hash access is the only place in the constellation where a protected payload is reached without going through a space — and it costs the substrate two load-bearing properties:

  • Conceptual. Everything in the substrate is placed in a space, and placement carries scope (authority and visibility project downward). A placeless global store is the lone exception, and it had to bolt on its own discovery + entitlement machinery instead of riding the normal projection/grant path. The asymmetry had no good justification — and a symptom showed it: the read key wanted to carry the space, and arche threw it away then scanned to get it back.
  • Practical (distribution). The space model exists for delegation and federation — authority flows downward, a root delegates a subtree, roots map authority to one another (0013's federation outsider, the leading open question for "global"). A single global flat store breaks every step: it has no root, cannot be partitioned along space lines, a delegate of /team-a cannot host the content its facts reference, and two polities cannot federate a store that belongs to neither. The whole no-central-authority thesis quietly caps at the CAS.

The binding was already a space-scoped fact (corpus's content(…) is asserted at a space). The fix is not to add scoping — it is to stop discarding it at read time.

Decision

1. Two layers, kept distinct.

  • The payload (corpus bytes, tabula state, cursus stream) is off-record, content/identity- addressed, and placeless — and should be: that is what gives dedup, integrity, and location-independence. The payload is raw matter, below the space model.
  • The binding (corpus.v0.content, tabula.v0.cell, cursus.v0.channel, …) is an ordinary fact, asserted at a space — its home. Naming, authority, and visibility live here.

2. Reach the payload only through its spaced binding — never around it. There is no bare-payload access path. This is not a new rule; it is 0017's "access goes through the fact interface" taken literally. A direct content-hash GET (arche's model) goes around the interface and is therefore disallowed.

3. Access is keyed on (space, identity). To reach a payload you name the space and the identity (e.g. the content digest). Resolution is projection: the binding must be visible in that space's projection — placed at the space or an ancestor (downward visibility). Authority is checked in the same projection (the reader's grant must be visible there). Existence and entitlement therefore collapse into one authorized projection read: a binding the reader may not see is indistinguishable from one that does not exist (uniform denial; no probing). No discovery scan — the space is given, not rediscovered.

Naming a space you control does not let you reach a payload bound elsewhere: if the binding is not visible in that space's projection, the read finds nothing. Security comes from projection visibility, not from hiding the space from the caller.

4. Identity and access are different, and both are kept.

  • The bare identity (the content hash) names what the payload is. It stays a universal, re-checkable name: a judgment "artifact sha256:X conforms to profile P" cites the bare hash, and anyone holding the bytes re-checks it (the search/check split — identity is checkable without access).
  • (space, identity) is the access capabilitywhere you may reach it. Fetches carry the pair; claims about content carry the bare identity.

5. This is the general adstrate rule, not a corpus special case. Every adstrate's binding is a fact, hence spaced; the same (space, identity) access and projection gate apply to tabula (state) and cursus (flow). corpus is the worked first instance.

6. Distribution is the payoff, and the two properties compose. Bindings distribute exactly like facts (they are facts). The payload, being content/identity-addressed, replicates untrusted — any node may serve it and the recipient re-checks by re-deriving the identity, so byte-serving needs no trust. So content delegates and federates with its space: the owner of a space owns its bindings and hosts (or caches) their payload; a cross-polity reference is (foreign-space, identity), resolved by the same root-to-root authority mapping as any cross-polity fact read. Content-addressing makes the matter freely replicable; space-scoping makes its governance delegable. A flat store had only the first half.

Consequences

  • corpus's read gate simplifies. It is one authorized projection read for the binding + grant (re-checked to root), then serve the verified bytes — the SpacesFor discovery tier of the arche port is dropped. corpus stops being a special case and becomes an ordinary space-projecting stele consumer. (Implemented as corpus slice 2.)
  • References split by purpose. Identity references (claims about content) stay bare-hash; access references (fetches) are (space, digest). Profiles that cite content for retrieval — process.v0 artifacts, a future work.v0 change-subject — carry the pair; profiles that judge content cite the hash. This is a vocabulary convention other profiles adopt.
  • GC reachability stays global even though reads are scoped. Payload bytes may be reclaimed only when no space holds a live binding for that identity — a cross-space reachability question — while each read projects one space. (corpus slice 3.)
  • Global dedup relaxes to locality under distribution. When one identity is bound in spaces owned by different nodes, each node hosts its own copy of the bytes; "store once globally" is a single-node luxury, traded deliberately for self-sufficiency. Truly-global content is bound high (at root or a shared ancestor) so it projects widely — "global" re-enters as a root-placed binding, not a flat namespace.
  • The federation property is preserved rather than capped. This is the load-bearing reason: with adstrate access space-governed, nothing in the substrate sits outside the model that makes it distributable. Recorded against 0013's federation outsider as a constraint any federation design may now assume.
  • No repo or topology change. This refines the adstrate definition; it mints nothing and moves no layer. corpus/tabula/cursus remain draft adstrate members.

The Bitspark constellation — how the systems are built and relate.

GitHub