Model access is vendor-agnostic: rename provider→vendor, add adapter seam (Phase A)

ADR 0050 Phase A. Rename the licence's `provider` field to `vendor` — the
inventory already uses "provider" for which node answers a brokered provision,
and one word must not carry two facts — and route the licence layer's sealing
and delivery through a per-vendor adapter selected by that field.

The rename touches the Go struct/params/SQL in internal/licences, the operator
CLI, and the schema: 0001 (the consolidated schema) now creates the column as
`vendor`; a new guarded 0002 renames it on a database that predates the change,
and is a no-op on a fresh one.

The adapter (internal/licences/adapters) has a `shape` and the two verbs a
static-key vendor needs — accept (the generic anonymous-box seal) and deliver
(the sealed blob unchanged). refresh/identity/usage are named as optional
capability interfaces so the refreshable-grant seam exists before its code.
A registry maps vendor→shape (anthropic→static-key for now, with a Phase-B
TODO to swap it to refreshable-grant); an unknown vendor is refused clearly.

Behaviour is unchanged from the operator's view except the field name.

Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
This commit is contained in:
2026-09-06 23:49:12 +02:00
parent 671fb4f8f3
commit ddb41baaf4
6 changed files with 245 additions and 25 deletions
+2 -2
View File
@@ -173,11 +173,11 @@ func TestUsingALicenceThatDoesNotExistIsRefused(t *testing.T) {
// apart without a schema knowing anything about sessions.
func TestTwoSessionsOnOneMachineHoldDifferentLicences(t *testing.T) {
held, ctx := fresh(t)
for _, l := range []struct{ name, provider string }{
for _, l := range []struct{ name, vendor string }{
{"personal", "anthropic"},
{"company", "anthropic"},
} {
if err := held.Add(ctx, l.name, l.provider, map[string]any{"model": "a-model"}); err != nil {
if err := held.Add(ctx, l.name, l.vendor, map[string]any{"model": "a-model"}); err != nil {
t.Fatal(err)
}
}