Decode refused any field it did not know, so every reader on an older
mesh-sdk refused a key the moment a writer added one (plan, this release).
It now reads past it and drops it; Encode still writes the layout alone, so
no value rides in a provision (issue 1126 review 1).
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The seat keys a consumer's provisions from its wanted and newest builds but
keeps the plan of its wanted build alone, and the provider helper bound only
from plans: a requirement the newest build adds stayed asked with no word,
and the want waiting for it never moved (mcp-endpoint on ace and shanks).
A provision now carries the plan entry it was composed from; the helper
binds from it where no plan names the key, the plan winning where both do,
and says each key it can bind from neither (issue 1126 review 1).
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The upgrade verb's compare answers each node's own composition and the assigner's findings, not
a policy against the controller's; tokens no longer says whether issuing is on, since no lease
gates it; the composed configuration names the grants part, not the controller (ADR 0590).
Issue 1126 B1, B3a.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0590 clause 3 ends the take-over and the hand-back, and with them compare: the readers follow
the keeper, and config its own sources, with no switch to ask. Issue 1126 B1.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The take-over key chose between the controller's conditions and the keeper's; ADR 0590 clause 3
ends that choice, so readers hear the keeper (KeeperSeat) and the self-check (SelfCheckSeat)
alone and the key, its version and its two sources go. The controller's hand-act log, its
show verb, its kept announcements and its assignments mirror's name go too, and the hand-act
recorder's unread LeaseAway. Issue 1126 B4b.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The controller ended (ADR 0590): the grants issued are the grants part's alone, so its grant value
is Grant and GrantSource goes; a node trusts the vault's key alone, follows the grants part's
user list alone and composes its own or none; the controller's composed and builds bucket names
go. nox calls seat verbs (ADR 0590 clause 7), so the cli package that spoke to the node-engine's
socket goes, and mesh-hand-compose, which wrote the controller's compositions. A have an engine
from before wrote, composes controller, still reads. Issue 1126 B4a, B6.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The controller ended (ADR 0590): nothing consumes what nodes report on CONTROL, so the mesh no
longer declares the stream, which would make it again before its removal; MeshConsumers is empty,
the controller's consumers and the events it followed go, and the lease holder's reading
(LeaseHolder, LeaseHandedAway) with them. Only the consumers' names stay, for the removal of the
leftovers and the watchman's read of whether controller still stands. Issue 1126 B3b.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The controller ended by its unassignment (ADR 0590): its user, its lease's cut and reads, the
operator's hand path to its compositions and its writers' rows go; an enrolling node enrols
through mesh-enrolment alone; the desk's prompt stays the vault's alone (DeskOnly). The golden
lists are now this composer's own, taken first from the controller's with its user removed.
The bus module's tools may remove the controller's leftovers by name, consumers, CONTROL,
ASSIGNMENTS, its 17 buckets and each node's declaration files' bucket, under the word
controller-leftovers (clause 6). The provisioner client reads placement in place of the
assignments mirror. Issue 1126 B3a, B5.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The lease write asked seat:node-service-manager.stop@novox-be through Conn.Call, which published
the '@' inside the subject: nobody served it and the call timed out after 30 s with nothing said
(issue 774 notes 84-87). Every key now parses in one place, calladdress: Call routes '@node' as
CallOn does, and stdio Ask refuses a key the runtime could not route, before anything is sent.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The controller ended by its unassignment (ADR 0590), so its seat, the grants seat's lease write and
hand-back and placement's take-over from it serve nothing. The dependence check becomes strict
(clause 5): a read of the lease, a claim, a require or the module itself is refused like any other
declaration. held and artifacts-gone are the artifact sweep seat's (ADR 0571 §2). Issue 1126 B1, B2.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0589 §6: an address key gains the issue's ask and time, written when the ask is raised. The key is written at the
reservation, before the ask, so both are empty then and both set from the ask; one without the other is refused, as
is no node. EncodeEnrolmentAddress takes node, ask and issued. EnrolmentIssuedID builds the enrolment-issued event's
id, enrolment-issued.<node>.<issue time in Unix nanoseconds>, as the holder names it today. Tested as rows of
TestNodeRecord; no new test function (1438 unit tests).
(issue 774, review round 1b)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The operator's decision of 2026-11-02 01:05: the tunnel key is given at issue. Enrolment gains overlay-key, required at
every stage and refused unless it is 32 bytes in base64. Tested as rows of TestNodeRecord; no new test function (1438
unit tests).
(issue 774, review round 1b)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The operator's decision of 2026-11-02 01:05: issue requires overlay_key, the machine's tunnel public key; the vault's
enrolment-token tunnel declares all five fields a token needs (hub_key, hub_endpoint, address, key, range). An
add-node is proposed at the yes with the tunnel key alone; the identity keys come whole at redeem or not at all. A new
remove-node, mesh-enrolment's alone on the same warrant and the proposal's one change, takes a joining node running
nothing off placement when its enrolment ends unconfirmed (RemovedNodes names the key the holder deletes; LayChanges
lays nothing for it and refuses a node that runs modules or holds seats). NodeLogin gains Acts, the hand acts that
warranted its rotations. Tested as rows of TestPlacement, TestNodeRecord and the two seat tests; no new test function
(1438 unit tests).
(issue 774, review round 1b)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
Lead's decision on milestone point 7 (a progressive insight of ADR 0587 §3): mesh-enrolment builds the joining
node's first tunnel at issue and passes it to the vault's enrolment-token as `tunnel`, an object of hub_key,
hub_endpoint and address, each required; the vault puts it in the token (delivery.TokenTunnel). Tested as a row of
TestTheVaultsSeatPromisesItsIntakeVerbs; no new test function (1438 unit tests).
(issue 774, review round 1)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
Blocker 6: enrolment-expired carries the enrolment-issued event's message id (IssuedID), since a bundle's publish
answers no stream sequence and ADR 0587 §2 asks only that the event be named; it gains a codec refusing no event named.
Blocker 7: NodeHealth gains Fallback (node, the login fallen back from, why, at), from which the watchman raises
node-account-fallback (ADR 0583 §6); a fall back naming another node is refused. A token missing its signer now says
the vault's signing key, not the retired word. Tested as rows of TestNodeRecord and the control records test; no new
test function (1438 unit tests).
(issue 774, review round 1)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0587 §7: at redeem mesh-enrolment proposes one change, the node with its decided fields (the approved address,
never the hub) and the public halves of its keys, carrying the issue's warrant; mesh-placement checks the warrant
names this node and address and that the caller is mesh-enrolment, and writes the key with no ask of its own
(changing ADR 0567 §2 and §5 for this one change by this one caller). The proposal codec refuses an add-node beside
other changes, without a warrant, or whose warrant names another node or address, and a warrant on any other
proposal; AddNodeRefusal adds the caller's check for the assigner; LayChanges adds the node and refuses one placed
already. Tested as rows of TestPlacement's proposal subtest, no new test function.
(issue 774, 774/S42)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0587 §1-§3 (changing ADR 0561 §5) make mesh-enrolment the only caller of the vault's enrolment-token and
node-account and a caller of sign, and §2 its bucket enrolments read by it and by the grants part as a named reader.
The holder calls the vault through its manifest's invokes, in its own name, as any caller does; while the vault serves
either enrolment verb every other principal is denied both, however wide its grant (a runtime's or an agent's `*`),
as ControllerOnly denies the desk's prompt. The writers table gains the open enrolments (mesh-enrolment) and the
node-logins (the vault), each one writer; NamedReaders names the grants part for enrolments. Golden lists unchanged.
Tested as a subtest of TestTheCopiedComposerComposesAsTheControllers, no new test function.
(issue 774, 774/S41)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0587 §4: the grants part composes enrol.<node> granted only to call mesh-enrolment.redeem and to hear its own
inbox; §6: from the lease write the controller's enrolment subject is not served. The enrolment principal now calls
redeem in its own name while the seat's holder serves it, and keeps mesh.control.enrol only until Records says the
lease is handed away (a field the grants part sets and the controller's composer never does). A user left able to
enrol nowhere is refused by name rather than composed empty. Golden lists unchanged. Tested as a subtest of
TestTheCopiedComposerComposesAsTheControllers, no new test function.
(issue 774, 774/S40)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0583 §1: a node's account rotates between node.<n> and node.<n>--b, each with the node's permissions and its
inbox _INBOX.node.<n>. Records gains NodeLogins (each node's key of node-logins; the context file's NodeRotating,
renamed because a node that rotated and rotates no more logs in as its second login alone), and Users composes one
node user per login: the one in use and, while it rotates, the other. Each login calls in its own name, which is how
the vault tells the login that confirms (§3). While the vault serves rotate-node, each node reads its own node's key
of node-logins alone and may call node-account-confirm in its own name (§1 insight); the grants part is the state's
one named reader. With no rotation every list is the controller's golden one, unchanged. Tested as a subtest of
TestTheCopiedComposerComposesAsTheControllers, no new test function.
(issue 774, 774/S39)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0583 §1 (insight 2026-11-01) keeps which login a node uses in the vault's state node-logins, one key per node:
the login in use, the one rotating and the stage (begun, ready, confirmed), with the list revision that held both.
§2, §3 and §5 give the vault's seat rotate-node (with the recorded hand act's id), node-account-confirm (the caller
is the proof) and abandon, optional until the vault serves them; the events rotation-begun, node-account-ready,
rotation-done and the engine's finding node-account-fallback are named beside them. The codec refuses a stage without
a rotation and a rotation to anything but the node's other login; an empty rotating reads as none. Tested as rows of
TestNodeRecord and TestTheVaultsSeatPromisesItsIntakeVerbs, no new test function.
(issue 774, 774/S38)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0587 §3 and §5 (changing ADR 0561 §5) have the vault make the token and its hash (enrolment-token), answer it
sealed to the operator key for tokens to relay (sealed, §8), drop both at every end (drop), and mint, answer again
and retire a joining node's account (node-account), with mesh-enrolment their only caller; sign names mesh-enrolment
for a joining node's certificate (with the serving key it presented, since the node has no record yet) and for a
redeem answer. Both verbs optional until the vault that runs serves them. Their answers' shapes are in go/delivery.
Tested as rows of TestTheVaultsSeatPromisesItsIntakeVerbs, no new test function.
(issue 774, 774/S37)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
From the lease write the vault makes the token (ADR 0587 §3), mesh-cli opens and prints it, and the node-engine
parses it: three repositories, so the type leaves mesh-host's internal/identity (which keeps an alias) for
go/delivery, field names unchanged from the controller's token issue, the tunnel kept (the lead's settlement 7).
Encode is added, refusing a token with a part missing. The test reads a token the controller's own code made and
encodes it back to the same line. Paid by merging TestGateBuckets into TestKeysOfPlainNamesAreUnchanged.
(issue 774, 774/S36)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0587 §2 gives the seat mesh-enrolment the bucket enrolments with keys node.<node> (an Enrolment: node, address,
why, caller, ask, stage, issued, expires, keys digest) and address.<address> (the node's name alone), no secret in
either. The token's life rules (an hour by default, at most a day, §4), the event enrolment-expired's content (§2),
and redeem's call, proof bytes, keys digest and signed answer (§6) live here too, because the holder in
mesh-delivery and the engine in mesh-host both read them. The proof binds the node and its keys, not the token's
secret, which the holder never holds (§1). Tested as rows of TestNodeRecord, no new test function.
(issue 774, 774/S35)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0587 §1 makes joining a machine a seat held once by the module mesh-enrolment, the vault's only caller for its
enrolment verbs. The seat is in the mesh's own set, its verbs not optional (the seat is new with its holder), and
its events the five that carry no secret. The test is a block in TestHoldingAMeshSeatRequiresServingItsVerbs, no new
test function.
(issue 774, 774/S34)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
mesh/check failed: mesh-build-go: the check of novox/mesh-catalog#590: the ask mvyhumdm860c7f's step on shanks did not end within 30m0s of its start |…
The repository is over its unit budget and a change may not raise the count: the case of the seat mesh-grants
(ADR 0582 clause 1) runs as a subtest of TestTheDeliverySeatPromisesChecks instead of a function of its own.
(issue 774, 774/S1)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0582 clauses 4 and 6 have mesh-grants say lease-altered and removal-failed "as a finding the watchman
raises". WatchmanHears, the one list its grant and its subscriptions come from, gains the seat mesh-grants'
three events and the advisory of ASSIGNMENTS deleted (which, with the controller's consumer deleted that it
hears already, clears a failed removal). Core subjects, read-only, no durable consumer.
Test: rows added to the watchman's subjects in TestTheCopiedComposerComposesAsTheControllers; no new function.
(issue 774, 774/S22)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0571 §13: the lease write's own delivery drops every entry but the builder's artifacts-gone, the artifact
sweep's collect and the engine's following of the controller's user list. Every module of this group stops
its read, invoke or consume of the controller (pacman, the keeper, mesh-config, the hand-act log's readers, the
watcher, messenger, the assigner, mesh-grants), so the list shrinks to the three and a read put back is
refused in either phase. Supersedes the keep of pacman's read at mesh-delivery 4a84370.
Tests: rows of TestTheLeaseWritesCheckJudgesEveryDependencyOnTheController changed (the keeper's read put back
is refused; the sweep's collect passes); no new test function.
(issue 774, 774/S30)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
It said which placement changes waited for the lease write while the assigner called the controller's assign,
unassign, pin and unpin (ADR 0567 §8). Since the assigner calls no controller verb (774/S25), nothing reads it.
Test: its table in TestPlacement goes with it.
(issue 774, 774/S25)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0571 clause 10: the grants part publishes memberships on mesh.assignment until the lease write and stops
then. FollowMembership now reads and watches its own key of the state memberships and nothing else, and refuses
to follow, naming the state, when it cannot read it (there is nothing else to follow, and a silent follow of
nothing is the fault). A module's principal and the runtime lose their subscribe on mesh.assignment; the grants
part's publish grant stays until the write (S21 stops the publishing).
Tests: TestFollowMembershipHearsWhatIsIssuedToTheAccount (integration) edited: no state is a refusal, a
membership put in the state is applied, one published on the subject is not; run locally against its
embedded bus. Rows added to TestTheCopiedComposerComposesAsTheControllers: nobody subscribes mesh.assignment,
and the controller's golden grant of it is the one row the copy now lacks. No new test function.
(issue 774, 774/S5)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0571 §13 names a test in mesh-catalog, mesh-delivery and mesh-tools that refuses a manifest depending on
the controller beyond the lease and the entries kept. The judge lived in mesh-grants (leasecheck.go); it moves
here whole (the kinds, the phases, KeepList, EndedBy, Dependencies, Judge) with ManifestRefusals(manifests,
phase) for those tests. Kept is renamed KeptDependency (catalogue already has a Kept), and a gap is Unread.
mesh-grants re-exports it in its own commit; the keep list is the one at mesh-delivery 4a84370.
Test: TestTheLeaseWritesCheckJudgesEveryDependencyOnTheController, moved from mesh-grants'
leasecheck_test.go (its manifest rows and the keep-list test, which mesh-grants deletes), with the
conditions row of 774/S4/AC1 added; not a new test.
(issue 774, 774/S4)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0582 clause 3 writes the key holder "with the why, the ask and the time": LeaseHolder gains ask and at,
which LeaseHandedAway ignores (it reads handed-to alone). The grants part's user-list key gains lease-handed,
so the bus node's engine follows the grants part's list alone once the lease is handed (ADR 0571 clause 8)
and never falls back to the controller's; a key written before reads false.
Tests: a row in the lease table of TestTheCopiedComposerComposesAsTheControllers; the old key (shaped as
EncodeGrantsUserList writes it today) and the flag's round trip added to the existing user-list case in
delivery_test.go; no new test function.
(issue 774, 774/S3)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0582 clause 3 composes the bus's user list without the controller's write on the lease key and update of
the lease's bucket. Records.LeaseCut, set by the grants part from the write's second step, drops the
controller's $KV grant on the lease, denies it the bucket's update, purge, delete and message delete (its
$JS.API.> reaches them), and lets the grants part write the key holder alone. The bus module's tools account
may read and update the lease's bucket, for the expiry tool the write and the hand-back call. Without the cut
the lists equal the controller's golden.
Tests: rows added to TestTheCopiedComposerComposesAsTheControllers' tables (the cut on and off; the tools
account's lease grants); no new test function.
(issue 774, 774/S2)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0582 clause 1 makes the lease write a verb of the seat mesh-grants: lease-write and lease-hand-back, each
taking a why, and the events lease-handed, lease-altered and removal-failed. The indexer's judge reads seats
through catalogue.SeatNamed, so it accepts mesh-grants' claim once it pins this head.
Test: TestTheGrantsSeatPromisesTheLeaseWrite (new), paid by merging the two ssh tests of filtering_test.go into
TestSSHIsOpenFromTheMeshEvenWhenNothingIsAssigned.
(issue 774, 774/S1)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
A node's plans took 2.6-13.6 s of CPU on the provisioner: one composition
resolved every machine of the mesh some two hundred times (who is on the
private network, and the rest of the mesh, worked out again on every
look), three compositions did so again each, and the holder composed
twice. A composer now works each out once over its unchanging Input;
Composing gives Resolve, Render and Generators one composer;
PlansHeldTwice composes the wanted and the newest builds over one read of
the bus, says where the time went by phase, and the states reader keeps a
build's take-in by its content. WatchedStates takes a process's own
writes into the copy at once, so a holder reads its own states from it.
Measured on a captured novox mesh: 11.7 s to 0.49 s per composition of an
unchanged node, plans and provisions identical on all four nodes.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The engine composes its node's wants itself, so the derivation the controller keeps
privately moves beside the layout: DeclaredPackagesOf gives the mirror's bytes from the
compositions, DiffDeclaredPackages what the node seat's verb packages compares until the
lease write, and EnginePackagesRead names the state as readers declare it (mesh-host.packages,
as mesh-host.data). Each engine may read the controller mirror's key of its own node alone.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
mesh/check pass 67354f8e019a on cad8250aaa8c | unit 7056 run, 243 kept, 16 skipped | integration 7194 run, 275 kept, 25 skipped | over bound: unit, in…
A check ask named no toolchain, so a node on the minority version could run it and its pass be recorded as run on the agreed one. CheckJob now carries the toolchain; a node on another declines it before it fetches, as for a build ask.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
With the toolchain agreed by majority, a node on the minority version can pull an ask for the agreed one. It now declines it (the issue 890 path) for the asker to put again, so it never fails a build.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
One build node on another version stopped every build of the language. The agreed toolchain is now the strict majority's; a tie still waits and names the versions.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
mesh/check pass 790d1c82d027 on da41823855a9 | unit 1964 run, 5697 kept, 30 skipped | integration 1999 run, 5829 kept, 38 skipped | over bound: unit, …
A read could start a state's watch before its follower joined, and a change landing in that gap woke nothing (review
of ADR 0580 §2): a joining follower now runs over the copy's current values before any later change. The watched
reader keeps each archive once per URL, and both caches are bounded.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The controller's hand-act and warranted are gone (issue 1953 L5b) and the bus refuses them, so the recorder no longer
falls back to them: an act the seat does not take is an error saying nothing was recorded. And ADR 0580 clause 1's
reader is shown reading a build by key each time and a manifest once per digest.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
A whole state read key by key took the provisioner's composition of one node past 30 s and the assigner's compare past
its call bound (ADR 0580 clause 1): each state is now one watch's current values, kept by its changes; a build is read
by key and a manifest once per digest.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL