Commit Graph
999 Commits
Author SHA1 Message Date
jschoubben e2380404a1 Act on a backup answer whatever runs, say why a module stays held, and let the engine's read tool show its want and its hold (issue 1585)
mesh/delivery merged: source.main moved to novox/mesh-host@e73aae3686a6
mesh/check being carried to e2380404a1fa on e73aae3686a6 | from 998d8f737008
nats on novox, 2026-11-04 11:07: after mesh-host #207 the module stayed held
although its want carried "Back up again", and the engine said nothing. The
engine's composition verb showed it running what its want names (taken from
its held have at the start), so when the answer was in a revision of the want
read after the hold, settleOne returned on "it runs what the want names"
before it looked at the hold: the answer was swallowed, silently. The start
path #207 fixed was right but never met; no test ran the live shape.

- settleOne: the hold is looked at before what runs. An answer (again or
  skip) in a want revision after the one the hold took is acted on whatever
  runs; with no answer the hold is kept and said with both revisions.
- baseline: the hold kept at the start is said (it was the silent branch).
- composition verb: the want as the engine holds it now carries self, backup,
  words and its key's revision, beside the engine's attempt (held, answered
  revision, want and composition revisions, transient) and whether the module
  was looked at since the start, so which want the engine read is read, never
  guessed.

Quick fix: answer once more by hand (a new want revision), which the guard
still swallows while what runs equals the want, so none exists. Thorough fix,
chosen: the order of the guards and the read tool, proved by rows of the live
shape (a self module of policy record, its held have naming the want's own
composition, the answer before the start, and again and skip arriving while
held); the two later rows fail with the old guard order.

Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
2026-11-04 11:36:14 +01:00
mesh-tools 998d8f7370 Merge pull request 'Node-engine: a stop never cuts a save off, an archive's unpack is recorded at once, and an answer the want carries is acted on at start (issue 1585)' (#207) from fix/archive-record-at-unpack into main 2026-11-04 10:04:25 +00:00
jschoubben 5dc3a8e17f Keep what an archive unpacked in the engine's own state directory, never beside the archive, and stop no slower than the host waits (issue 1585, review round 1)
mesh/delivery merged: source.main moved to novox/mesh-host@998d8f737008
mesh/check being carried to 5dc3a8e17f97 on 998d8f737008 | from fabfdf04f78a
The journal of an unpack sat at <target>.unpacked.json, in a directory
the module's account may write: a forged one would make the root engine
remove or adopt any path it named. It now lives under
<statedir>/unpacked/<sha256 of the target>.json, mode 0600, names its
target, and is refused whole when an entry is not filepath.IsLocal or a
parent is not above the target. It goes when the archive is taken off,
whether its state record still said what it unpacked or not.

The launcher's stop grace for a host on trial rises from 20 s to 75 s and
the unit's TimeoutStopSec is 120 s (openrc the same), past the host's own
60 s wait for the apply in flight, so neither cuts a save off again.

Tests folded as rows into existing ones (the repository is over its unit
budget): the journal's rows, a forged entry and parent refused, the
journal gone with a record that lost its Unpacked; the test that passed
on main dropped; the stop test waits on its own line, not a sleep, and no
longer consumes the save it waits for.

Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
2026-11-04 10:52:42 +01:00
jschoubben 768f637bd0 Act at the engine's start on a backup answer the want already carries, so an answer written before a restart is never swallowed (issue 1585)
nats on novox, 2026-11-04: the operator answered "Back up again", the
engine restarted, and baseline() took the hold with AnsweredRev = the
want's current revision, so the answer in that very revision was never
acted on and compose refused "held for a failed backup".

