Graduate issues 067 and 068 — provider scoping and the secrets vault #57

Merged
jschoubben merged 4 commits from multi-node/harden-and-prove into main 2026-09-20 19:30:13 +00:00
Owner

Two design gaps surfaced while proving the data-migration and secret-rotation are trustworthy, opened as issues 067/068 and graduated to decisions and to-be designs per playbook 02.

ADR 0084 — Which provider serves a consumer (extends 0027)

0027 settled a provision's name (the coupling) and left "two providers of one name should both match" as an aside. That aside is the gap: both control-capable nodes already run their own postgres/mssql/redis, and the single identity provider already serves apps on another node, so scope: "mesh" / one mesh-store is false on day one. 0084 decides a provider is a (node, module) pair the consumer selects, defaulting to co-location; data-coupling is named explicitly; genuine ambiguity is refused rather than resolved by picking. Folds in the second axis — a module may carry a private embedded instance (own network, no published port, not a provision) only when a fork or version forces it; share by default.
Design: 03-DESIGN/01-to-be/23-choosing-a-provider.md.

ADR 0085 — A secret is a provision, the vault is the module that provides it (extends 0031)

Store and broker seats were made ordinary modules; secret-minting is still a privileged controller property no module owns. Parallel to 0031 ("identity is a module"), a secret becomes a provision and the vault an ordinary node-scoped module. A module's own local secret becomes an ordinary consumer↔vault pair credential, so it rotates/backs-up/audits through the machinery doc 13 already defines — the local-secret rotation gap closes with no new machinery. The controller's provisioning-credential mint (ADR 0048) is deliberately left unchanged; break-glass-without-a-master-key is left as an open design question. Design: 03-DESIGN/01-to-be/24-the-secrets-vault.md; doc 13 amended to cross-link.

Notes for the reviewer

  • One genuine fork resolved rather than left open: 0085 does not fold the controller's own provisioning mint into the vault — the controller must mint to deliver any provision (the vault's own credential included). This is the place to push back if the intent was fuller subsumption.
  • Issues 067/068 marked resolved with amended-design set.
  • ADRs renumbered 0079/0080 → 0084/0085 after rebasing onto current main (main had taken 0079–0083).
  • Repo checks pass: 00-META/checks/records.py (all checks passed) and index.py (current); all internal links resolve; public-safe (role names only, no domains/nodes/addresses).

https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx

Two design gaps surfaced while proving the data-migration and secret-rotation are trustworthy, opened as issues 067/068 and graduated to decisions and to-be designs per playbook 02. ## ADR 0084 — Which provider serves a consumer (extends 0027) 0027 settled a provision's *name* (the coupling) and left "two providers of one name should both match" as an aside. That aside is the gap: both control-capable nodes already run their own postgres/mssql/redis, and the single identity provider already serves apps on another node, so `scope: "mesh"` / one `mesh-store` is false on day one. 0084 decides a provider is a (node, module) pair the consumer **selects**, defaulting to co-location; data-coupling is named explicitly; genuine ambiguity is refused rather than resolved by picking. Folds in the second axis — a module may carry a private embedded instance (own network, no published port, **not** a provision) only when a fork or version forces it; share by default. Design: `03-DESIGN/01-to-be/23-choosing-a-provider.md`. ## ADR 0085 — A secret is a provision, the vault is the module that provides it (extends 0031) Store and broker seats were made ordinary modules; secret-minting is still a privileged controller property no module owns. Parallel to 0031 ("identity is a module"), a `secret` becomes a provision and the vault an ordinary node-scoped module. A module's own local secret becomes an ordinary consumer↔vault **pair credential**, so it rotates/backs-up/audits through the machinery doc 13 already defines — the local-secret rotation gap closes with no new machinery. The controller's provisioning-credential mint (ADR 0048) is deliberately left unchanged; break-glass-without-a-master-key is left as an open design question. Design: `03-DESIGN/01-to-be/24-the-secrets-vault.md`; doc 13 amended to cross-link. ## Notes for the reviewer - One genuine fork resolved rather than left open: **0085 does not fold the controller's own provisioning mint into the vault** — the controller must mint to deliver any provision (the vault's own credential included). This is the place to push back if the intent was fuller subsumption. - Issues 067/068 marked `resolved` with `amended-design` set. - ADRs renumbered 0079/0080 → 0084/0085 after rebasing onto current main (main had taken 0079–0083). - Repo checks pass: `00-META/checks/records.py` (all checks passed) and `index.py` (current); all internal links resolve; public-safe (role names only, no domains/nodes/addresses). https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
jschoubben added 4 commits 2026-09-20 19:28:12 +00:00
The mesh models provisions as mesh-scoped (one provider of a kind, a single
mesh-store). But node-specific services delivered to the mesh was the plan from
the start: both nodes already run their own postgres, SQL server, redis and
object store, and identity — currently single — already serves apps on a second
node. The model cannot express which provider serves a consumer, so it collapses
a deliberately per-node fleet to one. Provider scoping is a whole-mesh decision
across postgres/s3-bucket/oidc, not an SSO patch.

Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
Naming which provider is only half of how a module gets a database. The other
half: a module may carry its own version/fork-pinned instance, module-network
only, no published port, not a provision — and the model has no word for it.
Add it as a second axis with its own open questions.

Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
Store and broker seats were made ordinary modules; secret-minting is still a
privileged property of the controller that no module owns. Propose the vault
become a module that provides a secret provision (generate/hold/rotate/backup/
audit), node-scoped like every other provider (issue 067), subsuming the three
secret paths and giving local-secret rotation a home.

Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
ADR 0084 (extends 0027) — a provision is served by a node-scoped provider the
consumer selects, defaulting to co-location; a module may instead carry a private
embedded instance that is not a provision. Design: 01-to-be/23-choosing-a-provider.

ADR 0085 (extends 0031) — a secret is a provision and the vault is the module that
provides it; a module's own local secret becomes an ordinary pair credential that
rotates through the existing machinery, while the controller's provisioning-credential
mint (0048) is unchanged. Design: 01-to-be/24-the-secrets-vault; doc 13 amended to
cross-link the non-pair secret.

Issues 067/068 marked resolved with amended-design set. ADR index regenerated;
records and index checks pass.

Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
jschoubben merged commit 731027c009 into main 2026-09-20 19:30:13 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: novox/hq#57