Fixes the failed live acceptance of issue 367 (ADR 0343) after mesh-catalog#276.
Seen (read-only)
shanks's node-tools journal, every minute since 16:31: watching the agent's memory not yet (the current values of memory did not arrive in 10s); g14's the same, every minute since. At 16:37:59 shanks logged ~450 lines claude-code did not take put operator.… of memory: mesh/state names no watch of this bundle.
mesh-tools node-tools/internal/bus/state.go: the runtime hands a watch's current values to the bundle one at a time (deliver waits for the bundle's answer) and gives the whole current set StateTimeout = 10 s, then stops the watch.
claude-code's Take (the handler) read the state (Get, a round trip), waited for the carrier's lock (held by a look for its whole run) and wrote files, for each of ~450 values. So the watch never started on any node; a file written on g14 was put in the state by g14's look (g14's claude_code_memory lists it, which it records only after the state write succeeds) but no node watched it. The first carrying at 14:31Z on shanks came from the values the failed watch attempts did apply before timing out, and from shanks's own look.
Fix
Take now only checks the value and notes the key's newest revision, then returns. A worker (Drain, woken by Take) applies what was noted under the carrier's lock, at the state's current version, as before.
Test
TestTheWatchHandlerReturnsAtOnceAndDrainAppliesWhatItNoted: 400 hand-overs while a look holds the carrier and the state does not answer must all return within a second; then Drain applies the change. On main it fails: the watch handler waited for the look or the state (0 of 400 returned). Every other memory test now drains after handing over, as the worker does. go test -race and merge-check.sh (MESH_CHECK_MODULES=claude-code, controller from main) pass.
Acceptance after delivery: the journal on g14 and shanks says watching the agent's memory without not yet, and the operator's test file written on g14 is listed by shanks/claude-code.claude_code_memory with g14's fingerprint within a minute.
Fixes the failed live acceptance of issue 367 (ADR 0343) after mesh-catalog#276.
## Seen (read-only)
- shanks's node-tools journal, every minute since 16:31: `watching the agent's memory not yet (the current values of memory did not arrive in 10s)`; g14's the same, every minute since. At 16:37:59 shanks logged ~450 lines `claude-code did not take put operator.… of memory: mesh/state names no watch of this bundle`.
- mesh-tools node-tools/internal/bus/state.go: the runtime hands a watch's current values to the bundle one at a time (`deliver` waits for the bundle's answer) and gives the whole current set `StateTimeout` = 10 s, then stops the watch.
- claude-code's `Take` (the handler) read the state (`Get`, a round trip), waited for the carrier's lock (held by a look for its whole run) and wrote files, for each of ~450 values. So the watch never started on any node; a file written on g14 was put in the state by g14's look (g14's `claude_code_memory` lists it, which it records only after the state write succeeds) but no node watched it. The first carrying at 14:31Z on shanks came from the values the failed watch attempts did apply before timing out, and from shanks's own look.
## Fix
`Take` now only checks the value and notes the key's newest revision, then returns. A worker (`Drain`, woken by `Take`) applies what was noted under the carrier's lock, at the state's current version, as before.
## Test
`TestTheWatchHandlerReturnsAtOnceAndDrainAppliesWhatItNoted`: 400 hand-overs while a look holds the carrier and the state does not answer must all return within a second; then `Drain` applies the change. On main it fails: `the watch handler waited for the look or the state (0 of 400 returned)`. Every other memory test now drains after handing over, as the worker does. `go test -race` and `merge-check.sh` (MESH_CHECK_MODULES=claude-code, controller from main) pass.
Acceptance after delivery: the journal on g14 and shanks says `watching the agent's memory` without `not yet`, and the operator's test file written on g14 is listed by `shanks/claude-code.claude_code_memory` with g14's fingerprint within a minute.
mesh/merge-gate head e46eeb829853 merged into trunk 4d15a155e634 — pass: builds claude-code → ace, g14, novox, shanks; no bus step; every machine composes …
mesh/repo-check head e46eeb829853 merged into trunk 4d15a155e634 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
The runtime hands a watch its current values one at a time and gives them ten
seconds. The handler read the state, waited for a running look and wrote files
for each value, so with about 450 memory values the watch never started on g14
or shanks, and a file written on g14 never reached shanks. The handler now
notes each key's newest revision and returns; a worker applies what was noted
at the state's current version.
Deliverynovox/mesh-catalog@e46eeb829853 — delivered since 2026-10-13T15:02:03Z
Delivery plan — builds claude-code → ace, g14, novox, shanks; no bus step
tier 0: claude-code
ace: receives claude-code
g14: receives claude-code
novox: receives claude-code
shanks: receives claude-code
claude-code keeps data (ADR 0233): what it holds is backed up before it moves
grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before claude-code is judged on its first machine
Machines
claude-code on ace: passed — healthy 1 times over 42s
claude-code on the rest running it: sent
Transitions
2026-10-13 14:41 (new) → proposed (announced): novox/mesh-catalog#279's head announced
2026-10-13 14:46 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
2026-10-13 14:46 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
2026-10-13 14:48 ready → proposed (trunk moved): out of date: judged against trunk 5f491e0c09, the trunk is now 4d15a155e634; judged again on a recheck or when it is merged
2026-10-13 14:58 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
2026-10-13 14:58 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
2026-10-13 14:58 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
2026-10-13 14:58 published → delivering (go): its walk started: let go by this owner in its group's order, by a person, or on the controller's own path — not a failed walk that carried a later commit for it, after which it waits for a walk of its own commit
2026-10-13 15:02 delivering → delivered (done): its walk is done, carrying its own commit: every machine of its deploy plan passed, or was left as its policy says
The commit's note under refs/notes/mesh-plan keeps every transition: git log --notes=mesh-plan.
<!-- mesh-delivery:view -->
**Delivery** `novox/mesh-catalog@e46eeb829853` — **delivered** since 2026-10-13T15:02:03Z
**Delivery plan** — builds claude-code → ace, g14, novox, shanks; no bus step
- tier 0: claude-code
- ace: receives claude-code
- g14: receives claude-code
- novox: receives claude-code
- shanks: receives claude-code
- claude-code keeps data (ADR 0233): what it holds is backed up before it moves
- grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before claude-code is judged on its first machine
**Machines**
- claude-code on ace: passed — healthy 1 times over 42s
- claude-code on the rest running it: sent
**Transitions**
- 2026-10-13 14:41 (new) → proposed (announced): novox/mesh-catalog#279's head announced
- 2026-10-13 14:46 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
- 2026-10-13 14:46 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
- 2026-10-13 14:48 ready → proposed (trunk moved): out of date: judged against trunk 5f491e0c097d, the trunk is now 4d15a155e634; judged again on a recheck or when it is merged
- 2026-10-13 14:58 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
- 2026-10-13 14:58 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
- 2026-10-13 14:58 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
- 2026-10-13 14:58 published → delivering (go): its walk started: let go by this owner in its group's order, by a person, or on the controller's own path — not a failed walk that carried a later commit for it, after which it waits for a walk of its own commit
- 2026-10-13 15:02 delivering → delivered (done): its walk is done, carrying its own commit: every machine of its deploy plan passed, or was left as its policy says
The commit's note under `refs/notes/mesh-plan` keeps every transition: `git log --notes=mesh-plan`.
Merge check at e46eeb82
Judged: head e46eeb829853 merged into trunk 5f491e0c097d; read beside it: mesh-controller 6f1a05366c1d, mesh-controller-main 6f1a05366c1d, mesh-host 0e92ef3d1b21, mesh-tools 954e1a53eef9
mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: claude-code)
mesh/repo-check: PASS — its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
Delivery plan — builds claude-code → ace, g14, novox, shanks; no bus step
tier 0: claude-code
ace: receives claude-code
g14: receives claude-code
novox: receives claude-code
shanks: receives claude-code
claude-code keeps data (ADR 0233): what it holds is backed up before it moves
grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before claude-code is judged on its first machine
read by no module's build: modules/claude-code/cmd/claude-code/memory_test.go
Run by the build seat on shanks as build-1791902475612885975 (builds --log build-1791902475612885975).
--- the gate: claude-code
note: claude-code uses the seat "operator-channel", which no module declares and the mesh does not define among the manifests given; registration judges it against the whole catalogue, and passing the declaring module's manifest too judges it here
claude-code: ok, 48 tool(s), keeps state servers, holdings, config, proposals, questions, memory, reads claude-licence-manager.bindings, keeps agent-home (valuable); WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 1
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 0 module(s) changed against 4 machine(s), as the snapshot of 2026-10-13T14:42:41Z says they run
composing every machine as the mesh is
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
composing every machine with the change
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose)
judged by controller development build against the facts of 2026-10-13T14:42:41Z
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 1 module(s) in 1 tier(s): claude-code
notes:
- modules/claude-code/cmd/claude-code/memory_test.go read by no module's build, and rebuild nothing (issue 280)
--- its merge-check.sh (go toolchain)
ok git.novox.be/novox/mesh-catalog/checks/words 0.002s
words: 12 retired words and 70 daemons' lines, none in the 46587 strings of 717 files
ok git.novox.be/novox/mesh-catalog/checks/agenthome 0.012s
agent-home: no archive and no file written into under the agent's home
ok git.novox.be/novox/mesh-catalog/checks/secrets 0.013s
secrets: no setting can replace a vault secret in a mergeable file (1 known, nested)
ok git.novox.be/novox/mesh-catalog/checks/paths 0.006s
paths: no module names another's state on its machine (3 known, listed to go)
long-running resources without health: 66, as kept
ok git.novox.be/novox/mesh-catalog/checks/deps 0.216s
testing modules/claude-code
ok claude-code/cmd/claude-code 6.593s
--- its merge-check-typescript.sh (typescript toolchain)
**Merge check** at `e46eeb82`
Judged: head `e46eeb829853` merged into trunk `5f491e0c097d`; read beside it: mesh-controller `6f1a05366c1d`, mesh-controller-main `6f1a05366c1d`, mesh-host `0e92ef3d1b21`, mesh-tools `954e1a53eef9`
- `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: claude-code)
- `mesh/repo-check`: **PASS** — its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
**Delivery plan** — builds claude-code → ace, g14, novox, shanks; no bus step
- tier 0: claude-code
- ace: receives claude-code
- g14: receives claude-code
- novox: receives claude-code
- shanks: receives claude-code
- claude-code keeps data (ADR 0233): what it holds is backed up before it moves
- grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before claude-code is judged on its first machine
- read by no module's build: modules/claude-code/cmd/claude-code/memory_test.go
Run by the build seat on shanks as `build-1791902475612885975` (`builds --log build-1791902475612885975`).
```
--- the gate: claude-code
note: claude-code uses the seat "operator-channel", which no module declares and the mesh does not define among the manifests given; registration judges it against the whole catalogue, and passing the declaring module's manifest too judges it here
claude-code: ok, 48 tool(s), keeps state servers, holdings, config, proposals, questions, memory, reads claude-licence-manager.bindings, keeps agent-home (valuable); WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 1
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 0 module(s) changed against 4 machine(s), as the snapshot of 2026-10-13T14:42:41Z says they run
composing every machine as the mesh is
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
composing every machine with the change
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose)
judged by controller development build against the facts of 2026-10-13T14:42:41Z
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 1 module(s) in 1 tier(s): claude-code
notes:
- modules/claude-code/cmd/claude-code/memory_test.go read by no module's build, and rebuild nothing (issue 280)
--- its merge-check.sh (go toolchain)
ok git.novox.be/novox/mesh-catalog/checks/words 0.002s
words: 12 retired words and 70 daemons' lines, none in the 46587 strings of 717 files
ok git.novox.be/novox/mesh-catalog/checks/agenthome 0.012s
agent-home: no archive and no file written into under the agent's home
ok git.novox.be/novox/mesh-catalog/checks/secrets 0.013s
secrets: no setting can replace a vault secret in a mergeable file (1 known, nested)
ok git.novox.be/novox/mesh-catalog/checks/paths 0.006s
paths: no module names another's state on its machine (3 known, listed to go)
long-running resources without health: 66, as kept
ok git.novox.be/novox/mesh-catalog/checks/deps 0.216s
testing modules/claude-code
ok claude-code/cmd/claude-code 6.593s
--- its merge-check-typescript.sh (typescript toolchain)
```
The code is approved, but the required checks are not green: mesh/merge-gate and mesh/repo-check are both pending, "out of date: judged against trunk 5f491e0c09, the trunk is now 4d15a155e634". Ask mesh-delivery.recheck and merge only on the new verdict.
I ran this niced with -race in a throwaway clone. The module's suite passes (ok claude-code/cmd/claude-code 5.5s). I reran my seven probe tests from reviews 205 and 207 against this head, now through Take then Drain. All seven pass: the traversal names, the secret after a removal, the secret after a conflict, the unreadable file, the unlistable folder and subfolder, the conflict whose write fails (one warning, the state not grown, both nodes equal after recovery), and non-UTF-8. Drain keeps every safety property, because it calls the same apply under the carrier's lock.
Three new probes for Drain also pass:
Older over newer: revision 2 noted, then revision 1, then Drain leaves v2. Revision 1 noted again after v2 was applied also leaves v2. Take keeps the highest revision per key (memory.go:910), and takeNow applies the state's current version and skips one older than noted (memory.go:947-958).
Deleted between noting and Drain: the file on the other node is neither changed nor removed (current returns nil and nothing is done). The next look carries it again as a lost key, as §9 says.
Burst while draining: 60 changes over 20 files, noted while a real wake loop drained. The other node ended on the newest version of every file. No note is lost: Drain swaps the queue under queueMu (memory.go:922-925), and a note made meanwhile lands in a fresh map and refills the one-slot wake, so another Drain follows. A race that -race reported first came from my probe's shared test clock, not the module.
On the other points:
No spin: wake holds one signal, and one Drain empties everything noted before it. Look and Drain share mu, so a long first Drain (about 450 keys) only delays a look; the 10-second look loop is not time-critical.
After a restart the queue is empty, but the watch hands the whole current set over again at start, so every key is noted again.
The handler now only unmarshals, checks names and notes (memory.go:880-918), which removes the stall seen live.
Not blocking, but worth a follow-up:
A note whose takeNow fails is dropped, and nothing tries it again. This can be a state read that fails or does not answer (memory.go:948). For a file that exists locally the next look reconciles it. For a file this node does not have yet, nothing does until the key changes again or the module restarts, because Look only walks local files. This was the same before (Take's error was only logged), but now a retry is cheap: put the key back in the queue on an error that is not errChangedHere or errNotCarried.
The gate's report says "judging 0 module(s) changed against 4 machine(s)", then "a merge would rebuild 1 module(s) in 1 tier(s): claude-code". Check this on the recheck.
Verdict: approve at e46eeb829853c4b6a9704d3747554338fbac1392
The code is approved, but the required checks are not green: mesh/merge-gate and mesh/repo-check are both pending, "out of date: judged against trunk 5f491e0c097d, the trunk is now 4d15a155e634". Ask mesh-delivery.recheck and merge only on the new verdict.
I ran this niced with -race in a throwaway clone. The module's suite passes (`ok claude-code/cmd/claude-code 5.5s`). I reran my seven probe tests from reviews 205 and 207 against this head, now through Take then Drain. All seven pass: the traversal names, the secret after a removal, the secret after a conflict, the unreadable file, the unlistable folder and subfolder, the conflict whose write fails (one warning, the state not grown, both nodes equal after recovery), and non-UTF-8. Drain keeps every safety property, because it calls the same `apply` under the carrier's lock.
Three new probes for Drain also pass:
- Older over newer: revision 2 noted, then revision 1, then Drain leaves v2. Revision 1 noted again after v2 was applied also leaves v2. `Take` keeps the highest revision per key (memory.go:910), and `takeNow` applies the state's current version and skips one older than noted (memory.go:947-958).
- Deleted between noting and Drain: the file on the other node is neither changed nor removed (`current` returns nil and nothing is done). The next look carries it again as a lost key, as §9 says.
- Burst while draining: 60 changes over 20 files, noted while a real wake loop drained. The other node ended on the newest version of every file. No note is lost: `Drain` swaps the queue under `queueMu` (memory.go:922-925), and a note made meanwhile lands in a fresh map and refills the one-slot `wake`, so another Drain follows. A race that -race reported first came from my probe's shared test clock, not the module.
On the other points:
- No spin: `wake` holds one signal, and one Drain empties everything noted before it. Look and Drain share `mu`, so a long first Drain (about 450 keys) only delays a look; the 10-second look loop is not time-critical.
- After a restart the queue is empty, but the watch hands the whole current set over again at start, so every key is noted again.
- The handler now only unmarshals, checks names and notes (memory.go:880-918), which removes the stall seen live.
Not blocking, but worth a follow-up:
- A note whose `takeNow` fails is dropped, and nothing tries it again. This can be a state read that fails or does not answer (memory.go:948). For a file that exists locally the next look reconciles it. For a file this node does not have yet, nothing does until the key changes again or the module restarts, because Look only walks local files. This was the same before (Take's error was only logged), but now a retry is cheap: put the key back in the queue on an error that is not errChangedHere or errNotCarried.
- The gate's report says "judging 0 module(s) changed against 4 machine(s)", then "a merge would rebuild 1 module(s) in 1 tier(s): claude-code". Check this on the recheck.
Merge check at e46eeb82
Judged: head e46eeb829853 merged into trunk 4d15a155e634; read beside it: mesh-controller 6f1a05366c1d, mesh-controller-main 6f1a05366c1d, mesh-host 0e92ef3d1b21, mesh-tools 954e1a53eef9
mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: claude-code)
mesh/repo-check: PASS — its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
Delivery plan — builds claude-code → ace, g14, novox, shanks; no bus step
tier 0: claude-code
ace: receives claude-code
g14: receives claude-code
novox: receives claude-code
shanks: receives claude-code
claude-code keeps data (ADR 0233): what it holds is backed up before it moves
grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before claude-code is judged on its first machine
read by no module's build: modules/claude-code/cmd/claude-code/memory_test.go
Run by the build seat on ace as build-1791903293106962305 (builds --log build-1791903293106962305).
--- the gate: claude-code
note: claude-code uses the seat "operator-channel", which no module declares and the mesh does not define among the manifests given; registration judges it against the whole catalogue, and passing the declaring module's manifest too judges it here
claude-code: ok, 48 tool(s), keeps state servers, holdings, config, proposals, questions, memory, reads claude-licence-manager.bindings, keeps agent-home (valuable); WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 1
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 0 module(s) changed against 4 machine(s), as the snapshot of 2026-10-13T14:52:41Z says they run
composing every machine as the mesh is
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
composing every machine with the change
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose)
judged by controller development build against the facts of 2026-10-13T14:52:41Z
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 1 module(s) in 1 tier(s): claude-code
notes:
- modules/claude-code/cmd/claude-code/memory_test.go read by no module's build, and rebuild nothing (issue 280)
--- its merge-check.sh (go toolchain)
ok git.novox.be/novox/mesh-catalog/checks/words 0.002s
words: 12 retired words and 70 daemons' lines, none in the 46615 strings of 717 files
ok git.novox.be/novox/mesh-catalog/checks/agenthome 0.012s
agent-home: no archive and no file written into under the agent's home
ok git.novox.be/novox/mesh-catalog/checks/secrets 0.012s
secrets: no setting can replace a vault secret in a mergeable file (1 known, nested)
ok git.novox.be/novox/mesh-catalog/checks/paths 0.005s
paths: no module names another's state on its machine (3 known, listed to go)
long-running resources without health: 66, as kept
ok git.novox.be/novox/mesh-catalog/checks/deps 0.205s
testing modules/claude-code
ok claude-code/cmd/claude-code 5.947s
--- its merge-check-typescript.sh (typescript toolchain)
**Merge check** at `e46eeb82`
Judged: head `e46eeb829853` merged into trunk `4d15a155e634`; read beside it: mesh-controller `6f1a05366c1d`, mesh-controller-main `6f1a05366c1d`, mesh-host `0e92ef3d1b21`, mesh-tools `954e1a53eef9`
- `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: claude-code)
- `mesh/repo-check`: **PASS** — its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
**Delivery plan** — builds claude-code → ace, g14, novox, shanks; no bus step
- tier 0: claude-code
- ace: receives claude-code
- g14: receives claude-code
- novox: receives claude-code
- shanks: receives claude-code
- claude-code keeps data (ADR 0233): what it holds is backed up before it moves
- grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before claude-code is judged on its first machine
- read by no module's build: modules/claude-code/cmd/claude-code/memory_test.go
Run by the build seat on ace as `build-1791903293106962305` (`builds --log build-1791903293106962305`).
```
--- the gate: claude-code
note: claude-code uses the seat "operator-channel", which no module declares and the mesh does not define among the manifests given; registration judges it against the whole catalogue, and passing the declaring module's manifest too judges it here
claude-code: ok, 48 tool(s), keeps state servers, holdings, config, proposals, questions, memory, reads claude-licence-manager.bindings, keeps agent-home (valuable); WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 1
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 0 module(s) changed against 4 machine(s), as the snapshot of 2026-10-13T14:52:41Z says they run
composing every machine as the mesh is
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
composing every machine with the change
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose)
judged by controller development build against the facts of 2026-10-13T14:52:41Z
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 1 module(s) in 1 tier(s): claude-code
notes:
- modules/claude-code/cmd/claude-code/memory_test.go read by no module's build, and rebuild nothing (issue 280)
--- its merge-check.sh (go toolchain)
ok git.novox.be/novox/mesh-catalog/checks/words 0.002s
words: 12 retired words and 70 daemons' lines, none in the 46615 strings of 717 files
ok git.novox.be/novox/mesh-catalog/checks/agenthome 0.012s
agent-home: no archive and no file written into under the agent's home
ok git.novox.be/novox/mesh-catalog/checks/secrets 0.012s
secrets: no setting can replace a vault secret in a mergeable file (1 known, nested)
ok git.novox.be/novox/mesh-catalog/checks/paths 0.005s
paths: no module names another's state on its machine (3 known, listed to go)
long-running resources without health: 66, as kept
ok git.novox.be/novox/mesh-catalog/checks/deps 0.205s
testing modules/claude-code
ok claude-code/cmd/claude-code 5.947s
--- its merge-check-typescript.sh (typescript toolchain)
```
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.
Fixes the failed live acceptance of issue 367 (ADR 0343) after mesh-catalog#276.
Seen (read-only)
watching the agent's memory not yet (the current values of memory did not arrive in 10s); g14's the same, every minute since. At 16:37:59 shanks logged ~450 linesclaude-code did not take put operator.… of memory: mesh/state names no watch of this bundle.deliverwaits for the bundle's answer) and gives the whole current setStateTimeout= 10 s, then stops the watch.Take(the handler) read the state (Get, a round trip), waited for the carrier's lock (held by a look for its whole run) and wrote files, for each of ~450 values. So the watch never started on any node; a file written on g14 was put in the state by g14's look (g14'sclaude_code_memorylists it, which it records only after the state write succeeds) but no node watched it. The first carrying at 14:31Z on shanks came from the values the failed watch attempts did apply before timing out, and from shanks's own look.Fix
Takenow only checks the value and notes the key's newest revision, then returns. A worker (Drain, woken byTake) applies what was noted under the carrier's lock, at the state's current version, as before.Test
TestTheWatchHandlerReturnsAtOnceAndDrainAppliesWhatItNoted: 400 hand-overs while a look holds the carrier and the state does not answer must all return within a second; thenDrainapplies the change. On main it fails:the watch handler waited for the look or the state (0 of 400 returned). Every other memory test now drains after handing over, as the worker does.go test -raceandmerge-check.sh(MESH_CHECK_MODULES=claude-code, controller from main) pass.Acceptance after delivery: the journal on g14 and shanks says
watching the agent's memorywithoutnot yet, and the operator's test file written on g14 is listed byshanks/claude-code.claude_code_memorywith g14's fingerprint within a minute.Delivery
novox/mesh-catalog@e46eeb829853— delivered since 2026-10-13T15:02:03ZDelivery plan — builds claude-code → ace, g14, novox, shanks; no bus step
Machines
Transitions
5f491e0c09, the trunk is now 4d15a155e634; judged again on a recheck or when it is mergedThe commit's note under
refs/notes/mesh-plankeeps every transition:git log --notes=mesh-plan.Merge check at
e46eeb82Judged: head
e46eeb829853merged into trunk5f491e0c097d; read beside it: mesh-controller6f1a05366c1d, mesh-controller-main6f1a05366c1d, mesh-host0e92ef3d1b21, mesh-tools954e1a53eef9mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: claude-code)mesh/repo-check: PASS — its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)Delivery plan — builds claude-code → ace, g14, novox, shanks; no bus step
Run by the build seat on shanks as
build-1791902475612885975(builds --log build-1791902475612885975).Verdict: approve at
e46eeb8298The code is approved, but the required checks are not green: mesh/merge-gate and mesh/repo-check are both pending, "out of date: judged against trunk
5f491e0c09, the trunk is now 4d15a155e634". Ask mesh-delivery.recheck and merge only on the new verdict.I ran this niced with -race in a throwaway clone. The module's suite passes (
ok claude-code/cmd/claude-code 5.5s). I reran my seven probe tests from reviews 205 and 207 against this head, now through Take then Drain. All seven pass: the traversal names, the secret after a removal, the secret after a conflict, the unreadable file, the unlistable folder and subfolder, the conflict whose write fails (one warning, the state not grown, both nodes equal after recovery), and non-UTF-8. Drain keeps every safety property, because it calls the sameapplyunder the carrier's lock.Three new probes for Drain also pass:
Takekeeps the highest revision per key (memory.go:910), andtakeNowapplies the state's current version and skips one older than noted (memory.go:947-958).currentreturns nil and nothing is done). The next look carries it again as a lost key, as §9 says.Drainswaps the queue underqueueMu(memory.go:922-925), and a note made meanwhile lands in a fresh map and refills the one-slotwake, so another Drain follows. A race that -race reported first came from my probe's shared test clock, not the module.On the other points:
wakeholds one signal, and one Drain empties everything noted before it. Look and Drain sharemu, so a long first Drain (about 450 keys) only delays a look; the 10-second look loop is not time-critical.Not blocking, but worth a follow-up:
takeNowfails is dropped, and nothing tries it again. This can be a state read that fails or does not answer (memory.go:948). For a file that exists locally the next look reconciles it. For a file this node does not have yet, nothing does until the key changes again or the module restarts, because Look only walks local files. This was the same before (Take's error was only logged), but now a retry is cheap: put the key back in the queue on an error that is not errChangedHere or errNotCarried.Merge check at
e46eeb82Judged: head
e46eeb829853merged into trunk4d15a155e634; read beside it: mesh-controller6f1a05366c1d, mesh-controller-main6f1a05366c1d, mesh-host0e92ef3d1b21, mesh-tools954e1a53eef9mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: claude-code)mesh/repo-check: PASS — its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)Delivery plan — builds claude-code → ace, g14, novox, shanks; no bus step
Run by the build seat on ace as
build-1791903293106962305(builds --log build-1791903293106962305).