ADR 0259: name the confirmation review's N1 findings and their fixes — an early desk unlink bars nothing, a trusted party's secret is never given at a desk — and root-free answered by the serving controller alone, a silence never ending an approval, the link bound's residual risk
This commit is contained in:
+53
-5
@@ -239,7 +239,13 @@ operator, via telegram, user id verified"), the channel module, the proofs prese
|
||||
met, and when. It carries no secret.
|
||||
|
||||
- **The asker acts once per ask id**, keeping that in its own record, and only on a warrant from its own
|
||||
`decided` subject.
|
||||
`decided` subject. A warrant that says no time it was given, or for an ask that says no expiry, is refused:
|
||||
neither can be shown to be in time (the confirmation review of 2026-10-09).
|
||||
- **A silence never takes an approval back** (the confirmation review of 2026-10-09, M1). The controller
|
||||
asks a condition's acknowledgements (Silence) apart from its approvals (Release, Stop, Restart), and choosing
|
||||
Silence silences the condition; the first build then took the approval ask back as no longer wanted, so an
|
||||
acknowledgement, which a desk click may give, ended an approval. An approval asked about a condition that is
|
||||
silenced since stays open, unchanged, until it is answered on a channel that proves who answered, or expires.
|
||||
- **A warrant authorises one act, as the person was shown it** (added on 2026-10-09, before the code was
|
||||
merged). Every option above `acknowledge` carries the digest of exactly what the asker performs when it is
|
||||
chosen — the verb, the machine and every argument (`binds`); an ask without it is refused at the router.
|
||||
@@ -286,7 +292,8 @@ met, and when. It carries no secret.
|
||||
channel and no router record keeps a copy, the desk channel stores none and hands it to the node's
|
||||
notifier as transient, and the notifier keeps it out of its history, where an agent could read it later.
|
||||
- **The desk channel runs as an account of its own**, like the router and Telegram (§8 rule 1): the codes
|
||||
pass through it.
|
||||
pass through it. Registration holds every holder of a `private` kind to it, as it holds a `verified-sender`
|
||||
holder (the confirmation review of 2026-10-09).
|
||||
- **One identity per kind.** A second link of a kind is refused until the first is unlinked.
|
||||
- **Unlinking is an approve ask, answered on the account that is linked** (revised after the security
|
||||
review of 2026-10-08). It is never a plain tool: whoever unlinks the operator's account could link one of
|
||||
@@ -301,7 +308,11 @@ met, and when. It carries no secret.
|
||||
- **Linking is bounded**: at most three links asked per account an hour and ten per kind, counted in the
|
||||
router's own state so a restart forgets nothing (a count that cannot be read or written refuses the link); the code's notice on the desk names the account by
|
||||
the name and the number the service gives, and only a channel declaring `private` (the desk) may show a
|
||||
code.
|
||||
code. **A residual risk of the bound, accepted** (the confirmation review of 2026-10-09): anyone may make
|
||||
throwaway accounts and send the bot `/start` ten times in an hour, so the operator's own link is refused
|
||||
for the rest of that hour. It denies a link, never makes one, and every refused link is said; the operator
|
||||
links when the hour has passed. A bound per sender alone would let the same throwaway accounts flood the
|
||||
desk with codes, which is worse.
|
||||
- **The ask to unlink or relink binds the account**, not only the kind (added on 2026-10-09): a warrant for
|
||||
unlinking one account never unlinks the one linked after it. A link re-checks that its kind has no account
|
||||
when it is made, and an account just unlinked cannot link again at once from a code shown before.
|
||||
@@ -310,6 +321,14 @@ met, and when. It carries no secret.
|
||||
while one is in its first hour, the router asks at the desk, as an acknowledgement bound to that account,
|
||||
whether to unlink it, and tells the sender so. If the hour has passed when the answer arrives, the unlink
|
||||
is refused. After the hour, unlinking needs the linked account's approval, or break-glass.
|
||||
- **An unlink at the desk in the first hour bars nothing** (the confirmation review of 2026-10-09, finding
|
||||
N1-router). A desk click is anyone's at the desk machine — a program there can forge one — and the first
|
||||
build barred the unlinked account for a day and made the next link wait for it. Another account's `/start`
|
||||
offered the desk the unlink, a forged click took it, and the operator's own account stayed barred, again
|
||||
and again, so the operator could never approve. Now such an unlink lets any account, the operator's too,
|
||||
link again at once with a code shown on the desk. **The day's bar is set only by an unlink the account
|
||||
itself approved, or root's**; root's `allow-link` at the router's machine lifts any bar. What is said on
|
||||
every channel names which it was.
|
||||
- **A new link answers `acknowledge` at once and `approve` only after one hour.** The hour runs from the
|
||||
moment the link is made, is kept in the identity's record, and is said in the announcement ("it can
|
||||
approve from 15:40"). An approve answer inside the hour is refused and said on the channel. Decided by
|
||||
@@ -380,8 +399,20 @@ with the router not knowing its own machine, it approved. Now:
|
||||
approve option and again when an approve answer arrives; an error, a missing machine, or a router that does
|
||||
not know its own machine is not a pass. **The controller asks it too when it composes**, and strips
|
||||
`verified-sender` from a kind without a pass; the router's live question covers a pass that ends between
|
||||
compositions. The `agent-root` condition is raised on the same judgement, so the condition and the verb
|
||||
never disagree.
|
||||
compositions. The `root-not-free` condition is raised on the same judgement, so the condition and the
|
||||
verb never disagree.
|
||||
- *Added after the confirmation review of 2026-10-09.* **Only the serving controller answers `root-free`.**
|
||||
Composed from the controller's own manifest, the module principal of the machine running the controller
|
||||
and that machine's runtime were granted the controller seat's verbs too, and that runtime's credential is
|
||||
one an agent there may hold. The controller's own seat is now served by the controller's principal alone,
|
||||
in grants and in memberships, and a grant test composes every principal and finds exactly one that may
|
||||
answer `root-free`. **A machine waiting for its node-engine's first setuid search is not root-free**
|
||||
(ADR 0266 keeps the self-check quiet for that bound after a restart; `root-not-free` keeps the same quiet,
|
||||
and the verb still answers no). The condition has its own key, apart from ADR 0266's
|
||||
`agent-can-become-root`, which a second probe wrote under the same key with other words. **The router asks
|
||||
`root-free` before it takes its work**, never while holding it — a controller slow to answer held every
|
||||
ask, answer and link behind it — and judges an answer with the word it was given then; inside the work it
|
||||
reads only a word under half a minute old, and an ask that failed drops the last word.
|
||||
|
||||
**3. What remains, said plainly.**
|
||||
|
||||
@@ -459,6 +490,18 @@ with the router not knowing its own machine, it approved. Now:
|
||||
from words a caller chose, and says the controller asks; the bus lets only the controller publish the
|
||||
prompt's verb; no secret value is accepted through a verb otherwise; and every value given raises the
|
||||
urgent condition `secret-given` on every channel until the operator silences it.
|
||||
**A trusted party's secret is never given at a desk** (the confirmation review of 2026-10-09, finding
|
||||
N1-give). The desk prompt's answer comes back over the desk machine's bus, on the subject that machine's
|
||||
runtime answers, and on a desk machine agents run as the operator, who holds that runtime's credential:
|
||||
an agent called `give` for the bot token and answered the prompt first with a token of its own, sealed to
|
||||
the call's key, and the channel the operator's answers are proven on became the agent's. Now the secret of
|
||||
a module running as an account of its own (the router, Telegram, the desk channel) is refused at the desk
|
||||
before anybody is asked, naming the line to type at the controller's terminal instead —
|
||||
`mesh-controller secret accept <node> telegram telegram-token`, read without echo. There it is announced
|
||||
on every channel, the one being replaced among them (it still runs on its old token until the next push),
|
||||
**before** it is kept, and not kept when that announcement fails. A grant test holds that only the desk
|
||||
machine's launcher, carried by that machine's runtime, may answer its prompt; for any other module's
|
||||
secret that remains the accepted risk of a desk where agents run as the operator.
|
||||
|
||||
**Where an ask can be answered is said by the router**, from the channels that qualify: "Answer on
|
||||
Telegram, or from the mesh MCP server." The asker's words never name a channel.
|
||||
@@ -511,6 +554,11 @@ Telegram, or from the mesh MCP server." The asker's words never name a channel.
|
||||
| A tool call never publishes an intake event or a proof | tool runner test: only a bundle's own channel reaches the seat publish, for its own kind |
|
||||
| The asker acts once per warrant and records the warrant | shared library test; controller test reading the hand-act after a warrant |
|
||||
| A warrant authorises only the act its option bound, for the ask as it was shown | shared library tests (`TestAWarrantAuthorisesOnlyTheActItsOptionBound`); controller test (`TestAWarrantPerformsOnlyTheActItsOptionBound`); router test (the warrant names the ask's digest) |
|
||||
| Only the serving controller answers `root-free`; a machine waiting for its first setuid search is not root-free | controller grant test `TestOnlyTheServingControllerMayAnswerRootFree` (one answerer); `TestAMachineWaitingForItsFirstSetuidSearchIsNotRootFree`; `TestRootNotFreeIsQuietWhileTheFirstSearchRunsAndKeyedApartFromDA` |
|
||||
| A desk unlink in the first hour bars nothing; root lifts any bar (N1-router) | router tests `TestAnUnlinkFromTheDeskInTheFirstHourBarsNothing`, `TestBreakGlassLiftsABarOnRelinking` |
|
||||
| A trusted party's secret is never given at a desk; only the desk machine's launcher answers its prompt (N1-give) | controller tests `TestATrustedPartysSecretIsNeverTakenAtADesk`, `TestOnlyTheDeskMachinesLauncherMayAnswerItsPrompt` |
|
||||
| A silence never takes an approval back (M1) | controller test `TestAnAcknowledgementNeverSharesAnAskWithAnApproval`, with the condition silenced as the controller silences it |
|
||||
| The router never waits on the controller while holding its work | router test `TestTheRootFreeWordIsNotAskedWhileTheWorkIsHeld` |
|
||||
| The self-check counts the login shell only where `execute` is served, and what it cannot measure fails | controller probe tests (`TestTheLoginShellCountsOnlyWhereExecuteIsServed`, the unmeasured case) |
|
||||
| The whole flow, before anyone uses it | the lab's proof `asks` (mesh-lab): a real bus with the controller's composed grants, the router and the Telegram channel in runtimes of their own accounts, a fake Telegram API — approve acted once, decline, expiry, a replayed tap, a tap from another account, a forged warrant, an ask under another name, an ask from a module that may not ask |
|
||||
| The controller holds no channel code | review; the controller's module imports no channel package |
|
||||
|
||||
Reference in New Issue
Block a user