Quick fix: answer once more (a new want revision). Thorough fix, chosen:
at baseline, a held module whose want carries again or skip is applied
(again backs it up first, skip goes on without one); a hold with no
answer stays held. The cost said in the code: an answer already acted on
before a stop, whose backup failed again, is tried once more per start.

Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
2026-11-04 10:36:48 +01:00
jschoubben ee0f46b78f Stop between applies and save the node's state as one writer, so a stop never cuts a save off and loses its records (issue 1585)
On novox the node-engine's state had lost the records of nats's two
archives, which only a temporary save file of 2026-10-24 still held, and
about 260 such files (~80 MB) lay beside it. The cause: an apply runs
detached from the engine's stop (applyContext, WithoutCancel), and
runLink returned, and the process ended, without waiting for it; a save
cut between its write and its rename left its temporary file and the
state before it, and whatever the apply did was never recorded.

Quick fix: remove the leftover files by hand and restore the records.
Thorough fix, chosen: the engine ends between applies whichever way it
ends (a stop, standing aside, a move to another bus): it waits up to 60 s
for the apply in flight, then lets no save start (store.Quiesce). Save is
one writer per process, flushes the directory after its rename, and says
loudly each record the state saved before held that this save drops and
nothing forgot (Forget, Release mark what is dropped on purpose, and no
longer write into an array an earlier copy reads). The engine's start
removes leftover temporary saves under the apply lock and says how many.

Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
2026-11-04 10:36:48 +01:00
jschoubben 84a14b08d5 Write down what an archive unpacked as soon as it is unpacked, so a lost record never makes the host's own files foreign (issue 1585)
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
2026-11-04 10:26:43 +01:00
mesh-tools fabfdf04f7 Merge pull request 'Node-engine: hand a moved module by its manifest, its build and the machine, never by the vault's reading of its plan (issue 1966)' (#206) from fix/handed-one-rule into main 2026-11-04 09:16:13 +00:00
jschoubben 966093d8d0 Hand a moved module by its manifest, its build and the machine, never by the vault's reading of its plan, so a node with no plan yet makes the plan that hands it (issue 1966)
mesh/delivery merged: source.main moved to novox/mesh-host@fabfdf04f78a
mesh/delivery-group group fix/handed-one-rule merged: every member is merged
mesh/check being carried to 966093d8d067 on fabfdf04f78a | from 4d47ff5ce743, mesh-catalog dd458cb155f5
The vault judged a module handed only when its assignment already carried a handing plan, and the node-engine followed
that word: a module with no plan was composed the old way, refused for a key only the provider's helper answers
(forge-account's ssh_alias), and so never got its plan. resolution.Handing is now the manifest, its build and the
machine alone; the vault's word is read only to say where the two disagree. A refusal of a file or an own secret the
provisioner's client should fill now says "handed module not handed" and why, never only the keys a binding lacks or a
secret to make.

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
2026-11-04 09:41:10 +01:00
mesh-tools 4d47ff5ce7 Merge pull request 'Node-engine: a node names its provisioner account even when no module's files are filled this pass (issue 774)' (#205) from fix/node-account-always into main 2026-11-04 08:39:53 +00:00
jschoubben 8e32583089 A node names its provisioner client's account whenever a client runs there, filled files or not (issue 774)
mesh/delivery merged: source.main moved to novox/mesh-host@4d47ff5ce743
mesh/check being carried to 8e325830891c on 4d47ff5ce743 | from 6019c6d514a7
The declaration named the account only beside its filled files (node.go), so a node whose every filled-file module
was held this pass named none: on ace from 2026-11-04 01:29 its build modules and ssh-client were held for their
forge binding, and the node-engine refused every write of the files they keep, and of every other module's. The
account is the node's, named whenever the rendering has one. A row holds restic, the provisioned mesh's one
filled-file module, with the client placed: the node's own still names the account; it named none before.

Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
2026-11-04 02:17:01 +01:00
mesh-tools 6019c6d514 Merge pull request 'Node-engine: a held provisioner client keeps its account; a module waiting for a yes has its new build read (issues 774, 1585)' (#204) from fix/frombus-inown-build into main 2026-11-04 01:05:49 +00:00
jschoubben 054754482c The running provisioner account is kept only for a client held this pass, and rows hold the guard (issue 774, review)
mesh/delivery merged: source.main moved to novox/mesh-host@6019c6d514a7
mesh/check being carried to 054754482cf4 on 6019c6d514a7 | from 83e135f10187
The review removed the guard and the suite still passed. The guard is now provisionerHeld, a placed client held as
its stand-in, rather than any placed client, so one placed and not held that composes no account keeps none stale.
Rows in the held client's table: the client taken out of the node's placement while what runs names the account, read
from the running own composition and from the client's running process, names no account; a placed client whose
process names no user names none. With the guard removed the first three fail; with it reduced to "placed", the last.

Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
2026-11-04 01:53:29 +01:00
jschoubben f7129fdb41 node-engine.composition shows the node's own fields and what the last pass held (issue 774)
Reading ace's node composition gave four resources twice and no way to see that one revision named no provisioner
client's account. The verb now shows, for module node, the revision's provisioner account beside what runs names, its
adoption, how many identities, groups and libraries it names, and each module the composer's last pass held with why.

Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
2026-11-04 01:50:21 +01:00
jschoubben f7abd05981 A node composition that drops the provisioner client's account what runs names is said (issue 774)
Applied, a node's own composition naming no account refuses every filled write and hands no module, which on ace
went unsaid from 01:29 to 01:33 but for the refusals themselves. The pass now says it once, naming the account what
runs names. A placed client keeps its account by the previous commit; this says the case that is left, a client no
longer composed here.

Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
2026-11-04 01:48:12 +01:00
jschoubben 514cf23aef The provisioner client's account stays named while the client is held: a held client keeps the node's handing (issue 774)
provisionerAccount reads the user of the client's process from this pass's plan, and a client held as its stub (or
carried as it runs) composes no process: on ace, 2026-11-04 01:29 to 01:33, the node's own composition named no
account, the node-engine refused every filled write, and no module was handed (postgres's consumers, restic, power).
A node now carries the account its client runs as (Node.RunningProvisioner: its own composition's account as it runs,
else the user of the client's running process), and a placed client that composes none this pass keeps it. A row holds
the client in the provisioned mesh, both ways: the account stays and restic keeps its filled files; both were lost
before.

Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
2026-11-04 01:47:19 +01:00
jschoubben 95b509e0d2 A module in InOwn wanted at a build of the new form has its build taken in: the reader and the composition fold by one rule (issue 1585)
frombus skipped reading the build of every module in Scope.InOwn, while compose.compositions folds such a module only
at no src2: fingerprint: a want at src2: (nats on novox, its have waiting for a yes) composed it from the indexer's
unresolved manifest and built() refused it, "no build has published" its server artifact. compose.Folds is now the one
rule; frombus takes the build in, or keeps the module at its wanted build, exactly where it says the module is not
folded. A row composes spiegel, in InOwn and wanted at src2:, from its build's upstream image; it read the indexer's
manifest before.

Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
2026-11-04 01:31:27 +01:00
mesh-tools 83e135f101 Merge pull request 'L3 final: the node-engine reads core-credentials and tool-runner with no fallback, and states its manifest reads (ADR 0601 §4, ADR 0614 §4, issue 774)' (#203) from feat/l3-final into main 2026-11-04 00:23:56 +00:00
jschoubben 30b86ea602 An input carries the modules it holds as their stubs across the bus, and the sandbox names why the node-engine holds one (issue 774, group check 278aa5f0ccbe)
mesh/delivery-group group feat/l3-final merged: every member is merged
mesh/delivery merged: source.main moved to novox/mesh-host@83e135f10187
mesh/check checking 30b86ea602a8 on 83e135f10187 | novox/mesh-host#203 in group feat/l3-final
The stub's mark (Manifest.Stubbed) is no field of a manifest's JSON, so an input a node-engine sent the check's
sandbox lost it: node-tools, held by its manifest's verdict, read as a tool runner with no bundle and refused every
module of ace, g14 and shanks for "its build produced 0 bundle(s)". compose.Input now writes its held modules (catalogue
and each node's kept) beside its fields and marks them again on reading; an input from an engine before the mark is
read by its contract, every module Refused names held as its stub. The sandbox composer also says, in the module's
read, why the input's node-engine holds a module the case carries, so the check names the cause, not a rule about the
stub. One subtest round-trips an input holding a refused tool runner, in both shapes; it refused for 0 bundles before.

Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
2026-11-04 00:45:35 +01:00
jschoubben 32a99144f6 The node record states the reader capabilities of the mesh-sdk the engine is built with (ADR 0614 §4, issue 774)
mesh/delivery closed: a newer head of the same pull request
mesh/delivery-group group feat/l3-final checking: 3 of 5 member(s) ready
mesh/check failed (2): unit: mesh-provisioner-client/cmd/mesh-provisioner-client.TestNatsANodeComingBackFil…; and 1 more | 32a99144f65e on 798d73eb11e9
recordOf writes catalogue.ManifestReads in NodeRecord.ManifestReads, once per build, so the assigner moves a want only
to an engine that reads its manifest. A row holds the engine's own manifest to the baseline's words, so its new build is
never held for a word only it reads.

Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
2026-11-03 23:29:17 +01:00
jschoubben 3544d644ba Pin mesh-sdk 85ba0a9a70d8, the head of feat/l3-final: the contract states the reader capabilities a node-engine reads and the node record carries them (ADR 0614 §4, issue 774)
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
2026-11-03 23:27:52 +01:00
jschoubben a0ce37fb2c Pin mesh-sdk b7abe203a929, the group's head of feat/l3b-bus: it keeps, deprecated, the exported names the running parts still use
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
2026-11-03 18:50:12 +01:00
jschoubben a24a1d72ad Pin mesh-sdk cf5812101b0b, the group's final head: the module graph is no part of mesh-sdk (ADR 0603, ADR 0604, issue 1367)
mesh/delivery-group group feat/l3b-bus rejected: composed together: the checker's verdict at the members' heads (a1cb9beeb97a): unit: modules/mesh-provisioner.…
mesh/delivery closed: the pull request closed unmerged
mesh/check failed (4): unit: modules/mesh-provisioner.gofmt: not as gofmt writes them (run gofmt -w): modul…; and 3 more | a24a1d72ad45 on 798d73eb11e9
2026-11-03 17:02:14 +01:00
jschoubben 02c7f8e052 Pin mesh-sdk 65b7adc8bdd9; the seat table here takes the SDK's mesh-catalog entry with its four verbs (ADR 0604 section 1) 2026-11-03 16:25:46 +01:00
jschoubben 53b0e8d318 Genesis installs no catalog module: the catalogue step and the take of mesh-catalog go (ADR 0604 section 7, issue 774) 2026-11-03 16:17:27 +01:00
jschoubben c777fbae8f Pin mesh-sdk e7ce86ff62b5, the group's head of feat/l3b-bus (review round 2) 2026-11-03 14:12:50 +01:00
jschoubben 98719a1bd5 Pin mesh-sdk 825483043549, the group's head of feat/l3b-bus (review round 1) 2026-11-03 14:05:07 +01:00
jschoubben 72bcf20870 The bus module's integration test publishes the backup's end at once: the node agent hears it before it asks, so no sleep (review round 1, finding 5) 2026-11-03 14:02:01 +01:00
jschoubben b47668421f The witness judges the tool runner's process by its id, <its module>.runtime, which the composition gives only the module whose manifest says it is the tool runner, never by a name (ADR 0601 §4; review round 1, finding 4) 2026-11-03 14:02:01 +01:00
jschoubben 2239fb253d Rows for the composer's composition of today: the same inputs give the running digest, a changed input another, a build it cannot compose none (ADR 0601 §1; review round 1, finding 2) 2026-11-03 14:02:01 +01:00
jschoubben 7da4deb3f1 What a node keeps of a module as it runs, for a manifest that does not yet say it, is carried on the module's have by module, so the watchman raises its condition (ADR 0601 §4; review round 1, finding 3) 2026-11-03 14:02:01 +01:00
jschoubben b461b005e9 Pin mesh-sdk 09ec82cb3551, the group's head of feat/l3b-bus (ADR 0601) 2026-11-03 13:46:47 +01:00
jschoubben 75e3a26336 The integration test of the bus module's first want shows its node backing it up through the backup seat before that apply and before the one that replaces the server, as every module that keeps data (ADR 0601 §2) 2026-11-03 13:37:42 +01:00
jschoubben 5b455cecfe A have waiting for a yes says whether the move changes the build alone: the composer composes the build the module runs with today's settings and secrets and the agent compares it with what runs, so a release's Approve answers it and a changed setting is still asked (ADR 0601 §1) 2026-11-03 13:35:12 +01:00
jschoubben faa2005538 A node agent that meets a manifest which does not yet say it is the tool runner, or that its own secrets are the core's credentials, keeps what runs of it, its tool runner process and its sealed secrets alike, known by what runs and said; never composed without it (ADR 0601 §4) 2026-11-03 13:31:44 +01:00
jschoubben 6ea23b6731 The sandbox's composer marks a node it does not judge in the contract's field (Machine.NotJudged), neither composed nor refused, never by a prefix of its reason (ADR 0593 §9; the prepare's seams finding on "not judged") 2026-11-03 13:29:21 +01:00
jschoubben db7cd273f0 The node-engine finds the tool runner by what its manifest says (tool-runner), never by its name, pinned at mesh-sdk a973bfa (issue 774, the operator 2026-11-03) 2026-11-03 13:28:44 +01:00
jschoubben 12c80d7c2e The node-engine carries a module's own secrets sealed by the vault when its manifest says they are the core's credentials, pinned at mesh-sdk 4f141ff (issue 774, the operator 2026-11-03) 2026-11-03 13:28:44 +01:00
jschoubben 649ed21d55 The sandbox refuses no module the node holds composing without the change, a module blamed for a refusal among them (issue 774, review round 1) 2026-11-03 13:28:44 +01:00
jschoubben 23cbf9294a The node agent's applies run through a runner its options name, so one integration test proves the bus module's first want takes the bus server over from the node's own composition without moving it, and a build that changes it replaces it once (ADR 0599 §4, §6) 2026-11-03 13:28:44 +01:00
jschoubben 03b7fcd7bb The sandbox fails a node whose change refuses a module the node-engine did not hold, in that module's words, instead of passing it with the rest composed (issue 774, review of the sandbox input) 2026-11-03 13:28:44 +01:00
jschoubben 7b8f5e7805 The sandbox composes a node as its node-engine does, from an input that says how, and names a node it cannot judge from an older engine's input (issue 774, ADR 0593 §9) 2026-11-03 13:28:44 +01:00
mesh-tools 798d73eb11 Merge pull request 'compose-candidate reads each manifest once and answers within its bound, from each ask's arrival' (#200) from fix/1126-compose-wait into main 2026-11-03 01:02:32 +00:00
jschoubben df13a83a91 The sandbox composes a node from the input its engine took in, through one shape
mesh/delivery merged: source.main moved to novox/mesh-host@798d73eb11e9
mesh/check checking df13a83a9117 on 798d73eb11e9
The second sandbox fault of the same kind on mesh-host #200 (postgres's secret
reader handed, the module not): the engine stripped the whole catalogue from
the input it answers, so the sandbox composed the node's own modules from the
indexer's source manifests while the bus reader composes them taken in from
their builds (artifacts, templates archive texts, what is handed). Both sides
now go through composer.SentInput: the node's own taken-in manifests and kept
builds stay in the input, and the sandbox composes them over the cases'. An
input past what one bus answer carries is refused in words. A conformance row
composes one node through the bus reader and through the sandbox and requires
the same declaration.

Issue 1126.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-03 01:55:08 +01:00
jschoubben 61a3bd996d The sandbox composer carries the module the mesh provides itself
mesh/delivery closed: a newer head of the same pull request
mesh/check failed: novox: not composed on novox: postgres: its own secret reader is handed to the provisioner and the m… | 61a3bd996dd4 on 27a956448c0a
A check that composes with a candidate's own composer (any mesh-host change)
gave it the indexer's manifests alone, and the input carries no catalogue, so
mesh-wireguard (shipped with mesh-sdk, no repository) was missing: "nothing
provides mesh-wireguard / mesh-addressing" on novox for mesh-host #200. Each case
now lays the provided module's manifest over its shelf, as the bus reader does.

Issue 1126.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-03 01:44:15 +01:00
jschoubben b8158affa7 compose-candidate is answered off its subscription, so its bound counts from the ask
mesh/delivery closed: a newer head of the same pull request
mesh/check failed: novox: not composed on novox: these assignments cannot be applied: | b8158affa7af on 27a956448c0a
An endpoint's subscription hands its asks over one at a time: two checks asking
one node at once queued, and the second answered at about 100 s, past the
checker's bound and the bus's one-minute reply window. compose-candidate is now
answered in a goroutine of its own, at most four at once, one more refused in
words. The new cases are rows of the existing tests (test budget).

Issue 1126, review round 1.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-03 01:28:45 +01:00
jschoubben ebb4f4af18 compose-candidate reads each manifest once and answers within the bus's reply window
Off the control-node an ask of compose-candidate ran into its 60 s bound: each of
its two compositions read every manifest in the mesh one key at a time over the
bus, on scratch copies of the shadow that kept nothing, so each ask read them all
twice again (about 35 s per composition on ace, g14 and shanks; 2 s on novox).
The answer at 60 s then came after the bus's one-minute reply window
(allow_responses ttl), so the bus refused it and the checker heard nothing.

Now the manifests are read eight at a time into the shadow before either
composition, a scratch copy keeps what never changes (manifest, archive, done
build) in the shadow too, the candidate is laid over a copy taken after the
composition without it, and the engine answers within 50 s: unready, naming what
it waits on, when not done. Every answer is said in one journal line with its
reads and its longest wait.

Issue 1126.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-03 01:23:17 +01:00
mesh-tools 27a956448c Merge pull request 'compose-candidate reads the candidate by its group, as the indexer stores it' (#199) from fix/compose-candidate-key into main 2026-11-02 23:14:57 +00:00
jschoubben 0bbdae1d9d compose-candidate reads the indexer's candidate by its group key, not the check's key
mesh/delivery merged: source.main moved to novox/mesh-host@27a956448c0a
mesh/check checking 0bbdae1d9dfb on 27a956448c0a
The checker asks by the composition key, <group>.<heads hash> (ADR 0593 §7), but the
indexer keys a candidate by its group alone (delivery.CandidatesKey). The node-engine
read the ask's key as the bucket key, so every check's composition was refused on
every node with "the indexer holds no candidate" (mesh-catalog #599, 2026-11-02).

It now parses the ask, reads CandidatesKey(group), and answers unready when the
group's candidate has moved to other heads. Both tests' fixtures had captured the
wrong key; they now key by group, with a slash in the group name.

Quick fix: this lookup. Thorough fix (a shared SDK reader that takes a composition
key and returns the candidate at those heads) not taken: one reader, one repository.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-03 00:05:04 +01:00
mesh-tools 4c7056de42 Merge pull request 'sdk1: the node-engine alone composes and answers compose-candidate (ADR 0593)' (#198) from feat/sdk1 into main 2026-11-02 20:42:47 +00:00
jschoubben ae4b86e333 route-proxy's proof skips aloud when mesh-networking is not beside, since the running checker places none for the node-engine until this release is delivered
mesh/delivery merged: source.main moved to novox/mesh-host@4c7056de4241
mesh/delivery-group group feat/sdk1 merged: every member is merged
mesh/check checking ae4b86e33300 on 98fbc490a4c9 | novox/mesh-host#198 in group feat/sdk1
With mesh-networking beside, or with nothing beside and the captured copy read, it still judges the manifest.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-02 20:39:56 +01:00