Files
mesh-controller/internal/link/contracts.go
T
jschoubben 48d9f22fa5 Retire the controller's merges consumer and read merges from the forge bridge's stream, so a held merge can never again queue every merge or look like a deaf controller (issue 774)
The controller-merges consumer (no max-deliver, one at a time) held the de-spiegel merge e25e1beb from
10-29 09:39: keepForgeMerge put an announcement with its Paths into delivery-merges (16 KiB values), got
10054, retried "not now" forever, and 167 merges queued behind it. Every five-minute hold outran the deaf
bound, so core.controller.deaf flapped.

Merges are mesh-delivery's: the gate merges on the Approve and the forge bridge says each merge on its
stream FORGE (pull request, head, merge commit), kept a week. The controller's copy was a leftover, read
only at a moved module's registration (ADR 0420 §7, ADR 0432). That read now finds the merge on FORGE;
the consumer, its follow, its handler and its hold delays are removed, and every assertion removes the
retired consumer from the bus.

Kind fix for the watchdog: the event loop records when a message it held back is due again, and deafness
counts from then, so no hold longer than the bound (on any consumer) reads as deafness.

Quick fix: strip Paths from the kept announcement and add max-deliver with a dead letter. Thorough fix:
remove the duplicate duty and make the deaf watchdog hold-aware. Chose thorough: the controller is being
deprecated and the merges already have an owner; the hold-vs-deaf confusion is a kind, not one consumer.

Research 072 piece: 03-domains (Control shrinks to placement and composition; the delivery parts own
what a merge is) and milestone 3 (health signals stop sharing the controller's loop assumptions).
2026-10-30 18:05:46 +01:00

63 lines
4.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package link
// The contract of every message kind the controller consumes (novox/hq to-be 45 Phase 2, ADR 0227 rule
// 2 "how it is checked": a contract test per consumed message kind in the receiver's repository, and a
// check listing every consumed subject against the tests that name it).
//
// **Each kind says how an older one is told from a newer, and the tests that deliver n, then n−1.** A
// kind that carries no order says why none is needed — a word whose newest is simply the latest heard,
// a request answered once. The test beside it fails a kind the controller can be handed without an
// entry here, and an entry naming a test that does not exist.
// Contract is one consumed kind's order.
type Contract struct {
// Ordered is how an older message of this kind is refused; empty for a kind that carries no order.
Ordered string
// Unordered is why a kind needs no order; empty for an ordered one.
Unordered string
// Tests are the tests that deliver the newer and then the older, and assert the older refused.
Tests []string
}
// Contracts are every kind the controller consumes, by kind.
var Contracts = map[string]Contract{
KindReport: {Ordered: "by the epoch and sequence of the declaration it is about, then the node-engine's " +
"report sequence (order.go); an older account is refused and counted. A report from a node-engine " +
"that orders nothing is judged by the digest it names (issue 267)",
Tests: []string{"TestAnAccountOfAnOlderDeclarationIsRefusedByItsSequence",
"TestAnOlderReportOfTheSameDeclarationIsRefused", "TestAnAccountOfAnOlderDeclarationIsRefusedByItsSequence",
"TestAnAccountIsOlderByEpochThenSequenceThenReportSequence"}},
KindBuilt: {Unordered: "a build's outcome on the retired build seat's subjects: dropped, nothing takes a build in " +
"from the bus any more (R4g, ADR 0501 §1); the subjects stay followed while the installer's carried user list " +
"names them"},
KindSourceMoved: {Unordered: "the forge's merge on EVENTS: no longer followed, dropped if one arrives; the forge " +
"bridge's stream FORGE is the record of the merges, read at a moved module's registration (sweep 2026-10-30)"},
KindToolsHeartbeat: {Unordered: "a word that the node tools are there, as a machine's heartbeat"},
KindHealth: {Ordered: "by the time the node-engine looked (`at`, on the machine's clock): a statement older " +
"than the one kept for that machine is refused, so an event arriving after a newer report does not undo it " +
"(novox/hq ADR 0240)",
Tests: []string{"TestAnOlderHealthStatementIsRefused"}},
KindEnrolment: {Unordered: "a request answered once, under a token spent once: a second presentation is " +
"refused by the token, not by an order (issue 083)",
Tests: []string{"TestAnEnrolmentMetByAHeldTokenIsAskedToTryAgain"}},
KindModuleMoved: {Unordered: "the catalogue saying a module's current build moved: acted on by reading the " +
"catalogue's record, which is the order, so a late one reads the same record"},
KindPullUpdated: {Unordered: "a pull request's head, asked to be checked: each head is its own commit, and its " +
"verdict is set on that commit alone, so a head heard late is checked and judged as itself and never " +
"stands for a newer one (novox/hq to-be 45 §9)"},
KindDecided: {Unordered: "the router's word on one ask, by the ask's id: an ask is ended once, by compare-and-set " +
"at the router, and the controller acts on it once, recording that it did under the ask's id — so a word " +
"heard again, or late, does nothing more (novox/hq ADR 0259)",
Tests: []string{"TestAWarrantIsActedOnOnce"}},
KindDeliveryMerged: {Unordered: "mesh-delivery's word that it merged a pull request, by the pull request and its head: " +
"kept under that key once, so a word heard again or late rewrites the same value (novox/hq ADR 0420 §7)"},
KindCatchUp: {Unordered: "a catalogue asking what it missed: answered from the record, whenever asked"},
KindProvisioner: {Unordered: "a provider's newest word about a consumer, said again every fifteen minutes " +
"while it holds (ADR 0224): the condition keeps the last observed, and S8 says when the words stop. " +
"Its retirement word (ADR 0230) is unordered too: a waiting set is said again every fifteen minutes, " +
"and every other change is checked against the provider itself — `retire` and `cleanup` ask it, " +
"and the self-check's D11 asks it every run — so an older word read late is corrected by the next",
Tests: []string{"TestAProviderFailingAConsumerBreaksAllWellUntilItRecovers",
"TestARetirementWordIsKeptAsItsConditionNamingTheEmitterFromTheSubject"}},
}