Issue 774 (design 47): nothing is left with the controller — the removal before the lease write. ADRs 0582, 0588, 0571 §13, 0567 §11, 0564 §9.
mesh-grants holds the seat mesh-grants: lease-write checks every precondition, stops the controller through node-service-manager, writes the lease with no expiry and removal-due (24 h), and lease-hand-back restores it until then (ADR 0582, ADR 0588). Recovery tool grants_removal_due.
The grants part reads placement alone and no controller assignments or condition events; modules/assignments-readers is deleted.
The watchman raises and clears lease-altered and removal-failed.
The assigner calls no controller verb after a placement write, reads no assignments, lease or mesh-controller.composed; placement's adopt and hand-back answer gone (ADR 0567 §11).
Fixes a live bug: a placed node's want dropped its failed-backup answer at every pass.
The indexer's seat count is 57 (it judges the new claim through mesh-sdk).
Pins mesh-sdk at the group's head in mesh-grants, the assigner, the watchman and the indexer.
Delivery group: the five pull requests on branch feat/l3-removal (mesh-sdk, mesh-catalog, mesh-delivery, mesh-host, mesh-tools), one check, one Approve, merged in one pass in the order mesh-sdk → mesh-catalog → mesh-delivery → mesh-host → mesh-tools. Every member pins mesh-sdk at c21d8fd9692c (this group's head). Every new behaviour is dormant until the lease write, which is asked separately on the operator's Approve.
Tested locally before the push (GOWORK=off, GOFLAGS=-mod=readonly, GOPROXY=off, GOSUMDB=off): gofmt, go vet and go vet -tags integration, and the whole untagged unit suite of every touched module pass. Integration tests that exercise the change, against an embedded bus: TestTheLeaseWriteOnTheBus (mesh-grants): ok, 3.1 s; the assigner's integration tests ./cmd/mesh-delivery-assigner: ok, 13.7 s; the checker's ./cmd/mesh-delivery-checker (incl. TestTheCheckersLineSaysTheAssignersComposition): ok, 9.5 s.
Reviewed-by: review-g1@shanks at 17ef1d577d
Pushed-by: lead-47@shanks
Issue 774 (design 47): nothing is left with the controller — the removal before the lease write. ADRs 0582, 0588, 0571 §13, 0567 §11, 0564 §9.
- mesh-grants holds the seat mesh-grants: `lease-write` checks every precondition, stops the controller through node-service-manager, writes the lease with no expiry and `removal-due` (24 h), and `lease-hand-back` restores it until then (ADR 0582, ADR 0588). Recovery tool `grants_removal_due`.
- The grants part reads placement alone and no controller assignments or condition events; `modules/assignments-readers` is deleted.
- The watchman raises and clears lease-altered and removal-failed.
- The assigner calls no controller verb after a placement write, reads no assignments, lease or `mesh-controller.composed`; placement's adopt and hand-back answer gone (ADR 0567 §11).
- Fixes a live bug: a placed node's want dropped its failed-backup answer at every pass.
- The indexer's seat count is 57 (it judges the new claim through mesh-sdk).
- Pins mesh-sdk at the group's head in mesh-grants, the assigner, the watchman and the indexer.
**Delivery group:** the five pull requests on branch `feat/l3-removal` (mesh-sdk, mesh-catalog, mesh-delivery, mesh-host, mesh-tools), one check, one Approve, merged in one pass in the order mesh-sdk → mesh-catalog → mesh-delivery → mesh-host → mesh-tools. Every member pins mesh-sdk at c21d8fd9692c (this group's head). Every new behaviour is dormant until the lease write, which is asked separately on the operator's Approve.
**Tested locally before the push** (GOWORK=off, GOFLAGS=-mod=readonly, GOPROXY=off, GOSUMDB=off): gofmt, `go vet` and `go vet -tags integration`, and the whole untagged unit suite of every touched module pass. Integration tests that exercise the change, against an embedded bus: `TestTheLeaseWriteOnTheBus` (mesh-grants): ok, 3.1 s; the assigner's integration tests `./cmd/mesh-delivery-assigner`: ok, 13.7 s; the checker's `./cmd/mesh-delivery-checker` (incl. `TestTheCheckersLineSaysTheAssignersComposition`): ok, 9.5 s.
Reviewed-by: review-g1@shanks at 17ef1d577d4f5452370d80283e43d49a38f3e75f
Pushed-by: lead-47@shanks
https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
pacman still falls back to the controller's declared-packages for a node whose engine has
not written its own packages (ADR 0565 §6), so the check named that read as ended and would
refuse the lease write. It is now a kept read, dropped with the others at the write's own
delivery (issue 774, design 47 L3).
Quick fix chosen over removing pacman's fallback: it matches the record as it stands, and
the read goes with the other kept reads at the write's delivery.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
Drops callAll, the refused-call conditions and the pin reads; the conditions a previous process raised are cleared once.
Tests: deletes four (the refused-call condition, its clearing, the contract of the calls, the condition's shape) and adds one.
(issue 774, 774/S25)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
Every handed-away branch is the only one: world.assigned is the placement, the pair comparison and its conditions go, the
lease and assignments buckets are no longer opened, watched or declared, and a proposal of any kind is taken.
Tests: the pair-comparison test and the controller-composition record-ask test are replaced by one placement test; the
rest are edited to place their modules instead of assigning them.
(issue 774, 774/S26)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
mesh-controller.composed leaves the reads and the watches; upgrade compare lists the node composition digests of the haves
instead of comparing with the controller's policies, which the controller no longer writes.
(issue 774, 774/S27)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The controller's placement-export is no longer called, its answer reader, the seed and the hand-back flow of the holder are
removed, and a seed or hand-back proposal a previous process left open ends at its next pass.
Tests: the adopt, hand-back and seed cases of the seat's verb test and of Propose are replaced by one gone-case; the export
reader's table and the seed test go.
(issue 774, 774/S28)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The integration tests put placement (not assignments) and the node's own composition (not the controller's) on the bus; the
three that tested the controller's judgements of a move (waiting for a composition, a record move, a user-list revision) go,
their unit counterparts standing. Run locally against the embedded bus, all of this module's integration tests pass.
Found by them: the answer to a failed backup was dropped from a placed node's want at every pass, because the carry-over
compared the want's digest, which a placed node's want does not carry; fixed in wants.go, with a case in the existing unit test.
Tests: three integration tests deleted, none added; one case added to an existing unit test.
(issue 774, 774/S26, 774/S27)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0582: lease-write is refused, naming each check, until the lease check at phase write and every condition
of clause 2 read green (design 47's earlier issues resolved, every node trusting the vault's key, mesh-config's
compare empty from the indexer, the upgrade compare empty, the keeper's take-over done, the vault minting with
nothing held back, the bus module listing its expiry and removal tools). It asks the operator once; the yes
binds the act, the holder, the ask and the checks' digest, and the checks are read again on the warrant (one
that reads otherwise refuses it, named). Then, each step read back: node-service-manager.stop on the
controller's node, the list composed with Records.LeaseCut and waited on until the bus node's have says it
loaded it, the expiry removed through nats_bucket_expiry, the key holder written (with the ask and the time),
lease-handed said, the act recorded through mesh-hand-acts.warranted, and removal-due written with a day to
live. lease-altered is said once when the key or the expiry differs; lease-hand-back reverses it for a day
and is refused once the removal ran; removal-due's marker alone starts the removal of the controller's
consumer and the stream ASSIGNMENTS, recorded as hand acts, and a failure says removal-failed and writes the
key again with a day (grants_removal_due is the recovery for a missed marker). From the write memberships are
written to the state alone (ADR 0571 clause 10), the user-list key says lease-handed, and the user list's
hand-back answers gone (ADR 0547 §11). Every step waits on an event, never a timer.
Bent rule: S14-S21 are one commit, not eight: the steps are one state machine in leasewrite.go, and splitting
it by hunks would review the same file eight times for nothing it protects.
Tests: TestTheLeaseWrite (new, one function with a subtest per subtask), paid by the deletion of
TestTheKeepListNamesItsRecordsAndThreeToTheWrite (moved to mesh-sdk, S4/S30) and the assigner's two deletions
(S25). Fixtures shaped from each writer's code: systemd's Manager.Status, nats-tools' BucketExpirySet,
ConsumerRemoved and StreamRemoved, mesh-issues' Brief, mesh-delivery-view's TrustsAnswer, mesh-config's
Comparison, the assigner's upgrade compare, mesh-vault's vault_status.
(issue 774, 774/S14, 774/S15, 774/S16, 774/S17, 774/S18, 774/S19, 774/S20, 774/S21)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0571 §13: the judge moved to mesh-sdk (catalogue.Dependencies, Judge, KeepList; issue 774, 774/S4) so the
manifest tests of three repositories and grants_lease_check give one judgement; mesh-grants re-exports it by
its names. The keep list there holds the three kept to the write alone (774/S30), superseding the keep of
pacman's read at 4a84370. grants_lease_check no longer counts the controller's standing assignments, which
nothing reads any more.
Tests: TestTheLeaseCheckJudgesEveryDependencyOnTheController keeps the tool's own rows (what it read, the
lease, the streams); its dependency rows moved to mesh-sdk's TestTheLeaseWritesCheckJudgesEveryDependencyOnTheController
(774/S24's replacement of the moved rows), and TestTheKeepListNamesItsRecordsAndThreeToTheWrite went with them.
(issue 774, 774/S30, 774/S24)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0549 §5, ADR 0564 §9, ADR 0571 §10: the part no longer reads mesh-controller.assignments (the union with
placement goes; placement not read is a failed read that places nothing) nor consumes the controller's
condition-raised and condition-cleared, the keeper's being the one source. ADR 0571 §13's test for this
repository replaces the guard of ADR 0549 §6 and its list ../assignments-readers, now empty and deleted: at
phase write no module.json here depends on mesh-controller beyond the lease and the three kept to the write
(catalogue.ManifestRefusals).
Tests: in TestGrants the fixture places through the seat's placement (assign, unassign), the subtest of the
stale assignments becomes 774/S29/AC1 (placement alone gives the fixture's three memberships with no read,
consume or call of the controller; the fixture is the suite's own, whose assignments named the same modules,
not a copy of live memberships), and the assignments-readers subtest becomes 774/S24/AC1. No new test function.
(issue 774, 774/S29, 774/S24)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0582 clauses 4 and 6: mesh-grants says lease-altered and removal-failed "as a finding the watchman raises".
The watchman hears the seat mesh-grants' three events on core subjects (mesh-sdk WatchmanHears, its grant and
its subscriptions from one list, rather than a consume and a durable consumer), raises lease-altered naming
what changed and clears it at the next lease-handed, and raises removal-failed naming what failed and clears it
once what it names reads gone: the controller's consumer of DEAD_LETTER_NOTICES by its deletion advisory
(heard already), the stream ASSIGNMENTS by its own. The finding DEAD_LETTER_NOTICES.controller stays as it is.
Test: a row in TestTheWatchmansFindings; no new function.
(issue 774, 774/S22)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0582 "How it is checked": against an embedded bus, a stand-in controller holds the lease in a bucket with an
expiry (2 s standing in for 15 s, through grants.LeaseExpiry, so the wait past it is seconds), with stand-in
node-service-manager and bus-tool seats (the expiry tool acting on the real bucket's stream, as nats-tools'
SetBucketExpiry does). On the warrant the key holder names mesh-grants, the expiry is gone, the controller's
create of the key is refused, and the lease still reads handed away past the old expiry; on the hand-back's
warrant the expiry is back and the controller takes the lease again. mesh-grants requires nats-server for it,
at mesh-sdk's version.
Budget: TestTheLeaseWriteOnTheBus (new, integration) is paid by merging the checker's
TestTheCheckerAwaitsTheAssignersComposition into TestTheCheckersLineSaysTheAssignersComposition as its first case.
(issue 774, 774/S23)
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 |…
Deliverynovox/mesh-delivery@17ef1d577d4f — merged since 2026-11-02T00:35:41Z
Source — source.main moved to novox/mesh-delivery@9125fcc712. Whether it reached the machines is mesh-delivery-view's, derived from source.main, the wants and the haves.
composed together: fail — the checker's verdict at the members' heads (49fb3ed27c03): mesh-build-go
Transitions
2026-11-01 23:58 (new) → proposed (announced): novox/mesh-delivery#133's head announced
2026-11-01 23:58 proposed → ready (accepted): a verdict names this commit and the trunk's head as its trunk commit, the gate passed or warned, and the repository's own check did not fail; or the check gates no merge (check-gates-merge false)
2026-11-02 00:35 ready → merged (merged): on the trunk its modules follow: merged there
The commit's note under refs/notes/mesh-plan keeps every transition of this change up to its merge: git log --notes=mesh-plan.
<!-- mesh-delivery:view -->
**Delivery** `novox/mesh-delivery@17ef1d577d4f` — **merged** since 2026-11-02T00:35:41Z
**Source** — source.main moved to novox/mesh-delivery@9125fcc71206. Whether it reached the machines is `mesh-delivery-view`'s, derived from `source.main`, the wants and the haves.
**Group** `feat/l3-removal`: novox/mesh-catalog@2c5e9c9a9847, novox/mesh-delivery@17ef1d577d4f, novox/mesh-host@c27fad5c6e36, novox/mesh-sdk@c21d8fd9692c, novox/mesh-tools@29fd452628ec
- composed together: fail — the checker's verdict at the members' heads (49fb3ed27c03): mesh-build-go
**Transitions**
- 2026-11-01 23:58 (new) → proposed (announced): novox/mesh-delivery#133's head announced
- 2026-11-01 23:58 proposed → ready (accepted): a verdict names this commit and the trunk's head as its trunk commit, the gate passed or warned, and the repository's own check did not fail; or the check gates no merge (check-gates-merge false)
- 2026-11-02 00:35 ready → merged (merged): on the trunk its modules follow: merged there
The commit's note under `refs/notes/mesh-plan` keeps every transition of this change up to its merge: `git log --notes=mesh-plan`.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Issue 774 (design 47): nothing is left with the controller — the removal before the lease write. ADRs 0582, 0588, 0571 §13, 0567 §11, 0564 §9.
lease-writechecks every precondition, stops the controller through node-service-manager, writes the lease with no expiry andremoval-due(24 h), andlease-hand-backrestores it until then (ADR 0582, ADR 0588). Recovery toolgrants_removal_due.modules/assignments-readersis deleted.mesh-controller.composed; placement's adopt and hand-back answer gone (ADR 0567 §11).Delivery group: the five pull requests on branch
feat/l3-removal(mesh-sdk, mesh-catalog, mesh-delivery, mesh-host, mesh-tools), one check, one Approve, merged in one pass in the order mesh-sdk → mesh-catalog → mesh-delivery → mesh-host → mesh-tools. Every member pins mesh-sdk at c21d8fd9692c (this group's head). Every new behaviour is dormant until the lease write, which is asked separately on the operator's Approve.Tested locally before the push (GOWORK=off, GOFLAGS=-mod=readonly, GOPROXY=off, GOSUMDB=off): gofmt,
go vetandgo vet -tags integration, and the whole untagged unit suite of every touched module pass. Integration tests that exercise the change, against an embedded bus:TestTheLeaseWriteOnTheBus(mesh-grants): ok, 3.1 s; the assigner's integration tests./cmd/mesh-delivery-assigner: ok, 13.7 s; the checker's./cmd/mesh-delivery-checker(incl.TestTheCheckersLineSaysTheAssignersComposition): ok, 9.5 s.Reviewed-by: review-g1@shanks at
17ef1d577dPushed-by: lead-47@shanks
https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
Delivery
novox/mesh-delivery@17ef1d577d4f— merged since 2026-11-02T00:35:41ZSource — source.main moved to novox/mesh-delivery@9125fcc712. Whether it reached the machines is
mesh-delivery-view's, derived fromsource.main, the wants and the haves.Group
feat/l3-removal: novox/mesh-catalog@2c5e9c9a98, novox/mesh-delivery@17ef1d577d, novox/mesh-host@c27fad5c6e, novox/mesh-sdk@c21d8fd969, novox/mesh-tools@29fd452628Transitions
The commit's note under
refs/notes/mesh-plankeeps every transition of this change up to its merge:git log --notes=mesh-plan.