Commit Graph
95 Commits
Author SHA1 Message Date
jochen 2b1edf046d ADR 0273: the agent's home is the module's, and the operator's personal rules and lessons are registered through it
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request
Research 040 measured the homes on four nodes: a skill retired a week ago on all four, the
operator's rules on one, nothing raised. The module now owns every configuration file under
the agent's home, excludes the program's working state by name, and raises agent-home-drift
on a hand edit; a fourth scope carries the operator's personal rules to every node; an agent
proposes a lesson when corrected and the operator accepts it at the terminal or on a warrant.
To-be 36 §10 and to-be 40 WP7–WP10 say what is built; ADR 0216 and 0243 gain notes.
2026-10-09 18:11:26 +02:00
jschoubben 32107428c4 ADR 0259: a rehearsal, not a drill; the announcement at the terminal checked; the operator's steps with nox, and the standard-input gap said
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request
2026-10-09 15:38:41 +02:00
jochen a04f1b90a0 Name the router, not the controller's retired verbs, where the glossary and to-be 46 still did 2026-10-09 15:36:36 +02:00
jochen 1714132a08 Accept ADR 0259 with the operator's two decisions, and amend to-be 46 to it 2026-10-09 15:36:36 +02:00
jochen 9f66452fff ADR 0259 (proposed): let any module ask a person and any channel answer, so Telegram is not built into the controller 2026-10-09 15:36:36 +02:00
jochen 3bdd4e8040 Merge remote-tracking branch 'origin/main' into decision/0272-mesh-cli-the-operators-command 2026-10-09 13:15:36 +02:00
jochen 95d78f7011 ADR 0272 (proposed) and issue 343: the controller's terminal has no command
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request
The records send the operator to "the controller's terminal", and on the
control-node `mesh-controller` is not a command: the controller is a mesh
process with its own account and environment, and nothing puts anything on
PATH. The record proposes mesh-cli, a module on every node whose program
asks the node-engine over a local socket; the node-engine vouches for the
account from the kernel and asks the controller on its node's own subject;
the controller runs the line as the terminal only for the operator's account
where no agent can be that account. The glossary gains mesh-cli, nox (its
zsh alias) and the controller's terminal.
2026-10-09 11:59:34 +02:00
jochen 537e5b733b ADR 0266: on the control node agents run under an account of their own
The operator chose this remedy for ADR 0259 section 8: an agent there could
become root through the operator account's sudo and docker group, and read the
tool runner's credential. Record the node fact, the node-engine's judgement
the self-check reads, the guard, and how a session starts; issue 333 holds
the measured symptom and to-be 36 the design.
2026-10-09 10:15:47 +02:00
jochen cbd9f092d8 ADR 0270 and 0271 accepted: their home in designs 47 and 45, and the glossary's final states
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request
The operator accepted both on 2026-10-09. Design 47's state table gains covered and what ends a held
delivery by itself, and its group the wait for a composed check and the lift; design 45's signals table
gains S17 and its planned bus step says the wait is told at once. The glossary's delivery entry names its
six final states.
2026-10-09 09:24:30 +02:00
jochen b04498c01f ADR 0270: the forge's ancestry decides covered, and say what covered means and does not (review of #241)
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request
Merge order on a protected trunk is kept only as the first filter; the forge's compare, through a new
read-only tool, decides whether a later merge contains a held one. A merge held without a passing check is
covered only by a later delivery whose own check passed. Covered says a later merge that contains it was
delivered, not that the change runs: a revert in between stays possible. A delivery that only adds a module
is delivered whatever its build does, and covered wins over go when a person's walk fails between two
readings. The glossary gains covered beside superseded and delivered.

