--- status: accepted date: 2026-08-26 deciders: jochen reconstructed: false extends: 0019-modules-and-the-graph.md --- # 20. A context owns its store, exclusively ## Context [ADR 0019](0019-modules-and-the-graph.md) settles what a module declares. This settles what a grant may be, and it is the half that **removes** things. `how-we-build` §4 already says *contexts integrate through the record, never through a shared schema*, and states the cost: several domains share one forty-five-table schema, which is why work belonging to one context keeps having to be implemented in another. That was written as a principle. Counted, it is thirteen foreign tables belonging to three separate contexts, living in the mesh's own registry database. ## Considered options 1. **A schema per consumer inside a shared database.** Namespaced, revocable by dropping the schema, with a cross-context join possible but deliberate. Rejected: it keeps the letter of §4 and leaves the temptation in place, and a boundary that is merely inconvenient to cross gets crossed. 2. **Read-only roles on another context's store.** Rejected for the same reason and one worse: reading another context's tables couples you to its layout exactly as firmly as writing them, and the coupling is invisible until the owner changes a column. 3. **Exclusive ownership.** Chosen. ## Decision > **A context is granted only what it exclusively owns.** No shared writes. No read-only role on another context's store. If you need what another context holds, you ask it or you subscribe to it. **The unit is the context, not the process.** Everything inside a context — its service, its surface, its tools — reads its own store freely. A board showing the mesh's own nodes and modules is the mesh showing its own data, not a boundary crossing. What is forbidden is a *different* context reading it. ### Asking or subscribing is derived, not chosen [ADR 0015](0015-a-node-and-how-it-joins.md) makes disconnection an ordinary situation. So: - **Anything that must keep working while disconnected cannot ask** — there is nobody to ask. It keeps a local copy, which means subscribing. - **Anything where a stale answer is worse than none cannot subscribe.** A display may lag; a decision about whether a grant is still valid may not. Neither is a query against another store, whatever transport it travels over. ## What this removes The first clear list of what the design deletes rather than adds: - **Grant kinds.** There is one: an exclusive resource. No schema grants, no read roles, no rules about who may see what inside a shared thing. - **The question of who owns which table**, and the guessing at revocation time. Removing a consumer drops what it was granted, whole. - **Cross-context migration ordering.** Two contexts migrating one database must be ordered against each other. Exclusive ownership means a context's migrations are ordered only against itself. - **A class of permission modelling** a shared store would otherwise need. ## Consequences - **Cross-context reporting is harder, and that is the point.** Anything wanting to see across contexts consumes their events or calls their interfaces. That is §4's argument, and the cost it names is the one already paid. - **A single surface over several contexts still works** — that is what a surface is. It reads interfaces, not stores. This holds while the contexts sit behind **one** interface; splitting a context into its own deployable costs that, and the composition would have nowhere to live that tier 3 permits. **A real constraint on how far the control plane may be split.** - **Three contexts must move out of the registry database**, taking thirteen tables with them. Their dependency on the registry then shrinks to almost nothing — one of them needs a single table. - **The node appliers were already handled.** [ADR 0016](0016-the-node-host.md) stopped the host querying the mesh database for tier reasons unrelated to this, and it removes most of the remaining direct readers as a side effect. - **What a consumer does about events missed while disconnected is not decided** — replay from a point, ask once and resume, or rebuild. The question every projection has. ## References - [`how-we-build.md`](../00-META/how-we-build.md) §4 — the rule this makes enforceable. - [Research 011](../01-RESEARCH/011-the-module-graph/worked-provider.md) — the count, the worked provider, and the dashboard case. - [ADR 0015](0015-a-node-and-how-it-joins.md) — why asking or subscribing is derived.