Compare a release's edges by the dependency part's digest and per node, and fill them once at the start

A module's version can change without changing the part an edge points to, a delivery happens per node, a build
of another branch has no version, and acting and serving are facts, not versions: the lead's review of §374 to
§376 found each would mark edges behind wrongly or redo work. A first fill keeps the first query from finding
the whole mesh behind.

Claude-Session: https://claude.ai/code/session_01JG73KK8HD1gufnqyFxMFdW
This commit is contained in:
2026-11-11 02:06:46 +01:00
parent b157283202
commit 5df2eca59e
2 changed files with 68 additions and 37 deletions
@@ -1931,14 +1931,17 @@ ADR 0667's checks, of milestone G itself:
reserves nothing, and no `tag-wanted` is said (whole, runner, builder and Go build module, mesh-delivery and
mesh-catalog).
104. **A release records its dependencies, and each kind follows its event** (design 47 G §374, §376). A module
released at `1.4.3`, built against mesh-sdk `0.1.15` and delivered after a provider at `2.0.1`, holds those two
versions on its release; mesh-sdk's `version-released` of `0.1.16` rebuilds it, and the provider's
`version-delivered` of `2.0.2` writes its wants again; a node away is named and waits (whole, indexer, builder,
assigner and runner, mesh-delivery).
released at `1.4.3`, built against mesh-sdk `0.1.15` and delivered after a provider at `2.0.1`, holds those
versions with their artifacts' digests, the provider's per node; mesh-sdk's `version-released` of `0.1.16` that
changes the imported package rebuilds it, and one that leaves its digest as it was rebuilds nothing; the
provider's new build running on one node writes the module's want again on that node only, while another node
waits for its own; a `beta` build's entries compare by digest (whole, indexer, builder, assigner and runner,
mesh-delivery).
105. **One query finds what is behind** (design 47 G §375). With the runner stopped while mesh-sdk `0.1.16` is
released, `outdated` names the module's kind-1 edge at `0.1.15` against `0.1.16`, and at its restart the runner
starts that module's pipeline once; `indexer_outdated_again` says the event again and writes the hand-act log
(whole, indexer and runner, mesh-delivery).
(whole, indexer and runner, mesh-delivery). After the first fill (§377), a mesh running its newest builds is
answered with nothing behind.
## What retires
@@ -523,35 +523,63 @@ record it follows from, and replaces the builder's own choice where one was made
and `builder_untag` go at G's delivery (design 51, *Tagged versions*). Why: the operator, 2026-11-10 about 21:40 CET,
no custom versions for now, a tagged version being one; a run delivers nothing (ADR 0666 §18), so it needs no
version. How it is checked: test 103.
- §374 **A released version records the versions it was built against or delivered after.** When the catalog
records a module's version as released (§349), it writes on that version, in its key of `versions`, one entry per
catalog-graph edge of the module's artifacts (the six kinds of *Dependencies between artifacts*): the kind, the
dependency's artifact reference and the dependency's version, a lockfile per released version. For the build kinds
(1 and 3) the version is the one the build used: the build module names each dependency version it resolved in its
step key, and the builder carries them in each artifact's `package-published`, so the indexer reads no other part's
state (ADR 0596). For the delivery kinds (2, 4, 5 and 6) it is the dependency's newest version running when the
released version first runs on a node, heard from the node-engine seat's `running` events through a durable consumer
of the indexer's own, the fingerprint mapped to its version in `versions`. The declared edge stays in the catalog
graph; the version is the release's fact, never changed after. Why: the operator, 2026-11-10 about 22:10 CET (issue
1961). Each entry is about 0.1 KiB, about ten a version, so `versions` stays within its 64 MiB (an estimate). How it
is checked: test 104.
- §375 **One query finds every edge behind.** The seat `mesh-catalog`'s verb `outdated`, with the indexer's tool
`indexer_outdated`, answers every recorded edge whose version is lower than the dependency's newest released
version (kinds 1 and 2) or newest delivered version (kinds 3 to 6): the module and its version, the edge's kind, the
dependency, the recorded and the newest version, and the act that catches it up. A delivered version is one the
catalog has said `version-delivered` for (§376). Its callers are any person, an agent session, the healers, the
runner and the assigner; `indexer_outdated_again`, a hand act written in the hand-act log, says the event that
starts an edge's work again for one dependency. At its start, the runner and the assigner each ask `outdated` once
and start the work it names, so a restart or a missed event leaves nothing behind. Why: the operator, 2026-11-10
(issue 1961's "outdated"); events start the work, and the query finds what is behind and answers a person. How it is
checked: test 105.
- §376 **Each kind is checked on its own event.** After a part's version is released, on its `version-released`:
the dependents by kind 1 are rebuilt against it and their pipelines started, as on `package-published` (§53), and
those by kind 2 are delivered again, the assigner writing their wants again naming the new version. After a part is
delivered, on the catalog's `version-delivered` (the module and the version, said once every present node that
places it runs it healthy, from the node-engine seat's `running`; nodes away are named and wait, ADR 0603 §7): the
dependents by kind 3 are rebuilt and their pipelines started, and those by kinds 4 and 6 are delivered again by
their wants. Kind 5, an acting part's act for a new version, is held by the acting parts' waits (*Within a revision
the new version acts first*) and is only recorded and shown by `outdated`. `version-delivered` is said on
`mesh.seat.mesh-catalog.event.version-delivered`, kept 90 days at 16 MiB. Why: the operator, 2026-11-10; the
events still start the work (ADR 0666 §14, §15). How it is checked: tests 104 and 105.
- §374 **A release records, per edge, the part it was built against or delivered after.** The catalog records on
each released version (§349), in its key of `versions`, one entry per catalog-graph edge of the module's artifacts
(the six kinds of *Dependencies between artifacts*), a lockfile per released version. An entry names the kind, the
dependency's artifact reference and what the edge depended on:
- kinds 1 and 3 (built against): the dependency's version and the digest of that artifact, as the build used them.
The build module names each dependency it resolved, version and digest, in its step key, and the builder carries
them in each artifact's `package-published`, so the indexer reads no other part's state (ADR 0596). A build is on
one build node, so these entries are per release.
- kinds 2 and 4 (delivered after): per node, the dependency's version and artifact digest running on that node
when the released version first runs there, heard from the node-engine seat's `running` events through a durable
consumer of the indexer's own, the fingerprint mapped to its version and digest in `versions`.
- kind 5 (has acted for): a fact, not a version: the acting part, its step, the build that acted and that the act
was done (or released by hand), from the holder's `wait-ended` (*Each step's wait is its own part's*).
- kind 6 (runs a version that serves): a fact, per node: the verb or manifest word used and the dependency's build
on that node that serves it, from the node-engine seat's `running` and the catalog entry of that build.
A build of a watched branch other than the registration's first releases no version (§371): its entries are kept in
the indexer's old `state` section `build-edges`, one key per module and watched branch holding the newest build's
entries, keyed by its fingerprint, replaced by the next build and deleted when `registration-changed` says the
branch is no longer watched. The declared edge stays in the catalog graph; an entry is the release's or the build's
fact, never changed after. Why: the operator, 2026-11-10 about 22:10 CET (issue 1961); a version is per module and an
edge per artifact, so the artifact's digest is what an edge compares (the lead's review of these lines, same
evening). Each entry is about 0.1 KiB, about ten a version and four nodes for the delivery kinds, so `versions`
stays within its 64 MiB (an estimate). How it is checked: test 104.
- §375 **One query finds every edge behind, by the part's digest.** The seat `mesh-catalog`'s verb `outdated`, with
the indexer's tool `indexer_outdated`, answers every entry that is behind: for kinds 1 and 2, the recorded artifact
digest differs from that artifact's digest in the dependency's newest released version (for a build of another
branch, its newest build on that branch); for kinds 3 and 4, it differs from the digest the dependency's newest build
has where it acts (for kind 3 the agreed toolchain, for kind 4 what runs on that node); for kind 5, the newest version
of the acting part has not acted for the dependent's current build; for kind 6, the build on that node no longer
serves the verb or word. A dependency's newer version that left the artifact's digest as it was makes nothing behind,
so nothing is done twice for the same inputs. Each answer names the module and its version or build, the node for a
per-node entry, the kind, the dependency, what was recorded and what is newest, and the act that catches it up. Its
callers are any person, an agent session, the healers, the runner and the assigner; `indexer_outdated_again`, a hand
act written in the hand-act log, says the event that starts an entry's work again. At its start, the runner and the
assigner each ask `outdated` once and start the work it names, so a restart or a missed event leaves nothing behind.
Why: the operator, 2026-11-10 (issue 1961's "outdated"); events start the work, and the query finds what is behind
and answers a person. How it is checked: test 105.
- §376 **Each kind is checked on its own event, per node where it is delivered.** After a dependency's version is
released, on its `version-released`: the dependents by kind 1 whose entry is behind are rebuilt against it and their
pipelines started, as on `package-published` (§53), and those by kind 2 are delivered again on each node whose entry
is behind, the assigner writing that node's want again. After a dependency is delivered: by kind 3, when the agreed
toolchain names the build module's new build (*A build module's wait ends on the agreed toolchain*), its dependents
whose entry is behind are rebuilt; by kinds 4 and 6, on the node-engine seat's `running.<node>.<module>` of the
dependency's new build on a node, the dependents on that node whose entry is behind are delivered again by their
wants there, so a dependent on one node follows its own node and waits for no other. The catalog also says
`version-delivered` (the module and the version, once every present node that places it runs it healthy, nodes away
named, ADR 0603 §7) on `mesh.seat.mesh-catalog.event.version-delivered`, kept 90 days at 16 MiB: the mesh-wide summary
a person and the status view read, which starts no per-node work. Kind 5 is held by the acting parts' waits
(*Within a revision the new version acts first*) and only shown by `outdated`. Why: the operator, 2026-11-10; the
events still start the work (ADR 0666 §14, §15); per node, since a node away holds only itself (ADR 0603 §7). How it
is checked: tests 104 and 105.
- §377 **The first fill.** At the indexer's first start under G, after `versions` is filled (§372), each module's
newest version gets its entries once: the build kinds from the dependency version published latest before that
version's build was claimed, read with the times of `builder_versions`, and its digest; the delivery kinds, per
node, from the last `running` of each module on each node, which the node-engine seat's stream keeps last per
subject with no age limit; kind 5 as done for every acting part's running build; kind 6 from what each node runs.
Each filled entry is marked `filled`, so a person sees it was derived, not recorded. It is not filled again. Why: so
the first `outdated` does not find the whole mesh behind (the lead, 2026-11-10). How it is checked: whole
(indexer), after the first fill `outdated` answers nothing for a mesh whose modules run their newest builds.