pacman keeps one mirror list for the mesh and reads each node's own packages; the provisioner composes once (ADR 0585, ADR 0565 §6, ADR 0570; issues 1876, 1953, 1954)
#588
Merged
mesh-toolsmerged 9 commits from feat/node-packages into main2026-11-01 17:02:29 +00:00
A test that slept a fixed time and then asserted what a goroutine, process or
watcher did failed under the checker's load. Each now waits for its positive
evidence (a started baseline, a call counted, a state reached) within 30 s, and
the concurrency-limit tests meet at a barrier instead of overlapping by sleep.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
mesh/delivery-group group feat/node-packages rejected: composed together: the checker's verdict at the members' heads (98ce55efa892): unit: i3/cmd/i3-tools.Tes…
The opener ranked the list and took its turn in the same step, so its upgrade started
before the keeper's change hook wrote /etc/pacman.d/mirrorlist, and a failed write on
any node was only logged. A round's run now writes the list first and checks the file
holds the revision the round opened with; otherwise the run is refused with why and
tried again an hour later, as every refused run is. A refresh asks again for a running
round right before its write, since ranking takes minutes.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The delivery group feat/node-packages pins one mesh-sdk head in every member: pacman reads EnginePackagesRead from it, and mesh-provisioner composes a node once with it.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
provisioner_compose took 2.6-13.6 s per node with nothing changed, CPU
bound. The node is now composed at its wanted and its newest builds over
one read (frombus.PlansHeldTwice, whose composer resolves each machine
once), its own plans, provisions and refusals and the providers' entries
are read from the watched copy, its own writes taken in at once, and a
provider's manifest once by digest: no read by key per composition is
left. The result says where the time went, phase by phase, and a slow
composition that changed nothing says it in the log.
BenchmarkComposeNode times it over a mesh captured with the read tools
(MESH_COMPOSE_CAPTURE): novox 11.7 s to 0.49 s, ace 0.49 s, g14 and
shanks 0.39 s; plans and provisions identical to before over nine
compositions of the four nodes.
Needs mesh-sdk feat/compose-once (5d26c65); go.mod still pins the old
mesh-sdk until the group pins its head.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
Each node's reflector ranked its own list on its own timer, and on 2026-10-31 one node's
lagging first mirror left it a Node.js version behind the rest. The list is now the
module's state mirrors, key list: the node that opens a week's round ranks it with the
module's reflector options, keeps only mirrors whose last sync is no older than the
newest found, and the round's key names the list's revision. Every keeper writes
/etc/pacman.d/mirrorlist whole from the key through the root helper's new verb
mirrorlist, when the key changes and when the file differs, and never writes an empty
or unreadable list. reflector.timer is declared stopped and disabled, and reflector.conf
saves nothing. pacman_mirrors answers the shared list, its ranker and age and whether
this node's file matches; with refresh it asks this node's keeper to rank again,
refused while a round runs, naming it. The round's integration test proves the opening
write and both nodes' files.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The read node-engine.packages named a bucket node-engine_packages that nothing writes:
the engine's manifest is mesh-host's, so its state is mesh-host_packages, read as
disk-load reads mesh-host.data. The view still names which source answered, the
engine's key or the controller's mirror.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL