Commit Graph
3463 Commits
Author SHA1 Message Date
jschoubben bb96fbbb3c zfs: the scheduled run names its minutes, so its timer starts (issue 1979)
mesh/delivery merged: source.main moved to novox/mesh-catalog@117f933dacf0
mesh/check checking bb96fbbb3c45 on 117f933dacf0
The node-engine writes a cron step (*/15) as a calendar systemd refuses, so
zfs-mesh-scrub.timer never started and the pool had no scrub schedule. A list
of minutes is written as *-*-* *:0,15,30,45:00, which systemd takes.

Builds: design 42 zfs-owns-zfs §18. Tests: 1979/AC1.
2026-11-12 23:07:55 +01:00
mesh-tools e271757db7 Merge pull request 'kernel: declare amd-ucode only (issue 1977, L10)' (#673) from fix/1977-amd-only into main 2026-11-12 20:51:32 +00:00
jschoubben c100e16ba0 kernel: declare amd-ucode only (issue 1977, L10)
mesh/delivery merged: source.main moved to novox/mesh-catalog@e271757db78b
mesh/check checking c100e16ba0af on e271757db78b
intel-ucode failed an apply on a stale package database and stopped the delivery; an Intel machine
fails the unit by the image check and gets intel-ucode in the change that adds it. Tests: 1977/AC1
and the pinned order string adjusted.

Builds: L10 (issue 1977 note 6)
2026-11-12 21:49:30 +01:00
mesh-tools b9abfde492 Merge pull request 'kernel: microcode in every initramfs (issue 1977)' (#672) from fix/1977-microcode into main 2026-11-12 20:35:16 +00:00
jschoubben f7616c6a9b kernel: the initramfs script takes over a default-config preset and checks each image (issue 1977, L7-L9)
mesh/delivery merged: source.main moved to novox/mesh-catalog@b9abfde492b2
mesh/check checking f7616c6a9bd4 on b9abfde492b2
Before mkinitcpio -P, a preset naming ALL_config="/etc/mkinitcpio.conf" is copied to the state's
taken-over/ and loses that line (another ALL_config is left and named); after it, an image without
kernel/x86/microcode/ in its first 64 KiB fails the unit and records nothing. The unit may write
/etc/mkinitcpio.d. The README names no node. Tests: 1977/AC7, 1977/AC8; AC3/AC4 fixtures write images.

Builds: L7, L8, L9 (issue 1977 note 4)
2026-11-12 21:31:05 +01:00
jschoubben 62c0eb90cb kernel: kernel_boot reads microcode from each initramfs image (issue 1977, L6)
Replaces the state record read (root's 0700) with images_with_microcode per /boot/initramfs-*.img:
true when the first 64 KiB hold a path under kernel/x86/microcode/; an unreadable image goes to
image_errors with its error. Test: 1977/AC5.

Builds: L6 (issue 1977 note 3)
2026-11-12 20:54:34 +01:00
jschoubben 5795f4d230 kernel: microcode in every initramfs through mkinitcpio's microcode hook (issue 1977)
Declares amd-ucode and intel-ucode, the drop-in /etc/mkinitcpio.conf.d/mesh-microcode.conf, the
initramfs script and mesh-kernel-initramfs.service; kernel_boot answers the running revision and
whether the images were built with the drop-in. Tests: 1977/AC1-AC5.

Builds: L1, L2, L3, L4, L5 (issue 1977 note 2)
2026-11-12 20:52:21 +01:00
mesh-tools a60728e6f0 Merge pull request 'systemd-resolved: the own resolver's file waits 3 s a try (issue 1748, ADR 0678)' (#671) from fix/1748-resolver-wait into main 2026-11-12 17:52:35 +00:00
mesh-tools 792a79720b Merge pull request 'mesh-vault: secret_holders lists every record of the vault's store by name and fingerprint (issue 1409)' (#670) from fix/1409-store-records-listed into main 2026-11-12 17:51:18 +00:00
jschoubben d22a7f3a41 fix-1748-own-resolver-wait: the own resolver's file waits 3 s a try
mesh/delivery merged: source.main moved to novox/mesh-catalog@a60728e6f09d
mesh/delivery-group group fix/1748-resolver-wait merged: every member is merged
mesh/check checking d22a7f3a412f on a60728e6f09d | novox/mesh-catalog#671 in group fix/1748-resolver-wait
The resolver file of systemd-resolved (resolvers and kept facts) carries options timeout:3 attempts:2 edns0 in place of timeout:1; manifest test asserts both facts, guard test's literal follows.

Builds: design 50 resolver-wait §1, §4 (and §2 of the main file, line 73)
2026-11-12 18:09:17 +01:00
jschoubben 45b0779b68 mesh-vault: a store file that is not a record is listed by name with its error (issue 1409, V10)
mesh/delivery merged: source.main moved to novox/mesh-catalog@792a79720b30
mesh/check checking 45b0779b6801 on 792a79720b30
Store.ListReadable lists every record and, beside them, each file it cannot read
by name with its error; RecordsHeld lists those as rows with an error and goes
on. recordsError stays for a store that cannot be listed at all. Store.List and
ListPrefix keep their behaviour for their other callers.

Builds: design 39 bus-and-switch §20; design 39 parts §12. Lead answers (issue 1409): V9 (keep recordsCount and recordsError), V10.
2026-11-12 17:41:39 +01:00
mesh-tools 0ec8347786 Merge pull request 'node-uplink links answers each link's mac, master and parent (issue 1965)' (#669) from fix/1965-links-mac into main 2026-11-12 16:35:36 +00:00
jschoubben 52572698cb mesh-vault: secret_holders lists every record of the vault's store by name and fingerprint (issue 1409)
S1 vault-licence-secrets-listed. secret_holders answers `records` and
`recordsCount` beside holders, count and enrolments: each store record's name,
generation, since, changed, changedBy/changedVia, origin, length and the vault's
own fingerprint of the whole value, plus key and part for licence.<key>.<part>.
A record the vault cannot open stays listed with an error. Never a value.

Builds: design 39 bus-and-switch §20, §15; design 39 parts §12 (D1); design 24 Every secret lives in the vault, Beyond generate and hold; as-is 06 The vault, as it runs.
Lead answers (issue 1409 note 11): V1, V-thorough, V2-V8. V3 drops the map's
tokenFingerprint and AC5; V-thorough widens the licence.-prefix list to every record.
2026-11-12 17:34:00 +01:00
jschoubben 700b37890b node-uplink links answers each link's mac, master and parent (S1a links-mac, issue 1965)
mesh/delivery merged: source.main moved to novox/mesh-catalog@0ec8347786f4
mesh/check checking 700b37890bfd on 0ec8347786f4
Both holders' uplink-tools copies read address, master, link and
link_index/link_netnsid from the existing ip -j address show call. Fields
are left out where a link has none (L3); a parent in another namespace is
{index, namespace} (L2); the form lives in uplink.go only (L4); only the
tool description changes, not seat.json (L5); bridge fdb MACs are not
answered (L6); names mac, master, parent (L1).

Builds: design 48 10, design 08 code:, issue 1965 note 11 L1-L6
2026-11-12 17:30:17 +01:00
mesh-tools 836fcd81f6 Merge pull request 'mesh-files: find writes the NUL itself, so a list or search through root runs at all (issue 1409)' (#668) from fix/1409-root-list-nul into main 2026-11-12 15:39:51 +00:00
mesh-tools 8484ab0032 Merge pull request 'A step answer over the steps state's bound is kept without its taken versions, said, not lost' (#667) from fix/step-answer-over-bound into main 2026-11-12 15:37:54 +00:00
jschoubben c29ef0d95e mesh-files: find writes the NUL itself, so a list or search through root runs at all (issue 1409)
mesh/delivery merged: source.main moved to novox/mesh-catalog@836fcd81f65b
mesh/check checking c29ef0d95ea7 on 836fcd81f65b
Live on novox 2026-11-12: node-files.list of a root-only directory answered
'fork/exec /usr/bin/sudo: invalid argument'. The kernel refuses a program
argument that holds a NUL byte, and listAsRoot's -printf format and
searchBelowAsRoot's ended in a literal \x00 since 5d98bcc0 (2026-10-16), so
no list or search through root ever ran on a node. find writes \0 itself.
The stand-in root in the tests refuses an argument holding a NUL, as exec
does, so every root call is held to it; it found the search's instance.

Builds: design 39 parts §15 and the lead's answer D3 (list through root of a place a secret is kept).
2026-11-12 16:34:24 +01:00
mesh-tools c0d666fdcf Merge pull request 'The provisioner's retiring asks get a bounded id, and a refused one is said (issue 1966)' (#666) from fix/1966-unpublished-placed-module into main 2026-11-12 15:34:21 +00:00
jschoubben 22bbb9c2c0 Keep a check's answer within the steps state: leave out the taken versions
mesh/delivery merged: source.main moved to novox/mesh-catalog@8484ab0032a5
mesh/check checking 22bbb9c2c09f on 8484ab0032a5
A catalog check's answer of 264712 bytes was refused by the steps state
(256 KiB per value) and its end written failed without it, so the checker
lost the biggest member's answer and could not preview it. When a passed
or failed end is refused as too large, finish writes it once more without
the fetch's taken versions (fetch.packages, which no reader judges), the
step's reason saying how many were left out, why, and that the module's
journal names each; still too large, it ends failed as before.

Quick fix for issue 1921 (note 91); the thorough fix is design 47 G A-290
(an answer over the bound kept as the object output.<ask>).

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
2026-11-12 16:32:48 +01:00
mesh-tools 7b50628627 Merge pull request 'node-files lists a place a secret is kept, entries without content, and stat says a missing path is missing (issue 1409)' (#665) from fix/1409-list-secret-place into main 2026-11-12 15:28:22 +00:00
mesh-tools 23a280a664 Merge pull request 'licences_switches answers switches carried from the old database with their licence and consumer (issue 1409)' (#664) from fix/1409-carried-switches into main 2026-11-12 15:27:13 +00:00
jschoubben 3bb8ace833 U6, U7 provisioner: a bounded retiring ask id, a refused ask said, the Composition comment corrected
mesh/delivery merged: source.main moved to novox/mesh-catalog@c0d666fdcf55
mesh/delivery-group group fix/1966-unpublished-placed-module merged: every member is merged
mesh/check checking 3bb8ace833d1 on c0d666fdcf55 | novox/mesh-catalog#666 in group fix/1966-unpublished-placed-module
The retiring ask's id is made from the key's digest and the time (at most 64 characters),
so a long key is asked. An ask the router's rules refuse is said in the key's why and in
provisioner_health. The Composition comment says what the code does: an unpublished
module keeps only its own plan and keys.

Builds: design 47 fix-unpublished-placed-module U6, U7, ADR 0593 §8
2026-11-12 16:01:25 +01:00
jschoubben ab1eb0cb47 Review 1 of S1: the served-text row finds the list tool by its full name; list's text is the contract's word for word
mesh/delivery merged: source.main moved to novox/mesh-catalog@7b5062862758
mesh/delivery-group group fix/1409-list-secret-place merged: every member is merged
mesh/check checking ab1eb0cb4781 on 7b5062862758 | novox/mesh-catalog#665 in group fix/1409-list-secret-place
Builds: design 39 parts D3 (§15), bullets 2 and 4.
2026-11-12 15:52:34 +01:00
jschoubben 2a9827ce18 Review 1 of S1: list's served text ends with the account sentence only; a secret-shaped link target in a secret place is withheld
Issue 1409. readTools no longer appends the refusal sentence to list. A row in
TestSecretPlacesAreRefusedByNameBeforeAnyRead holds a link's target in a secret place to the content rule.
S2's match on sudo's English message is left as it is: the root path sets no locale, and sudo's environment
handling decides whether LC_ALL reaches stat.

Builds: design 39 parts D3 (§15), bullets 2 and 4
2026-11-12 15:50:45 +01:00
jschoubben fdd33e1234 S2 stat-says-missing: mesh-files stat says a path root finds missing does not exist
Issue 1409. A stat through root of a path that is not there answered that the file modes refuse it; it says
it does not exist, so design 39 parts §15's "gone" can be read.

Builds: design 39 parts D3 (§15), bullet 3
2026-11-12 15:44:51 +01:00
jschoubben c41387f271 S1 list-secret-place: mesh-files lists a place a secret is kept, entries only, marked secret-place
Issue 1409. A list of a place the mesh keeps a secret, or of a machine's credential places, at any depth,
answers each entry's name, type, owner, group, mode, size and a link's target held to the content rule,
never content, and says secret-place; a process's environ, mem, fd, map_files, root and cwd stay refused.
Lines touched cite ADR 0394 §7.

Builds: design 39 parts D3 (§15), bullets 2 and 5
2026-11-12 15:44:50 +01:00
jschoubben ee6d7c284d The carried-switch test names no real node or address (review round 1)
mesh/delivery merged: source.main moved to novox/mesh-catalog@23a280a664be
mesh/check being carried to ee6d7c284da9 on 23a280a664be | from f1c04801e477
2026-11-12 15:40:10 +01:00
jschoubben b5c5594ea7 licences_switches answers the old field names of carried entries (issue 1409)
Builds: design 39 bus-and-switch §37, §12 and the lead's answer C5 (hq 45ee2475).
2026-11-12 15:38:00 +01:00
mesh-tools f1c04801e4 Merge pull request 'A check step that errors after its fetch merged still answers its fetch' (#663) from fix/checker-preview-after-failed-step into main 2026-11-12 14:34:05 +00:00
jschoubben fff3b819d3 A check step that errors after its fetch merged still answers its fetch
mesh/delivery merged: source.main moved to novox/mesh-catalog@f1c04801e477
mesh/delivery-group group fix/checker-preview-after-failed-step merged: every member is merged
mesh/check checking fff3b819d383 on f1c04801e477 | novox/mesh-catalog#663 in group fix/checker-preview-after-failed-step
A level that does not compile or generate ended the check step failed with no
result, so the checker could not tell a merged fetch from one that never
answered, and previewed and judged no manifest or composition of the member.
The step now ends failed with its answer all the same: its fetch and the
levels so far beside the error, which the step's end already keeps.

Builds: design 47 G A-286 (G-22-lead-answers-2.md at hq 41dd30fe; issue 1921; principle 3)
Quick: this checker on main; thorough: the same rule in G's checker (join 11, J15).

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
2026-11-12 15:23:48 +01:00
mesh-tools 6d000647de Merge pull request 'The licence manager is built of its parts, a manager and its tools, and the finished carry-over leaves (issue 1409)' (#662) from feat/1409-parts into main 2026-11-12 12:05:46 +00:00
jschoubben cff1005422 P2: the licence manager is four parts of one manifest (issue 1409)
mesh/delivery merged: source.main moved to novox/mesh-catalog@6d000647de2d
mesh/check being carried to cff1005422c1 on 6d000647de2d | from f9dcbc295723
The one bundle that did everything becomes the manager bundle, which runs long and answers the seat's ten verbs and
the three acting tools, and a tools bundle of its own that answers the four reading tools and writes nothing, so they
answer while the manager fails to load or stops. Both import the module's one package for the layouts of the kept
data and the log entries, the key form, the entries' names and the settings with their validity; the settings file
and the account with its directory stay as they are.

Builds: design 39 parts §1, §2, §3, §4, §5, §6, §7, §8
2026-11-12 12:08:03 +01:00
jschoubben ce9f984363 P1: the carry-over leaves the licence manager (issue 1409)
The carry-over from the store database ran live once and carried every row, so its code, the gate that answered
"the carry-over has not ended", the condition carry-over-failed, the tool licences_carried, the opening of grants
with grant.key and the postgres driver leave the module, with its requirement of the database and of the secret
grant-key. The state carried stays as the carry-over's record; at its start the manager waits for nothing and
clears a carry-over-failed it finds kept.

Builds: design 39 parts §6 (the template files/database.url), §9, §10, §11
2026-11-12 11:55:54 +01:00
mesh-tools f9dcbc2957 Merge pull request 'The licence manager counts room from the weekly window alone, so the switch finds a target (issue 1409)' (#661) from fix/1409-weekly-only into main 2026-11-12 10:18:53 +00:00
jschoubben 94a0ebbedf C4: a licence's room is its weekly window alone (issue 1409)
mesh/delivery merged: source.main moved to novox/mesh-catalog@f9dcbc295723
mesh/check checking 94a0ebbedfa6 on f9dcbc295723
The vendor retired the session limit and answers the session window empty, so Room required a percentage that never
comes: live, no licence had room and no switch could choose a target. Room is now 100 less the weekly percentage; the
session window takes no part in the switch threshold, a target's bound, the near-limit warning or no-room's words.
A reading with no weekly percentage still has unknown room. The settings' descriptions and the README say so.

The whole tests' vendor answers the session window empty, as it does live; on the old rule they failed with the live
symptom ("has no session or weekly window in its reading").

Builds: design 39 bus-and-switch C4
2026-11-12 10:57:19 +01:00
mesh-tools c5f6845386 Merge pull request 'The licence manager declares its logs in the logs section, so they are issued and its carry-over can finish (issue 1409)' (#660) from fix/1409-logs-section into main 2026-11-12 09:29:45 +00:00
jschoubben 636cb633ac C3: the manager's two logs in the logs section the runtime issues (issue 1409)
mesh/delivery merged: source.main moved to novox/mesh-catalog@c5f684538607
mesh/check checking 636cb633acfd on c5f684538607
Live after #659 the manager, in its own runtime, was still issued none of its logs: the runtime on main issues
template states but logs only from the `logs` section. usage (35 days, 256 MiB) and audit (64 MiB) move there; the
states stay templates. The whole tests' runtime now issues logs only from `logs`, as main does, and failed on the
old manifest.

Builds: design 39 bus-and-switch C3
2026-11-12 10:21:27 +01:00
mesh-tools 6181d9afb3 Merge pull request 'The licence manager runs as its own account, so its own logs are issued to it and its carry-over can finish (issue 1409)' (#659) from fix/1409-own-runtime into main 2026-11-12 08:41:49 +00:00
mesh-tools 89ad370485 Merge pull request 'systemd: serve kernel-log, the node's kernel log of this boot or an earlier one; journal refuses a boot (issue 1975)' (#658) from fix/1975-kernel-log into main 2026-11-12 08:40:36 +00:00
jschoubben 8291502cbb C2: a key pair the manager cannot read is made anew in its place (issue 1409)
mesh/delivery merged: source.main moved to novox/mesh-catalog@6181d9afb3e5
mesh/check checking 8291502cbbaf on 6181d9afb3e5
Moved to its own account, the manager finds manager-key.json still owned by the tool runner's account, which the
node-engine does not hand over; it skipped making a pair because the file existed, and every verb answered the read
error. Now a pair it cannot read is replaced by a new one, renamed over it, and said in its journal; every use passes
the public key per ask, so nothing depends on the old pair.

Builds: design 39 bus-and-switch C2

Claude-Session: https://claude.ai/code/session_01NcbgfHb9d4T9nq5Q6WqdiJ
2026-11-12 09:38:03 +01:00
jschoubben 8d2497b65e C1: the licence manager runs as its own account, its service and its tools in its own runtime (issue 1409)
Run inside the machine's tool runner, the manager was issued none of its own logs and states, so the carry-over
failed live ("keeps no log called usage ... it was issued: none"). It now declares runs-as claude-licence-manager,
makes that account, owns what it places on its machine and its secrets, reaches the bus with its own broker secret,
and invokes a node's claude_code_grant, which the tool runner's account could ask and its own could not.

The whole tests play the manager's own runtime: they issue only the states, logs, asks and events its manifest
names, and fail on a manifest without runs-as; a unit test holds every ask in the code to the manifest's invokes.

Builds: design 39 bus-and-switch C1

Claude-Session: https://claude.ai/code/session_01NcbgfHb9d4T9nq5Q6WqdiJ
2026-11-12 09:25:57 +01:00
jschoubben 15db34169e distribution: the holder's test follows the rule that a chunk 0 again starts a part afresh
mesh/delivery merged: source.main moved to novox/mesh-catalog@89ad37048520
mesh/delivery-group group fix/1975-kernel-log merged: every member is merged
mesh/check being carried to 15db34169e24 on 89ad37048520 | from d9f2b7bcfa07, mesh-contracts 29ec1c3df312
mesh-delivery's parts.Receiver.Take took a chunk 0 again on purpose (276412d7, design 51 Publishing, 1966/AC203-1,
AC203-2); the holder's test still expected it refused and failed on every run, on trunk too. The test now expects a
chunk out of sequence refused and a chunk 0 again taken.

Builds: design 51 Publishing, the bullet "The file travels in parts through the seat"; issue 1975's group check

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
2026-11-12 03:04:00 +01:00
jschoubben ebcc7761f1 journal refuses a boot argument it does not use (issue 1975, AC4); tests cite their acceptance labels
mesh/delivery-group group fix/1975-kernel-log rejected: composed together: the checker's verdict at the members' heads (c265ee221ccf): unit: distribution/inter…
mesh/delivery closed: a newer head of the same pull request
mesh/check failed (2): unit: distribution/internal/holder.TestTheHolderOfTheTwoImageSeats/a_transfer_in_par…; and 1 more | ebcc7761f178 on d9f2b7bcfa07
Builds: issue 1975 note 2: lead answer L4, acceptance 1975/AC1-AC4

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
2026-11-12 02:24:44 +01:00
jschoubben 3ebcb15a4b systemd: serve kernel-log, the kernel's messages of one boot (issue 1975)
journalctl --dmesg --boot=N under the same escalation, window, priority, fixed-string match, 2000-line cap
and redaction as the journal verb (shapeLines is the one filter both use); a boot is 0 or a negative whole
number, refused otherwise before anything runs. No scope: the kernel belongs to no manager.

Builds: issue 1975, the operator's request of 2026-11-12 (the lead's handover; no design line names the verb)

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
2026-11-12 02:17:28 +01:00
mesh-tools d9f2b7bcfa Merge pull request 'The licence manager keeps its data on the bus and switches licences by itself at 99% (issue 1409)' (#657) from feat/39-licence-switch into main 2026-11-12 00:13:04 +00:00
jschoubben dbcba161d5 M-6 fix: the carry-over carries each live lease with its remaining lifetime (issue 1409)
mesh/delivery-group group feat/39-licence-switch merged: every member is merged
mesh/delivery merged: source.main moved to novox/mesh-catalog@d9f2b7bcfa07
mesh/check checking dbcba161d57c on d9f2b7bcfa07
The lead's answer B44: a lease the bundle before held in today's database
and still live at the run is written to `leases` under the bus's key form
with what is left of its lifetime, so no refresh races it whatever the
delivery's order; an expired one is counted read and not written.

Builds: design 39 bus-and-switch §4, §12, B44

Claude-Session: https://claude.ai/code/session_01NcbgfHb9d4T9nq5Q6WqdiJ
2026-11-12 01:07:09 +01:00
jschoubben c8e321c8e1 M-11 fix: a reading takes its licence's lease, and a grant the vault does not answer is a failed reading (issue 1409)
Review round 1, finding 5: the reading reads the grant under the licence's
lease (another run holding it reads nothing that round), and a grant the
vault refuses writes readError, keeps the percentages and goes on to the
next licence, so the conditions are still said after the round.

Review round 1, finding 6: these answers were built by earlier commits that
did not name them: B26, B27, B28 and B29 by M-6 (9cc62818), B30 by M-9
(39912119), B35 by M-11 (6cf98386); B23 and B24 by V-1 (e85cf002) and M-7
(5ca3876b), named again in b8e8be61; B31 and B32 in 36d9d739.

Builds: design 39 bus-and-switch §4, §16, §24, §31, B23, B24, B26, B27, B28, B29, B30, B34, B35

Claude-Session: https://claude.ai/code/session_01NcbgfHb9d4T9nq5Q6WqdiJ
2026-11-12 01:04:07 +01:00
jschoubben b8e8be619d M-15 fix: resync hands the vault each access token built from its grant (issue 1409)
Review round 1, finding 4: the vault hands a licence's access token only to
a machine a binding names, so licences_resync builds it from the grant (the
key itself for an API key) instead of reading it back.

Builds: design 39 bus-and-switch §15, §17, §42, B23, B24

Claude-Session: https://claude.ai/code/session_01NcbgfHb9d4T9nq5Q6WqdiJ
2026-11-12 01:02:54 +01:00
jschoubben cc8a354f75 M-3 fix: an adopted licence says where it came from, and a newer login keeps its reading (issue 1409)
Review round 1, finding 3: adoptedFrom is the node a login came from, or
where an API key came from; a newer login of the same account keeps the
latest reading and generation the key holds.

Builds: design 39 bus-and-switch §2, §34, §46

Claude-Session: https://claude.ai/code/session_01NcbgfHb9d4T9nq5Q6WqdiJ
2026-11-12 01:02:14 +01:00
jschoubben 6a57bb7218 M-6 fix: each carried binding is said as binding.changed (issue 1409)
Review round 1, finding 2: a reader's first view taken while the carry-over
runs is brought up to date by the event said after each key is written.

Builds: design 39 bus-and-switch §12, §21

Claude-Session: https://claude.ai/code/session_01NcbgfHb9d4T9nq5Q6WqdiJ
2026-11-12 01:01:40 +01:00