ADR 0271 names the bus upgrade as the mesh call and says S17 clears once the step sent the new bus.
2026-10-09 02:58:36 +02:00
jochen d2fe9bc870 Accept ADR 0267: the operator's word of 2026-10-08
mesh/delivery delivered
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
Set its status to accepted and state the notes on ADR 0162, 0238 and 0236
as decided.
2026-10-08 23:11:35 +02:00
jochen 7d3f4407a7 ADR 0267 (proposed): an artifact is rebuilt only when its build source changes
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request
A merge to a shared repository moved every module that read it, in a gated
tier each (issue 338). The operator's rule maps a change onto the artifacts
whose build source it touches and adds only modules with a build dependency
on a changed artifact; sharing a repository is no dependency. Supersedes in
part ADR 0162 decision 1 (the packages kind) and ADR 0238 decision 3 (whole
repository and context reads); adds build source to the glossary.
2026-10-08 23:05:51 +02:00
mesh-admin 4eb8be9e66 Merge pull request 'ADR 0263 (accepted), research 038, design 52: a share is a provision, a node mounts it on demand' (#221) from feat/mounts-module into main 2026-10-08 18:39:59 +00:00
jochen 34899385ec Accept ADR 0263 with the operator's choices: one share per folder so backups are never exported, mesh machines only 2026-10-08 18:23:23 +02:00
jochen 0e5a5e2085 ADR 0262: record the lenient read of stored manifests and the marked defaults layer
A stored manifest read strictly would fail the whole catalogue after a controller rollback, and a node
called default would lose its layer. Also scope the default, retire tunable, and list the new checks.
2026-10-08 17:55:04 +02:00
jochen 417db4d837 ADR 0262: let a preference carry a default so a running module can gain a setting
A ${setting:} nothing set failed composition, and settings refused a key no file asked
for yet, so no order of changes could add a setting to a running module. A manifest may
now default a preference; the operator's own value still has none.
2026-10-08 17:55:04 +02:00
jochen 3a09387c8e ADR 0261: an assignment made while its module's build runs is kept pending
The review of mesh-controller#150 found the controller now makes an
assignment after the person's act, which no record decided. Decide it,
cite it from the glossary and to-be 45, and correct issue 325's account
of what is settled where and what is sent.
2026-10-08 16:46:40 +02:00
jochen 63754ca874 Issue 325: assign said no module of that name while the module's build ran
Register the symptom and the fix in mesh-controller#150 (replay R325 in
mesh-lab#68), and name the pending assignment in the glossary.
2026-10-08 16:46:40 +02:00
jochen 356c5f23f4 ADR 0253: say whether the operator is needed, keep quiet what needs nothing, answer from the notification
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered
mesh/delivery-group group feat/plain-notifications delivered: every member is delivered
The operator read the reworded popup and could not tell whether to act, and was
sent to open a session to act at all. The record now decides the verdict, the
quiet rule and the path by which a notification is answered.
2026-10-08 14:00:38 +02:00
jochen 7c49aa0ffc Issue 320 and ADR 0253: a condition says itself to the operator in plain words
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request
The operator could not read the mesh's notifications: they were the summary meant
for an agent, with ids, commits, keys and verbs, in UTC. The condition now carries
a headline, an explanation and a resolved line beside its summary.
2026-10-08 13:28:50 +02:00
jochen 3449775cb6 ADR 0252: a module puts an account in a group, and the mesh says when a new login is needed
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered
Issue 247 left adding the operator's account to a daemon's group a sudo step by hand. Decide that
a module declares it with the user resource's groups, that the mesh gives back only what it added,
and that the node-engine says relogin needed; amend to-be 41 with WP6 and resolve the issue.
2026-10-08 12:04:50 +02:00
jochen 5d4e427117 Ignore Python's cache: running the checks wrote it, and one file had been committed by mistake
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered
2026-10-08 01:04:03 +02:00
jochen 55637ecb95 ADR 0248: the decision index is generated when it is read, so two open decisions no longer conflict 2026-10-07 23:38:34 +02:00
jochen 478a198e9a ADR 0247: a machine with a VPN client routes names by domain, through a resolver of its own
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request
Research 033 measured the laptop's VPN client and the mesh overwriting each
other's resolver file in nine of nine sessions, each time cutting off one
kind of name. The operator chose a resolver module on a node seat of its
own, installed only where something requires split-dns, with the VPN
client's module carrying the adapter. Graduates research 033 into to-be 50,
and amends connectivity §2, to-be 48 §10, the seats and the glossary.
2026-10-07 21:33:48 +02:00
mesh-admin 0bd12fc777 Merge pull request 'Issue 298 and ADR 0246: a seat's new verb is promised before it is required' (#178) from issues/298-a-new-seat-verb-deadlocks into main 2026-10-07 19:21:52 +00:00
jochen 4b36234c9b Reword the hosts file in to-be 36, found by the plural on the rebase onto main
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered
mesh/delivery-group group fix/words-match-plurals delivered: every member is delivered
2026-10-07 21:14:43 +02:00
jochen 350f7dcdc2 Hold a retired word's plural to the word, so alerts and rollouts no longer pass
words.py matched a retired word only when nothing followed it, so the
plural of every retired word passed. The pattern now takes s or es on the
last word; 14 uses in 9 documents are reworded, two of them 'the hosts'
for the node-engines.
2026-10-07 21:14:36 +02:00
jochen e6a17b8bf6 Issue 298 and ADR 0246: a seat's new verb is promised before it is required
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request
Design 33 said a seat's verbs change additively, and section 3 made each
one a condition of holding, so a verb added in the controller and served
from the catalogue could land in neither order. It happened three times on
2026-10-07. Section 7 now says the three steps and how each is checked.
2026-10-07 21:14:20 +02:00
jochen 008014591b Do not track the word check's compiled cache
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered
2026-10-07 20:07:33 +02:00
jochen 051696e107 Retire "the host" in hq prose only: in the tools it is also an SSH server's word
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request
2026-10-07 20:02:03 +02:00
jochen a28da1734b Graduate research 034: the mesh in domains, one word per thing, checked
ADR 0244 sorts the mesh's concepts into ten domains (ADR 0006's contexts
carry over as domains), keeps machine and node as distinct words, and
makes the glossary the authority with every retired word on its
replacement's Not: line. To-be 49 draws the domains; the glossary is
reorganised by them, its two contradictions removed and the missing
words added. words.py now fails on a retired word in running prose and
on a word defined twice, so the rule is enforced rather than believed;
the 63 documents it failed on are reworded here, and research 034 is
kept as the record of the words it studied.
2026-10-07 19:58:39 +02:00
jochen 16b187d4c3 ADR 0239: a delivery is owned by mesh-delivery and runs from commit to delivered
mesh/delivery superseded: a newer head of the same pull request
mesh/merge-gate pass: the change touches no module of the mesh's graph
One owner for one commit's journey, so 'did my change go out' is answered by
one module instead of five records joined by hand; delivery groups make the
cross-repository order the mesh enforces instead of the person merging.
2026-10-06 23:18:31 +02:00
jochen d245df7dea ADR 0237, to-be 45 Phase 5: a change is judged against the mesh that runs before it merges
The operator approved Phase 5. Decides what the design left open: the build seat runs the
merge check, the facts live in the artifact store, the merge gate composes the mesh as it is
and with the change and judges only what the change adds, a replay lives where its incident
is, and the controller's tests run a bus of their own at the mesh's release. A core issue now
resolves only with a replay or a stated reason, checked by cycle.py.
2026-10-06 21:10:54 +02:00
jochen 54fe510b54 ADR 0234, to-be 46: decide factor recovery, addressing, references and who is the operator
The operator found four gaps that would bite on first use: a lost phone
locked the mesh's only person out, an operator message had no addressee,
asks could not name the specifics they need, and the operator was a
holder's flag. Each is now a rule with its check and its build phase.
2026-10-06 16:58:59 +02:00
jochen fb30b75f20 ADR 0234, to-be 46: let the operator answer, and let only the controller act on an answer
Research 028 graduates: the mesh needs to ask as well as tell, over
channels that are seats rather than code inside one notifier, and an
action a person must approve cannot rest on a desk click an agent can
forge. TOTP verified by the controller is the proof; a key stays optional.
Amends to-be 45 section 5 as ADR 0227 left it to.
2026-10-06 16:39:11 +02:00
jochen 4f1300fd48 ADR 0223: the mesh has two resolvers, and a machine lists only them
musl asks every listed nameserver at once and takes the first reply, so ADR
0196's public fallback answered NXDOMAIN for mesh names in every Alpine build
on the home server. Decide two mesh resolvers and no public line now; record
resolv.conf moving to the uplink's holder and /etc/hosts with /etc/hostname
moving to one hostname seat as the next steps. Amend to-be 08 and 26.
2026-10-05 22:43:18 +02:00
jochen eb7356360f Glossary: the node-engine, the program every node runs, replaces "host agent" and mesh-host 2026-10-05 22:31:13 +02:00
jochen e4f80cc3ce ADR 0207: a module depends on the node seats that apply its resources
A service needs node-service-manager held on its node, a package
node-package-manager, a container node-container-runtime: derived from the
resources, never stated; refused at assign, reported at composition until the
three holders are on every node. Glossary: depends on a seat; nothing claims a
package.
2026-10-04 12:21:24 +02:00
jschoubben da8b4b4ee4 Renumber to ADR 0188: 0187 landed on main first, as the dead-tracker record
Two records shared 0187 (issue 155's collision); the branch landing last
renumbers, and this is it. Only the number changes.
2026-10-02 21:01:02 +02:00
jochen 709240ec1f ADR 0187: a module's own code is bundles in any language, and a tools bundle speaks MCP to the runtime; design 38 gains WP1b
The operator's direction, absent from every record until now: the SDK must not limit who writes a
module; tools and services may be written in any language; one module may ship several bundles
(tools, a seat's implementation, a daemon); skeleton first, a full implementation when the work
requires it. ADR 0175 had the runtime import a bundle, which only JavaScript can be.

0187 makes a tools bundle a process the node's runtime launches and speaks MCP over stdio to —
the vocabulary the runtime already speaks outward — so any language with an MCP library can write
one today and the mesh's SDK per language is thin; the transport stays in the runtime (0039's
refusal, kept). Importing a TypeScript bundle is the shortcut, not the contract. Notes in 0175,
0039 and 0150 say where their mechanism moved; design 38 records WP1 as built and adds WP1b (the
launcher and the skeleton SDKs); the glossary's bundle widens.
2026-10-02 18:56:57 +02:00
jochen 7b1dabbce0 The operator's agent and its licence manager are modules: ADR 0181–0183, to-be 36 and 39
The predecessor's agent module was retired and its six files stayed on both workstations telling
every session to use tools that no longer exist. This is its successor's design, revised during
review on the operator's directions: the host is module-agnostic, the controller has no part, and a
real licence manager hands out the correct licence in every situation.

- ADR 0181 (reconstructed): the operator account is a node fact stated by the operator; the home is
  derived unless stated; a resource may be placed under it owned by the account; a node with no
  account refuses one. What the controller shipped on 2026-09-27 without a record.
- ADR 0182: inside a home the module owns the directory and the files it places, writes into the
  tool's own files for its few keys, never declares a credential's content, and holds everything
  else as found; a predecessor's leftovers are the operator's to remove once.
- ADR 0183: claude-licence-manager holds the mesh seat anthropic-licence-manager and owns the
  Anthropic licences, grants (encrypted with a key the vault made for it), bindings per touchpoint,
  usage and audit; one rotation source under a lease; a token travels module to module sealed to
  each node's module key on request/reply, never as an event; the agent module alone writes what
  the agent reads; the host delivers package and state and knows nothing else. A bounded exception
  to ADR 0113; dated mechanism notes on ADR 0050 and 0113.
- To-be 36 (claude-code): the mesh's part of the agent's configuration lives in the agent's
  machine-wide managed directory, owned whole by the module and written by its code; nothing under
  the home but the credentials file of a subscription licence; the API-key licence through the
  key-helper; the console as a node-scoped provision (to-be 34 amended); MCP servers as settings
  with an mcp_configure tool; one agent directory per machine shared by every session.
- To-be 39 (claude-licence-manager): store, the two licence kinds, keeping a grant alive, the
  hand-over, who gets which licence with the predecessor's fallbacks, adoption with the identity
  guard, the seat's verbs.

Numbers taken across main and every open branch at the time of the merge; to-be 14, 29 and 34
carry dated notes; the glossary gains "operator account".
2026-10-02 17:22:12 +02:00
jochen bf39baf104 Research 018 graduates: ADRs 0173–0177 and to-be 37, the operator's machine
Every configurable thing on a node is a module, the home included, and a
module is whatever it declares (0173, extending 0040). A node varies a module
only through a setting rendered into the file or a kept region, never an edit
(0174, extending 0011; issue 168 first). One tool runtime per node serves every
module's tools on the host side, never in a container; the console is its
serving mode, renamed node-tools (0175, extending 0150; 0047/0150/0152 carry
dated notes). The login shell is a node seat held by one shell module with
`execute` as its contract (0176). A unit may be user-scoped and the service
manager is a node seat held by systemd (0177).

To-be 37 is handed off in-progress to mesh-host, mesh-controller, mesh-tools
and mesh-catalog, with the build in order: the account on every node, the
runtime, zsh, systemd, then the graphical stack. To-be 29 keeps ~/.ssh and
points at 37; 33 §6 and 34 are amended; the glossary gains node tools, bundle,
kept region, installed/holding, and retires flavor.
2026-10-02 16:34:57 +02:00
jschoubben 98eb3aa76f ADR 0169 → 0170: the firewall seat's record renumbered after a collision on main; its built note; cycle.py refuses two records sharing a number
Another session's 0169 landed first. The collision check from issue 155
covered issue folders only; it covers decision records now, and would have
refused this.
2026-10-02 14:51:22 +02:00
jschoubben 22a28ad548 ADR 0156: an artifact is what a build produces, and the store's seat is named for its scope
Issue 123 resolved; glossary corrected; design 26 and ADR 0121 point at the rename.
2026-09-30 21:14:40 +02:00
jschoubben ad4a5ea004 ADR 0152: the operator's surface is a module, the console
The work order's group-3 question answered: an ordinary module the mesh assigns to the machine a
person sits at, holding a minted credential, calling tools under a manifest grant (invokes), serving
MCP on loopback. Design 34; pointers in 33, 25 and 0095; module check designed into 12 (issue 148);
README stops claiming an indexing nothing provides (issue 006).
2026-09-30 16:08:52 +02:00
jschoubben 47909c6b71 The records pointed at branches that no longer exist, and two fixes had no sequel
Three issues named the branch that fixed them, and a branch is deleted
when it merges — so every `fixed-by:` was a pointer that resolved to
nothing by the time anyone followed it. They name commits and pull
requests now, and playbook 03 says to.

Two records were missing the thing a reader arrives for. 146 did not say
that one of its fixes crash-looped the control plane on a running mesh,
which is the whole reason the delivery subject carries the stream and the
raise path was the only one exercised. 151 did not say that 152 removed
the false reasons its roster moved, or that it stays open for the real
ones.

ADR 0080 enumerates what cycle.py enforces and named four things; it
enforces five. A progressive insight names the fifth — the decision
stands, the list had gone stale. The checks README and playbook 03 gained
the same rule, and 155 points at all three.
2026-09-30 00:28:35 +02:00
jschoubben b967ef7be3 Two records shared a number, twice, and every check passed
Two machines filing issues in the same hour both read main correctly and
both took "the next free number". main lags every open pull request —
seven that evening — so they collided twice. The second collision
reached main with records, cycle and index all reporting success.

cycle.py now refuses a tree where two issue folders share a leading
number, and names both. Proven by adding a duplicate and watching it
fail. The colliding records become 153 and 154, renumbered in the branch
that lands last, because renumbering a branch whose author is still
pushing only moves the race.

The check catches a collision; it does not prevent one. Taking a number
still means reading the open pull requests as well as main — issue 155
says so.
2026-09-29 23:38:48 +02:00
jschoubben 1aeb4fe8d8 ADR 0140: the filter constrains what arrives from outside, and says nothing about a machine's own guests
Reading a converged machine's rendered rules showed the cause: the chain blocks
everything passing through and then allows the machine's own containers back by
listing their address ranges. 0137 made that list typeable and 0139 tried to
generate it; both refined a list that should not exist, because the mesh has no
position on a container reaching outward. Constrain what arrives from outside,
allow what did not, and let the machine report which links face outside — one
fact instead of a list. Ports keep following the modules unchanged.

The records check now allows one record to supersede several, and stops
requiring a withdrawn record's own citations to be live.
2026-09-28 23:31:50 +02:00
jschoubben 784b487bf9 ADR 0131: everything on the mesh speaks to the broker seat, and AMQP is not a provision
Taken during the outage of 2026-09-27, when the protocol leaked into the seat's
contract: to hold mesh-broker a module had to provide amqp, so the module that
will carry the bus could not hold the seat that names the bus, while the module
being retired could. Supersedes 0127. Modules depend on the seat and reach the
bus through the sdk; no manifest provides or requires amqp; the old broker's
module and the two modules that required it leave the catalogue; the AMQP
transport is deleted once every node reports on the new bus.

Design 28 step 5 rewritten under it: the seat handover becomes its own task and
is built first, because the seat the control plane dereferences cannot be empty
in between — that emptiness was the outage. The cost note now carries what was
measured rather than what was assumed.

0128 and 0130 extended 0127; each now rests on 0131 with a dated note and
changes nothing it decided. Every other citation of 0127 names its replacement.
records.py still fails on 0120/0112, which predates this branch.
2026-09-27 23:03:05 +02:00
jschoubben ce6ae943b7 Merge main: renumber this branch's records around the trunk's
Both lines of work numbered from the same point, so four decision records and one design
document existed twice with different content. The trunk keeps its numbers and this branch
yields — the only rule that scales, because the trunk's are already cited by what merged
before them.

  0117 the bus is the only broker        -> 0125
  0118 a module declares its own seats   -> 0126
  0119 amqp is a provision, not the bus  -> 0127
  0120 the mesh bus is required          -> 0128
  0123 a seat carries its role's protocol -> 0129
  0124 the predecessor is ending          -> 0130
  design 29, what a module declares       -> design 32

Applied to the code repositories too, because a stale reference is worse when numbers
collide than when they dangle: the reader lands on a real record that decided something
else.

Two reconciliations the merge forced, both real:

**0110 was marked wholly superseded and was not.** Its successor says in as many words that
everything 0110 decided about what a seat *is* stands untouched — and two records that
landed on the trunk rest on exactly that part. So it is accepted again, extended rather than
replaced, with a note saying which of its claims moved and where.

**A seat's protocol becomes columns, not fields.** The trunk moved the seat set out of
compiled code into a table the controller owns. This branch had added what a role accepts,
emits and serves to the Go slice. The decision is unaffected and the mechanism is better for
it: giving a role a protocol is now a write rather than a rebuild, which is the trunk's own
argument applied to what this branch added.

One check still fails and it fails on main too: a record resting on ADR 0112 while that is
still 'proposed'. Left alone — it is not this merge's to answer.
2026-09-27 18:23:41 +02:00