From 850b275218ef6bf5d65b4be278a2a252be6bc9e4 Mon Sep 17 00:00:00 2001 From: POWERFULMOVES Date: Fri, 7 Aug 2026 15:46:07 -0400 Subject: [PATCH 1/2] =?UTF-8?q?docs(spec):=20NATS=20accounts=20+=20leaf=20?= =?UTF-8?q?topology=20v0=20=E2=80=94=20trust=20zones,=20nsc/JWT,=20CHIT=20?= =?UTF-8?q?two-layer=20trust?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Design spec for completing the NATS forks (PMOVES-nats-server config+packaging, pmoves-nats-mcp CORE creds + CHIT-signed publish). Grounded in official NATS docs (accounts, leafnodes 7422, memory resolver) + GEOMETRY BUS/CHIT/prosodic subjects. Server stays upstream-clean (no Go patches). Fixes b850 leaf 4222->7422 bug. Co-Authored-By: Claude Opus 4.8 --- ...counts-leaf-topology-v0-spec-2026-08-07.md | 211 ++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 pmoves/docs/specs/nats-accounts-leaf-topology-v0-spec-2026-08-07.md diff --git a/pmoves/docs/specs/nats-accounts-leaf-topology-v0-spec-2026-08-07.md b/pmoves/docs/specs/nats-accounts-leaf-topology-v0-spec-2026-08-07.md new file mode 100644 index 0000000000..1d2071459d --- /dev/null +++ b/pmoves/docs/specs/nats-accounts-leaf-topology-v0-spec-2026-08-07.md @@ -0,0 +1,211 @@ +# PMOVES NATS Accounts + Leaf Topology — v0 Design Spec + +**Date:** 2026-08-07 **Author:** z890-claude (KEYSTONE, infra) **Status:** design — operator review +**Lane:** NATS fork completion (`PMOVES-nats-server` + `pmoves-nats-mcp`) grounded in official NATS refs. + +**Goal:** Give PMOVES a real NATS multi-tenancy + leaf-node trust model — trust-zone accounts, +nsc/JWT credentials, a hub leafnode listener that edge/cloud nodes actually attach to — and +complete the two NATS forks so they are real integrations (config + packaging), not shims. + +**Architecture:** Stock `nats-server` (upstream-clean fork) configured with four trust-zone +accounts (SYS/CORE/EDGE/CLOUD) via a memory resolver of nsc-minted account JWTs. Hub exposes a +`7422` leafnode listener; edge/cloud nodes attach as account-scoped leaves. CHIT signing rides +inside messages as an orthogonal, reinforcing trust layer. The MCP bridge becomes a CHIT-aware +signed publisher bound to CORE. + +**Tech stack:** `nats-server` 2.11.x (stock), `nsc` (JWT operator/account/user), memory resolver, +Python MCP (`pmoves-nats-mcp`), CHIT signing tooling (existing), CHIT vault + secrets-funnel. + +## Global Constraints + +- **Server stays upstream-clean** — no Go patches to `PMOVES-nats-server` in v0. Value lives in + config + packaging. Broker-level CHIT enforcement is explicitly out of scope (see §11). +- **No plaintext credentials** anywhere — replaces b850's `nats:pmoves`. All creds are nsc-minted + `.creds`, held in the **CHIT vault**, materialized via secrets-funnel. Never hand-edit `env.shared`. +- **Committed artifacts use hostnames/placeholders, never literal IPs** (refer to nodes by Tailscale hostname). +- **Compose/Dockerfile/config edits are Known-Road domains** — operator-authorized. +- Reconcile against prior operator decisions in `#1901` (JWT key custody + voice RBAC) — do not contradict. +- 100% stock NATS features only (accounts, leafnodes, memory resolver, JWT) — verified against official docs (§ References). + +--- + +## 1. Current state (measured 2026-08-07) + +- `pmoves-nats-1` = `nats:2.11.8-alpine`, launched via **flags** (`--user/--pass`, `--http_port 8222`) — + **no accounts, one flat global namespace.** +- Client `4222` published cross-node; monitoring `8222`→`9223` bound loopback but **not credential-guarded**. +- Leaf `.conf` files exist (`elder-melchor-leaf.conf`, `configs/nats-leaf-z890.conf`, `nats/config/external.conf`) + but the server is **not** launched with them, and **no leafnode listener** exists. +- **Bug:** b850's `elder-melchor-leaf.conf` remote points at `${TS_Z890}:4222` (client port) with plaintext + `nats:pmoves`. Per NATS docs a leaf attaches to the hub's **7422** leafnode port. It has never been a real leaf. +- `PMOVES-nats-server` = clean fork of `nats-io/nats-server`, tracking upstream, **zero PMOVES commits**. +- `pmoves-nats-mcp` = tracked (7 files), env `NATS_URL=nats://nats:pmoves@…:4222`, tools `nats_publish` / + `nats_subscribe`. **No Dockerfile/compose/examples** — shim-shaped. + +## 2. Account topology (trust zones) + +| Account | Holds | Users (initial) | +|---|---|---| +| **SYS** | NATS system account: `$SYS.*` events, monitoring. Guards `8222` (fixes the unguarded gap). | `sys` (ops) | +| **CORE** | All hub services on z890 — agents, geometry/chit, media, tokenism, mesh, archon, evo, a2ui. Shared account: they already share a flat namespace and mutually trust; keeps cross-lane subjects friction-free. | `core-service` (per-service split deferred) | +| **EDGE** | Jetson/edge leaves. Sees only what CORE exports. | `edge-nano-1` (+ `edge-*` per leaf) | +| **CLOUD** | Hostinger VPS/KVM leaves (egress/exit-node lane). Separate trust zone from EDGE. | `cloud-kvm-*` per leaf | + +Rationale: NATS "one account per application, don't over-fragment." Four zones give isolation at the +network trust boundary without walling the mutually-trusting hub services off from each other. + +## 3. Auth — nsc hierarchy + memory resolver + +nsc mints one **Operator** (`PMOVES`) → four **Accounts** (SYS/CORE/EDGE/CLOUD) → **Users** (`.creds` JWTs). + +Hub config (rendered from env like the kong pattern): +``` +resolver: MEMORY +resolver_preload: { + : + : + : + : +} +system_account: +``` +Memory resolver is the doc-recommended choice for "a small number of accounts that don't change +very often" — exactly our four fixed zones. User creds are still nsc-rotatable; only the four +account JWTs are preloaded (edit + reload to change an account, which is rare). + +**Custody (aligned to `#1901` precedent):** the operator holds key-custody decisions. `#1901` +(Supabase asymmetric JWT) set the fleet precedent — **file-mounted Docker secret for initial +rollout (the `_FILE` convention used across `pmoves/services/**`), CHIT-managed custody as a +follow-up.** This spec follows that: v0 mounts the nsc operator seed (`PMOVES.nk`) + account/user +`.creds` as **file-mounted Docker secrets**; **CHIT-vault-managed custody is the documented +follow-up**, not v0. The `resolver_preload` account JWTs (public, non-secret) render into the +`.conf` via secrets-funnel. Final custody choice remains the operator's per `#1901` §7. + +## 4. Leaf binding + the 7422 fix + +Hub adds: +``` +leafnodes { + listen: 0.0.0.0:7422 +} +``` +and **publishes 7422** cross-node (currently only 4222/8222 are exposed). + +Each leaf's remote (fix `4222`→`7422`, plaintext→creds): +``` +leafnodes { + remotes: [ + { + urls: [ "nats://:7422" ] + credentials: "/etc/nats/creds/edge-nano-1.creds" + # account binding is carried by the creds' user→account JWT + } + ] +} +``` +> **Open detail to confirm at implementation:** the exact field for pinning a leaf-side local account +> to the remote (`account:` on the remote vs. implied by creds). The nats.docs leaf-JWT page 404'd at +> design time; confirm against `nsc` docs / the security deep-dive before writing the leaf conf. + +## 5. Export/import matrix (the isolation payoff) + +CORE exports a **curated** set; EDGE/CLOUD export their announcements back. Everything else in CORE +(chit trails, `tokenism.attribution.*`, `archon.mint.*`) stays hub-private by construction. + +| Flow | Subjects | Type | +|---|---|---| +| CORE → EDGE | `image.gen.request.v1` (jobs to jetsons); prosodic **control** (voice-suit param surface) | stream | +| EDGE → CORE | `mesh.gpu.status.v1`, `voice.stt.edge.v1`, `image.prompt.expanded.v1`, `image.analysis.v1`, `mesh.combiner.heartbeat.v1`, **`tokenism.prosodic.bpm.v1`** (signed CGP), `chit.cgp.v1` | stream | +| CORE ↔ CLOUD | `mesh.*` + egress/exit-node subjects only | stream | +| CORE → EDGE (reserved, not wired v0) | `evoswarm.training.genome.v1` (genome to evaluate) | stream | +| EDGE → CORE (reserved, not wired v0) | `evoswarm.training.fitness.v1` (result) | stream | + +## 6. CHIT / GEOMETRY BUS / EVO SWARM / prosodic integration + +**Two orthogonal, reinforcing trust layers:** +- **NATS accounts = transport trust** — who may pub/sub which subjects across a boundary. +- **CHIT signing = payload provenance** — the CGP packet is signed (`chit.signed.v1`, `chit.cgp.v1`); + the signature rides inside the message regardless of account. + +A message from a leaf is trusted only if it clears **both** gates: the account let the bytes cross, +and the CHIT signature proves origin. + +- **All GEOMETRY BUS / CHIT services are CORE** (Tokenism `:8103`, Hi-RAG, Consciousness `:8106`, + Evo `:8113`, A2UI NATS Bridge `:9224`). `geometry.*`, `chit.*`, `tokenism.*`, `a2ui.*`, `evoswarm.*` + flow freely intra-CORE; invisible to leaves unless exported (§5). +- **Prosodic bpm is the CORE↔EDGE seam.** A jetson "prosodic ear" emitting `tokenism.prosodic.bpm.v1` + needs **both** an EDGE export right **and** a CHIT signing key — two-layer gate on the one subject + that must cross. CORE returns prosodic *control* so edge agents are "tuned like a tuning fork." +- **EVO SWARM stays CORE for v0** (evo-controller models grounded ∪ synthetic on the hub) with a + reserved edge seam (§5) for future distributed fitness evaluation — defined, not walled off. +- **Convergence:** `tokenism.credential.rotated.v1` already exists. The nsc creds lifecycle emits a + **CHIT-signed, tokenism-attributed** rotation event; A2UI renders the live trust topology + (`a2ui.trail.v1`). The accounts model *feeds* the geometry bus. + +## 7. The two forks — real-integration treatment + +### 7a. `PMOVES-nats-server` (register as submodule) +Stock binary, **no Go patches**. Carries the PMOVES config + packaging: +- `conf/pmoves-nats.conf` — accounts (memory resolver), `system_account`, `leafnodes{listen:7422}`, + monitoring behind SYS, rendered from env. +- `Dockerfile` (thin: stock `nats-server` + baked conf + entrypoint that templates the resolver_preload). +- compose stanza (replaces the flag-launched `nats` service) + `examples/` (a working leaf-attach demo). +- Tracks upstream for CVE currency via the existing fork-sync discipline. + +### 7b. `pmoves-nats-mcp` (complete + enhance) +1. **CORE `.creds` auth** — replace `NATS_URL=nats://nats:pmoves@…` with a CORE user `.creds` file + (env `NATS_CREDS` path); connect on the client port with the CORE account. +2. **CHIT-signed publish** — `nats_publish(subject, payload, sign?)`: when the subject is CHIT-aware + (`chit.*`, `tokenism.prosodic.*`, `geometry.*`, or `sign:true`), sign the CGP via the existing CHIT + signing tooling before publishing; otherwise raw publish (back-compat). Makes the MCP a first-class + two-layer-trust citizen. +3. **Packaging** — `Dockerfile`, compose service (CORE-bound), `examples/` (signed + raw publish, subscribe). + +## 8. Secrets & rendering + +- nsc keyring: operator seed + account/user seeds as **file-mounted Docker secrets** for v0 (per + `#1901` precedent); CHIT-vault-managed custody (`%APPDATA%/pmoves/chit` lane) is the follow-up. +- `.creds` files materialized to `/etc/nats/creds/` per node (file-mounted secret) — never committed, never in `ps`. +- Account JWTs (public) render into the hub `.conf` `resolver_preload` at funnel time. +- Add the new secret ids to `secrets_manifest.yaml` (example → manifest → funnel), never `env.shared` by hand. + +## 9. Rollout (greenfield, phased — each independently testable) + +1. **Mint** — nsc operator + 4 accounts + initial users; stash seeds in CHIT vault; add manifest entries. +2. **Hub** — deploy `PMOVES-nats-server` with accounts + `leafnodes{listen:7422}` + SYS; publish 7422. + Verify SYS-guarded monitoring, CORE clients connect with `.creds`. +3. **Migrate CORE** — switch hub services' `NATS_URL`→CORE `.creds`; verify the flat-namespace traffic + is unchanged intra-CORE. +4. **EDGE** — attach nano-1 as an EDGE leaf at 7422; wire §5 exports/imports; prove isolation. +5. **CLOUD** — attach a KVM as a CLOUD leaf; egress subjects only. +6. **MCP** — cut `pmoves-nats-mcp` to CORE `.creds`; land the CHIT-signed publish path. + +## 10. Acceptance tests (proves the model holds) + +- **Leaf handshake:** nano-1 leaf attaches at `7422` (hub `varz`/`leafz` shows the leaf); `4222`-target refused. +- **Isolation (the point):** an EDGE user subscribing a CORE-private subject (`tokenism.attribution.recorded.v1`) + is **denied**; publishing outside its export set is denied. +- **Export round-trip:** jetson publishes `mesh.gpu.status.v1` → observed on CORE; CORE publishes + `image.gen.request.v1` → observed on EDGE. +- **Two-layer trust:** an EDGE `tokenism.prosodic.bpm.v1` with a valid CHIT signature is accepted+trusted; + an unsigned one crosses transport but fails CHIT verification at the consumer. +- **MCP signed publish:** `nats_publish("tokenism.prosodic.bpm.v1", …, sign=true)` yields a CHIT-verifiable CGP. +- **Monitoring guard:** `8222`/`9223` requires SYS creds. +- **Rotation:** rotate a user cred via nsc without dropping CORE traffic; emits `tokenism.credential.rotated.v1`. + +## 11. Out of scope (v0) + +- **Broker-level CHIT enforcement** (Go patches rejecting unsigned publishes at the server) — deliberate + future decision; commits us to maintaining patches against a fast upstream. +- NATS-based (full) resolver / `nsc push` dynamic distribution — memory resolver suffices for 4 static accounts. +- Per-service CORE sub-accounts / fine-grained intra-CORE permissions. +- TLS on the leaf link (add after the account model lands; Tailscale already encrypts the transport). +- Wiring the EVO edge-fitness seam (reserved in §5, not built). + +## References (verified 2026-08-07) +- NATS accounts (multi-tenancy, export/import): `nats.docs .../securing_nats/accounts` +- NATS leafnodes (7422, remotes, credentials): `docs.nats.io/.../configuration/leafnodes` +- NATS JWT resolvers (memory vs full): `nats.docs .../securing_nats/jwt/resolver` +- `nats-io/nsc`, `nats-io/nats-architecture-and-design` (operator/account/user + accounts topology) +- Local: `.claude/context/geometry-nats-subjects.md`, `.claude/context/nats-subjects.md`, `#1901` decisions +- Sibling: `pmoves/docs/handoffs/jetson-combiner-archon-assignment-2026-08-07.md` (§C1 leafnode), `JUICEFS_MEDIA_MINIO_REFORMAT_RUNBOOK.md` From 543e1c46a5ba625cc4a1915191039774df28d0a0 Mon Sep 17 00:00:00 2001 From: POWERFULMOVES Date: Sat, 8 Aug 2026 12:55:55 -0400 Subject: [PATCH 2/2] docs(nats): phased rollout runbook + AGNOTE claim for leaf-topology adoption MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Companion to the v0 spec: turns §9 into a gated, per-phase-testable sequence with the operator/tooling gates called out explicitly (nsc install, #1901 custody, secrets_manifest via funnel, Known-Road compose, cross-node access). Claims the NATS lane in the register (Village Rule) and records the three landed slices (#2492 spec, #2493 submodule, this runbook) + the actionable z890-next work (mcp §7b packaging, fork §7a config templates — no secrets). Co-Authored-By: Claude Opus 4.8 --- pmoves/docs/AGENTS/AGNOTE4482PHI.t1.md | 6 ++ .../NATS_LEAF_TOPOLOGY_ROLLOUT_RUNBOOK.md | 77 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 pmoves/docs/operations/NATS_LEAF_TOPOLOGY_ROLLOUT_RUNBOOK.md diff --git a/pmoves/docs/AGENTS/AGNOTE4482PHI.t1.md b/pmoves/docs/AGENTS/AGNOTE4482PHI.t1.md index e8e095a283..9e4b1ed96f 100644 --- a/pmoves/docs/AGENTS/AGNOTE4482PHI.t1.md +++ b/pmoves/docs/AGENTS/AGNOTE4482PHI.t1.md @@ -1835,3 +1835,9 @@ b8cea26c8\ that added it to the top-level equired\ array). (2) PMOVES-pinokio PR - `2026-08-09T22:05:00Z` CLAIM+RELEASE `5090-CLAUDE (Claude Fable 5)` scope: **Signing is a claim — stepped into the lane, swept the grep dirt, and signed for real.** Operator anchor: messages 2026-08-09 17:32-17:33 EDT, 5090 session ("signing is a claim and a lane that may be easy to step into quick with a bunch of grep dirt hanging on... operator claims and quotes need to be anchored... always a reference" — hedged in the next breath to "almost always usually mostly often": a strong default, not dogma). **Discovery that changes the default:** the signing passphrase IS present in this node's shared env and `make -C pmoves sign-trail` works — produced a real `HMAC-SHA256` receipt (kid `chit-signing-v01`, hmac `XlKmNmOhU1YeBXccyFMJElz7/jJuCh3aczySTZaXRN4=`, payload at `pmoves/docs/logs/graphiti_signed_latest.json`). The register's **87 "unsigned-local (no signing passphrase)" disclaimers** are therefore a process gap, not a material gap — at least on 5090, and likely on any node whose env is funneled. Sessions should attempt `sign-trail` before writing the disclaimer. **Grep-dirt survey (identity drift):** 12+ signature-id variants including case splits `4090-CLAUDE`(17)/`4090-claude`(8), `Mavis`(37)/`Mavis-5090`(11), and the order-swap `SPARK-KIMI`(8)/`KIMI-SPARK`(5) — the same agent greps as two. Recommendation (not claimed): canonicalize ACK ids against `pmoves/config/agent_signatures.yaml` casing; `make naming-drift-check` already exists and is the natural home for a warn-only rule. **Fixed this entry:** the 2026-08-08 `Mavis-verifier` row was shell-mangled (backticks -> backslashes/U+0082, leading chars eaten) which made it **invisible to the anchored-bullet pattern both lane sweeps grep for** — repaired in place with a provenance note; visiting-agent append tooling should quote entries or write via a file, never through shell interpolation (the same class that ate part of this wave's own submodule commit message). **Anchoring protocol adopted:** operator claims/quotes carried into docs and memory get a reference (timestamp + session at minimum) — Three-Body's memory body IS the reference, not ceremony; hedge acknowledged. SPARK MCP-audit handoff updated accordingly with message-level anchors. Three-body: delivery=5090-CLAUDE (Claude Fable 5), control=DARKXSIDE (17:32 directive + live steer), memory=this trail + the signed payload + Cipher. CHIT trail **SIGNED** via `make sign-trail` (receipt above). agent_signature: `ACK::5090-CLAUDE-FABLE5::SIGNING-LANE-SWEEP-2026-08-09`. + +## z890 — NATS accounts + leaf-topology ADOPTION (operator go 2026-08-08) + +- `2026-08-08T17:00:00Z` CLAIM `Z890-CLAUDE` scope: **Operator adopted the NATS accounts + leaf-topology v0 spec + wiring the PMOVES-nats-server fork** (decision after a git forensic proved there's no coherent leaf in prod — the March-2026 WSL2-hack leaf ossified via file-persistence; current CATALOG.md topology is standalone brokers + KVM4-2 hub, NOT leaf-federated; the fork was decorative). **Slices landed (draft PRs, operator merge gate):** (1) spec **#2492** (`feat/nats-accounts-leaf-topology`); (2) fork submodule **#2493** (`feat/wire-nats-server-submodule` — registers `PMOVES-nats-server` at repo root, upstream-clean, gitlink d9dd620b); (3) this rollout runbook + claim (`pmoves/docs/operations/NATS_LEAF_TOPOLOGY_ROLLOUT_RUNBOOK.md`, on **#2492**). **Gates (operator/tooling, do NOT bypass):** `nsc` not installed on z890 (Phase-1 mint blocker); custody decision per #1901 (file-mounted Docker secret v0 → CHIT-vault follow-up); `secrets_manifest.yaml` entries via example→manifest→funnel (zero-access, operator adds); Known-Road compose/Dockerfile swap (flag-launched→fork image + 7422 listener + publish 7422); cross-node access for EDGE(jetson)/CLOUD(kvm) leaf attach. **z890 next (actionable, no gate):** `pmoves-nats-mcp` §7b packaging (Dockerfile/compose/examples, creds-optional CHIT-signed publish) + `PMOVES-nats-server` §7a config templates (`conf/pmoves-nats.conf` placeholder resolver, thin Dockerfile) — no secrets, JWTs render at funnel time. **Also this session:** infra.mk `docker-prune-all` parity fix **#2480** (auto-merge armed, needs 1 review approval). **Village Rule — NATS lane is z890-owned; coordinate before overlapping.** Converges with 4090's `validate-command-anchors` ratchet #2488 (guards the documented-command drift this lane must not reintroduce). **Three-body:** delivery=Z890-CLAUDE, control=DARKXSIDE (merge gate + the 5 gates above), memory=this trail + #2492/#2493/#2480 + spec + runbook. **CHIT trail unsigned-local.** agent_signature: `ACK::Z890-CLAUDE::NATS-LEAF-ADOPT-CLAIM-2026-08-08`. + + diff --git a/pmoves/docs/operations/NATS_LEAF_TOPOLOGY_ROLLOUT_RUNBOOK.md b/pmoves/docs/operations/NATS_LEAF_TOPOLOGY_ROLLOUT_RUNBOOK.md new file mode 100644 index 0000000000..46cf71fb54 --- /dev/null +++ b/pmoves/docs/operations/NATS_LEAF_TOPOLOGY_ROLLOUT_RUNBOOK.md @@ -0,0 +1,77 @@ +# NATS Accounts + Leaf-Topology — Rollout Runbook + +**Companion to:** `pmoves/docs/specs/nats-accounts-leaf-topology-v0-spec-2026-08-07.md` +**Decision:** 2026-08-08 — operator adopted the spec + wiring the `PMOVES-nats-server` fork. +**Owner:** z890-claude (KEYSTONE, infra). **Merge gate:** DARKXSIDE (Control). + +This turns the spec's §9 phases into a gated, independently-testable sequence. Each phase names +what is **actionable now** vs. what is **operator-gated** and why. Nothing here bypasses a gate. + +--- + +## Why (one paragraph) + +A git forensic (2026-08-08) established there is **no coherent leaf in production**: the `nats-leaf` +pattern was a 2026-03-19 WSL2 Docker-routing workaround (#1034) that was reverted 3 days later +(`feafffae6`) but whose config files persisted and got copied into every later "leaf" (none ever +worked — `elder-melchor-leaf.conf` even targets client port 4222, not a 7422 leaf port). The current +documented topology (`CATALOG.md`) is a hub-and-spoke of **independent standalone brokers on KVM4-2**, +explicitly **not** leaf-federated. This lane builds the *real* leaf trust model for the first time. + +--- + +## Status board + +| Slice | State | Gate | +|-------|-------|------| +| Land the design spec (#2492) | **done** (draft PR) | operator merge | +| Wire fork as submodule (#2493) | **done** (draft PR) | operator merge | +| This runbook + AGNOTE claim | **done** | operator merge | +| Phase 1 — mint nsc operator/accounts/users | **blocked** | `nsc` not installed on z890; custody decision (#1901) | +| Phase 2 — hub: fork config + `leafnodes{7422}` + SYS | blocked on P1 | Known-Road compose/Dockerfile (operator-auth) | +| Phase 3 — migrate CORE services → `.creds` | blocked on P2 | Known-Road compose | +| Phase 4 — EDGE leaf (nano-1 @ 7422) | blocked on P2 | cross-node access (jetson) | +| Phase 5 — CLOUD leaf (KVM) | blocked on P2 | cross-node access (Hostinger) | +| Phase 6 — `pmoves-nats-mcp` → CORE `.creds` + CHIT-signed publish | **partly actionable** | packaging now; `.creds` wiring on P1 | + +--- + +## The gates (what the operator/tooling must clear before deeper slices) + +1. **`nsc` install** — Phase 1 mints Operator `PMOVES` → 4 Accounts (SYS/CORE/EDGE/CLOUD) → user + `.creds`. `nsc` is not on z890. Install is the critical-path unblocker for everything after slice 3. +2. **Custody decision (#1901 precedent)** — spec §3/§8: v0 = **file-mounted Docker secret** for the + nsc operator seed + `.creds` (the `_FILE` convention across `pmoves/services/**`); CHIT-vault custody + is the documented follow-up. **Final custody choice is the operator's** per #1901 §7 — confirm before minting. +3. **`secrets_manifest.yaml` entries (§8)** — zero-access under damage-control. Operator adds the new + secret IDs via the **example → manifest → funnel** pipeline (never hand-edit `env.shared`). +4. **Known-Road compose/Dockerfile/config** — the hub service swap (flag-launched → fork image with + accounts + 7422), publishing 7422, and the leaf `.conf` edits are operator-authorized Known-Road domains. +5. **Cross-node access** — Phases 4–5 attach jetson (EDGE) and a KVM (CLOUD) as leaves; needs those nodes. + +## Actionable now (no gate) + +- **Phase 6a packaging** for `pmoves-nats-mcp` (§7b): add `Dockerfile`, a CORE-bound compose stanza, + `examples/` (raw + signed publish, subscribe) — the `.creds` auth path is written creds-optional + (back-compat raw publish per spec §7b.2) so it lands before minting; flip to CORE `.creds` at P1. +- **Fork config templates** in `PMOVES-nats-server` (§7a): `conf/pmoves-nats.conf` with `${...}` + placeholders for `resolver_preload` (rendered at funnel time), a thin Dockerfile (stock + `nats-server` + baked conf + entrypoint that templates the resolver), `examples/` leaf-attach demo. + These carry **no secrets** — the account JWTs are public and render at funnel time; the seeds/`.creds` + stay file-mounted secrets. + +## Acceptance tests (spec §10 — run per phase) + +Leaf handshake at 7422 (4222 refused) · EDGE isolation (CORE-private subject denied) · export +round-trip (`mesh.gpu.status.v1` ↑, `image.gen.request.v1` ↓) · two-layer trust (signed +`tokenism.prosodic.bpm.v1` accepted, unsigned crosses transport but fails CHIT verify) · MCP signed +publish · SYS-guarded monitoring (`:9223` needs SYS creds) · cred rotation emits +`tokenism.credential.rotated.v1`. + +## Coordination + +- **z890 (me):** slices 1–3 done; Phase 6a packaging + fork config templates next (actionable). +- **operator (DARKXSIDE):** install `nsc`, confirm custody (#1901), add manifest entries, authorize the + Known-Road compose swap. +- **4090's anchor ratchet (#2488)** now guards documented-command drift — the hub runbook commands here + must resolve (GHOST_TARGET/PATH), which keeps this doc honest as the config lands.