DLV-J1, DLV-J2, DLV-J3: the foundation is the nine parts, and indexer_old_sections counts the reads left on the owners' state
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
This commit is contained in:
@@ -27,9 +27,11 @@ func Tools(ask asker, now func() time.Time, read stdio.KeptState, counts func()
|
||||
str := func(args map[string]any, k string) string { s, _ := args[k].(string); return strings.TrimSpace(s) }
|
||||
return []stdio.Tool{
|
||||
{Name: index.OldSectionsTool,
|
||||
Description: "How many accepted modules use each old section of a manifest (state, logs, streams, objects), the foundation " +
|
||||
"(nats, mesh-grants, the indexer) left out: the count the judge refuses a use of a section at 0 by, as modules move " +
|
||||
"their bus state into `requires` by template. Read from the indexer's oldsections state, kept as the indexer judges " +
|
||||
Description: "How many accepted modules use each old section of a manifest (state, logs, streams, objects), the nine parts of " +
|
||||
"the foundation left out (ADR 0619): the count the judge refuses a use of a section at 0 by, as modules move " +
|
||||
"their bus state into `requires` by template; and, under reads, the `reads` entries the accepted manifests still declare " +
|
||||
"on the indexer's and the assigner's state, by owner and by entry, which reads 0 for each owner once every reader asks the " +
|
||||
"owners' tools instead (ADR 0615 §1). Read from the indexer's oldsections state, kept as the indexer judges " +
|
||||
"the manifests; an empty answer means the indexer has not judged since it started.",
|
||||
Input: map[string]any{"type": "object", "properties": map[string]any{}},
|
||||
Run: func(map[string]any) (any, error) {
|
||||
@@ -37,7 +39,7 @@ func Tools(ask asker, now func() time.Time, read stdio.KeptState, counts func()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.Counts, nil
|
||||
return map[string]any{"sections": c.Counts, "reads": c.Reads}, nil
|
||||
}},
|
||||
{Name: index.TakeInTool,
|
||||
Description: "Take a registered module in now: the indexer reads its manifest from the repository and commit the controller's " +
|
||||
|
||||
@@ -28,6 +28,9 @@ const (
|
||||
type OldSectionsCount struct {
|
||||
V int `json:"v"`
|
||||
Counts map[string]int `json:"counts"`
|
||||
// Reads are the `reads` entries left on the indexer's and the assigner's state, by owner and by entry, across the
|
||||
// accepted manifests (judge.CountOwnerReads; ADR 0615 §1): 0 for each owner once every reader moved.
|
||||
Reads map[string]int `json:"reads,omitempty"`
|
||||
}
|
||||
|
||||
// DecodeOldSections reads the oldsections value.
|
||||
@@ -60,17 +63,17 @@ func (ix *Indexer) heldOldSections(ctx context.Context) judge.OldSectionCounts {
|
||||
}
|
||||
|
||||
// keepOldSections writes the counts under OldSectionsKey when they differ from the ones held.
|
||||
func (ix *Indexer) keepOldSections(ctx context.Context, counts judge.OldSectionCounts) error {
|
||||
func (ix *Indexer) keepOldSections(ctx context.Context, counts judge.OldSectionCounts, reads map[string]int) error {
|
||||
if ix.OldSections == nil {
|
||||
return nil
|
||||
}
|
||||
return write(ctx, ix.OldSections, OldSectionsKey, func(value []byte, found bool) ([]byte, bool, error) {
|
||||
if found {
|
||||
if cur, err := DecodeOldSections(value); err == nil && maps.Equal(cur.Counts, counts) {
|
||||
if cur, err := DecodeOldSections(value); err == nil && maps.Equal(cur.Counts, counts) && maps.Equal(cur.Reads, reads) {
|
||||
return nil, false, nil
|
||||
}
|
||||
}
|
||||
next, err := json.Marshal(OldSectionsCount{V: 1, Counts: counts})
|
||||
next, err := json.Marshal(OldSectionsCount{V: 1, Counts: counts, Reads: reads})
|
||||
return next, false, err
|
||||
})
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ func (ix *Indexer) judgeOver(ctx context.Context, fresh map[string]bool, over ma
|
||||
if over != nil {
|
||||
return out, nil
|
||||
}
|
||||
if err := ix.keepOldSections(ctx, judge.CountOldSections(accepted)); err != nil {
|
||||
if err := ix.keepOldSections(ctx, judge.CountOldSections(accepted), judge.CountOwnerReads(accepted)); err != nil {
|
||||
ix.logf("judge: the count of the old sections is not kept: %v", err)
|
||||
}
|
||||
return out, nil
|
||||
|
||||
@@ -11,6 +11,8 @@ import (
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
|
||||
"mesh-delivery-indexer/judge"
|
||||
)
|
||||
|
||||
// The indexer judges every manifest it holds and writes each verdict only when it differs; a module's value carries a
|
||||
@@ -179,6 +181,29 @@ func TestTheIndexerJudgesEveryManifestOnce(t *testing.T) {
|
||||
if c := counts(); c["state"] != 1 || c["logs"] != 0 || c["streams"] != 0 || c["objects"] != 0 {
|
||||
t.Fatalf("the old sections count %v, want state 1 and the rest 0", c)
|
||||
}
|
||||
// DLV-J2, DLV-J3 (ADR 0615 §1): one reads entry on the assigner's state counts 1 for the assigner and 0 for the indexer.
|
||||
hold("reader", `{"module":"reader","version":"1","state":["x"],"reads":["mesh-delivery-assigner.wants"]}`)
|
||||
if _, err := ix.JudgeAll(ctx, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if value, _, _, _ := ix.OldSections.Get(ctx, OldSectionsKey); true {
|
||||
c, _ := DecodeOldSections(value)
|
||||
if c.Reads["mesh-delivery-assigner"] != 1 || c.Reads["mesh-delivery-assigner.wants"] != 1 || c.Reads["mesh-delivery-indexer"] != 0 {
|
||||
t.Fatalf("the reads on the owners' state count %v", c.Reads)
|
||||
}
|
||||
}
|
||||
// DLV-J1 (ADR 0619 §1, §3): a foundation part asking bus state in the new form is refused; the nine are the foundation.
|
||||
cfg := hold("mesh-config", `{"module":"mesh-config","version":"1","requires":[{"name":"cache","storage":"key-value","template":"state"}]}`)
|
||||
if _, err := ix.JudgeAll(ctx, map[string]bool{cfg: true}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if v := verdict(cfg); !v.Refused() || !strings.Contains(strings.Join(v.Problems, " "), "part of the foundation") {
|
||||
t.Fatalf("mesh-config asking new-form bus state: %+v", v)
|
||||
}
|
||||
if !slices.Equal(judge.Foundation, []string{"nats", "mesh-grants", "mesh-delivery-indexer", "mesh-delivery-assigner", "node-tools",
|
||||
"mesh-delivery-builder", "mesh-delivery-checker", "mesh-config", "mesh-vault"}) {
|
||||
t.Fatalf("the foundation is %v, want exactly the nine of ADR 0619", judge.Foundation)
|
||||
}
|
||||
late := hold("late", `{"module":"late","version":"1","logs":[{"name":"l"}]}`)
|
||||
grants := hold("mesh-grants", `{"module":"mesh-grants","version":"2","logs":[{"name":"l"},{"name":"m"}]}`)
|
||||
if _, err := ix.JudgeAll(ctx, map[string]bool{late: true, grants: true}); err != nil {
|
||||
|
||||
@@ -3,6 +3,7 @@ package judge
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
)
|
||||
@@ -15,8 +16,36 @@ import (
|
||||
// OldSections are the sections of a manifest that keep bus state in the old forms.
|
||||
var OldSections = []string{"state", "logs", "streams", "objects"}
|
||||
|
||||
// Foundation are the modules that keep using the old sections for good.
|
||||
var Foundation = []string{"nats", "mesh-grants", "mesh-delivery-indexer"}
|
||||
// Foundation are the modules that keep using the old sections for good: exactly the nine parts the bus module's own
|
||||
// composition, placement, build or delivery needs before it can answer (novox/hq ADR 0619 §1, §3): the bus module, the
|
||||
// grants part, the indexer, the assigner, the tool runner, the builder, the checker, mesh-config and the vault. Their new
|
||||
// state goes on their old sections too, so a foundation manifest asking bus state in the new form is refused.
|
||||
var Foundation = []string{"nats", "mesh-grants", "mesh-delivery-indexer", "mesh-delivery-assigner", "node-tools",
|
||||
"mesh-delivery-builder", "mesh-delivery-checker", "mesh-config", "mesh-vault"}
|
||||
|
||||
// ViewOwners are the two owners whose state every reader reads through their first views and read tools, never by a
|
||||
// `reads` entry (novox/hq ADR 0615 §1): CountOwnerReads counts what is left of those entries.
|
||||
var ViewOwners = []string{"mesh-delivery-indexer", "mesh-delivery-assigner"}
|
||||
|
||||
// CountOwnerReads counts the `reads` entries on each view owner's state, by owner and by entry, across manifests: what
|
||||
// the live row of the move reads 0 of (novox/hq ADR 0615 How it is checked). Every owner is in the answer, 0 where none.
|
||||
func CountOwnerReads(manifests []catalogue.Manifest) map[string]int {
|
||||
counts := map[string]int{}
|
||||
for _, o := range ViewOwners {
|
||||
counts[o] = 0
|
||||
}
|
||||
for _, m := range manifests {
|
||||
for _, r := range m.Reads {
|
||||
for _, o := range ViewOwners {
|
||||
if strings.HasPrefix(r, o+".") {
|
||||
counts[o]++
|
||||
counts[r]++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return counts
|
||||
}
|
||||
|
||||
// OldSectionCounts is, per old section, how many accepted modules outside the foundation use it. Nil is no count: the
|
||||
// judge then refuses no use of a section.
|
||||
@@ -54,7 +83,14 @@ func CountOldSections(manifests []catalogue.Manifest) OldSectionCounts {
|
||||
|
||||
// OldSectionProblems are the old sections a manifest uses that no accepted module outside the foundation uses any more.
|
||||
func OldSectionProblems(m catalogue.Manifest, counts OldSectionCounts) []string {
|
||||
if counts == nil || slices.Contains(Foundation, m.Module) {
|
||||
if slices.Contains(Foundation, m.Module) {
|
||||
if len(m.BusState) > 0 {
|
||||
return []string{fmt.Sprintf("%s is a part of the foundation, which keeps its bus state in the old sections, new "+
|
||||
"entries included: it asks none in `requires` by template (novox/hq ADR 0619 §1)", m.Module)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if counts == nil {
|
||||
return nil
|
||||
}
|
||||
var problems []string
|
||||
|
||||
Reference in New Issue
Block a user