From 316af50da36a32865ac252e5d6de9b534f90dd83 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 12 Nov 2026 09:15:40 +0100 Subject: [PATCH] VW3: the view's tiers are the assigner's difference of a source revision's kept revision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit view_tiers compares the kept assignment revision whose catalog carries the source revision with the one kept before it, through the seat mesh-wants' verbs revision and difference (view/difference.go, tiers.go Tiers), and reads the tiers and each module's after (module and edge kind) from the answer; the view orders nothing. The manifest invokes the two verbs. Builds: design 47 G §512, §186, A-242 --- .../cmd/mesh-delivery-view-tools/main.go | 1 + .../tiers_rows_test.go | 60 ++++++-- .../internal/view/difference.go | 93 ++++++++++++ .../mesh-delivery-view/internal/view/read.go | 5 + .../mesh-delivery-view/internal/view/tiers.go | 138 ++++++++---------- modules/mesh-delivery-view/manifest_test.go | 2 + modules/mesh-delivery-view/module.json | 2 + 7 files changed, 205 insertions(+), 96 deletions(-) create mode 100644 modules/mesh-delivery-view/internal/view/difference.go diff --git a/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/main.go b/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/main.go index 27d69d37..3d2d7c34 100644 --- a/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/main.go +++ b/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/main.go @@ -438,6 +438,7 @@ func main() { r.ConditionsState, r.AttemptsState = read(stdio.State(view.StatusConditionsState)), read(stdio.State(view.StatusAttemptsState)) r.PresenceState, r.StuckState = read(stdio.State(view.StatusPresenceState)), read(stdio.State(view.StatusStuckState)) r.Sources = view.SourcesOf(stdio.Ask, branches.Followed) + r.Assignment, r.Difference = view.AssignmentOf(stdio.Ask), view.DifferenceOf(stdio.Ask) r.ProvisionsState = read(stdio.State(view.ProvisionsRead)) r.BuildLog = stdio.Log(builds.BuildLogRead).Since r.Pending = pendingOf diff --git a/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/tiers_rows_test.go b/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/tiers_rows_test.go index 5d0e6dba..2b1d533b 100644 --- a/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/tiers_rows_test.go +++ b/modules/mesh-delivery-view/cmd/mesh-delivery-view-tools/tiers_rows_test.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshdelivery" + "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshwants" "mesh-delivery-view/internal/view" "reflect" "strings" @@ -16,9 +17,7 @@ import ( "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient" "git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" - "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/clients/meshcatalogclient" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/clients/meshwantsclient" - "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshcatalog" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-sdk/graph" ) @@ -41,10 +40,6 @@ func short(fp string) string { return fp[:len("src2:")+12] } func tiersToolSaysEachModulesWait(t *testing.T) { fp := func(c string) string { return "src2:" + strings.Repeat(c, 64) } manifest := strings.Repeat("d", 64) - mod := func(f string, src uint64) string { - b, err := meshcatalogclient.EncodeModule(meshcatalog.ModulesByModuleValue{Fp2: f, Manifest: manifest, Src: int64(src), FpSrc: int64(src), Repository: "novox/mesh-catalog", Commit: "c"}) - return encoded(t, b, err) - } node := func(g graph.Node) string { b, err := graph.Encode(g) return encoded(t, b, err) @@ -68,7 +63,35 @@ func tiersToolSaysEachModulesWait(t *testing.T) { return k } since := time.Date(2026, 11, 3, 16, 40, 0, 0, time.UTC) - r := fake{"db": mod(fp("a"), 9), "web": mod(fp("b"), 9), "lib": mod(fp("c"), 9), "old": mod(fp("e"), 5)}.reader() + r := fake{}.reader() + // The tiers are the assigner's difference of the kept revision carrying source revision 9 against the one before it (design + // 47 G §512, A-242): db and lib first, web after db by its provisioning edge; the view orders nothing. + ref := func(m string) meshwants.NodeEntryRef { return meshwants.NodeEntryRef{Node: "ace", Module: m, Digest: "sha256:" + m} } + kept := map[int64]meshwants.AssignmentRevision{ + 3: {Revision: 3, Catalogs: []meshwants.CatalogOf{{Branch: "release", Revision: 2, Source: 5}}}, + 4: {Revision: 4, Catalogs: []meshwants.CatalogOf{{Branch: "release", Revision: 3, Source: 8}}}, + 5: {Revision: 5, Catalogs: []meshwants.CatalogOf{{Branch: "release", Revision: 4, Source: 9}}}, + 6: {Revision: 6, Catalogs: []meshwants.CatalogOf{{Branch: "release", Revision: 4, Source: 9}}}, + } + differences := map[[2]int64]meshwants.Difference{{4, 5}: {From: 4, To: 5, + Changes: []meshwants.Change{{Node: "ace", Module: "db", To: fp("a")}, {Node: "ace", Module: "lib", To: fp("c")}, + {Node: "ace", Module: "web", To: fp("b"), After: []meshwants.ChangeAfterItem{{Node: "ace", Module: "db", Kind: "provisioning"}}}}, + Tiers: [][]meshwants.NodeEntryRef{{ref("db"), ref("lib")}, {ref("web")}}}} + r.Assignment = func(n int64) (meshwants.AssignmentRevision, error) { + if n == 0 { + n = 6 + } + if rev, ok := kept[n]; ok { + return rev, nil + } + return meshwants.AssignmentRevision{}, errors.New("not kept") + } + r.Difference = func(from, to int64) (meshwants.Difference, error) { + if d, ok := differences[[2]int64{from, to}]; ok { + return d, nil + } + return meshwants.Difference{}, fmt.Errorf("no difference of %d and %d", from, to) + } r.GraphState = fake{ "db": node(graph.Node{FP: fp("a"), Repository: "novox/mesh-catalog", Provides: []string{"database"}}), "web": node(graph.Node{FP: fp("b"), Repository: "novox/mesh-catalog", Requires: []string{"database"}, Awaits: []string{"database"}}), @@ -103,7 +126,7 @@ func tiersToolSaysEachModulesWait(t *testing.T) { t.Errorf("the first tier = %s, want db with no wait and lib's build waiting for its package", first) } web := got.Tiers[1][0] - if web.Module != "web" || !reflect.DeepEqual(web.After, []string{"db"}) || len(web.Waits) != 2 || + if web.Module != "web" || !reflect.DeepEqual(web.After, []view.TierAfter{{Module: "db", Kind: "provisioning"}}) || len(web.Waits) != 2 || web.Waits[0].Edge != "want" || web.Waits[0].Node != "ace" || web.Waits[0].Rule != meshwantsclient.RuleProvisions || !web.Waits[0].Since.Equal(since) || web.Waits[1].Edge != "provision database" || !strings.Contains(web.Waits[1].Words, "asked: the build db runs does not offer it") { t.Errorf("web = %+v, want after db, held on ace by the provision rule and its provision asked (g14 is away)", web) @@ -181,17 +204,22 @@ func tiersToolSaysEachModulesWait(t *testing.T) { t.Errorf("web held by %q = %+v, want its want named %s, no wait for a bus-state key and db.loop left out", words, web, edge) } } - // The graph not readable: every module in the first tier, said; past 500 modules the answer says it is cut short. - r.GraphState = view.StateRead{Keys: func() ([]string, error) { return nil, errors.New("no bucket") }, Get: r.GraphState.Get} - if out, err := run(t, r, view.TiersTool, map[string]any{"revision": float64(9)}); err != nil || len(out.(view.Tiers).Tiers) != 1 || - !strings.Contains(out.(view.Tiers).Graph, "cannot be read") { - t.Errorf("view_tiers with no graph = %+v, %v", out, err) + // No revision kept before the one carrying the source: said, and no module named; past 500 modules the answer says it is cut + // short. + delete(kept, 4) + delete(kept, 3) + if out, err := run(t, r, view.TiersTool, map[string]any{"revision": float64(9)}); err != nil || len(out.(view.Tiers).Tiers) != 0 || + !strings.Contains(out.(view.Tiers).Graph, "no assignment revision is kept before") { + t.Errorf("view_tiers with no earlier revision = %+v, %v", out, err) } - many := fake{} + kept[4] = meshwants.AssignmentRevision{Revision: 4, Catalogs: []meshwants.CatalogOf{{Branch: "release", Source: 8}}} + big := meshwants.Difference{From: 4, To: 5, Tiers: [][]meshwants.NodeEntryRef{{}}} for i := 0; i < view.TiersMost+2; i++ { - many[fmt.Sprintf("m%03d", i)] = mod(fp("a"), 9) + m := fmt.Sprintf("m%03d", i) + big.Changes = append(big.Changes, meshwants.Change{Node: "ace", Module: m, To: fp("a")}) + big.Tiers[0] = append(big.Tiers[0], ref(m)) } - r.State = many.reader().State + differences[[2]int64{4, 5}] = big if out, err := run(t, r, view.TiersTool, map[string]any{"revision": "9"}); err != nil || out.(view.Tiers).Modules != view.TiersMost+2 || !strings.Contains(out.(view.Tiers).Cut, "the first 500") { t.Errorf("view_tiers past its bound = %+v, %v", out.(view.Tiers).Cut, err) diff --git a/modules/mesh-delivery-view/internal/view/difference.go b/modules/mesh-delivery-view/internal/view/difference.go new file mode 100644 index 00000000..2deed190 --- /dev/null +++ b/modules/mesh-delivery-view/internal/view/difference.go @@ -0,0 +1,93 @@ +package view + +import ( + "encoding/json" + "fmt" + + "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshwants" + "git.novox.be/novox/mesh-sdk/go/buscalls" +) + +// The seat mesh-wants' verbs revision and difference as the view's invokes names them: the tiers of a source revision are +// read through them and worked out nowhere in the view (design 47 G §512, §186, A-242). +const ( + RevisionVerb = "seat:" + meshwants.Seat + "." + meshwants.VerbRevision + DifferenceVerb = "seat:" + meshwants.Seat + "." + meshwants.VerbDifference +) + +// WalkMost is the most kept assignment revisions a source revision's revision is looked for through, newest first. +const WalkMost = 256 + +// callSeat asks verb with body through call and reads its declared answer into out. +func callSeat(call func(key string, body any) (json.RawMessage, error), verb string, body, out any) error { + raw, err := call(verb, body) + if err != nil { + return fmt.Errorf("%s: %w", verb, err) + } + answer, said, ok := buscalls.Unwrap(raw) + if !ok { + return fmt.Errorf("%s answered: %s", verb, said) + } + if err := json.Unmarshal(answer, out); err != nil { + return fmt.Errorf("the answer of %s does not read: %w", verb, err) + } + return nil +} + +// AssignmentOf asks the seat for one kept assignment graph revision (0: the trunk's newest). +func AssignmentOf(call func(key string, body any) (json.RawMessage, error)) func(revision int64) (meshwants.AssignmentRevision, error) { + return func(revision int64) (meshwants.AssignmentRevision, error) { + var a meshwants.RevisionAnswer + err := callSeat(call, RevisionVerb, meshwants.RevisionInput{Revision: revision}, &a) + return a.Revision, err + } +} + +// DifferenceOf asks the seat for the difference of two kept revisions. +func DifferenceOf(call func(key string, body any) (json.RawMessage, error)) func(from, to int64) (meshwants.Difference, error) { + return func(from, to int64) (meshwants.Difference, error) { + var d meshwants.Difference + err := callSeat(call, DifferenceVerb, meshwants.DifferenceInput{From: from, To: to}, &d) + return d, err + } +} + +// revisionsOf finds the kept assignment revisions that carry the source revision for a watched branch: to the first of them +// (the one whose change it is) and from the revision kept before it, walking back from the newest. A zero from says there is +// none before it. +func (r Reader) revisionsOf(source uint64) (from, to int64, err error) { + if r.Assignment == nil || r.Difference == nil { + return 0, 0, fmt.Errorf("the assigner's revisions cannot be read here") + } + newest, err := r.Assignment(0) + if err != nil { + return 0, 0, fmt.Errorf("the assigner's newest revision: %w", err) + } + carries := func(rev meshwants.AssignmentRevision) bool { + for _, c := range rev.Catalogs { + if c.Source > 0 && uint64(c.Source) == source { + return true + } + } + return false + } + for n, steps := newest.Revision, 0; n >= 1 && steps < WalkMost; n, steps = n-1, steps+1 { + rev := newest + if n != newest.Revision { + if rev, err = r.Assignment(n); err != nil { + continue // a revision no longer kept + } + } + if !carries(rev) { + if to != 0 { + return rev.Revision, to, nil // the kept revision before the first that carries it + } + continue + } + to = rev.Revision + } + if to == 0 { + return 0, 0, fmt.Errorf("no kept assignment revision of the assigner carries the source revision %d", source) + } + return 0, to, nil +} diff --git a/modules/mesh-delivery-view/internal/view/read.go b/modules/mesh-delivery-view/internal/view/read.go index b3209763..a833ce49 100644 --- a/modules/mesh-delivery-view/internal/view/read.go +++ b/modules/mesh-delivery-view/internal/view/read.go @@ -20,6 +20,7 @@ import ( "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/clients/meshcatalogclient" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/clients/meshwantsclient" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshcatalog" + "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshwants" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-sdk/trunk" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-view/viewstate" @@ -72,6 +73,10 @@ type Reader struct { // Sources is the newest source revision of each watched branch, by branch name, as the seat mesh-delivery's verb source // answers it (design 47 G §507, A-173): what view_tiers given no revision answers per branch. Unset, it must be named. Sources func() (map[string]uint64, error) + // Assignment and Difference are the seat mesh-wants' verbs revision and difference (AssignmentOf, DifferenceOf): what + // view_tiers works the tiers of a source revision from (design 47 G §512, A-242). + Assignment func(revision int64) (meshwants.AssignmentRevision, error) + Difference func(from, to int64) (meshwants.Difference, error) // Pending reads the indexer's waits through its tool indexer_pending (ADR 0633 §5); unset names no module held back. Pending func() (takein.PendingAnswer, error) // BuildLog reads the builder's log from a time (stdio.Log(builds.BuildLogRead).Since); unset reads none. diff --git a/modules/mesh-delivery-view/internal/view/tiers.go b/modules/mesh-delivery-view/internal/view/tiers.go index 11d5726c..b22dff6d 100644 --- a/modules/mesh-delivery-view/internal/view/tiers.go +++ b/modules/mesh-delivery-view/internal/view/tiers.go @@ -13,9 +13,9 @@ import ( "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshwatchdogsclient" "git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" - "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/clients/meshcatalogclient" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/clients/meshwantsclient" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshcatalog" + "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshwants" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-indexer/takein" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-sdk/graph" ) @@ -48,7 +48,6 @@ type Tiers struct { Tiers [][]TierModule `json:"tiers"` Cut string `json:"cut,omitempty"` Graph string `json:"graph,omitempty"` - Cycle []string `json:"cycle,omitempty"` Away []string `json:"away,omitempty"` // Pending says why the indexer's waits could not be read, so no module is named held by its revision's indexer (ADR 0633 §5). Pending string `json:"pending,omitempty"` @@ -58,12 +57,18 @@ type Tiers struct { // wait of its own now (no wait is a module that reached every node present), and the verbs it invokes whose edge the // module graph leaves out on a cycle, so nothing waits on them (LeftOut, ADR 0614 §3). type TierModule struct { - Module string `json:"module"` - FP string `json:"fp,omitempty"` - None string `json:"none,omitempty"` - After []string `json:"after,omitempty"` - Waits []TierWait `json:"waits,omitempty"` - LeftOut []string `json:"left-out,omitempty"` + Module string `json:"module"` + // FP is the build: the fingerprint the difference says the module is to run. + FP string `json:"build,omitempty"` + After []TierAfter `json:"after,omitempty"` + Waits []TierWait `json:"waits,omitempty"` + LeftOut []string `json:"left-out,omitempty"` +} + +// TierAfter is a module a module is ordered after, with the kind of the edge that orders it (design 47 G §512, §378). +type TierAfter struct { + Module string `json:"module"` + Kind string `json:"kind"` } // TierWait is one thing a module waits on: the edge (build, have, provision , or for a want held back want, verb @@ -111,32 +116,47 @@ func (r Reader) Newest() (BranchTiers, error) { return out, nil } -// Tiers works out the tiers of one source revision (not 0). +// Tiers works out the tiers of one source revision (not 0): the difference of the kept assignment revision that carries it +// against the one kept before it, as the assigner's verb difference answers it with its tiers and each change's after +// (design 47 G §512, §186, A-242). The view orders nothing itself. func (r Reader) Tiers(revision uint64) (Tiers, error) { if revision == 0 { return Tiers{}, fmt.Errorf("name the source revision") } - modules, err := values(r.State) + out := Tiers{Revision: revision} + from, to, err := r.revisionsOf(revision) if err != nil { - return Tiers{}, fmt.Errorf("the indexer's modules: %w", err) + return Tiers{}, err } - moved := map[string]meshcatalog.ModulesByModuleValue{} - for key, raw := range modules { - if m, err := meshcatalogclient.DecodeModule(raw); err == nil && uint64(m.FpSrc) == revision { - moved[key] = m + var d meshwants.Difference + if from > 0 { + if d, err = r.Difference(from, to); err != nil { + return Tiers{}, fmt.Errorf("the assigner's difference of %d and %d: %w", from, to, err) + } + } else { + out.Graph = fmt.Sprintf("no assignment revision is kept before %d, so the difference names nothing", to) + } + // One module per name, in the highest tier any of its nodes is in; the changes name each module's build and what it is + // ordered after. + changes := map[string][]meshwants.Change{} + for _, c := range d.Changes { + changes[c.Module] = append(changes[c.Module], c) + } + tierOf := map[string]int{} + for i, tier := range d.Tiers { + for _, ref := range tier { + tierOf[ref.Module] = max(tierOf[ref.Module], i) } } - out := Tiers{Revision: revision, Modules: len(moved)} - names := slices.Sorted(maps.Keys(moved)) + names := slices.Sorted(maps.Keys(changes)) + out.Modules = len(names) if len(names) > TiersMost { out.Cut = fmt.Sprintf("the revision moves %d modules: the first %d by name are shown, %s and the %d after it are not", len(names), TiersMost, names[TiersMost], len(names)-TiersMost-1) names = names[:TiersMost] } gr := graph.Graph{} - if raws, err := values(r.GraphState); err != nil { - out.Graph = "the module graph cannot be read, so no module is ordered after another: " + err.Error() - } else { + if raws, err := values(r.GraphState); err == nil { for key, raw := range raws { if n, err := graph.Decode(raw); err == nil { gr[key] = n @@ -148,87 +168,45 @@ func (r Reader) Tiers(revision uint64) (Tiers, error) { wants, _ := values(r.WantsState) provided, perr := values(r.ProvisionsState) held, heldAll := r.heldBack(&out) - - // The ordering among the revision's modules: each one's tier is one past the highest of the modules it waits for. in := map[string]bool{} for _, n := range names { in[n] = true } - after := map[string][]string{} for _, n := range names { - for _, b := range gr.Before(n) { - if in[b] { - after[n] = append(after[n], b) - } - } - } - sub := graph.Graph{} - for _, n := range names { - if g, ok := gr[n]; ok { - sub[n] = g - } - } - out.Cycle = sub.Cycle() - tier := map[string]int{} - var level func(string, map[string]bool) int - level = func(n string, visiting map[string]bool) int { - if t, ok := tier[n]; ok { - return t - } - if visiting[n] { - return -1 - } - visiting[n] = true - t := 0 - for _, b := range after[n] { - lb := level(b, visiting) - if lb < 0 { - return -1 - } - t = max(t, lb+1) - } - delete(visiting, n) - tier[n] = t - return t - } - top := 0 - for _, n := range names { - if t := level(n, map[string]bool{}); t > top { - top = t - } - } - for _, n := range names { - if _, ok := tier[n]; !ok { - tier[n] = top + 1 // on a cycle: after every tier that is ordered - } - } - for _, n := range names { - t := tier[n] + t := tierOf[n] for len(out.Tiers) <= t { out.Tiers = append(out.Tiers, nil) } - m := moved[n] - tm := TierModule{Module: n, FP: m.Fp2, None: m.None2, After: after[n], LeftOut: gr[n].LeftOut} - tm.Waits = r.waitsOf(n, m, gr[n], wants, provided, perr, away) + tm := TierModule{Module: n, LeftOut: gr[n].LeftOut} + seen := map[string]bool{} + for _, c := range changes[n] { + if tm.FP == "" { + tm.FP = c.To + } + for _, a := range c.After { + if k := a.Module + "\x00" + a.Kind; !seen[k] && a.Module != n { + seen[k] = true + tm.After = append(tm.After, TierAfter{Module: a.Module, Kind: a.Kind}) + } + } + } + slices.SortFunc(tm.After, func(a, b TierAfter) int { return strings.Compare(a.Module+"\x00"+a.Kind, b.Module+"\x00"+b.Kind) }) + tm.Waits = r.waitsOf(n, meshcatalog.ModulesByModuleValue{Fp2: tm.FP}, gr[n], wants, provided, perr, away) if w, ok := held[n]; ok { tm.Waits = append(tm.Waits, w) } out.Tiers[t] = append(out.Tiers[t], tm) } // A module the indexer holds back is not at the revision yet, so no tier of it names it: it is named in the first tier with - // its wait alone (ADR 0633 §5), with the fingerprint the indexer last took in. + // its wait alone (ADR 0633 §5). for _, n := range heldAll { if in[n] { continue } - tm := TierModule{Module: n, Waits: []TierWait{held[n]}} - if m, err := meshcatalogclient.DecodeModule(modules[n]); err == nil { - tm.FP, tm.None = m.Fp2, m.None2 - } if len(out.Tiers) == 0 { out.Tiers = append(out.Tiers, nil) } - out.Tiers[0] = append(out.Tiers[0], tm) + out.Tiers[0] = append(out.Tiers[0], TierModule{Module: n, Waits: []TierWait{held[n]}}) } compact := out.Tiers[:0] for _, t := range out.Tiers { diff --git a/modules/mesh-delivery-view/manifest_test.go b/modules/mesh-delivery-view/manifest_test.go index d5793658..071ce461 100644 --- a/modules/mesh-delivery-view/manifest_test.go +++ b/modules/mesh-delivery-view/manifest_test.go @@ -157,6 +157,8 @@ func TestManifestIsTakenAndReadsOnly(t *testing.T) { // 1134/AC7 {Verb: "seat:mesh-catalog.seat-definitions"}, // design 47 G A-82, §204: the build seats are read from the seat list {Verb: "seat:mesh-hand-acts.hand-act"}, // the join: its first view asked again by hand is a hand act (views.StatusTools) {Verb: "seat:mesh-module-assigner.assignments"}, // A-82: the holder of each build seat + {Verb: "seat:mesh-wants.revision"}, // §512, A-242: view_tiers compares kept assignment revisions + {Verb: "seat:mesh-wants.difference"}, // §512, A-242: the tiers and each change's after are the assigner's {Verb: "seat:node-engine.manifest-reads"}}; !reflect.DeepEqual(m.Invokes, want) { // ADR 0618 §3: node_manifest_reads asks the node-engine seat's verb of every node; 1585/T24: view_tiers asks indexer_pending, a verb edge (ADR 0614 §2) t.Errorf("invokes = %v, want %v", m.Invokes, want) } diff --git a/modules/mesh-delivery-view/module.json b/modules/mesh-delivery-view/module.json index 19107792..c7368ba1 100644 --- a/modules/mesh-delivery-view/module.json +++ b/modules/mesh-delivery-view/module.json @@ -93,6 +93,8 @@ "seat:mesh-catalog.seat-definitions", "seat:mesh-hand-acts.hand-act", "seat:mesh-module-assigner.assignments", + "seat:mesh-wants.revision", + "seat:mesh-wants.difference", "seat:node-engine.manifest-reads" ], "reads": [