Designs 25, 51: write what review round 1 settled (acted key, ask lifetime, loopback bootstrap, shared idle drop, shared-digest tag, forge account removal)

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
2026-11-04 17:32:21 +01:00
parent 8f75606167
commit c3d8367b33
2 changed files with 26 additions and 5 deletions
+8 -2
View File
@@ -938,8 +938,14 @@ channel's `decided` for the asker that raised the ask (ADR 0259 §6; ADR 0620 §
hears its own `decided` through `consumes` on a durable consumer and runs its pass over the waiting `recreate` and
`drop` requests when one arrives, so a warranted `drop` acts within seconds of the operator's answer, and one given
while the process was down is heard when it is back. **A warrant acts once** (ADR 0259 §6): before it acts, the
process claims the warrant's ask id in its own state by a compare-and-set, and a request naming an ask it already
acted on is refused, deleting nothing and saying which act that warrant already performed. `create` and `apply` need no warrant, since they only make or grow what an accepted manifest
process claims the warrant's ask id by writing the key `acted.<ask id>` in its own state `requests` (no new state),
created by compare-and-set after the snapshot and before any deletion, and a request naming an ask it already
acted on is refused, deleting nothing and saying which act that warrant already performed. **An ask lasts 12 hours**,
shorter than the 24 hours `requests` keeps a request: a request whose ask ended unanswered is ended and said, and a
warrant is not acted on once its ask ended; the tool raises the ask before it hands the request over. A request
that cannot act yet says why in its field Waiting, and a hand act the process could not record is written on the
request in its field Unrecorded. The tool `nats_requests` reads the waiting and ended requests and the warrants
spent, and drops a waiting request by hand, recorded as a hand act. `create` and `apply` need no warrant, since they only make or grow what an accepted manifest
asks for, and the process refuses either for an entry no accepted manifest asks for. A tool acts only for a caller
whose role grants it; the process records each act as a hand act (`mesh-hand-acts`) and answers what it did. What
stands between the tool runner's account and the process's delete power is that check of the warrant, so its tests
@@ -141,7 +141,12 @@ the verb.
own object store `incoming`, asked for as bus state in its manifest (design 25 § 12) with a cap of 8 GiB, the most the
objects template allows (design 25 § 12.1), and no lifetime, since that template keeps for good; the holder counts its
fill against the cap its binding carries, never a number of its own. The holder itself drops a transfer with no part
for 24 hours and deletes its parts (ADR 0611 §3), so an abandoned transfer does not stay. The holder hashes every part and refuses one whose bytes do not
for 24 hours and deletes its parts (ADR 0611 §3), so an abandoned transfer does not stay. **Both are mesh-sdk's
`parts.Receiver`, shared by every holder** (ADR 0611 §3), never copied into a holder: an expiring key per open
transfer, in a state of the holder with a key lifetime, is armed when a transfer is opened or opened again, and its
expiry (an event, never a timer) drops the transfer with its parts, or arms it again for the rest of the day if a
part came; a key that cannot be written fails the opening loudly. The cap is read once from the binding's fill and
kept; only where no binding is read does the holder state the 8 GiB it asked for. The holder hashes every part and refuses one whose bytes do not
match its digest. At 80 % of the cap it writes a finding (cleared below 80 %); at the cap it refuses a new transfer
with `refused` naming the cap. Its tool `registry_incoming` lists open transfers and the fill, and drops one by hand.
- **The holder asks the builder**, through `builder_versions`, whether the name, version and digest are recorded, and
@@ -163,6 +168,10 @@ the verb.
want whose build carries it reaches a node only once that node's engine states the capability to read both forms
and both seat names; the assigner holds the node's want meanwhile and names the capability as the reason, and a
node away keeps its want and catches up on return (ADR 0612 §2, made general by ADR 0614 §4).
- **The forge's accounts and teams are what the catalog declares.** The forge module removes, at each start and
when its teams change, the teams and the accounts of the retired per-node package-reading form that nothing
declares any more; one the forge refuses to delete because it owns something has its login prohibited. How it is
checked: after a delivery the forge module's team and account tools list none of them.
- **No build module holds a registry's write credential** (ADR 0605 §5). The npm write token goes. The image push
credential and the artifact store's write binding that ADR 0605 §5 revokes do not exist today: the store takes
writes from any process on the mesh network, so the rule protects nothing until its write side is closed. So
@@ -438,7 +447,10 @@ modules' manifests for such an edge. The done keys written in the new form stay
revert and are not built again for their form; each still carries every form a counted node-engine states, the
oldest in its single reference, so a node is held from them only when its engine reads none of those forms (ADR 0624
§1-3). **On a fresh mesh** the foundation's bootstrap (research 075) pushes the holders' own images
with a one-off credential of the bootstrap, discarded once the holders serve `publish`.
to the store on its node's loopback, with no credential, as the publish contract allows for a write that reaches the
store from its own node, and records their references under the seat's reach. No one-off credential exists: the
node-engine writes no push credential and the holder's front keeps no bootstrap token. How the rest of the bootstrap
goes is research 075's.
### Acceptance tests
@@ -451,7 +463,10 @@ test).
- **Builder.** A branch pushed with no ask publishes nothing; a lone pull request's check publishes nothing; a group
introducing a new package takes `0.1.0-<tag>.1`; the checker's `tag-wanted` yields `numbered` and `published`, and
members are built only after `published`; no `published` in 10 minutes fails the check naming the package;
`builder_untag` removes a branch's tagged versions with `removed`; a `remove` while the holder is down is retried and
`builder_untag` removes a branch's tagged versions with `removed`; a tagged version whose digest another tag names
keeps its tag on the store pinned today (a registry that cannot remove a tag alone), `removed` is said with that
reason and the builder records it gone, and its bytes go with the other tag's removal, the move to a registry that
removes a tag alone being the next milestone's; a `remove` while the holder is down is retried and
past 15 minutes writes its finding; a late `published` after the bound writes the done key; `builder_publish_again`
after the build's file is gone builds again under the same number; with the seat's holder stopped at a first claim
nothing is numbered and the finding names it; two merges claimed in reverse order are numbered in merge order; a