**0024 accepted.** Model access was decided, built, and proven in the lab, and two design documents rest on it; only the status had never moved. The gate is green again. **The work breakdown rewritten.** It planned a decomposition of the existing system in place — extract contexts, declared features, shrink the shared library. That is not the work. A replacement is being built beside it, and only the old Phase 0 survived contact with reality, so the one document meant to say what happens next was describing a system being retired. Now ordered by what "modules move across one at a time until the old registry is off" actually requires: - Phase 0 is marked done against the twenty-two lab assertions, **and carries its own limitation**: every module exercised was written to test the mechanism, so the vocabulary was shaped by its own fixtures. - Phase 1 is the vocabulary gaps found by asking what real modules need — an object-store provision, a session as a licence consumer, a network shape with ordering, public certificate issuance. - Phase 2 is one module, then a week of running it, because the point of going first is to find what Phase 1 missed. - Phase 3 picks modules that each prove something the first did not; the mail system is last because it is the one that may send work back into the declaration language. - Phase 4 is switching the registry off, named as a phase so it is not mistaken for the goal. Keeps the rules of engagement unchanged — they were about how work is done, not what it is — with one addition: stop and ask before anything that touches a machine outside the lab. Adds a section on keeping the list true, since the document it replaces was wrong for weeks and nothing said so. A claim here is counted, not reasoned, and a phase is done when the lab says so.
96 lines
5.1 KiB
Markdown
96 lines
5.1 KiB
Markdown
---
|
|
topic: what runs on it
|
|
status: accepted
|
|
date: 2026-08-30
|
|
deciders: jochen
|
|
reconstructed: false
|
|
---
|
|
|
|
# 24. Model access is a provision, and a licence is a thing with a name
|
|
|
|
## Context
|
|
|
|
Everything in this mesh that thinks needs a model, and there is more than one way to reach one:
|
|
|
|
| | |
|
|
|---|---|
|
|
| **hosted services** | several vendors, each with its own account, quota and key |
|
|
| **models the mesh runs itself** | open-weight models on a node with the hardware for them |
|
|
|
|
And the choice is **per consumer, deliberately**: a workstation's own session on one account, a
|
|
laptop on the organisation's, two hired workers on the mesh's local model because their work does
|
|
not justify paid tokens. Those are three different answers to one requirement, held at once, in
|
|
one mesh.
|
|
|
|
**The existing system has the hard half of this already** — automatic licence refresh and
|
|
switching between accounts when one is exhausted — and it works. It is not being replaced because
|
|
it was wrong; it is being rebuilt because it lives in a place that cannot express the rest.
|
|
|
|
## Decision
|
|
|
|
**Model access is a provision.** A module that needs to think declares `requires: model-access`;
|
|
anthropic, openai, grok and a locally-run model are four modules that provide it. That is
|
|
[ADR 0009](0009-modules-and-the-graph.md)'s mechanism unchanged, and it buys the things that
|
|
mechanism already buys: several implementations of one job, a refusal when more than one could
|
|
answer, and choosing by assigning the one you want.
|
|
|
|
**A locally-run model needs nothing new at all.** It is a mesh-scoped provision on the node with
|
|
the hardware — the same shape as a database, including the credential.
|
|
|
|
### A licence is a named thing, and the name is the operator's
|
|
|
|
Not an anonymous credential hanging off a provider. *The personal account*, *the organisation's
|
|
account* — those are names a person uses, and the mesh has to use them too, because the whole
|
|
point is saying **which one** a given consumer uses.
|
|
|
|
**Many to many.** One provider has several licences; one licence serves several consumers. So it
|
|
is **not a claim** — claims are for things only one holder may have, and two machines sharing an
|
|
account is the ordinary case rather than a collision.
|
|
|
|
### Four things this needs that the mesh does not have
|
|
|
|
Written as gaps rather than as design, because each is a real piece of work and pretending
|
|
otherwise is how a plan becomes a surprise.
|
|
|
|
**1. A provider that is not on a node.** A mesh-scoped provision today is answered by *the machine
|
|
running it*, and the reachability rule refuses two ends that share no private network. A hosted
|
|
service is on nobody's machine and is reached over the public internet. That is a third scope —
|
|
answered by a record rather than by a node — and the reachability rule must not apply to it.
|
|
|
|
**2. A secret the mesh is given rather than one it mints.** Every credential the mesh handles
|
|
today it generated itself, sealed to both ends, and discarded. An API key arrives from a person.
|
|
The missing verb is *accept*: take a value, seal it to each holder, and **discard the plaintext**
|
|
— because a mesh that keeps operator-supplied keys readably is the arrangement this project
|
|
[measured and rejected](0009-modules-and-the-graph.md).
|
|
|
|
**3. A consumer that is not a machine.** *This worker uses that licence* is a binding to an agent,
|
|
not to a node. [ADR 0001](0001-mesh-brokers-nodes-host-agents-think.md) already says an agent
|
|
holds credentials and that delivery follows its node bindings and modality — so what is delivered
|
|
still lands on a machine, and what is **chosen** is chosen per agent. The provisions model has no
|
|
consumer identity other than a node.
|
|
|
|
**4. Switching is a reaction, not a declaration.** Everything here is desired state, reconciled by
|
|
comparison. A licence that hits its limit and must be swapped is a response to something observed,
|
|
and it cannot be expressed as a declaration without the declaration meaning *whatever is working
|
|
right now* — which is not a thing anybody declared. **It belongs with observability, changing a
|
|
binding**, and the binding is then declared as usual. Saying this plainly is what stops the
|
|
declaration language growing a conditional.
|
|
|
|
## Consequences
|
|
|
|
- **The refusing rule applies here and will be felt.** A mesh holding three ways to reach a model
|
|
refuses every consumer that has not said which — which is correct and is a great deal of
|
|
saying-which the first time. The remedy is one assignment per consumer, and the message names
|
|
the candidates.
|
|
- **A licence outliving its holder is a live credential nobody is watching.** The same rule the
|
|
provisioner follows applies: what the mesh granted and no longer grants is withdrawn.
|
|
- **Nothing here makes a node authenticate to a model provider.** ADR 0001 holds: an agent does.
|
|
What changes is that the mesh can now say *which agent, which licence, which node it lands on*,
|
|
which is the fact ADR 0001 records as missing.
|
|
|
|
## References
|
|
|
|
- [ADR 0009](0009-modules-and-the-graph.md) — provisions, scope, choosing, and sealed credentials
|
|
- [ADR 0001](0001-mesh-brokers-nodes-host-agents-think.md) — agents hold credentials, not nodes;
|
|
`hal/ai` as the context owning provider grants and rotation
|