diff --git a/00-META/glossary.md b/00-META/glossary.md index 18687df..34fa695 100644 --- a/00-META/glossary.md +++ b/00-META/glossary.md @@ -75,6 +75,18 @@ another — and a mesh you cannot name precisely is a mesh two people describe d is a role you occupy, and the two meet where a seat delivers a provision: occupying the seat is what makes a module *the* provider of it. +## The surfaces + +- **console** — the module (`mesh-console`) that puts the mesh's tools in front of whoever is on a + machine: an MCP endpoint on the machine's loopback for an agent, the same endpoint for a person. It + is assigned like any module, holds a credential the mesh minted, and calls tools under a grant its + manifest declares (`invokes`). Loopback is the authority boundary: whoever is on the machine owns the + mesh there ([ADR 0152](../02-DECISIONS/0152-the-operators-surface-is-a-module-the-console.md)). + Not "the tool bridge", "the brain" or "the MCP server" — those name the predecessor's program or a + protocol, and the console is a module. +- **invokes** — the manifest word for the tools a module calls, `.` each or `*` for + every one. A grant on the publish side and nothing else; a module that declares none calls nothing. + ## How this page is kept A new name for an existing thing lands here first, in the same change that introduces it in code. A diff --git a/02-DECISIONS/0095-the-control-plane-is-the-way-to-ask-a-module.md b/02-DECISIONS/0095-the-control-plane-is-the-way-to-ask-a-module.md index df3d292..8eebbec 100644 --- a/02-DECISIONS/0095-the-control-plane-is-the-way-to-ask-a-module.md +++ b/02-DECISIONS/0095-the-control-plane-is-the-way-to-ask-a-module.md @@ -47,6 +47,14 @@ Anything with the control plane in reach can ask any module anything it serves. harder: nothing outside the control plane can, and the control plane's connection is one more thing on the path of every question — a cost accepted for the audit it buys. +> **The mechanism changed — 2026-09-30, by ADR 0152.** What stands: `ask` on the control plane, and +> that every call passes an account whose permission list says what it may ask. What moved: "nothing +> outside the control plane can" stopped being true when a person's account gained a publish grant per +> tool (design 25 §7, 2026-09-28), and [ADR 0152](0152-the-operators-surface-is-a-module-the-console.md) +> takes the first option above for a module as well — a manifest declares `invokes`, and the bus grants +> exactly that publish side. The audit the second option bought is the bus's permission list, which +> derives both. + ## How it is checked A tools-only bed asks a served tool through the control plane and asserts an answer arrived — diff --git a/02-DECISIONS/0152-the-operators-surface-is-a-module-the-console.md b/02-DECISIONS/0152-the-operators-surface-is-a-module-the-console.md new file mode 100644 index 0000000..e9f75bd --- /dev/null +++ b/02-DECISIONS/0152-the-operators-surface-is-a-module-the-console.md @@ -0,0 +1,160 @@ +--- +topic: what runs on it +status: accepted +date: 2026-09-30 +deciders: jochen +reconstructed: false +extends: 02-DECISIONS/0095-the-control-plane-is-the-way-to-ask-a-module.md +--- + +# 152. The operator's surface is a module the mesh assigns: the console + +## Context + +**Since the bus moved, nobody can ask the mesh anything without opening a shell on a machine.** Every +tool call an operator's assistant makes fails, on every machine including the one the operator sits +at, with *AMQP not connected* +([issue 147](../04-ISSUES/147-the-operators-tools-still-dial-the-bus-that-was-removed/00-report.md)). +The program answering is the predecessor's tool server, started on the workstation by hand, with the +predecessor's broker address written into the assistant's own configuration. It has no manifest, no +assignment, no account on the bus, and the mesh has never known it exists. Nothing regressed: the +mesh removed a transport that a program outside the mesh still dials. + +**The mesh has a tool model, and it works.** A module serves each tool on its own subject and its +account may serve nothing else ([ADR 0047](0047-a-module-runs-its-code-as-its-own-process-with-its-own-account.md)); +a person is issued an account whose only permission is to publish the tool subjects named at issue +([25 — The bus on NATS](../03-DESIGN/01-to-be/25-the-bus-on-nats.md) §7); a client on the +runtime repository's main branch speaks that account as a command line and as an MCP server. Measured +on the live mesh on 2026-09-28: a call to the forge's `gitea_list_repos` answered with real +repositories; the tool list came back empty, because it asks the catalogue for a tool nothing serves +([ADR 0132](0132-a-seat-carries-the-tools-its-holder-must-serve.md)). + +**Two records have already said where the surface belongs.** ADR 0132's consequences: *the MCP +surface belongs inside the mesh — a module the mesh assigns to the machine where the agent sits, with +a credential the mesh minted and authority derived from what it may call, not a program started by +hand with a credential printed to a terminal.* Design [33](../03-DESIGN/01-to-be/33-the-tools-the-mesh-answers.md) +§6 says the same. Neither is a decision about the surface: 0132 decided where a seat's tools live, +and named the surface in passing. + +**And one record says the opposite, in the letter.** [ADR 0095](0095-the-control-plane-is-the-way-to-ask-a-module.md) +made the control plane *the* way to ask a module, deferred "calling is a grant" until something asked +for it, and recorded that *nothing outside the control plane can*. A person's account (design 25 §7, +built 2026-09-28) is exactly that grant, minted for a person. So 0095's exclusivity has already been +widened once without a record saying so; a module that calls tools widens it a second time, and this +record is where that is said. + +**What a module's account may do today, counted from the composition** (`internal/broker`): publish +its own events, publish the accept subjects of seats it uses, subscribe its own tools and what it +consumes. No module principal may publish another module's tool subject. Of 72 modules in the +catalogue, 45 serve tools and 0 may call one. + +The question the work order asks before any code: **does the mesh grow its own operator surface, or is +the surface an ordinary module that happens to serve tools?** + +## Considered Options + +**1. The control plane serves the agent protocol itself** — a listener on the controller, or a verb +its binary runs. Rejected. It puts a surface for tools the control plane does not implement on the one +component that must stay answerable while it is itself being replaced, which is the reason 0132 +rejected the control plane as the answer to discovery. A person on a workstation would reach it over +the network, and the networked surface [ADR 0035](0035-one-implementation-several-surfaces.md) +reserves for that authenticates through an OAuth2 provider that is not configured — so the controller's +`api` verb correctly serves nothing today, and this option would either wait for it or bypass it. + +**2. A program a person installs and starts by hand with a printed credential** — what exists on the +runtime repository's main. Rejected as the end state. It is outside the mesh in every way issue 147 +names: no assignment, no declaration, no seat, no check that it reaches anything, revoked only by a +person remembering to. It is the predecessor's arrangement one bus later, and it fails the same way +the next time an address moves. It stays as the recovery path, the way the command line does +(ADR 0035): a credential from `operator issue` and the `mesh` client work with no console assigned. + +**3. An ordinary module, assigned to the machine the person sits at, holding a credential the mesh +minted, serving the mesh's tools on that machine's loopback.** Chosen. + +## Decision + +**The console is a module.** `mesh-console` is built by the mesh, registered like any module, +assigned to a machine, and given a bus credential sealed to that machine. It serves the mesh's tools to +whoever is on that machine: to an agent over MCP, and to a person through the same endpoint. Assigning +it to a machine is what makes the mesh reachable from there; unassigning it revokes that, at the next +composition, with nothing on the machine to remember to remove. + +**A grant to call is a manifest word: `invokes`.** A module declares the tools it calls, each as +`.`, or the single entry `*` for every tool on the mesh. The bus grants exactly that +publish side and nothing beside it — no event, no subscription, no seat. This is ADR 0095's deferred +first option, taken now that a consumer asks for it; a person's account already has this shape, and +the same composition derives both. The control plane's `ask` stands, and 0095's audit point with it: +every call still passes one account whose permission list says what it may ask. + +**Authority is the machine's login.** The console listens on the machine's loopback only, declared +`from: machine`, so whoever can open a socket on the machine is whoever owns the machine, and *the +account that installed the host owns the mesh on that node* +([ADR 0034](0034-the-local-account-owns-the-mesh.md)). Anything on a machine may call anything on it, +and that is the whole of local ([ADR 0144](0144-anything-on-a-machine-may-call-anything-on-it.md)). +The mesh knows no person: what the audit sees is which console asked, under the account +`.mesh-console`. How a person's identity reaches a session is the question design 15 leaves +open, and this record does not close it. + +**What the console lists is asked of the modules.** Design 33 §5: a module's own tools are answered by +the module, from the code that defines them. The tool runtime therefore answers one reserved verb for +every module it serves — `tools`, the module's tool names, descriptions and argument schemas — and the +console assembles its list by asking the catalogue which modules the mesh holds and each module what +it answers. A module that is not running is absent from the list and says so; a tool an agent already +knows the name of can be called whether or not it was listed. A module may not name a tool of its own +`tools`; the runtime refuses the collision at load rather than letting one shadow the other. A +role's tools, and the mesh's own verbs, join the list when the `mesh-controller` seat serves them +(design 33 §1, third family) — the console reads whatever the mesh can say about itself, and grows as +that does. + +**The console holds one credential and one grant: `*`.** It is the operator's surface on a machine the +operator owns; narrowing what it may call is a setting on its assignment, which +[ADR 0046](0046-a-module-configuration-is-its-assignments-not-its-manifest.md) already provides for +and nothing here builds. + +## Consequences + +- **The way a person drives the mesh is inside the mesh.** It is declared, delivered, replaced and + revoked by the same machinery as everything else, and `status` says whether the machine carrying it + has applied. Issue 147's shape — a surface kept alive by an address in a file — cannot recur, because + there is no file: the console's credential names the bus the mesh is on, and moves when it does. +- **A module may now call tools, which ADR 0095 had reserved to the control plane.** The grant is + explicit, per tool or `*`, and derived by the same composition that grants everything else. A module + that declares no `invokes` gains nothing. What got harder: a manifest reviewer has one more field to + read for authority, and `*` in it deserves the reader's attention every time. +- **A new manifest word ships one release before any manifest uses it**, and must reach both parsers: + the build machine's and the running controller's. The console's manifest cannot be registered until + the controller and the builder that packages it have been rebuilt with the word. +- **Discovery costs a fan-out per list.** One request per module the mesh holds, answered at once by + the bus for every module nothing serves, so the cost is bounded by the modules that are up. The list + is cached briefly in the console; a module assigned a moment ago appears at the next refresh. +- **Every tool runtime must be rebuilt once** to answer `tools`. Until a module is, it is callable and + not listed, and the console says which modules did not answer. +- **The mesh's own verbs are not in the console yet.** `status`, `push`, `assign` are the + `mesh-controller` seat's tools under 0132, and the three prerequisites 0132 names are still not in + place. A person asking what a node runs still opens a shell for that question, and that gap is design + 33's to close, not this record's — recorded here so nobody reads the console as the whole of 147. +- **The person's credential is not retired.** `operator issue` and the `mesh` client remain the path + when no console is assigned, and the path an operator uses to bring a mesh up far enough to assign + one. + +## How this is checked + +| Rule | Checked by | +|---|---| +| A module's `invokes` becomes exactly that publish grant, and nothing else | the bus user composition test: a module invoking `shop.price` may publish that subject and no other tool's; `*` may publish every tool subject; neither may publish an event or subscribe anything it did not consume | +| A malformed `invokes` entry is refused at registration | a parser test: an entry naming no tool is a problem named in the manifest's words | +| The runtime answers `tools` for every module it serves | the runtime's test: a module registering two tools answers three names, and a module naming one of its own `tools` is refused at load | +| The console's list is what the modules answer | the client's test against a real bus: two modules up, a third the catalogue holds and nothing serves, and the list carries the two and names the third as not answering | +| A call from the console reaches a module over the bus | the same test, and the live mesh: the console assigned to a workstation answers `tools/list` on its loopback and a call to the forge returns repositories | +| The console listens on loopback and nowhere else | its manifest declares `from: machine`, and the filter composed for the machine opens nothing for it | + +## References + +- [issue 147](../04-ISSUES/147-the-operators-tools-still-dial-the-bus-that-was-removed/00-report.md) — the surface outside the mesh +- [ADR 0095](0095-the-control-plane-is-the-way-to-ask-a-module.md) — extended: a grant to call, for a module as for a person +- [ADR 0132](0132-a-seat-carries-the-tools-its-holder-must-serve.md) — where a seat's tools live, and the sentence that named the surface +- [ADR 0035](0035-one-implementation-several-surfaces.md) — three surfaces over one implementation +- [ADR 0034](0034-the-local-account-owns-the-mesh.md), [ADR 0144](0144-anything-on-a-machine-may-call-anything-on-it.md) — why loopback is the authority boundary +- [33 — The tools the mesh answers](../03-DESIGN/01-to-be/33-the-tools-the-mesh-answers.md) §5, §6 — discovery, and what serves it to an agent +- [34 — The console](../03-DESIGN/01-to-be/34-the-console.md) — the design this record authorises +- mesh-tools `src/client.ts`, `src/mcp.ts`, `src/mesh.ts` — the client this makes a module of diff --git a/02-DECISIONS/README.md b/02-DECISIONS/README.md index e0b35a0..a7c4d99 100644 --- a/02-DECISIONS/README.md +++ b/02-DECISIONS/README.md @@ -256,6 +256,7 @@ python3 00-META/checks/index.py fail if stale - **0146** — [Connectivity is checked by name, per hosting form, with a valid certificate](0146-connectivity-is-checked-by-name-per-hosting-form.md) - **0147** — [A module anchors the mesh's authority on a machine, and takes it away again](0147-a-module-anchors-the-meshs-authority.md) - **0150** — [A module's own code runs as supervised processes under the module's one account](0150-a-modules-own-code-runs-as-supervised-processes-under-one-account.md) +- **0152** — [The operator's surface is a module the mesh assigns: the console](0152-the-operators-surface-is-a-module-the-console.md) ### How it is built diff --git a/03-DESIGN/01-to-be/12-a-module-repository.md b/03-DESIGN/01-to-be/12-a-module-repository.md index d9da073..7cf2592 100644 --- a/03-DESIGN/01-to-be/12-a-module-repository.md +++ b/03-DESIGN/01-to-be/12-a-module-repository.md @@ -7,9 +7,10 @@ code: - mesh-controller internal/catalogue/build.go - mesh-controller internal/inventory/secrets.go - mesh-controller cmd/mesh-builder -updated: 2026-09-12 +updated: 2026-09-30 decisions: - 02-DECISIONS/0069-a-module-is-a-repository-and-a-path.md + - 02-DECISIONS/0037-where-a-module-lives.md - 02-DECISIONS/0009-modules-and-the-graph.md - 02-DECISIONS/0010-delivery.md - 02-DECISIONS/0005-the-node-host.md @@ -60,6 +61,32 @@ module from a repository and a path, and the root-only reading left every existi unbuildable — pointed at the catalogue the builder finds no manifest, pointed at a module's source it finds no manifest either.* +## A manifest is checked where it is written + +*Added 2026-09-30, from [issue 148](../../04-ISSUES/148-a-manifest-outside-this-catalogue-has-no-check/00-report.md).* + +The check the mesh applies at registration — the manifest parses strictly, every name in it is a +usable one, its routes and events and seats are well formed, and no two manifests given together +declare one seat — is a verb on the controller's binary, `module check …`, and it needs no +mesh. It reads the files it is given, runs the same functions registration runs, prints every problem +in the manifest's own words, and exits non-zero if there was one. Somebody describing their own +application in their own repository — the case [ADR 0037](../../02-DECISIONS/0037-where-a-module-lives.md) +calls the one that matters most — runs it before pushing, and finds out there rather than when a +running mesh refuses the registration, or later, when a machine applies something that resolved and +should not have. + +**What it cannot know, it says.** A seat another module declares elsewhere is unknown to a check that +was not handed that module's manifest, and the output says so rather than refusing: pass the other +manifest too. The mesh's own seats it knows from the binary, which is the one place that set may be +read without a store ([ADR 0122](../../02-DECISIONS/0122-a-seat-is-data-a-rename-is-a-database-update.md) +keeps the store authoritative, so a claim on a mesh seat is judged fully only at registration, and the +check says that too). + +*How it is checked:* the controller's test runs the check over the catalogue checkout beside it and +over a manifest with a known fault, and asserts the first passes and the second names the fault; the +test that used to be the only check, `TestEveryCatalogueManifestParses`, now stands beside a command +anybody can run. + ## The manifest in the repository is not the manifest the mesh holds A resource names an artifact: diff --git a/03-DESIGN/01-to-be/25-the-bus-on-nats.md b/03-DESIGN/01-to-be/25-the-bus-on-nats.md index 40d9775..20a7b73 100644 --- a/03-DESIGN/01-to-be/25-the-bus-on-nats.md +++ b/03-DESIGN/01-to-be/25-the-bus-on-nats.md @@ -361,6 +361,13 @@ bridged. It is three things: Nothing is built of this before §10's bed passes; the MCP surface is a thin adapter over (2). +*Built, and then made a module — 2026-09-30.* (1) and (2) exist: `operator issue` and the `mesh` +client. What (2) describes as a program on the workstation is now the recovery path; the surface an +operator uses is a module the mesh assigns to the machine, holding a credential the mesh minted — +[ADR 0152](../../02-DECISIONS/0152-the-operators-surface-is-a-module-the-console.md), +[34 — The console](34-the-console.md). The tool list it asks for is no longer +`catalog_tools`, which nothing served: each runtime answers `tools` for its own module. + ## 8. What a module sees, and what the wire does **The contract a module is written against does not change.** `publish` on an envelope becomes a diff --git a/03-DESIGN/01-to-be/33-the-tools-the-mesh-answers.md b/03-DESIGN/01-to-be/33-the-tools-the-mesh-answers.md index cdb2127..0d8b599 100644 --- a/03-DESIGN/01-to-be/33-the-tools-the-mesh-answers.md +++ b/03-DESIGN/01-to-be/33-the-tools-the-mesh-answers.md @@ -102,6 +102,12 @@ being something a person carries and becomes something the mesh runs, on a node, An agent's authority can then be role-shaped: *the forge's tools*, rather than a list of module-specific names that changes the day the forge is replaced. +*Decided and designed on 2026-09-30:* the module is the console — +[ADR 0152](../../02-DECISIONS/0152-the-operators-surface-is-a-module-the-console.md), +[34 — The console](34-the-console.md). It builds the second half of §5 now (a module's tools are +asked of the module, through a `tools` verb every runtime answers) and lists a role's tools when the +records carry them. + ## 7. Versioning A seat's tools are an interface and change like one. Additive within a version. A change that would diff --git a/03-DESIGN/01-to-be/34-the-console.md b/03-DESIGN/01-to-be/34-the-console.md new file mode 100644 index 0000000..653e477 --- /dev/null +++ b/03-DESIGN/01-to-be/34-the-console.md @@ -0,0 +1,116 @@ +--- +layer: to-be +status: in-progress +code: [mesh-catalog, mesh-tools, mesh-controller] +updated: 2026-09-30 +decisions: + - 02-DECISIONS/0152-the-operators-surface-is-a-module-the-console.md + - 02-DECISIONS/0132-a-seat-carries-the-tools-its-holder-must-serve.md + - 02-DECISIONS/0095-the-control-plane-is-the-way-to-ask-a-module.md + - 02-DECISIONS/0035-one-implementation-several-surfaces.md + - 02-DECISIONS/0034-the-local-account-owns-the-mesh.md +--- + +# 34 — The console + +**The mesh's tools, on the machine a person sits at, served by a module the mesh assigned there.** +An agent reaches them over MCP on the machine's loopback; a person reaches the same endpoint. Nothing is +installed by hand, nothing is configured with an address, and the mesh knows the surface exists because +it put it there ([ADR 0152](../../02-DECISIONS/0152-the-operators-surface-is-a-module-the-console.md)). + +## 1. What it is + +A module, `mesh-console`, in the catalogue. Its image is the tool runtime's own — the client that +already speaks the bus as a command line and as an MCP server — started in a mode that reads the +module's credential and listens on loopback. It has no state, no provision, no seat. What it needs is +the bus, which it gets the way every module does: a credential the mesh minted for `.mesh-console`, +sealed to the machine, delivered as the module's own secret. + +Its manifest says three things nothing else in the catalogue says together: + +- `invokes: ["*"]` — it calls every tool on the mesh, and the bus grants exactly that publish side; +- `listens` on a port `from: machine` — the filter opens nothing for it, because loopback is not outside; +- no `emits`, no `consumes`, no `tools` — it answers nothing on the bus and nobody can address it there. + +## 2. What it serves, and to whom + +**One endpoint, `POST /mcp` on the machine's loopback**, speaking MCP over HTTP: `initialize`, +`tools/list`, `tools/call`. An agent on the machine is pointed at it once — the address is the machine's +own and never changes — and sees every tool the mesh can say it has. A person at a terminal uses the +same endpoint through the `mesh` client, or through anything that can make an HTTP request; the client +needs no credential, because the console holds it. + +**The endpoint is the machine's login.** It binds `127.0.0.1` and nothing else. Whoever can connect is +on the machine, and whoever is on the machine is the account that owns the mesh there +([ADR 0034](../../02-DECISIONS/0034-the-local-account-owns-the-mesh.md), +[ADR 0144](../../02-DECISIONS/0144-anything-on-a-machine-may-call-anything-on-it.md)). There is no +token, no login page and no second identity, on purpose: a credential a person had to carry to reach +their own machine's console would be the arrangement this replaces, moved one hop. + +## 3. How it knows what the mesh can do + +Design [33](33-the-tools-the-mesh-answers.md) §5 splits discovery in two: a role's tools are read from +the mesh's records, a module's own are asked of the module. The console builds the second half now and +reads the first when it exists. + +**Every tool runtime answers `tools`.** The runtime that serves a module's tools also serves one verb of +its own under that module's name, `mesh.mod..tool.tools`, answering the module's tool names, +descriptions and argument schemas — the definitions from the code that answers them, and from nowhere +else. A module may not name a tool of its own `tools`; the runtime refuses the collision at load. + +**The console asks the catalogue which modules the mesh holds, then asks each.** `catalog_modules` +answers the roster; one `tools` request per module, in parallel, answers the list. The bus refuses at +once a request nothing serves, so a module that is not running costs nothing and is named in the answer +as not answering, rather than silently absent — *silence and success must never look alike*. The list is +kept for a short while and refreshed, so an agent asking on every turn does not fan out on every turn. + +**A tool that was not listed can still be called.** Listing is discovery; calling is the grant. An agent +that knows a tool's name asks for it by `.` and the module answers or the bus says why not. + +**What is missing from the list, and until when.** A role's tools and the mesh's own verbs — `status`, +`push`, `assign` — are the `mesh-controller` seat's under ADR 0132 and are not served yet; their three +prerequisites are listed in that record. When the seat serves them, the console lists them beside the +modules' own, and the person stops opening a shell for the mesh's own questions. Until then the console +says so in its handshake. + +## 4. Where it runs + +On whichever machines an operator sits at, by assignment. It is not on the control node by default and +does not need to be: it reaches the bus like any module, from anywhere in the mesh. A machine that is +not a node cannot have it, which is the right refusal — the mesh reaches what it declares, and a +workstation that wants the console joins first. + +The person's credential and the `mesh` client (design [25](25-the-bus-on-nats.md) §7) remain the path +for a machine that is not a node, and the path to a mesh not yet far enough along to assign anything. + +## 5. Removing it + +Unassigning the console from a machine revokes its bus account at the next composition and stops the +container; nothing is left on the machine that could still connect. An agent pointed at the loopback +address gets a refused connection, which is the truthful answer. + +## How it is checked + +| Check | Defends | +|---|---| +| a module invoking one tool may publish that subject and no other tool's; `*` may publish every one; neither may publish an event or subscribe what it did not consume | ADR 0152, the grant | +| a module registering two tools answers three names to `tools`, with schemas; a module naming its own `tools` is refused at load | ADR 0152, discovery | +| against a real bus: two modules up, a third held and not running — the console lists the two and names the third as not answering | ADR 0152, silence is not success | +| a call through the console's endpoint reaches a module over the bus and the answer is the module's own, unshaped | ADR 0035, a surface decides nothing | +| on the live mesh: the console assigned to a workstation answers `tools/list` on loopback and a call to the forge returns repositories | the exit of work-order step 3 | +| the composed filter for a machine carrying the console opens no port for it | ADR 0144 | + +## What this does not settle + +- Narrowing a console's grant per assignment. ADR 0046 makes it a setting; nothing reads one yet. +- The mesh's own verbs on the bus. Design 33's third family; this document only says where they appear + once they exist. +- A person's identity behind the console. The mesh sees the console's account; design 15 keeps the + question open. + +## References + +- [ADR 0152](../../02-DECISIONS/0152-the-operators-surface-is-a-module-the-console.md) — the decision +- [33 — The tools the mesh answers](33-the-tools-the-mesh-answers.md) — what the console lists +- [25 — The bus on NATS](25-the-bus-on-nats.md) §7 — the person's client this makes a module of +- [issue 147](../../04-ISSUES/147-the-operators-tools-still-dial-the-bus-that-was-removed/00-report.md) — the symptom diff --git a/04-ISSUES/006-hq-is-not-indexed-into-the-knowledge-base/00-report.md b/04-ISSUES/006-hq-is-not-indexed-into-the-knowledge-base/00-report.md index 2c8c762..2860a01 100644 --- a/04-ISSUES/006-hq-is-not-indexed-into-the-knowledge-base/00-report.md +++ b/04-ISSUES/006-hq-is-not-indexed-into-the-knowledge-base/00-report.md @@ -1,7 +1,7 @@ --- status: located opened: 2026-08-23 -located-in: [hal, hq] +located-in: [hq README.md, and the agent ADR 0025 names — not built] fixed-by: amended-design: 02-DECISIONS/0025-the-design-record-is-read-not-copied.md --- @@ -169,3 +169,16 @@ them into. The record stays open, and its answer is no longer "index this reposi is whatever the mesh grows as its own knowledge surface, if it grows one. Until then the honest fix is the README, which should stop claiming a property nothing provides. + +## Where this stands, 2026-09-30 + +The README no longer claims a property nothing provides: it says the indexing never existed, that the +store it named is unreachable since the cut-over, and that ADR 0025's answer — read, not copied, by an +agent that consults this repository — is decided and not built. That was the honest fix the previous +note asked for, and it is done. + +The record stays open on ADR 0025's build, and on nothing else. The mesh's own operator surface is now +a module ([ADR 0152](../../02-DECISIONS/0152-the-operators-surface-is-a-module-the-console.md)); the +reader ADR 0025 describes is the mesh session of design 15, which would answer through that surface +like any tool. What closes this is still the check 0025 names: search for a phrase that appears only in +a design document here, and get it back. diff --git a/04-ISSUES/147-the-operators-tools-still-dial-the-bus-that-was-removed/00-report.md b/04-ISSUES/147-the-operators-tools-still-dial-the-bus-that-was-removed/00-report.md index b056a21..7f918f7 100644 --- a/04-ISSUES/147-the-operators-tools-still-dial-the-bus-that-was-removed/00-report.md +++ b/04-ISSUES/147-the-operators-tools-still-dial-the-bus-that-was-removed/00-report.md @@ -1,7 +1,9 @@ --- status: located opened: 2026-09-29 -located-in: [nothing in the mesh — the surface in use is the predecessor's, installed on the workstation] +located-in: [mesh-catalog modules/mesh-console, mesh-tools src/mesh.ts, mesh-controller internal/broker] +fixed-by: +amended-design: 03-DESIGN/01-to-be/34-the-console.md --- # 147 — the operator's tools still dial the bus that was removed @@ -73,3 +75,21 @@ outside the mesh. - It fails identically for the local machine, which rules out reachability and points at the transport alone. - The mesh's own traffic over the new bus is unaffected: nodes report, declarations apply. + +## Answered, 2026-09-30 + +The work order's question — does the mesh grow its own operator surface, or is the surface an +ordinary module — is answered by [ADR 0152](../../02-DECISIONS/0152-the-operators-surface-is-a-module-the-console.md): +**the console is a module.** `mesh-console` is assigned to the machine a person sits at, holds a +credential the mesh minted, calls tools under a grant its manifest declares (`invokes`), and serves the +mesh's tools on that machine's loopback to an agent over MCP and to a person through the same endpoint. +Designed in [34 — The console](../../03-DESIGN/01-to-be/34-the-console.md). + +What that leaves, said plainly so nobody reads this record as closed on the whole of its first +paragraph: the console reaches every tool a *module* serves. The mesh's own questions — what a node +runs, what is assigned — are the `mesh-controller` seat's tools under ADR 0132 and are not on the bus +yet; for those a shell is still the way, and design 33 is where that closes. + +The predecessor's program on the workstation is not replaced by the mesh; it is left where it is and +the assistant is pointed at the console beside it. The `hal` entry in the assistant's configuration +still names things that are not the mesh's. diff --git a/04-ISSUES/148-a-manifest-outside-this-catalogue-has-no-check/00-report.md b/04-ISSUES/148-a-manifest-outside-this-catalogue-has-no-check/00-report.md index 1bd3f00..87cd992 100644 --- a/04-ISSUES/148-a-manifest-outside-this-catalogue-has-no-check/00-report.md +++ b/04-ISSUES/148-a-manifest-outside-this-catalogue-has-no-check/00-report.md @@ -1,7 +1,9 @@ --- -status: open +status: located opened: 2026-09-29 -located-in: [mesh-controller cmd/mesh-controller] +located-in: [mesh-controller cmd/mesh-controller, mesh-controller internal/catalogue] +fixed-by: +amended-design: 03-DESIGN/01-to-be/12-a-module-repository.md --- # 148 — a manifest outside this catalogue has no check @@ -35,3 +37,14 @@ Nothing prevents this; it was noticed and left. ADR 0037 named it on 2026-09-01 take a path from `MESH_CATALOG`, so the mechanism is already path-driven and not repository-bound. - `mesh-controller module add` refuses a bad manifest at registration, which is the same check far too late: by then it is in a running mesh's records. + +## Built, 2026-09-30 + +`mesh-controller module check …` runs what registration runs — the strict parse, the +per-manifest problems, and the cross-manifest rules over every manifest given — with no store and no +mesh, prints every problem in the manifest's words, and exits non-zero on any. What it cannot judge +without a store it says: a claim on one of the mesh's own seats is judged fully only at registration +([ADR 0122](../../02-DECISIONS/0122-a-seat-is-data-a-rename-is-a-database-update.md)), and a seat +declared by a module whose manifest was not passed reads as unknown. Written into +[12 — A module repository](../../03-DESIGN/01-to-be/12-a-module-repository.md) as the section *a +manifest is checked where it is written*. The console's own manifest was the first checked with it. diff --git a/README.md b/README.md index 720d4e1..cf023f4 100644 --- a/README.md +++ b/README.md @@ -87,12 +87,15 @@ rather than location** — that these documents would be indexed into the knowle symptom search returns them beside everything else. One source, many surfaces. Where the source is authored is then a separate question. -**That indexing does not exist.** It was checked on 2026-08-23 and returns nothing; it appears -never to have existed. Until it does, the objection stands unanswered and this repository is -the fourth knowledge system it was argued not to be. Recorded as -[`04-ISSUES/006`](04-ISSUES/006-hq-is-not-indexed-into-the-knowledge-base/00-report.md), and -left standing here rather than quietly reworded, because a claim that held up a decision and -was never checked is precisely the failure this repository exists to name. +**That indexing never existed, and the store it would have indexed into is gone.** It was checked +on 2026-08-23 and returned nothing; the knowledge base it named was the predecessor's, and since the +mesh moved to its own bus on 2026-09-28 nothing can reach it at all. The claim is recorded as +[`04-ISSUES/006`](04-ISSUES/006-hq-is-not-indexed-into-the-knowledge-base/00-report.md) and answered +by [ADR 0025](02-DECISIONS/0025-the-design-record-is-read-not-copied.md): these documents are +**read, not copied** — an agent reads this repository and a search consults it — and that agent is +not built. So today this repository is reachable by whoever knows to open it and surfaces to nobody +else. Said here rather than quietly reworded, because a claim that held up a decision and was never +checked is precisely the failure this repository exists to name. Answered separately, a repository of its own is the better home: