Commit Graph
77 Commits
Author SHA1 Message Date
jschoubben 0b03b9c7c5 mesh-grants: create a module's object buckets and history streams, grant their readers read-only, and warn at 75 percent
ADR 0592 §5, §6, §9, §25 (the grants part's share by ADR 0593 §10): an object bucket and a stream that
keeps its history are created create-only with their caps and no age limit, refusing new data when full;
the owner alone writes its bucket and a module its grant names reads it; the part raises
mesh-grants.history-full once any passes 75 percent. Each engine also reads the indexer's manifest
verdicts by one key for compose-candidate.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-02 18:56:19 +01:00
jschoubben 74304052b4 mesh-grants: every node's engine writes its own compositions and the named readers read them all
ADR 0593 §6, §7: the grants part creates composed-<node> per node, grants each engine the writes of its
own bucket and a direct get of the indexer's candidates for compose-candidate, and grants
mesh-host.composed read-only, with the stream listing and creation advisory a per-node read needs, to
the provisioner, the assigner and the view alone; memberships issue it per node.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-02 18:56:19 +01:00
jschoubben 78fedabeb1 mesh-grants: own the bus's composer, so a change to who may say what rebuilds only the grants part
ADR 0593 §1: buscompose's engine moves from mesh-sdk into mesh-grants/internal/buscompose, its golden
user lists unchanged; the controller's raise and assert code is left behind, and the merged switch
test runs inside the part's whole integration test.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-02 18:56:19 +01:00
jschoubben 6a4d88265d Say mesh-grants.consumer-behind again only when the consumers behind change, not their counts
The counts change every pass, so a consumer that stays behind was said to the operator again at each pass. The
condition names the consumers alone; how far each is stays in the last pass.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-02 12:23:23 +01:00
jschoubben 8f9766e46c Let the grants part say an account consumer far behind as mesh-grants.consumer-behind
The self-check's bus-consumer probe judged consumers the controller defined, and with the controller ended it judges none
(issue 1126). The grants part owns the account consumers, so it says when one stays more than 1000 messages behind its
stream's head at two passes running, the probe's bound and confirmation, and clears it once none is.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-02 12:03:29 +01:00
jschoubben 8d4c13427a Build against mesh-sdk without the controller (issue 1126)
mesh-sdk's group B member renames the grant to Grant, drops the
controller principal, the signer and the lease fields from the user
list key, and the keeper's and config's take-over verbs. The grants
part, the assigner and the view use the new names; the judge's copies of
the health and config seats follow; the tests' fixtures lose the
controller's user, and the refused principal is one removing what the
closed set does not name, the controller's mirror being gone.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-02 11:46:12 +01:00
jschoubben d4aa1fe11b Hear the keeper alone and stop reading the controller's lease in mesh-grants (issue 1126, B7b)
ADR 0590 §3 ends the choice of a condition source by the keeper's
take-over key: the controller is unassigned and the keeper is the one
source. The part still read the take-over key, fell back to the
controller's condition events when it was absent, and read and watched
the controller's lease, which nothing writes any more. It now hears the
keeper's events alone and reads neither.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-02 11:27:19 +01:00
jschoubben 14046f9b14 Remove the lease write, take-over and their tools from mesh-grants (issue 1126, B7a)
The controller ended by its unassignment (ADR 0590), which supersedes the
lease write and its hand-back whole and makes the grants part's list the
only one the bus node follows. The lease write, its check, the removal
marker, the take-over and hand-back asks, their five tools, the seat
claim and the lease and takeover states had nothing left to act on; the
membership notice on its subject had no reader. A whole-module test on
the bus replaces the lease write's: with no controller at all, the part
publishes a membership in its state alone, makes the module's consumer
and writes the key the bus node follows.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-02 11:25:59 +01:00
jschoubben e094e362f4 Run mesh-grants' handed behaviour without the lease (issue 1126, A1)
The controller ended by its unassignment and its lease key expired, so
every gate on "the lease is handed away" stayed shut for good: no account
consumer was created or matched, grant-missing was never raised, the
enrolment users kept the controller's subject, memberships were still
said on their subject and the sealed key never said LeaseHanded. The
handed branch now always runs, and a hand-back is gone.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-02 10:33:14 +01:00
jschoubben d1a256b429 mesh-grants: give the enrolment fixture its tunnel key, which an enrolment now requires
mesh-sdk 22c03af (feat/l3-enrol) requires overlay-key on every enrolment; the fixture of the enrolment-user subtest carries one.

(issue 774, review round 1b)

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-02 01:45:53 +01:00
jschoubben 1a1d3a1ecc Compose both of a rotating node's logins from the vault's node-logins, so its engine can test-dial the new one
ADR 0583 §1 (insight 2026-11-01) and §2: the grants part reads the vault's node-logins as its named reader and
composes a node user per login, both while the node rotates and the new one alone after rotation-done; each node's
engine reads its own node's key alone (composed by mesh-sdk while the vault serves rotate-node). The part follows the
state by watch, so a rotation begun or ended composes again at once. A second login is judged its node's when the
list is compared (Placed), and a hash changing by a rotation node-logins names is not counted as a writer changing
several hashes at once (sealed.go). The state not on the bus yet is a standing gap: every node logs in as node.<n>,
as today. Tested as a subtest of TestGrants, no new test function. Built against the group's mesh-sdk head 5000774
through a go.work outside the worktree; the pin is the lead's.

(issue 774, 774/S53)

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-02 01:45:44 +01:00
jschoubben 288364f28d Compose each enrol.<node> user from the seat mesh-enrolment's keys, so a token issued by the seat can be redeemed
ADR 0587 §4: the grants part composes enrol.<node> from a key at live and the vault's hash, granted only the seat's
redeem and its own inbox; §5: when the key ends the user goes. The part reads mesh-enrolment.enrolments as its named
reader and follows it by watch: a key reaching live composes the user, and its end (by the holder, or by the bus at
its expiry) is a change of the key that takes it out, so no consume of the seat's ending events is added beside the
watch (the subtask named one; the watch already hears every end, the bus's expiry included). From the lease write the
user loses the controller's enrolment subject (§6) and the standing gap of the controller's tokens is dropped; before
it the gap stands. Tested as a subtest of TestGrants, no new test function. Built against the group's mesh-sdk head
5000774 through a go.work outside the worktree; the pin is the lead's.

(issue 774, 774/S52)

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-02 01:45:32 +01:00
jschoubben a78fa3db9d mesh-grants reads placement alone and hears no controller event; this repository's manifests depend on the controller only by the lease
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
2026-11-02 00:35:59 +01:00
jschoubben 7ec6767418 mesh-grants holds the seat mesh-grants and writes the controller's lease on the operator's warrant
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
2026-11-02 00:31:35 +01:00
jschoubben f52f47e1ff mesh-grants and the assigner read the grants part's key alone, root-free is each engine's word, and the hand-act log is the seat's alone (ADR 0571 clauses 9 and 11, ADR 0565 clause 11, issues 1953 and 1955)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-01 09:54:22 +01:00
jschoubben 8a98271680 Move the judge's rules and their tests from mesh-sdk into the indexer's judge (ADR 0578 §4)
Issue 1585, S6-S8: 192 judge-only declarations (the strict parser, every manifest problem function, the tables)
moved whole by an AST mover, methods becoming functions; 163 helpers composition keeps too are copied. 245 tests
move with them, reading the captured catalogue through a copy of internal/beside. judge.WithTemplatesFrom and
ReadTreeManifest judge what mesh-sdk's readers now only fill. mesh-delivery's own tests decode. Pinned to mesh-sdk 25a2cec.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-01 02:34:26 +01:00
jschoubben efef7183ef Let grants, builder and checker decode manifests, and the checker judge a change with the indexer's judge (ADR 0578 §2, §3)
Issue 1585, S12: grants, builder and checker read with catalogue.Decode and grants holds a module the indexer
refused; the checker asks the Go build seat to run mesh-judge, built at mesh-delivery's trunk or at the group's
mesh-delivery head when it changes the judge, over the catalogue as the change leaves it, and fails on a refusal.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
2026-11-01 02:15:54 +01:00
jschoubben e7f51caedb Read each membership's last value from mesh-grants' own state and say it on its subject without the assignments stream, so memberships keep flowing once nats_stream_remove takes the stream at the lease write (issue 774, research 072 row 33) 2026-10-31 10:25:20 +01:00
jschoubben 4b194215dc Read and write the seat mesh-placement's state as one key per module and node, converting each node's placement.<node> once at the holder's start (issue 774, research 072 row 37)
The holder writes a node's changed module keys, then its node key as the commit by compare-and-set at
the revision the proposal was laid over, then the placement.<node> mirror for readers not yet delivered.
Every reader assembles through mesh-sdk's PlacementKeys, which reads both forms.
2026-10-31 09:32:32 +01:00
jschoubben 94f555277c Never name the private network the mesh provides as a module missing its grant (issue 774)
mesh-wireguard is provided by the mesh itself (mesh-sdk delivery.ProvidedByMesh): no repository builds it, so the
indexer holds no fingerprint of it and the assigner never wants it by one; the controller composes it with the
node's own. The grants part named it "no fingerprint of the new form: the indexer holds no value of it" on every
pass, a warning nothing could clear (sweep 2026-10-30 item 6).

Quick fix: drop mesh-wireguard by name from the missing list.
Thorough fix, chosen as cheap and covering every module the mesh may provide later: MissingGrants passes over any
module ProvidedByMesh names. The controller says the same of it in mesh-control (its grants and switch lines).
2026-10-30 18:10:55 +01:00
jschoubben 031cfb8277 Compose the user list principal by principal, so one refused principal never freezes it (issue 774)
Met twice on 2026-10-30 (the engine's acts, then mesh-host_health): the composer refused one principal as a
second writer, and that refusal ended the whole composition, so the list in force stood for every principal
while changes piled up; the next list that composed moved 52 users at once (16:37:28).

Quick fix: leave the refused principal out and write the rest (locks that principal out of the bus).
Thorough fix, chosen because the kind was met twice and it hides every other change: ComposeEach composes each
principal on its own; a refused one keeps its grants of the list in force (the part's sealed grants), written as
the composer writes an entry; one the list in force does not carry stays out; a list that would drop one the
list in force carries, whose grants were not kept, is held, said. The refusal is raised as the warning
mesh-grants.principal-refused, by name and why, cleared once it composes, and listed in the pass
(principals_refused). The entry renderer mirrors buscompose.ComposeAccounts's lines and is pinned to them by the
test (the entry the bus loaded is written back byte for byte); it belongs in mesh-sdk as an exported entry writer.
2026-10-30 18:10:26 +01:00
jschoubben c1b28cc4fe Keep each sealed list's permissions one key per user, so no value outgrows the bucket (issue 774)
The sealed-grants value held every user of the last two lists in one value; at 61 users it was refused with
"message size exceeds maximum" (JetStream 10054, 16:37 and 16:55 on 2026-10-30), so the permissions of the
list in force were never kept and a grant judged against them waited.

Quick fix: keep only the newest list in the one value (halves it; it still grows with the mesh).
Thorough fix, chosen because the value grows with every placed module and the kind was met twice: one key per
user and list, sealed-grants.<digest hex>.<user>, and an index sealed-lists naming the kept lists and their users,
written only once every user's key is there; the third list's keys are taken away, and the old one-value key read
as a fallback and removed. mesh-sdk's kvlimit guard (7b02f63) refuses an oversized value before the put through
process.State.Put, which the part's own store (cmd/mesh-grants ownStore.Put) writes through once pinned.
2026-10-30 18:07:26 +01:00
jschoubben 57193ab2e4 Pin mesh-grants to the mesh-sdk that composes no user from the node-engine's manifest, so the whole user list composes again (issue 774)
mesh/delivery merged: source.main moved to novox/mesh-delivery@98594c990287
mesh/delivery-group group fix/runner-carries-no-engine-state merged: every member is merged
mesh/check checking 57193ab2e474 on f7cd4698db7e | novox/mesh-delivery#115 in group fix/runner-carries-no-engine-state
Second meeting of the engine-state-in-runner kind; thorough: the runner
never carries the engine module. The live placement names mesh-host,
and with its health state the runner was a second writer, so every
grant since 13:54 was held back. The seeded-placement test now carries
the engine's manifest and refuses any runner write of mesh-host_*.
2026-10-30 16:32:43 +01:00
jschoubben 4bb1970fef Write the grants part's memberships bare, through mesh-sdk's codec, so the tool runner serves again
The state memberships held the part's wrapper ({node, module, digest, membership, published, retired}) while every
reader takes the bare membership the assignments stream carries: novox's tool runner decoded an empty one and served
no tool. The part now writes membership.EncodeGrantsMembership of a membership published or unchanged, never one held
back. The pass record moves to the pass the part already keeps (user-list at pass): published or why not was there, the
retired seat verbs are added as Result.Retired; grants_membership reads both, so no new state is declared.

Issue 774 (the bus login list, L3). Quick fix: marshal m.Membership here. Thorough, chosen: one codec in mesh-sdk the
writer and the tool runner share, because a hand-built fixture agreed with the mistake. Pins mesh-sdk at the head of
its fix/memberships-shape.
2026-10-30 15:27:06 +01:00
jschoubben e564eaf75f Grants: write the hearings it withholds to its state withheld on change, so the self-check's probe D-heard reads them from the bus and not the controller's store (issue 1955) 2026-10-29 23:51:48 +01:00
jschoubben 5235bb2e79 Assigner and grants part: record hand acts and warrants through the seat mesh-hand-acts, the controller's log only while that seat has no holder and the controller holds its lease (issue 1953 D8)
Pins mesh-sdk 2d2aa7b in the L5 modules.
2026-10-29 22:24:00 +01:00
jschoubben 3b6f3af38e Grants part: create a module's log with the max age it declares, so a log's entries age out as its manifest says (issue 1952)
Its nats fixture gives the tools bundle's account a secret the tool runtime can reach, as mesh-sdk 2e5cc4f asks. Pins mesh-sdk 2e5cc4f.
2026-10-29 22:19:35 +01:00
jschoubben 7dbf7a19a1 Grants part: compose a principal for every own bus account, a tools bundle's with what it may remove, so the bus tools remove the controller's dead-letter consumer and the engine's acts on their own account (issue 1952 S5)
Pins mesh-sdk 7000bd5.
2026-10-29 21:56:13 +01:00
jschoubben b8e8981730 Grants part: hear root-not-free from the seat the take-over key names, never both, so the switch to the condition keeper moves it with the router (issue 1952 G1)
Watchman: subscribe exactly what its grant lets it hear (buscompose.WatchmanHears). Both pin mesh-sdk 69fcb6c.
2026-10-29 21:46:29 +01:00
jschoubben 013b7420f6 mesh-grants: hold a grant only while the loaded list lacks its permissions, read from the part's own record of the lists it sealed, so a release whose bus tools are down still moves (issue 774) 2026-10-29 21:18:21 +01:00
jschoubben c7fbc530da mesh-grants: compose the user list from the running and the trunk manifest, and write a grant only once the loaded list carries it, so L3's parts never use a subject the bus has not loaded (issue 774) 2026-10-29 21:15:55 +01:00
jschoubben b01cf63237 Revert "Merge pull request 'Revert L3: its node-engine removed every held module on novox, the bus server among them (issue 774)' (#109) from revert/774-l3 into main"
This reverts commit c1b4533201, reversing
changes made to d8274204fb.
2026-10-29 21:05:14 +01:00
jschoubben 6771db22ae Revert L3 (mesh-delivery, merge d827420): its node-engine removed every held module on novox, the bus server among them, at 08:54 CET on 2026-10-29 (issue 774)
mesh/delivery merged: source.main moved to novox/mesh-delivery@c1b4533201c8
mesh/delivery-group group revert/774-l3 merged: every member is merged
mesh/check being carried to 6771db22ae69 on d8274204fbed | from mesh-catalog 1555241393fe | novox/mesh-delivery#109 in group revert/774-l3
L3 lands again with two fixes: a held module is never removed, and the grants cover L3's new subjects.
2026-10-29 09:42:29 +01:00
jschoubben b2351a213d Follow L2 under L3: the builder, checker, indexer and view read the seat mesh-placement's placement, the seat's Leased is the lease handed away, and the view keeps no read of the indexer's placement L2 removed (issue 774, ADR 0567 §8, ADR 0549 §3) 2026-10-28 21:54:47 +01:00
jschoubben 685810720e mesh-grants: place by the catalogue's placement alone once the controller's lease is handed away, and refuse any other reader of the assignments in this repository (issue 774, ADR 0549 §3, §6)
Why: after the lease write the assignments are frozen, so the part's union kept a module the catalogue takes off a node
with its account, grant, membership and user-list entry. The lease is read as the assigner reads it
(buscompose.LeaseHandedAway); before it, or with no placement on the bus, the union stands. The read stays declared until
the first change after the lease write, named in modules/assignments-readers with the assigner; a TestGrants row refuses
any other module.json that reads mesh-controller.assignments, as mesh-catalog's checks/placement does for the catalogue.
2026-10-28 21:54:47 +01:00
jschoubben 8e25926e91 mesh-grants: the node-engine's manifest is placed on every node, so its declared state is asserted and created as a placed module's, and it adds no account (issue 774, ADR 0563 §2, §3) 2026-10-28 21:54:47 +01:00
jschoubben 6f721dd536 mesh-grants: say every placed module left without a grant, in the pass and as the condition mesh-grants.grant-missing once the lease is handed away (issue 1126, ADR 0547 §5)
Why: the controller's grant writer skipped link2pay, snake, f1-circuits and txt-game in silence (it read the fingerprint by
their unchanged commit, a build of the old form) and the take-in said 'its grant written'. The part already reads the
fingerprint from the indexer's value, so those four are granted at their src2 done key's fingerprint; a row proves it.
What a pass leaves without a grant (no fingerprint of the new form with the indexer's none2, a refused manifest, no
hashed account) is now said rather than passed over. Quick: log it. Thorough (chosen): the pass's Missing, shown by the
grants tool, and a warning condition raised and cleared on change, as consumer-differs is.
2026-10-28 21:54:47 +01:00
jschoubben 3618831992 mesh-grants: write grants.<module>.<fp> in shadow into the state grants, say grant-written, and show every difference from the controller's in grants_grants (issue 774, ADR 0547 §5)
Why: the assigner switches its grants source when the controller's lease is handed away; until then the written keys are compared with the controller's, so the switch rests on a measured equality. Needs the group's mesh-sdk pin (PartGrantKey) before it builds.
2026-10-28 21:54:47 +01:00
jschoubben 6d709e1fc1 mesh-grants: grants_accept_hashes releases the clause 7 hold once, for exactly the held users of the held list, with why, said as hashes-accepted (issue 774, ADR 0561 §7, §9) 2026-10-28 21:54:35 +01:00
jschoubben eb11b2c844 mesh-grants: hold a list that changes several loaded users' hashes at once with no rotation by the vault naming them, and raise user-list-held naming them (issue 774, ADR 0561 §7) 2026-10-28 21:54:35 +01:00
jschoubben 67e3ebf22f mesh-grants: grants_accounts reads the account consumers' differences in shadow, where no condition is raised (issue 774, ADR 0561 §6, §9) 2026-10-28 21:54:35 +01:00
jschoubben 9b31746cdb mesh-grants: raise a condition when an account consumer differs from its composed configuration, and bring one to it by hand with grants_consumer_match, never under the controller's lease (issue 774, ADR 0561 §6, §9) 2026-10-28 21:54:35 +01:00
jschoubben ebad58f7e2 mesh-grants: create the durable consumers an account needs from the lease write, compared in shadow until then, so a module assigned after the controller leaves still hears what it consumes (issue 774, ADR 0561 §6) 2026-10-28 21:54:35 +01:00
jschoubben 3c6fb7fc9e mesh-grants: compose the user list again when the vault says account-issued, so a minted account reaches the bus within one pass (issue 774, ADR 0561 §1) 2026-10-28 21:54:35 +01:00
jschoubben 71aa3e86c6 mesh-grants: write the bus accounts the mesh wants to a state only the vault reads, so the vault can mint them; grants_accounts reads it (issue 774, ADR 0561 §2, §9) 2026-10-28 21:54:35 +01:00
jschoubben 451a4dfe74 Grants: pin mesh-sdk 38dbe1d, so the bus loads the node agents' reads of the seat mesh-placement's states before anything reads them (ADR 0567 §9, issue 1126)
mesh/delivery merged: source.main moved to novox/mesh-delivery@db737df597c3
mesh/delivery-group group feat/1126-grants-first merged: every member is merged
mesh/check pass 451a4dfe74d9 on 2ac146078f47 | unit 1909 run, 715 kept, 3 skipped | integration 1931 run, 813 kept, 3 skipped | over bound: unit (slow…
2026-10-28 19:11:58 +01:00
jschoubben 3d916a685e mesh-grants: the same list said again moves neither the sealed key nor the shadow list (issue 1126)
Live since the take-over the shadow list was written every 3 s (revision 99270
to 99357 in 90 s, nothing differing): the sealed key read back says [] for the
nil left-out a pass composes, so every pass wrote the key again; each write
moved the bus node's report of what it loaded, whose revision and time were
inputs of the shadow list, and woke the next pass. The bus itself reloads only
when the list's bytes change (its log: two configurations alternating with the
placement, f8567865 and 473f9ad3), so this loop was load, not the reload.
2026-10-28 00:20:44 +01:00
jschoubben 3192d89edf mesh-grants: refuse a take-over over an uncompared deny; ask words only for added rights
mesh/delivery merged: source.main moved to novox/mesh-delivery@a49fd9cc65f7
mesh/check checking 3192d89edfcb on a49fd9cc65f7
Review round 1 of issue 1945's fix found two ways the guard could let a loss
through or hide one from the operator.

A publish deny was never compared: grants.User carried no deny, so a widened
allow that brings a new deny (a lost publish right) passed as an added right.
The user now carries its deny; a deny the shadow adds is a loss, and while
nats_users answers no deny for the loaded list, a user whose grants differ
and whose shadow grant has a deny refuses, named as a deny the loaded list
cannot be compared on. None of today's 41 differing users carries a deny
(only the four node-tools users do, and they are the same in both lists).

The ask said "takes none away" whenever rights were added, whatever else
differed. Its words now name the added rights only when nothing else refuses
(Refusals: unread list, Removing, a missing hash), and otherwise say what the
yes would be refused for, naming the users; Decide uses the same Refusals.

issue 1945
2026-10-27 22:33:53 +01:00
jschoubben 9edfcc40e9 mesh-grants: allow take-over when the lists differ only by added rights
The operator's yes to take-over was refused twice (2026-10-26 13:48 and
2026-10-27 21:19 UTC) because 41 users differ, every difference a right the
grants part's list adds. The controller's list is not changed (ADR 0547 §1),
so ADR 0547 §8's equality could never hold again. ADR 0562 changes it:
take-over is allowed when no user is added or dropped, no loaded user loses a
publish, subscribe or responses right and every hash is held; the ask names
the added rights by user and kind, and a yes after they changed is refused.

Tests: rows from the captured live comparison of 21:19 (testdata, no
hashes) in the compare table, and rows in the take-over table for a right
removed, added rights changed since the ask, and only added rights recorded.

issue 1945
2026-10-27 22:28:22 +01:00
jschoubben bb7f2ff365 Merge remote-tracking branch 'origin/main' into fix/1126-node-creds
mesh/delivery merged: source.main moved to novox/mesh-delivery@68bdda1a4dbf
mesh/delivery-group group fix/1126-node-creds merged: every member is merged
mesh/check checking bb7f2ff365c7 on 68bdda1a4dbf | novox/mesh-delivery#89 in group fix/1126-node-creds
2026-10-27 21:18:57 +01:00