Merge pull request 'The approval mark and every-event: the prepare's answers, so both parts are complete for develop with milestone G' (#542) from design/34-wait-on-any-event into main
This commit was merged in pull request #542.
This commit is contained in:
@@ -65,7 +65,8 @@ that holds its mark reach the machines together.
|
|||||||
`EventSubjects` answers for its cases is covered by a subject of `EveryEvent`.
|
`EventSubjects` answers for its cases is covered by a subject of `EveryEvent`.
|
||||||
2. **The manifest loses `waits`.** `catalogue.Manifest.Waits` and its comment go from `go/catalogue/manifest.go`;
|
2. **The manifest loses `waits`.** `catalogue.Manifest.Waits` and its comment go from `go/catalogue/manifest.go`;
|
||||||
the comment on `ToolRunner` loses "and the only module that may declare `waits`". `go/catalogue/waits_test.go` is
|
the comment on `ToolRunner` loses "and the only module that may declare `waits`". `go/catalogue/waits_test.go` is
|
||||||
deleted, and one row is added to the decoder's existing table of unknown fields: a manifest
|
deleted, and one row is added to the nearest table over raw manifests, `go/catalogue/invokes_test.go`'s
|
||||||
|
`TestAManifestMaySayWhatItInvokes` (Q-T): a manifest
|
||||||
`{"module":"node-tools","version":"1","tool-runner":true,"waits":["a.b"]}` decodes with `UnknownField()` naming
|
`{"module":"node-tools","version":"1","tool-runner":true,"waits":["a.b"]}` decodes with `UnknownField()` naming
|
||||||
`waits` (ADR 0670 §2). The decoder itself is unchanged: a stored manifest that still carries `waits` is read
|
`waits` (ADR 0670 §2). The decoder itself is unchanged: a stored manifest that still carries `waits` is read
|
||||||
without it (ADR 0578 §3).
|
without it (ADR 0578 §3).
|
||||||
@@ -123,7 +124,8 @@ that holds its mark reach the machines together.
|
|||||||
|
|
||||||
11. **Its manifest's changes, every one.** `node-tools/module.json` drops the key `waits` and its five entries (ADR
|
11. **Its manifest's changes, every one.** `node-tools/module.json` drops the key `waits` and its five entries (ADR
|
||||||
0670 §2); gains `operator-channel` in `uses`, for the asks of marked waits (§35; design 46 7-approval-mark §7); gains
|
0670 §2); gains `operator-channel` in `uses`, for the asks of marked waits (§35; design 46 7-approval-mark §7); gains
|
||||||
in `requires` the state `approvals` of design 46 7-approval-mark §13; and gains the stream `node-tools-findings` and
|
in its old `state` section the per-machine state `approvals` of design 46 7-approval-mark §13 (the tool runner is a
|
||||||
|
foundation part, ADR 0619 §2, §3); and gains the stream `node-tools-findings` and
|
||||||
the `consumes` of `mesh-conditions.findings-asked` that design 47 G §387 writes. Its `version` stays `2`, a label
|
the `consumes` of `mesh-conditions.findings-asked` that design 47 G §387 writes. Its `version` stays `2`, a label
|
||||||
no reader judges. Nothing else in it changes.
|
no reader judges. Nothing else in it changes.
|
||||||
12. **The publication time is kept.** `bus.Heard` gains `Published`, read from the event's header `x-time`, which
|
12. **The publication time is kept.** `bus.Heard` gains `Published`, read from the event's header `x-time`, which
|
||||||
@@ -182,8 +184,9 @@ that holds its mark reach the machines together.
|
|||||||
answered after the timeout with §16's words; `TestMeshWaitWithNoFamiliesIssuedWaitsOnNothing` is deleted. In
|
answered after the timeout with §16's words; `TestMeshWaitWithNoFamiliesIssuedWaitsOnNothing` is deleted. In
|
||||||
`bus/wait_test.go`, `TestTheBusRefusesAWaitOutsideTheGrant` stays as §16's refusal test, with a timeout of a
|
`bus/wait_test.go`, `TestTheBusRefusesAWaitOutsideTheGrant` stays as §16's refusal test, with a timeout of a
|
||||||
fraction of a second, its comment citing ADR 0670 §1. The manifest test also holds each change of §11: no `waits`,
|
fraction of a second, its comment citing ADR 0670 §1. The manifest test also holds each change of §11: no `waits`,
|
||||||
`operator-channel` in `uses`, the state `approvals` in `requires` with its options, and the finding stream. No test
|
`operator-channel` in `uses`, the state `approvals` in the old `state` section, per machine with its time to live,
|
||||||
function is added: the module stays within its budget.
|
and none in `requires`, and the finding stream. New
|
||||||
|
test functions are allowed within the module's budget of 500 unit and 50 integration tests (Q-TB).
|
||||||
|
|
||||||
## The claude-code module's Stop hook
|
## The claude-code module's Stop hook
|
||||||
|
|
||||||
@@ -316,7 +319,8 @@ approves, for a marked event or a restricted stream.
|
|||||||
`from: seat` is never marked.
|
`from: seat` is never marked.
|
||||||
35. **A marked wait runs only on the operator's warrant for that one wait.** The call is an act as design 46
|
35. **A marked wait runs only on the operator's warrant for that one wait.** The call is an act as design 46
|
||||||
7-approval-mark §8 makes one: the address `mesh_wait`, the node, the module `node-tools` and the tool `mesh_wait`,
|
7-approval-mark §8 makes one: the address `mesh_wait`, the node, the module `node-tools` and the tool `mesh_wait`,
|
||||||
its build (the digest of the tool runner's own artifact), and every
|
its build (the tool runner's own fingerprint, as the node-engine's `running.<node>.node-tools` last said it, which the
|
||||||
|
tool runner hears, design 47 G §309; Q-BD; while it is unknown, a marked wait is refused, saying so), and every
|
||||||
argument given (`subjects`, `from`, `filter`, `timeout`), so the warrant binds the exact names, the filter and the
|
argument given (`subjects`, `from`, `filter`, `timeout`), so the warrant binds the exact names, the filter and the
|
||||||
bound. The tool runner refuses, asks, judges and claims it as that part's §9, §10, §11 and §13 to §17 do for a
|
bound. The tool runner refuses, asks, judges and claims it as that part's §9, §10, §11 and §13 to §17 do for a
|
||||||
marked tool, asking on the seat `operator-channel` under its own module's name, `node-tools`, whose manifest gains
|
marked tool, asking on the seat `operator-channel` under its own module's name, `node-tools`, whose manifest gains
|
||||||
@@ -348,7 +352,8 @@ approves, for a marked event or a restricted stream.
|
|||||||
so the restricted stream's event is heard only after the warrant; with a warrant for other names, another filter
|
so the restricted stream's event is heard only after the warrant; with a warrant for other names, another filter
|
||||||
or another timeout it is refused; the same names `from: seat` ask nothing; a wait named `<module>.<event>.<node>`
|
or another timeout it is refused; the same names `from: seat` ask nothing; a wait named `<module>.<event>.<node>`
|
||||||
under a marked `<module>.<event>` is marked; and before the catalog half is read, a marked wait asks nothing, is
|
under a marked `<module>.<event>` is marked; and before the catalog half is read, a marked wait asks nothing, is
|
||||||
judged when the first view comes within its timeout, and is refused at its timeout when it does not. The warrant is
|
judged when the first view comes within its timeout, and is refused at its timeout when it does not. A marked wait while
|
||||||
|
the tool runner's own fingerprint is unknown is refused, saying so. The warrant is
|
||||||
written on the test bus as the router's record. `Overlaps` gains rows in §1's table (`mesh.stream.mail.event.mail.>` overlaps
|
written on the test bus as the router's record. `Overlaps` gains rows in §1's table (`mesh.stream.mail.event.mail.>` overlaps
|
||||||
`mesh.stream.mail.event.mail.*.message`; `mesh.mod.mail.event.x` does not overlap `mesh.stream.mail.event.x`), and
|
`mesh.stream.mail.event.mail.*.message`; `mesh.mod.mail.event.x` does not overlap `mesh.stream.mail.event.x`), and
|
||||||
§32's refusal a row in the indexer's `judge/rules_test.go`.
|
§32's refusal a row in the indexer's `judge/rules_test.go`.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ layer: to-be
|
|||||||
design: 46
|
design: 46
|
||||||
milestone: 7-approval-mark
|
milestone: 7-approval-mark
|
||||||
updated: 2026-11-11
|
updated: 2026-11-11
|
||||||
code: [mesh-sdk, mesh-contracts, mesh-delivery, mesh-tools, mesh-catalog modules/zsh, mesh-catalog modules/gitea]
|
code: [mesh-sdk, mesh-contracts, mesh-delivery, mesh-tools, mesh-host, mesh-catalog modules/zsh, mesh-catalog modules/gitea, mesh-catalog modules/mesh-files]
|
||||||
decisions:
|
decisions:
|
||||||
- "ADR 0286"
|
- "ADR 0286"
|
||||||
- "ADR 0259"
|
- "ADR 0259"
|
||||||
@@ -14,6 +14,8 @@ decisions:
|
|||||||
- "ADR 0595"
|
- "ADR 0595"
|
||||||
- "ADR 0597"
|
- "ADR 0597"
|
||||||
- "ADR 0310"
|
- "ADR 0310"
|
||||||
|
- "ADR 0394"
|
||||||
|
- "ADR 0619"
|
||||||
- "ADR 0268"
|
- "ADR 0268"
|
||||||
- "ADR 0564"
|
- "ADR 0564"
|
||||||
---
|
---
|
||||||
@@ -50,26 +52,36 @@ and not a retry on a timer (§16), and a fourth open ask is offered as G makes i
|
|||||||
not hold for a process that reads the tool runner's bus credential (the file `broker` in its state directory,
|
not hold for a process that reads the tool runner's bus credential (the file `broker` in its state directory,
|
||||||
`own-secrets`) and speaks to the bus itself: that account may subscribe a marked subject, a restricted stream's among
|
`own-secrets`) and speaks to the bus itself: that account may subscribe a marked subject, a restricted stream's among
|
||||||
them, on a machine whose runner honours the mark. Read on the workstation on 2026-11-11 with `node-reads.stat`, the
|
them, on a machine whose runner honours the mark. Read on the workstation on 2026-11-11 with `node-reads.stat`, the
|
||||||
file is mode 0600, owned by the operator's account, in a directory of mode 0755: every process running as the
|
file is mode 0600, owned by the operator's account, in a directory of mode 0755, and the prepare of 2026-11-11 read
|
||||||
|
the same mode and owner on all four nodes: every process running as the
|
||||||
operator's account, every module on the machine's shared account and every agent session among them, can read it and
|
operator's account, every module on the machine's shared account and every agent session among them, can read it and
|
||||||
hear a restricted stream without a warrant. This is the same known limit as design 47 G §385 (modules running as the
|
hear a restricted stream without a warrant. This is the same known limit as design 47 G §385 (modules running as the
|
||||||
machine's account, issue 1966 note 193, whose fix carries its check), and this milestone does not change it: that a
|
machine's account, issue 1966 note 193, whose fix carries its check), and this milestone does not change it: that a
|
||||||
restricted stream is heard only on a warrant holds against every caller once that fix runs modules and sessions on
|
restricted stream is heard only on a warrant holds against every caller once that fix runs modules and sessions on
|
||||||
accounts that cannot read the file, and until then against callers that go through the tool runner. The
|
accounts that cannot read the file, and until then against callers that go through the tool runner. The
|
||||||
prepare reads the file's mode and owner on every node with `<node>/node-reads.stat` and writes them in the milestone
|
prepare reads the file's mode and owner on every node with `<node>/node-files.stat` and writes them in the milestone
|
||||||
file; a node where the file is readable beyond the operator's account is a finding of the prepare.
|
file; a node where the file is readable beyond the operator's account is a finding of the prepare. The forge module's
|
||||||
|
own credential (§21) lies in a directory of mode 0700, owned by the forge's account, which the reading account cannot
|
||||||
|
enter; `node-files.stat` answers such a file's mode from this milestone (§21a), and the prepare reads it then.
|
||||||
|
|
||||||
## The mark
|
## The mark
|
||||||
|
|
||||||
1. **A module marks its tools and verbs in `needs-approval`.** mesh-sdk's `catalogue.Manifest` gains `NeedsApproval`,
|
1. **A module marks its tools and verbs in `needs-approval`.** mesh-sdk's `catalogue.Manifest` gains `NeedsApproval`,
|
||||||
the manifest key `needs-approval`: a list of strings, each a tool the module serves (`<tool>`) or a seat verb it
|
the manifest key `needs-approval`: a list of strings, each a tool the module serves (`<tool>`) or a seat verb it
|
||||||
serves (`<seat>.<verb>`), and, under design 34 every-event §32, one of its events. Absent is no mark. *Why:* ADR
|
serves (`<seat>.<verb>`), and, under design 34 every-event §32, one of its events. Absent is no mark. *Why:* ADR
|
||||||
0286 §1, §49 (each marking is a manifest change, reviewed like any other). *How it is checked:* unit, a row in the
|
0286 §1, §49 (each marking is a manifest change, reviewed like any other). Only the contract's manifest reads
|
||||||
decoder's table test in `go/catalogue`; the manifest reads baseline gains `word:needs-approval`.
|
(`ManifestReads`) gain `word:needs-approval`; the baseline of the engines before any stated what it reads
|
||||||
|
(`manifest_reads_baseline.txt`) is unchanged, since none of them reads the word (Q-BL). *How it is checked:* unit, a
|
||||||
|
row in `go/catalogue/invokes_test.go`'s `TestAManifestMaySayWhatItInvokes`, the nearest table over raw manifests
|
||||||
|
(Q-T): a manifest naming a tool, a seat verb and an event in `needs-approval` decodes all three with `UnknownField()`
|
||||||
|
empty, and one without it has no mark.
|
||||||
2. **A seat's definition marks a verb for every holder.** mesh-sdk's `seatdef` reads a verb's `needs-approval`, a
|
2. **A seat's definition marks a verb for every holder.** mesh-sdk's `seatdef` reads a verb's `needs-approval`, a
|
||||||
boolean, in a seat definition (`seats/<seat>/seat.json` in mesh-contracts); the seat definitions the catalog half
|
boolean, in a seat definition (`seats/<seat>/seat.json` in mesh-contracts); the seat definitions the catalog half
|
||||||
carries (design 47 G §194) carry it on the verb. *Why:* ADR 0286 §2. *How it is checked:* unit, a fixture row in
|
carries (design 47 G §194) carry it on the verb. The definition format's own schema in mesh-contracts
|
||||||
`seatdef`'s table test.
|
(`format/seat-definition.schema.json`) gains a verb's `needs-approval`, a boolean (Q-SC). Every strict reader of a
|
||||||
|
seat definition reads the word from G's reader release (design 47 G §340), so no reader refuses a definition that
|
||||||
|
carries it (Q-RR). *Why:* ADR 0286 §2. *How it is checked:* unit, a fixture row in `go/seatdef/seatdef_test.go`'s
|
||||||
|
`TestADefinitionIsReadStrictlyNamingWhatIsWrong` (Q-T), and the schema validates the login shell's definition of §21.
|
||||||
3. **Marks add up.** A verb is marked when its seat's definition or its holder's `needs-approval` marks it; a holder
|
3. **Marks add up.** A verb is marked when its seat's definition or its holder's `needs-approval` marks it; a holder
|
||||||
cannot unmark what its seat marks. *Why:* ADR 0286 §3. *How it is checked:* unit, a row of §5's table.
|
cannot unmark what its seat marks. *Why:* ADR 0286 §3. *How it is checked:* unit, a row of §5's table.
|
||||||
4. **The manifest validator refuses a mark it cannot honour.** The indexer's manifest validator (`judge/rules.go`)
|
4. **The manifest validator refuses a mark it cannot honour.** The indexer's manifest validator (`judge/rules.go`)
|
||||||
@@ -89,50 +101,71 @@ file; a node where the file is readable beyond the operator's account is a findi
|
|||||||
enforce its own verbs, and no other own-process server has a gate, so such a mark is refused rather than ignored;
|
enforce its own verbs, and no other own-process server has a gate, so such a mark is refused rather than ignored;
|
||||||
and an entry that names two things is read one way by one reader and another way by the next (the design's choices
|
and an entry that names two things is read one way by one reader and another way by the next (the design's choices
|
||||||
under ADR 0286 §4, §40, the refusal kept by lead-47 on 2026-11-11). *How it is checked:* unit, one row per refusal
|
under ADR 0286 §4, §40, the refusal kept by lead-47 on 2026-11-11). *How it is checked:* unit, one row per refusal
|
||||||
in `judge/rules_test.go`, rows that accept the zsh and forge manifests of §21, and a row of §22's mark table for
|
in `judge/rules_test.go`'s `TestRulesManifests` (Q-T), rows that accept the zsh and forge manifests of §21, and a row of §22's mark table for
|
||||||
`mark-unserved`.
|
`mark-unserved`.
|
||||||
|
|
||||||
## Where the marks are read, and where they are withheld
|
## Where the marks are read, and where they are withheld
|
||||||
|
|
||||||
5. **From the catalog half on the bus, never from a bundle.** The indexer's catalog graph entry of a module (design 47
|
5. **From the catalog half on the bus, never from a bundle.** The indexer's catalog graph entry of a module (design 47
|
||||||
G §174) gains its `needs-approval`, its `emits`, and for each stream it declares its events and whether it carries a
|
G §174) carries the validated manifest whole (design 47 G §443), its `needs-approval`, its `emits` and its streams
|
||||||
`grant`; no part but the indexer reads a manifest (the operator, 2026-11-11: "only the indexer uses the manifest to
|
(their events as the manifest spells them, and whether each carries a `grant`) among it; mesh-sdk's `buscompose`
|
||||||
build the module catalog"); the seat
|
exports `WirePattern`, which a reader uses to turn a stream's events into the bus's subjects, the grants part's own
|
||||||
|
copy going (Q-WP). No part but the indexer reads a manifest: every other part reads the entry of the build concerned
|
||||||
|
from the catalog half (design 47 G §442; the operator, 2026-11-11: "only the indexer uses the manifest to build the
|
||||||
|
module catalog"; Q-MR), the grants part's `declaredFor` among them for every grant, not only the marks; the seat
|
||||||
definitions of the catalog half carry the verb marks (§2). The tool runner, which from G takes its first view of the
|
definitions of the catalog half carry the verb marks (§2). The tool runner, which from G takes its first view of the
|
||||||
catalog half by `mesh-catalog.revision` and follows `catalog-revision` (design 47 G §196), derives from it, for each
|
catalog half by `mesh-catalog.revision` and follows `catalog-revision` (design 47 G §196), derives from it, for each
|
||||||
module it serves, its marked tools and verbs, in a package of its own, `node-tools/internal/approval`, again on
|
module it serves, its marked tools and verbs, in a package of its own, `node-tools/internal/approval`, again on
|
||||||
every revision it hears. No module's name is written in its code. The marks follow the running version: the runner
|
every revision it hears. No module's name is written in its code. The marks follow the running version: a bundle's
|
||||||
applies the marks of the module's version it serves, and, while the newest revision's entry for that module
|
served version is the fingerprint its composed environment carries (design 47 G §424), whose entry the runner reads
|
||||||
differs, the union of both, so a mark is never lost before or after the module moves. A mark added while a call
|
by `mesh-catalog.entry` (design 47 G §443) when it loads the bundle; it applies that entry's marks and, while the
|
||||||
waits applies from the next call, which the answer of §12 says. *Why:* ADR 0286 §5 had the controller issue the mark
|
newest revision's entry for that module differs, the union of both, so a mark is never lost before or after the
|
||||||
in a membership so that a bundle could not drop it; no controller issues memberships now, and the judged catalog
|
module moves, and a delivery that drops a mark while the old bundle still runs is still asked. When the served
|
||||||
half is the same guarantee: the bundle never carries the mark (ADR 0656 §6, one source for which modules exist).
|
entry cannot be read, every marked call on that runtime is refused (§19). A mark added while a call waits applies
|
||||||
The union keeps ADR 0286 §3's "marks add up" across a version change. *How it is checked:* unit, a table test in
|
from the next call, which the answer of §12 says. *Why:* ADR 0286 §5 had the controller issue the mark in a
|
||||||
`approval` derives the marks from fixture catalog halves, §3's row, a version change and the union among them.
|
membership so that a bundle could not drop it; no controller issues memberships now, and the judged catalog half is
|
||||||
|
the same guarantee: the bundle never carries the mark (ADR 0656 §6, one source for which modules exist). The union
|
||||||
|
keeps ADR 0286 §3's "marks add up" across a version change. The served version is read from what the bundle runs,
|
||||||
|
not from a placement, which can change before the bundle does (step 0b). *How it is checked:* unit, a table test in
|
||||||
|
`approval` derives the marks from fixture catalog halves and served entries, §3's row, a version change and the
|
||||||
|
union among them, and a served entry that cannot be read.
|
||||||
6. **A machine whose tool runner does not honour the mark serves no marked tool or verb.** The tool runner states
|
6. **A machine whose tool runner does not honour the mark serves no marked tool or verb.** The tool runner states
|
||||||
`approval-mark/1` among its call capabilities (`runtime.CallCapabilities`), which its announcement carries and its
|
`approval-mark/1` among its call capabilities (`runtime.CallCapabilities`), which its announcement carries with
|
||||||
node's node-engine takes into the node's record; the assignment half carries it among the capability readings
|
the tool runner's own fingerprint, and its node's node-engine takes both into the node's record; the assignment
|
||||||
(design 47 G §194). The grants part, composing a runtime's account, reads that runtime's node's readings: where the
|
half carries, for each node, its capability readings, each with the fingerprint of the runner that announced it
|
||||||
tool runner does not state `approval-mark/1`, where the node has no readings, or where its readings are older than
|
(design 47 G §194; Q-CR). The grants part, composing a runtime's account, reads that runtime's node's readings and
|
||||||
the tool runner's version on that node (failing closed as §19), it composes a subscribe deny of every marked
|
the fingerprint the node-engine's `running.<node>.node-tools` last said running (design 47 G §309): where the tool
|
||||||
subject of every module the runtime carries, the marks read from the catalog half as §5 has them:
|
runner does not state `approval-mark/1`, where the node has no readings, or where the readings' fingerprint differs
|
||||||
`mesh.mod.<module>.tool.<tool>` and the same followed by `.*`; the
|
from the running one or is absent (an older reading, failing closed as §19; no time is compared), it composes a
|
||||||
caller-named subject mesh-sdk's `process.Call` sends on first, `mesh.mod.<module>.call.<tool>.>`; and for a marked
|
subscribe deny of every marked subject of every module the runtime carries, the marks read from the catalog half
|
||||||
verb `mesh.seat.<seat>.tool.<verb>`, the same followed by `.<node>`, and `mesh.seat.<seat>.call.<verb>.<node>.>`.
|
as §5 has them: `mesh.mod.<module>.tool.<tool>` and the same followed by `.*`; the caller-named subject mesh-sdk's
|
||||||
The bus's deny outranks its allow of `mesh.mod.<module>.tool.>` for each. The tool runner's version on a node is read from the
|
`process.Call` sends on first, `mesh.mod.<module>.call.<tool>.>`; for a marked verb of a seat held per node
|
||||||
same assignment half revision, its entry for `node-tools` on that node (the module version placed there, design 47
|
`mesh.seat.<seat>.tool.<verb>`, the same followed by `.<node>`, and `mesh.seat.<seat>.call.<verb>.<node>.>`; and for
|
||||||
G §175), against the version the node-engine's `running.<node>.node-tools` last said running (design 47 G §309);
|
a marked verb of a seat held once for the mesh `mesh.seat.<seat>.tool.<verb>` and `mesh.seat.<seat>.call.<verb>.>`,
|
||||||
readings that revision names from before that version ran are older. Going back to an older tool runner on a
|
since its subjects name no node (Q-DL). The bus's deny outranks its allow of `mesh.mod.<module>.tool.>` for each.
|
||||||
node leaves the window until its readings update, in which the old deny or none stands; that window is accepted. `Permissions` gains `SubscribeDeny`, written into the user list as the server's
|
Going back to an older tool runner on a node leaves the window until its readings update, in which the old deny or
|
||||||
subscribe deny, as `PublishDeny` is for publishing. The withheld tools and verbs are named in the grants part's read
|
none stands; that window is accepted. `Permissions` gains `SubscribeDeny`, written into the user list as the
|
||||||
of that account (`mesh-grants.grants_user_list`, a field `withheld` with each subject and "its tool runner does not
|
server's subscribe deny, as `PublishDeny` is for publishing; the user list's `User` gains `subscribe_deny` beside
|
||||||
state approval-mark/1"), and in the node-engine's `composition` of the module. *Why:* ADR 0286 §7, §8, §9: the bus
|
`publish_deny`, in its comparison and in the differences the grants part says (Q-SD). An added `subscribe_deny` is a
|
||||||
|
narrowing: the user-list guard lets it pass at once, on the first composition after the release, and counts it as
|
||||||
|
no right lost. The withheld tools and verbs are named in the grants part's read of that account
|
||||||
|
(`mesh-grants.grants_user_list`, a field `withheld` with each subject and "its tool runner does not state
|
||||||
|
approval-mark/1"), and in the node-engine's `composition` of the module, which reads them through a verb `withheld`
|
||||||
|
that the seat `mesh-grants`'s definition gains: class `read`, callers the node-engine, persons and the operator,
|
||||||
|
input `node`, answer each module's withheld subjects and why, with a fixture in the definition; the node-engine's
|
||||||
|
manifest gains `mesh-grants` in `uses`; when the verb does not answer, the composition says "withheld unknown: the
|
||||||
|
grants part does not answer"; never read from the grants part's state (Q-NE). *Why:* ADR 0286 §7, §8, §9: the bus
|
||||||
enforces the mark; the runner's status of ADR 0286 §7 is read from the grants part's account read, since a runner
|
enforces the mark; the runner's status of ADR 0286 §7 is read from the grants part's account read, since a runner
|
||||||
that does not honour the mark is a version that cannot say so. A call that reaches no responder because its
|
that does not honour the mark is a version that cannot say so. A reading is tied to the runner that made it, not to
|
||||||
|
a time, so a clock or a late reading cannot lift the deny (step 0b). A call that reaches no responder because its
|
||||||
subject is withheld is answered by the mesh MCP server naming `withheld` and the grants part's read. *How it is
|
subject is withheld is answered by the mesh MCP server naming `withheld` and the grants part's read. *How it is
|
||||||
checked:* unit, the grants part's composition table: readings lacking the capability, no readings, and readings
|
checked:* unit, the grants part's composition table: readings lacking the capability, no readings, readings with
|
||||||
older than the runner each compose the deny of every subject above, the caller-named ones and a marked seat verb's
|
another runner's fingerprint and readings with none each compose the deny of every subject above, the caller-named
|
||||||
`.<node>` form among them, each named in `withheld`; readings with the capability compose no deny; integration, the
|
ones, a marked seat verb's `.<node>` form and a mesh-wide seat's marked verb among them, each named in `withheld`;
|
||||||
|
readings with the capability and the running fingerprint compose no deny; the release's first composition passes
|
||||||
|
the user-list guard with the deny added; a node gaining `approval-mark/1`, where only its readings change, has the
|
||||||
|
deny removed; unit, the assigner's table: a reading keeps the announcing runner's fingerprint; whole (node-engine),
|
||||||
|
`composition` shows the withheld subjects, and with the grants part down says "withheld unknown"; integration, the
|
||||||
grants part's real-bus test: an account composed with the deny is refused delivery of a call on a marked subject
|
grants part's real-bus test: an account composed with the deny is refused delivery of a call on a marked subject
|
||||||
while it holds `mesh.mod.<module>.tool.>`, and so is a call sent through `process.Call` on the caller-named
|
while it holds `mesh.mod.<module>.tool.>`, and so is a call sent through `process.Call` on the caller-named
|
||||||
subject.
|
subject.
|
||||||
@@ -148,7 +181,7 @@ file; a node where the file is readable beyond the operator's account is a findi
|
|||||||
|
|
||||||
8. **The act is digested with operator-channel's client.** For a call of a marked tool or verb, the tool runner
|
8. **The act is digested with operator-channel's client.** For a call of a marked tool or verb, the tool runner
|
||||||
builds an `operatorchannelclient.Act` with `address` (as called), `node` (the node that serves it), `module` and
|
builds an `operatorchannelclient.Act` with `address` (as called), `node` (the node that serves it), `module` and
|
||||||
`tool`, or `seat` and `verb`, `build` (the digest of the bundle it serves the module from), and `arg.<name>` for each
|
`tool`, or `seat` and `verb`, `build` (the fingerprint the bundle's environment carries, the version it serves, §5; Q-BD), and `arg.<name>` for each
|
||||||
argument given, a string as itself and any other value as its JSON in RFC 8785's canonical form; an argument left
|
argument given, a string as itself and any other value as its JSON in RFC 8785's canonical form; an argument left
|
||||||
out is not in the act. Its digest is `operatorchannelclient.ActDigest`. *Why:* ADR 0286 §10, §11; the digest is in
|
out is not in the act. Its digest is `operatorchannelclient.ActDigest`. *Why:* ADR 0286 §10, §11; the digest is in
|
||||||
mesh-contracts since ADR 0627 §1. The TypeScript twin ADR 0286 named is not built: the tool runner is Go, and no
|
mesh-contracts since ADR 0627 §1. The TypeScript twin ADR 0286 named is not built: the tool runner is Go, and no
|
||||||
@@ -164,9 +197,11 @@ file; a node where the file is readable beyond the operator's account is a findi
|
|||||||
every asker today), is `<node>.`; never before the router's record it reads through `Record` and `Where`, whose key
|
every asker today), is `<node>.`; never before the router's record it reads through `Record` and `Where`, whose key
|
||||||
stays `<module>.<id>` in the seat state `asks`; unless an ask for the same act is
|
stays `<module>.<id>` in the seat state `asks`; unless an ask for the same act is
|
||||||
open there (§13's `act.` key), in which case it asks nothing new. The ask: `about` the act's digest; `who`
|
open there (§13's `act.` key), in which case it asks nothing new. The ask: `about` the act's digest; `who`
|
||||||
`operator`; `expires` 60 minutes after; no `on-expiry`; two options, `approve` (label Approve) and `decline` (label
|
`operator`; `expires` 60 minutes after; `on-expiry` "nothing runs; call again to ask anew", since the client's
|
||||||
|
`Check` refuses an authorising ask without it, and no option is taken on expiry (ADR 0286 §22; Q-OC2); two options, `approve` (label Approve) and `decline` (label
|
||||||
Decline), both at level `approve`, each binding the act's digest; the headline "Run <tool> on <node>?",
|
Decline), both at level `approve`, each binding the act's digest; the headline "Run <tool> on <node>?",
|
||||||
"Run <tool>?" when that is longer than the router allows, ending "Part shown" whenever an argument is not shown
|
"Run <tool>?" when that is longer than the router allows (`HeadlineLength`, 60), and, when that too is longer,
|
||||||
|
the names cut with "…" to fit (Q-HL), ending "Part shown" whenever an argument is not shown
|
||||||
whole; the explanation: the first line of the tool's own description, the node, that it was called through the
|
whole; the explanation: the first line of the tool's own description, the node, that it was called through the
|
||||||
mesh's tools, which cannot tell who called, every argument one per line as "name: value", and the act's
|
mesh's tools, which cannot tell who called, every argument one per line as "name: value", and the act's
|
||||||
fingerprint, its digest's first 24 hexadecimal digits in groups of four. *Why:* ADR 0286 §13, §15, §16, §20 to
|
fingerprint, its digest's first 24 hexadecimal digits in groups of four. *Why:* ADR 0286 §13, §15, §16, §20 to
|
||||||
@@ -188,22 +223,29 @@ file; a node where the file is readable beyond the operator's account is a findi
|
|||||||
called is named in the answer ("marked since <revision>"). *Why:* ADR 0286 §14, §37; the caller calls again, as
|
called is named in the answer ("marked since <revision>"). *Why:* ADR 0286 §14, §37; the caller calls again, as
|
||||||
the operator chose on 2026-11-11 ("Call again (as designed)") over a held call that runs on the Approve and returns
|
the operator chose on 2026-11-11 ("Call again (as designed)") over a held call that runs on the Approve and returns
|
||||||
its outcome (issue 417, 2026-10-16). *How it is checked:* unit,
|
its outcome (issue 417, 2026-10-16). *How it is checked:* unit,
|
||||||
rows of §22's table hold both answers; a row with no router holds that a second call asks nothing new.
|
rows of §22's table hold both answers; a row with no router holds that a second call asks nothing new; a row holds
|
||||||
|
a headline whose names are cut with "…" to 60 characters (Q-HL).
|
||||||
|
|
||||||
## The runner's record, and the same call again
|
## The runner's record, and the same call again
|
||||||
|
|
||||||
13. **The runner keeps its asks and claims in a state of its own, per machine.** The tool runner's manifest asks in
|
13. **The runner keeps its asks and claims in a state of its own, per machine.** The tool runner, a foundation part,
|
||||||
`requires` for a state `approvals`, template `state`, `per-machine`, `ttl-seconds` 172,800 (48 hours), cap 64 MiB.
|
declares a state `approvals` in its manifest's old `state` section, per machine, with a time to live of 172,800
|
||||||
|
seconds (48 hours), which the grants part creates as it creates a foundation part's states (ADR 0619 §2, §3; the bus
|
||||||
|
module refuses a per-machine state in the new form today). Its size is the old form's fixed one, 64 MiB
|
||||||
|
(`StateMaxBytes`), which §18 reads from the bucket, and a value is at most 256 KiB: an ask whose kept call would pass
|
||||||
|
it fails closed, naming the cause (ADR 0595 §3; Q-CAP). A runner whose membership binds no `approvals` serves every
|
||||||
|
unmarked call as before and refuses only marked ones (§19).
|
||||||
Its keys: `<node>.ask.<id>`, the asked call as the client keeps it (the ask, the act, the whole arguments, when
|
Its keys: `<node>.ask.<id>`, the asked call as the client keeps it (the ask, the act, the whole arguments, when
|
||||||
asked, whether acted on, and `recorded` once `warranted` answered, §16), and `<node>.act.<digest>`, the id of the
|
asked, whether acted on, and `recorded` once `warranted` answered, §16; the client's `Kept` gains `act`, `arguments`
|
||||||
|
and `recorded` for it, Q-KP), and `<node>.act.<digest>`, the id of the
|
||||||
newest ask for that act. The runner on each machine is the one writer of its machine's keys; a key is deleted by
|
newest ask for that act. The runner on each machine is the one writer of its machine's keys; a key is deleted by
|
||||||
its time to live, never by hand. A per-machine state reaches today only the key named for its machine; mesh-sdk's
|
its time to live, never by hand. A per-machine state reaches today only the key named for its machine; mesh-sdk's
|
||||||
per-machine form and the grants part's `stateAccess` gain the keys below it, `<node>.>`, for every per-machine
|
per-machine form and the grants part's `stateAccess` gain the keys below it, `<node>.>`, for every per-machine
|
||||||
state, a bundle's membership (`stateIssuedFor`, ADR 0260 §18) too, in the same form: one more subject per
|
state, a bundle's membership (`stateIssuedFor`, ADR 0260 §18) too, in the same form: one more subject per
|
||||||
per-machine state on each account, and every module's per-machine keys keep their form; mesh-sdk's rebuild of it
|
per-machine state on each account, and every module's per-machine keys keep their form; mesh-sdk's rebuild of it
|
||||||
rides in G's group. The cap is the bucket's, shared by every machine's keys. A write the bus refuses (the cap
|
rides in G's group. That size is the bucket's, shared by every machine's keys. A write the bus refuses (the size
|
||||||
reached, or any other) fails closed under §19 and is said in the answer; `mesh_approvals` reports the bucket's fill
|
reached, or any other) fails closed under §19 and is said in the answer; `mesh_approvals` reports the bucket's fill
|
||||||
against its cap, saying that the fill and the cap are every machine's together. A run still unrecorded (§16) an hour before its key's 48 hours end is written in the runner's log
|
against its size read from the bucket, saying that both are every machine's together. A run still unrecorded (§16) an hour before its key's 48 hours end is written in the runner's log
|
||||||
as an error naming the ask; this is written only while the runner runs, so a machine asleep through that hour keeps
|
as an error naming the ask; this is written only while the runner runs, so a machine asleep through that hour keeps
|
||||||
only the `call-unanswered` history of §16, which is accepted.
|
only the `call-unanswered` history of §16, which is accepted.
|
||||||
*Why:* ADR 0286 §24, §30 kept the waiting call in the runner's record and claimed a warrant in the node's own file,
|
*Why:* ADR 0286 §24, §30 kept the waiting call in the runner's record and claimed a warrant in the node's own file,
|
||||||
@@ -211,12 +253,15 @@ file; a node where the file is readable beyond the operator's account is a findi
|
|||||||
compare-and-set in a module's bus state (ADR 0259 §10, ADR 0627 §1), and a per-machine state (ADR 0595) is one
|
compare-and-set in a module's bus state (ADR 0259 §10, ADR 0627 §1), and a per-machine state (ADR 0595) is one
|
||||||
writer per machine, so the file is not built. The keys below the machine's own depart from ADR 0260 §16 (a
|
writer per machine, so the file is not built. The keys below the machine's own depart from ADR 0260 §16 (a
|
||||||
per-machine state reaches only its machine's key), the design's choice following the operator's answers of
|
per-machine state reaches only its machine's key), the design's choice following the operator's answers of
|
||||||
2026-11-11 (the gate built in G); the cap and the key form are the design's choices too. *How it is
|
2026-11-11 (the gate built in G); the key form is the design's choice too. *How it is
|
||||||
checked:* unit, the manifest test of `node-tools` holds the entry; the grants part's composition table holds the
|
checked:* unit, the manifest test of `node-tools` holds the old-form entry (per machine, its time to live) and no
|
||||||
|
`approvals` in `requires`; a row of §22's table: an ask over 256 KiB refused naming the cause; another: with no
|
||||||
|
binding, an unmarked call runs and a marked one is refused; the grants part's composition table holds the
|
||||||
`<node>.>` reach and no other node's; integration, §22's whole test reads the keys.
|
`<node>.>` reach and no other node's; integration, §22's whole test reads the keys.
|
||||||
14. **The same call again is judged on the router's record.** When a call of a marked tool comes and `<node>.act.`
|
14. **The same call again is judged on the router's record.** When a call of a marked tool comes and `<node>.act.`
|
||||||
names an ask, the runner reads the router's own record of that ask under the module's name (`Client.Where`, the
|
names an ask, the runner reads the router's own record of that ask under the module's name (`Client.Where`, the
|
||||||
seat state `asks`, key `<module>.<id>`), never a record of its own or the caller's; it composes the ask again from
|
seat state `asks`, key `<module>.<id>`, whose value in operator-channel's definition gains the `warrant` it already
|
||||||
|
carries, so the definition names what `Where` reads; Q-OC1), never a record of its own or the caller's; it composes the ask again from
|
||||||
the act and holds the warrant to it with `operatorchannelclient.For` (the same asker and ask, the ask's digest, a
|
the act and holds the warrant to it with `operatorchannelclient.For` (the same asker and ask, the ask's digest, a
|
||||||
person's choice, an option offered, at its level, before it expired); it requires the option to be `approve` and
|
person's choice, an option offered, at its level, before it expired); it requires the option to be `approve` and
|
||||||
the act to be the one it bound (`operatorchannelclient.Performs`: the same node, build and every argument); and it
|
the act to be the one it bound (`operatorchannelclient.Performs`: the same node, build and every argument); and it
|
||||||
@@ -231,15 +276,17 @@ file; a node where the file is readable beyond the operator's account is a findi
|
|||||||
16. **The call runs, and its warrant is recorded, across a restart too.** Once the checks pass, the runner runs the
|
16. **The call runs, and its warrant is recorded, across a restart too.** Once the checks pass, the runner runs the
|
||||||
call and answers with the tool's own answer and a line naming the approval ("run on the operator's approval via
|
call and answers with the tool's own answer and a line naming the approval ("run on the operator's approval via
|
||||||
<channel> at <time>, ask <id>"). It then calls `mesh-hand-acts.warranted` with `asker` (the module) and `ask` (the
|
<channel> at <time>, ask <id>"). It then calls `mesh-hand-acts.warranted` with `asker` (the module) and `ask` (the
|
||||||
id) as a kept call (ADR 0668 §1, §2: the verb takes it once per ask), and on its answer writes `recorded` on
|
id) as a kept call in mesh-sdk's kept-call form (ADR 0668 §1, §2, §7; design 47 G §351, §425: the verb takes it once
|
||||||
`<node>.ask.<id>`. At each start the runner calls `warranted` again for every acted, unrecorded ask its keys hold,
|
per ask), the key that keeps it open being `<node>.ask.<id>` without `recorded`, and no event replacing it; it is not
|
||||||
|
`busretry`, which stops after 30 seconds (Q-KC). On its answer the runner writes `recorded` on `<node>.ask.<id>`. At each start the runner calls `warranted` again for every acted, unrecorded ask its keys hold,
|
||||||
within their 48 hours, each named in its `findings-stated`'s `pending` until it is made (design 47 G §384). One
|
within their 48 hours, each named in its `findings-stated`'s `pending` until it is made (design 47 G §384). One
|
||||||
unanswered after five minutes is the runner's finding `<node>.<ask id>.call-unanswered` in its state `findings`,
|
unanswered after five minutes is the runner's finding `<node>.<ask id>.call-unanswered` in its state `findings`,
|
||||||
said on its stream `node-tools-findings` (design 47 G §383, §387), which the condition keeper hears; it clears when
|
said on its stream `node-tools-findings` (design 47 G §383, §387), which the condition keeper hears; it clears when
|
||||||
`warranted` answers. *Why:* ADR 0286 §34, §35; the hand-act log is the seat `mesh-hand-acts`, whose `warranted`
|
`warranted` answers. *Why:* ADR 0286 §34, §35; the hand-act log is the seat `mesh-hand-acts`, whose `warranted`
|
||||||
reads the router's own record, and its "again every ten minutes for a week" is ADR 0668's kept call now, kept
|
reads the router's own record, and its "again every ten minutes for a week" is ADR 0668's kept call now, kept
|
||||||
across a restart by the `recorded` mark (ADR 0668 §3, ADR 0564). *How it is checked:* integration, §22's whole test
|
across a restart by the `recorded` mark (ADR 0668 §3, ADR 0564). *How it is checked:* integration, §22's whole test
|
||||||
reads the hand-act recorded once, also when the runner is restarted after the run and before `warranted` answers.
|
reads the hand-act recorded once, also when the runner is restarted after the run and before `warranted` answers;
|
||||||
|
unit, §18's row of `record`.
|
||||||
17. **What a later call is told.** For the same call made again before it can run, the caller is told, as an error:
|
17. **What a later call is told.** For the same call made again before it can run, the caller is told, as an error:
|
||||||
still waiting; declined (the same act is not asked again for 10 minutes, and the answer says so); expired,
|
still waiting; declined (the same act is not asked again for 10 minutes, and the answer says so); expired,
|
||||||
approved too long ago or already run (each asks again, §15); not yet taken by the router (§12); or refused, with the
|
approved too long ago or already run (each asks again, §15); not yet taken by the router (§12); or refused, with the
|
||||||
@@ -251,22 +298,26 @@ file; a node where the file is readable beyond the operator's account is a findi
|
|||||||
with no argument, the calls asked on that machine in the last day, newest first, each with its state and
|
with no argument, the calls asked on that machine in the last day, newest first, each with its state and
|
||||||
fingerprint, read from §13's state, and the marks it applies, each module's marked tools and verbs with their
|
fingerprint, read from §13's state, and the marks it applies, each module's marked tools and verbs with their
|
||||||
source (its module's entry in the catalog half or its seat's definition) and the catalog revision read; given an ask's id, its whole
|
source (its module's entry in the catalog half or its seat's definition) and the catalog revision read; given an ask's id, its whole
|
||||||
arguments and the act's digest; given `cancel` and an ask's id, it takes that open ask back (`Client.Cancel`),
|
arguments and the act's digest; given `record` and an ask's id, it asks `warranted` again for that one ask by hand,
|
||||||
recorded first in the hand-act log through `mesh-hand-acts.hand-act` with who and why, and refused when the record
|
in the kept-call form of §16, recorded in the hand-act log first; given `cancel` and an ask's id, it takes that open ask back (`Client.Cancel`),
|
||||||
|
recorded first in the hand-act log through `mesh-hand-acts.hand-act` with why, the verb taking who from the caller
|
||||||
|
it proves (Q-HA), and refused when the record
|
||||||
cannot be written. `mesh_describe` answers, for a marked tool or verb, `needs-approval` with its source. *Why:*
|
cannot be written. `mesh_describe` answers, for a marked tool or verb, `needs-approval` with its source. *Why:*
|
||||||
ADR 0286 §25 (the runner's `approvals`), named as the mesh MCP server's own tools are; a tool reads everything a
|
ADR 0286 §25 (the runner's `approvals`), named as the mesh MCP server's own tools are; a tool reads everything a
|
||||||
module holds and does by hand what it does by itself (the operator's instruction of 2026-10-25). *How it is
|
module holds and does by hand what it does by itself (the operator's instruction of 2026-10-25). *How it is
|
||||||
checked:* unit, rows in the mesh MCP server's tool table test: the list, the marks with their sources, an ask read
|
checked:* unit, rows in the mesh MCP server's tool table test: the list, the marks with their sources, an ask read
|
||||||
whole, a cancel recorded and one refused without a record, and `mesh_describe` of a marked tool.
|
whole, a `record` that asks `warranted` again for one ask, a cancel recorded and one refused without a record, and
|
||||||
|
`mesh_describe` of a marked tool.
|
||||||
|
|
||||||
## Failing closed
|
## Failing closed
|
||||||
|
|
||||||
19. **Nothing runs when a part of the check is missing, and a stuck gate is said.** A call of a marked tool is
|
19. **Nothing runs when a part of the check is missing, and a stuck gate is said.** A call of a marked tool is
|
||||||
refused, runs nothing and says why when: no module holds `operator-channel` (read from the assigner's first view
|
refused, runs nothing and says why when: no module holds `operator-channel` (read from the assigner's first view
|
||||||
`mesh-delivery-assigner.views.seat-holders`, which the tool runner consumes; the seat list names no holders); the
|
`mesh-delivery-assigner.views.seat-holders`, which the tool runner consumes; the seat list names no holders); the
|
||||||
|
served entry of the module cannot be read (§5), which refuses every marked call on that runtime; the
|
||||||
router refuses the ask; the ask cannot be published; the router's record cannot be read; §13's state cannot be read
|
router refuses the ask; the ask cannot be published; the router's record cannot be read; §13's state cannot be read
|
||||||
or written, in which case no marked call runs on that machine until it can, the failed read or write being made
|
or written, in which case no marked call runs on that machine until it can, the failed read or write being made
|
||||||
again as a kept call (ADR 0668 §1) until it succeeds; or the marks are not yet read. Before
|
again in the kept-call form (ADR 0668 §7; design 47 G §351), kept open by the failing key, until it succeeds; or the marks are not yet read. Before
|
||||||
the first view of the catalog half is read, a call waits for it within its 5 seconds and is then judged, asking
|
the first view of the catalog half is read, a call waits for it within its 5 seconds and is then judged, asking
|
||||||
nothing while the marks are unread; still unread, it is refused, naming `mesh_first_views`. When §13's state has
|
nothing while the marks are unread; still unread, it is refused, naming `mesh_first_views`. When §13's state has
|
||||||
been unreadable or unwritable for five minutes, the runner raises its finding `<node>.approvals.approvals-unreadable`
|
been unreadable or unwritable for five minutes, the runner raises its finding `<node>.approvals.approvals-unreadable`
|
||||||
@@ -275,11 +326,16 @@ file; a node where the file is readable beyond the operator's account is a findi
|
|||||||
written in the runner's log with the ask's id and fingerprint, never the arguments. *Why:* ADR 0286 §40, §42; a
|
written in the runner's log with the ask's id and fingerprint, never the arguments. *Why:* ADR 0286 §40, §42; a
|
||||||
gate that refuses every call for a reason nobody hears is a silent fault, and the finding and its five minutes are
|
gate that refuses every call for a reason nobody hears is a silent fault, and the finding and its five minutes are
|
||||||
the design's choice. *How it is checked:* unit, one row of §22's table per case, the holder read from a fixture
|
the design's choice. *How it is checked:* unit, one row of §22's table per case, the holder read from a fixture
|
||||||
`views.seat-holders` with none and with one; and a row where the state fails, the finding is raised after five
|
`views.seat-holders` with none and with one; a row where the served entry cannot be read and every marked call on
|
||||||
|
that runtime is refused; and a row where the state fails, the finding is raised after five
|
||||||
minutes, the state recovers with no further call, and the finding clears.
|
minutes, the state recovers with no further call, and the finding clears.
|
||||||
20. **The terminal is not exempt.** A marked tool called through `mesh-cli` or any caller asks as every call does: the
|
20. **The terminal is not exempt.** A marked tool called through `mesh-cli` or any caller asks as every call does: the
|
||||||
runner cannot tell who called. *Why:* ADR 0286 §41. *How it is checked:* the code review reads that the gate sits
|
runner cannot tell who called. *Why:* ADR 0286 §41. The gate wraps every handler the runner serves, a bundle's
|
||||||
on the call's handler, before the bundle, and that no path to a bundle passes around it.
|
tools and seat verbs and the runner's own tools beside them (the ledger repairs) alike (Q-LR); the act, the ask,
|
||||||
|
the check, the claim, the recording and the refusals of §8 to §19 are all in `node-tools/internal/approval` (Q-PK).
|
||||||
|
*How it is checked:* the code review reads that the gate sits on every handler, before the bundle, and that no path
|
||||||
|
to a bundle or a runner's own tool passes around it; unit, a row of §22's table: a runner's own tool marked in a
|
||||||
|
fixture is refused unasked, never run.
|
||||||
|
|
||||||
## Marked first
|
## Marked first
|
||||||
|
|
||||||
@@ -287,10 +343,11 @@ file; a node where the file is readable beyond the operator's account is a findi
|
|||||||
marks the verb `execute` with `needs-approval`; the zsh module's manifest (mesh-catalog `modules/zsh`), which holds
|
marks the verb `execute` with `needs-approval`; the zsh module's manifest (mesh-catalog `modules/zsh`), which holds
|
||||||
the seat, gains `operator-channel` in `uses`. The control-node keeps withholding `execute`, and whether it serves
|
the seat, gains `operator-channel` in `uses`. The control-node keeps withholding `execute`, and whether it serves
|
||||||
it again under the mark stays the operator's setting. *Why:* ADR 0286 §44, §45: the reads it carried have their
|
it again under the mark stays the operator's setting. *Why:* ADR 0286 §44, §45: the reads it carried have their
|
||||||
tools on every node (the seat `node-reads`, ADR 0310; issue 418 resolved 2026-10-12, answering on every node since
|
tools on every node (the seat `node-reads` of issue 418, resolved 2026-10-12, which `node-files` replaces whole, ADR
|
||||||
2026-10-16). *How it is checked:* live, as the acceptance says.
|
0394 §9). *How it is checked:* live, as the acceptance says.
|
||||||
- **The forge's two acts on a trunk's protection are marked.** The forge module (mesh-catalog `modules/gitea`)
|
- **The forge's two acts on a trunk's protection are marked.** The forge module (mesh-catalog `modules/gitea`)
|
||||||
gains a tool `gitea_branch_protection_loosen`, marked in its `needs-approval`, which alone performs the two acts
|
gains a tool `gitea_branch_protection_loosen`, marked in its `needs-approval`, taking `owner`, `repo`, `branch`,
|
||||||
|
`act` (`remove-protection` or `allow-force-push`) and `why` (Q-FG), which alone performs the two acts
|
||||||
`gitea_branch_protection_set_full` refuses today: removing a trunk's protection, and allowing a force-push onto
|
`gitea_branch_protection_set_full` refuses today: removing a trunk's protection, and allowing a force-push onto
|
||||||
a trunk; `gitea_branch_protection_set_full` keeps refusing both and its refusal names the new tool. The manifest
|
a trunk; `gitea_branch_protection_set_full` keeps refusing both and its refusal names the new tool. The manifest
|
||||||
gains `operator-channel` in `uses`. No other tool or verb is marked in this milestone. *Why:* the forge's own
|
gains `operator-channel` in `uses`. No other tool or verb is marked in this milestone. *Why:* the forge's own
|
||||||
@@ -300,9 +357,17 @@ file; a node where the file is readable beyond the operator's account is a findi
|
|||||||
principle: loosening a trunk's protection runs only on the operator's own warrant for that one act, never on a
|
principle: loosening a trunk's protection runs only on the operator's own warrant for that one act, never on a
|
||||||
session's word. Its bound: a process that reads the forge module's own credential speaks to the forge directly
|
session's word. Its bound: a process that reads the forge module's own credential speaks to the forge directly
|
||||||
and goes around it, the same known limit as issue 1966 note 193; the prepare reads that credential's mode and
|
and goes around it, the same known limit as issue 1966 note 193; the prepare reads that credential's mode and
|
||||||
owner on the forge's node with `<node>/node-reads.stat` and writes them in the milestone file. *How it
|
owner on the forge's node with `<node>/node-files.stat` (§21a) and writes them in the milestone file. *How it
|
||||||
is checked:* the forge module's tool test: `set_full` refuses both acts naming the new tool; the new tool
|
is checked:* the forge module's tool test: `set_full` refuses both acts naming the new tool; the new tool
|
||||||
performs each; and live, as the acceptance says.
|
performs each; and live, as the acceptance says.
|
||||||
|
21a. **`node-files.stat` answers a mode under a directory the account cannot enter.** The seat `node-files`' holder
|
||||||
|
(mesh-catalog `modules/mesh-files`) answers `stat` of a path its account cannot reach through `sudo -n` with its
|
||||||
|
fixed `/usr/bin/stat`, as its writes already go (ADR 0394 §2), answering the path's mode, owner, group and kind and
|
||||||
|
nothing of its content; the secret places ADR 0394 §7 names are stated, never read. Its README's "not yet through
|
||||||
|
sudo" loses `stat`. *Why:* the prepare could not read the forge credential's mode (step 0b); ADR 0394 §2 has the
|
||||||
|
holder use sudo where it must. The lead's handover named the retired `node-reads` (ADR 0394 §9), whose successor this
|
||||||
|
is. *How it is checked:* unit, a row in mesh-files' `Stat` test: a file under a directory of mode 0700 owned by
|
||||||
|
another account answers its mode and owner through sudo, with no content.
|
||||||
|
|
||||||
## Tests, delivery and going back
|
## Tests, delivery and going back
|
||||||
|
|
||||||
@@ -313,15 +378,19 @@ file; a node where the file is readable beyond the operator's account is a findi
|
|||||||
operator's Approve written as the router's record, the call again, the run, the hand-act, `mesh_approvals`, and a
|
operator's Approve written as the router's record, the call again, the run, the hand-act, `mesh_approvals`, and a
|
||||||
restart between the run and `warranted`'s answer. The client's `KeyPrefix` (§10) has a row in mesh-contracts'
|
restart between the run and `warranted`'s answer. The client's `KeyPrefix` (§10) has a row in mesh-contracts'
|
||||||
client test: every key of its own `State` written and read carries it, an empty prefix writes today's keys, and
|
client test: every key of its own `State` written and read carries it, an empty prefix writes today's keys, and
|
||||||
with a prefix set `Where` still reads `<module>.<id>`. *Why:* the operator's test budget (one whole test over many small
|
with a prefix set `Where` still reads `<module>.<id>`. The mesh MCP server's `TestMeshWaitIsAnnouncedAmongSeven` counts eight
|
||||||
ones). *How it is checked:* the check counts the module's tests against its budget.
|
tools with `mesh_approvals` (Q-T). New test functions are allowed within each module's budget of 500 unit and 50
|
||||||
|
integration tests, and a module over it shrinks toward it with each change (Q-TB). *Why:* the operator's test
|
||||||
|
budget (one whole test over many small ones). *How it is checked:* the check counts each module's tests against
|
||||||
|
its budget.
|
||||||
23. **In G's delivery group, ordered by the module graph.** The members are pushed and checked in design 47 milestone
|
23. **In G's delivery group, ordered by the module graph.** The members are pushed and checked in design 47 milestone
|
||||||
G's group, with design 34's milestone every-event. The orders are the module graph's: the indexer's manifest
|
G's group, with design 34's milestone every-event. The orders are the module graph's: the indexer's manifest
|
||||||
validator and catalog graph entry that read `needs-approval` before any manifest or seat definition carrying it (a
|
validator and catalog graph entry that read `needs-approval` before any manifest or seat definition carrying it (a
|
||||||
reader edge, design 47 G §89); and the grants part that composes the deny of §6 before the seat definition marking
|
reader edge, design 47 G §89, whose list covers `needs-approval`; Q-RE); and the grants part that composes the deny of §6 before the seat definition marking
|
||||||
`execute` (an edge of the seat definition's readers), so no machine serves `execute` unasked between the two.
|
`execute` (an edge of the seat definition's readers), so no machine serves `execute` unasked between the two; and
|
||||||
|
the grants part serving `withheld` before a node-engine calls it (a served-verb edge, §6).
|
||||||
*Why:* the operator, 2026-11-11, "Build the gate in G"; the operator, 2026-11-03, a change is designed as it should
|
*Why:* the operator, 2026-11-11, "Build the gate in G"; the operator, 2026-11-03, a change is designed as it should
|
||||||
be and its delivery is the delivery system's. *How it is checked:* the delivery plan names both edges.
|
be and its delivery is the delivery system's. *How it is checked:* the delivery plan names the three edges.
|
||||||
24. **Going back is going forward.** A fault met after the delivery is fixed by a new change delivered the same way.
|
24. **Going back is going forward.** A fault met after the delivery is fixed by a new change delivered the same way.
|
||||||
Reverting instead reverts G's whole group in the reverse of §23's order: the seat definition's mark first, then the
|
Reverting instead reverts G's whole group in the reverse of §23's order: the seat definition's mark first, then the
|
||||||
grants part, then the validator. The `approvals` state is then declared by no running module: it is an orphan
|
grants part, then the validator. The `approvals` state is then declared by no running module: it is an orphan
|
||||||
@@ -341,6 +410,8 @@ file; a node where the file is readable beyond the operator's account is a findi
|
|||||||
`gitea_branch_protection_loosen` removing the trunk's protection answers "Not run" and asks on the phone; after the
|
`gitea_branch_protection_loosen` removing the trunk's protection answers "Not run" and asks on the phone; after the
|
||||||
Approve the same call runs once; then `gitea_branch_protection_set_full` sets the full protection again and
|
Approve the same call runs once; then `gitea_branch_protection_set_full` sets the full protection again and
|
||||||
`gitea_branch_protection_get` reads it back as it was (§21).
|
`gitea_branch_protection_get` reads it back as it was (§21).
|
||||||
|
- **A dropped mark still asks while the old bundle runs** (live, read by tool call): a delivery that drops a module's
|
||||||
|
mark asks a call of that tool until the node runs the new bundle, read with `mesh_approvals` (§5).
|
||||||
- **No machine serves `execute` unasked** (live, read by tool call): before this acceptance passes, on every node
|
- **No machine serves `execute` unasked** (live, read by tool call): before this acceptance passes, on every node
|
||||||
`execute` is either asked as above or absent, read with each node's `node-engine.composition` and
|
`execute` is either asked as above or absent, read with each node's `node-engine.composition` and
|
||||||
`mesh-grants.grants_user_list`'s `withheld` (§6).
|
`mesh-grants.grants_user_list`'s `withheld` (§6).
|
||||||
|
|||||||
Reference in New Issue
Block a user