Rename mesh-control -> mesh-controller, substrate -> foundation

One name per thing, per the HQ glossary: the module/container/image/binary/repo
becomes mesh-controller, the seat the-controller, and the store+broker pair the
foundation (embedded base bundles, default template and example lock renamed with
their go:embed directives). No behaviour change — a pure vocabulary rename.

Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
This commit is contained in:
2026-09-16 18:40:40 +02:00
parent b520bd1825
commit 41637befff
9 changed files with 34 additions and 34 deletions
+3 -3
View File
@@ -1,9 +1,9 @@
// Reading the manager node's PUBLIC sealing key out of the bound facts the mesh delivers, and
// writing a sealed refresh token in the wire shape mesh-control reads.
// writing a sealed refresh token in the wire shape mesh-controller reads.
//
// **The public key is delivered, not derived.** The manager module holds no node key of its own
// (novox/hq ADR 0050) — it is deliberately never given one. To seal a refresh token to this node it
// needs the node's PUBLIC sealing key, and mesh-control puts that in the manager holder's bound facts
// needs the node's PUBLIC sealing key, and mesh-controller puts that in the manager holder's bound facts
// (`serves.manager_public_key`), safe to disclose because it is public. Both adoption and every
// rotation read it from there.
@@ -23,7 +23,7 @@ export function managerPublicKey(boundFile: string): string {
return key;
}
/** Write a sealed refresh token in the {sealed, manager_key} wire shape mesh-control reads. */
/** Write a sealed refresh token in the {sealed, manager_key} wire shape mesh-controller reads. */
export function writeSealedGrant(path: string, sealed: string, managerKey: string): void {
mkdirSync(dirname(path), { recursive: true });
const tmp = `${path}.tmp`;
+3 -3
View File
@@ -12,13 +12,13 @@
// never the refresh token — which it seals per consumer holder and stores;
// 5. poll usage with the fresh access token and record the licence-grain reading.
//
// mesh-control receives the products of steps 3–4 through `licence submit-refresh` (access token +
// mesh-controller receives the products of steps 3–4 through `licence submit-refresh` (access token +
// sealed box). The refresh token never leaves this process except as ciphertext, and it never had to
// be opened here at all — the host did that.
//
// This runs as `mesh-tools run`, which connects no broker, so the outputs are written to files the
// host mounts; the submit itself (the transport to mesh-control) is done by the caller invoking
// `mesh-control licence submit-refresh`. In the lab that caller is the scenario; in production it is
// host mounts; the submit itself (the transport to mesh-controller) is done by the caller invoking
// `mesh-controller licence submit-refresh`. In the lab that caller is the scenario; in production it is
// an authenticated call the manager node makes. The transport is the one part stubbed here — FLAGGED
// — because a cross-node authenticated command surface is out of this module's scope.
+4 -4
View File
@@ -5,14 +5,14 @@
// carve-out delivers the refresh token to the manager module the way the mesh delivers every other
// credential: sealed to the node's key, and unsealed by the *host* — never by the module. The host
// unseals with Go's `golang.org/x/crypto/nacl/box.OpenAnonymous` (mesh-host
// internal/identity/sealing.go), and mesh-control seals with `box.SealAnonymous`
// (mesh-control internal/secrets/seal.go). Both are NaCl `crypto_box_seal`:
// internal/identity/sealing.go), and mesh-controller seals with `box.SealAnonymous`
// (mesh-controller internal/secrets/seal.go). Both are NaCl `crypto_box_seal`:
//
// sealed = ephemeralPub(32) ‖ crypto_box(msg, nonce, recipientPub, ephemeralSecret)
// nonce = blake2b( ephemeralPub ‖ recipientPub , 24 bytes, unkeyed )
//
// When the vendor rotates the refresh token, the manager module must store the new one back the
// same way — sealed to the manager node's own sealing key — so mesh-control keeps it without ever
// same way — sealed to the manager node's own sealing key — so mesh-controller keeps it without ever
// reading it and the host can later unseal it to deliver the cleartext again. That reseal happens
// here, on the manager node, in TypeScript. It therefore has to produce the *identical* byte format
// Go's `Open` accepts, or the host would refuse the delivery.
@@ -27,7 +27,7 @@
// (package.json dependencies; novox/hq ADR 0052).
//
// **How it is kept honest.** A cross-language test seals a fixture here and opens it in Go
// (mesh-control internal/secrets/sealedbox_xcheck_test.go); the fixture is regenerated from this
// (mesh-controller internal/secrets/sealedbox_xcheck_test.go); the fixture is regenerated from this
// `seal()`. A drift between this seal and Go's box surfaces there as a seal Go cannot open, not as a
// refresh token silently mangled in production.
//
@@ -5,7 +5,7 @@ import { generateKeyPairSync } from "node:crypto";
import { seal } from "../sealedbox.ts";
// The definitive proof that this seal interoperates with Go's box.OpenAnonymous (the host's Unseal
// and mesh-control's secrets.Seal/Open) is a cross-language test in mesh-control
// and mesh-controller's secrets.Seal/Open) is a cross-language test in mesh-controller
// (internal/secrets/sealedbox_xcheck_test.go), which opens a fixture this module's seal() produced.
// These tests hold the TypeScript side: the output has the crypto_box_seal shape, and it is
// randomised so a rotation that changed nothing looks nothing like one that changed everything.