mesh-grants judges the controller's dependents with mesh-sdk's judge, and its keep list holds the three kept to the write
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
This commit is contained in:
@@ -3,7 +3,6 @@ package grants
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -27,232 +26,40 @@ const ToolLeaseCheck = "grants_lease_check"
|
||||
// Controller is the module and the seat the check is about.
|
||||
const Controller = "mesh-controller"
|
||||
|
||||
// The kinds of a dependency on the controller, as a manifest declares them.
|
||||
// **The judge is mesh-sdk's** (catalogue.Dependencies, catalogue.Judge; issue 774): the same judgement the three
|
||||
// repositories' manifest tests run through catalogue.ManifestRefusals (ADR 0571 §13), re-exported here by its names.
|
||||
const (
|
||||
DependsRead = "read"
|
||||
DependsInvoke = "invoke"
|
||||
DependsConsume = "consume"
|
||||
DependsUses = "uses"
|
||||
DependsWaits = "waits"
|
||||
DependsRead = catalogue.DependsRead
|
||||
DependsInvoke = catalogue.DependsInvoke
|
||||
DependsConsume = catalogue.DependsConsume
|
||||
DependsUses = catalogue.DependsUses
|
||||
DependsWaits = catalogue.DependsWaits
|
||||
PhaseBefore = catalogue.PhaseBefore
|
||||
PhaseWrite = catalogue.PhaseWrite
|
||||
)
|
||||
|
||||
// The phases of the lease write's check (ADR 0571 §13): before the lease write's own delivery the whole named list is
|
||||
// allowed; that delivery drops every entry but the three kept to the write itself, and its check runs with those alone.
|
||||
const (
|
||||
PhaseBefore = "before-delivery"
|
||||
PhaseWrite = "write"
|
||||
type (
|
||||
// Dependency, Kept, Verdict and Coverage are mesh-sdk's.
|
||||
Dependency = catalogue.Dependency
|
||||
Kept = catalogue.KeptDependency
|
||||
Verdict = catalogue.Verdict
|
||||
Coverage = catalogue.Coverage
|
||||
)
|
||||
|
||||
// Dependency is one declaration of a manifest other than the controller's on the controller: a read of one of its
|
||||
// states, an invoke of one of its verbs or tools, a consume or a wait on one of its events, or a send to its seat.
|
||||
type Dependency struct {
|
||||
Module string `json:"module"`
|
||||
// By is the account declaring it when it is not the module's own: `process <id>` or `tools <binary>`.
|
||||
By string `json:"by,omitempty"`
|
||||
Kind string `json:"kind"`
|
||||
What string `json:"what"`
|
||||
// Kept is the record that keeps it until the lease write, from the named list; empty when none does.
|
||||
Kept string `json:"kept,omitempty"`
|
||||
// ToTheWrite says it is one of the three kept to the write itself, which the lease write's own delivery keeps.
|
||||
ToTheWrite bool `json:"to_the_write,omitempty"`
|
||||
}
|
||||
// KeepList and EndedBy are mesh-sdk's named list and the records that ended what it no longer keeps.
|
||||
var (
|
||||
KeepList = catalogue.KeepList
|
||||
EndedBy = catalogue.EndedBy
|
||||
)
|
||||
|
||||
// Kept is one entry of the named, temporary list ADR 0571 §13 allows: a read, invoke or consume another accepted record
|
||||
// keeps until the lease write, with that record. ToTheWrite marks the three kept to the write itself.
|
||||
type Kept struct {
|
||||
Module, Kind, What, Record string
|
||||
ToTheWrite bool
|
||||
}
|
||||
|
||||
// KeepList is the named list. Each entry names the clause that keeps it; a dependency not on it fails the check. The
|
||||
// third entry kept to the write, the bus node agent's following of the controller's user list (ADR 0571 §8, ADR 0547
|
||||
// §8), is no manifest's declaration but the node-engine's own, so no manifest matches it; it stays named here so the
|
||||
// list reads as the record has it.
|
||||
var KeepList = []Kept{
|
||||
// Kept to the write itself (ADR 0571 §4, §8, §13).
|
||||
{Module: "mesh-delivery-builder", Kind: DependsConsume, What: "mesh-controller.artifacts-gone", Record: "ADR 0571 §4, §13", ToTheWrite: true},
|
||||
{Module: "artifact-store-tools", Kind: DependsInvoke, What: "seat:mesh-controller.collect", Record: "ADR 0571 §4, §13", ToTheWrite: true},
|
||||
{Module: "node-engine", Kind: DependsRead, What: "the controller's user list of the bus module's composition", Record: "ADR 0571 §8, §13; ADR 0547 §8", ToTheWrite: true},
|
||||
// Kept until the lease write's own delivery.
|
||||
{Module: "mesh-delivery-assigner", Kind: DependsInvoke, What: "seat:mesh-controller.placement-export", Record: "ADR 0567 §7"},
|
||||
{Module: "mesh-delivery-assigner", Kind: DependsInvoke, What: "seat:mesh-controller.assign", Record: "ADR 0567 §8"},
|
||||
{Module: "mesh-delivery-assigner", Kind: DependsInvoke, What: "seat:mesh-controller.unassign", Record: "ADR 0567 §8"},
|
||||
{Module: "mesh-delivery-assigner", Kind: DependsInvoke, What: "seat:mesh-controller.pin", Record: "ADR 0567 §8"},
|
||||
{Module: "mesh-delivery-assigner", Kind: DependsInvoke, What: "seat:mesh-controller.unpin", Record: "ADR 0567 §8"},
|
||||
{Module: "mesh-delivery-assigner", Kind: DependsRead, What: "mesh-controller.assignments", Record: "ADR 0567 §8"},
|
||||
{Module: "mesh-delivery-assigner", Kind: DependsRead, What: "mesh-controller.composed", Record: "ADR 0571 §8"},
|
||||
{Module: "mesh-grants", Kind: DependsRead, What: "mesh-controller.assignments", Record: "ADR 0549 §5"},
|
||||
{Module: "mesh-grants", Kind: DependsConsume, What: "mesh-controller.condition-raised", Record: "ADR 0564 §9"},
|
||||
{Module: "mesh-grants", Kind: DependsConsume, What: "mesh-controller.condition-cleared", Record: "ADR 0564 §9"},
|
||||
{Module: "messenger", Kind: DependsConsume, What: "mesh-controller.condition-raised", Record: "ADR 0564 §9"},
|
||||
{Module: "messenger", Kind: DependsConsume, What: "mesh-controller.condition-cleared", Record: "ADR 0564 §9"},
|
||||
{Module: "messenger", Kind: DependsConsume, What: "mesh-controller.condition-changed", Record: "ADR 0564 §9"},
|
||||
{Module: "messenger", Kind: DependsInvoke, What: "seat:mesh-controller.conditions", Record: "ADR 0564 §9"},
|
||||
{Module: "mesh-watcher", Kind: DependsConsume, What: "mesh-controller.doctor-heartbeat", Record: "ADR 0564 §9"},
|
||||
{Module: "mesh-conditions", Kind: DependsRead, What: "mesh-controller.conditions", Record: "ADR 0564 §9"},
|
||||
{Module: "mesh-config", Kind: DependsRead, What: "mesh-controller.declared-config", Record: "ADR 0565 §4"},
|
||||
{Module: "mesh-config", Kind: DependsRead, What: "mesh-controller.predefined", Record: "ADR 0565 §4"},
|
||||
{Module: "mesh-healers", Kind: DependsRead, What: "mesh-controller.hand-acts", Record: "ADR 0565 §11"},
|
||||
{Module: "mesh-hand-acts", Kind: DependsRead, What: "mesh-controller.hand-acts", Record: "ADR 0565 §11"},
|
||||
// pacman's fallback for a node whose engine has not written its own packages yet.
|
||||
{Module: "pacman", Kind: DependsRead, What: "mesh-controller.declared-packages", Record: "ADR 0565 §6"},
|
||||
}
|
||||
|
||||
// EndedBy names, for a declaration no entry keeps, the record that already ended it, so a refusal says where it moved.
|
||||
// The controller's `grants` is one: ADR 0571 §9 has no manifest read it from L7's delivery, which changes ADR 0567 §10
|
||||
// and ADR 0547 §5's shadow compare, so neither the assigner's nor the grants part's read of it is kept.
|
||||
var EndedBy = map[string]string{
|
||||
DependsRead + " mesh-controller.grants": "ADR 0571 §9: no manifest reads the controller's grants; the grants part's key is the one read",
|
||||
DependsInvoke + " seat:mesh-controller.hand-act": "ADR 0565 §11: every recorder calls mesh-hand-acts",
|
||||
DependsInvoke + " seat:mesh-controller.warranted": "ADR 0565 §11: every recorder calls mesh-hand-acts",
|
||||
DependsInvoke + " seat:mesh-controller.root-free": "ADR 0571 §11: each machine's engine answers root-free (seat:node-engine.root-free@machine)",
|
||||
DependsInvoke + " seat:mesh-controller.held": "ADR 0571 §2: held is the seat mesh-artifact-sweep's",
|
||||
}
|
||||
|
||||
// keptFor is the list's entry for one dependency, or nil.
|
||||
func keptFor(d Dependency) *Kept {
|
||||
for i, k := range KeepList {
|
||||
if k.Module == d.Module && k.Kind == d.Kind && k.What == d.What {
|
||||
return &KeepList[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// onController says whether a name `<owner>.<rest>` is the controller's.
|
||||
func onController(name string) bool { return strings.HasPrefix(name, Controller+".") }
|
||||
|
||||
// invokesController says whether an invoke names a verb of the controller's seat or a tool of its module. `*` names none:
|
||||
// it is the console's grant to every tool, judged by no record as a dependency.
|
||||
func invokesController(invoke string) bool {
|
||||
if seat, _, ok := catalogue.SeatInvoke(invoke); ok {
|
||||
return seat == Controller
|
||||
}
|
||||
return onController(invoke)
|
||||
}
|
||||
|
||||
// Dependencies are every declaration on the controller in the manifests given, by module, each with the list's entry
|
||||
// that keeps it. The controller's own manifest is not judged, nor a read of its lease key: it names the lease's holder,
|
||||
// whoever that is, and parts read it to learn that the write happened (ADR 0571 §13).
|
||||
// Dependencies are every declaration on the controller in the manifests given (catalogue.Dependencies).
|
||||
func Dependencies(manifests map[string]catalogue.Manifest) []Dependency {
|
||||
var out []Dependency
|
||||
add := func(module, by, kind, what string) {
|
||||
d := Dependency{Module: module, By: by, Kind: kind, What: what}
|
||||
if k := keptFor(d); k != nil {
|
||||
d.Kept, d.ToTheWrite = k.Record, k.ToTheWrite
|
||||
}
|
||||
if !slices.Contains(out, d) {
|
||||
out = append(out, d)
|
||||
}
|
||||
}
|
||||
for name, m := range manifests {
|
||||
if name == Controller || m.Module == Controller {
|
||||
continue
|
||||
}
|
||||
for _, r := range m.Reads {
|
||||
if onController(r) && r != buscompose.ControllerLease {
|
||||
add(name, "", DependsRead, r)
|
||||
}
|
||||
}
|
||||
for _, i := range m.Invokes {
|
||||
if invokesController(i) {
|
||||
add(name, "", DependsInvoke, i)
|
||||
}
|
||||
}
|
||||
for _, c := range m.Consumes {
|
||||
if onController(c) {
|
||||
add(name, "", DependsConsume, c)
|
||||
}
|
||||
}
|
||||
for _, w := range m.Waits {
|
||||
if onController(w) {
|
||||
add(name, "", DependsWaits, w)
|
||||
}
|
||||
}
|
||||
for _, u := range m.Uses {
|
||||
if u == Controller {
|
||||
add(name, "", DependsUses, u)
|
||||
}
|
||||
}
|
||||
for _, a := range m.BusAccounts() {
|
||||
by := "process " + a.ID
|
||||
if a.Tools {
|
||||
by = "tools " + a.ID
|
||||
}
|
||||
for _, i := range a.Bus.Invokes {
|
||||
if invokesController(i) {
|
||||
add(name, by, DependsInvoke, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(out, func(i, j int) bool {
|
||||
a, b := out[i], out[j]
|
||||
if a.Module != b.Module {
|
||||
return a.Module < b.Module
|
||||
}
|
||||
if a.Kind != b.Kind {
|
||||
return a.Kind < b.Kind
|
||||
}
|
||||
if a.What != b.What {
|
||||
return a.What < b.What
|
||||
}
|
||||
return a.By < b.By
|
||||
})
|
||||
return out
|
||||
return catalogue.Dependencies(manifests)
|
||||
}
|
||||
|
||||
// Verdict is the lease write's check in one phase.
|
||||
type Verdict struct {
|
||||
Phase string `json:"phase"`
|
||||
Passes bool `json:"passes"`
|
||||
Reasons []string `json:"reasons"`
|
||||
}
|
||||
|
||||
// Coverage is how much of the indexer the dependencies were derived from: the manifests read, the modules the indexer
|
||||
// holds (-1 when its keys could not be listed, which Unread then names), and each manifest that could not be read.
|
||||
type Coverage struct {
|
||||
Read, Indexed int
|
||||
Unread []Gap
|
||||
}
|
||||
|
||||
// Judge runs the lease write's check over the dependencies (ADR 0571 §13) in one phase: before the lease write's own
|
||||
// delivery, every dependency must be on the named list; at the write, only the three kept to the write itself may stay.
|
||||
// It passes only over every module the indexer holds: no manifest read, fewer read than the indexer holds, or one that
|
||||
// could not be read fails it, since what was not read could hide a dependency. A lease already handed away leaves
|
||||
// nothing to write.
|
||||
// Judge runs the lease write's check in one phase (catalogue.Judge).
|
||||
func Judge(deps []Dependency, phase string, cov Coverage, handedAway bool, leaseSays string) Verdict {
|
||||
v := Verdict{Phase: phase, Reasons: []string{}}
|
||||
if handedAway {
|
||||
v.Reasons = append(v.Reasons, "there is nothing to write: "+leaseSays)
|
||||
}
|
||||
switch {
|
||||
case cov.Read == 0:
|
||||
v.Reasons = append(v.Reasons, fmt.Sprintf("no manifest was read from the indexer (it holds %d modules): with nothing read, nothing on the controller can be judged absent", max(cov.Indexed, 0)))
|
||||
case cov.Indexed >= 0 && cov.Read < cov.Indexed:
|
||||
v.Reasons = append(v.Reasons, fmt.Sprintf("only %d of the %d modules the indexer holds had their manifest read, so what the others declare on the controller is not known", cov.Read, cov.Indexed))
|
||||
}
|
||||
for _, d := range deps {
|
||||
who := d.Module
|
||||
if d.By != "" {
|
||||
who += " (" + d.By + ")"
|
||||
}
|
||||
switch {
|
||||
case d.Kept == "":
|
||||
why := fmt.Sprintf("%s declares %s %s, which no record keeps until the lease write (ADR 0571 §13)", who, d.Kind, d.What)
|
||||
if ended := EndedBy[d.Kind+" "+d.What]; ended != "" {
|
||||
why += "; ended by " + ended
|
||||
}
|
||||
v.Reasons = append(v.Reasons, why)
|
||||
case phase == PhaseWrite && !d.ToTheWrite:
|
||||
v.Reasons = append(v.Reasons, fmt.Sprintf("%s declares %s %s, kept by %s only until the lease write's own delivery, which drops it", who, d.Kind, d.What, d.Kept))
|
||||
}
|
||||
}
|
||||
for _, g := range cov.Unread {
|
||||
v.Reasons = append(v.Reasons, fmt.Sprintf("%s could not be read (%s), so what it declares on the controller is not known", g.Input, g.Why))
|
||||
}
|
||||
v.Passes = len(v.Reasons) == 0
|
||||
return v
|
||||
return catalogue.Judge(deps, phase, cov, handedAway, leaseSays)
|
||||
}
|
||||
|
||||
// LeaseNow is who holds the lease and what follows from it.
|
||||
@@ -274,7 +81,6 @@ var (
|
||||
"mesh-healers writes each act it would take in `would`, and acts on none (ADR 0564 §8)",
|
||||
"the artifact sweep lets go of nothing; the controller's take-in sweeps and says `artifacts-gone` (ADR 0571 §4)",
|
||||
"the watchman only lists dead letters; the controller keeps DEAD_LETTERS through its consumer of DEAD_LETTER_NOTICES (ADR 0564 §5)",
|
||||
"placement proposals take only assignments, pins and config values, and the assigner keeps the controller's assignments in step (ADR 0567 §8, §9)",
|
||||
"the controller keeps composing for the bus node, whose agent follows its user list, so the hand-backs of config, conditions, placement and the user list still answer (ADR 0547 §8, ADR 0564 §9, ADR 0565 §4, ADR 0567 §11)",
|
||||
}
|
||||
DoesHandedAway = []string{
|
||||
@@ -414,8 +220,6 @@ type LeaseAnswer struct {
|
||||
Streams []StreamUse `json:"streams,omitempty"`
|
||||
Idle []string `json:"streams_idle,omitempty"`
|
||||
StreamsError string `json:"streams_unread,omitempty"`
|
||||
// Assignments is how many of the controller's assignments stand, which it publishes memberships and grants for.
|
||||
Assignments int `json:"assignments_standing"`
|
||||
// Check is the dry run at the write (the three alone), Before the same over the whole list before the write's
|
||||
// delivery.
|
||||
Check Verdict `json:"check"`
|
||||
@@ -451,20 +255,16 @@ func (p *Part) LeaseCheck() (any, error) {
|
||||
out.Unkept[d.Module] = append(out.Unkept[d.Module], d.Kind+" "+d.What)
|
||||
}
|
||||
}
|
||||
var gaps []Gap
|
||||
for _, raw := range each(p.Read, ReadAssignments, &gaps) {
|
||||
var a assignment
|
||||
if json.Unmarshal(raw, &a) == nil && a.stands() {
|
||||
out.Assignments++
|
||||
}
|
||||
}
|
||||
if used, idle, err := Duties(p.Call); err != nil {
|
||||
out.StreamsError = err.Error()
|
||||
} else {
|
||||
out.Streams, out.Idle = used, idle
|
||||
}
|
||||
// Only the indexer's own modules count as read: a manifest the mesh provides itself must not stand in for one missing.
|
||||
cov := Coverage{Indexed: -1, Unread: out.Unread}
|
||||
cov := Coverage{Indexed: -1}
|
||||
for _, g := range out.Unread {
|
||||
cov.Unread = append(cov.Unread, catalogue.Unread{Input: g.Input, Why: g.Why})
|
||||
}
|
||||
if keys, err := p.Read.Keys(ReadModules); err == nil {
|
||||
cov.Indexed = len(keys)
|
||||
for _, k := range keys {
|
||||
|
||||
@@ -13,7 +13,9 @@ import (
|
||||
|
||||
// Issue 774, design 47 L3 (ADR 0547 §11, ADR 0561 §3, ADR 0571 §13): grants_lease_check answers from bus state who holds
|
||||
// the controller's lease, every manifest's dependency on the controller with what keeps it, the controller's streams in
|
||||
// use, and the lease write's check run dry, at the write (the three kept to it alone) and before its delivery.
|
||||
// use, and the lease write's check run dry, at the write (the three kept to it alone) and before its delivery. The
|
||||
// judgement of each kind of dependency is mesh-sdk's and tested there (catalogue/controller_dependence_test.go, its rows
|
||||
// moved from here, 774/S4); these rows are the tool's own: what it read, the lease, the streams.
|
||||
func TestTheLeaseCheckJudgesEveryDependencyOnTheController(t *testing.T) {
|
||||
const mManifest = `{"module":"mod-m","version":"1","reads":["mesh-controller.declared-packages"]}`
|
||||
controllerHolds := map[string]any{"instance": "controller@novox-be pid 1 since 2026-10-30T14:52:10Z", "epoch": 60,
|
||||
@@ -39,33 +41,6 @@ func TestTheLeaseCheckJudgesEveryDependencyOnTheController(t *testing.T) {
|
||||
map[string]string{"mod-l": `{"module":"mod-l","version":"1","reads":["mesh-controller.lease"]}`,
|
||||
"mesh-controller": `{"module":"mesh-controller","version":"1","invokes":["seat:mesh-controller.status"]}`},
|
||||
controllerHolds, want{writePasses: true, beforePasses: true}, nil},
|
||||
{"the builder's consume of artifacts-gone is kept to the write itself",
|
||||
map[string]string{"mesh-delivery-builder": `{"module":"mesh-delivery-builder","version":"1","consumes":["mesh-controller.artifacts-gone"]}`},
|
||||
controllerHolds, want{deps: []string{"mesh-delivery-builder consume mesh-controller.artifacts-gone kept"}, writePasses: true, beforePasses: true}, nil},
|
||||
{"the assigner's read of composed is kept until the write's delivery, which drops it",
|
||||
map[string]string{"mesh-delivery-assigner": `{"module":"mesh-delivery-assigner","version":"1","reads":["mesh-controller.composed","mesh-controller.lease"]}`},
|
||||
controllerHolds, want{deps: []string{"mesh-delivery-assigner read mesh-controller.composed kept"}, beforePasses: true,
|
||||
reason: "mesh-delivery-assigner declares read mesh-controller.composed, kept by ADR 0571 §8 only until the lease write's own delivery"}, nil},
|
||||
{"pacman's read of declared-packages is kept until the write's delivery, which drops it",
|
||||
map[string]string{"pacman": `{"module":"pacman","version":"1","reads":["mesh-controller.declared-packages"]}`},
|
||||
controllerHolds, want{deps: []string{"pacman read mesh-controller.declared-packages kept"}, beforePasses: true,
|
||||
reason: "pacman declares read mesh-controller.declared-packages, kept by ADR 0565 §6 only until the lease write's own delivery"}, nil},
|
||||
{"a read no record keeps fails both phases, named",
|
||||
map[string]string{"mod-u": `{"module":"mod-u","version":"1","reads":["mesh-controller.declared-packages"]}`},
|
||||
controllerHolds, want{deps: []string{"mod-u read mesh-controller.declared-packages unkept"},
|
||||
reason: "mod-u declares read mesh-controller.declared-packages, which no record keeps until the lease write"}, nil},
|
||||
{"a seat verb and a module tool of the controller's, a consume and a wait are each one; every tool (*) is none",
|
||||
map[string]string{"mod-i": `{"module":"mod-i","version":"1","invokes":["seat:mesh-controller.root-free","mesh-controller.status","*","nats.nats_users"],` +
|
||||
`"consumes":["mesh-controller.checked","mod-x.thing"],"uses":["mesh-controller"]}`,
|
||||
"node-tools": `{"module":"node-tools","version":"1","waits":["mesh-controller.checked"]}`},
|
||||
controllerHolds, want{deps: []string{"mod-i consume mesh-controller.checked unkept", "mod-i invoke mesh-controller.status unkept",
|
||||
"mod-i invoke seat:mesh-controller.root-free unkept", "mod-i uses mesh-controller unkept", "node-tools waits mesh-controller.checked unkept"},
|
||||
reason: "mod-i declares invoke seat:mesh-controller.root-free, which no record keeps"}, nil},
|
||||
{"a process's own invoke of the controller is its module's dependency, named by the process",
|
||||
map[string]string{"mod-p": `{"module":"mod-p","version":"1","resources":[{"id":"account","type":"user","name":"mod-p"},{"id":"worker","type":"process","run":["./w"],"user":"mod-p",` +
|
||||
`"bus":{"invokes":["seat:mesh-controller.held"]}}]}`},
|
||||
controllerHolds, want{deps: []string{"mod-p invoke seat:mesh-controller.held unkept"},
|
||||
reason: "mod-p (process worker) declares invoke seat:mesh-controller.held"}, nil},
|
||||
{"no manifest read from the indexer fails both phases, though nothing read depends on the controller",
|
||||
map[string]string{},
|
||||
controllerHolds, want{reason: "no manifest was read from the indexer (it holds 0 modules)", bothPhases: true}, nil},
|
||||
@@ -144,19 +119,3 @@ func TestTheLeaseCheckJudgesEveryDependencyOnTheController(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Every entry of the keep list names the record that keeps it, and exactly three are kept to the write itself (ADR 0571 §13).
|
||||
func TestTheKeepListNamesItsRecordsAndThreeToTheWrite(t *testing.T) {
|
||||
toTheWrite := 0
|
||||
for _, k := range grants.KeepList {
|
||||
if !strings.HasPrefix(k.Record, "ADR ") || k.Module == "" || k.What == "" {
|
||||
t.Errorf("entry %+v names no record, module or declaration", k)
|
||||
}
|
||||
if k.ToTheWrite {
|
||||
toTheWrite++
|
||||
}
|
||||
}
|
||||
if toTheWrite != 3 {
|
||||
t.Errorf("%d entries kept to the write itself, ADR 0571 §13 names three", toTheWrite)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user