indexer: say manifest-accepted for a merged manifest a pull request's judgement already accepted (issue 1966)
mesh/delivery merged: source.main moved to novox/mesh-delivery@76db40eb6be1
mesh/check being carried to 104909817b70 on 76db40eb6be1 | from 983c46e2576c
mesh/delivery merged: source.main moved to novox/mesh-delivery@76db40eb6be1
mesh/check being carried to 104909817b70 on 76db40eb6be1 | from 983c46e2576c
A pull request's candidate is judged before its merge and its verdict written, said nowhere. At the merge the digest becomes the module's trunk manifest, but the merge's judging pass finds the same verdict, writes nothing and so said nothing: the bus module never heard the new manifest, and the grants part, which follows the verdicts on manifest-accepted, held the module as having no verdict and wrote no grant for its new fingerprint (claude-licence-manager, three times on 2026-11-12). The merge's pass now says a fresh trunk manifest's accepted verdict from the verdict held, with its revision. Builds: design 25 bus-state §1, §12.2 (the indexer says manifest-accepted for every newly accepted manifest; the grants part follows the verdicts on it) Builds: design 25 bus-state L1 (hq ff30ac16, the lead's answer: a merged candidate's manifest is newly accepted).
This commit is contained in:
@@ -245,6 +245,12 @@ func (ix *Indexer) judgeOverHeld(ctx context.Context, fresh map[string]bool, ove
|
||||
a := acceptedOf(digests[name], v, revision, raws[name])
|
||||
_ = ix.sayAccepted(ctx, a, acceptedEventID(a))
|
||||
}
|
||||
} else if over == nil && fresh[digests[name]] && !meshcatalogclient.VerdictHeld(v) {
|
||||
// A manifest a merge just made its module's trunk manifest is newly accepted there, even when a pull request's
|
||||
// judgement wrote its verdict before the merge and said it nowhere (a candidate's verdict is not said): it is
|
||||
// said now from the verdict held, with its revision, so the bus module and the grants part hear it (design 25
|
||||
// bus-state §1; issue 1966: claude-licence-manager's new builds waited for a grant nothing wrote).
|
||||
ix.sayHeld(ctx, digests[name], raws[name])
|
||||
}
|
||||
// The reader capabilities the manifest's own words, forms and seat names need, named with the verdict (ADR 0614 §4).
|
||||
needs, _ := catalogue.ManifestNeeds(raws[name])
|
||||
@@ -262,6 +268,26 @@ func (ix *Indexer) judgeOverHeld(ctx context.Context, fresh map[string]bool, ove
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// sayHeld says manifest-accepted for the trunk's manifest of digest from the accepted verdict the verdicts state holds on
|
||||
// it, with that verdict's revision; a verdict that cannot be read, or that refuses or waits, says nothing.
|
||||
func (ix *Indexer) sayHeld(ctx context.Context, digest string, raw []byte) {
|
||||
key, err := meshcatalogclient.VerdictsKey(digest)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
value, revision, found, err := ix.Verdicts.Get(ctx, key)
|
||||
if err != nil || !found {
|
||||
ix.logf("judge: the verdict on %s cannot be read, so its manifest-accepted is not said: %v", digest, err)
|
||||
return
|
||||
}
|
||||
v, err := meshcatalogclient.DecodeVerdict(value)
|
||||
if err != nil || meshcatalogclient.VerdictHeld(v) {
|
||||
return
|
||||
}
|
||||
a := acceptedOf(digest, v, revision, raw)
|
||||
_ = ix.sayAccepted(ctx, a, acceptedEventID(a))
|
||||
}
|
||||
|
||||
// JudgeAtStart is JudgeAll of every manifest held, none fresh, as the indexer starts (a judge that changed judges every
|
||||
// one again); one that fails is judged again at the next message or source revision heard (kickJudge). Then every other
|
||||
// digest of the verdicts state that another judge refused or held waiting (one of a candidate, or one back on the trunk
|
||||
|
||||
@@ -185,8 +185,9 @@ func TestTheIndexerJudgesEveryManifestOnce(t *testing.T) {
|
||||
moved := hold("moved", `{"module":"moved","version":"1","requires":[`+
|
||||
`{"name":"cache","storage":"key-value","template":"state","options":{"history":8}},`+
|
||||
`{"name":"audit","storage":"stream","template":"log","options":{"max-mib":64}}]}`)
|
||||
for pass := 0; pass < 2; pass++ {
|
||||
if _, err := ix.JudgeAll(ctx, map[string]bool{moved: true}); err != nil {
|
||||
// The merge's pass, then a later one that knows nothing of the merge.
|
||||
for _, fresh := range []map[string]bool{{moved: true}, nil} {
|
||||
if _, err := ix.JudgeAll(ctx, fresh); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -235,6 +236,17 @@ func TestTheIndexerJudgesEveryManifestOnce(t *testing.T) {
|
||||
if _, err := ix.judgeOver(ctx, nil, "bydigest", candidate); err != nil || accepted[len(accepted)-1].Digest != byDigest {
|
||||
t.Fatalf("a candidate's verdict was said: %v %+v", err, accepted[len(accepted)-1])
|
||||
}
|
||||
// Issue 1966 (design 25 bus-state §1): the candidate merged, its verdict unchanged, is newly accepted on the trunk and
|
||||
// said at the merge's pass, from the verdict held and with its revision, though the pass writes no verdict.
|
||||
if hold("bydigest", `{"module":"bydigest","version":"2"}`) != candidate {
|
||||
t.Fatal("the merged manifest is not the candidate's")
|
||||
}
|
||||
if j, err := ix.JudgeAll(ctx, map[string]bool{candidate: true}); err != nil || j.Written != 0 {
|
||||
t.Fatalf("the merge's pass: %+v %v", j, err)
|
||||
}
|
||||
if _, rev, _, _ := ix.Verdicts.Get(ctx, candidate); accepted[len(accepted)-1].Digest != candidate || accepted[len(accepted)-1].Revision != int64(rev) {
|
||||
t.Fatalf("the merged candidate's manifest was not said accepted with its verdict's revision %d: last said %+v", rev, accepted[len(accepted)-1])
|
||||
}
|
||||
// DLV-I9b: a failed publish is published again; one failing twice writes the finding naming the module, which the next
|
||||
// judging pass says again and clears.
|
||||
ix.Findings = newMem()
|
||||
|
||||
Reference in New Issue
Block a user