Hear an event every declaring module says, keep the connectivity verbs open, and clear findings of a node a module left

The keeper finds its sources in the catalog and names none in its manifest, so one generic consumes form with its
validator rule and per-module grant carries the finding events; the operator's answer that a verb open today stays
open covers the connectivity verbs that name no callers; and findings of a module no longer placed on a node would
otherwise stand forever.

Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
This commit is contained in:
2026-11-11 02:21:43 +01:00
parent 9f9cb58f54
commit bfd5fd2c0b
+37 -15
View File
@@ -152,7 +152,12 @@ record it follows from, and replaces the builder's own choice where one was made
`persons`, and every other text the names the design gives that verb. Why: ADR 0666 §20 makes the definition the
grants part's one source of caller limits, in a form it reads; `invokers`, which ADR 0666 §20's list does not name,
is the operator's choice for the verbs whose text said "any caller whose role grants it" (Telegram, 2026-11-11 02:13
CET: "Any declaring module"). How it is checked: unit (definition reader), each
CET: "Any declaring module"), and by the same answer, that a verb open today stays open to any module declaring it,
for the fifteen verbs of the Connectivity domain's seats that name no `callers` on main, which §68 would otherwise
close to their holders and the operator: `node-hostname`'s `entries`, `add` and `remove`;
`node-intrusion-prevention`'s `status`, `banned`, `ban` and `unban`; `node-packet-filter`'s `rules`, `reload` and
`remove`; `node-resolver`'s `routes`, `route` and `unroute`; `node-uplink`'s `resolvers` and `links`. Each of their
definitions in `mesh-connectivity-contracts` names `invokers` in this milestone. How it is checked: unit (definition reader), each
form accepted and any other entry refused; the grants part's table test grants each form.
- §337 **The bus module's restore points.** The verbs the holder of `node-backup` on the bus module's node calls to take
and restore a module's kept data on the bus name `holder:node-backup@same-node`. Why: only that holder takes them
@@ -257,7 +262,8 @@ record it follows from, and replaces the builder's own choice where one was made
(assigner), a composition step's `run` is answered and its input read by digest.
- §355 **The assigner says an unanswered `manifest-reads`.** The assigner, the one caller of the node-engine's
`manifest-reads` from G, writes `call-unanswered` as its own finding and says it as an observer does (§383, §384),
so the condition keeper hears it with no change of its own (ADR 0668 §3; the operator, 2026-11-11). The assigner and
so the condition keeper hears it with no change of its own, departing from ADR 0668 §3's reads by the operator's
answer of 2026-11-11. The assigner and
the runner each declare their own state `findings` in their old `state` section, both being foundation parts, read
by their own read tools alone. How it is checked: whole (assigner, runner, condition keeper), a node-engine that
never answers makes the assigner say `finding-written` for `call-unanswered` after five minutes, and the keeper
@@ -297,12 +303,17 @@ record it follows from, and replaces the builder's own choice where one was made
modules whose entry declares the finding events of §383, the node-engine among them, its holder read from the seat
list. It joins the readers of *Every other reader of which modules exist*, reading every watched branch's newest
catalog revision, so a module watched on any branch is a source. A condition of a module that is in no branch's
revision is cleared, said with the reason `module left the catalog`. Before its first view the keeper keeps the
revision is cleared, said with the reason `module left the catalog`. The keeper also takes a first view of the
assignment half (through `meshwantsclient`, following `assignment-revision` of `mesh-wants`), and a module's findings
of a node where the newest assignment graph revision no longer places that module are cleared, said with the reason
`module left the node`. Before its first view the keeper keeps the
conditions it holds and applies no finding event, which waits on its durable consumer, and says `view-waits` after
five minutes (*A part with no view says it waits*). It reads no module's `findings` state (§383). Why: no part fixes
a name (§7), and the keeper hears findings and reads no other module's state (ADR 0596 §2, §4; the operator,
2026-11-11). How it is checked: whole (keeper), a fixture module declaring the finding events is heard with no code
change; the catalog's validation finds no `findings` in the keeper's manifest `reads`.
a name (§7), and the keeper hears findings and reads no other module's state (ADR 0596 §2, §4), departing from
ADR 0564 §2 by the operator's answer of 2026-11-11; the assignment half and `module left the node` are the design's
choice. How it is checked: whole (keeper), a fixture module declaring the finding events is heard with no code
change, and a fixture module's condition on a node is cleared with `module left the node` when an assignment graph
revision no longer places it there; the catalog's validation finds no `findings` in the keeper's manifest `reads`.
### From round 1 of the review by architectural domain (2026-11-10)
@@ -505,11 +516,8 @@ events, and a module states its findings from its own truth; the shared tool-run
(`headline`, `explanation`), `since` and `at`; `finding-cleared` carries `observer`, `node`, `scope`, `id`, `kind`,
`at` and `why`. mesh-sdk's finding writer (`go/views`' `FindingWriter`) says them for every part, beside the key it
writes in the part's own state `findings`, which stays the owner's and is read only by the owner's read tool. The
keeper hears them on one durable consumer of its own: its manifest's `consumes` names them with the emitter `*`
(`*.finding-written`, `*.finding-cleared`, `*.findings-stated`), a form that takes that event from every module
whose manifest declares it, and the grants part grants the subscription per declaring module, derived from the
manifests as every grant is (§59); the manifest validator takes `*` only as the whole emitter before a declared event
name. The keeper takes a finding only from a source its catalog view names (§365), raises or changes a condition on
keeper hears them on one durable consumer of its own, its manifest's `consumes` naming them with the emitter `*`
(`*.finding-written`, `*.finding-cleared`, `*.findings-stated`, §386). The keeper takes a finding only from a source its catalog view names (§365), raises or changes a condition on
`finding-written` and clears it on `finding-cleared`, save while ADR 0564 §13 holds it; a condition's looks are
those of its last event, and the observer's read tool shows its newest. What exists today goes in the same change:
every `findings` entry of the keeper's manifest `reads`, its `consumes` of the assigner's and the indexer's
@@ -517,10 +525,10 @@ events, and a module states its findings from its own truth; the shared tool-run
indexer declare no `views.findings`, which no reader follows any more; the read tools stay for persons and sessions.
No ordering edge is needed: a source still on its old version says nothing, its conditions stand as they are, and
§384's bound names it. Why: only its owner reaches a module's state, and a part hears another's events (ADR 0596 §2,
§4); the operator, 2026-11-11. The subjects, the fields, the writer and the `*` emitter are the design's choice.
§4), departing from ADR 0564 §2 by the operator's answer of 2026-11-11. The subjects, the fields and the writer are
the design's choice.
How it is checked: unit (mesh-sdk's writer), a finding written and one cleared each say their event with these
fields after the key; unit (manifest validator), `*.finding-written` accepted, `*.>` and `*` before an undeclared
event refused; whole (keeper), a fixture observer's `finding-written` raises a condition and its `finding-cleared`
fields after the key; the manifest validator's rows of §386; whole (keeper), a fixture observer's `finding-written` raises a condition and its `finding-cleared`
clears it, and the same event from an account that is not the source's is refused by the bus; the catalog's
validation finds no `findings` in the keeper's `reads`.
- §384 **An observer states every finding it owns at its start and when the keeper asks; the keeper's view is
@@ -544,7 +552,8 @@ events, and a module states its findings from its own truth; the shared tool-run
with the full list states no `seat-list-unread`, and the keeper clears it at that start. Why: the node-engine's
seat-list waiter kept only in its process that it had written its finding, so a node-engine restarted with the full
list never cleared it, and two machines said they waited for the seat list for a day while both held it (issue 1966);
the operator, 2026-11-11: the fix is NATS-native, from each observer's own truth. The event, its fields, the bound,
departing from ADR 0564 §2 and §12 by the operator's answer of 2026-11-11: the fix is NATS-native, from each
observer's own truth. The event, its fields, the bound,
the reasons and the replacement for an observer held once are the design's choice. How it is checked: whole (the
node-engine, and each observer through mesh-sdk's writer), a module restarted after raising a finding whose cause has
gone clears it at its start, the node-engine's `seat-list-unread` among them; whole (keeper), a `findings-asked` is
@@ -556,3 +565,16 @@ events, and a module states its findings from its own truth; the shared tool-run
granted, and call `merge-pull` or the runner's `run` as a session; G changes neither that account nor its grants, a
known limit. Why: the operator, 2026-11-11; modules running as the machine's account are issue 1966's (note 193),
whose fix carries its check. How it is checked: none in G; the limit is named on issue 1966.
- §386 **A `*` emitter in `consumes` hears one event from every module that declares it.** A `consumes` entry
`*.<event>` takes the event `<event>` from every module whose manifest declares it, and is the one generic form for
hearing an event that many modules say; the keeper's three finding events are the first (§383, §384). The manifest
validator takes `*` only as the whole emitter, and only before an event that a seat's definition or a contract
in mesh-sdk defines, with its fields (for the finding events, mesh-sdk's finding writer); it refuses `*`
before any other event, `*.>`, and `*` in part of an emitter's name. The grants part grants the subscription per
declaring module, the subject of each module whose manifest declares the event, derived from the manifests as every
grant is (§59), so a module that declares it later is heard with no change to the consumer's manifest, and a module
that does not declare it is not granted. Why: the keeper hears modules it finds in the catalog and its manifest names
none (§7, §365); the form, the validator's rule and the grant are the design's choice following the operator's
answer of 2026-11-11 (§383). How it is checked: unit (manifest validator), `*.finding-written` accepted, `*.>`,
`*x.finding-written` and `*` before an event no contract defines refused; the grants part's table test grants a
`*.finding-written` consumer the subject of each declaring module and of no other.