S1 grants-unread-catalog-no-hold: an entry not answered while the catalog half is unread is no failed read, so the list composes from the trunk and the want's entry
Builds: design 47 G A-363 (G-22-lead-answers-2.md), start-waits.md S1 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
@@ -5207,3 +5207,67 @@ func (h heldHalf) Revision() (meshwants.AssignmentRevision, bool) {
|
||||
}
|
||||
return *h.rev, true
|
||||
}
|
||||
|
||||
// TestPassBeforeTheCatalogHalfComposesFromTheTrunkToo is design 47 G A-363: while the catalog half is unread, each account is composed
|
||||
// from the manifest the indexer's `modules` first view names for its module (the trunk's) in union with what its want's entry gives, never
|
||||
// from the list in force alone, so the first parts of a new build get their subjects before any of them serves.
|
||||
func TestPassBeforeTheCatalogHalfComposesFromTheTrunkToo(t *testing.T) {
|
||||
older := strings.Replace(xManifest, `{"name":"kept","history":3}`, `{"name":"older"}`, 1)
|
||||
rows := []struct {
|
||||
name string
|
||||
entry bool // the want's entry is answered (the older build); else it is not answered
|
||||
wantsOld bool
|
||||
}{
|
||||
{"the want's entry is not answered", false, false},
|
||||
{"the want names an entry that is asked", false, false},
|
||||
{"the want's entry is an older build", true, true},
|
||||
}
|
||||
for _, row := range rows {
|
||||
t.Run(row.name, func(t *testing.T) {
|
||||
b := fixture()
|
||||
if strings.Contains(row.name, "asked") {
|
||||
b.put(grants.ReadWants, "want.a.mod-x", meshwantsclient.Want{V: keys.Version, Fp: "src2:" + strings.Repeat("cd", 32), Composed: "sha256:" + strings.Repeat("ef", 32)})
|
||||
b.put(grants.ReadHave, "a.mod-x", nodeengine.HaveByNodeModuleValue{V: keys.Version, Phase: nodeengineclient.PhaseRunning, Health: nodeengineclient.HealthOK,
|
||||
Fp: "src2:" + strings.Repeat("cd", 32)})
|
||||
b.entriesAsked = true
|
||||
}
|
||||
if row.entry {
|
||||
digest := meshcatalogclient.ManifestDigest([]byte(older))
|
||||
b.put(grants.ReadManifests, digest, meshcatalog.ManifestsByDigestValue{V: keys.Version, Module: "mod-x", Manifest: older})
|
||||
fp := "src2:" + strings.Repeat("cd", 32)
|
||||
b.put(grants.ReadWants, "want.a.mod-x", meshwantsclient.Want{V: keys.Version, Fp: fp, Composed: "sha256:" + strings.Repeat("ef", 32)})
|
||||
b.entry(fp, digest)
|
||||
}
|
||||
b.mu.Lock()
|
||||
b.catalogWaited = []string{"the catalog half of the branch main"}
|
||||
b.mu.Unlock()
|
||||
in := grants.ReadInputs(b, &grants.Manifests{})
|
||||
if in.CatalogUnread == "" {
|
||||
t.Fatal("the catalog half is not unread")
|
||||
}
|
||||
// An entry asked and not answered is no failed read while the catalog half is unread: the trunk's manifest composes the
|
||||
// account and the list is not held for it.
|
||||
if f := in.ReadFailed(); len(f) > 0 {
|
||||
t.Errorf("the unread catalog half's asked entry is a failed read: %v", f)
|
||||
}
|
||||
recs, _ := grants.ListRecords(in)
|
||||
users, err := grants.ComposeUsers(recs)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var got []string
|
||||
for _, u := range users {
|
||||
if u.User == "a.mod-x" {
|
||||
got = append(got, u.Publish...)
|
||||
got = append(got, u.Subscribe...)
|
||||
}
|
||||
}
|
||||
if !slices.ContainsFunc(got, func(s string) bool { return strings.Contains(s, "kept") }) {
|
||||
t.Errorf("a.mod-x is not granted the trunk manifest's state kept: %v", got)
|
||||
}
|
||||
if row.wantsOld && !slices.ContainsFunc(got, func(s string) bool { return strings.Contains(s, "older") }) {
|
||||
t.Errorf("a.mod-x is not granted its want's entry's state older: %v", got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,7 +204,7 @@ func catalogWaiting(r Reader) string {
|
||||
return ""
|
||||
}
|
||||
slices.Sort(w)
|
||||
return fmt.Sprintf("the first views of the catalog half are not in (%v), so each account is composed from its want's entry by fingerprint and the list in force is kept", w)
|
||||
return fmt.Sprintf("the first views of the catalog half are not in (%v), so each account is composed from the trunk's manifest of its module in union with its want's entry by fingerprint, and the list in force is kept in union", w)
|
||||
}
|
||||
|
||||
// **The grants part reads the assignment half** (design 46 approval mark §6, design 47 G §195, lead answer A-203): the view of
|
||||
|
||||
@@ -836,7 +836,10 @@ func runningByHaves(r Reader, in *Inputs, cache *Manifests, into map[string]cata
|
||||
if err != nil {
|
||||
if state == meshcatalogclient.EntryAsked {
|
||||
in.HadFailed[node+"."+module] = "the catalog half's entry of " + h.Fp + " is asked"
|
||||
in.Gaps = append(in.Gaps, Gap{Input: "catalog entry " + h.Fp, Why: "asked and not answered yet, so the manifest of the build " + node + "." + module + " runs is unknown: " + err.Error(), Failed: true})
|
||||
// While the catalog half is unread an entry cannot be answered yet: that is no failed read, and the account is composed
|
||||
// from the trunk's manifest of its module (the indexer's `modules` view) in union with what its entry gives, so the list is
|
||||
// not held to the list in force alone (design 47 G, A-363).
|
||||
in.Gaps = append(in.Gaps, Gap{Input: "catalog entry " + h.Fp, Why: "asked and not answered yet, so the manifest of the build " + node + "." + module + " runs is unknown: " + err.Error(), Failed: in.CatalogUnread == ""})
|
||||
}
|
||||
fromTrunk = append(fromTrunk, node+"."+module)
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user