From bfd5fd2c0b2d272b7d2ad955712ad6cb60fc0324 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 11 Nov 2026 02:21:43 +0100 Subject: [PATCH] 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 --- .../01-to-be/47-milestones/G-7-answers.md | 52 +++++++++++++------ 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/03-DESIGN/01-to-be/47-milestones/G-7-answers.md b/03-DESIGN/01-to-be/47-milestones/G-7-answers.md index 05d2dfc2..ba512476 100644 --- a/03-DESIGN/01-to-be/47-milestones/G-7-answers.md +++ b/03-DESIGN/01-to-be/47-milestones/G-7-answers.md @@ -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 + `*.` takes the 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.