Dropped since the hear was removed (ADR 0625 §4); the golden user list and the grants case now hold the node user's subscriptions. The indexer's open-tries comment says it refuses an answer without the key.
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
The seat verb try gains members (ADR 0637 section 6); the try's group name and the missing-preview reason are one definition of mesh-delivery-sdk (ADR 0637 section 8).
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
mesh-sdk compares its bootstrapped seat definitions with their contracts files, read beside it; the checker
places both, at the group's head for a member, else at the trunk, for a check and for a group try alike.
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
The checker says try.started (members at their commits) and try.ended for a whole try; the indexer writes and
deletes the candidate from them and finds the open tries again at its start through checker_tries, never reading
the checker's state. The try's digests are judged inside the one pass that takes the seats; the definitions of every
contracts module of each member are read; the config declarations leave a try's candidate alone.
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
A whole try has no pull request, yet compose-candidate and the manifest validator read the indexer's
candidate of a group. The indexer reads the checker's tries, writes candidates.<try id> (number 0 per member) from the
previews, judges its manifests with the seat definitions the members carry, leaves try-* alone in the open message,
deletes it when the try ends, and has a tool that reads and one that drops it.
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
A try names several repositories, each the exact commit asked. A whole try (not narrowed to a level or
tests) runs the group check's own path: the manifest validator, the module graph and the composition on every
placed node, reading the indexer's candidate of the try's group. A try with no such candidate is an error that
says so, never a pass. A try's candidate is no check: the checker leaves it alone and owes the forge nothing.
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
A member's go.mod names the oldest version a module accepts; the check builds the group's own heads whatever it names. go.sum lines of mesh packages are left out.
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
The take-in's dry run reads the contracts modules' definitions of the revision's merges and puts them over the seats while it judges; cmd/mesh-judge puts the request's seats over its own. A refusal of the named indexer's manifest is said on take-in.pending and in indexer_pending.
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
sdk/forms could not import the reference package: the registry client's module requires the delivery sdk (parts).
builds already requires the client and both seats, and both users of forms (builder, assigner) require builds.
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
mesh-sdk go/buildstep and go/health's condition and finding names are no longer imported; the seat's condition-cleared is heard under the seat events pattern already held.
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
The judge keeps the node's answer as the verdict's body; pointer times of the contract are guarded. One ask test folded into a table to hold the unit count.
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
The take-in unblocks merges without the read grant on the forge bridge's stream: the message Arrive was handed is used,
the stream is read only for a pending merge not held in memory, and older merges of a repository in a revision are
covered by its newest and never read.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
The pending value holds the stream sequence and the small fields the waits read; the take-in reads the message from the
forge bridge's stream by sequence. A message the stream no longer holds is said (take-in.pending lost, indexer_pending)
and never taken in silently. indexer_take_in_forge takes one forge message in by its sequence.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
mesh/check being carried to c78941e80b59 on 4596fbe1b7ac | from ae31b66a9e33, mesh-catalog fd4931a75261 | novox/mesh-delivery#153 in group feat/take-in
The group's check failed at 7b7096f3: the group's own manifest validator refuses the indexer's stream "take-in", outside
the bus's predefined forms. The lead's ruling: the indexer says take-in.pending and take-in.taken as its ordinary events
(its emits, mesh.mod.<module>.event.take-in.<kind>), as manifest-accepted is said, and keeps no stream. The wait's key is
in the body only: an emitted event names one event (no wildcard), and a key such as g.<group> is no event name. The
watchman consumes the two events by name on the shared events stream; it needs no replay, since it seeds its waits from
indexer_pending at its start. indexer_pending says the last event of each wait as take-in.<kind>.
Run locally, as the check runs it: cmd/mesh-judge over every manifest of mesh-catalog, mesh-delivery, mesh-host,
mesh-tools, mesh-networking and mesh-media-catalog, with this branch's and mesh-catalog's feat/take-in manifests in the
change case and origin/main's in the trunk case: 171 of 171 accepted in both. The same run with the indexer's manifest at
7b7096f3 refuses it with the check's words.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
mesh/check failed (2): mesh-build-go: the indexer's judge at the group's mesh-delivery head 7b7096f37ea76e1…; and 1 more | 7b7096f37ea7 on ae31b66a9e33
- A take-in releases its claims (compare-and-set, only while the claim is still its own) on a lost claim, on a claim it
cannot read back, and on a merge it fails to take in: a claim left behind refused every later take-in until a
restart. T5 row with a store that fails once, both ways.
- The start step waits for nothing: with the build it runs unknown it says so and the forge consumer starts; a merged
message left unacknowledged asks the build again (clause 1). T10 row: the start answers at once and takes nothing in.
- A toolchain report evaluates pending again (ToolchainReported), since the build a revision names moves with the
toolchain. T7 row: the revision is taken in once the report makes it name the running build.
- The group's end is told by its whole subject (process.ModuleStreamSubject), so a repository named forge/group is
never taken for one; row in the indexer's handle test.
- The watchman asks the indexer's waits through indexer_pending at its start (invokes), before its durable consumer,
which does not hear again what it acknowledged before a restart; the comment that said the whole stream is heard is
corrected. W2 row: a wait seeded within its bound is raised past it.
- bridge_groups names each group's last end ask, its who, why and when, and the bridge's answer (state end-asks).
- The check's words for the indexer's rules: the trunk's manifest validator.
- The bridge's end drops the merged-state test its merge commit already implies.
- Test budget: groupask_test folded into groups_test, and the K1 mesh/check test into the owed status one: 804 unit
tests (was 806).
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
The operator, 2026-11-04: logic one module owns lives inside that module as a package of its own, so the take-in step
changes no mesh-sdk. TakeIn, its keys and event names, PendingWait and PendingAnswer move to
modules/mesh-delivery-indexer/takein (its merges a takein.Merge of its own); Forge whole, with its group fields,
ForgeGroupEnd and GroupMerge, moves to modules/mesh-delivery-forge-bridge/forgemsg. Both are nested Go modules that their
readers take by replace, as buildrun is. Every importer moves in this commit: the indexer, the bridge, the watchman and
the view. Forge's private checks (the repository name, the version) are copied small; mesh-sdk main still holds an unused
Forge until its own fold removes it.
The indexer, bridge, watchman, view and checker pin mesh-sdk 5a38a12 (origin/main), no feat/take-in commit.
The bridge's integration bus now grants the state end-asks that bridge_group_end_again added: without it every test of
the package failed on a permissions violation. Test budget: two new test functions (TestForge, TestTakeInEvents) and the
two the join added are paid by merging four pairs in internal/bridge; the repository stays at 806 unit tests.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
A revision changing the indexer writes only what the named build needs and is
taken in when that build starts; a gathered group stays across the restart and
its end makes one take-in.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
TestIndexerWhole found the start waiting for ever on a build no node-engine
answered, so the forge consumer never started, though nothing can be pending.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
The group is read from the gate's merges state the bridge already reads;
the end comes only once every approved member is merged and its merged
message written, never on a refusal, with a message id the stream's
duplicate window holds to one.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
The group is read from the gate's merges state the bridge already reads;
the end comes only once every approved member is merged and its merged
message written, never on a refusal, with a message id the stream's
duplicate window holds to one.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
The consumer tells a group's end apart by its name before the forge decode,
a merged message goes through the pending state, and the pending revisions
naming this build are taken in before the consumer starts; take-in events go
on the indexer's own stream. Until the pending state is on the bus every
merge is taken in at once, as before.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
A merged message is kept in the indexer's own state pending and the merges
there are computed together on overlays of the indexer's states: taken in
whole when the indexer's fingerprint is the running build, otherwise only
the indexer's own entry, graph key and verdict are written and the rest
waits for the named indexer. A group's members are gathered until its end.
Waits are said on the stream take-in, read by indexer_pending and steered
by indexer_take_in_pending and indexer_drop_pending.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
docker's daemon file names the image seat's reach while its manifest stays, so
the hold read from the manifest alone let an engine before the reading lose the
file. The forge bridge reads each manifest's templates at the merge and carries
the module's needs whole; the indexer takes them, keeps them past the judge, and
holds any changed entry, not only a new manifest digest.
A hold standing past 30 minutes is the finding manifest-held, its bound a key
of the new state hold-bounds that expires; its expiry and the start weigh the
holds again, so a restart loses no bound. A hold moved by hand names the nodes
it strands, in its answer and its hand act. The hold test is a case of the
manifests test, not a function of its own.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
Every node-engine reads the store holder's manifest to find the store, and an
engine before form:seat-reach finds it only through the retired provision, so
writing the new entry while one counted engine lacks the reading would leave
that node without the store. The entry keeps its old manifest, fingerprint and
inputs; the new one waits in the state holds and moves once every counted
node-engine (ADR 0624 §1, read as the builder reads them) states it.
indexer_holds reads, asks again or moves a hold by hand; indexer_engine_reads
reads the engines' statements.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
The operator's decision of 2026-11-04: the fresh-mesh circle, a holder whose build publishes through itself, is caught
where a fresh mesh starts (issue 1152), not by a rule that refuses the registry seats' holder.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
mesh-sdk's views.Emitter writes the owner's finding of a change not said past its bound only when Findings is
set; both owners of views in mesh-delivery now set it to their findings state.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
A seat that cannot remove a tag alone (another tag names its digest) now answers and says kept. The builder ends
that remove there, with no retry, and marks the version kept on its store with the reason and the other tags;
builder_versions shows it, and a later branch end asks it no more. The four seats' kept are consumed.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
mesh-sdk's state read-only (d420491c) is mapped into the grants' buckets, so the module's account and the tool
runner read it and never write it; the judge refuses a read-only state no process's bus state names, since
nothing would write it.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The bus module's spend record must not be writable by the tool runner. A state declared read-only gets read on
the module's own account and the tool runner carrying it (direct get, a watch's consumer) and no publish on its
$KV subjects; the process whose bus state names it writes it. The judge rule and the manifest field follow
with mesh-sdk's read-only.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
Bind runs once at a part's start, so the finding's words no longer promise it clears when the grants part makes
the consumer. The assigner's comment on firstViewBound named five seconds for views.Bound, which is two minutes.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
A watch of bounds that cannot start lost every bound's end with a log line only: it is now family-not-heard
naming the state. A publish bound that cannot be written would never end: the version is publish-unanswered
at once, saying why.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
Review round 1, running F4 (design 25 § 12.7), moved here from the nats test by the lead: in the composed-grants case
of the whole test, the part composes nats and messenger from their manifests (testdata copies of the catalogue's at
the join); the keeper connects on its own process account to a server loading the composed list, reads the router's
record of its ask, and is refused a write to the router's asks and the part's state and another asker's record.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
Its durable consumer filtered only its consumes, composed as module subjects, so the operator channel's
decided for its own asks could not be heard there (design 25 § 12.3: it wakes on the warrant).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The raise and clear of first-view-unanswered dropped a failed publish (_ = say). The binding comment
named the bus module's own stream and 30 days; the part hears the seat's events on the shared stream, 7 days.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
Every state a module keeps has a read tool (the lead's ruling). Each key of bounds now holds what it bounds
and when it ends, and builder_bounds lists them with the time left.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The case ran only on the in-memory store. Eight claims of one name at once on the builder's state versions,
through its own bus adapter, get eight versions; with Create turned into Put they share one.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The finding was written only at the window's next change. Each node holding the window has a key of the
builder's state bounds whose time to live ends at its seven days; the bus's marker of its end steps the
window, which raises the finding then; a node that no longer holds it loses its key.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
A read naming no node (an empty node_haves, the placement not read yet) closed the window for good (security
review F3, second of a kind). The window embeds delivery.WindowHeld and steps by the shared rule, named being
the placement's nodes before any is dropped. The builder's expiring keys share one state, bounds (the publish
bound of F-delivery 5 renamed), for the old-form bound next.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
A holder's refused, and a version no holder answered, raised no finding outside the floor, so a build said done
while its file was not in the registry; a seat's outcome that does not read was only logged (design 51 Health
and conditions). The bound is a key of the new state publish-bounds with its own time to live, armed when a
built version is still numbered; a later published of the name clears both findings.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The indexer's, the assigner's, the builder's and the watchman's consumers that were not there or could not be
heard only said so in the log, so the part stayed healthy while it heard nothing (ADR 0615 §5). sdk/heard is
the one shared helper: the finding family-not-heard names the observer and the family, written when the
consumer does not bind and deleted when it does.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The bus module says created once per entry, so every later accepted manifest of the module raised a false
bus-state-overdue five minutes on. The watchman keeps a mark per entry said created, on its pulse state with no
time to live and read back at a restart; a refused or an entry no longer asked drops it.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The assigner read the indexer's graph state itself, the one reader left after ADR 0615 §1. The indexer serves
graph as a seventh first-view tool to the assigner alone; the assigner asks it, follows views.graph, raises the
first-view condition past the bound while the indexer is down, and its reads of graph goes.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
An answered packages state with no name handed the judge nil, which judges no name, so a manifest naming an
unknown package passed (DLV-I14, design 32). PackageNames is nil only until the state's first reading ends.
judgeOver takes one module and digest, so dropping the known packages for a digest the trunk does not hold
cannot drop them for another (J7's note).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
catalogue.InRegistrySeat now reads the holder's upstream naming and InArtifactStore derives its store path, so forms'
own reader goes, and the upstream rows run the encode check again.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
ADR 0624: container-image-registry/<module>/<artifact>@<digest> and the holder's container-image-registry/upstream/<host>/<path>@<digest> are form:seat-reference; Older derives artifact-store://... so a key keeps both. The registry form now precedes the artifact-store form, so a node stating nothing keeps the recorded store form of an image.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The checker, which knows the delivery group, judges a change's names; the indexer's state knows only the trunk's packages
and refused a package new in the group. The trunk's manifests are still judged on them, and a merge's manifest in full,
though its candidate was accepted without them (UnknownPackageNames).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
Input is the composition's input; the judge's names now have their own field (mesh-sdk), so packagename.Input and the
judge's inputOf are gone and mesh-judge reads Packages.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
Their three copies of the id and option checks (askjson.go checkedAsk, the teller's routerAskOf, the view's routerAsk)
are deleted; each calls occ.Carried with the id the key and the asking give.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
After the join the builder looks at a done key again whenever a first view is answered late or a package's name is
heard (lead's i), and each look's "version kept" narration was written to the build log after the build's end, with no
start or end around it. A look at a done key builds nothing: a kept version says nothing new there and stays in the
process log only. TestBuilderMakesADoneKeyWithTheDigests failed at about one run in three (kept narrations of
tools-go and tools-typescript after the end); 8 of 8 pass.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The indexer's packages state is read through its read tool's first view and its views family (ADR 0615 §1), as the
other four states the builder follows, not by its bucket: the manifest drops the read, invokes indexer_read_packages and
consumes views.packages.
A package built unnumbered because its name was not known at its claim was numbered only at its module's next claim.
Now a series key heard naming a name looks at its module again (Builder.PackageNamed), and a look at a done trunk build
numbers what it left unnumbered with the done key's digests (BuildClaim.Done), so version.numbered carries the digest
for the build module's late publish. Woken by the views family, never a timer.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
Design 32 names a package in a manifest's packages by its name in its own
language, so the judge (DLV-I14) now refuses a name no known package carries
instead of any name that is not a declared <module>/<artifact>. The indexer
hands it its packages state's names, kept before the merge's judge pass; the
checker hands it its followed packages picture plus, for a package new in the
group, the name read at the member's head. Both read a name with one reader,
sdk/packagename.Of, and the judge request carries the names in its Input
(packagename.Input). The series-form check stays.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
History (A2j finding 1, J4): the indexer's and the assigner's read tools are views.ReadTool over views.KeptSource, which
answers `{key, history: true}` now; modules (20), heard (64) and wants (20) keep more than one revision. Rows in the
view's "each tool answers through the owners' read tools as before": indexer_module_history and indexer_heard answer
the owner's kept history, and a want's history (view_tiers' Since) is read through assigner_read_wants (the row it
replaces held that the owner answered no history).
Series (A2j finding 2, J4): the checker keeps each series change as a delivery.SeriesChange {module, artifact, from,
to} and renders the status line from it; delivery.Verdict.Series holds the case's changes (each module's artifact once),
and the verdict event's series the pull request's (meshdeliverychecker.VerdictHolderEventSeriesItem). An artifact new
on the head is no series change (the lead's ruling). Rows: TestTheIndexersJudgeJudgesTheChangesManifests (the verdict's
series; failed first, empty) and TestTheStatusIsPendingWhileTheCheckRunsAndEndsSuccessOrFailure (the event's; failed
with the fill cut).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The indexer's SeriesPackage and SeriesVersion are aliases of delivery.SeriesPackage and SeriesVersion (J4), SeriesKey and
IsSeriesKey are delivery.SeriesPackageKey and IsSeriesPackageKey; the indexer's readers (the series read for a user's
fingerprint, indexer_package_users) and the builder's NamesIn decode with delivery.DecodeSeriesPackage (the builder no
longer reads the indexer's value by field names). Found by the contract: a published newest's Contents named no time,
which DecodeSeriesPackage refuses, so the accepted series was left out and its users kept the commit form; the
indexer now stamps the time the contents were read (TestImportsReportedMoveTheFingerprintOnlyWithAnImportedPackage,
"an accepted series' newest ... pins it", failed with the decode before the stamp).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
versions.NumberedBody and NumberedEvent are mesh-sdk's delivery.VersionNumbered and VersionNumberedEvent now (J3), the
contract a build module consumes for BG2's late publish; the body's JSON is unchanged. The lane reads a step's
out-of-step files through delivery.BuildAnswer.OutOfStep, a failed step's result too (as before, A2k's d15d66fc: read
before the step's state; its three rows hold it), in place of a local decode by name. The integration test hears
version.numbered on delivery.VersionNumberedSubject and reads it with DecodeVersionNumbered, as a build module does.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
One modules value per module means a trunk claim has no earlier merge of the same name to wait on, so nothing called
it; its subtest "merge order" goes with it. Design 51's merge-order line holds by that (a review check).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
mesh-delivery's sdk/firstview moved whole into mesh-sdk go/views (J3): the builder, checker, watchman, teller and view
follow each owner's state with views.ProcessReader.Follow(owner, state, tool, stream), naming the owner's read tool as
their invokes name it and its views family as the owner's manifest's `streams` names it ("indexer-views",
"assigner-views"); a refused Follow stops the start. Their beds serve the owners with viewstest.Serve and grant with
viewstest.Grants by the same names. The view's tools ask the owners' read tools by their literal names. The assigner
names its own views family and the indexer's itself (views.AssignerStream and IndexerStream are gone).
Every views.StatusTools call takes handacts.Recorder{Ask: stdio.Ask}: a first view asked again by hand is a hand act,
recorded through seat:mesh-hand-acts.hand-act, which the builder's, checker's, watchman's, teller's and view's
manifests now invoke (a row in each manifest test, each failed first).
Row (A2j's written-time switch): TestRunNeedsItsCredential "a want stood since the assigner's bus wrote it": the
watchman's want time (createdOr) is the time the owner's bus wrote the key, through ProcessReader's first view (failed
with createdOr ignoring the entry's time). sdk/go.mod: nats.go is indirect now.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
mesh-sdk holds no go/asks, go/asker, vault answers or compose-candidate types (A1d, J1): each module now names the
operator-channel contract and client, the channel benches (mesh-sdk/go/channel), mesh-vault's contract, and node-engine's
contract and client (a1-progress.md, the A1d and J1 rewrite maps).
- assigner, teller, view: delivery.Ask.Ask and AssignerAsk.Ask are the router's ask as JSON; the refusals mesh-sdk
dropped (an id other than AskingID(key, asking), no option) are each reader's and writer's: assign.EncodeAsk/DecodeAsk
(askjson.go), the teller's routerAskOf (teller.go) and the view's routerAsk (view.go); the teller refuses an option
the asking does not offer and one whose level is not acknowledge (viewanswers.go), the two refusals ViewAnswerFits
gave. Row: subtest of TestTheHoldAskIsValid (another id, no option, no ask; each written before).
- enrolment, grants: the vault's verbs and answers from meshvault; asks' conditions from the contract and client.
- checker, assigner's judge: compose-candidate from nodeengine/nodeengineclient (nec.Own for "node").
- mesh-grants' user-lists golden: the node-engine's users now subscribe to mesh-delivery-view's settled (mesh-sdk's
NodeAgentHears, A7's ENG-8 retry).
go.mod: each module requires the mesh-contracts modules it imports (and nodeengineclient, which mesh-sdk imports) at the
zero version, for the group pin.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The checker invokes it (A2j 5700edf) and the indexer said the state on its views family without a read tool for it.
Row in TestManifestDeclarations: every indexer tool a module of this repository invokes is one the indexer serves
(failed first, naming the checker's invoke).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
delivery.ManifestAccepted.EventID now names, for an event with no digest, the module and the event's revision (J3,
ruling A5(d)), so the indexer drops its own left id. The revision is the modules state's revision of the value that left
(write hands the revision it read), so two leaves of one module are two events; asked again by hand for a module no
longer held it is 0, and the again suffix keeps it unique. Row in TestAMergeThatRemovesAModuleDeletesItsKey (failed
first: Revision 0, id naming the last digest).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
views.IndexerStream and views.AssignerStream are gone from mesh-sdk (J3 lead's (a)): the indexer names its own views
family "indexer-views" and the assigner's "assigner-views", as each manifest's `streams` names them. Its first-view
ask-again records the hand act through seat:mesh-hand-acts.hand-act (views.StatusTools takes a handacts.Recorder;
the manifest already invokes the verb). judge_test.go gofmt'd (c6c6687 left it unformatted).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
L3 (710c4032) arrives with it. Conflicts, each kept from both sides:
- assigner module.json, manifest_test.go, main.go, tools.go, integration_test.go: A2's first-view tools,
read tools and states beside L3's assigner_engine_reads and engine-reads; the two "consumes" lists
joined into one (the indexer's views and node-engine.manifest-reads-changed).
- builder module.json and manifest_test.go: A3's tools, states, consumes and invokes beside A2g's first
views (DLV-M1); one findings state (A3's, history 5) carries both; reads keep A3o's
mesh-delivery-indexer.packages until the builder follows it (join item).
- builder cmd main.go: rebuilt from A3's with A2g's changes applied (the reader follows modules,
manifests, candidates and placement; one calls connection; one findings bucket, A3's
health.FindingsBucket; FollowPlacement on a goroutine once placement's first view is answered;
buildFromModules in place of the start's settle). Tools main.go: A3's tools then the first-view tools.
- builder run.go: A2k's out-of-step on the end entry, then A3's numbering of a done build.
- view module.json and manifest_test.go: node_manifest_reads and seat:node-engine.manifest-reads beside
A2j's first views and read tools; one invokes list.
- indexer judge rules_test.go: L3's manifest-reads verb and event, without pull-waits (J1 dropped it).
- sdk/go.mod and builder go.mod: both requires kept.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
Conflict: modules/mesh-delivery-watchman/manifest_test.go, both sides asserting m.Consumes,
and both adding a Consumes field to the test's manifest struct (kept once).
Git also auto-merged module.json into two "consumes" keys (A2g's first views and A5's
manifest-accepted and mesh-broker events): joined into one list, and the test asserts all five.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The builder numbers, asks the floor of, records and tags a package under the name the indexer's series key names for
its <module>/<artifact> (a Go module path, an npm package name; design 32), so builder_versions answers the holder's
question by the name a registry seat publishes it under. A package the state names nothing for, or a state not readable,
is built unnumbered and said; the rest of the claim is numbered.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The builder's forms gain seat-reference for bundles and archives (oci-artifact-registry/<module>/<artifact>@<digest>);
the old-form window writes the older artifact-store reference beside it (catalogue.InArtifactStore), the oldest kept
in the single reference (ADR 0624 §1, §3), so mesh-build-go's seat-form answer no longer strands an engine stating nothing.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
At each trunk merge the indexer reads every package artifact's name from the merge commit (a Go package's go.mod module
path, a TypeScript package's package.json name) and writes it into the series key as name, beside the module and artifact
it is built from, so the builder numbers it under that name before its first version. Series keys, accepted series and
indexer_package_users go by the name (the lead's design limit for design 32, replacing the builder-name fallback).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The lead's ruling on A2h's finding 1: J3 builds each first-view key's written time into mesh-sdk views
(Answer.Written, a Picture entry's Created) and J2 the tool runner's state reads' at. The watchman and
the builder's toolchain gate already read the entry's Created(), so neither changes; this says so where
the fallback stands.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The lead's ruling on A2i's finding 1 (design 26): the indexer keeps an unparsed definition of a pull
request's head as its entry of the state seat-definitions with `unparsed`, and cannot refuse the manifest.
The checker follows that state as its seventh first view (invokes indexer_read_seat_definitions, consumes
views.seat-definitions; checks start once it is answered too, as M2's six) and fails each pull request
with an entry holding `unparsed`, naming the seat, its module, its directory and the indexer's words; a
state that cannot be read fails it too. Rows: TestTheIndexersJudgeJudgesTheChangesManifests (fails
first without the refusal), the adapter's key match in TestThePublishedVersionsAreTheIndexersPackagesState
(fails first matching every key), the manifest's invokes and consumes; the integration bed serves the
state (without it every check waits and five tests fail).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
Cases in TestAMeshSDKMergeMovesOnlyTheModulesImportingAChangedPackage: the checker's verdict event keeps a pull request's
files, a trunk build end raises generated-types-out-of-step and a clean one clears it, as indexer_out_of_step reads them;
indexer_seat_definitions_again, asked through takeins, reads a pull request's head and indexer_seat_definition answers it.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The builder reads out-of-step from each lane's step result, a failed step's too, and writes it on the build's end
entry (BuildLogEntry.OutOfStep, J3's mesh-sdk field), where the indexer raises generated-types-out-of-step for a trunk
(the lead's ruling on A2i's finding 2). BuildAnswer names no such field yet, so it is read by name and shape.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
Design 32 (A config value renamed): the checker invokes seat:mesh-config.renames, never the module. A
change bringing renamed-from to a holder that serves no renames (nothing answers the optional verb) is
refused naming it; dropping a renamed-from while its window is open is refused naming the nodes holding it
open; a check that cannot ask fails, saying so. The pull request's trunk and head manifests are read once
for this and for the series changes (manifestPair). Rows in TestTheIndexersJudgeJudgesTheChangesManifests
with the verb faked from the seat's definition (its fixture's answer): not served, served, open on g14,
closed, an ask that fails, no seat to ask; the four refusals failed first. Manifest row for the invokes.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
A second repository's trunk defining a seat another trunk holds is refused and kept nowhere, with the finding
seat-defined-twice naming both repositories; indexer_seat_definitions_again for a pull request reads the head's own
generated-from, so a pull request changing that field is read right by hand too (the lead's rulings on A2i 3 and 4).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The case in the assigner's whole-module test serves the tools bundle's first-view tools as the runtime of its own does,
with the callers its manifest writes, while the assigner still waits on the indexer: the grants part, the tool runner and
the indexer each get theirs, every other account (the assigner's own included) is refused (ADR 0621 §1-§3).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
Design 32 (A package, its series): the review of a change sees every series it raises. For each module a
pull request touches, every artifact its trunk manifest and its head's manifest both declare whose series
differs is named as "<module>/<artifact> series <trunk> → <head>" in the pull request's mesh/check line,
never dropped when the line is cut; a manifest that cannot be read is said in the same place. Rows in
TestTheIndexersJudgeJudgesTheChangesManifests (raised: named; kept: not named); the raised row failed
first. gofmt of the integration test's imports (M2).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
ADR 0615 §1, design 25 § 12.2: the manifest drops its twelve reads of the two owners' states and invokes
their twelve read tools. The process follows the six it watches (placement, wants, asks, candidates,
modules, taken) by the first view and then the views families (consumes), through firstview pictures, so
its watch code is unchanged; an owner that is down holds no other watch, and the unanswered first view is
the view's finding (states first-views and findings; tools view_first_views, view_first_view_again).
The tools keep their names, arguments and answers and ask the owners' read tools on each call
(view.OwnerRead; a read of many keys is one paged values read). DLV-V1: a table subtest answers each
tool through the owner's own Read over a fake state and matches what reading the state answered.
The owners' read tools answer no history of a key: indexer_module_history, indexer_heard and view_tiers'
times say so (an error, never none) until the read tool takes a history argument (a request to the join).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
A case of the assigner's existing whole-module test: the indexer's first views are held until the
assigner has started, and the wants are written from what they answer (ADR 0621 §3).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
A case of the indexer's existing whole-module test: the assigner's first view is held until the
indexer has started, and only the placed node's toolchain counts once it answers (ADR 0621 §3).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
Design 26 and ADR 0608 §2-§4: the definitions are read at each trunk merge and pull request head
through the forge's get-file tool, parsed by mesh-sdk seatdef and kept in the state seat-definitions
by seat and source; seat-definition-changed is said, kept seven days, only when a digest moved. A
trunk definition that does not parse leaves the trunk's entry and writes seat-definition-unparsed;
a pull request's entries go when it closes or merges. A trunk build end naming out-of-step files
writes generated-types-out-of-step, cleared only by a clean build of the same module; the checker's
verdict keeps a pull request's. Tools indexer_seat_definition, indexer_seat_definitions_again (a hand
act) and indexer_out_of_step.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The lead's ruling 5: one row in the judge's table, the enrolment's shape (a claim serving the seat's
verbs and the first-view tools in its own tools list); the judge accepts it as it stands.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
ADR 0615 §1 and ADR 0596: the checker invokes the six read tools, consumes their views families and
reads none of the six buckets; this ends its direct read of the packages state (the lead's ruling 2).
It keeps first-views and findings and announces both as its own. The lead's ruling: an owner that is
down never holds the start; the checks, the tries and the hand asks start once every first view is
answered, the placement is followed into the toolchain gate once its first view is. firstview.Reader
opens a followed state's picture as a process.BucketOpener (the builder uses it too). Tools
checker_first_views and checker_first_view_again.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
ADR 0615 §1: the builder invokes indexer_read_modules, _manifests, _candidates and
assigner_read_placement, consumes their views families and reads none of the four buckets; it keeps
first-views and findings. The lead's ruling: an owner that is down never holds the start; the modules
are built once the modules', manifests' and candidates' first views are answered, the placement is
followed into the toolchain gate once its first view is, and until then the gate passes every report on
as before the placement settled. Tools builder_first_views and builder_first_view_again.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
ADR 0615 §1: the watchman invokes assigner_read_wants and indexer_read_modules, consumes their views
families and never reads either bucket; it keeps first-views and writes an unanswered first view as a
finding of its own. The lead's ruling: an owner that is down never holds the start; each state is read
on a goroutine once its first view is answered, and what it holds (seeded pulses, stuck keys, the
findings it is the source of) is reconciled then (watch.Awaits, ReadLate), never dropped at the start's
end. Tools watchman_first_views and watchman_first_view_again.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
A rename moves a module's own value with its trust (design 32): the old name is a value the trunk's manifest of the
same module declares and the change does not, no secret and no key of the predefined list, and the old and new value
have the same trust, declared or by the predefined key they take. Judged for a change over the trunk; each refusal
names the module and the key.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
Between the manifests (design 32): each name in a module's packages is a package some manifest declares, by the
builder's name <module>/<artifact>, and each accepted series is <major>.<minor>.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
Design 32's words: a series is <major>.<minor> and only on the four kinds the builder numbers, a package is go or
typescript, generated-from only on a package. A package is published as its source, so it names no system: today's
judge refused mesh-sdk's Go package (no system) as a binary.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
Left by the bus-state review (ADR 0595 §8): a set-entry or remove names its into and key, an operation's fields and an
index's on name schema fields, and a digest-of names a text field; each refusal names module, entry, type, operation
or index, and the field.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The bus module's orphans need to hear a module that asks nothing now (design 25 § 12.2): every newly accepted manifest
is said, its entries an empty list when it asks for none, and a module whose directory leaves the trunk gets an empty
one; a manifest set aside to wait gets none. A failed publish is published once more; one failing twice writes the
finding accepted-unsaid naming the module, said again at the next judging pass and cleared once said.
indexer_say_accepted says it again by hand from the held verdict, a hand act through mesh-hand-acts; it refuses a
module with no accepted verdict.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
ADR 0615 §1: views.Reader asks mesh-delivery-assigner.assigner_read_placement and hears views.placement;
the holder reads placement from the picture and every other state through the runtime. The manifest drops
the read, invokes the tool, consumes the event, keeps findings and serves enrolment_first_views and
enrolment_first_view_again.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
ADR 0615 §1: sdk/firstview is a process's picture of an owner's state, read as the bucket it
replaces (Get, Keys, Watch; every write refused), asked through <owner>.<short>_read_<state> with
values and kept from the owner's views family; firstviewtest serves an owner in a whole-module test.
The teller declares invokes assigner_read_asks, consumes views.asks, states first-views and findings,
and the tools teller_first_views and teller_first_view_again.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
So a user left on an older series is seen (design 32): per package its series with each one's newest published
version, and its trunk users with the series they accept, that series' newest and the version they are pinned to.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
A series' newest published Go package keeps its module's digests read at the version's commit; each module of another
repository whose series the user's manifest accepts enters the import form and the version line by them, pinned to the
version (Go's form). A series with no published version keeps the commit form; a group member keeps its head.
A publish that moves a series' newest recomputes at once.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
A user takes the newest of the series it accepts (ADR 0609 §1), so the
indexer learns versions from the builder's numbered and the registry seats'
published, one key <package>.<series> beside the per-module digests.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
Design 26 has the indexer learn out-of-step generated files from the check's
verdict event, so it runs no generator; the test step's answer carries them.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
A case of the existing group test (no new integration test): the bed's streams are the manifest's (checks with
preview.written, asks with verdict and tag-wanted at the mesh-delivery-checker definition's subjects) and the shared
events stream with the registry seats' published. A group whose mesh-sdk member has no preview yet is read at its head,
says tag-wanted whose body decodes strictly into the definition's type, is not judged before the Go seat's published,
and then builds mesh-delivery against v0.1.15-feat-x.1. The verdict half of DLV-C6 follows DLV-C2.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
Design 51 says the build log tells a version kept and why, a tag ask unanswered after five minutes,
and the old form's window closing; the process log alone was read by nobody. Each numbering decision
is now a build.said of its module and fingerprint, its why one of numbered, kept, waiting, unnumbered;
the tag ask and the window, no one build's, are said under the builder's own key, the ask's or the
window's key standing for the fingerprint. Needs mesh-sdk 7efb173 (build.said). Each failed first.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The two copies of IsBuildEntry move into sdk/buildlog, which both modules already require from the repository's own
sdk module (the lead's ruling 5 on A2c's finding 5). The existing rows in the indexer's registered test and the view's
history test cover it unchanged.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
Design 51 *Tagged versions* and ADR 0607 §3, §5: once each package's published is heard, a Go member's ask names the
group's tagged version of each package another member publishes (Go's form, v0.1.15-feat-x.2), a package new in the
group included, and a TypeScript member's Node fetch takes {name, version} from the registry instead of a packed head.
The published is matched by seat, head and name, so one head with several Go packages (mesh-contracts) gets each its
own version. With no preview of the merge, a member's manifest is read at its head on the forge, so a package new in
the group is asked for on the first check too (the lead's ruling 4 on A2c's finding 4).
Needs mesh-sdk's PackageVersions.Check to take a Go semantic version (a2d-sdk-tagged-version.patch, for A1).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
On the real bus the artifact seat's removed (retention) and refused (another digest) move a numbered
version, and the forge bridge's merged asks the Go seat to remove the version tagged for the branch,
reason tag-gone, whose removed turns it removed. Each failed first with its hearing off. No new test
function: the builder holds 16 integration tests.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The bed holds the builder's versions, findings, floor-waits and reasks, EVENTS with the artifact
seat's outcomes, and the floor's three sources served on the bus. Two merges close together number
the second at once; builder_publish_again after published takes a new number; a step bound running
out raises build-failed, and the fingerprint built again keeps its number, said with why, and clears
it. Each case failed first with its behaviour off. The kept version is said in the process log until
the build log takes build.said.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
A case of the grants part's whole-module test (ADR 0615 §6, ADR 0621 §3): each first view refused once, the part's log
names the indexer's and the assigner's tools it waits on, no membership is written; once the owners answer it composes
as before.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The builder's integration tests fall from 17 to 16: the two-instance test is a row of the archive table; the bed holds the
tag asks and their key-ttl bounds and the builder's process log.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
A check's build of the ask's head writes the ask numbered in tag-asks by compare-and-set. An unanswered ask has a key in the
new key-ttl state tag-ask-bounds (five minutes); the bus's marker of its end, heard on the watch, narrates the ask with what
it waits on (the check's build not claimed, names waiting on their floor) and writes the bound again; no timer (design 51
*Tagged versions*). A restart arms each unanswered ask whose bound ended meanwhile.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The checker's family asks is its own stream, whose subjects are mesh.stream.<module>.event.* (ruled on A2c's finding 1);
its verdicts on the same stream are acknowledged and not taken as tag asks.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
ADR 0615 §5: a gap in revisions asks the first view once more. The indexer's verdict events carry no mark of when its
verdicts were made, so verdicts made again show only as revisions starting low, which the grants part passed over as
already held. A redelivery of a verdict the picture holds for its manifest is still passed over, so a consumer's backlog
after a restart asks nothing.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The builder writes design 51's old-form close into its build log; the indexer's Builds.Put refused it
(no repository) and the view's history stopped on it. Both read the entry's event first and skip any other
kind, whatever its form.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The lead's ruling of 13:0x (registry milestone): mesh-broker's events are mesh.seat.mesh-broker.event.<event> on the
shared events stream like every seat's. The grants part and the watchman consume mesh-broker.<event> and no longer hear
the bus module's own stream, which is its history for its tool. The keeper's process account is composed the seat's
event subjects, and the acknowledgement of a snapshot's chunks of each entry it keeps, which ADR 0626 §1 grants and the
composition lacked; a row holds it to no subscription of a restricted stream's subjects and no consumer of one.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The checker's family asks (stream asks, seven days, in the old streams section) carries tag-wanted
{repository, branch, head, module, package, pull}; the tag is left to the builder, which makes it from the
branch. Each package's published is heard from the two package registry seats on the checker's durable
consumer of the shared events stream; none within the ten-minute bound fails the check naming the package,
before any member is built. A lone pull request and a try ask nothing (design 51 *Tagged versions*).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The builder reads tag-asks for the candidate's repository and head (versions.TagFor), numbers only its packages under
the tag below the next version, keeps each with its repository for the branch's end, and says numbered with the head;
the same fingerprint claimed again keeps its number (design 51 *Tagged versions*).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The window opens while a counted node-engine reads, of some kind, none of the newest form sdk/forms knows, and closes
when none does: said once as version.old-form-closed, and a node holding it seven days is old-form-held about it. It
steps on a statement's change, the placement, a hand drop and each build key written, never on a timer. A retired node
dropped by hand leaves the count of the forms a build key keeps (design 51). internal/versions' own Forms goes: which
forms a key keeps is sdk/forms'.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The builder keeps both: the registry's versions, floor, tag asks and findings, and ADR 0618's engine-reads state,
its tool builder_engine_reads, the node-engine seat's manifest-reads verb and manifest-reads-changed event.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The next revision changes the verdicts' picture with no ask; one already held is passed over; an
event carrying no revision, past the next, or naming no manifest above the picture asks the first
view once more, said in the log. The manifest consumes the two events in place of views.verdicts.
Needs mesh-sdk 3ff694e (the events' Revision) and the indexer setting it (A2b).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
Filled at each merge from the go.sum the indexer reads (the lead's ruling on I7), read once per consumer per process
even where its hash is unchanged; the builder's floor asks {package} and reads {requirements: [...]}, highest last.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
Answers {revision, modules:[{module, digest, revision, bus-state}]} from the indexer's own states, at the verdicts
state's mark, as A5's keeper reads it.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
A process of the bus module without keeps, or keeps on any other module, is composed nothing
of it. mesh-sdk's ProcessBus.Keeps is asked of A1 (a5-sdk-keeps.patch).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
mesh-sdk's compose-candidate answer is now the node-engine seat's generated type, whose input is a JSON object; the
composer's request takes bytes, so the checker encodes it again, its numbers kept as written (json.Number).
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
The builder hears the forge bridge's stream on a durable consumer: merged, a
pull's closed and branch-deleted ask remove of each tagged version still
held, and the bus gives the message again each minute until all are removed;
past 15 minutes its finding tag-removal-not-done names the seats. The builder
gains the state findings (ADR 0564 §2). Every forge message also wakes a floor
whose bridge_tags was silent.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
mesh-broker's verbs are all optional now and the composition grants its reading verbs to its
holder, so taking one from a membership loses no holder: the rows that prove a lost last holder
is held back name a seat the catalogue defines without verbs, claimed by the bus module beside
mesh-broker.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The new nats manifest has a keeper process with a bus account of its own; the judge refused it under ADR 0235 §8.
Needs mesh-sdk's ProcessBus to carry keeps (requested of A1); until then the strict decoder refuses the key.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
Each outcome is a seat event <seat>.<event> on the shared events stream (the
lead's ruling of 12:4x), heard on the builder's events consumer through its
consumes; the subjects are mesh-contracts'. A restarted builder takes its
floor waits in again, so its silent sources' events still wake them;
builder_floor_waits reads them.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The contract carries no checks, so sdk/enginereads judges the layout's version, the node, each capability, the reason and the times. The local replaces of mesh-sdk are gone: the lead pins mesh-sdk and mesh-contracts at the join.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
Each first view is asked at the start until answered, past two minutes raising
first-view-unanswered naming the owner and the tool; an empty answer at revision 0 reads as
a failed read, so the user list stays in force, and first-view-empty names the operator's
step until an answer above 0. Each owner's views event applies one change with no ask; a gap
asks once more. The reads of the five buckets leave the manifest, and the tools ask the
first views too. Tools grants_first_views and grants_first_view_again (a hand act).
The verdicts are followed on the indexer's views family (views.verdicts), not on
manifest-accepted and manifest-refused as ADR 0622 §2 words it: those carry no revision.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
Nothing in the composition changes for it: the consumers on module streams are made since
DLV-G1. The row proves it on the tool runner's own manifest.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The keeper is asked by a person through its own state requests (CAT-N8); the acting verbs
are served by nobody on the bus and denied to every principal whose grant reaches them. The
bus module's tools bundle may read its module's own stream back (nats_history).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The seat's definition (mesh-contracts meshbroker) names local-name and storage-type and puts
the events on mesh.seat.mesh-broker.event.<event>; design 25 § 12.3 keeps them on the bus
module's own stream. Both are read until that is ruled.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
It consumes the indexer's manifest-accepted and the bus module's created and refused on its
durable consumers. The five-minute bound is a row of its signals table (a pulse key whose
expiry is the finding, read back at a restart), not a new state: the prepare's state
overdue would have kept the same keys with no expiry to act on.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The grants are composed for the process of the module holding mesh-broker, from every
manifest's bus-state entries and the streams of the bindings kept; the writers table names
it beside the grants part as a definer of streams; the acting verbs are denied to every
principal whose grant reaches them, and neither the holder's own account nor the tool runner
serves the seat's verbs.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The part hears the bus module's own stream on its durable consumer there. That consumer did
not exist: since the controller ended (ADR 0590) nobody created a module's consumer on a
module stream it hears (AccountConsumers left them to the controller), so it is created now
with every account consumer, and a pass that created consumers wakes one more pass so the
part's own hearing opens at once. Bindings are kept per module under bound.<module>.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
A holder that failed leaves a version to publish again by hand: said numbered again while the build is held, built
again under the same number when its file is gone, numbered anew after a published; refused for other bytes. The
floor is asked again by hand; a branch's tagged versions are removed through each seat's remove, per repository.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
A counted node is one the placement names; a node with no statement reads as the baseline's first forms, and no node record is read in its place. builder_engine_reads lists, asks again and drops.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
indexer_config_readers {module} answers {readers: [{module, key, kind,
readers}]} for every value key and own secret any kept manifest of the
module ever declared: the module where its trunk's manifest declares it,
each open pull request whose head declares it, none for a key no longer
read (design 32 *A value no longer read*). It reads one watched copy of
the modules, manifests and config-candidates states. Nodes is left out:
the indexer cannot say which nodes' builds read a key. The indexer's
findings are said on its views family and read by indexer_read_findings,
for the condition keeper (the lead's ruling).
Issue 1966.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The judge's foundation holds exactly the nine parts of ADR 0619 §1 and §3,
left out of the old sections' count, and refuses a foundation manifest
asking bus state in the new form. The indexer also counts, across the
accepted manifests, the reads entries still declared on the indexer's and
the assigner's state, by owner and by entry; indexer_old_sections answers
both, so design 25 § 12.7's live row (0 on each owner) has its tool.
Issue 1966.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The assigner no longer reads the indexer's manifests and modules buckets
(ADR 0615 §1): it asks mesh-delivery-indexer.manifests and .modules at its
start, its first pass waiting for both answers as it waits for every watch,
then follows indexer-views on its durable consumer, asking once more on a
gap; past the bound its finding names the indexer and the tool. Its status
is in its state first-views, read by assigner_first_views and asked again
by hand with assigner_first_view_again. The whole-module tests run against
an indexer owner built from the views emitter and first-view answer.
Issue 1966.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The indexer no longer reads the assigner's placement bucket (ADR 0615 §1):
it asks mesh-delivery-assigner.placement at its start, waiting at most the
two-minute bound so a normal start computes the fingerprints once, then
follows assigner-views on its durable consumer, asking once more on a gap.
Past the bound it raises its finding naming the assigner and placement,
cleared by the answer. Its status is kept in its state first-views, read
by indexer_first_views; indexer_first_view_again asks again by hand.
sdk/views gains the event's write time, the status hook, and the status
state and tools a reader's bundle serves.
Issue 1966.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The forge bridge now says a branch's end as branch-deleted (design 51); the
indexer terminated it as unreadable. It acknowledges it, writes it to heard
as ignored, and the two handle tests are one table (mesh-delivery is over
its unit budget).
Issue 1966.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The assigner's bundle runs in a runtime of its own on its own account and
serves the first-view tools placement, seat-holders and wants, each answering
only the callers its manifest writes (ADR 0621 §1-§2), and the six read tools
of design 25 § 12.2. The process says each change of those six states on the
family assigner-views beside placement in its old streams section (ADR 0619
§2, ADR 0615 §5); a waiter on put never wakes on it.
Issue 1966.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The indexer's tools bundle runs in a runtime of its own on its own account
(runs-as) and serves the first-view tools manifests, modules and verdicts,
each answering only the callers its manifest writes (ADR 0621 §1-§2, ADR
0622 §1), and the nine read tools of design 25 § 12.2. The process says each
change of its ten read states on the family indexer-views in its old streams
section (7 days, 256 MiB), with a mark per state the first view answers its
revision from, so a reader that takes the answer misses no event after it
(ADR 0615 §4-§5). The shared shape lives in sdk/views: event, answer, mark,
the emitter, the tools and the reader's follower.
Issue 1966.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
Where the engine does not answer the verb, the node's record is read once in its place, said in the journal (the fallback until every counted engine serves the verb). Kept in the state engine-reads, which assigner_engine_reads lists and asks again.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
Logic only mesh-delivery's parts share, so it is mesh-delivery's and not mesh-sdk's (ADR 0593 §1, ADR 0608 §5). Tested through the assigner's and the builder's rows (the test budget). mesh-sdk is pinned by a local replace to the group's head while developing.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
The builder's one consumer of EVENTS now consumes the indexer's manifest-accepted and
the condition keeper's condition-cleared; a heard source revision stands for the
forge's merge. Numberer.Heard marks a version published, refused or removed and wakes
a floor whose seat was silent; its consumer of each <seat>.events waits on the seat
family's stream form (asked of A1).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
A package whose floor is not known waits and nothing is claimed; an image, bundle or
archive is built unnumbered. The state versions is bound when the bus holds it, every
new number is said as version.numbered, and the manifest invokes the floor's three
sources (design 51 The versions, The floor; ADR 0606, ADR 0617 §1).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
A watch of the node-engine's manifest-reads-changed subscribed the flat subject, which no engine says, so its consumer would hear nothing. mesh-sdk is pinned by a local replace to the group's head while developing.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
The bridge consumes the forge module's forge.delete and writes a branch-deleted message on FORGE for a deleted
branch (never the trunk, never a tag), so the builder removes the branch's tagged versions (design 51 *The forge
bridge says a branch's end*). Only the forge module's account may say forge.delete: the bus refuses it from
another (a case of the bridge's whole-module test). bridge_tags, served by a new tools bundle, answers a
package's git tags by prefix through the forge module's gitea_api, for the builder's floor.
One unit test merged into another, so the tags test adds no function (test budget).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The floor asks the seat's versions, bridge_tags and indexer_requirements; a silent source is named in the
floor finding and woken by an event of that source (the holder's published, the forge bridge's next message, the
indexer's next manifest-accepted) or its module's condition clearing, or by hand (builder_floor_again), never by
a timer (design 51 *The floor*, ADR 0617 §1). The old form's window (ADR 0624 §1-§3, ADR 0618 §2): each counted
engine gets the newest form it reads among those written, the new form only once every present engine states
it, the oldest kept in the single reference; a node not serving manifest-reads counts as the baseline; a node
dropped by hand counts no more; old-form-closed is said once, and a node holding it seven days is a finding.
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
The builder keeps one key per name, tag and version (design 51 *The versions*, ADR 0606), in its old state
section (ADR 0619), history one, 64 MiB with the 80 % mark. A package is numbered per source revision and keeps a
version held published, publishing nothing; one numbered but never stored is published again under it. An image,
bundle or archive keeps its fingerprint's number. An unknown floor builds an image, bundle or archive unnumbered and
makes a package wait (ADR 0617 §1). Merge order and tagged versions below the next version are the package's
helpers. builder_versions answers a name's versions and the holder's question (ADR 0605 §4).
Four claim tests merged into two, so the new table test adds no function (test budget).
Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
mesh/check checking 70ade15c36eb on dd90a26251b9 | novox/mesh-delivery#149 in group feat/l3-final
The indexer judged only the manifests its modules state holds, so a digest refused by an older judge (node-tools
48c729f6 and mesh-provisioner-client a382b9df, refused for words then unknown) kept that refusal once it was back on
the trunk or in a candidate. Each such digest is now judged alone, in the catalogue the trunk holds, writing its
verdict and nothing else; an accepted verdict stays accepted under any later judge (ADR 0579 §1), so only a refused or
waiting verdict by another judge, or none, is judged again.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
mesh/delivery-group group feat/l3-final rejected: composed together: the checker's verdict at the members' heads (278aa5f0ccbe): unit: mesh-provisioner-client/…
mesh/check failed (2): unit: mesh-provisioner-client/cmd/mesh-provisioner-client.TestNatsANodeComingBackFil…; and 1 more | cbbc10871f2e on 007c982ae670
bus-state is offered with no credential of a consumer's own, so the provisioner keys nothing for it; the view showed
every module asking bus state as waiting for that key for good.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
A bus module that both offers and asks bus state waited on itself for good at its first such build; it now waits on
nobody for it, as the graph and catalogue.Awaited leave a module's own provision out.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
bus-state is answered with no credential of a consumer's own, so ADR 0603 §5 counts the provider's own have: the
assigner reads, per pass, what the running healthy builds on online nodes offer (their manifests through the builder's
builds) and holds a consumer with a bus-state entry under the provisions' rule until one offers it, handed or not and
with no provisioner key. The words name bus state, and the delivery view names the edge from them.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
The words of a want held on a verb or a reader capability are written and read in one place, the module graph's
package: the assigner writes them, the view names the edge from them. A bus-state wait is named bus state, and each
module's verb edges the graph leaves out on a cycle are listed beside its waits.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
Rows in the judge's table: two modules invoking each other, or a verb closing a cycle with a provision, are not
refused; a cycle of provisions and one of bases are. The refusal's words name what a part waits on now.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
What the running builds serve is read when a changed build module is met: the node-engine's haves, the builder's
build of each, its manifest. The modules it builds are composed from their manifests, as for any changed build
module, and the composition's warnings name the verb.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
The assigner reads the indexer's module graph (a new reads line): of what a module invokes it waits only on the edges
the graph keeps and another module serves, so a left-out cycle holds nothing; a verb counts as served once a running
healthy build's manifest serves it. The hold is under the provisions' rule, its words naming the verb, since no reader
knows a rule number of its own yet. Without the graph no want waits on a verb.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
The assigner reads which edges are left out from the graph, so one place decides the cycle; the whole graph is
judged, a module past the graph's cap included, before the first GraphMost are written.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
A graph node now names what its manifest invokes and serves, and the verb edges the graph leaves out; a bus-state
entry is a requirement of bus-state. Before and Cycle count the kept verb edges beside bases and awaited provisions,
never a package or toolchain edge. LeaveOut leaves out every verb edge whose ends reach each other, so the builder's
remove and a holder's builder_versions hold nothing and the check never refuses them.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
The rules read Module.Needs from the indexer's modules value and each node's stated reads from its record in
`<node>.node` of the haves; an engine stating none is read as the baseline, so the node-engine's own new build, whose
manifest uses only the baseline's words, is not held. The hold is rule 7 (no rule of its own is numbered in this
release, ADR 0614 F2) with words naming the node's engine and each capability, which the want tools and view_tiers
already show.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
Module.Needs is catalogue.ManifestNeeds of the manifest held: written by the merge that takes a changed manifest in, so
no reader takes it as needing nothing before the judge's pass, named again by the judge with the verdict, and carried
over by a write that leaves the digest, as the verdict is. The module value is the one the assigner and the checker
already read.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
mesh/check being carried to e3ce4b095ce9 on 007c982ae670 | from 4154c3040cee, mesh-catalog e6de42630355, mesh-tools 01ee2ef39488
The running indexer refuses the tool-runner word, so node-tools' trunk manifest takes it out again (mesh-tools
fix/l3-words-after-judge); trunk's judge then refuses node-tools twice (its waits, its runtime bundle) and mesh-grants
would compose its node users as plain modules. One helper, sdk/toolrunner.Is, counts a manifest as the tool runner
when it says tool-runner or its module is the SDK's deprecated catalogue.RuntimeModule; the judge's waits and
undelivered-bundle rules and mesh-grants' declared records ask it. It goes once tool-runner is back on node-tools'
trunk manifest (issue 774, issue 1585 note 42).
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
mesh/delivery-group group feat/l3b-bus rejected: composed together: the checker's verdict at the members' heads (62ca67fc6b58): integration: mesh-delivery-assi…
A failed candidate build no longer needs mesh-delivery.recheck, an exception verb (ADR 0421 §12): the checker hears the
builder's keys the failed verdict names and, once each is written done (builder_build_again), retakes the check of the
same heads as it does after a failure of the nodes, at its start too. When the tests have already failed the check
composes at once and names the builds it did not wait on, so its red status is never held back by a build.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
Worked out from the builder's builds state at each read, stored nowhere: of each running check, the candidate's builds
that are neither done nor failed.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
The builder already builds every candidate fingerprint into its own key. The check now watches exactly those keys on the
bus and composes once each is done or failed, within the new setting build-wait-bound (1800 s). A failed build fails the
check, naming it; a build not ended within the bound is named and the check composes without it. A module built by a
build module the change alters (mesh-build-go or mesh-build-node), one standing on a base the change alters, and one the
trunk holds no record of are not waited on, and the composition's warnings name each with why.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
D13b: the composition's warnings, and so the check's line, name the changed modules built with the Go build module the change alters and those standing on a changed base. D9: builder and verdict rows. D15: the assigner's integration test gets a source revision changing a provider, its new consumer and a build module.
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
The indexer's recompute and merge failed on listing a graph bucket not yet on the bus, and a package published from inside a module's directory had no publisher, so the dependents of a build module missed what imports its packages (review findings 3 and 4 of L3).
Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
dropRemoved hands the module over from the other trunk, read from the forge at the head the source names, so no wait in memory is needed. indexer_take_in with a repository takes in a head with no module.json as a merge that leaves none, and answers by name for a head with modules.
The forge bridge wrote no merged message for such a merge, so taken.<repo> never moved
and the view held 'the indexer has not yet taken in <head>' (hq #490-#492). The bridge
now writes it with no trees; the indexer drops every module of the repository on it,
after the same order check as any merged message. The view needed no change: with the
taken key moving it reaches the merge, which its new row proves.
Needs mesh-sdk fix/1126-no-module-reach (a merged message may carry no trees).
mesh/check being carried to 34a607a1f5cf on a62276bcafad | from 15d28ddf5bd3
The invoke was left out (mesh-delivery #142) only while the indexer built before the verb ran; the new indexer and the
node-engine's compose-candidate run on every machine since 22:57, so a check composes on the machines again instead of
passing with a warning (ADR 0593 §7, §9).
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The check of 2026-11-02 22:35 on a loaded shanks failed two buildrun tests on wall-clock bounds of 60 ms, the
second failure of this kind tonight (the first: mesh-sdk's busretry tests, f02f142).
Quick fix: give the two buildrun asker tests bounds of seconds.
Thorough fix (chosen, because the kind recurs across every module of the repository): every test that raced a
wall clock now waits on an event, steps a clock it is given, or has a bound only a failing test reaches.
- buildrun asker tests: the steps' own times stand for the clock (bound an hour, starts and phases written in the
past), no goroutine paces phases with sleeps.
- builder: the decline bound reads Builder.Now; the decline test steps it; the stream-wait test waits for five
check reads instead of 100 ms.
- checker: the lost-ask try bounds an untaken ask at 200 ms only where that is what ends it; the program says when a
merge turn changes, and the integration test waits on that line instead of 300 ms.
- teller: the bed makes the teller's own ends bucket (a 10 s stall at start the tests raced by 0.5 s), waits for its
warrant subscription instead of 500 ms pauses, and the package-level now is restored with t.Cleanup.
- watchman: the recount, run in its own goroutine, is waited for instead of 10 ms.
- polls of 2-5 s become 10 s (unit) and 20 s (integration).
Under a throttled cgroup (half a core shared with two busy loops) beside the node-engine's suite, the buildrun
tests failed 5 of 20 runs before and passed 30 of 30 after; no test added.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The running indexer, built before the verb existed, refuses a manifest invoking it, and one refused manifest holds the
grants part's whole list: no new grant is written, so the new indexer never moves (issue 1126, 2026-11-02). Quick fix,
chosen because the thorough one (the grants part keeps only the refused module's grants) cannot be delivered while the
list is held; a follow-up adds the invoke back. Until then a check's compose-candidate call is refused on the bus and the
node is named silent: the check passes with that warning (engines.go, ADR 0593 §9).
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
mesh/check failed: mesh-build-go: the indexer's judge at the group's mesh-delivery head 3b3b096be8cdf8f49246ed3961ece3eb5c349d62 refuses the manifest …
The composer command moved to the node-engine (ADR 0593 §7); a catalogue check had only mesh-sdk beside it. Pin the build runner to the catalogue head whose composer test skips aloud until then.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
mesh/check failed: integration: meshbuildgo/cmd/mesh-build-go.TestAComposeAskIsBuiltOnceAndAnsweredOnTheBus: NOT CHECKED: the node-engine's composer c…
mesh/check failed: integration: meshbuildgo/cmd/mesh-build-go.TestAComposeAskIsBuiltOnceAndAnsweredOnTheBus: NOT CHECKED: the node-engine's composer c…
Review finding 5: the repository's unit tests rose from 810 to 814 (over the 500 budget); eleven test
functions of buildrun become two, so the count is 805.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
Review finding 4: an unreadable placement gave no nodes, so nobody was asked and the check passed. The
placement read now answers its error, and the verdict says the composition was not made and why.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
Review finding 3 (ADR 0593 §9): only a node that does not answer may let a check pass with a warning; a
sandbox composer that cannot be built or run was filed with the silent nodes. It now fails that node's
composition, naming the head.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
Review finding 2 (ADR 0593 §2, §3): after the release no build has reported imports, and a module that
replaces a mesh Go module of its own repository by a directory had no go.sum line and no version for it,
so a change of buildstep or buildrun alone moved no importer. The indexer now reads go.mod's directory
replaces, publishes those modules, and puts their content digest on the version line; builds are pinned
to the other repositories' versions alone.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0593 §7: OffersIssuedOutside, Resolution and UnknownFieldReason left mesh-sdk with the composition,
so the judge's tests keep its own reading and refusals and those proofs go to the node-engine's tests.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0593 §7: the catalogue's composition (Resolution.Compose and Declaration, LeftOut, Resolve,
JudgeSettings, ApplySettings, HeldTemplateProblem) leaves mesh-sdk for the node-engine, so the judge's
tests keep only its verdicts and refusals; each proof that a manifest composes goes to the node-engine's
tests, and the helpers only those proofs used go with them.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The named tree is the indexer's computation (ADR 0593 §2): the builder reads it
from the module's value, so its test gives one as the indexer would write it.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0593 §7: compose and frombus left mesh-sdk for the node-engine, so how a composer holds a refused
module is the engine's to test; the indexer's test keeps proving the verdicts and refusals it writes.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0593 §1: the step runner left mesh-sdk for mesh-build-go's buildstep package, so the examiner's unit
tests and the module's integration test require it by the group's version (as the builder does) rather
than an imitation of its plan and kept-verdict rules.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0593 §7, §9: the checker asks compose-candidate of each placed node in parallel within its own setting
compose-answer-bound (60 s); a refusal fails the check naming node and module, a silent, unready or
unreachable node passes with "not composed on that node: no answer". A group with a node-engine member is
composed by the composer at that head on the Go build seat over each node's input. The wait on the
assigner's compositions goes, and the checker invokes the one engine verb it needs.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0593 §2: only the indexer computes a package's version; the checker follows its packages state and
hands those commits to a Go check, so LatestPackages leaves repoModules and mesh-sdk's
PackageVersionsOf has no reader here.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0593 §7, §8: the check's composition, its compose asks to the Go build seat and the state
compositions go (the checker asks the engines); a proposal is judged without frombus; mesh-wants.upgrade
compare reads every node's composed-<node> through mesh-host.composed. The assigner no longer imports
compose, composer, frombus or buildrun.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0593 §1, §8: compose/judge moves back from mesh-sdk; every node answers a proposal, what a placement
changes is read from its entries, and a node silent past the answer bound (60 s) is named and the
proposal decided on the answers it has.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0593 §7: compose-candidate's read of one key times out without the consumer grants, so both buckets
are granted as the builder's builds are; the node grant now equals mesh-host's golden node.json.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
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
ADR 0593 §6: a bundle such as the provisioner reads mesh-host.composed on the runtime's connection, so the
runtime account gets the stream listing and the creation advisory beside the read of each bucket.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
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
ADR 0593 §11: the controller's repository holds nothing that builds once route-proxy moves, so its
sibling rule goes; its tests fold into the sibling test, which now uses mesh-sdk's rule.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
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
Review of 650a1d0: a member that only failed its tests got no preview, so the indexer held no manifest
of it, the assigner's composition only said it waits, and the check waited for ever. The preview is now
written whenever every build module's fetch merged; a member with no preview of a merge (a conflict, a
fetch that did not answer) makes the composition not run, said with the members it names, unawaited.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The operator, 2026-11-02: "A failed check shows only its first fault". Group feat/1126-removal's
check failed four times, each verdict naming one fault, so three faults took three runs of 20-40 minutes.
The checker no longer returns at a member's first failure: every member is asked, every level's
failures and every member's refused step or conflict are joined in judging order, the manifests are
judged and the composition is read also when the tests failed, and a failed composition is added after
them. The status line says how many failed and names the first, cut so "; and N more" stays whole.
checker_verdicts and checker_pull answer the whole list (failed). Needs mesh-sdk's buildstep change
(every level runs after a failure) pinned at the group's head.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
mesh-delivery is over its budget (810 unit, 73 integration on main), so this
branch adds none net: its new cases are subtests, the three work-queue process
tests and the consumes test become one, the history stream bounds join the
stream values table, and the go/-only mesh-sdk merge check joins the one new
integration test. buildrun's 20 unit and 1 integration tests moved in from
mesh-sdk with it.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
A module's fingerprint takes the digests of the packages its last build
imported, so the published packages say why a merge moved a module or not;
the state needs a read tool like every other (ADR 0593 §2; D2).
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The indexer whole: two catalogue modules report their imports at their builds'
end, mesh-sdk merges a change of buildstep alone, the packages key names the
merge with a digest per package, the buildstep importer moves and the other
keeps its fingerprint though the version line would have moved it (ADR 0593
§2-§4; D11).
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The indexer's judge takes a module's own object bucket (a plain local name,
once, no name its states take, none of the mesh's derived prefixes, 1 to 8192
MiB with no default, a grant only by a trusted value) and a stream that keeps
its history (no max age, deliveries or duplicates), counts such a stream among
the bus's predefined forms, gives a bucket's name one owner on the bus, and
refuses a read of a bucket its owner grants nobody. The seat table expects
the node-engine's compose-candidate verb (ADR 0593 §7; D5).
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The pulling code leaves mesh-sdk for mesh-build-go's own package (ADR 0593 §1),
so the bed imports it by its published version and tests the builder against
the real runner, not an imitation. The required version is a placeholder at
mesh-catalog 9c57f7af: the group pins the catalogue's head before its push.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The build runner leaves mesh-sdk for mesh-build-go (ADR 0593 §1), another
repository the builder does not import; the tests answer asks as the builder
needs them answered.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
buildrun leaves mesh-sdk for the builder's own Go module (ADR 0593 §1); the
checker, assigner, indexer and watchman require it by a replace to the sibling
directory. Issue 1930's bound was already on mesh-sdk's main and moves with it.
The builder copies the imports a build module answers to the done key and the
log's end entry, where the indexer keeps them (§2; D7).
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
Only the indexer computes what a fingerprint takes (ADR 0593 §2): the merged and
pull messages carry no Packages, and the kept inputs no longer hold them (D6).
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The fingerprint, named tree and package versions move from mesh-sdk into the
indexer's internal/fingerprint (ADR 0593 §2). The indexer publishes each reached
mesh Go module's package digests from the forge's listing in its new packages
state, keeps the imports a done build reports, and writes the import form only
when an input differs from the build that reported them (§4), so the form change
costs no rebuild and a package merge moves only its importers (§3). Candidates
take the same form against the group's member heads (D1-D4).
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
mesh/check being carried to d26781b403df on 4dd7dcfc1411 | from be88162cde31
A group's check judges each member against the group's heads (ADR 0482 §2,
ADR 0573 §4), but the checker placed mesh-catalog at its trunk beside every
other member even when the group held a catalogue pull request, so
mesh-delivery's judge tests in group feat/1126-removal judged the new judge
against catalogue main and failed. The catalogue now follows the rule of
every other sibling: the member's head and ref in a group, the trunk alone.
A catalogue change's own trunk copy (ADR 0529 §2) is placed separately and
is unchanged.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
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
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
mesh-sdk now says what upgrade's compare answers without the controller:
each node's own composition and the assigner's findings. The judge keeps
a copy of the seat, which must read the same.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
route-proxy leaves the controller's repository, which is archived, and nothing registered a move since the controller
went: the indexer left a module named by another repository's merge as it was, forever. Now that merge waits, and the
holding repository's merge that drops the module hands it over in place, so its key never goes missing between the two;
merged the other way round, the key is deleted and written new. A trunk that still holds the module keeps it (ADR 0420
clause 7, ADR 0501 clause 3).
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The watchman held a node a control node, urgent after half an hour
silent, while its have named mesh-controller; the controller ended by
its unassignment (ADR 0590), so no node was one any more and the bus
node's silence stayed a warning. The control node is now the node whose
have holds the bus module, nats, which the watchman already hears by
that name.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
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
ADR 0590 clause 3 ends the choice of a condition source by the keeper's
take-over key, which mesh-sdk no longer defines. The assigner watched
that key and said every condition straight to the router while it named
the controller. It now writes each as a finding the keeper carries, and
says one straight only where it has no findings bucket at all.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0590 supersedes the lease write: mesh-grants says no lease event any
more, so the watchman's lease-altered and removal-failed findings and
their row had nothing to hear. The ended controller's consumers are
removed as hand acts, so their deletion is no consumer lost; only the
one on DEAD_LETTER_NOTICES is still read, since its removal hands the
notices to the watchman. The builder hears artifacts-gone from the
artifact sweep seat alone, and mesh-enrolment's tokens no longer report
an issuing gate that nothing can turn off.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The controller ended by its unassignment (ADR 0590) and mesh-sdk drops
its seat, the grants seat and placement's adopt and hand-back. The
indexer's judge still carried the controller's seat entry, the old
removal words and the two placement verbs, and counted 58 seats; the
checker still placed mesh-controller beside the node-engine's and the
catalogue's tests and failed a node-engine check without its trunk; the
assigner still asked a compose of the running controller, served adopt
and hand-back as stubs, and kept a policy-split finding that could no
longer arise.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
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
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
mesh/check being carried to a192052d82fe on be88162cde31 | from 0490043990e2
The grants part, the enrolment seat and the watchman now act without
reading the lease, so a controller placed again would write beside them
with nothing saying so. The assigner refuses every proposal, seed or
joining node's write that would place mesh-controller, naming why.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The controller ended by its unassignment, so its lease key is absent for
good and mesh-sdk reads that as not handed away: mesh-enrolment's issue
stayed off and the watchman never took DEAD_LETTER_NOTICES, whose notices
age out after a week. Both now act without reading the lease; the
watchman still waits, and says so, while the controller's consumer on the
notices stands. Neither manifest reads the lease any more.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
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
mesh/check being carried to 8f87dbe94d76 on cc9c681fa348 | from f1c33439292d
The teller read the router's record from KV_asks, a bucket no composed grant
names, so every read was denied and its operator answers could not be read
back. It now reads messenger_asks, as mesh-grants does. The integration bed
grants the real subject and reads a record on the teller's credential, so it
no longer agrees with the mistake. (issue 774)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The lease write addressed node-service-manager at the lease holder's host, a
hostname no node carries ("novox-be" on novox), so the operator's yes timed out
at its first step and failed without a log line. The node now comes from
placement (exactly one node placing mesh-controller, else refused by name), a
failed act is logged beside its condition, and the asks record is read from
messenger_asks, the bucket the composed grant names, instead of asks, which no
grant allows. The fixtures give the lease a host unlike the node, so the tests
no longer agree with the mistake. (issue 774)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
mesh/check failed (2 tests): integration: mesh-mail-reader/cmd/mesh-mail-reader.TestAcceptanceOneMatteringMailSendsExactlyOneTellNamingIt: timed out w…
The judge refused nats's manifest for its invokes (seat:mesh-hand-acts.hand-act,
which nats_bucket_expiry asks to record its hand act), and with one manifest
refused the grants part holds the whole bus user list, freezing every build
that adds bus permissions. The bundle asks through the node's tool runner,
which buscompose grants every tool and seat verb, so the invokes are granted:
the same condition that already lets the bundle declare emits (ADR 0357).
ADR 0235's rule stands for a bus module with no bundle.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The enrolment's issue waits for the lease write itself (ADR 0587 §4); the assigner takes an add-node on its warrant at any time (ADR 0567 §8). (issue 774)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0589 version 29, clause 6. At start and after a catch-up an address key is an expiry never heard only when its
enrolment key is gone and the router records its ask answered yes; one declined or not answered yet is no expiry, and one
not answered stays until its ask ends. A confirm, a decline and a refused add delete the address key before their other
steps, so one stopped midway never leaves a key the catch-up would take for an expiry and unplace a node that joined. A
refused add (mesh-placement's refusal of the proposal, not a call that did not reach it) now ends the enrolment as refused;
a call that failed still waits for again. Tests: rows in the end table (after a confirm stopped before its enrolment key
went, after a decline, after a refused add, a declined ask, an ask not answered: nothing unplaced) and the integration test's
holder-was-down case reading the yes; no new function.
(issue 774)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0589 clause 6: a placed but unconfirmed node is always taken out again, on the warrant of its ask. The address key now
names the ask and the issue's time (delivery.EnrolmentAddress, mesh-sdk c7130e3), written just before the ask is raised and
with no expiry of its own, so it outlives the enrolment key; the holder deletes it at every end. An expiry, seen or not, ends
the enrolment in this order, each step safe to repeat: remove-node on the ask's warrant (only when placement holds the
node), enrolment-expired naming the rebuilt issued event (delivery.EnrolmentIssuedID), the vault's drop of the token, and
the address key last. Reconcile finds every address key that names an ask and whose enrolment key is gone (expired while
the holder was down, before its watch caught up, or an end that stopped) and ends it; it runs once the watch has caught up,
on every expiry, and again with a growing wait while a step fails. An address reserved by an issue under way (no ask yet) is
left alone. Tests: rows in the end table (expired unseen; the holder down with a drop that fails once; a reservation under
way) and the integration test's expiry case (the address key goes; a holder that was down unplaces on its pass); no new
function.
(issue 774)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
mesh-sdk 22c03af carries the machine's tunnel key on the enrolment (OverlayKey, overlay-key, required at every stage), so the
holder's wrapper that kept it beside the contract is gone; the wire is unchanged. Test fixtures give the seeded enrolments a
real tunnel key, which the contract now requires.
(issue 774)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
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
The operator's decision of 2026-11-02 01:05, on mesh-sdk 4224665:
- issue takes overlay_key, the machine's tunnel public key as `nox-mesh-host key` prints it, and refuses a missing one. The
token's first tunnel is whole: key, address, range (the hub's tunnel range in placement, the one the controller's token
carries today; a hub with none is a finding, never a guess), hub key and hub endpoint.
- On the operator's yes the node is proposed into placement at once (add-node with its tunnel key alone, on the warrant), and
only then is the token made, so the hub peers it before redeem. Redeem writes no placement: it refuses a tunnel key other
than the one issued for, or a node placement does not hold yet, and the certificate's call carries all four keys presented.
- A revoke, a refusal or an expiry before confirm takes the node off placement (remove-node, same warrant) before the end is
said, and the end brings the token's drop.
- The assigner applies a remove-node: the node's key deleted at once, with no ask, placement-changed carrying the warrant.
- The tunnel key is kept as one more member of the node key's JSON, beside delivery.Enrolment, until the contract carries it.
Tests: rows in the existing tables and both integration tests (the token's Missing() is empty; the node is placed before
redeem and leaves placement when its enrolment expires); no function added, mesh-delivery stays at 816.
(issue 774)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
- redeem writes the node into placement before it asks the vault for the account and the certificate of the serving key
presented (the vault reads the node's address from placement); a retry by the same keys still finishes (blocker 3).
- loadedVia reads mesh-grants.user-list's pass as the part's whole Result, the list state under user_list; the fixture
testdata/grants-pass.json was written by mesh-grants' own Result, not by hand (blocker 4).
- enrolment-expired is delivery.EnrolmentExpiry with IssuedID, through its codec; a key that expired before its content was
seen names no issued event, so nothing is said and its token is dropped at once (blocker 6).
- issue builds the joining node's first tunnel from placement (the hub, its endpoint, the node's address) and the hub's
record (its tunnel key) and passes it to enrolment-token; no hub, or a hub with no key or endpoint, is a finding of issue
(ADR 0587 §3, insight of 2026-11-02).
- The assigner takes an add-node only from mesh-enrolment's own bus user (stdio.Callers), never person.mesh-enrolment.
- The watchman raises machine.<node>.node-account-fallback from a node's health report's fall back and clears it when the
report no longer carries one (ADR 0583 §6, blocker 7).
- mesh-enrolment's ten unit test functions are two table tests now (blocker 8): the repository is back at 816.
(issue 774)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The holder's code over a real nats-server bucket with a time to live per key: issue, the operator's yes, redeem as enrol.ace,
the node confirming as the login its key of node-logins names (the stand-in vault writes it at node-account), node-enrolled
and placement-changed said on their subjects, the user enrol.ace composed while the key is live and gone with it, the token
dropped only after the end; and a token never redeemed expires on the bus, is heard, says enrolment-expired and is dropped.
Found by it: a bucket with a time to live per key must keep one revision per key, or the bus expires nothing (nats-server
2.11.17), so the state enrolments declares no history. Paid for: the integration test is paid by merging the builder's
archive-only and root-module integration tests into one table test; the module's ten unit tests by merging the assigner's
three small composition tests into one table (net 2 of 10 paid; the rest is for the lead, the repository being over budget).
(issue 774, 774/S60)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
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
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
propose takes the enrolment's warrant {node, address, ask, warrant} and refuses an add-node from any caller but
mesh-enrolment, with no warrant or with a warrant naming another node or address (delivery.AddNodeRefusal); the joining node
counts as having a record for this one change, as ADR 0587 §7 changes ADR 0567 §2. The assigner's process then writes
placement.<node> at once, with no node to answer and no ask raised, and says placement-changed carrying the enrolment's
warrant; the hand-act record of that warrant is the enrolment's, made when it was given. The holder of mesh-enrolment calls
propose with the change, the keys and the warrant read from the router's record of the ask. Tests: rows appended to the
seat's verbs test and a case to the whole-seat integration test; none added, so none to pay for (the budget is paid in
774/S60).
(issue 774, 774/S59)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The seat, the enrolment state, redeem and its proof, the answer the vault signs, and the vault's two verbs' answers are now
mesh-sdk's (catalogue and delivery), which the vault, the grants part and the engine read too; the proof is the contract's
RedeemProof, the answer carries the login, account, certificate and the vault's signing key (read from its state signers),
and the bucket's values are written through the contract's codecs. The expiry event names the issued event by message id as
well as by the sequence, which a bundle cannot learn. The module builds against the group's mesh-sdk head through a go.work
outside the tree; the lead re-pins go.mod before the push. Tests merged into the same functions; none added.
(issue 774, 774/S54-S58)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
revoke ends an enrolment at any stage without an Approve and records it as an act done by hand (the vault retires an
account minted for a redeem under way); the bus's expiry marker of a key at live says enrolment-expired with the issued
event; the durable consumer of the seat's own ending events asks the vault to drop the token and its hash, acknowledging
only once the vault answers, never before an end. No event or key holds a token (ADR 0587 §5, §8). Run starts the watch,
the consumer and the operator's answers. Tests added: two table-style tests.
(issue 774, 774/S58)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
Only the node dialled as node.<node> confirms (the runtime's proof of the caller is the confirmation, ADR 0587 §6); the
holder then says node-enrolled with the key's content and deletes the address key (while it still names the node) and the
node's key. A stop between the event and the deletes is finished by calling confirm again; the event keeps one message.
release now answers what it could not delete. Tests added: one table-style test.
(issue 774, 774/S57)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
redeem answers only enrol.<node> as the runtime proves it, checks the proof against the identity key presented, spends the
token once by compare-and-set (the keys lose their expiry), asks the vault for the node's account and certificate, writes
the node into placement on the issue's warrant, answers once the bus node loaded node.<node>, signed by the vault; the
same keys called again finish what is not done and answer the same (ADR 0587 §5-§7). The proof is mesh-host's EnrolProof
with the node's name in the token's place, since the seat never holds the secret. Tests added: two table-style tests.
(issue 774, 774/S56)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
issue refuses at once naming every finding (a bad name, a name a node record, a placement key or an open enrolment
holds, an expiry past a day, any call before the lease write), reserves the lowest free address by creating its key,
writes the enrolment at asked and asks the operator (ADR 0587 §4). On the yes the warrant is recorded, the vault
makes the token and both keys go live with the bus's expiry; a no or an expired ask takes both keys and says
enrolment-refused. Tests added: three table-style tests; none deleted here (paid with 774/S59's merges).
(issue 774, 774/S55)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The holder of the seat mesh-enrolment (ADR 0587 §1, §2, §8) runs as a bundle on its own account, keeps the bucket
enrolments with a time to live per key, and answers tokens: every open enrolment or one node's with stage, expiry,
ask and revision, the bucket's fill, whether issuing is on and why, and for one node at live the token sealed by
the vault and relayed, kept nowhere. Tests added: two (one table-style test of tokens, the manifest test); the
repository is over its budget, paid by merging tests in the assigner's seat tests in 774/S59's commit.
(issue 774, 774/S54)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
mesh/check failed: mesh-build-go: the check of novox/mesh-catalog#590: the ask mvyhumdm860c7f's step on shanks did not end within 30m0s of its start |…
ADR 0582 "How it is checked": against an embedded bus, a stand-in controller holds the lease in a bucket with an
expiry (2 s standing in for 15 s, through grants.LeaseExpiry, so the wait past it is seconds), with stand-in
node-service-manager and bus-tool seats (the expiry tool acting on the real bucket's stream, as nats-tools'
SetBucketExpiry does). On the warrant the key holder names mesh-grants, the expiry is gone, the controller's
create of the key is refused, and the lease still reads handed away past the old expiry; on the hand-back's
warrant the expiry is back and the controller takes the lease again. mesh-grants requires nats-server for it,
at mesh-sdk's version.
Budget: TestTheLeaseWriteOnTheBus (new, integration) is paid by merging the checker's
TestTheCheckerAwaitsTheAssignersComposition into TestTheCheckersLineSaysTheAssignersComposition as its first case.
(issue 774, 774/S23)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0582 clauses 4 and 6: mesh-grants says lease-altered and removal-failed "as a finding the watchman raises".
The watchman hears the seat mesh-grants' three events on core subjects (mesh-sdk WatchmanHears, its grant and
its subscriptions from one list, rather than a consume and a durable consumer), raises lease-altered naming
what changed and clears it at the next lease-handed, and raises removal-failed naming what failed and clears it
once what it names reads gone: the controller's consumer of DEAD_LETTER_NOTICES by its deletion advisory
(heard already), the stream ASSIGNMENTS by its own. The finding DEAD_LETTER_NOTICES.controller stays as it is.
Test: a row in TestTheWatchmansFindings; no new function.
(issue 774, 774/S22)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
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
ADR 0571 §13: the judge moved to mesh-sdk (catalogue.Dependencies, Judge, KeepList; issue 774, 774/S4) so the
manifest tests of three repositories and grants_lease_check give one judgement; mesh-grants re-exports it by
its names. The keep list there holds the three kept to the write alone (774/S30), superseding the keep of
pacman's read at 4a84370. grants_lease_check no longer counts the controller's standing assignments, which
nothing reads any more.
Tests: TestTheLeaseCheckJudgesEveryDependencyOnTheController keeps the tool's own rows (what it read, the
lease, the streams); its dependency rows moved to mesh-sdk's TestTheLeaseWritesCheckJudgesEveryDependencyOnTheController
(774/S24's replacement of the moved rows), and TestTheKeepListNamesItsRecordsAndThreeToTheWrite went with them.
(issue 774, 774/S30, 774/S24)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
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
The integration tests put placement (not assignments) and the node's own composition (not the controller's) on the bus; the
three that tested the controller's judgements of a move (waiting for a composition, a record move, a user-list revision) go,
their unit counterparts standing. Run locally against the embedded bus, all of this module's integration tests pass.
Found by them: the answer to a failed backup was dropped from a placed node's want at every pass, because the carry-over
compared the want's digest, which a placed node's want does not carry; fixed in wants.go, with a case in the existing unit test.
Tests: three integration tests deleted, none added; one case added to an existing unit test.
(issue 774, 774/S26, 774/S27)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The controller's placement-export is no longer called, its answer reader, the seed and the hand-back flow of the holder are
removed, and a seed or hand-back proposal a previous process left open ends at its next pass.
Tests: the adopt, hand-back and seed cases of the seat's verb test and of Propose are replaced by one gone-case; the export
reader's table and the seed test go.
(issue 774, 774/S28)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
mesh-controller.composed leaves the reads and the watches; upgrade compare lists the node composition digests of the haves
instead of comparing with the controller's policies, which the controller no longer writes.
(issue 774, 774/S27)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
Every handed-away branch is the only one: world.assigned is the placement, the pair comparison and its conditions go, the
lease and assignments buckets are no longer opened, watched or declared, and a proposal of any kind is taken.
Tests: the pair-comparison test and the controller-composition record-ask test are replaced by one placement test; the
rest are edited to place their modules instead of assigning them.
(issue 774, 774/S26)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
Drops callAll, the refused-call conditions and the pin reads; the conditions a previous process raised are cleared once.
Tests: deletes four (the refused-call condition, its clearing, the contract of the calls, the condition's shape) and adds one.
(issue 774, 774/S25)
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
pacman still falls back to the controller's declared-packages for a node whose engine has
not written its own packages (ADR 0565 §6), so the check named that read as ended and would
refuse the lease write. It is now a kept read, dropped with the others at the write's own
delivery (issue 774, design 47 L3).
Quick fix chosen over removing pacman's fallback: it matches the record as it stands, and
the read goes with the other kept reads at the write's delivery.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
mesh/check checking b18c62f671e1 on cc38ca3f8dc8 | novox/mesh-delivery#132 in group feat/node-packages
The node seat's verb packages compares the engine's key with the controller's mirror until the lease write; the grants part composes the engine's read of its own node's mirror key only from this mesh-sdk.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
mesh/check pass d739516056dd on 55a506975b01 | unit 7056 run, 243 kept, 16 skipped | integration 7194 run, 275 kept, 25 skipped | over bound: unit, in…
A check ask named no toolchain, so a node on the minority version could run it and KeepPasses record the pass as run on the agreed one. The check ask now carries the agreed toolchain and a node off it declines (mesh-sdk), for the checker's decline loop to put again. Pins the builder, indexer and checker.
Known limit: the checker puts a declined check ask again at once, with no pause; the declining puller skips that kind until its next pull wait, which paces a lone minority node.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
A build node off the agreed toolchain declines the ask and, idle, takes the ask put again at once, so three declines used the three askings and failed the build. A decline now uses no asking: the ask is put again after a short pause, and past a bound from the first decline the key fails naming the declining nodes and their reasons. A person reads which node sits out in the key's step text, which the view's builder_builds answers as stored.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
One build node on another version refused every build of the language. The builder and the checker now follow mesh-sdk's majority agreement; the key's step names a node that sits out ("ace sits out: typescript 26.12.1, agreed 26.13.0"), and a build ask a minority node declined is put again for a node on the agreed version. Check steps compare no toolchain, so clause 2 already holds for them. Pins builder, indexer and checker to mesh-sdk 71be15f.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
mesh/delivery-group group feat/l5-l7-main rejected: composed together: the checker's verdict at the members' heads (e32e2c9c4fea): integration: mesh-delivery-b…
One helper serves every part that reads whole states (ADR 0580 clause 3): the assigner's own watched mirror goes, its
compare reads the large states from stdio.WatchedStates and each manifest once per digest. mesh-sdk pinned at 8311ecb.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
mesh/check checking 8e9cc5830119 on b1f262d7d06e | novox/mesh-delivery#129 in group feat/judge-once
Review of fb96216: a missing mesh-sdk or catalogue in a merge check is the checker's fault and fails, never judged
against a stale copy. The captured placement guard is refreshed to mesh-host's main 233bb23.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The judge's tests moved from mesh-sdk, where mesh-host was beside them; the checker places only mesh-sdk and the
catalogue beside mesh-delivery (besideRules), so the node-engine's path rules failed as not beside. A sibling the run
holds beside is read there; one it does not is read from testdata/beside and the log says which; only a sibling
with neither fails.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
mesh/delivery-group group feat/judge-once rejected: composed together: the checker's verdict at the members' heads (253f35815198): unit: mesh-delivery-indexer/…
mesh/check failed: unit: mesh-delivery-indexer/judge.TestTheResolvedPathRulesAreTheNodeEnginesOwn: mesh-host is not beside this check in MESH_CHECK_BE…
Issue 1585: the bridge names the mesh packages each module's go.sum names (builder-1585b's fold); its integration test
still wanted none. All nine modules' integration suites pass locally (the lead allowed a whole local run this round).
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
mesh/check checking edf7b3c0bf3a on b1f262d7d06e | novox/mesh-delivery#129 in group feat/judge-once
Issue 1585, R1: fresh holds the digests a take-in newly wrote (a new module, a changed manifest); a registered or
taken-in module is judged too; a start pass that fails is judged again at the next message heard, no timer.
R2: a module's verdict, problems and warnings are carried while its digest stands and are no part of the compare.
R3: the checker judges the trunk beside the change and fails on every problem the change case adds, an untouched
manifest's included. R4: the judge reads the indexer's kept predefined keys, or the catalogue member's when it
changes them. A log line names a package no held module publishes. Every module pins mesh-sdk 62cddf4.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
Issue 1585: the indexer keeps an accepted manifest accepted when a stricter judge re-judges it, its problems as
warnings carried in its value; a merge's new manifests are judged in full. The watchman raises manifest-outgrown as
a warning until mended. The checker fails only on a manifest the change adds or changes and names the rest as
warnings. Every module pins mesh-sdk 19c2042.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
The checker builds every Go check against them (issue 1585, S14); a row
in the repoModules test proves they come from the modules that hold each
package and leave out a package no module holds.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0573 §4 makes refusing a member for its mesh-sdk pin a fault of the
check (issue 1585, S14). Every Go check ask now carries the latest
published version of each package, or the head of the group member that
publishes it, so the pin check, its forge reads and its tests go, and
the controller's tests read mesh-sdk at the version it is built with.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
ADR 0573 §2: a module builds against the latest published version of
each mesh package it uses, and a package's trunk merge moves every
dependent (issue 1585, S13). The bridge reads the packages each go.sum
names, the indexer keeps them and takes each one's trunk merge into the
fingerprint, a candidate takes a group member's head instead, and the
builder's ask carries the versions so the build module writes them.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
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
Issue 1585, S5-S8: the indexer's fingerprint reads go through judge.ForInputs, so judge/ is the one place in
mesh-delivery that calls mesh-sdk's rules; the command's request judging moves into judge.Request, tested in the
judge's table; two predefined tests become one.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
Issue 1585: the indexer's merge test takes in three manifests more against the real bus; it writes their
verdicts, says each refusal, and mesh-sdk's bus reader composes the valid one and holds the refused, named; before
any verdict it takes each as accepted and names the field set aside. One test extended, no test added.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
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
Issue 1585, S11: world and wants read with catalogue.Decode; a trunk refusal is held, named and handed to the
composer in its input; a proposal's composition read that fails is said, not dropped; a reader that cannot read a
changed field is a warning, no longer a failure.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
Issue 1585, S10: the watchman watches the indexer's modules and finds manifest-refused for a module whose value
carries a refusal, ending it once accepted. Its mesh-sdk pin moves to the group head, so it takes health.Finding's
Ref (issue 1952 renamed Token).
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
Issue 1585, S9: verdicts keyed by digest, written only when they differ; a module's value carries a refusal; a
new refusal is said as manifest-refused. Judged at start (a new judge judges again) and after every merge.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
Issue 1585, S5: judge.Shelf judges each manifest alone and the rules between them, giving a problem between
manifests to each module whose removal ends it (naming alone blamed the module mounts for f1-circuits' problem).
cmd/mesh-judge answers a composer request so a Go build module runs it as it runs the composer.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
mesh/check pass ddadb75bf474 on 91128d4f0af6 | unit 4510 run, 4259 kept, 49 skipped | integration 4589 run, 4361 kept, 51 skipped | over bound: unit, …
The only change taken in is ADR 0577's: each node's engine writes its own keys of mesh-host_data,
and each node's disk-load reads its own node's keys alone. Without it the engine's writes are
refused and disk-load measures nothing.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
At a restart a standing finding is observed again by the replayed failed have: kept, not confirmed again, and its urgent
signal runs on from the finding's Since; an urgent one stays urgent with no signal restarted.
Quick: skip the confirm when a finding stands. Thorough, chosen: the same, plus urgency read from the finding itself.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
A have that turned failed once and stayed unchanged was written once, so the old count of two writes never fired and the
finding was never written (fail2ban on novox). Confirm by time, with a signal, also at a restart.
Quick: raise the count to one write (loses the confirmation). Thorough, chosen: confirm by a time bound, as ADR 0564 s4's
signals are keys that expire, so no write count is needed.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
mesh/check pass a2558171e11e on f83835b4b6ad | unit 2729 run, 4570 kept, 16 skipped | integration 2975 run, 4493 kept, 25 skipped | over bound: unit, …
The grants part composes every membership and runtime grant from
mesh-sdk, which now lists a held seat's events for its holder, so the
self-check the tool runner carries can say `checked`. Pinned to that
mesh-sdk head.
Quick vs thorough: quick, these fixes for L4's take-over now; the
thorough fix (research 032 / ADR 0240's health view extension) is
decided later.
Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
mesh/check failed: shanks: the check of novox/mesh-controller#487 failed: go mod download in modules/route-proxy: go: git.novox.be/novox/mesh-controll…
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.
mesh/check checking 17abe6af32ce on af0fd83aec09 | novox/mesh-delivery#124 in group fix/merge-ask-ends-on-merge
On 2026-10-31 two merge asks of pull requests merged by another path held two of
the router's three places for the teller and a placement ask was refused for want
of room. The gate's fix ends such asks by itself; this tool is the recovery for any
ask that still outlives its question: it cancels the open ask at the router, or
drops one waiting for room, by its router id or its key, and logs who and why. The
tools bundle asks through the teller's new state ends, as indexer_take_in does.
mesh/check checking 14f68219cf29 on 804d5cc06559 | novox/mesh-delivery#123 in group fix/engine-seat-any-verb
The grants part pinned eff81f1, before the verb composition (6bce1fb): the bus refused every engine's subscription to it and each engine reopened its link every few minutes. With 748543c a verb added to the node-engine seat needs no grants release first. Group with mesh-sdk fix/engine-seat-any-verb.
On novox the asks of postgres, keycloak and mongodb were judged stale against the controller's compositions, taken away and made again under a new id every pass (8 s), so no answer could count; and every put is a change the node composes again on.
Quick fix: the stale check keeps a record ask whose digest the node's have waits on; the pass skips a put whose value the bucket holds.
Thorough fix beside it (not here, another branch owns the file): the node-engine's composer composes again only when a want's value changed.
mesh/check being carried to 2dd5239726ca on e559798972b4 | from d409bdf20f48
Review of 09791f5: with the indexer's modules bucket readable but empty, nothing was read, so
nothing was found and both phases passed; the operator could have handed the lease away while an
unkept read still stood. Judge now refuses when no manifest was read, or fewer of the indexer's
modules than it holds (a provided manifest does not count for a missing one), saying why; a
missing or refused manifest is named as before, now under test.
The controller's grants leave the keep list: ADR 0571 §9 has no manifest read them from L7's
delivery, changing ADR 0567 §10 and ADR 0547 §5's shadow compare, so the assigner's and the grants
part's reads are refused, and a refusal names the record that ended a declaration where one does.
Quick fix: the counts in the grants part's Judge, as here. Thorough fix: the same coverage rule
in the shared mesh-sdk derivation once the keep list moves there; the quick one stands until then.
The operator asked to remove the controller by finishing its hand-over; no tool said who holds
the lease, which manifests still read, invoke or consume mesh-controller, or whether the lease
write's check (ADR 0571 §13) would pass. grants_lease_check answers all three from bus state on
the grants part, which already reads the lease, every manifest at the indexer's trunk and the
bus's streams: the holder and what follows from it, every dependency with the record on the
named keep list that keeps it, the controller's streams and buckets someone consumes, and the
check run dry at the write (the three kept to it alone) and before its delivery, with reasons.
Quick fix: the judgement and the keep list in the grants part, as here.
Thorough fix: the keep list and the dependency derivation in mesh-sdk, shared by this tool and
the §13 manifest tests in mesh-catalog, mesh-delivery and mesh-tools. Chosen quick: the tests do
not exist yet and an sdk move needs a group; the move is named for the lead.
Rule 8 asked a key for every `requires`, and the plans key only a handed module's needs and what a helper answers:
grafana waited on ace for oidc-client, which the controller still makes, and mesh-build-go for go-toolchain on its own
machine, for ever. MissingProvisions now takes catalogue.Awaited, the one rule the plan composition and mesh-provisioner
key by, judged against the providers placed somewhere.
Quick fix: drop the missing-key check. Thorough fix (chosen): the shared rule in mesh-sdk, so the three parts cannot
drift again. Needs mesh-sdk at 30098229b831.
mesh/check checking 8fe6442c4754 on c104e7500d21 | novox/mesh-delivery#118 in group fix/held-module-and-assigner-contract
A pin made by hand, as the condition's Needs asks, changed nothing the assigner looked at, so its urgent condition
never cleared, and a restart left every one raised. The assigner now reads the controller's pins (placement-export,
asked again only after the controller's compositions change, never on a timer) and clears a pin's condition once
they agree with the placement's after being seen differing, as a module's place already did. The first pass takes
over the call conditions a previous process raised, pins and places alike, and retries at the next pass when the
findings cannot be read.
The assigner added "why" to every assign, unassign, pin and unpin since 2026-10-28; the controller's seat contract
takes no such argument, so it refused each one and did nothing. No approved placement reached the controller's
assignments, no bus account was minted for a newly placed module, and the refusal was only a journal line.
Quick fix: drop "why" from ControllerCalls. Thorough fix: a contract test that every argument ControllerCalls gives,
for every verb, is declared (and every required one given) in catalogue.ControllerVerbs, plus an urgent condition per
pair whose call was refused (verb, node, module, the controller's words), cleared when a later call is answered or the
two sources agree. Chosen: both here; a caller-side check of arguments against the seat's contract for every seat
call belongs in mesh-sdk and is noted for the lead. The warrant stays in the assigner's own record (placement-changed,
the hand-act log).
Every module pins mesh-sdk eff81f1220e2 (in review).
A key that ages out of its bucket (the build seats' asks pass the stream's 168 h) leaves no marker a watch hears,
and one deleted while the watchman was down is not heard either: its stuck key stood unmoved for ever, and 26
stuck-key conditions of asks from 2026-10-21 were open on 10-30.
Quick fix: mark stuck keys older than the stream's maximum age moved.
Thorough fix, chosen because it covers every bucket the watchman mirrors and any way a key goes: at the start's
end, a stuck key not moved whose bucket was read whole at this start (each build seat's steps, the assigner's
wants) and whose key was not read standing is written moved, which clears its finding, and the closing is said
in the log. A bucket that could not be read closes nothing. A key that ages out while the watchman runs is
closed at its next start: a KV age-out emits no event, and no timer is added.
The grants part repeated the composer's entry lines to keep a refused principal's grants of the list in force;
mesh-sdk 61b67d6 exports them as buscompose.AccountsEntry, so the copy goes. The byte-for-byte test of the kept
entry still passes. Needs the mesh-sdk pin at 61b67d6 or later.
The forge carries the operator's own repositories (jschoubben/hal, jschoubben/novadock) beside the mesh's; the
indexer writes their pull requests as candidates, the gate never names their trunk, so the checker said each
"cannot be judged" and owed the status error on mesh/check, which the forge module wrote into repositories the
mesh's forge account may not write: 403, 119 times each (sweep 2026-10-30 item 7).
Quick fix: name the two repositories as not the mesh's in the checker.
Thorough fix, chosen because any repository on the forge can meet it: a candidate every pull request of which is
of a repository the gate's source.main names no trunk of and touches no module is outside the mesh. The checker
writes it no verdict and owes it no status, takes away a status owed before, says it once in the log, and lists it
in checker_status as outside_the_mesh. A new mesh repository's first pull request adds a module, so it is still
said untrunked and owed error (issue 1422). Nothing is outside before the gate's source is read.
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).
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.
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.
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_*.
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.
S1 is urgent after half an hour for a control node (the node running mesh-controller). S9 also hears the bus module's
slow consumers and closed connections, each closure counted once. S21 is one finding per heard machine from its failed
haves and its provisioner clients' reports (PROV_APPLIED). DEAD_LETTERS is counted again at a letter's age and every
five minutes while letters are held, on the watchman's own pulse. needs-operator waits for L6: its inputs are not on the
bus. Pins mesh-sdk b6ef01d.
The signals rows S1, S8, S9, S10, S11, S21 and the haves' unhealthy and needs-operator are pulses whose expiry is a finding;
stuck keys and presence are its own findings; it keeps the dead letters from the lease write on its own consumer, lists and
shows them, and refuses deliver and drop until the hand-act log's home (issue 1953). Tools read every state it keeps and
start resync. Pins mesh-sdk 2a04bf0.
Recovery of photos and link2pay on novox, 2026-10-29: their composition and grant were lost and no tool wrote a done key again.
Quick fix: rewrite the done key unchanged as a new revision. Thorough fix: ADR 0547, the node agent composes its own and the
assigner stops waiting on controller compositions (design 47).
mesh/check pass d54eab4052d1 on c1b4533201c8 | unit 3318 run, 1951 kept, 38 skipped | integration 3994 run, 2125 kept, 38 skipped | over bound: unit, …
On novox on 2026-10-29 the assigner wrote no want for de-spiegel and link2pay (rule 5: no provider of route runs
healthy) nor photos (rule 5: no provider of s3-bucket), and none where no node of a module was online (rule 3). A
module with no want is on no list and nothing applies it; a site runs while the proxy in front of it is down.
- Quick fix: skip rules 3 and 5 for the three modules' first wants. Leaves rule 5 holding every move and the
canary holding new assignments.
- Thorough fix, chosen: rule 5 holds no want; it is said per node (Outcome.Unreached, journaled once per words by the
pass). The canary (rule 3) no longer holds the first want of a node that does not run the module. A node that runs
it keeps the canary order: at an older composed and granted fingerprint of the new form its first want stays at what
it runs; at an old-form build it waits for the canary as before (issue 1945); at an older fingerprint with no
composition or grant it gets F. This departs from ADR 0429 §6, which makes every provider healthy a rule of every want.
Tests: rows changed in the existing rule tests, and rows for today's modules (route-proxy down: de-spiegel and
link2pay wanted; minio not healthy: photos moves; novox offline: a first want written, a move kept back).
mesh/check failed: ace: the check of novox/mesh-host#168 failed: the pin of git.novox.be/novox/mesh-sdk/go at commit d4c61ee8ffd0 is on no pull reques…
mesh/check failed: shanks: novox/mesh-delivery#105 does not merge into the trunk: files in conflict: modules/mesh-delivery-assigner/go.mod, modules/me…
mesh/delivery-group group feat/774-vault-mints-l2 checking: the checker's verdict is out of date: novox/mesh-sdk@8eafc0c5ce3c was judged on trunk 53f26493697e,…
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.
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.
Why: from the lease write the grants part's state grants is the source and the controller's bucket otherwise; the assigner follows the lease key (a pass only when the source changes), and neither bucket stops its start. Needs the group's mesh-sdk pin (GrantSource, LeaseHandedAway, the assigner a named reader of the lease).
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.
mesh/check pass 2d8ad2e66a8f on 38f89c6976c9 | carried from 1f6f4eda3208 | unit 470 run, 4760 kept, 13 skipped | integration 503 run, 4844 kept, 22 sk…
Once the gate's one-hour ask bound goes (mesh-catalog fix/1733-no-hour), the
gate asks the operator's Approve only on a verdict, so every path that left
a candidate without one now writes one, from an event and with no timer:
- a group with a member whose repository's trunk head is not known (a pull
request the checker cannot claim) is not judged in part: its verdict fails
naming that repository, and every status of the group says so (a pass of
the others would have let it merge with that member never checked);
- the verdict of heads that cannot be judged replaces whatever the key held,
such as a running verdict left by a check that can no longer run;
- a verdict key deleted is judged again on its delete (the checker watches its
verdicts), and a check running when its key is deleted writes it anew.
Tests: three rows at the end of the no-trunk test; counts unchanged.
mesh/check checking e7888024a826 on 769815ac0fea | novox/mesh-delivery#103 in group fix/lost-check
Re-review of fix/lost-check: writing an empty list at the end kept one key
for every verdict key ever checked. Tests: every row of the lost-ask table
proves the key gone at the end; one row more (deaf after its build module
replaced it, asked again by hand); counts unchanged.
Since 9db9499 the checker asks no check while no node record is on the bus; the bed wrote none, so eight integration tests failed on main (PR #101's check). The fake build module now records the names an ask carries, and the first test asserts n1 is named.
Review of fix/lost-check: an ask no node took yet has no step key, so
asking again then would run the check twice (issue 1791's kind). The
checker keeps the asks each running check put in a new state asks, and the
tool refuses unless every one of them has a step key. Asking again under the
same ask id is not done: the stream drops a second put of an id within its
de-duplication window and keeps both past it, so the waiting copy is never
replaced.
Tests: the hand row of the lost-ask table refuses while its ask waits;
counts unchanged.
The checker's HeardEnds moved to mesh-sdk buildrun (fix/lost-check,
6aeb401): both modules pin it, and the builder, which waits on the same
Asker, now reads an ask's step at each step end of its build module too.
checker_ask_again and checker_status's lost stay in the checker.
Tests: one row in the builder's ask table (its watch deaf, read at a
nudge, done with no new ask); counts unchanged.
mesh-catalog #553's verdict stayed running after its step mvsgthyjed5786
passed on shanks at 19:09:31Z: the watch of that one step key, opened at
18:46:05Z, heard neither its start nor its end and never closed, so the
wait had no bound running and nothing would ever judge it.
- HeardEnds stands between the asker and each ask's watch: at every step
end of the same build module (one watch per steps state), at a
reconnect, the asks waited on read their keys now and are judged; a
watch that closes is opened again, at most 3 times.
- A step the build module's next process ended (RestartReason, a delivery
replacing it) counts as a lost ask: asked again under the claim, at most
LostAskTries, then failed as not heard, judged again when the nodes change.
- checker_ask_again {group, why} ends a running verdict as asked again by
hand; the checker hears its verdicts, ends the wait and claims it anew.
Refused while a step of its pull requests runs, or for a verdict that
is not running.
- checker_status names such checks under lost, and each step's what.
Tests: one table replaces the given-up test (rows for given up, replaced,
deaf and nudged, deaf and asked by hand); counts unchanged (147 unit, 10
integration in the checker).
mesh/check failed: integration: meshbuildgo/cmd/mesh-build-go.TestAComposeAskIsBuiltOnceAndAnsweredOnTheBus: the compose ask mvsg85b34d25b4 never ende…
Deletes the placement and candidate writes, the reread tool and its forge reads, the two buckets and the placement-changed event.
D1a and D1b are one commit: the index package, the named reads, the tools and the manifest do not compile apart.
mesh/check being carried to 726bbf1f1ffa on 2ac146078f47 | from e753009fbc71
The view remembered a reach value, a reached head and a motion event as written or said before the bus took them; a write refused at its start (no responders) was never made again while the derivation stayed the same, and mesh-delivery.show said mesh-delivery-view not running on shanks while node_haves said it running.
Quick fix: forget only the refused reach write. Thorough fix, chosen: every write and event the view makes after its lock (reach, reached head, delivered revision, motion) answers its error, and the model forgets what was refused, so the next change it takes in makes it again; one place, the writer of the state both mesh-delivery.show and knowledge-base.progress read.
Asking whether the merge contains the held commit refused forward merges
forever on a diverged or rewritten main or a squash-merged registered head,
failed every later merge when the forge no longer had the held commit, and
cost one forge call per held commit. The question is now the reverse: a merge
is kept back only when it is in the taken merge and differs from it. A merged
message asks it once, before it writes anything, and a late message writes no
module, deletion, placement or taken key. A take-in asks it once for its
module. A 404 is not known to be older and is written, and said; any other
failure to say leaves the message for redelivery.
The indexer wrote mesh-catalog's merge 9cdac09a back over the later 69056948,
rolling kernel and mesh-build-image back on the nodes: a merged message's
commit was written whatever the held one was. Before writing or deleting a
module's value, the indexer now asks the forge whether the merge contains the
held commit, keeps the held value when it does not and says so, and leaves the
message for redelivery when the forge cannot say. Each applied merged message
is said in one line with the modules written.
No tool showed what the indexer heard of FORGE nor a modules key's history
with times, so the cause could not be proven: the indexer now records each
FORGE message it handles (sequence, deliveries, times, commit, outcome) in its
state heard, read by indexer_heard, and indexer_module_history reads
modules.<module>'s kept values with their times.
Quick fix (Src order in writeOverlay) rejected: Src is 0 once the source moved
on, as here. Thorough fix chosen: the order is the forge's, on every path that
writes a module (merged message, take-in).
Review round 1 (issue 1126 note 72): the inflight check, the watch and the look were three locks, so a second request or the builder's own look could build the key twice; the answer said asked when the look wrote nothing or the build failed before its asks.
The builder retakes a failed key only when it looks at its module again, which nothing does for an unchanged module. The tool makes it look now, with the claim's own rules, and refuses a key that is done or waiting.
mesh/check being carried to 2b801f5bd49a on 31bbf207ef3b | from ae7ec702a5e9, mesh-catalog 9fd95693db54
A head older than the record, or one whose order the forge cannot say, would have written
an older manifest back. The new tests become rows of existing ones: the repository is over
its 500 unit tests.
A merge whose merged message never reached the indexer had no recovery: take-in answered
held for mesh-vault, whose record stayed at 78d7ef7 after mesh-catalog#535.
Without it the first merge after the bridge starts, with nothing kept, still reads all 140
catalogue directories in one 30 s try and times out as before.
mesh-catalog's 140 module directories are 420 forge reads per merge, past the 30 s bound
of a handled event while the forge is busy: the merged message of #535 timed out on every
try, and #3fb7951 needed seven (issue 1458 met the same kind at 131). A tree hash names its
bytes, so what was read at a tree is kept in the new state inputs and in memory, and a
merge reads only the directories it changed.
A drained forge stream does not say a merge was applied: the forge bridge was still
retrying mesh-catalog#535's merged message when the indexer started, and the source's
head moved taken.mesh-catalog to 9fd9569, so the view and show said the merge was on the
machines while mesh-vault's record stood at 78d7ef7 (ADR 0556 clause 1).
The checker judges pull requests into main only and source.main names main's head only (ADR 0484 §11), but a live update
into another base (de-spiegel#6 into nox-mesh) became a candidate, unlike at the start (OpenPulls) and at its merge. Once
the gate seeds a repository's trunk head, such a candidate would be judged against main's head: a verdict that lies.
A repository never merged through the gate has no entry in source.main, so its pull requests were dropped without a log
line, a verdict or a status, and checker_status counted them as new. Now the verdict says it cannot be judged and why,
the forge status is error with those words, checker_status names it under cannot_be_judged, the log says it once per
head, and the heads are judged whole once the trunk head is known. Quick fix: this. Thorough fix (the gate seeding
source.main from the pull message's base head) is still to do: it needs mesh-sdk, the forge bridge and the gate.
mesh/delivery-group group fix/1126-shadow-bodies rejected: composed together: the checker's verdict at the members' heads (46e1e846f8db): unit: modules/mesh-de…
mesh/check failed (2 tests): unit: modules/mesh-delivery-view.gofmt: not as gofmt writes them (run gofmt -w): modules/mesh-delivery-view/internal/view…
The bodies of each difference never reached the answer shown: the view decoded
the node's answer with its mesh-sdk, which did not know the field, and encoded
it again. The answer now rides through as stored; a decoded copy only says its
state.
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.
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
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
A node composing a consumer reads the served keys of the trunk's manifest of a
provider elsewhere, which may serve a setting the build it runs does not.
mesh-grants declares each module's served settings (catalogue.ServedSettings), so
the user list grants every other node's agent those keys of mesh-config_resolved
alone: shanks then settles what novox's mailu serves. The assigner's check of
every node reads no build, archive or served value: it composes as before.
mesh/check being carried to ec0b7e2dcc06 on da514816204b | from 24cb379434f5
A dropped verified-sender comes from a root-free word that failed for one
pass, not from a release, and losing it cut the operator's approvals on
2026-10-27. Holdings.CapabilitiesLost holds such a membership with its own
reason while the holder is assigned and its manifest still asks for it; a
dropped tool or field and a moved seat stay published.
Holding the user list on any loss would freeze it after take-over at the
first release that drops a tool or moves a seat (ADR 0547 §7), with nothing
to accept a deliberate loss; memberships had the same gap. The lead's decision
in review round 1: one pure guard, Holdings.LastHolders, holds the list and
each membership only when a seat held in force would have no holder in what
is composed now while an assigned module still claims it, the 09:21 kind.
A dropped tool, verb or field, or a seat handed to another node, is written.
The user list of 2026-10-27 09:21 granted no holder for nine seats: the seeded
placements hold only the seats the controller had on record, and the grants part
read those holds as every holder (records.go heldWherePlaced). A placement's
holds are now the holders on record, as catalogue.World's Holdings are: a mesh
seat no placement holds is held by derivation, wherever its claimant is placed.
The membership loss guard (Losses) did not cover the user list: after take-over
the list that lost those seats went out. UserLosses applies the same guard per
user against the loaded list, and holdsBack holds a list that would lose a grant,
or whose loaded grants cannot be read, raising the held warning.
Quick fix chosen over moving the on-record rule into mesh-sdk: mesh-grants is the
only part reading placement holds itself; the others pass them to the catalogue.
mesh/check being carried to bb63d83f849e on c38e81c7f5e9 | from 2915d74822cd
After the placement seed's revert the rules that hold a want (a hold, rules 3 and 5) kept g14's and shanks's Self wants: the held branch copied them whole, and the rule branch wrote a want naming no composition, which EncodeWant refuses. Module.Self, set once from the placement, is now the one source, and every want the rules write or keep is derived from it: an unplaced node's kept want names the controller's composition of the same fingerprint, asked as any record move; with none, it stays and rule 7 says why.
mesh/check being carried to efadc691e7ea on 475bb4bb0b8f | from 4af36c69a761
view_reach asked for mesh-delivery-view.reach, a name the mesh never issued, so it failed on the machines;
the same line was not gofmt'd, which failed the try of main. Quick fix: the name. Thorough for this module: the
manifest test now refuses any stdio.State literal in cmd/ that is neither an own state nor listed in reads.
mesh/check checking f007ca42279a on 4b36cc29a6ae | novox/mesh-delivery#81 in group fix/1496-start-health
Review of 50c4674: the bar on new wants naming F while a node fails it alone
also caught a node that runs F with no live want, the issue-1945 recovery path:
it went on neither list and its node-engine gave the module up. The bar now
holds only a node that neither wants nor runs F.
ADR 0557 version 9: a failure that is one node's holds nothing and sets nothing
back, but the version reaches no node that does not want it yet until it is
over. A node whose want does not name F gets no new want naming it (rule 2, in
words naming the failing nodes); wants already written stay.
Review round 2 of 16e4e61: gating the first-pass clear on a failed have left a
condition an earlier process raised standing for good once its node recovered
while no assigner watched. The first pass now clears it for every module and
every node the presence bucket knows, a quiet clear at the router for one that
is not open.
Review of 2ee7589: a node that sleeps after running F healthy kept its stale
have as a witness, so F stayed unheld while it failed on the online nodes; and a
failed-alone condition was never cleared once its node left the module.
A witness must now be online by the watchman's presence. F failing on a second
node is no longer one node's failure: the hold and the set-back stand (ADR 0557
version 6, §2). A remembered failed-alone key whose node is no longer one of the
module's nodes is cleared once; the first pass after a start clears it for every
node the presence bucket knows, for a module with a failed have.
On ace, 2026-10-26 21:19, a newly assigned mesh-build-node failed its first
health check at 8a98386f (later 31be2f24) while shanks, g14 and novox had run it
healthy for an hour. Being first by name, ace was the canary, and the assigner
held the version and moved the three healthy nodes back.
A failed health check of the newest fingerprint now holds it only when no other
node's have names it healthy (ADR 0557 §2 keeps ADR 0429 §6's hold and set-back
for that case). Otherwise the failure is that node's (ADR 0557 §1): nothing is
held or set back, the node keeps its want, and the assigner raises the node's
condition once (failed-alone.<node>.<module>), naming the node, the module, the
fingerprint and the have's words, and clears it once when it ends; the first
pass after a start clears what a previous process may have raised.
mesh/check checking c47afd8f4b88 on 3dd94f714d6e | novox/mesh-delivery#78 in group fix/capacity-follows-cpu-share
A build module's capacity.<node> now carries its node's build window (the operator, 2026-10-26: g14
builds only from 18:00 to 06:00); the seat shows it, outside it says it takes nothing new, and a
value the module cannot read shows as any hour with the value and why. The checker's and the view's
SDK pin moves to mesh-sdk d00dac1.
Only tries a build node holds count toward the 4 at once; tries waiting for a node are bounded
apart at 8, and the refusal names both counts (issue 1890: at 19:53 four tries queued behind 44
checks for up to 47 minutes refused every further try).
The checker wrote a try's asks only at its end, so a 31-minute try could not be told queued from
running (issue 1890). The try's record now names each ask as it is put, then the node that took
it, its state and the phase its step says, written on the step key's own changes. build_usage
names a running try's asks and takes a build module's capacity.<node> (configured bounded by its
node's build CPU, issue 1806's follow-up) when it is current with mesh-config.
A failed test with no cause, or a passing line as its cause, was worded as if it were the failure: a try of mesh-catalog
failed with a passing '✔' line of the first test file. Under mesh-sdk's failure contract the verdict's words and its
status line now start with 'the build module hid the failure (<module> at <version>)', and the check still fails.
mesh/check failed: ace: novox/mesh-catalog#505 does not merge into the trunk: files in conflict: .gitignore | 2e0013ec2500 on df8b9ac3b1b5 | unit 1245…
mesh/check failed: ace: novox/mesh-catalog#505 does not merge into the trunk: files in conflict: .gitignore | 2493aa65299e on df8b9ac3b1b5 | unit 1245…
One commit for the branch feat/1126-nodes-compose of mesh-delivery: its 16 commits squashed so its history does not carry the 17.8 MB compiled mesh-delivery-assigner a commit added by mistake and a later one removed (issue 1577). The tree equals the former head ff6c038d. The operator allowed this rewrite of the feature branch on 2026-10-26.
A delivery restarted the checker and the builder before the grants part created their new state hearing;
OptionalBucket answered nil and the hearing was never kept. They, and the builder's reasks and queues and the
indexer's takeins, now open their own states through mesh-sdk process.AwaitBucket (mesh-sdk
fix/1790-state-appears d515c71), which binds on the bus's STREAM.CREATED advisory and writes the latest kept
value. mesh-grants takes the same SDK, whose composer grants that advisory.
A capacity this tool cannot read is unknown to it, not 0: the seat says eligible_known false and the node not known.
A key mesh-config holds without a readable value is what the puller reads as 0, and was dropped silently.
Since mesh-sdk #90 a build module ends a left-running key as failed at the moment it notices; counted as finished,
such a step put hours into the medians and the time at capacity. The view takes mesh-sdk's step bound and restart
reason from the SDK it now pins.
The operator's question (how much are the build nodes used, is ace eligible) took six calls over four tools.
build_usage reads it from the bus's states: seats held (have), capacity (mesh-config resolved), pauses, the
build modules' steps by kind with left-running keys, the last hour and day with total and median time and time
at capacity, the running tries, and the backlog the view program reads from the seats' streams. A try now names
the asks it put, and the checker announces its tries readable, so the view tells a try's asks from a check's.
mesh-grants moves to the same mesh-sdk (3203358c), so its shadow user list grants the checker and the builder the
DEAD_LETTERS reads the controller's list will, and the take-over is not blocked by a difference. The checker and the
builder hear DEAD_LETTERS through buildrun.DeadLetterHearing: in the background, again at every reconnect and every ask
waited for while deaf, and keep whether they hear it in their new state hearing, which checker_status and builder_stuck
say as dead_letters. checker_try says that a try ended by the not-taken bound leaves its ask in the stream.
Not done as asked: a module health tool. The catalogue refuses a tool check on a module with no runtime of its own and no
other check beside it (ADR 0227 rule 8, ADR 0366 §1), so the deaf state is said in the status tools and the log.
The waiter moved to mesh-sdk buildrun (fix/734-lost-ask, d96b9fd6), where every asker of the build seats shares it.
The builder hears DEAD_LETTERS for the go, node and image seats and asks a given-up part of a build again at once, with
the seat's words as why, instead of waiting for the check bound. The checker keeps what it does with a lost ask (a try
ends as error, a check is asked again) and its verdict words.
A check ask handed out five times during a bus reload was given up into DEAD_LETTERS and no build node wrote a step for it,
so try-1793017340003993788 stayed running for ever, held one of the four try places, and checker_try of its head kept
answering its id. The checker now hears the copies DEAD_LETTERS keeps of the build seats' given-up asks (an ordered
consumer from its start; the grant is mesh-sdk/mesh-controller DeadLetterReads, branch fix/734-lost-ask) and ends the
step it waits for: a try ends as error saying why, a check is asked again under its claim, up to three times, then fails
as not heard. A try whose ask no node takes within the step bound ends the same way (a check's backlog stays no fault,
ADR 0525 §9). checker_try_end ends a try by hand, freeing its place and stopping its judging.
A registered module whose repository the forge answered 404 (car-hunter, snake, before the forge's account could read
them) was read again only when the indexer started again or the controller wrote a new build record of it, so the grants
part's composed user list stayed short of their subjects and the take-over was refused. A failed read now keeps the
module as unread, read again on the next source revision and the next merged message (no timer of its own), and the new
tool indexer_take_in (the tools bundle mesh-delivery-indexer-tools, through the indexer's takeins state, as the
builder's builder_ask_again) takes one in now and answers what it stored or why not.
Review round 1: while an operator's put runs through its steps it owns the want, so the clear said
'the node does not run it' of a node that runs the bus.
A bus whose move only the operator's put may make (ADR 0546 §8) got no want and nothing in the outcome:
nats on novox, running an old-form build, was on no list while the pass cleared its condition and logged
that it had a want again. The bar now names its holding, puts a node without a live want on neither list
(its condition needs the operator: assigner_put), and a neither condition is cleared as 'has a want again'
only when a live want exists.
A check that landed on ace passed with mesh-build-node's integration tests skipped. The build module now leaves such a
package unmet; the checker keeps the passes and asks the levels from the first unmet one with the need named, putting the
ask again under a new id when a node lacking it declines it. Re-pins mesh-sdk feat/890-placement.
mesh/check failed: ace: the check of novox/mesh-catalog#492 refused: the installed go version could not be read: `go version` with GOTOOLCHAIN=local f…
mesh/check failed: ace: the check of novox/mesh-delivery#65 refused: the installed go version could not be read: `go version` with GOTOOLCHAIN=local f…
The bus node can only take over a list that exists: each pass composes the accounts block with the vault's hashes, seals
it to the key the bus node says in its have, puts it in the part's own object bucket by digest and writes the key with
digest, revision, user count, users left out and which list to follow. take-over is refused, naming why, while no list is
sealed to the bus node's current key or the loaded list does not grant the bus node its read.
Review of fix/1945-takeover-blockers: no responders on the router's record is an error, not 'no record'; an answer whose
record cannot be reached is not closed; an ask that failed to publish is taken back at the router; an error acting on an
answer is logged. Pins mesh-sdk 175a5567.
The part composed every membership with no root-free input, so telegram's verified-sender was dropped and the membership held as a shadow
difference. It now asks mesh-controller.root-free for the machines a composition needs, per pass, failing closed and said once, and wakes
on root-not-free condition-raised and condition-cleared.
The checker stopped reading a level's test results at the first that did
not pass and kept only its first failure, so a check named one fault per
round. It now reads and counts every result and writes every failed test
with its first line into the verdict's Failures and the try's failed
list (at most 50, then how many more); Failed keeps the first one's
words whole (issue 1901). Pins mesh-sdk fix/1921-every-failure.
mesh/check pass 769dab43a24d on 2f697216eee4 | unit 168 run, 488 kept | integration 178 run, 554 kept | composition passed on ace
The held record is the memory that a fingerprint failed (ADR 0408 section 4); a revert returns the
trunk to exactly it, and without the key rule 3 would move the canary onto the failed build with
nothing asked. A stale hold ask now clears only the condition (raised again on a revisit), and the
hold is asked again under a new asking. Also read the single want key for a record ask.
Review round 1: a record ask is about the composition of any fingerprint a node may still want
(trunk, want, have), not only the trunk's, so deleting it looped with the wants rule that asks it
again and the operator was never asked. It is now stale only when the module left the trunk or no
read composition of those fingerprints has its digest. A hold or restore ask taken away as stale
also takes its held record and clears its held condition.
An ask outlived its fingerprint: a lift left the restore asks of its fingerprint on every node,
and no pass removed an ask of a fingerprint that is no longer the module's trunk fingerprint,
so the operator kept being asked about a module that runs the trunk healthy. Each pass now
takes those asks away (the teller then withdraws the router ask), and a lift takes the restore
asks of its fingerprint. Nothing is taken away while the trunk or a composition is unread.
mesh/check pass aea22bf793b4 on 7ddbf40715ff | unit 168 run, 479 kept | integration 178 run, 545 kept | composition passed on novox
The part reads seats, buckets, logs and streams, never a config value, and
the merge gate already judged the fallbacks; reading the controller's
predefined mirror would tie the part to the leaving controller (ADR 0547
clause 1). ParseManifestForInputs takes a fallback as it declares itself.
Issue: 1945
A manifest falling back to a predefined key (claude-code, dunst) was parsed
with no list, refused silently, and its module counted as placed nowhere, so
three memberships would lose claude-code's reach addresses and were held back.
The part now reads the list the controller mirrors (mesh-controller.predefined,
key list), follows it, and lists every manifest it cannot read in its gaps,
its pass (refused) and its log.
Issue: 1945
mesh/check checking 12f16bbebd40 on 13380e3d0e52 | novox/mesh-delivery#58 in group fix/1790-grants-create-buckets
A module's new state reached the bus only when the controller started (issue 1790, met three
times: puts, queues, mesh-vault's bus-accounts). The operator allowed one more grant in the
controller's composer on 2026-10-26 08:54, creation only: the part's process now creates each
bucket, log or stream a placed module's manifest declares and the bus lacks, with the same
configuration the controller asserts (mesh-sdk BucketStreamConfig, Log.Config,
ModuleStreamConfig), on the event that brought the manifest, never on a timer. It says asserted
and logs one line per module; a stream the bus holds is never updated or deleted, its difference
only said; a create refused is said and tried at the next event; one created at this manifest
and gone since is made again only by hand. grants_assert asks the process to do the same for one
module now. The user list, the grants and any change to a held stream stay in shadow. mesh-sdk
moves to fix/1790-grants-create-buckets, whose composer grants this, so the shadow list is
composed as the controller's.
Issue: 1790
The guard that holds back a membership losing anything held back five since 01:24: the frozen
controller's memberships still serve the delivery seat's mark-ready, which mesh-sdk d506f21
retired on purpose (ADR 0421), so every membership composed with today's seat catalogue looked
like a loss. A seat verb the catalogue defines no longer is now dropped from the comparison and
named in the pass (retired); any other loss, a module's own seat's verbs included, is still
refused. The log named only the first held membership: it now says each one, with what it would
lose, whenever the set changes, and grants_membership with neither node nor module lists them.
Issue: 1945
mesh/check pass 9132b6a296b9 on 13380e3d0e52 | unit 168 run, 473 kept | integration 178 run, 539 kept | composition passed in 36ms on novox
ADR 0547 clause 9: the vault writes the hash of each bus account it holds into bus-accounts.<user>. The grants part
watches that state (no timer), carries the hash with each shadow user in memory only, and its user-list tool says per
user whether a hash is held and how its line would differ from the loaded one (same, adds, left out for want of a
credential, loses its login); never the hash, since bcrypt salts make two hashes incomparable. Take-over names the
users with no hash.
Issue: 1945
mesh/check pass 3e8bd9b0def2 on bcb5aafdbe80 | unit 168 run, 472 kept | integration 178 run, 538 kept | composition passed on shanks
mesh-delivery #51's re-ask never fired for mesh-build-node.4e7b118e: messages the
SEAT_NODE_BUILD_GO workers had given up on stay on the work queue, and each counted
as waiting ahead, so the ask was never asked again (note 62). A message ahead now
waits only when no node wrote its step and no ask of its kind asked after it was
taken; the old message of an ask asked again is deleted from its stream; and
builder_seat_queue (answered by the builder through its queues state, as only its
account may read the stream) shows each message and whether it still waits.
builder_stuck, checker_kept, checker_verdicts, checker_status, checker_previews, checker_pull and checker_try listed a
bucket of thousands of keys and read each value (builder_stuck also its history) one round trip at a time before
filtering, so they timed out at 30 s. Now keys are narrowed by what the key carries first, history is read only for rows
kept, values are read sixteen at a time, at most 1000 a call with the answer saying it was cut, steps newest first, a new
try reads only the newest 64 tries, and each tool logs the values read and the time taken. Same kind as the view's fix
(PR 52); the helper is copied, not put in mesh-sdk, as a few lines do not earn a group delivery.
Composed without a root-free judgement, a membership would drop a kind's verified-sender and the
operator's channel approvals would stop being honoured; any loss now stays a shadow difference,
named. A tool no longer waits on a pass's round trip. compose-now says the controller serves no
verb to write a module's grant again.
Since release 6 nobody publishes memberships, so a module placed since cannot serve its seat
or reach a new state (the operator, 2026-10-25 22:31). The part publishes each membership on
the assignments stream only when it differs from the one last published, composes from the
manifest the wanted build names, and says a refused publish and tries again at the next event.
Pins mesh-sdk 881da7f, whose composer grants mesh-grants that publish.
mesh/check pass 41f25d3129fd on 73be3df28cd4 | unit 21 run, 579 kept | integration 21 run, 655 kept | composition passed on shanks
On 2026-10-25 node_haves and assigner_wants timed out at 30 s four times, even narrowed to one node and one module,
while assigner_want answered at once. Each listed every key of its bucket and then read every value one after the
other, filtering only afterwards; every value is a round trip from the tool through the runtime to the bus, which
opens the bucket and gets the key, so a few hundred keys outlasted the call. Now a node and a module read that one
key directly, a node or a module alone filters the keys before any value is read, and the values are read sixteen
at a time, at most 1000 a call, the answer saying when it was cut. indexer_modules, indexer_candidates and
builder_builds read their values the same parallel way. The kind: a read tool that reads a whole bucket key by key;
every list tool of the view is covered.
mesh/check pass 4628ba26b41a on 73be3df28cd4 | unit 167 run, 443 kept | integration 177 run, 509 kept | composition passed on 3 machines
The open helpers were copied into seven parts; code shared between
modules lives in mesh-sdk, so they are mesh-sdk process's now and the
parts are pinned at fix/1945-optional-buckets (e0d1de04), moved to its
main once it merges, one delivery group with mesh-sdk.
Met twice on 2026-10-25: the builder of #48 exited on a refused read of
the gate's source and crash-looped, and its new reasks bucket would have
done the same. A grant reaches the bus with a delivery, so a refusal or a
timeout at start is often only a grant not there yet; exiting for it
stopped the whole part until a hand step on the bus.
Every startup open in the parts is now essential or optional. Essential
ones (a part's own state and the input it exists for) still stop the
start, with an error naming the bucket and its grant. Optional ones are
said and left: watches the bus refuses too. The builder builds trunk keys
without the gate's source, which it opens again at the next candidate
that asks a trunk head; toolchains and previews open again at their next
event, as a missing bucket did. builder_ask_again says that asking a
running step again builds it twice.
A new assignment whose trunk build was not done fell through the rules
with nothing said: no want, no neither-list entry, no log line, and the
rule holding it back was computed and dropped. The pass now logs the rule
when a node's reason appears or changes and when it has a want again, one
line per change. A node whose want is removed and that does not run the
module gets the reason in that removed want's words, so assigner_want
answers why; a node with no key gets no removed want, since its node agent
would then remove the module and stop holding its resources back.
A build ask its seat's stream gave up on, dropped or ended with no step was
waited for with no end, and on restart taken over and waited for again: no
build node would ever answer it, and nothing could ask it again (trunk key
of mesh-build-node at 4e7b118e, building since 19:06; seven keys at 18:44).
At the step bound, a context's bound and no timer of its own, the builder
reads what the bus says of an ask with no step: gone from its stream, or
first in line while a node took a later ask. Such an ask is asked again
under a new id the key names, logged and said as build.asked-again, at most
three askings, then the key fails with why. The bus's max-deliveries
advisory would tell it sooner, but the builder is granted neither it nor the
workers' information, and the controller is not changed here.
builder_stuck reads every waiting key with its asks, askings and steps;
builder_ask_again writes the new reasks state, which the builder watches
and answers.
The grants part must compose with the controller's own composer before it can take over the
list; in shadow it proves the two agree, names every input the bus does not carry yet, and
takes no effect. It claims no seat (mesh-sdk's seat list does not name mesh-grants for the
running composer), serves module tools, and keeps running when a read or write is refused.
// Package reference holds the form of an artifact's reference once a registry seat published it: `<seat>/<module>/<artifact>@<digest>`
// (novox/hq ADR 0605 §9), and the older `artifact-store://<path>` form read beside it. It is the rule the holders and callers of the two
// registry seats that front the artifact store share (the seats' client, novox/hq ADR 0625 §4, ADR 0634 §2); it names no seat itself (ADR 0634 §4, ADR 0635 §4): the
// caller gives the seats' names from their contracts (Seats), so a package here cannot drift from a contract.
packagereference
import"strings"
// ArtifactStoreScheme marks a reference to something in the mesh's artifact store, kept without the store's address.
constArtifactStoreScheme="artifact-store://"
// UpstreamPrefix opens the holder's own name for an upstream copy it keeps: `upstream/<host>/<path>@<digest>`, after
// `<image seat>/` in the seat's form and after `artifact-store://` in the older one.
constUpstreamPrefix="upstream/"
// Seats are the names of the two registry seats a reference of the registry form names first: Image the seat that fronts
// images and upstream copies (container-image-registry), Object the seat that fronts bundles and archives
// (oci-artifact-registry). The caller reads them from the seats' contracts.
returnfmt.Errorf("meshcatalogclient: the verdict on %s waits and names no unknown field, or names problems or warnings: a wait names the fields",v.Module)
}
default:
returnfmt.Errorf("meshcatalogclient: the verdict on %s is %q, none of %s, %s and %s",v.Module,v.State,VerdictAccepted,VerdictRefused,VerdictManifestWaits)
}
ifv.Judge==""{
returnfmt.Errorf("meshcatalogclient: the verdict on %s names no judge",v.Module)
}
returnnil
}
// EncodeVerdict is v as JSON at the kept values' version; it refuses a verdict without a module or a judge, a state other
// than accepted, refused or waits, a refusal naming no problem and an acceptance naming one.
returnfmt.Errorf("meshdeliverycheckerclient: the verdict's composition is not run and names no mesh-sdk commit or machines")
}
caseCompositionPass:
ifc.Sdk==""{
returnfmt.Errorf("meshdeliverycheckerclient: the verdict's composition passed and names no mesh-sdk commit")
}
caseCompositionFail:
ifc.Words==""{
returnfmt.Errorf("meshdeliverycheckerclient: the verdict's composition failed and gives no words")
}
default:
returnfmt.Errorf("meshdeliverycheckerclient: the verdict's composition state %q is not %s, %s or %s",c.State,CompositionNotRun,CompositionPass,CompositionFail)
}
returnnil
}
// CheckVerdict refuses a verdict a reader could not place: no group, heads that are not 12 lowercase hex digits, a repository
// both merged and read beside, a carried-from that carries nothing, a series change from a series to itself or named twice, a
// level that is neither unit nor integration or counts a negative number, a time below zero, a pass that says nothing of a
// level, a fail that names neither a test nor a machine, and failures on a verdict that did not fail.
returnfmt.Errorf("meshdeliveryclient: the turn of %s is not in the order of the Approve: %s was approved before %s",t.Repository,w.Group,t.Waiting[i-1].Group)
}
ifw.WaitsFor!=""{
if_,_,err:=parseVerdictKey(w.WaitsFor);err!=nil{
returnfmt.Errorf("meshdeliveryclient: the delivery %s in the turn of %s waits for what is not a verdict key: %w",w.Group,t.Repository,err)
// A node the catalogue places composes its own modules (ADR 0547 §2): its want is Self and names the build alone. Any
// other want names the one composition it allows (ADR 0539 clause 1).
switch{
casew.Self&&w.Composed!="":
returnfmt.Errorf("wants: the want of %s says the node composes it, and names a composition",w.Fp)
case!w.Self&&w.Composed=="":
returnfmt.Errorf("wants: the want of %s names no composition: a want names the digest of the one composition it allows (ADR 0539 clause 1), unless the node composes it itself",w.Fp)
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package containerimageregistry is the contract of the seat "container-image-registry", defined whole (seats/container-image-registry/seat.json): The mesh's container images, in the one artifact store: the OCI distribution protocol's read side, an image's tags and mirroring an outside image.
packagecontainerimageregistry
import(
"bytes"
"encoding/json"
"errors"
"strings"
)
// Seat is the seat's name.
constSeat="container-image-registry"
const(
VerbPublish="publish"
VerbPublishPart="publish-part"
VerbVersions="versions"
VerbRemove="remove"
VerbMirror="mirror"
VerbTags="tags"
VerbHold="hold"
VerbRelease="release"
VerbList="list"
)
const(
EventPublished="published"
EventRefused="refused"
EventRemoved="removed"
EventKept="kept"
EventHeld="held"
EventReleased="released"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
// ParseHoldsBySeatNameDigestKey reads the parts of a key of the form "<seat>.<name>.<digest>", in the order of the form; the last result is false for a key of another form.
// DecodeHoldsBySeatNameDigestValue reads one value of the state holds under the form "<seat>.<name>.<digest>", refusing a field HoldsBySeatNameDigestValue does not know and any text after the value.
// ParseWindowsByCallerKey reads the parts of a key of the form "<caller>", in the order of the form; the last result is false for a key of another form.
// DecodeWindowsByCallerValue reads one value of the state windows under the form "<caller>", refusing a field WindowsByCallerValue does not know and any text after the value.
// Artifact is one published thing, as every registry event and answer names it.
typeArtifactstruct{
// the source commit it was built from
Commitstring`json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digeststring`json:"digest"`
// the build's fingerprint
Fingerprintstring`json:"fingerprint,omitempty"`
// what it is
Kindstring`json:"kind"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Namestring`json:"name"`
// the tag it carries, for a tagged version
Tagstring`json:"tag,omitempty"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Versionstring`json:"version,omitempty"`
}
// The values of Artifact's kind.
const(
ArtifactKindPackage="package"
ArtifactKindImage="image"
ArtifactKindBundle="bundle"
ArtifactKindArchive="archive"
ArtifactKindUpstream="upstream"
)
// Hold is the body of held and released.
typeHoldstruct{
// when, RFC 3339
Atstring`json:"at,omitempty"`
// the caller the holder proved
Bystring`json:"by,omitempty"`
// the digest
Digeststring`json:"digest"`
// the module holding the seat
Holderstring`json:"holder"`
// the name
Namestring`json:"name"`
// why
Reasonstring`json:"reason,omitempty"`
}
// Listed is a type of the contract.
typeListedstruct{
// for a manifest keeping one bundle or archive, the digest of that blob: what a reference names it by
Artifactstring`json:"artifact,omitempty"`
// the manifest's digest, sha256:<hex>
Digeststring`json:"digest"`
// a hold keeps it from retention
Heldbool`json:"held"`
// it is an index, naming a manifest per platform
Indexbool`json:"index"`
// for an index, the digests of the manifests it names
Platforms[]string`json:"platforms,omitempty"`
// its bytes: its own content and every blob it names
Sizeint64`json:"size"`
// the tags naming it, none for an untagged one
Tags[]string`json:"tags,omitempty"`
}
// Outcome is the body of published, refused and removed.
typeOutcomestruct{
// the source commit it was built from
Commitstring`json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digeststring`json:"digest"`
// the build's fingerprint
Fingerprintstring`json:"fingerprint,omitempty"`
// the module holding the seat that said it
Holderstring`json:"holder"`
// what it is
Kindstring`json:"kind"`
// the Go module path a Go package is fetched under, equal to name for a Go package (go-package-registry's published); empty for every other kind of artifact
Modulestring`json:"module,omitempty"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Namestring`json:"name"`
// why: a refusal's cause, a removal's (retention, tag-gone, by-hand), or why a removal was kept (shared-digest)
Reasonstring`json:"reason,omitempty"`
// the reference the seat answers: <registry>/<module>/<artifact>@sha256:<digest>, or <name>@<version> for a package (ADR 0605 §9)
Referencestring`json:"reference,omitempty"`
// the tag it carries, for a tagged version
Tagstring`json:"tag,omitempty"`
// for kept: the other tags still naming its digest
Tags[]string`json:"tags,omitempty"`
// the transfer it ends, when it ended one
Transferstring`json:"transfer,omitempty"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Versionstring`json:"version,omitempty"`
}
// The values of Outcome's kind.
const(
OutcomeKindPackage="package"
OutcomeKindImage="image"
OutcomeKindBundle="bundle"
OutcomeKindArchive="archive"
OutcomeKindUpstream="upstream"
)
// Part is one part of a transfer.
typePartstruct{
// the part's digest, sha256:<hex>: an image's layer or config, a package's file, a bundle's blob
Digeststring`json:"digest"`
// its size in bytes
Sizeint64`json:"size"`
}
// Repository is a type of the contract.
typeRepositorystruct{
// each manifest it holds, by digest
Manifests[]Listed`json:"manifests"`
// the repository
Namestring`json:"name"`
}
// PublishInput is what publish takes.
typePublishInputstruct{
// the source commit it was built from
Commitstring`json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digeststring`json:"digest"`
// the build's fingerprint
Fingerprintstring`json:"fingerprint,omitempty"`
// what it is
Kindstring`json:"kind"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Namestring`json:"name"`
// every part's digest and size; none when the digest is already held
Parts[]Part`json:"parts,omitempty"`
// the tag it carries, for a tagged version
Tagstring`json:"tag,omitempty"`
// the transfer's name, the caller's own; the same name opens the same transfer again
Transferstring`json:"transfer"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Versionstring`json:"version,omitempty"`
}
// The values of PublishInput's kind.
const(
PublishInputKindPackage="package"
PublishInputKindImage="image"
PublishInputKindBundle="bundle"
PublishInputKindArchive="archive"
PublishInputKindUpstream="upstream"
)
// PublishAnswer is what publish answers.
typePublishAnswerstruct{
// the digest is held already: nothing to send; the outcome follows as an event
Heldbool`json:"held,omitempty"`
// the digests of the parts the holder lacks, to send by publish-part
Lacks[]string`json:"lacks,omitempty"`
// the transfer
Transferstring`json:"transfer"`
}
// PublishPartInput is what publish-part takes.
typePublishPartInputstruct{
// the chunk's bytes, base64 (at most 760 KiB before encoding)
Datastring`json:"data"`
// this chunk is the part's last
Lastbool`json:"last"`
// the part's digest
Partstring`json:"part"`
// the chunk's place in its part, from 0
Sequenceint64`json:"sequence"`
// the transfer
Transferstring`json:"transfer"`
}
// PublishPartAnswer is what publish-part answers.
typePublishPartAnswerstruct{
// the part is whole and its bytes match its digest
Completebool`json:"complete,omitempty"`
// the part
Partstring`json:"part"`
// the chunks of the part held so far
Receivedint64`json:"received,omitempty"`
// the transfer
Transferstring`json:"transfer"`
}
// VersionsInput is what versions takes.
typeVersionsInputstruct{
// narrowed to one kind (optional)
Kindstring`json:"kind,omitempty"`
// the name
Namestring`json:"name"`
}
// VersionsAnswer is what versions answers.
typeVersionsAnswerstruct{
// the name
Namestring`json:"name"`
// newest first
Versions[]Artifact`json:"versions"`
}
// RemoveInput is what remove takes.
typeRemoveInputstruct{
// the digest (for a bundle, archive or copied base)
Digeststring`json:"digest,omitempty"`
// the name
Namestring`json:"name"`
// why it goes
Reasonstring`json:"reason"`
// the tag (for a tagged version)
Tagstring`json:"tag,omitempty"`
// the version
Versionstring`json:"version,omitempty"`
}
// The values of RemoveInput's reason.
const(
RemoveInputReasonTagGone="tag-gone"
RemoveInputReasonRetention="retention"
)
// RemoveAnswer is what remove answers.
typeRemoveAnswerstruct{
Artifact*Artifact`json:"artifact,omitempty"`
// it stays whole, its tag and its bytes: the store cannot remove the tag alone while another tag names its digest (reason, tags)
Keptbool`json:"kept,omitempty"`
// why it was kept: shared-digest, another tag names its digest
Reasonstring`json:"reason,omitempty"`
// it is gone
Removedbool`json:"removed"`
// the other tags still naming its digest, when kept
Tags[]string`json:"tags,omitempty"`
}
// The values of RemoveAnswer's reason.
const(
RemoveAnswerReasonSharedDigest="shared-digest"
)
// MirrorInput is what mirror takes.
typeMirrorInputstruct{
// its pinned digest, sha256:<hex>
Digeststring`json:"digest"`
// the name it is kept under
Namestring`json:"name"`
// the outside image's reference
Sourcestring`json:"source"`
}
// MirrorAnswer is what mirror answers.
typeMirrorAnswerstruct{
// the digest stored
Digeststring`json:"digest"`
// the reference the seat answers
Referencestring`json:"reference"`
}
// TagsInput is what tags takes.
typeTagsInputstruct{
// the image
Namestring`json:"name"`
}
// TagsAnswerTagsItem is a type of the contract.
typeTagsAnswerTagsItemstruct{
// its digest
Digeststring`json:"digest"`
// the tag
Tagstring`json:"tag"`
}
// TagsAnswer is what tags answers.
typeTagsAnswerstruct{
// the image
Namestring`json:"name"`
// every tag
Tags[]TagsAnswerTagsItem`json:"tags"`
}
// HoldInput is what hold takes.
typeHoldInputstruct{
// the digest
Digeststring`json:"digest"`
// the name
Namestring`json:"name"`
// which of the sweep's rules keeps it
Reasonstring`json:"reason"`
}
// HoldAnswer is what hold answers.
typeHoldAnswerstruct{
// it is held
Heldbool`json:"held"`
// when the hold began, RFC 3339
Sincestring`json:"since,omitempty"`
}
// ReleaseInput is what release takes.
typeReleaseInputstruct{
// the digest
Digeststring`json:"digest"`
// the name
Namestring`json:"name"`
// why it is let go
Reasonstring`json:"reason"`
}
// ReleaseAnswer is what release answers.
typeReleaseAnswerstruct{
// a hold was let go; false when there was none
Releasedbool`json:"released"`
}
// ListInput is what list takes.
typeListInputstruct{
// the repository, <module>/<artifact>; every repository of the seat when not given
Namestring`json:"name,omitempty"`
}
// ListAnswer is what list answers.
typeListAnswerstruct{
// each repository named, in order of its name
Repositories[]Repository`json:"repositories"`
}
// PublishedEvent is the body of the event published.
typePublishedEvent=Outcome
// RefusedEvent is the body of the event refused.
typeRefusedEvent=Outcome
// RemovedEvent is the body of the event removed.
typeRemovedEvent=Outcome
// KeptEvent is the body of the event kept.
typeKeptEvent=Outcome
// HeldEvent is the body of the event held.
typeHeldEvent=Hold
// ReleasedEvent is the body of the event released.
typeReleasedEvent=Hold
// HoldsBySeatNameDigestValue is one value of the state holds under the key <seat>.<name>.<digest>.
typeHoldsBySeatNameDigestValuestruct{
Bystring`json:"by"`
Digeststring`json:"digest"`
Kindstring`json:"kind"`
Namestring`json:"name"`
Seatstring`json:"seat"`
// when (RFC 3339 time)
Sincestring`json:"since"`
Whystring`json:"why,omitempty"`
}
// WindowsByCallerValueDroppedItem is a type of the contract.
typeWindowsByCallerValueDroppedItemstruct{
// when (RFC 3339 time)
Atstring`json:"at,omitempty"`
Bystring`json:"by,omitempty"`
Nodestring`json:"node"`
Whystring`json:"why,omitempty"`
}
// WindowsByCallerValue is one value of the state windows under the key <caller>.
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
packagecontainerimageregistry
import(
"encoding/json"
"reflect"
"regexp"
"testing"
)
// TestFixtures reads every fixture of seats/container-image-registry/fixtures: each decodes into its type, a field the type does not
// know is dropped (ADR 0608 §6), and it reads back as its wire says; each subject named is the contract's.
funcTestFixtures(t*testing.T){
cases:=[]struct{
name,subject,given,wirestring
decodefunc([]byte)(any,error)
subjectIs*regexp.Regexp
}{
{name:"published on the seat's subject",subject:"mesh.seat.container-image-registry.event.published",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"image\",\"name\":\"mesh-sdk\",\"reference\":\"container-image-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"image\",\"name\":\"mesh-sdk\",\"reference\":\"container-image-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
{name:"refused on the seat's subject",subject:"mesh.seat.container-image-registry.event.refused",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"image\",\"name\":\"mesh-sdk\",\"reason\":\"retention\",\"reference\":\"container-image-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"image\",\"name\":\"mesh-sdk\",\"reason\":\"retention\",\"reference\":\"container-image-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
{name:"removed on the seat's subject",subject:"mesh.seat.container-image-registry.event.removed",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"image\",\"name\":\"mesh-sdk\",\"reason\":\"retention\",\"reference\":\"container-image-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"image\",\"name\":\"mesh-sdk\",\"reason\":\"retention\",\"reference\":\"container-image-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
{name:"kept on the seat's subject: a tagged version sharing its digest stays, naming the tags on it",subject:"mesh.seat.container-image-registry.event.kept",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"image\",\"name\":\"mesh-sdk\",\"reason\":\"shared-digest\",\"reference\":\"container-image-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"tag\":\"0.1.19-feat-x.2\",\"tags\":[\"0.1.19\"],\"version\":\"0.1.19-feat-x.2\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"image\",\"name\":\"mesh-sdk\",\"reason\":\"shared-digest\",\"reference\":\"container-image-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"tag\":\"0.1.19-feat-x.2\",\"tags\":[\"0.1.19\"],\"version\":\"0.1.19-feat-x.2\"}",
{name:"held on the seat's subject",subject:"mesh.seat.container-image-registry.event.held",given:"{\"at\":\"2026-11-04T12:00:00Z\",\"by\":\"mesh-artifact-sweep\",\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"holder\":\"distribution\",\"name\":\"mesh-sdk\",\"reason\":\"kept by the sweep's rule\"}",wire:"{\"at\":\"2026-11-04T12:00:00Z\",\"by\":\"mesh-artifact-sweep\",\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"holder\":\"distribution\",\"name\":\"mesh-sdk\",\"reason\":\"kept by the sweep's rule\"}",
{name:"released on the seat's subject",subject:"mesh.seat.container-image-registry.event.released",given:"{\"at\":\"2026-11-04T12:00:00Z\",\"by\":\"mesh-artifact-sweep\",\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"holder\":\"distribution\",\"name\":\"mesh-sdk\",\"reason\":\"kept by the sweep's rule\"}",wire:"{\"at\":\"2026-11-04T12:00:00Z\",\"by\":\"mesh-artifact-sweep\",\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"holder\":\"distribution\",\"name\":\"mesh-sdk\",\"reason\":\"kept by the sweep's rule\"}",
{name:"an open window",subject:"",given:"{\"holding\":[\"ace\"],\"name\":\"mesh-delivery-builder\",\"open\":true,\"since\":{\"ace\":\"2026-11-05T10:00:00Z\"}}",wire:"{\"holding\":[\"ace\"],\"name\":\"mesh-delivery-builder\",\"open\":true,\"since\":{\"ace\":\"2026-11-05T10:00:00Z\"}}",
{name:"publish opens a transfer",subject:"",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"image\",\"name\":\"mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"image\",\"name\":\"mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
{name:"a field the reader does not know is dropped",subject:"",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"image\",\"later\":{\"x\":1},\"name\":\"mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"image\",\"name\":\"mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
{name:"publish answers what it lacks",subject:"",given:"{\"lacks\":[\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"transfer\":\"t1\"}",wire:"{\"lacks\":[\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"transfer\":\"t1\"}",
{name:"a chunk of a part",subject:"",given:"{\"data\":\"aGVsbG8=\",\"last\":true,\"part\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"sequence\":0,\"transfer\":\"t1\"}",wire:"{\"data\":\"aGVsbG8=\",\"last\":true,\"part\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"sequence\":0,\"transfer\":\"t1\"}",
{name:"a tagged version sharing its digest with another tag is kept, not removed",subject:"",given:"{\"kept\":true,\"reason\":\"shared-digest\",\"removed\":false,\"tags\":[\"0.1.19\"]}",wire:"{\"kept\":true,\"reason\":\"shared-digest\",\"removed\":false,\"tags\":[\"0.1.19\"]}",
{name:"list answers an index with its platforms, its tag and its hold",subject:"",given:"{\"repositories\":[{\"manifests\":[{\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"held\":false,\"index\":true,\"platforms\":[\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"size\":2048,\"tags\":[\"3\"]},{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"held\":false,\"index\":false,\"size\":1024}],\"name\":\"mail/server\"}]}",wire:"{\"repositories\":[{\"manifests\":[{\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"held\":false,\"index\":true,\"platforms\":[\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"size\":2048,\"tags\":[\"3\"]},{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"held\":false,\"index\":false,\"size\":1024}],\"name\":\"mail/server\"}]}",
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package gopackageregistry is the contract of the seat "go-package-registry", defined whole (seats/go-package-registry/seat.json): The mesh's Go modules: Go's module proxy protocol's read side, and publishing over the bus.
packagegopackageregistry
// Seat is the seat's name.
constSeat="go-package-registry"
const(
VerbPublish="publish"
VerbPublishPart="publish-part"
VerbVersions="versions"
VerbRemove="remove"
)
const(
EventPublished="published"
EventRefused="refused"
EventRemoved="removed"
EventKept="kept"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
// Artifact is one published thing, as every registry event and answer names it.
typeArtifactstruct{
// the source commit it was built from
Commitstring`json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digeststring`json:"digest"`
// the build's fingerprint
Fingerprintstring`json:"fingerprint,omitempty"`
// what it is
Kindstring`json:"kind"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Namestring`json:"name"`
// the tag it carries, for a tagged version
Tagstring`json:"tag,omitempty"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Versionstring`json:"version,omitempty"`
}
// The values of Artifact's kind.
const(
ArtifactKindPackage="package"
ArtifactKindImage="image"
ArtifactKindBundle="bundle"
ArtifactKindArchive="archive"
ArtifactKindUpstream="upstream"
)
// Outcome is the body of published, refused and removed.
typeOutcomestruct{
// the source commit it was built from
Commitstring`json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digeststring`json:"digest"`
// the build's fingerprint
Fingerprintstring`json:"fingerprint,omitempty"`
// the module holding the seat that said it
Holderstring`json:"holder"`
// what it is
Kindstring`json:"kind"`
// the Go module path a Go package is fetched under, equal to name for a Go package (go-package-registry's published); empty for every other kind of artifact
Modulestring`json:"module,omitempty"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Namestring`json:"name"`
// why: a refusal's cause, a removal's (retention, tag-gone, by-hand), or why a removal was kept (shared-digest)
Reasonstring`json:"reason,omitempty"`
// the reference the seat answers: <registry>/<module>/<artifact>@sha256:<digest>, or <name>@<version> for a package (ADR 0605 §9)
Referencestring`json:"reference,omitempty"`
// the tag it carries, for a tagged version
Tagstring`json:"tag,omitempty"`
// for kept: the other tags still naming its digest
Tags[]string`json:"tags,omitempty"`
// the transfer it ends, when it ended one
Transferstring`json:"transfer,omitempty"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Versionstring`json:"version,omitempty"`
}
// The values of Outcome's kind.
const(
OutcomeKindPackage="package"
OutcomeKindImage="image"
OutcomeKindBundle="bundle"
OutcomeKindArchive="archive"
OutcomeKindUpstream="upstream"
)
// Part is one part of a transfer.
typePartstruct{
// the part's digest, sha256:<hex>: an image's layer or config, a package's file, a bundle's blob
Digeststring`json:"digest"`
// its size in bytes
Sizeint64`json:"size"`
}
// PublishInput is what publish takes.
typePublishInputstruct{
// the source commit it was built from
Commitstring`json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digeststring`json:"digest"`
// the build's fingerprint
Fingerprintstring`json:"fingerprint,omitempty"`
// what it is
Kindstring`json:"kind"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Namestring`json:"name"`
// every part's digest and size; none when the digest is already held
Parts[]Part`json:"parts,omitempty"`
// the tag it carries, for a tagged version
Tagstring`json:"tag,omitempty"`
// the transfer's name, the caller's own; the same name opens the same transfer again
Transferstring`json:"transfer"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Versionstring`json:"version,omitempty"`
}
// The values of PublishInput's kind.
const(
PublishInputKindPackage="package"
PublishInputKindImage="image"
PublishInputKindBundle="bundle"
PublishInputKindArchive="archive"
PublishInputKindUpstream="upstream"
)
// PublishAnswer is what publish answers.
typePublishAnswerstruct{
// the digest is held already: nothing to send; the outcome follows as an event
Heldbool`json:"held,omitempty"`
// the digests of the parts the holder lacks, to send by publish-part
Lacks[]string`json:"lacks,omitempty"`
// the transfer
Transferstring`json:"transfer"`
}
// PublishPartInput is what publish-part takes.
typePublishPartInputstruct{
// the chunk's bytes, base64 (at most 760 KiB before encoding)
Datastring`json:"data"`
// this chunk is the part's last
Lastbool`json:"last"`
// the part's digest
Partstring`json:"part"`
// the chunk's place in its part, from 0
Sequenceint64`json:"sequence"`
// the transfer
Transferstring`json:"transfer"`
}
// PublishPartAnswer is what publish-part answers.
typePublishPartAnswerstruct{
// the part is whole and its bytes match its digest
Completebool`json:"complete,omitempty"`
// the part
Partstring`json:"part"`
// the chunks of the part held so far
Receivedint64`json:"received,omitempty"`
// the transfer
Transferstring`json:"transfer"`
}
// VersionsInput is what versions takes.
typeVersionsInputstruct{
// narrowed to one kind (optional)
Kindstring`json:"kind,omitempty"`
// the name
Namestring`json:"name"`
}
// VersionsAnswer is what versions answers.
typeVersionsAnswerstruct{
// the name
Namestring`json:"name"`
// newest first
Versions[]Artifact`json:"versions"`
}
// RemoveInput is what remove takes.
typeRemoveInputstruct{
// the digest (for a bundle, archive or copied base)
Digeststring`json:"digest,omitempty"`
// the name
Namestring`json:"name"`
// why it goes
Reasonstring`json:"reason"`
// the tag (for a tagged version)
Tagstring`json:"tag,omitempty"`
// the version
Versionstring`json:"version,omitempty"`
}
// The values of RemoveInput's reason.
const(
RemoveInputReasonTagGone="tag-gone"
RemoveInputReasonRetention="retention"
)
// RemoveAnswer is what remove answers.
typeRemoveAnswerstruct{
Artifact*Artifact`json:"artifact,omitempty"`
// it stays whole, its tag and its bytes: the store cannot remove the tag alone while another tag names its digest (reason, tags)
Keptbool`json:"kept,omitempty"`
// why it was kept: shared-digest, another tag names its digest
Reasonstring`json:"reason,omitempty"`
// it is gone
Removedbool`json:"removed"`
// the other tags still naming its digest, when kept
Tags[]string`json:"tags,omitempty"`
}
// The values of RemoveAnswer's reason.
const(
RemoveAnswerReasonSharedDigest="shared-digest"
)
// PublishedEvent is the body of the event published.
typePublishedEvent=Outcome
// RefusedEvent is the body of the event refused.
typeRefusedEvent=Outcome
// RemovedEvent is the body of the event removed.
typeRemovedEvent=Outcome
// KeptEvent is the body of the event kept.
typeKeptEvent=Outcome
// GoPackageRegistryForm is the form of the provision go-package-registry.
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
packagegopackageregistry
import(
"encoding/json"
"reflect"
"regexp"
"testing"
)
// TestFixtures reads every fixture of seats/go-package-registry/fixtures: each decodes into its type, a field the type does not
// know is dropped (ADR 0608 §6), and it reads back as its wire says; each subject named is the contract's.
funcTestFixtures(t*testing.T){
cases:=[]struct{
name,subject,given,wirestring
decodefunc([]byte)(any,error)
subjectIs*regexp.Regexp
}{
{name:"published on the seat's subject",subject:"mesh.seat.go-package-registry.event.published",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"module\":\"git.novox.be/novox/mesh-sdk/go\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"reference\":\"git.novox.be/novox/mesh-sdk/go@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"module\":\"git.novox.be/novox/mesh-sdk/go\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"reference\":\"git.novox.be/novox/mesh-sdk/go@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
{name:"refused on the seat's subject",subject:"mesh.seat.go-package-registry.event.refused",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"reason\":\"retention\",\"reference\":\"git.novox.be/novox/mesh-sdk/go@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"reason\":\"retention\",\"reference\":\"git.novox.be/novox/mesh-sdk/go@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
{name:"removed on the seat's subject",subject:"mesh.seat.go-package-registry.event.removed",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"reason\":\"retention\",\"reference\":\"git.novox.be/novox/mesh-sdk/go@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"reason\":\"retention\",\"reference\":\"git.novox.be/novox/mesh-sdk/go@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
{name:"kept on the seat's subject: a tagged version sharing its digest stays, naming the tags on it",subject:"mesh.seat.go-package-registry.event.kept",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"reason\":\"shared-digest\",\"reference\":\"git.novox.be/novox/mesh-sdk/go@0.1.19\",\"tag\":\"0.1.19-feat-x.2\",\"tags\":[\"0.1.19\"],\"version\":\"0.1.19-feat-x.2\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"reason\":\"shared-digest\",\"reference\":\"git.novox.be/novox/mesh-sdk/go@0.1.19\",\"tag\":\"0.1.19-feat-x.2\",\"tags\":[\"0.1.19\"],\"version\":\"0.1.19-feat-x.2\"}",
{name:"publish opens a transfer",subject:"",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
{name:"a field the reader does not know is dropped",subject:"",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"later\":{\"x\":1},\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
{name:"publish answers what it lacks",subject:"",given:"{\"lacks\":[\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"transfer\":\"t1\"}",wire:"{\"lacks\":[\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"transfer\":\"t1\"}",
{name:"a chunk of a part",subject:"",given:"{\"data\":\"aGVsbG8=\",\"last\":true,\"part\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"sequence\":0,\"transfer\":\"t1\"}",wire:"{\"data\":\"aGVsbG8=\",\"last\":true,\"part\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"sequence\":0,\"transfer\":\"t1\"}",
{name:"a tagged version sharing its digest with another tag is kept, not removed",subject:"",given:"{\"kept\":true,\"reason\":\"shared-digest\",\"removed\":false,\"tags\":[\"0.1.19\"]}",wire:"{\"kept\":true,\"reason\":\"shared-digest\",\"removed\":false,\"tags\":[\"0.1.19\"]}",
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
packagemeshartifactsweep
import(
"encoding/json"
"reflect"
"regexp"
"testing"
)
// TestFixtures reads every fixture of seats/mesh-artifact-sweep/fixtures: each decodes into its type, a field the type does not
// know is dropped (ADR 0608 §6), and it reads back as its wire says; each subject named is the contract's.
funcTestFixtures(t*testing.T){
cases:=[]struct{
name,subject,given,wirestring
decodefunc([]byte)(any,error)
subjectIs*regexp.Regexp
}{
{name:"artifacts-gone on the seat's subject",subject:"mesh.seat.mesh-artifact-sweep.event.artifacts-gone",given:"{\"at\":\"2026-11-05T15:04:05Z\",\"event\":\"artifacts-gone\",\"fingerprint\":\"f1\",\"gone\":[\"artifact-store://ca-trust/archive/blobs/sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"artifact-store://ca-trust/archive/blobs/sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"key\":\"ca-trust.archive.f1\",\"module\":\"ca-trust\"}",wire:"{\"at\":\"2026-11-05T15:04:05Z\",\"event\":\"artifacts-gone\",\"fingerprint\":\"f1\",\"gone\":[\"artifact-store://ca-trust/archive/blobs/sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"artifact-store://ca-trust/archive/blobs/sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"key\":\"ca-trust.archive.f1\",\"module\":\"ca-trust\"}",
{name:"held asks the references",subject:"",given:"{\"references\":[\"artifact-store://ca-trust/archive/blobs/sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"artifact-store://ca-trust/archive/blobs/sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"artifact-store://ca-trust/archive/blobs/sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\"]}",wire:"{\"references\":[\"artifact-store://ca-trust/archive/blobs/sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"artifact-store://ca-trust/archive/blobs/sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"artifact-store://ca-trust/archive/blobs/sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\"]}",
{name:"held answers held, gone and unknown",subject:"",given:"{\"gone\":[\"artifact-store://ca-trust/archive/blobs/sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"held\":[\"artifact-store://ca-trust/archive/blobs/sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"],\"store\":\"store.test:5100\",\"unknown\":{\"artifact-store://ca-trust/archive/blobs/sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\":\"the store answered 503\"}}",wire:"{\"gone\":[\"artifact-store://ca-trust/archive/blobs/sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"held\":[\"artifact-store://ca-trust/archive/blobs/sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"],\"store\":\"store.test:5100\",\"unknown\":{\"artifact-store://ca-trust/archive/blobs/sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\":\"the store answered 503\"}}",
{name:"held answers with nothing unknown",subject:"",given:"{\"gone\":[],\"held\":[],\"store\":\"store.test:5100\"}",wire:"{\"gone\":[],\"held\":[],\"store\":\"store.test:5100\"}",
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package meshcatalog is the contract of the seat "mesh-catalog", defined whole (seats/mesh-catalog/seat.json): The catalog of the mesh: every module the trunk holds with its manifest, fingerprint and verdict, the packages published, and the seat list (ADR 0636 §1, §4).
// ParseManifestsByDigestKey reads the parts of a key of the form "<digest>", in the order of the form; the last result is false for a key of another form.
// DecodeManifestsByDigestValue reads one value of the state manifests under the form "<digest>", refusing a field ManifestsByDigestValue does not know and any text after the value.
// ParseModulesByModuleKey reads the parts of a key of the form "<module>", in the order of the form; the last result is false for a key of another form.
// DecodeModulesByModuleValue reads one value of the state modules under the form "<module>", refusing a field ModulesByModuleValue does not know and any text after the value.
// ParseCandidatesByGroupKey reads the parts of a key of the form "<group>", in the order of the form; the last result is false for a key of another form.
// DecodeCandidatesByGroupValue reads one value of the state candidates under the form "<group>", refusing a field CandidatesByGroupValue does not know and any text after the value.
// ParseVerdictsByDigestKey reads the parts of a key of the form "<digest>", in the order of the form; the last result is false for a key of another form.
// DecodeVerdictsByDigestValue reads one value of the state verdicts under the form "<digest>", refusing a field VerdictsByDigestValue does not know and any text after the value.
// PredefinedByListKey is the key of one value of the state predefined under the form "list".
funcPredefinedByListKey()string{return"list"}
// ParsePredefinedByListKey reads the parts of a key of the form "list", in the order of the form; the last result is false for a key of another form.
funcParsePredefinedByListKey(keystring)bool{
rest:=key
if!strings.HasPrefix(rest,"list"){
returnfalse
}
rest=rest[4:]
ifrest!=""{
returnfalse
}
returntrue
}
// DecodePredefinedByListValue reads one value of the state predefined under the form "list", refusing a field PredefinedByListValue does not know and any text after the value.
// ParseConfigCandidatesByPullKey reads the parts of a key of the form "<pull>", in the order of the form; the last result is false for a key of another form.
// DecodeConfigCandidatesByPullValue reads one value of the state config-candidates under the form "<pull>", refusing a field ConfigCandidatesByPullValue does not know and any text after the value.
// ParsePackagesByModuleKey reads the parts of a key of the form "<module>", in the order of the form; the last result is false for a key of another form.
// DecodePackagesByModuleValue reads one value of the state packages under the form "<module>", refusing a field PackagesByModuleValue does not know and any text after the value.
// ParsePackagesByPackageSeriesKey reads the parts of a key of the form "<package>.<series>", in the order of the form; the last result is false for a key of another form.
// DecodePackagesByPackageSeriesValue reads one value of the state packages under the form "<package>.<series>", refusing a field PackagesByPackageSeriesValue does not know and any text after the value.
{name:"a module (xclip, read through mesh-catalog.modules; the inputs and toolchains no tool reads are not here)",subject:"",given:"{\"commit\":\"f469eb387a3015569d9b16c66ed418e9dd098f64\",\"fp2\":\"src2:b427bdde1f100e2f52490cfa9df0c5112dd3700226b4892349f0c14a15a4af56\",\"path\":\"modules/xclip\",\"repository\":\"novox/mesh-catalog\",\"v\":1}",wire:"{\"commit\":\"f469eb387a3015569d9b16c66ed418e9dd098f64\",\"fp2\":\"src2:b427bdde1f100e2f52490cfa9df0c5112dd3700226b4892349f0c14a15a4af56\",\"path\":\"modules/xclip\",\"repository\":\"novox/mesh-catalog\",\"v\":1}",
{name:"a refused verdict (nats, read through the indexer's verdicts tool)",subject:"",given:"{\"at\":\"2026-11-04T18:51:12.614583047+01:00\",\"judge\":\"exe:661e6fb424d7ffea\",\"module\":\"nats\",\"problems\":[\"this is not a module manifest: a state is either a name or {name, history, ttl-seconds, per-machine, key-ttl}: json: unknown field \\\"read-only\\\" (read without state[2].read-only)\"],\"state\":\"refused\"}",wire:"{\"at\":\"2026-11-04T18:51:12.614583047+01:00\",\"judge\":\"exe:661e6fb424d7ffea\",\"module\":\"nats\",\"problems\":[\"this is not a module manifest: a state is either a name or {name, history, ttl-seconds, per-machine, key-ttl}: json: unknown field \\\"read-only\\\" (read without state[2].read-only)\"],\"state\":\"refused\"}",
{name:"a pull request's configuration state whose bounds are declared 0 (a zero is a bound, not none)",subject:"",given:"{\"declares\":{\"nats\":{\"limit\":{\"default\":0,\"kind\":\"setting\",\"maximum\":0,\"minimum\":0,\"why\":\"a bound\"}}},\"head\":\"cccccccccccccccccccccccccccccccccccccccc\",\"pull\":\"novox/mesh-catalog#1\",\"v\":1}",wire:"{\"declares\":{\"nats\":{\"limit\":{\"default\":0,\"kind\":\"setting\",\"maximum\":0,\"minimum\":0,\"why\":\"a bound\"}}},\"head\":\"cccccccccccccccccccccccccccccccccccccccc\",\"pull\":\"novox/mesh-catalog#1\",\"v\":1}",
decode:func(b[]byte)(any,error){
varvConfigCandidatesByPullValue
err:=json.Unmarshal(b,&v)
returnv,err
},subjectIs:nil},
{name:"a published Go module",subject:"",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"module\":\"git.novox.be/novox/mesh-sdk/go\",\"packages\":[{\"digest\":\"ab\",\"package\":\"git.novox.be/novox/mesh-sdk/go/keys\"}],\"repository\":\"novox/mesh-sdk\",\"v\":1}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"module\":\"git.novox.be/novox/mesh-sdk/go\",\"packages\":[{\"digest\":\"ab\",\"package\":\"git.novox.be/novox/mesh-sdk/go/keys\"}],\"repository\":\"novox/mesh-sdk\",\"v\":1}",
{name:"a module with its toolchain",subject:"",given:"{\"commit\":\"f469eb387a3015569d9b16c66ed418e9dd098f64\",\"fp2\":\"src2:b427bdde1f100e2f52490cfa9df0c5112dd3700226b4892349f0c14a15a4af56\",\"repository\":\"novox/mesh-catalog\",\"toolchains\":{\"go\":{\"language\":\"go\",\"recipe\":\"1\",\"version\":\"1.26.0\"}},\"v\":1}",wire:"{\"commit\":\"f469eb387a3015569d9b16c66ed418e9dd098f64\",\"fp2\":\"src2:b427bdde1f100e2f52490cfa9df0c5112dd3700226b4892349f0c14a15a4af56\",\"repository\":\"novox/mesh-catalog\",\"toolchains\":{\"go\":{\"language\":\"go\",\"recipe\":\"1\",\"version\":\"1.26.0\"}},\"v\":1}",
{name:"the modules verb (captured: the first three modules)",subject:"",given:"{\"modules\":[{\"commit\":\"f469eb387a3015569d9b16c66ed418e9dd098f64\",\"fp\":\"src2:5e4a1b4ad4ea6175c05e4655ce58aeb957547149d4c9805eb27636efd50c1c87\",\"module\":\"adwaita\",\"path\":\"modules/adwaita\",\"repository\":\"novox/mesh-catalog\"},{\"commit\":\"b112adcecc41d18f54190cbd2fc864199b70c518\",\"fp\":\"src2:7dd0db8e98224f46121a5ae05c0b9c5a430eff531a5120aa40b1a59237853a3f\",\"module\":\"amqp-email-forwarder\",\"path\":\".\",\"repository\":\"jschoubben/amqp-email-forwarder\"},{\"commit\":\"dd458cb155f5f5fa3ed824a23728e444be5b156a\",\"fp\":\"src2:a98f8152f0a837dd5ba883a15efaf110ba88100193157e4bdb1a93ba55209371\",\"module\":\"artifact-store-tools\",\"path\":\"modules/artifact-store-tools\",\"repository\":\"novox/mesh-catalog\"}]}",wire:"{\"modules\":[{\"commit\":\"f469eb387a3015569d9b16c66ed418e9dd098f64\",\"fp\":\"src2:5e4a1b4ad4ea6175c05e4655ce58aeb957547149d4c9805eb27636efd50c1c87\",\"module\":\"adwaita\",\"path\":\"modules/adwaita\",\"repository\":\"novox/mesh-catalog\"},{\"commit\":\"b112adcecc41d18f54190cbd2fc864199b70c518\",\"fp\":\"src2:7dd0db8e98224f46121a5ae05c0b9c5a430eff531a5120aa40b1a59237853a3f\",\"module\":\"amqp-email-forwarder\",\"path\":\".\",\"repository\":\"jschoubben/amqp-email-forwarder\"},{\"commit\":\"dd458cb155f5f5fa3ed824a23728e444be5b156a\",\"fp\":\"src2:a98f8152f0a837dd5ba883a15efaf110ba88100193157e4bdb1a93ba55209371\",\"module\":\"artifact-store-tools\",\"path\":\"modules/artifact-store-tools\",\"repository\":\"novox/mesh-catalog\"}]}",
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package meshdelivery is the contract of the seat "mesh-delivery", defined whole (seats/mesh-delivery/seat.json): The delivery gate: reads and steers deliveries, merges and the checks that decide them; the merge is made on the operator's Approve once both checks passed.
packagemeshdelivery
import(
"bytes"
"encoding/json"
"errors"
"strings"
"time"
)
// Seat is the seat's name.
constSeat="mesh-delivery"
const(
VerbDeliveries="deliveries"
VerbTimes="times"
VerbShow="show"
VerbGroups="groups"
VerbWhatIf="what-if"
VerbChecks="checks"
VerbTable="table"
VerbStalled="stalled"
VerbRecheck="recheck"
VerbRelease="release"
VerbStop="stop"
VerbClose="close"
VerbRetireHistory="retire-history"
VerbSettle="settle"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
// SourceByMainKey is the key of one value of the state source under the form "main".
funcSourceByMainKey()string{return"main"}
// ParseSourceByMainKey reads the parts of a key of the form "main", in the order of the form; the last result is false for a key of another form.
funcParseSourceByMainKey(keystring)bool{
rest:=key
if!strings.HasPrefix(rest,"main"){
returnfalse
}
rest=rest[4:]
ifrest!=""{
returnfalse
}
returntrue
}
// DecodeSourceByMainValue reads one value of the state source under the form "main", refusing a field SourceByMainValue does not know and any text after the value.
// DecodeMergesByGroupValue reads one value of the state merges under the form "<group>", refusing a field MergesByGroupValue does not know and any text after the value.
// ParseAsksByMergeGroupHeadsKey reads the parts of a key of the form "merge.<group>.<heads>", in the order of the form; the last result is false for a key of another form.
// DecodeAsksByMergeGroupHeadsValue reads one value of the state asks under the form "merge.<group>.<heads>", refusing a field AsksByMergeGroupHeadsValue does not know and any text after the value.
// ParseOwedByRepositoryNumberHeadActKey reads the parts of a key of the form "<repository>.<number>.<head>.<act>", in the order of the form; the last result is false for a key of another form.
// DecodeOwedByRepositoryNumberHeadActValue reads one value of the state owed under the form "<repository>.<number>.<head>.<act>", refusing a field OwedByRepositoryNumberHeadActValue does not know and any text after the value.
// ParseTurnsByRepositoryKey reads the parts of a key of the form "<repository>", in the order of the form; the last result is false for a key of another form.
// DecodeTurnsByRepositoryValue reads one value of the state turns under the form "<repository>", refusing a field TurnsByRepositoryValue does not know and any text after the value.
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package meshdeliverychecker is the contract of the seat "mesh-delivery-checker", defined whole (seats/mesh-delivery-checker/seat.json): The merge check's tries: start one, read one, end one. The checker's own events stay under its own subjects (ADR 0620 §2).
packagemeshdeliverychecker
import(
"bytes"
"encoding/json"
"errors"
"strings"
)
// Seat is the seat's name.
constSeat="mesh-delivery-checker"
const(
VerbTry="try"
VerbTryRead="try-read"
VerbTryEnd="try-end"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
funcVerbs()[]string{
return[]string{VerbTry,VerbTryRead,VerbTryEnd}
}
// The holder's own events, listed beside the seat and published under the holder's subjects (ADR 0620 §2).
const(
HolderEventVerdict="verdict"
HolderEventTagWanted="tag-wanted"
HolderEventPreviewWritten="preview.written"
)
// HolderSubjectVerdict is where the holder publishes verdict, kept in checker.asks.
// ParseVerdictsByGroupHeadsKey reads the parts of a key of the form "<group>.<heads>", in the order of the form; the last result is false for a key of another form.
// DecodeVerdictsByGroupHeadsValue reads one value of the state verdicts under the form "<group>.<heads>", refusing a field VerdictsByGroupHeadsValue does not know and any text after the value.
// ParseKeptByLevelDigestKey reads the parts of a key of the form "<level>.<digest>", in the order of the form; the last result is false for a key of another form.
// DecodeKeptByLevelDigestValue reads one value of the state kept under the form "<level>.<digest>", refusing a field KeptByLevelDigestValue does not know and any text after the value.
// ParseOwedByRepositoryNumberHeadActKey reads the parts of a key of the form "<repository>.<number>.<head>.<act>", in the order of the form; the last result is false for a key of another form.
// DecodeOwedByRepositoryNumberHeadActValue reads one value of the state owed under the form "<repository>.<number>.<head>.<act>", refusing a field OwedByRepositoryNumberHeadActValue does not know and any text after the value.
// ParsePreviewsByRepositoryHeadTrunkKey reads the parts of a key of the form "<repository>.<head>.<trunk>", in the order of the form; the last result is false for a key of another form.
// DecodePreviewsByRepositoryHeadTrunkValue reads one value of the state previews under the form "<repository>.<head>.<trunk>", refusing a field PreviewsByRepositoryHeadTrunkValue does not know and any text after the value.
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
packagemeshdeliverychecker
import(
"encoding/json"
"reflect"
"regexp"
"testing"
)
// TestFixtures reads every fixture of seats/mesh-delivery-checker/fixtures: each decodes into its type, a field the type does not
// know is dropped (ADR 0608 §6), and it reads back as its wire says; each subject named is the contract's.
funcTestFixtures(t*testing.T){
cases:=[]struct{
name,subject,given,wirestring
decodefunc([]byte)(any,error)
subjectIs*regexp.Regexp
}{
{name:"verdict on the checker's own family",subject:"mesh.stream.mesh-delivery-checker.event.verdict",given:"{\"head\":\"cccccccccccccccccccccccccccccccccccccccc\",\"out-of-step\":[\"go/seats/meshbroker/contract.go\"],\"pull\":3,\"repository\":\"novox/mesh-contracts\",\"series\":[{\"artifact\":\"go\",\"from\":\"0.1\",\"module\":\"mesh-contracts\",\"to\":\"0.2\"}],\"verdict\":\"fail\"}",wire:"{\"head\":\"cccccccccccccccccccccccccccccccccccccccc\",\"out-of-step\":[\"go/seats/meshbroker/contract.go\"],\"pull\":3,\"repository\":\"novox/mesh-contracts\",\"series\":[{\"artifact\":\"go\",\"from\":\"0.1\",\"module\":\"mesh-contracts\",\"to\":\"0.2\"}],\"verdict\":\"fail\"}",
{name:"tag-wanted on the checker's own family",subject:"mesh.stream.mesh-delivery-checker.event.tag-wanted",given:"{\"branch\":\"feat/registry\",\"head\":\"cccccccccccccccccccccccccccccccccccccccc\",\"module\":\"mesh-sdk\",\"package\":\"go\",\"pull\":170,\"repository\":\"novox/mesh-sdk\",\"tag\":\"registry-1966\"}",wire:"{\"branch\":\"feat/registry\",\"head\":\"cccccccccccccccccccccccccccccccccccccccc\",\"module\":\"mesh-sdk\",\"package\":\"go\",\"pull\":170,\"repository\":\"novox/mesh-sdk\",\"tag\":\"registry-1966\"}",
{name:"the status owed for a head",subject:"",given:"{\"act\":\"status=mesh/check\",\"context\":\"mesh/check\",\"state\":\"success\",\"v\":1}",wire:"{\"act\":\"status=mesh/check\",\"context\":\"mesh/check\",\"state\":\"success\",\"v\":1}",
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package meshwants is the contract of the seat "mesh-wants", defined whole (seats/mesh-wants/seat.json): The seat that says what each node should run and whether each module's new builds wait for a person (ADR 0565, ADR 0539).
packagemeshwants
import(
"bytes"
"encoding/json"
"errors"
"strings"
)
// Seat is the seat's name.
constSeat="mesh-wants"
const(
VerbUpgrade="upgrade"
VerbBus="bus"
)
const(
EventPolicyChanged="policy-changed"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
funcVerbs()[]string{
return[]string{VerbUpgrade,VerbBus}
}
// Events is every event published on the seat's subject: a new copy each call.
funcEvents()[]string{
return[]string{EventPolicyChanged}
}
// Family is where the seat's events are kept: the shared events stream, filtered to the seat's subjects.
const(
Family="mesh-wants.events"
FamilyMaxAgeDays=7
)
// SubjectPolicyChanged is where policy-changed is published.
// ParseWantsByWantNodeModuleKey reads the parts of a key of the form "want.<node>.<module>", in the order of the form; the last result is false for a key of another form.
// DecodeWantsByWantNodeModuleValue reads one value of the state wants under the form "want.<node>.<module>", refusing a field WantsByWantNodeModuleValue does not know and any text after the value.
// ParseWantsByWantNodeNodeKey reads the parts of a key of the form "want.<node>.node", in the order of the form; the last result is false for a key of another form.
// DecodeWantsByWantNodeNodeValue reads one value of the state wants under the form "want.<node>.node", refusing a field WantsByWantNodeNodeValue does not know and any text after the value.
// ParseWantsByHeldModuleFingerprintKey reads the parts of a key of the form "held.<module>.<fingerprint>", in the order of the form; the last result is false for a key of another form.
// DecodeWantsByHeldModuleFingerprintValue reads one value of the state wants under the form "held.<module>.<fingerprint>", refusing a field WantsByHeldModuleFingerprintValue does not know and any text after the value.
// ParseDifferencesByNodeModuleKey reads the parts of a key of the form "<node>.<module>", in the order of the form; the last result is false for a key of another form.
// DecodeDifferencesByNodeModuleValue reads one value of the state differences under the form "<node>.<module>", refusing a field DifferencesByNodeModuleValue does not know and any text after the value.
// ParseCompositionsByGroupHeadsKey reads the parts of a key of the form "<group>.<heads>", in the order of the form; the last result is false for a key of another form.
// DecodeCompositionsByGroupHeadsValue reads one value of the state compositions under the form "<group>.<heads>", refusing a field CompositionsByGroupHeadsValue does not know and any text after the value.
{name:"a node's own want",subject:"",given:"{\"composed\":\"sha256:aa\",\"self\":true,\"v\":1}",wire:"{\"composed\":\"sha256:aa\",\"self\":true,\"v\":1}",
decode:func(b[]byte)(any,error){
varvWantsByWantNodeNodeValue
err:=json.Unmarshal(b,&v)
returnv,err
},subjectIs:nil},
{name:"a held fingerprint",subject:"",given:"{\"node\":\"ace\",\"v\":1}",wire:"{\"node\":\"ace\",\"v\":1}",
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package nodebuildgo is the contract of the seat "node-build-go", defined whole (seats/node-build-go/seat.json): The Go build module on a node: it takes the asks of the builder and the checker, runs them as steps and answers.
packagenodebuildgo
import(
"bytes"
"encoding/json"
"errors"
"strings"
"time"
)
// Seat is the seat's name.
constSeat="node-build-go"
const(
VerbCurrent="current"
VerbPause="pause"
VerbResume="resume"
)
const(
AcceptDelivery="delivery"
AcceptCheck="check"
AcceptRecheck="recheck"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
funcVerbs()[]string{
return[]string{VerbCurrent,VerbPause,VerbResume}
}
// AcceptSubjectDelivery is where delivery is sent.
// ParseStepsByNodeIDKey reads the parts of a key of the form "<node>.<id>", in the order of the form; the last result is false for a key of another form.
// DecodeStepsByNodeIDValue reads one value of the state steps under the form "<node>.<id>", refusing a field StepsByNodeIDValue does not know and any text after the value.
// ParsePausesByPausedNodeKey reads the parts of a key of the form "paused.<node>", in the order of the form; the last result is false for a key of another form.
// DecodePausesByPausedNodeValue reads one value of the state pauses under the form "paused.<node>", refusing a field PausesByPausedNodeValue does not know and any text after the value.
// ParsePausesByCapacityNodeKey reads the parts of a key of the form "capacity.<node>", in the order of the form; the last result is false for a key of another form.
// DecodePausesByCapacityNodeValue reads one value of the state pauses under the form "capacity.<node>", refusing a field PausesByCapacityNodeValue does not know and any text after the value.
// ParseToolchainsByNodeLanguageKey reads the parts of a key of the form "<node>.<language>", in the order of the form; the last result is false for a key of another form.
// DecodeToolchainsByNodeLanguageValue reads one value of the state toolchains under the form "<node>.<language>", refusing a field ToolchainsByNodeLanguageValue does not know and any text after the value.
// FetchPackage is the TypeScript module's group package: the group's tagged version of the SDK ({name, version}), placed from the registry in each member whatever its lock names, or the group's package member ({repository, commit, ref}), packed by the fetch and served to the members in place of the registry's.
typeFetchPackagestruct{
Commitstring`json:"commit,omitempty"`
Namestring`json:"name,omitempty"`
Refstring`json:"ref,omitempty"`
Repositorystring`json:"repository,omitempty"`
Versionstring`json:"version,omitempty"`
}
// Fetch is what a build module's fetch tool is asked: the repository and the full commit, the pull request's ref when only its head carries the commit, the trunk commit to merge onto for a merge preview, the module's directory and named paths, the mesh packages to build against, and the sibling repositories placed beside.
typeFetchstruct{
// the trunk commit a merge preview merges onto
Basestring`json:"base,omitempty"`
// the sibling repositories placed beside the fetched tree
Beside[]FetchBesideItem`json:"beside,omitempty"`
// the full commit
Commitstring`json:"commit"`
// the module's directory in the repository ("." for its root), with paths
Dirstring`json:"dir,omitempty"`
// the TypeScript module's group package: the group's tagged version of the SDK ({name, version}), placed from the registry in each member whatever its lock names, or the group's package member ({repository, commit, ref}), packed by the fetch and served to the members in place of the registry's
Package*FetchPackage`json:"package,omitempty"`
// the version (a full commit) of each mesh package to build against, by its module path
// the pull request's ref, when only its head carries the commit
Refstring`json:"ref,omitempty"`
// <owner>/<name>
Repositorystring`json:"repository"`
}
// FetchAnswer is what a build module's fetch tool answers, whole: the workspace it made, the commit in it, the module directories found; and, when the call gave a base, the merge preview (the trunk commit, the merge commit, the files that conflict, the paths the merge changes, the compiled programs among them, the tree of each module directory). A head that does not merge cleanly is an answer, not an error: merge is empty and conflicts names the files. The Go module adds the sibling repositories placed and the package versions taken; the TypeScript module the directories installed and refused and the group's package.
// LevelAnswerUnmetItem is a type of the contract.
typeLevelAnswerUnmetItemstruct{
Needs[]string`json:"needs,omitempty"`
Packagestring`json:"package,omitempty"`
}
// LevelAnswer is one level of a check ask: the digest's answer, the kept verdicts taken, one test result per test step run, and the packages the node could not test.
// ModuleTree is the tree of one module directory in a merge preview: its git tree, the digest of its manifest, the lock files' digests and the digests of the named paths.
typeModuleTreestruct{
Locksmap[string]string`json:"locks,omitempty"`
Manifeststring`json:"manifest"`
// no longer filled (ADR 0593 section 2); kept so a preview written before still reads
Packages[]string`json:"packages,omitempty"`
Pathsmap[string]string`json:"paths,omitempty"`
Treestring`json:"tree"`
}
// Pause is whether the node takes no new ask.
typePausestruct{
// when (RFC 3339 time)
At*time.Time`json:"at,omitempty"`
Bystring`json:"by,omitempty"`
Pausedbool`json:"paused"`
// the layout version
Vint64`json:"v,omitempty"`
}
// PlacedBeside is a sibling repository placed as a plain directory under the workspace's beside directory.
typePlacedBesidestruct{
Commitstring`json:"commit"`
Dirstring`json:"dir"`
Repositorystring`json:"repository"`
}
// Program is a changed file that is a compiled program (issue 1577): its path, its executable format, and the commit of the branch that added it when the merge's tree no longer holds it.
typeProgramstruct{
Commitstring`json:"commit,omitempty"`
// ELF, Mach-O or PE
Kindstring`json:"kind"`
Pathstring`json:"path"`
}
// Step is one step a build module runs on a node.
// StepResult is what a step answered, by the kind of ask: a build's artifacts, toolchain, imports and out-of-step modules; a check's fetch and levels; a compose's built, key and verdict; a declined ask's declined, needs and lacks. The fields of the kinds do not meet, so one layout holds the four.
// the compose-candidate verdict (the composer's own layout)
Verdictany`json:"verdict,omitempty"`
}
// TakenVersion is of a directory whose go.mod requires an asked mesh package, the version it is built against: the asked one, or go.mod's when it names a newer one, said.
typeTakenVersionstruct{
Askedstring`json:"asked"`
Builtstring`json:"built"`
Dirstring`json:"dir"`
Namedstring`json:"named"`
Packagestring`json:"package"`
Saidstring`json:"said,omitempty"`
Sumstring`json:"sum,omitempty"`
}
// Toolchain is the toolchain a node reports.
typeToolchainstruct{
// when (RFC 3339 time)
At*time.Time`json:"at,omitempty"`
// go or typescript
Languagestring`json:"language"`
Recipestring`json:"recipe"`
// the layout version
Vint64`json:"v,omitempty"`
Versionstring`json:"version"`
}
// ToolchainUsed is the toolchain a build was made with: the language, the installed version and the build module's recipe.
typeToolchainUsedstruct{
Languagestring`json:"language"`
Recipestring`json:"recipe"`
Versionstring`json:"version"`
}
// CurrentInput is what current takes.
typeCurrentInputstruct{
}
// CurrentAnswer is what current answers.
typeCurrentAnswer=map[string]any
// PauseInput is what pause takes.
typePauseInputstruct{
}
// PauseAnswer is what pause answers.
typePauseAnswer=map[string]any
// ResumeInput is what resume takes.
typeResumeInputstruct{
}
// ResumeAnswer is what resume answers.
typeResumeAnswer=map[string]any
// DeliveryAccept is the body of delivery.
typeDeliveryAccept=StepAsk
// CheckAccept is the body of check.
typeCheckAccept=StepAsk
// RecheckAccept is the body of recheck.
typeRecheckAccept=StepAsk
// StepsByNodeIDValue is one value of the state steps under the key <node>.<id>.
typeStepsByNodeIDValue=Step
// PausesByPausedNodeValue is one value of the state pauses under the key paused.<node>.
typePausesByPausedNodeValue=Pause
// PausesByCapacityNodeValue is one value of the state pauses under the key capacity.<node>.
typePausesByCapacityNodeValue=Capacity
// ToolchainsByNodeLanguageValue is one value of the state toolchains under the key <node>.<language>.
{name:"a node's capacity",subject:"",given:"{\"configured\":2,\"effective\":2,\"v\":1,\"why\":\"the configured steps fit the cores\"}",wire:"{\"configured\":2,\"effective\":2,\"v\":1,\"why\":\"the configured steps fit the cores\"}",
{name:"a check ask with its fetch, siblings and levels",subject:"mesh.seat.node-build-go.accept.check",given:"{\"asker\":\"mesh-delivery-checker\",\"at\":\"2026-11-05T10:00:00Z\",\"check\":{\"fetch\":{\"base\":\"89abcdef0123456789abcdef0123456789abcdef\",\"beside\":[{\"commit\":\"fedcba9876543210fedcba9876543210fedcba98\",\"repository\":\"novox/mesh-sdk\"}],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"packages\":{\"git.novox.be/novox/mesh-sdk/go\":\"fedcba9876543210fedcba9876543210fedcba98\"},\"ref\":\"refs/pull/7/head\",\"repository\":\"novox/mesh-catalog\"},\"kept\":true,\"levels\":[\"unit\",\"integration\"],\"node-names\":[\"ace\",\"g14\"],\"toolchain\":{\"language\":\"go\",\"recipe\":\"2\",\"version\":\"1.26.0\"}},\"id\":\"c3d4\",\"kind\":\"check\",\"language\":\"go\",\"v\":1}",wire:"{\"asker\":\"mesh-delivery-checker\",\"at\":\"2026-11-05T10:00:00Z\",\"check\":{\"fetch\":{\"base\":\"89abcdef0123456789abcdef0123456789abcdef\",\"beside\":[{\"commit\":\"fedcba9876543210fedcba9876543210fedcba98\",\"repository\":\"novox/mesh-sdk\"}],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"packages\":{\"git.novox.be/novox/mesh-sdk/go\":\"fedcba9876543210fedcba9876543210fedcba98\"},\"ref\":\"refs/pull/7/head\",\"repository\":\"novox/mesh-catalog\"},\"kept\":true,\"levels\":[\"unit\",\"integration\"],\"node-names\":[\"ace\",\"g14\"],\"toolchain\":{\"language\":\"go\",\"recipe\":\"2\",\"version\":\"1.26.0\"}},\"id\":\"c3d4\",\"kind\":\"check\",\"language\":\"go\",\"v\":1}",
{name:"a finished build step with its artifacts",subject:"",given:"{\"ended\":\"2026-11-05T10:03:00Z\",\"id\":\"a1b2\",\"node\":\"ace\",\"result\":{\"artifacts\":[{\"artifact\":\"go\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"reference\":\"container-image-registry/nats/go@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}],\"imports\":[\"git.novox.be/novox/mesh-sdk/go\"],\"toolchain\":{\"language\":\"go\",\"recipe\":\"1\",\"version\":\"1.26.0\"}},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"passed\",\"tool\":\"build\",\"v\":1}",wire:"{\"ended\":\"2026-11-05T10:03:00Z\",\"id\":\"a1b2\",\"node\":\"ace\",\"result\":{\"artifacts\":[{\"artifact\":\"go\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"reference\":\"container-image-registry/nats/go@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}],\"imports\":[\"git.novox.be/novox/mesh-sdk/go\"],\"toolchain\":{\"language\":\"go\",\"recipe\":\"1\",\"version\":\"1.26.0\"}},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"passed\",\"tool\":\"build\",\"v\":1}",
{name:"a finished check step with its levels",subject:"",given:"{\"ended\":\"2026-11-05T10:06:00Z\",\"id\":\"c3d4\",\"node\":\"ace\",\"result\":{\"fetch\":{\"base\":\"abcdef0123456789abcdef0123456789abcdef01\",\"changed\":[\"a.go\",\"modules/m/main.go\"],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"merge\":\"fedcba9876543210fedcba9876543210fedcba98\",\"modules\":[\".\"],\"trees\":{\"modules/m\":{\"locks\":{\"go.sum\":\"c5fc83c01e92404452b986527d239140ccf9a48b88e0c268fbf38c2e1429e9c9\"},\"manifest\":\"ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356\",\"tree\":\"1111111111111111111111111111111111111111\"}},\"workspace\":\"mvii1iwu5414e4\"},\"levels\":[{\"digest\":{\"level\":\"unit\",\"packages\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"package\":\"./modules/a\"}]},\"kept\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"package\":\"./modules/a\",\"tests\":12}],\"level\":\"unit\",\"tests\":[{\"package\":\"./modules/b\",\"pass\":true}],\"unmet\":[{\"needs\":[\"docker\"],\"package\":\"./modules/c\"}]}]},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"passed\",\"tool\":\"check\",\"v\":1}",wire:"{\"ended\":\"2026-11-05T10:06:00Z\",\"id\":\"c3d4\",\"node\":\"ace\",\"result\":{\"fetch\":{\"base\":\"abcdef0123456789abcdef0123456789abcdef01\",\"changed\":[\"a.go\",\"modules/m/main.go\"],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"merge\":\"fedcba9876543210fedcba9876543210fedcba98\",\"modules\":[\".\"],\"trees\":{\"modules/m\":{\"locks\":{\"go.sum\":\"c5fc83c01e92404452b986527d239140ccf9a48b88e0c268fbf38c2e1429e9c9\"},\"manifest\":\"ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356\",\"tree\":\"1111111111111111111111111111111111111111\"}},\"workspace\":\"mvii1iwu5414e4\"},\"levels\":[{\"digest\":{\"level\":\"unit\",\"packages\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"package\":\"./modules/a\"}]},\"kept\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"package\":\"./modules/a\",\"tests\":12}],\"level\":\"unit\",\"tests\":[{\"package\":\"./modules/b\",\"pass\":true}],\"unmet\":[{\"needs\":[\"docker\"],\"package\":\"./modules/c\"}]}]},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"passed\",\"tool\":\"check\",\"v\":1}",
{name:"a finished check step whose head does not merge",subject:"",given:"{\"ended\":\"2026-11-05T10:01:00Z\",\"id\":\"c3d5\",\"node\":\"ace\",\"result\":{\"fetch\":{\"base\":\"abcdef0123456789abcdef0123456789abcdef01\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"conflicts\":[\"a.go\",\"sub/b.go\"],\"modules\":[\".\"],\"workspace\":\"mvii1iwz5050eb\"}},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"passed\",\"tool\":\"check\",\"v\":1}",wire:"{\"ended\":\"2026-11-05T10:01:00Z\",\"id\":\"c3d5\",\"node\":\"ace\",\"result\":{\"fetch\":{\"base\":\"abcdef0123456789abcdef0123456789abcdef01\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"conflicts\":[\"a.go\",\"sub/b.go\"],\"modules\":[\".\"],\"workspace\":\"mvii1iwz5050eb\"}},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"passed\",\"tool\":\"check\",\"v\":1}",
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package nodebuildimage is the contract of the seat "node-build-image", defined whole (seats/node-build-image/seat.json): The image build module on a node: it takes the asks of the builder and the checker, runs them as steps and answers.
packagenodebuildimage
import(
"bytes"
"encoding/json"
"errors"
"strings"
"time"
)
// Seat is the seat's name.
constSeat="node-build-image"
const(
VerbCurrent="current"
VerbPause="pause"
VerbResume="resume"
)
const(
AcceptDelivery="delivery"
AcceptCheck="check"
AcceptRecheck="recheck"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
funcVerbs()[]string{
return[]string{VerbCurrent,VerbPause,VerbResume}
}
// AcceptSubjectDelivery is where delivery is sent.
// ParseStepsByNodeIDKey reads the parts of a key of the form "<node>.<id>", in the order of the form; the last result is false for a key of another form.
// DecodeStepsByNodeIDValue reads one value of the state steps under the form "<node>.<id>", refusing a field StepsByNodeIDValue does not know and any text after the value.
// ParsePausesByPausedNodeKey reads the parts of a key of the form "paused.<node>", in the order of the form; the last result is false for a key of another form.
// DecodePausesByPausedNodeValue reads one value of the state pauses under the form "paused.<node>", refusing a field PausesByPausedNodeValue does not know and any text after the value.
// ParsePausesByCapacityNodeKey reads the parts of a key of the form "capacity.<node>", in the order of the form; the last result is false for a key of another form.
// DecodePausesByCapacityNodeValue reads one value of the state pauses under the form "capacity.<node>", refusing a field PausesByCapacityNodeValue does not know and any text after the value.
// ParseToolchainsByNodeLanguageKey reads the parts of a key of the form "<node>.<language>", in the order of the form; the last result is false for a key of another form.
// DecodeToolchainsByNodeLanguageValue reads one value of the state toolchains under the form "<node>.<language>", refusing a field ToolchainsByNodeLanguageValue does not know and any text after the value.
// FetchPackage is the TypeScript module's group package: the group's tagged version of the SDK ({name, version}), placed from the registry in each member whatever its lock names, or the group's package member ({repository, commit, ref}), packed by the fetch and served to the members in place of the registry's.
typeFetchPackagestruct{
Commitstring`json:"commit,omitempty"`
Namestring`json:"name,omitempty"`
Refstring`json:"ref,omitempty"`
Repositorystring`json:"repository,omitempty"`
Versionstring`json:"version,omitempty"`
}
// Fetch is what a build module's fetch tool is asked: the repository and the full commit, the pull request's ref when only its head carries the commit, the trunk commit to merge onto for a merge preview, the module's directory and named paths, the mesh packages to build against, and the sibling repositories placed beside.
typeFetchstruct{
// the trunk commit a merge preview merges onto
Basestring`json:"base,omitempty"`
// the sibling repositories placed beside the fetched tree
Beside[]FetchBesideItem`json:"beside,omitempty"`
// the full commit
Commitstring`json:"commit"`
// the module's directory in the repository ("." for its root), with paths
Dirstring`json:"dir,omitempty"`
// the TypeScript module's group package: the group's tagged version of the SDK ({name, version}), placed from the registry in each member whatever its lock names, or the group's package member ({repository, commit, ref}), packed by the fetch and served to the members in place of the registry's
Package*FetchPackage`json:"package,omitempty"`
// the version (a full commit) of each mesh package to build against, by its module path
// the pull request's ref, when only its head carries the commit
Refstring`json:"ref,omitempty"`
// <owner>/<name>
Repositorystring`json:"repository"`
}
// FetchAnswer is what a build module's fetch tool answers, whole: the workspace it made, the commit in it, the module directories found; and, when the call gave a base, the merge preview (the trunk commit, the merge commit, the files that conflict, the paths the merge changes, the compiled programs among them, the tree of each module directory). A head that does not merge cleanly is an answer, not an error: merge is empty and conflicts names the files. The Go module adds the sibling repositories placed and the package versions taken; the TypeScript module the directories installed and refused and the group's package.
// LevelAnswerUnmetItem is a type of the contract.
typeLevelAnswerUnmetItemstruct{
Needs[]string`json:"needs,omitempty"`
Packagestring`json:"package,omitempty"`
}
// LevelAnswer is one level of a check ask: the digest's answer, the kept verdicts taken, one test result per test step run, and the packages the node could not test.
// ModuleTree is the tree of one module directory in a merge preview: its git tree, the digest of its manifest, the lock files' digests and the digests of the named paths.
typeModuleTreestruct{
Locksmap[string]string`json:"locks,omitempty"`
Manifeststring`json:"manifest"`
// no longer filled (ADR 0593 section 2); kept so a preview written before still reads
Packages[]string`json:"packages,omitempty"`
Pathsmap[string]string`json:"paths,omitempty"`
Treestring`json:"tree"`
}
// Pause is whether the node takes no new ask.
typePausestruct{
// when (RFC 3339 time)
At*time.Time`json:"at,omitempty"`
Bystring`json:"by,omitempty"`
Pausedbool`json:"paused"`
// the layout version
Vint64`json:"v,omitempty"`
}
// PlacedBeside is a sibling repository placed as a plain directory under the workspace's beside directory.
typePlacedBesidestruct{
Commitstring`json:"commit"`
Dirstring`json:"dir"`
Repositorystring`json:"repository"`
}
// Program is a changed file that is a compiled program (issue 1577): its path, its executable format, and the commit of the branch that added it when the merge's tree no longer holds it.
typeProgramstruct{
Commitstring`json:"commit,omitempty"`
// ELF, Mach-O or PE
Kindstring`json:"kind"`
Pathstring`json:"path"`
}
// Step is one step a build module runs on a node.
// StepResult is what a step answered, by the kind of ask: a build's artifacts, toolchain, imports and out-of-step modules; a check's fetch and levels; a compose's built, key and verdict; a declined ask's declined, needs and lacks. The fields of the kinds do not meet, so one layout holds the four.
// the compose-candidate verdict (the composer's own layout)
Verdictany`json:"verdict,omitempty"`
}
// TakenVersion is of a directory whose go.mod requires an asked mesh package, the version it is built against: the asked one, or go.mod's when it names a newer one, said.
typeTakenVersionstruct{
Askedstring`json:"asked"`
Builtstring`json:"built"`
Dirstring`json:"dir"`
Namedstring`json:"named"`
Packagestring`json:"package"`
Saidstring`json:"said,omitempty"`
Sumstring`json:"sum,omitempty"`
}
// Toolchain is the toolchain a node reports.
typeToolchainstruct{
// when (RFC 3339 time)
At*time.Time`json:"at,omitempty"`
// go or typescript
Languagestring`json:"language"`
Recipestring`json:"recipe"`
// the layout version
Vint64`json:"v,omitempty"`
Versionstring`json:"version"`
}
// ToolchainUsed is the toolchain a build was made with: the language, the installed version and the build module's recipe.
typeToolchainUsedstruct{
Languagestring`json:"language"`
Recipestring`json:"recipe"`
Versionstring`json:"version"`
}
// CurrentInput is what current takes.
typeCurrentInputstruct{
}
// CurrentAnswer is what current answers.
typeCurrentAnswer=map[string]any
// PauseInput is what pause takes.
typePauseInputstruct{
}
// PauseAnswer is what pause answers.
typePauseAnswer=map[string]any
// ResumeInput is what resume takes.
typeResumeInputstruct{
}
// ResumeAnswer is what resume answers.
typeResumeAnswer=map[string]any
// DeliveryAccept is the body of delivery.
typeDeliveryAccept=StepAsk
// CheckAccept is the body of check.
typeCheckAccept=StepAsk
// RecheckAccept is the body of recheck.
typeRecheckAccept=StepAsk
// StepsByNodeIDValue is one value of the state steps under the key <node>.<id>.
typeStepsByNodeIDValue=Step
// PausesByPausedNodeValue is one value of the state pauses under the key paused.<node>.
typePausesByPausedNodeValue=Pause
// PausesByCapacityNodeValue is one value of the state pauses under the key capacity.<node>.
typePausesByCapacityNodeValue=Capacity
// ToolchainsByNodeLanguageValue is one value of the state toolchains under the key <node>.<language>.
{name:"a node's capacity",subject:"",given:"{\"configured\":2,\"effective\":2,\"v\":1,\"why\":\"the configured steps fit the cores\"}",wire:"{\"configured\":2,\"effective\":2,\"v\":1,\"why\":\"the configured steps fit the cores\"}",
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package nodebuildnode is the contract of the seat "node-build-node", defined whole (seats/node-build-node/seat.json): The Node build module on a node: it takes the asks of the builder and the checker, runs them as steps and answers.
packagenodebuildnode
import(
"bytes"
"encoding/json"
"errors"
"strings"
"time"
)
// Seat is the seat's name.
constSeat="node-build-node"
const(
VerbCurrent="current"
VerbPause="pause"
VerbResume="resume"
)
const(
AcceptDelivery="delivery"
AcceptCheck="check"
AcceptRecheck="recheck"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
funcVerbs()[]string{
return[]string{VerbCurrent,VerbPause,VerbResume}
}
// AcceptSubjectDelivery is where delivery is sent.
// ParseStepsByNodeIDKey reads the parts of a key of the form "<node>.<id>", in the order of the form; the last result is false for a key of another form.
// DecodeStepsByNodeIDValue reads one value of the state steps under the form "<node>.<id>", refusing a field StepsByNodeIDValue does not know and any text after the value.
// ParsePausesByPausedNodeKey reads the parts of a key of the form "paused.<node>", in the order of the form; the last result is false for a key of another form.
// DecodePausesByPausedNodeValue reads one value of the state pauses under the form "paused.<node>", refusing a field PausesByPausedNodeValue does not know and any text after the value.
// ParsePausesByCapacityNodeKey reads the parts of a key of the form "capacity.<node>", in the order of the form; the last result is false for a key of another form.
// DecodePausesByCapacityNodeValue reads one value of the state pauses under the form "capacity.<node>", refusing a field PausesByCapacityNodeValue does not know and any text after the value.
// ParseToolchainsByNodeLanguageKey reads the parts of a key of the form "<node>.<language>", in the order of the form; the last result is false for a key of another form.
// DecodeToolchainsByNodeLanguageValue reads one value of the state toolchains under the form "<node>.<language>", refusing a field ToolchainsByNodeLanguageValue does not know and any text after the value.
// FetchPackage is the TypeScript module's group package: the group's tagged version of the SDK ({name, version}), placed from the registry in each member whatever its lock names, or the group's package member ({repository, commit, ref}), packed by the fetch and served to the members in place of the registry's.
typeFetchPackagestruct{
Commitstring`json:"commit,omitempty"`
Namestring`json:"name,omitempty"`
Refstring`json:"ref,omitempty"`
Repositorystring`json:"repository,omitempty"`
Versionstring`json:"version,omitempty"`
}
// Fetch is what a build module's fetch tool is asked: the repository and the full commit, the pull request's ref when only its head carries the commit, the trunk commit to merge onto for a merge preview, the module's directory and named paths, the mesh packages to build against, and the sibling repositories placed beside.
typeFetchstruct{
// the trunk commit a merge preview merges onto
Basestring`json:"base,omitempty"`
// the sibling repositories placed beside the fetched tree
Beside[]FetchBesideItem`json:"beside,omitempty"`
// the full commit
Commitstring`json:"commit"`
// the module's directory in the repository ("." for its root), with paths
Dirstring`json:"dir,omitempty"`
// the TypeScript module's group package: the group's tagged version of the SDK ({name, version}), placed from the registry in each member whatever its lock names, or the group's package member ({repository, commit, ref}), packed by the fetch and served to the members in place of the registry's
Package*FetchPackage`json:"package,omitempty"`
// the version (a full commit) of each mesh package to build against, by its module path
// the pull request's ref, when only its head carries the commit
Refstring`json:"ref,omitempty"`
// <owner>/<name>
Repositorystring`json:"repository"`
}
// FetchAnswer is what a build module's fetch tool answers, whole: the workspace it made, the commit in it, the module directories found; and, when the call gave a base, the merge preview (the trunk commit, the merge commit, the files that conflict, the paths the merge changes, the compiled programs among them, the tree of each module directory). A head that does not merge cleanly is an answer, not an error: merge is empty and conflicts names the files. The Go module adds the sibling repositories placed and the package versions taken; the TypeScript module the directories installed and refused and the group's package.
// LevelAnswerUnmetItem is a type of the contract.
typeLevelAnswerUnmetItemstruct{
Needs[]string`json:"needs,omitempty"`
Packagestring`json:"package,omitempty"`
}
// LevelAnswer is one level of a check ask: the digest's answer, the kept verdicts taken, one test result per test step run, and the packages the node could not test.
// ModuleTree is the tree of one module directory in a merge preview: its git tree, the digest of its manifest, the lock files' digests and the digests of the named paths.
typeModuleTreestruct{
Locksmap[string]string`json:"locks,omitempty"`
Manifeststring`json:"manifest"`
// no longer filled (ADR 0593 section 2); kept so a preview written before still reads
Packages[]string`json:"packages,omitempty"`
Pathsmap[string]string`json:"paths,omitempty"`
Treestring`json:"tree"`
}
// Pause is whether the node takes no new ask.
typePausestruct{
// when (RFC 3339 time)
At*time.Time`json:"at,omitempty"`
Bystring`json:"by,omitempty"`
Pausedbool`json:"paused"`
// the layout version
Vint64`json:"v,omitempty"`
}
// PlacedBeside is a sibling repository placed as a plain directory under the workspace's beside directory.
typePlacedBesidestruct{
Commitstring`json:"commit"`
Dirstring`json:"dir"`
Repositorystring`json:"repository"`
}
// Program is a changed file that is a compiled program (issue 1577): its path, its executable format, and the commit of the branch that added it when the merge's tree no longer holds it.
typeProgramstruct{
Commitstring`json:"commit,omitempty"`
// ELF, Mach-O or PE
Kindstring`json:"kind"`
Pathstring`json:"path"`
}
// Step is one step a build module runs on a node.
// StepResult is what a step answered, by the kind of ask: a build's artifacts, toolchain, imports and out-of-step modules; a check's fetch and levels; a compose's built, key and verdict; a declined ask's declined, needs and lacks. The fields of the kinds do not meet, so one layout holds the four.
// the compose-candidate verdict (the composer's own layout)
Verdictany`json:"verdict,omitempty"`
}
// TakenVersion is of a directory whose go.mod requires an asked mesh package, the version it is built against: the asked one, or go.mod's when it names a newer one, said.
typeTakenVersionstruct{
Askedstring`json:"asked"`
Builtstring`json:"built"`
Dirstring`json:"dir"`
Namedstring`json:"named"`
Packagestring`json:"package"`
Saidstring`json:"said,omitempty"`
Sumstring`json:"sum,omitempty"`
}
// Toolchain is the toolchain a node reports.
typeToolchainstruct{
// when (RFC 3339 time)
At*time.Time`json:"at,omitempty"`
// go or typescript
Languagestring`json:"language"`
Recipestring`json:"recipe"`
// the layout version
Vint64`json:"v,omitempty"`
Versionstring`json:"version"`
}
// ToolchainUsed is the toolchain a build was made with: the language, the installed version and the build module's recipe.
typeToolchainUsedstruct{
Languagestring`json:"language"`
Recipestring`json:"recipe"`
Versionstring`json:"version"`
}
// CurrentInput is what current takes.
typeCurrentInputstruct{
}
// CurrentAnswer is what current answers.
typeCurrentAnswer=map[string]any
// PauseInput is what pause takes.
typePauseInputstruct{
}
// PauseAnswer is what pause answers.
typePauseAnswer=map[string]any
// ResumeInput is what resume takes.
typeResumeInputstruct{
}
// ResumeAnswer is what resume answers.
typeResumeAnswer=map[string]any
// DeliveryAccept is the body of delivery.
typeDeliveryAccept=StepAsk
// CheckAccept is the body of check.
typeCheckAccept=StepAsk
// RecheckAccept is the body of recheck.
typeRecheckAccept=StepAsk
// StepsByNodeIDValue is one value of the state steps under the key <node>.<id>.
typeStepsByNodeIDValue=Step
// PausesByPausedNodeValue is one value of the state pauses under the key paused.<node>.
typePausesByPausedNodeValue=Pause
// PausesByCapacityNodeValue is one value of the state pauses under the key capacity.<node>.
typePausesByCapacityNodeValue=Capacity
// ToolchainsByNodeLanguageValue is one value of the state toolchains under the key <node>.<language>.
{name:"a node's capacity",subject:"",given:"{\"configured\":2,\"effective\":2,\"v\":1,\"why\":\"the configured steps fit the cores\"}",wire:"{\"configured\":2,\"effective\":2,\"v\":1,\"why\":\"the configured steps fit the cores\"}",
{name:"a check ask with the group's tagged package",subject:"mesh.seat.node-build-node.accept.check",given:"{\"asker\":\"mesh-delivery-checker\",\"at\":\"2026-11-05T10:00:00Z\",\"check\":{\"fetch\":{\"base\":\"89abcdef0123456789abcdef0123456789abcdef\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"package\":{\"name\":\"@novox/mesh-sdk\",\"version\":\"0.1.15-feat-x.1\"},\"ref\":\"refs/pull/7/head\",\"repository\":\"novox/mesh-delivery\"},\"kept\":true,\"levels\":[\"unit\",\"integration\"],\"node-names\":[\"ace\",\"g14\"],\"toolchain\":{\"language\":\"typescript\",\"recipe\":\"1\",\"version\":\"26.12.0\"}},\"id\":\"c3d5\",\"kind\":\"check\",\"language\":\"typescript\",\"v\":1}",wire:"{\"asker\":\"mesh-delivery-checker\",\"at\":\"2026-11-05T10:00:00Z\",\"check\":{\"fetch\":{\"base\":\"89abcdef0123456789abcdef0123456789abcdef\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"package\":{\"name\":\"@novox/mesh-sdk\",\"version\":\"0.1.15-feat-x.1\"},\"ref\":\"refs/pull/7/head\",\"repository\":\"novox/mesh-delivery\"},\"kept\":true,\"levels\":[\"unit\",\"integration\"],\"node-names\":[\"ace\",\"g14\"],\"toolchain\":{\"language\":\"typescript\",\"recipe\":\"1\",\"version\":\"26.12.0\"}},\"id\":\"c3d5\",\"kind\":\"check\",\"language\":\"typescript\",\"v\":1}",
{name:"a finished check step of a TypeScript merge preview",subject:"",given:"{\"ended\":\"2026-11-05T10:01:00Z\",\"id\":\"c3d6\",\"node\":\"ace\",\"result\":{\"fetch\":{\"base\":\"abcdef0123456789abcdef0123456789abcdef01\",\"changed\":[\"modules/m/package.json\"],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"merge\":\"0123456789abcdef0123456789abcdef01234567\",\"modules\":[\"modules/m\"],\"trees\":{\"modules/m\":{\"manifest\":\"0581b699d9d05517e69b21f5cedbeb2eee8aba2b205280b561be731594d7feef\",\"tree\":\"0123456789abcdef0123456789abcdef01234567\"}},\"workspace\":\"mvii1sxt979f67\"}},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"passed\",\"tool\":\"check\",\"v\":1}",wire:"{\"ended\":\"2026-11-05T10:01:00Z\",\"id\":\"c3d6\",\"node\":\"ace\",\"result\":{\"fetch\":{\"base\":\"abcdef0123456789abcdef0123456789abcdef01\",\"changed\":[\"modules/m/package.json\"],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"merge\":\"0123456789abcdef0123456789abcdef01234567\",\"modules\":[\"modules/m\"],\"trees\":{\"modules/m\":{\"manifest\":\"0581b699d9d05517e69b21f5cedbeb2eee8aba2b205280b561be731594d7feef\",\"tree\":\"0123456789abcdef0123456789abcdef01234567\"}},\"workspace\":\"mvii1sxt979f67\"}},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"passed\",\"tool\":\"check\",\"v\":1}",
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package npmpackageregistry is the contract of the seat "npm-package-registry", defined whole (seats/npm-package-registry/seat.json): The mesh's npm packages: the npm registry protocol's read side, and publishing over the bus.
packagenpmpackageregistry
// Seat is the seat's name.
constSeat="npm-package-registry"
const(
VerbPublish="publish"
VerbPublishPart="publish-part"
VerbVersions="versions"
VerbRemove="remove"
)
const(
EventPublished="published"
EventRefused="refused"
EventRemoved="removed"
EventKept="kept"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
// Artifact is one published thing, as every registry event and answer names it.
typeArtifactstruct{
// the source commit it was built from
Commitstring`json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digeststring`json:"digest"`
// the build's fingerprint
Fingerprintstring`json:"fingerprint,omitempty"`
// what it is
Kindstring`json:"kind"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Namestring`json:"name"`
// the tag it carries, for a tagged version
Tagstring`json:"tag,omitempty"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Versionstring`json:"version,omitempty"`
}
// The values of Artifact's kind.
const(
ArtifactKindPackage="package"
ArtifactKindImage="image"
ArtifactKindBundle="bundle"
ArtifactKindArchive="archive"
ArtifactKindUpstream="upstream"
)
// Outcome is the body of published, refused and removed.
typeOutcomestruct{
// the source commit it was built from
Commitstring`json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digeststring`json:"digest"`
// the build's fingerprint
Fingerprintstring`json:"fingerprint,omitempty"`
// the module holding the seat that said it
Holderstring`json:"holder"`
// what it is
Kindstring`json:"kind"`
// the Go module path a Go package is fetched under, equal to name for a Go package (go-package-registry's published); empty for every other kind of artifact
Modulestring`json:"module,omitempty"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Namestring`json:"name"`
// why: a refusal's cause, a removal's (retention, tag-gone, by-hand), or why a removal was kept (shared-digest)
Reasonstring`json:"reason,omitempty"`
// the reference the seat answers: <registry>/<module>/<artifact>@sha256:<digest>, or <name>@<version> for a package (ADR 0605 §9)
Referencestring`json:"reference,omitempty"`
// the tag it carries, for a tagged version
Tagstring`json:"tag,omitempty"`
// for kept: the other tags still naming its digest
Tags[]string`json:"tags,omitempty"`
// the transfer it ends, when it ended one
Transferstring`json:"transfer,omitempty"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Versionstring`json:"version,omitempty"`
}
// The values of Outcome's kind.
const(
OutcomeKindPackage="package"
OutcomeKindImage="image"
OutcomeKindBundle="bundle"
OutcomeKindArchive="archive"
OutcomeKindUpstream="upstream"
)
// Part is one part of a transfer.
typePartstruct{
// the part's digest, sha256:<hex>: an image's layer or config, a package's file, a bundle's blob
Digeststring`json:"digest"`
// its size in bytes
Sizeint64`json:"size"`
}
// PublishInput is what publish takes.
typePublishInputstruct{
// the source commit it was built from
Commitstring`json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digeststring`json:"digest"`
// the build's fingerprint
Fingerprintstring`json:"fingerprint,omitempty"`
// what it is
Kindstring`json:"kind"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Namestring`json:"name"`
// every part's digest and size; none when the digest is already held
Parts[]Part`json:"parts,omitempty"`
// the tag it carries, for a tagged version
Tagstring`json:"tag,omitempty"`
// the transfer's name, the caller's own; the same name opens the same transfer again
Transferstring`json:"transfer"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Versionstring`json:"version,omitempty"`
}
// The values of PublishInput's kind.
const(
PublishInputKindPackage="package"
PublishInputKindImage="image"
PublishInputKindBundle="bundle"
PublishInputKindArchive="archive"
PublishInputKindUpstream="upstream"
)
// PublishAnswer is what publish answers.
typePublishAnswerstruct{
// the digest is held already: nothing to send; the outcome follows as an event
Heldbool`json:"held,omitempty"`
// the digests of the parts the holder lacks, to send by publish-part
Lacks[]string`json:"lacks,omitempty"`
// the transfer
Transferstring`json:"transfer"`
}
// PublishPartInput is what publish-part takes.
typePublishPartInputstruct{
// the chunk's bytes, base64 (at most 760 KiB before encoding)
Datastring`json:"data"`
// this chunk is the part's last
Lastbool`json:"last"`
// the part's digest
Partstring`json:"part"`
// the chunk's place in its part, from 0
Sequenceint64`json:"sequence"`
// the transfer
Transferstring`json:"transfer"`
}
// PublishPartAnswer is what publish-part answers.
typePublishPartAnswerstruct{
// the part is whole and its bytes match its digest
Completebool`json:"complete,omitempty"`
// the part
Partstring`json:"part"`
// the chunks of the part held so far
Receivedint64`json:"received,omitempty"`
// the transfer
Transferstring`json:"transfer"`
}
// VersionsInput is what versions takes.
typeVersionsInputstruct{
// narrowed to one kind (optional)
Kindstring`json:"kind,omitempty"`
// the name
Namestring`json:"name"`
}
// VersionsAnswer is what versions answers.
typeVersionsAnswerstruct{
// the name
Namestring`json:"name"`
// newest first
Versions[]Artifact`json:"versions"`
}
// RemoveInput is what remove takes.
typeRemoveInputstruct{
// the digest (for a bundle, archive or copied base)
Digeststring`json:"digest,omitempty"`
// the name
Namestring`json:"name"`
// why it goes
Reasonstring`json:"reason"`
// the tag (for a tagged version)
Tagstring`json:"tag,omitempty"`
// the version
Versionstring`json:"version,omitempty"`
}
// The values of RemoveInput's reason.
const(
RemoveInputReasonTagGone="tag-gone"
RemoveInputReasonRetention="retention"
)
// RemoveAnswer is what remove answers.
typeRemoveAnswerstruct{
Artifact*Artifact`json:"artifact,omitempty"`
// it stays whole, its tag and its bytes: the store cannot remove the tag alone while another tag names its digest (reason, tags)
Keptbool`json:"kept,omitempty"`
// why it was kept: shared-digest, another tag names its digest
Reasonstring`json:"reason,omitempty"`
// it is gone
Removedbool`json:"removed"`
// the other tags still naming its digest, when kept
Tags[]string`json:"tags,omitempty"`
}
// The values of RemoveAnswer's reason.
const(
RemoveAnswerReasonSharedDigest="shared-digest"
)
// PublishedEvent is the body of the event published.
typePublishedEvent=Outcome
// RefusedEvent is the body of the event refused.
typeRefusedEvent=Outcome
// RemovedEvent is the body of the event removed.
typeRemovedEvent=Outcome
// KeptEvent is the body of the event kept.
typeKeptEvent=Outcome
// NpmPackageRegistryForm is the form of the provision npm-package-registry.
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
packagenpmpackageregistry
import(
"encoding/json"
"reflect"
"regexp"
"testing"
)
// TestFixtures reads every fixture of seats/npm-package-registry/fixtures: each decodes into its type, a field the type does not
// know is dropped (ADR 0608 §6), and it reads back as its wire says; each subject named is the contract's.
funcTestFixtures(t*testing.T){
cases:=[]struct{
name,subject,given,wirestring
decodefunc([]byte)(any,error)
subjectIs*regexp.Regexp
}{
{name:"published on the seat's subject",subject:"mesh.seat.npm-package-registry.event.published",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"reference\":\"@novox/mesh-sdk@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"reference\":\"@novox/mesh-sdk@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
{name:"refused on the seat's subject",subject:"mesh.seat.npm-package-registry.event.refused",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"reason\":\"retention\",\"reference\":\"@novox/mesh-sdk@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"reason\":\"retention\",\"reference\":\"@novox/mesh-sdk@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
{name:"removed on the seat's subject",subject:"mesh.seat.npm-package-registry.event.removed",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"reason\":\"retention\",\"reference\":\"@novox/mesh-sdk@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"reason\":\"retention\",\"reference\":\"@novox/mesh-sdk@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
{name:"kept on the seat's subject: a tagged version sharing its digest stays, naming the tags on it",subject:"mesh.seat.npm-package-registry.event.kept",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"reason\":\"shared-digest\",\"reference\":\"@novox/mesh-sdk@0.1.19\",\"tag\":\"0.1.19-feat-x.2\",\"tags\":[\"0.1.19\"],\"version\":\"0.1.19-feat-x.2\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"reason\":\"shared-digest\",\"reference\":\"@novox/mesh-sdk@0.1.19\",\"tag\":\"0.1.19-feat-x.2\",\"tags\":[\"0.1.19\"],\"version\":\"0.1.19-feat-x.2\"}",
{name:"publish opens a transfer",subject:"",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
{name:"a field the reader does not know is dropped",subject:"",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"later\":{\"x\":1},\"name\":\"@novox/mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
{name:"publish answers what it lacks",subject:"",given:"{\"lacks\":[\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"transfer\":\"t1\"}",wire:"{\"lacks\":[\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"transfer\":\"t1\"}",
{name:"a chunk of a part",subject:"",given:"{\"data\":\"aGVsbG8=\",\"last\":true,\"part\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"sequence\":0,\"transfer\":\"t1\"}",wire:"{\"data\":\"aGVsbG8=\",\"last\":true,\"part\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"sequence\":0,\"transfer\":\"t1\"}",
{name:"a tagged version sharing its digest with another tag is kept, not removed",subject:"",given:"{\"kept\":true,\"reason\":\"shared-digest\",\"removed\":false,\"tags\":[\"0.1.19\"]}",wire:"{\"kept\":true,\"reason\":\"shared-digest\",\"removed\":false,\"tags\":[\"0.1.19\"]}",
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package ociartifactregistry is the contract of the seat "oci-artifact-registry", defined whole (seats/oci-artifact-registry/seat.json): The mesh's bundles and archives, by digest, in the one artifact store: the OCI distribution protocol's read side.
packageociartifactregistry
import(
"bytes"
"encoding/json"
"errors"
"strings"
)
// Seat is the seat's name.
constSeat="oci-artifact-registry"
const(
VerbPublish="publish"
VerbPublishPart="publish-part"
VerbVersions="versions"
VerbRemove="remove"
VerbHold="hold"
VerbRelease="release"
VerbList="list"
)
const(
EventPublished="published"
EventRefused="refused"
EventRemoved="removed"
EventKept="kept"
EventHeld="held"
EventReleased="released"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
// ParseHoldsBySeatNameDigestKey reads the parts of a key of the form "<seat>.<name>.<digest>", in the order of the form; the last result is false for a key of another form.
// DecodeHoldsBySeatNameDigestValue reads one value of the state holds under the form "<seat>.<name>.<digest>", refusing a field HoldsBySeatNameDigestValue does not know and any text after the value.
// ParseWindowsByCallerKey reads the parts of a key of the form "<caller>", in the order of the form; the last result is false for a key of another form.
// DecodeWindowsByCallerValue reads one value of the state windows under the form "<caller>", refusing a field WindowsByCallerValue does not know and any text after the value.
// Artifact is one published thing, as every registry event and answer names it.
typeArtifactstruct{
// the source commit it was built from
Commitstring`json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digeststring`json:"digest"`
// the build's fingerprint
Fingerprintstring`json:"fingerprint,omitempty"`
// what it is
Kindstring`json:"kind"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Namestring`json:"name"`
// the tag it carries, for a tagged version
Tagstring`json:"tag,omitempty"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Versionstring`json:"version,omitempty"`
}
// The values of Artifact's kind.
const(
ArtifactKindPackage="package"
ArtifactKindImage="image"
ArtifactKindBundle="bundle"
ArtifactKindArchive="archive"
ArtifactKindUpstream="upstream"
)
// Hold is the body of held and released.
typeHoldstruct{
// when, RFC 3339
Atstring`json:"at,omitempty"`
// the caller the holder proved
Bystring`json:"by,omitempty"`
// the digest
Digeststring`json:"digest"`
// the module holding the seat
Holderstring`json:"holder"`
// the name
Namestring`json:"name"`
// why
Reasonstring`json:"reason,omitempty"`
}
// Listed is a type of the contract.
typeListedstruct{
// for a manifest keeping one bundle or archive, the digest of that blob: what a reference names it by
Artifactstring`json:"artifact,omitempty"`
// the manifest's digest, sha256:<hex>
Digeststring`json:"digest"`
// a hold keeps it from retention
Heldbool`json:"held"`
// it is an index, naming a manifest per platform
Indexbool`json:"index"`
// for an index, the digests of the manifests it names
Platforms[]string`json:"platforms,omitempty"`
// its bytes: its own content and every blob it names
Sizeint64`json:"size"`
// the tags naming it, none for an untagged one
Tags[]string`json:"tags,omitempty"`
}
// Outcome is the body of published, refused and removed.
typeOutcomestruct{
// the source commit it was built from
Commitstring`json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digeststring`json:"digest"`
// the build's fingerprint
Fingerprintstring`json:"fingerprint,omitempty"`
// the module holding the seat that said it
Holderstring`json:"holder"`
// what it is
Kindstring`json:"kind"`
// the Go module path a Go package is fetched under, equal to name for a Go package (go-package-registry's published); empty for every other kind of artifact
Modulestring`json:"module,omitempty"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Namestring`json:"name"`
// why: a refusal's cause, a removal's (retention, tag-gone, by-hand), or why a removal was kept (shared-digest)
Reasonstring`json:"reason,omitempty"`
// the reference the seat answers: <registry>/<module>/<artifact>@sha256:<digest>, or <name>@<version> for a package (ADR 0605 §9)
Referencestring`json:"reference,omitempty"`
// the tag it carries, for a tagged version
Tagstring`json:"tag,omitempty"`
// for kept: the other tags still naming its digest
Tags[]string`json:"tags,omitempty"`
// the transfer it ends, when it ended one
Transferstring`json:"transfer,omitempty"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Versionstring`json:"version,omitempty"`
}
// The values of Outcome's kind.
const(
OutcomeKindPackage="package"
OutcomeKindImage="image"
OutcomeKindBundle="bundle"
OutcomeKindArchive="archive"
OutcomeKindUpstream="upstream"
)
// Part is one part of a transfer.
typePartstruct{
// the part's digest, sha256:<hex>: an image's layer or config, a package's file, a bundle's blob
Digeststring`json:"digest"`
// its size in bytes
Sizeint64`json:"size"`
}
// Repository is a type of the contract.
typeRepositorystruct{
// each manifest it holds, by digest
Manifests[]Listed`json:"manifests"`
// the repository
Namestring`json:"name"`
}
// PublishInput is what publish takes.
typePublishInputstruct{
// the source commit it was built from
Commitstring`json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digeststring`json:"digest"`
// the build's fingerprint
Fingerprintstring`json:"fingerprint,omitempty"`
// what it is
Kindstring`json:"kind"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Namestring`json:"name"`
// every part's digest and size; none when the digest is already held
Parts[]Part`json:"parts,omitempty"`
// the tag it carries, for a tagged version
Tagstring`json:"tag,omitempty"`
// the transfer's name, the caller's own; the same name opens the same transfer again
Transferstring`json:"transfer"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Versionstring`json:"version,omitempty"`
}
// The values of PublishInput's kind.
const(
PublishInputKindPackage="package"
PublishInputKindImage="image"
PublishInputKindBundle="bundle"
PublishInputKindArchive="archive"
PublishInputKindUpstream="upstream"
)
// PublishAnswer is what publish answers.
typePublishAnswerstruct{
// the digest is held already: nothing to send; the outcome follows as an event
Heldbool`json:"held,omitempty"`
// the digests of the parts the holder lacks, to send by publish-part
Lacks[]string`json:"lacks,omitempty"`
// the transfer
Transferstring`json:"transfer"`
}
// PublishPartInput is what publish-part takes.
typePublishPartInputstruct{
// the chunk's bytes, base64 (at most 760 KiB before encoding)
Datastring`json:"data"`
// this chunk is the part's last
Lastbool`json:"last"`
// the part's digest
Partstring`json:"part"`
// the chunk's place in its part, from 0
Sequenceint64`json:"sequence"`
// the transfer
Transferstring`json:"transfer"`
}
// PublishPartAnswer is what publish-part answers.
typePublishPartAnswerstruct{
// the part is whole and its bytes match its digest
Completebool`json:"complete,omitempty"`
// the part
Partstring`json:"part"`
// the chunks of the part held so far
Receivedint64`json:"received,omitempty"`
// the transfer
Transferstring`json:"transfer"`
}
// VersionsInput is what versions takes.
typeVersionsInputstruct{
// narrowed to one kind (optional)
Kindstring`json:"kind,omitempty"`
// the name
Namestring`json:"name"`
}
// VersionsAnswer is what versions answers.
typeVersionsAnswerstruct{
// the name
Namestring`json:"name"`
// newest first
Versions[]Artifact`json:"versions"`
}
// RemoveInput is what remove takes.
typeRemoveInputstruct{
// the digest (for a bundle, archive or copied base)
Digeststring`json:"digest,omitempty"`
// the name
Namestring`json:"name"`
// why it goes
Reasonstring`json:"reason"`
// the tag (for a tagged version)
Tagstring`json:"tag,omitempty"`
// the version
Versionstring`json:"version,omitempty"`
}
// The values of RemoveInput's reason.
const(
RemoveInputReasonTagGone="tag-gone"
RemoveInputReasonRetention="retention"
)
// RemoveAnswer is what remove answers.
typeRemoveAnswerstruct{
Artifact*Artifact`json:"artifact,omitempty"`
// it stays whole, its tag and its bytes: the store cannot remove the tag alone while another tag names its digest (reason, tags)
Keptbool`json:"kept,omitempty"`
// why it was kept: shared-digest, another tag names its digest
Reasonstring`json:"reason,omitempty"`
// it is gone
Removedbool`json:"removed"`
// the other tags still naming its digest, when kept
Tags[]string`json:"tags,omitempty"`
}
// The values of RemoveAnswer's reason.
const(
RemoveAnswerReasonSharedDigest="shared-digest"
)
// HoldInput is what hold takes.
typeHoldInputstruct{
// the digest
Digeststring`json:"digest"`
// the name
Namestring`json:"name"`
// which of the sweep's rules keeps it
Reasonstring`json:"reason"`
}
// HoldAnswer is what hold answers.
typeHoldAnswerstruct{
// it is held
Heldbool`json:"held"`
// when the hold began, RFC 3339
Sincestring`json:"since,omitempty"`
}
// ReleaseInput is what release takes.
typeReleaseInputstruct{
// the digest
Digeststring`json:"digest"`
// the name
Namestring`json:"name"`
// why it is let go
Reasonstring`json:"reason"`
}
// ReleaseAnswer is what release answers.
typeReleaseAnswerstruct{
// a hold was let go; false when there was none
Releasedbool`json:"released"`
}
// ListInput is what list takes.
typeListInputstruct{
// the repository, <module>/<artifact>; every repository of the seat when not given
Namestring`json:"name,omitempty"`
}
// ListAnswer is what list answers.
typeListAnswerstruct{
// each repository named, in order of its name
Repositories[]Repository`json:"repositories"`
}
// PublishedEvent is the body of the event published.
typePublishedEvent=Outcome
// RefusedEvent is the body of the event refused.
typeRefusedEvent=Outcome
// RemovedEvent is the body of the event removed.
typeRemovedEvent=Outcome
// KeptEvent is the body of the event kept.
typeKeptEvent=Outcome
// HeldEvent is the body of the event held.
typeHeldEvent=Hold
// ReleasedEvent is the body of the event released.
typeReleasedEvent=Hold
// HoldsBySeatNameDigestValue is one value of the state holds under the key <seat>.<name>.<digest>.
typeHoldsBySeatNameDigestValuestruct{
Bystring`json:"by"`
Digeststring`json:"digest"`
Kindstring`json:"kind"`
Namestring`json:"name"`
Seatstring`json:"seat"`
// when (RFC 3339 time)
Sincestring`json:"since"`
Whystring`json:"why,omitempty"`
}
// WindowsByCallerValueDroppedItem is a type of the contract.
typeWindowsByCallerValueDroppedItemstruct{
// when (RFC 3339 time)
Atstring`json:"at,omitempty"`
Bystring`json:"by,omitempty"`
Nodestring`json:"node"`
Whystring`json:"why,omitempty"`
}
// WindowsByCallerValue is one value of the state windows under the key <caller>.
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
packageociartifactregistry
import(
"encoding/json"
"reflect"
"regexp"
"testing"
)
// TestFixtures reads every fixture of seats/oci-artifact-registry/fixtures: each decodes into its type, a field the type does not
// know is dropped (ADR 0608 §6), and it reads back as its wire says; each subject named is the contract's.
funcTestFixtures(t*testing.T){
cases:=[]struct{
name,subject,given,wirestring
decodefunc([]byte)(any,error)
subjectIs*regexp.Regexp
}{
{name:"published on the seat's subject",subject:"mesh.seat.oci-artifact-registry.event.published",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"bundle\",\"name\":\"mesh-sdk\",\"reference\":\"oci-artifact-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"bundle\",\"name\":\"mesh-sdk\",\"reference\":\"oci-artifact-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
{name:"refused on the seat's subject",subject:"mesh.seat.oci-artifact-registry.event.refused",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"bundle\",\"name\":\"mesh-sdk\",\"reason\":\"retention\",\"reference\":\"oci-artifact-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"bundle\",\"name\":\"mesh-sdk\",\"reason\":\"retention\",\"reference\":\"oci-artifact-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
{name:"removed on the seat's subject",subject:"mesh.seat.oci-artifact-registry.event.removed",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"bundle\",\"name\":\"mesh-sdk\",\"reason\":\"retention\",\"reference\":\"oci-artifact-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"bundle\",\"name\":\"mesh-sdk\",\"reason\":\"retention\",\"reference\":\"oci-artifact-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
{name:"kept on the seat's subject: a tagged version sharing its digest stays, naming the tags on it",subject:"mesh.seat.oci-artifact-registry.event.kept",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"bundle\",\"name\":\"mesh-sdk\",\"reason\":\"shared-digest\",\"reference\":\"oci-artifact-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"tag\":\"0.1.19-feat-x.2\",\"tags\":[\"0.1.19\"],\"version\":\"0.1.19-feat-x.2\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"bundle\",\"name\":\"mesh-sdk\",\"reason\":\"shared-digest\",\"reference\":\"oci-artifact-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"tag\":\"0.1.19-feat-x.2\",\"tags\":[\"0.1.19\"],\"version\":\"0.1.19-feat-x.2\"}",
{name:"held on the seat's subject",subject:"mesh.seat.oci-artifact-registry.event.held",given:"{\"at\":\"2026-11-04T12:00:00Z\",\"by\":\"mesh-artifact-sweep\",\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"holder\":\"distribution\",\"name\":\"mesh-sdk\",\"reason\":\"kept by the sweep's rule\"}",wire:"{\"at\":\"2026-11-04T12:00:00Z\",\"by\":\"mesh-artifact-sweep\",\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"holder\":\"distribution\",\"name\":\"mesh-sdk\",\"reason\":\"kept by the sweep's rule\"}",
{name:"released on the seat's subject",subject:"mesh.seat.oci-artifact-registry.event.released",given:"{\"at\":\"2026-11-04T12:00:00Z\",\"by\":\"mesh-artifact-sweep\",\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"holder\":\"distribution\",\"name\":\"mesh-sdk\",\"reason\":\"kept by the sweep's rule\"}",wire:"{\"at\":\"2026-11-04T12:00:00Z\",\"by\":\"mesh-artifact-sweep\",\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"holder\":\"distribution\",\"name\":\"mesh-sdk\",\"reason\":\"kept by the sweep's rule\"}",
{name:"an open window",subject:"",given:"{\"holding\":[\"ace\"],\"name\":\"mesh-delivery-builder\",\"open\":true,\"since\":{\"ace\":\"2026-11-05T10:00:00Z\"}}",wire:"{\"holding\":[\"ace\"],\"name\":\"mesh-delivery-builder\",\"open\":true,\"since\":{\"ace\":\"2026-11-05T10:00:00Z\"}}",
{name:"publish opens a transfer",subject:"",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"bundle\",\"name\":\"mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"bundle\",\"name\":\"mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
{name:"a field the reader does not know is dropped",subject:"",given:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"bundle\",\"later\":{\"x\":1},\"name\":\"mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",wire:"{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"bundle\",\"name\":\"mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
{name:"publish answers what it lacks",subject:"",given:"{\"lacks\":[\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"transfer\":\"t1\"}",wire:"{\"lacks\":[\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"transfer\":\"t1\"}",
{name:"a chunk of a part",subject:"",given:"{\"data\":\"aGVsbG8=\",\"last\":true,\"part\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"sequence\":0,\"transfer\":\"t1\"}",wire:"{\"data\":\"aGVsbG8=\",\"last\":true,\"part\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"sequence\":0,\"transfer\":\"t1\"}",
{name:"a tagged version sharing its digest with another tag is kept, not removed",subject:"",given:"{\"kept\":true,\"reason\":\"shared-digest\",\"removed\":false,\"tags\":[\"0.1.19\"]}",wire:"{\"kept\":true,\"reason\":\"shared-digest\",\"removed\":false,\"tags\":[\"0.1.19\"]}",
{name:"list answers an untagged archive by the blob it keeps",subject:"",given:"{\"repositories\":[{\"manifests\":[{\"artifact\":\"sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"held\":true,\"index\":false,\"size\":4096}],\"name\":\"mail/files\"}]}",wire:"{\"repositories\":[{\"manifests\":[{\"artifact\":\"sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"held\":true,\"index\":false,\"size\":4096}],\"name\":\"mail/files\"}]}",
"description":"What the three build seats share: the verbs that read and steer a node's builds, and the layouts of the asks they accept and the steps they keep. A seat lists its states against these (a part carries no states).",
"verbs":[
{
"name":"current",
"description":"The asks this node runs now (each ask's id, kind, module and when it started), its build capacity, and whether it is paused, taking no new ask.",
"input":{
"type":"object",
"properties":{}
},
"answer":{
"type":"object",
"description":"the steps running, the capacity and whether paused"
}
},
{
"name":"pause",
"description":"Take no new ask on this node until resumed; an ask running here ends in its place. Kept across a restart of the build module. A capacity of 0 is the lasting way to keep a node from building.",
"input":{
"type":"object",
"properties":{}
},
"answer":{
"type":"object",
"description":"whether the node is paused"
}
},
{
"name":"resume",
"description":"Take asks again on this node.",
"input":{
"type":"object",
"properties":{}
},
"answer":{
"type":"object",
"description":"whether the node is paused"
}
}
],
"defs":{
"StepAsk":{
"type":"object",
"properties":{
"v":{
"type":"integer",
"description":"the layout version"
},
"id":{
"type":"string"
},
"kind":{
"type":"string",
"description":"build, check or compose"
},
"language":{
"type":"string",
"description":"go, typescript or image"
},
"asker":{
"type":"string"
},
"at":{
"type":"string",
"description":"when (RFC 3339 time)",
"format":"date-time"
},
"build":{
"type":"object",
"properties":{
"module":{
"type":"string"
},
"path":{
"type":"string"
},
"fp":{
"type":"string"
},
"fetch":{
"$ref":"#/defs/Fetch"
},
"artifacts":{
"type":"array",
"items":{
"$ref":"#/defs/AskArtifact"
}
},
"publish":{
"type":"boolean"
},
"toolchain":{
"$ref":"#/defs/ToolchainUsed"
}
},
"required":[
"module",
"artifacts"
]
},
"check":{
"type":"object",
"properties":{
"fetch":{
"$ref":"#/defs/Fetch"
},
"levels":{
"type":"array",
"items":{
"type":"string",
"description":"unit or integration"
}
},
"kept":{
"type":"boolean"
},
"runner":{
"type":"string"
},
"runner_when":{
"type":"string"
},
"run":{
"type":"string"
},
"packages":{
"type":"array",
"items":{
"type":"string"
}
},
"toolchain":{
"$ref":"#/defs/ToolchainUsed",
"description":"the toolchain the checker agreed for the language (ADR 0584 clause 2): a node on another declines the check"
},
"node-names":{
"type":"array",
"items":{
"type":"string"
},
"description":"the node names the check's tests run against"
}
},
"required":[
"fetch",
"levels"
]
},
"compose":{
"type":"object",
"properties":{
"fetch":{
"$ref":"#/defs/Fetch"
},
"dir":{
"type":"string"
},
"package":{
"type":"string"
},
"request":{
"description":"the compose-candidate request"
},
"reader":{
"type":"string"
}
},
"required":[
"fetch",
"dir",
"package",
"request"
]
},
"needs":{
"type":"array",
"items":{
"type":"string"
}
},
"packages":{
"type":"object",
"additionalProperties":{
"type":"string"
},
"description":"package to the tagged version a build pins"
}
},
"required":[
"id",
"kind",
"language",
"asker"
],
"description":"one ask of a build module"
},
"BuildAnswer":{
"type":"object",
"properties":{
"artifacts":{
"type":"array",
"items":{
"$ref":"#/defs/BuiltArtifact"
}
},
"toolchain":{
"$ref":"#/defs/ToolchainUsed"
},
"imports":{
"type":"array",
"items":{
"type":"string"
}
},
"out-of-step":{
"type":"array",
"items":{
"type":"string"
}
}
},
"required":[
"artifacts"
]
},
"CheckAnswer":{
"type":"object",
"properties":{
"fetch":{
"$ref":"#/defs/FetchAnswer"
},
"levels":{
"type":"array",
"items":{
"$ref":"#/defs/LevelAnswer"
}
}
},
"required":[
"fetch"
]
},
"ComposeAnswer":{
"type":"object",
"properties":{
"built":{
"type":"boolean"
},
"key":{
"type":"string"
},
"verdict":{
"description":"the compose-candidate verdict"
}
},
"required":[
"built"
]
},
"Step":{
"type":"object",
"properties":{
"v":{
"type":"integer",
"description":"the layout version"
},
"id":{
"type":"string"
},
"tool":{
"type":"string"
},
"node":{
"type":"string"
},
"state":{
"type":"string",
"description":"running, passed, failed or refused"
},
"started":{
"type":"string",
"description":"when (RFC 3339 time)",
"format":"date-time"
},
"ended":{
"type":"string",
"description":"when (RFC 3339 time)",
"format":"date-time"
},
"reason":{
"type":"string"
},
"result":{
"$ref":"#/defs/StepResult"
},
"what":{
"type":"string"
},
"phase":{
"type":"string"
},
"phase-at":{
"type":"string",
"description":"when (RFC 3339 time)",
"format":"date-time"
},
"owner":{
"type":"string"
}
},
"required":[
"id",
"tool",
"node",
"state",
"started"
],
"description":"one step a build module runs on a node"
},
"Toolchain":{
"type":"object",
"properties":{
"v":{
"type":"integer",
"description":"the layout version"
},
"language":{
"type":"string",
"description":"go or typescript"
},
"version":{
"type":"string"
},
"recipe":{
"type":"string"
},
"at":{
"type":"string",
"description":"when (RFC 3339 time)",
"format":"date-time"
}
},
"required":[
"language",
"version",
"recipe"
],
"description":"the toolchain a node reports"
},
"Pause":{
"type":"object",
"properties":{
"v":{
"type":"integer",
"description":"the layout version"
},
"paused":{
"type":"boolean"
},
"by":{
"type":"string"
},
"at":{
"type":"string",
"description":"when (RFC 3339 time)",
"format":"date-time"
}
},
"required":[
"paused"
],
"description":"whether the node takes no new ask"
},
"Capacity":{
"type":"object",
"properties":{
"v":{
"type":"integer",
"description":"the layout version"
},
"effective":{
"type":"integer"
},
"configured":{
"type":"integer"
},
"configured-from":{
"type":"string"
},
"quota-cores":{
"type":"number"
},
"quota-from":{
"type":"string"
},
"cores-per-step":{
"type":"number"
},
"by-cpu":{
"type":"integer"
},
"build-hours":{
"type":"string"
},
"outside-hours":{
"type":"boolean"
},
"build-hours-fault":{
"type":"string"
},
"ineligible":{
"type":"string"
},
"why":{
"type":"string"
},
"at":{
"type":"string",
"description":"when (RFC 3339 time)",
"format":"date-time"
}
},
"required":[
"effective",
"configured",
"why"
],
"description":"how many steps the node runs at once"
},
"Fetch":{
"type":"object",
"description":"what a build module's fetch tool is asked: the repository and the full commit, the pull request's ref when only its head carries the commit, the trunk commit to merge onto for a merge preview, the module's directory and named paths, the mesh packages to build against, and the sibling repositories placed beside",
"properties":{
"repository":{
"type":"string",
"description":"<owner>/<name>"
},
"commit":{
"type":"string",
"description":"the full commit"
},
"ref":{
"type":"string",
"description":"the pull request's ref, when only its head carries the commit"
},
"base":{
"type":"string",
"description":"the trunk commit a merge preview merges onto"
},
"dir":{
"type":"string",
"description":"the module's directory in the repository (\".\" for its root), with paths"
},
"paths":{
"type":"array",
"items":{
"type":"string"
},
"description":"the paths the module names, relative to dir"
},
"packages":{
"type":"object",
"additionalProperties":{
"type":"string"
},
"description":"the version (a full commit) of each mesh package to build against, by its module path"
},
"package":{
"type":"object",
"description":"the TypeScript module's group package: the group's tagged version of the SDK ({name, version}), placed from the registry in each member whatever its lock names, or the group's package member ({repository, commit, ref}), packed by the fetch and served to the members in place of the registry's",
"properties":{
"name":{"type":"string"},
"version":{"type":"string"},
"repository":{"type":"string"},
"commit":{"type":"string"},
"ref":{"type":"string"}
}
},
"beside":{
"type":"array",
"items":{
"type":"object",
"properties":{
"repository":{
"type":"string"
},
"commit":{
"type":"string"
}
},
"required":[
"repository",
"commit"
]
},
"description":"the sibling repositories placed beside the fetched tree"
}
},
"required":[
"repository",
"commit"
]
},
"ToolchainUsed":{
"type":"object",
"properties":{
"language":{
"type":"string"
},
"version":{
"type":"string"
},
"recipe":{
"type":"string"
}
},
"required":[
"language",
"version",
"recipe"
],
"description":"the toolchain a build was made with: the language, the installed version and the build module's recipe"
},
"AskArtifact":{
"type":"object",
"properties":{
"artifact":{
"type":"string"
},
"from":{
"type":"string"
},
"seat":{
"type":"string"
},
"version":{
"type":"string"
}
},
"required":[
"artifact"
],
"description":"one artifact of a build ask: built from the fetched tree, or copied from an upstream pin"
},
"BuiltArtifact":{
"type":"object",
"properties":{
"artifact":{
"type":"string"
},
"digest":{
"type":"string"
},
"reference":{
"type":"string"
}
},
"required":[
"artifact",
"digest"
],
"description":"one artifact a build made: its digest and the reference it was published under"
},
"LevelAnswer":{
"type":"object",
"properties":{
"level":{
"type":"string"
},
"judged":{
"type":"string"
},
"digest":{
"type":"object",
"properties":{
"level":{
"type":"string"
},
"packages":{
"type":"array",
"items":{
"type":"object",
"properties":{
"package":{
"type":"string"
},
"digest":{
"type":"string"
}
},
"required":[
"package",
"digest"
]
}
},
"beside":{
"type":"array",
"items":{
"type":"string"
}
},
"without_tests":{
"type":"array",
"items":{
"type":"string"
}
},
"judged_by":{
"type":"string"
},
"needs":{
"type":"array",
"items":{
"type":"object",
"properties":{
"package":{
"type":"string"
},
"needs":{
"type":"array",
"items":{
"type":"string"
}
}
}
}
}
}
},
"kept":{
"type":"array",
"items":{
"type":"object",
"properties":{
"package":{
"type":"string"
},
"digest":{
"type":"string"
},
"tests":{
"type":"integer"
}
}
}
},
"tests":{
"type":"array",
"items":{
"description":"one test's result"
}
},
"unmet":{
"type":"array",
"items":{
"type":"object",
"properties":{
"package":{
"type":"string"
},
"needs":{
"type":"array",
"items":{
"type":"string"
}
}
}
}
}
},
"required":[
"level"
],
"description":"one level of a check ask: the digest's answer, the kept verdicts taken, one test result per test step run, and the packages the node could not test"
},
"StepResult":{
"type":"object",
"description":"what a step answered, by the kind of ask: a build's artifacts, toolchain, imports and out-of-step modules; a check's fetch and levels; a compose's built, key and verdict; a declined ask's declined, needs and lacks. The fields of the kinds do not meet, so one layout holds the four",
"properties":{
"artifacts":{
"type":"array",
"items":{
"$ref":"#/defs/BuiltArtifact"
}
},
"toolchain":{
"$ref":"#/defs/ToolchainUsed"
},
"imports":{
"type":"array",
"items":{
"type":"string"
}
},
"out-of-step":{
"type":"array",
"items":{
"type":"string"
}
},
"fetch":{
"$ref":"#/defs/FetchAnswer"
},
"levels":{
"type":"array",
"items":{
"$ref":"#/defs/LevelAnswer"
}
},
"built":{
"type":"boolean"
},
"key":{
"type":"string"
},
"verdict":{
"description":"the compose-candidate verdict (the composer's own layout)"
},
"declined":{
"type":"boolean",
"description":"the holder declined the ask: its node lacks what the ask needs"
},
"needs":{
"type":"array",
"items":{
"type":"string"
},
"description":"what the declined ask needs"
},
"lacks":{
"type":"array",
"items":{
"type":"string"
},
"description":"what the holder's node lacks of it"
}
}
},
"ModuleTree":{
"type":"object",
"description":"the tree of one module directory in a merge preview: its git tree, the digest of its manifest, the lock files' digests and the digests of the named paths",
"properties":{
"tree":{
"type":"string"
},
"manifest":{
"type":"string"
},
"locks":{
"type":"object",
"additionalProperties":{
"type":"string"
}
},
"paths":{
"type":"object",
"additionalProperties":{
"type":"string"
}
},
"packages":{
"type":"array",
"items":{
"type":"string"
},
"description":"no longer filled (ADR 0593 section 2); kept so a preview written before still reads"
}
},
"required":[
"tree",
"manifest"
]
},
"Program":{
"type":"object",
"description":"a changed file that is a compiled program (issue 1577): its path, its executable format, and the commit of the branch that added it when the merge's tree no longer holds it",
"properties":{
"path":{
"type":"string"
},
"kind":{
"type":"string",
"description":"ELF, Mach-O or PE"
},
"commit":{
"type":"string"
}
},
"required":[
"path",
"kind"
]
},
"PlacedBeside":{
"type":"object",
"description":"a sibling repository placed as a plain directory under the workspace's beside directory",
"properties":{
"repository":{
"type":"string"
},
"commit":{
"type":"string"
},
"dir":{
"type":"string"
}
},
"required":[
"repository",
"commit",
"dir"
]
},
"TakenVersion":{
"type":"object",
"description":"of a directory whose go.mod requires an asked mesh package, the version it is built against: the asked one, or go.mod's when it names a newer one, said",
"properties":{
"dir":{
"type":"string"
},
"package":{
"type":"string"
},
"asked":{
"type":"string"
},
"named":{
"type":"string"
},
"built":{
"type":"string"
},
"sum":{
"type":"string"
},
"said":{
"type":"string"
}
},
"required":[
"dir",
"package",
"asked",
"named",
"built"
]
},
"FetchRefusal":{
"type":"object",
"description":"a TypeScript module whose packages the fetch did not install, with why",
"properties":{
"module":{
"type":"string"
},
"reason":{
"type":"string"
}
},
"required":[
"module",
"reason"
]
},
"FetchAnswer":{
"type":"object",
"description":"what a build module's fetch tool answers, whole: the workspace it made, the commit in it, the module directories found; and, when the call gave a base, the merge preview (the trunk commit, the merge commit, the files that conflict, the paths the merge changes, the compiled programs among them, the tree of each module directory). A head that does not merge cleanly is an answer, not an error: merge is empty and conflicts names the files. The Go module adds the sibling repositories placed and the package versions taken; the TypeScript module the directories installed and refused and the group's package",
"description":"The verbs and events every registry seat shares, written once so the four cannot drift (design 51, design 26). Who may call each verb is the holder's trusted config value listing its callers (ADR 0363's form), checked against the caller the tool runner proved.",
"verbs":[
{
"name":"publish",
"description":"Open a transfer, naming the artifact and the digest of every part; answers the digests the holder lacks, which the caller then sends by publish-part. A transfer already open answers the parts held, so a cut transfer goes on from there. With no parts and a version, the held digest is published under that version and nothing is stored (the trunk's claim).",
"callers":"the build modules",
"input":{
"type":"object",
"properties":{
"name":{
"type":"string",
"description":"the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)"
},
"version":{
"type":"string",
"description":"the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone"
},
"kind":{
"type":"string",
"enum":[
"package",
"image",
"bundle",
"archive",
"upstream"
],
"description":"what it is"
},
"tag":{
"type":"string",
"description":"the tag it carries, for a tagged version"
},
"digest":{
"type":"string",
"description":"its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)"
},
"fingerprint":{
"type":"string",
"description":"the build's fingerprint"
},
"commit":{
"type":"string",
"description":"the source commit it was built from"
},
"transfer":{
"type":"string",
"description":"the transfer's name, the caller's own; the same name opens the same transfer again"
},
"parts":{
"type":"array",
"items":{
"$ref":"#/defs/Part"
},
"description":"every part's digest and size; none when the digest is already held"
}
},
"required":[
"transfer",
"name",
"kind",
"digest"
]
},
"answer":{
"type":"object",
"properties":{
"transfer":{
"type":"string",
"description":"the transfer"
},
"lacks":{
"type":"array",
"items":{
"type":"string"
},
"description":"the digests of the parts the holder lacks, to send by publish-part"
},
"held":{
"type":"boolean",
"description":"the digest is held already: nothing to send; the outcome follows as an event"
}
},
"required":[
"transfer"
]
},
"optional":true
},
{
"name":"publish-part",
"description":"Send one chunk of one part of an open transfer; the last chunk of the last part ends the transfer, and the holder hashes what it received, asks builder_versions, stores it and says published or refused. A chunk's message stays under the bus's largest message (1 MiB), so at most 760 KiB of data, base64.",
"callers":"the build modules, and only the proved caller that opened the transfer",
"input":{
"type":"object",
"properties":{
"transfer":{
"type":"string",
"description":"the transfer"
},
"part":{
"type":"string",
"description":"the part's digest"
},
"sequence":{
"type":"integer",
"description":"the chunk's place in its part, from 0"
},
"last":{
"type":"boolean",
"description":"this chunk is the part's last"
},
"data":{
"type":"string",
"description":"the chunk's bytes, base64 (at most 760 KiB before encoding)"
}
},
"required":[
"transfer",
"part",
"sequence",
"last",
"data"
]
},
"answer":{
"type":"object",
"properties":{
"transfer":{
"type":"string",
"description":"the transfer"
},
"part":{
"type":"string",
"description":"the part"
},
"received":{
"type":"integer",
"description":"the chunks of the part held so far"
},
"complete":{
"type":"boolean",
"description":"the part is whole and its bytes match its digest"
}
},
"required":[
"transfer",
"part"
]
},
"optional":true
},
{
"name":"versions",
"description":"The versions the seat holds of one name, newest first: each one's version, tag, digest, kind and when it was published.",
"callers":"any caller whose role grants it",
"input":{
"type":"object",
"properties":{
"name":{
"type":"string",
"description":"the name"
},
"kind":{
"type":"string",
"description":"narrowed to one kind (optional)"
}
},
"required":[
"name"
]
},
"answer":{
"type":"object",
"properties":{
"name":{
"type":"string",
"description":"the name"
},
"versions":{
"type":"array",
"items":{
"$ref":"#/defs/Artifact"
},
"description":"newest first"
}
},
"required":[
"name",
"versions"
]
},
"optional":true
},
{
"name":"remove",
"description":"Remove one tagged version; the holder refuses an untagged one but for the retention removal of a bundle, archive or copied base by the artifact sweep's holder. Every removal emits removed with its reason. A tagged version the store cannot remove alone, because another tag names its digest, stays whole, its tag and bytes kept: the answer says kept with the reason shared-digest and the tags still naming the digest, removed false, and kept is emitted, never removed; the caller ends there without a retry.",
"callers":"the builder, for a tagged version; the artifact sweep's holder, for retention",
"input":{
"type":"object",
"properties":{
"name":{
"type":"string",
"description":"the name"
},
"version":{
"type":"string",
"description":"the version"
},
"tag":{
"type":"string",
"description":"the tag (for a tagged version)"
},
"digest":{
"type":"string",
"description":"the digest (for a bundle, archive or copied base)"
},
"reason":{
"type":"string",
"enum":[
"tag-gone",
"retention"
],
"description":"why it goes"
}
},
"required":[
"name",
"reason"
]
},
"answer":{
"type":"object",
"properties":{
"removed":{
"type":"boolean",
"description":"it is gone"
},
"kept":{
"type":"boolean",
"description":"it stays whole, its tag and its bytes: the store cannot remove the tag alone while another tag names its digest (reason, tags)"
},
"reason":{
"type":"string",
"enum":[
"shared-digest"
],
"description":"why it was kept: shared-digest, another tag names its digest"
},
"tags":{
"type":"array",
"items":{
"type":"string"
},
"description":"the other tags still naming its digest, when kept"
},
"artifact":{
"$ref":"#/defs/Artifact"
}
},
"required":[
"removed"
]
},
"optional":true
}
],
"events":[
{
"name":"published",
"body":{
"$ref":"#/defs/Outcome"
}
},
{
"name":"refused",
"body":{
"$ref":"#/defs/Outcome"
}
},
{
"name":"removed",
"body":{
"$ref":"#/defs/Outcome"
}
},
{
"name":"kept",
"body":{
"$ref":"#/defs/Outcome"
}
}
],
"defs":{
"Artifact":{
"type":"object",
"properties":{
"name":{
"type":"string",
"description":"the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)"
},
"version":{
"type":"string",
"description":"the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone"
},
"kind":{
"type":"string",
"enum":[
"package",
"image",
"bundle",
"archive",
"upstream"
],
"description":"what it is"
},
"tag":{
"type":"string",
"description":"the tag it carries, for a tagged version"
},
"digest":{
"type":"string",
"description":"its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)"
},
"fingerprint":{
"type":"string",
"description":"the build's fingerprint"
},
"commit":{
"type":"string",
"description":"the source commit it was built from"
}
},
"required":[
"name",
"kind",
"digest"
],
"description":"one published thing, as every registry event and answer names it"
},
"Part":{
"type":"object",
"properties":{
"digest":{
"type":"string",
"description":"the part's digest, sha256:<hex>: an image's layer or config, a package's file, a bundle's blob"
},
"size":{
"type":"integer",
"description":"its size in bytes"
}
},
"required":[
"digest",
"size"
],
"description":"one part of a transfer"
},
"Outcome":{
"type":"object",
"properties":{
"name":{
"type":"string",
"description":"the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)"
},
"module":{
"type":"string",
"description":"the Go module path a Go package is fetched under, equal to name for a Go package (go-package-registry's published); empty for every other kind of artifact"
},
"version":{
"type":"string",
"description":"the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone"
},
"kind":{
"type":"string",
"enum":[
"package",
"image",
"bundle",
"archive",
"upstream"
],
"description":"what it is"
},
"tag":{
"type":"string",
"description":"the tag it carries, for a tagged version"
},
"digest":{
"type":"string",
"description":"its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)"
},
"fingerprint":{
"type":"string",
"description":"the build's fingerprint"
},
"commit":{
"type":"string",
"description":"the source commit it was built from"
},
"holder":{
"type":"string",
"description":"the module holding the seat that said it"
},
"transfer":{
"type":"string",
"description":"the transfer it ends, when it ended one"
},
"reference":{
"type":"string",
"description":"the reference the seat answers: <registry>/<module>/<artifact>@sha256:<digest>, or <name>@<version> for a package (ADR 0605 §9)"
},
"reason":{
"type":"string",
"description":"why: a refusal's cause, a removal's (retention, tag-gone, by-hand), or why a removal was kept (shared-digest)"
},
"tags":{
"type":"array",
"items":{
"type":"string"
},
"description":"for kept: the other tags still naming its digest"
}
},
"required":[
"name",
"kind",
"digest",
"holder"
],
"description":"the body of published, refused and removed"
"description":"The mesh's container images, in the one artifact store: the OCI distribution protocol's read side, an image's tags and mirroring an outside image.",
"includes":[
"registry"
],
"verbs":[
{
"name":"mirror",
"description":"Copy an outside image into the store by its pinned digest; emits published or refused.",
"callers":"mesh-build-image's holder of the image build seat",
"input":{
"type":"object",
"properties":{
"source":{
"type":"string",
"description":"the outside image's reference"
},
"digest":{
"type":"string",
"description":"its pinned digest, sha256:<hex>"
},
"name":{
"type":"string",
"description":"the name it is kept under"
}
},
"required":[
"source",
"digest",
"name"
]
},
"answer":{
"type":"object",
"properties":{
"reference":{
"type":"string",
"description":"the reference the seat answers"
},
"digest":{
"type":"string",
"description":"the digest stored"
}
},
"required":[
"reference",
"digest"
]
},
"optional":true
},
{
"name":"tags",
"description":"The tags of one image and the digest each names.",
"callers":"any caller whose role grants it",
"input":{
"type":"object",
"properties":{
"name":{
"type":"string",
"description":"the image"
}
},
"required":[
"name"
]
},
"answer":{
"type":"object",
"properties":{
"name":{
"type":"string",
"description":"the image"
},
"tags":{
"type":"array",
"items":{
"type":"object",
"properties":{
"tag":{
"type":"string",
"description":"the tag"
},
"digest":{
"type":"string",
"description":"its digest"
}
},
"required":[
"tag",
"digest"
]
},
"description":"every tag"
}
},
"required":[
"name",
"tags"
]
},
"optional":true
},
{
"name":"hold",
"description":"Keep one untagged bundle, archive or copied base from removal by retention, as the artifact sweep's rules keep it (ADR 0617 §2); never an image of the holder's own. Emits held.",
"callers":"the module that runs the artifact sweep alone",
"input":{
"type":"object",
"properties":{
"name":{
"type":"string",
"description":"the name"
},
"digest":{
"type":"string",
"description":"the digest"
},
"reason":{
"type":"string",
"description":"which of the sweep's rules keeps it"
}
},
"required":[
"name",
"digest",
"reason"
]
},
"answer":{
"type":"object",
"properties":{
"held":{
"type":"boolean",
"description":"it is held"
},
"since":{
"type":"string",
"description":"when the hold began, RFC 3339"
}
},
"required":[
"held"
]
},
"optional":true
},
{
"name":"release",
"description":"Let a hold go; emits released. A release of what is not held answers released false and emits nothing, never an error: the outcome asked holds already. By hand only through the holder's own tool, the operator's session as the proved caller, recorded as a hand act.",
"callers":"the module that runs the artifact sweep; the operator's session through the holder's tool",
"input":{
"type":"object",
"properties":{
"name":{
"type":"string",
"description":"the name"
},
"digest":{
"type":"string",
"description":"the digest"
},
"reason":{
"type":"string",
"description":"why it is let go"
}
},
"required":[
"name",
"digest",
"reason"
]
},
"answer":{
"type":"object",
"properties":{
"released":{
"type":"boolean",
"description":"a hold was let go; false when there was none"
}
},
"required":[
"released"
]
},
"optional":true
},
{
"name":"list",
"description":"What the store holds of one repository, or of every repository the seat holds when none is named: every image manifest and index, each with its digest, whether it is an index (and the manifests an index names), the tags naming it, its size and whether it is held. Read from the store itself, so a manifest no tag names is listed too; it reads only (ADR 0632 §3).",
"callers":"any caller whose role grants it",
"input":{
"type":"object",
"properties":{
"name":{
"type":"string",
"description":"the repository, <module>/<artifact>; every repository of the seat when not given"
}
}
},
"answer":{
"type":"object",
"properties":{
"repositories":{
"type":"array",
"items":{
"$ref":"#/defs/Repository"
},
"description":"each repository named, in order of its name"
"description":"Every artifact the mesh made that lives in its artifact store, each with its repository, digest, kind (image or archive) and state: kept, and why (a want names it, or one of the five newest builds of its module in the builder's log), eligible (made, kept for no reason, not yet let go), or unrecorded (in the store and named by nothing the mesh made: never removed). Reads only.",
"input":{
"properties":{
"collected":{
"description":"\"true\": list the collected references too (counted always)",
"enum":[
"true",
"false"
],
"type":"string"
},
"repository":{
"description":"only this repository's references, as \u003cmodule\u003e/\u003cartifact\u003e (the counts stay whole)",
"type":"string"
}
},
"type":"object"
},
"answer":{
"type":"object",
"description":"what artifacts answers, as its description says"
}
},
{
"name":"held",
"description":"Whether the artifact store holds each reference given, asked with one HEAD each: held, gone (the store answered 404) or unknown with why. The builder asks it before it reuses a done key. Reads only.",
"input":{
"properties":{
"references":{
"description":"the artifacts' references, artifact-store://\u003cmodule\u003e/\u003cartifact\u003e/blobs/sha256:\u003chex\u003e: a list, or one text separated by commas",
"items":{
"type":"string"
},
"type":"array"
}
},
"required":[
"references"
],
"type":"object"
},
"answer":{
"type":"object",
"properties":{
"store":{
"type":"string",
"description":"the store asked, host and port"
},
"held":{
"type":"array",
"items":{
"type":"string"
},
"description":"the references the store holds"
},
"gone":{
"type":"array",
"items":{
"type":"string"
},
"description":"the references the store answered 404 for"
},
"unknown":{
"type":"object",
"additionalProperties":{
"type":"string"
},
"description":"a reference the store could not be asked about, to why"
}
},
"required":[
"held",
"gone"
],
"description":"what held answers: a reference is in held, gone or unknown, never none of them"
}
},
{
"name":"collect",
"description":"The artifact store's sweep, now: what is eligible is let go of. Without confirm a dry run: what would be let go, nothing held or deleted. With confirm and why: every kept archive held first, then each eligible artifact let go of, oldest first, an index with the platform manifests no kept index names, each deletion recorded in the hand-act log. Bounded by most (500 by default, at most 5000) and 45 seconds; what is left is said. Never touches a digest the mesh did not make.",
"input":{
"properties":{
"confirm":{
"description":"\"true\": let go of what is eligible (needs why); without it nothing is done",
"enum":[
"true",
"false"
],
"type":"string"
},
"most":{
"description":"let go of at most this many (500 by default, at most 5000)",
"type":"string"
},
"why":{
"description":"with confirm: why, required and recorded",
"type":"string"
}
},
"type":"object"
},
"answer":{
"type":"object",
"description":"what collect answers, as its description says"
}
},
{
"name":"mirrors",
"description":"The bases the mesh copied into its artifact store, each kept (a kept build stood on it), eligible (only builds no longer kept stood on it) or unrecorded (no build the builder's log holds stood on it: never removed), by what the builder's log says each build stood on. Records nothing by hand.",
"input":{
"properties":{},
"type":"object"
},
"answer":{
"type":"object",
"description":"what mirrors answers, as its description says"
}
},
{
"name":"images",
"description":"Every container image one machine's want and have name, each with the resources naming it: what the machine keeps when it prunes its images. Reads only.",
"input":{
"properties":{
"node":{
"description":"the machine's name",
"type":"string"
}
},
"required":[
"node"
],
"type":"object"
},
"answer":{
"type":"object",
"description":"what images answers, as its description says"
}
}
],
"family":{
"name":"mesh-artifact-sweep.events",
"max-age-days":7
},
"events":[
{
"name":"artifacts-gone",
"body":{
"$ref":"#/defs/ArtifactsGone"
}
}
],
"defs":{
"ArtifactsGone":{
"type":"object",
"properties":{
"event":{
"type":"string",
"description":"artifacts-gone"
},
"module":{
"type":"string",
"description":"the module whose builder's key names a gone artifact"
},
"key":{
"type":"string",
"description":"the builder's done key"
},
"fingerprint":{
"type":"string",
"description":"the key's fingerprint"
},
"gone":{
"type":"array",
"items":{
"type":"string"
},
"description":"every reference of the key the store does not hold, sorted"
"name":"a refused verdict (nats, read through the indexer's verdicts tool)",
"of":"state:verdicts/<digest>",
"given":{
"module":"nats",
"state":"refused",
"problems":[
"this is not a module manifest: a state is either a name or {name, history, ttl-seconds, per-machine, key-ttl}: json: unknown field \"read-only\" (read without state[2].read-only)"
"description":"Try pushed heads before their pull requests are opened: the checker judges them as it judges a delivery group's pull requests, each member merged onto its trunk, its unit and integration levels through the build modules, then the members' manifests, the module graph and the composition on every placed node, and owes the forge nothing. Name the group's members (each a repository and the exact commit), or one repository and its head for a try of one member. Answers the try's id at once; try-read reads where it stands. The same members at the same commits, in any order, are the answer to a second ask while that try waits or runs; at most 4 run on a build node, and 8 wait for one, mesh-wide.",
"optional":true,
"replaces":[
"sh merge-check.sh",
"docker run postgres"
],
"input":{
"properties":{
"head":{
"description":"the full commit to try, 40 or 64 hex digits, for a try of one member (instead of members)",
"type":"string"
},
"level":{
"description":"unit or integration: only this level; both when absent",
"type":"string"
},
"repository":{
"description":"<owner>/<name>, for a try of one member (instead of members)",
"type":"string"
},
"tests":{
"description":"a go test -run pattern: only those tests run, and nothing is kept",
"type":"string"
},
"trunk":{
"description":"the trunk commit to merge it onto, or the trunk's branch for its head now; the trunk's head when absent",
"type":"string"
},
"members":{
"description":"the group: one repository at most once, each at the exact commit asked and the trunk commit it is merged onto; instead of repository and head",
"type":"array",
"items":{
"type":"object",
"properties":{
"repository":{
"description":"<owner>/<name>",
"type":"string"
},
"head":{
"description":"the full commit to try, 40 or 64 hex digits",
"type":"string"
},
"trunk":{
"description":"the trunk commit to merge it onto, or the trunk's branch for its head now; the trunk's head when absent",
"type":"string"
}
},
"required":[
"repository",
"head"
]
}
}
},
"type":"object"
},
"answer":{
"type":"object",
"properties":{
"id":{
"type":"string",
"description":"the try's id"
},
"state":{
"type":"string",
"description":"its state"
}
},
"required":[
"id"
]
}
},
{
"name":"try-read",
"description":"Where a try stands, as stored: queued, running, or its end (pass, fail, or error when it could not run), with what was said of it, the head and the trunk commit it was merged onto, the time it took and what failed first. Read-only.",
"optional":true,
"input":{
"properties":{
"id":{
"description":"the try's id, try-<digits>",
"type":"string"
}
},
"required":[
"id"
],
"type":"object"
},
"answer":{
"type":"object",
"description":"the try: its state, its steps and its verdict when it has one"
}
},
{
"name":"try-end",
"description":"End a try that waits or runs, as error, by hand: say why (kept in what it says). Its place among the tries is free at once and the next try of its head asks anew with a new id. A try that ended already is refused.",
"optional":true,
"input":{
"properties":{
"id":{
"description":"the try's id, try-<digits>",
"type":"string"
},
"why":{
"description":"why it is ended, in words",
"type":"string"
}
},
"required":[
"id",
"why"
],
"type":"object"
},
"answer":{
"type":"object",
"properties":{
"id":{
"type":"string",
"description":"the try"
},
"ended":{
"type":"boolean",
"description":"it is ended"
}
},
"required":[
"id",
"ended"
]
}
}
],
"description":"The merge check's tries: start one, read one, end one. The checker's own events stay under its own subjects (ADR 0620 §2).",
"holder-events":[
{
"name":"verdict",
"subject":"mesh.stream.<holder>.event.verdict",
"family":"checker.asks",
"body":{
"type":"object",
"properties":{
"repository":{
"type":"string",
"description":"owner/repo"
},
"pull":{
"type":"integer",
"description":"the pull request's number, for a pull request's check"
},
"head":{
"type":"string",
"description":"the commit checked"
},
"verdict":{
"type":"string",
"description":"pass or fail"
},
"out-of-step":{
"type":"array",
"items":{
"type":"string"
},
"description":"the generated files out of step with their seat definitions, each path (design 26)"
},
"series":{
"type":"array",
"items":{
"type":"object",
"properties":{
"module":{
"type":"string",
"description":"the module whose artifact's series changes"
},
"artifact":{
"type":"string",
"description":"its artifact, or the package's ecosystem name as the module's packages name it"
},
"from":{
"type":"string",
"description":"the series on trunk"
},
"to":{
"type":"string",
"description":"the series the checked head gives it"
}
},
"required":[
"module",
"artifact",
"from",
"to"
]
},
"description":"each change of an artifact's series the checked head makes against trunk's manifests, once each (design 32); absent when it changes none"
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.