A recompute with no merge writes the fingerprint's source revision as not known, so no release's Approve answers a build it never carried, though the source revision is still that release's (ADR 0601 §1; review round 2)

This commit is contained in:
2026-11-03 16:44:47 +01:00
parent 478f0110e9
commit 22aedbe97f
4 changed files with 29 additions and 21 deletions
@@ -811,10 +811,11 @@ func aReleasesApproveAnswersTheMoveOfItsBuildAlone(t *testing.T) {
{"a setting changed at the build it runs", true, fpTest, commit, 7, false, true},
{"no approved release carries it", true, fpOld, "", 7, false, true},
{"the release merged another commit", true, fpOld, strings.Repeat("2", 40), 7, false, true},
// Review round 1: its fingerprint moved by a recompute after the release (a toolchain, a package), with no merge of
// web: stamped with that moment's revision, whose release carries nothing of web; the earlier Approve answers nothing.
{"a fingerprint moved by a recompute after the release", true, fpOld, commit, 8, false, true},
{"a fingerprint whose revision is not known", true, fpOld, commit, 0, false, true},
// Its fingerprint last moved at another release's revision, which merged nothing of web: that Approve answers nothing.
{"a fingerprint another release moved", true, fpOld, commit, 8, false, true},
// Review rounds 1 and 2: moved by a recompute after the release (a toolchain, a package, a base) with no merge, the
// indexer writes fp-src 0, not known, though Src is still the release's: asked of a person.
{"a fingerprint moved by a recompute after the release", true, fpOld, commit, 0, false, true},
} {
asksKV := &memKV{values: map[string][]byte{}}
p := newPasser(buckets{delivery.AssignerAsksBucket: asksKV}, time.Now())
@@ -14,13 +14,6 @@ import (
// with it (Module.Src) when the head the source names for its repository is the merge commit the module's fingerprint
// was computed at: from the modules bucket when the merge was heard first, and when the merge is heard after the source.
// sourceRev is the latest source revision seen, 0 before any.
func (ix *Indexer) sourceRev() uint64 {
ix.mu.Lock()
defer ix.mu.Unlock()
return ix.source.rev
}
// sourceNow is the latest source revision seen.
type sourceNow struct {
rev uint64
@@ -313,9 +313,11 @@ func (ix *Indexer) recomputeModules(ctx context.Context, overlay map[string]deli
return nil, false, nil
}
if cur.FP2 != r.fp {
// Moved with no merge of its own repository (a toolchain, a package, a base): the source revision of now, whose
// release does not carry it, never the Src of the merge it was last merged at (ADR 0601 §1).
cur.FPSrc = ix.sourceRev()
// Moved with no merge (a toolchain, a package, a base): no release carries this build, and the source revision
// moves only at a merge, so it is not known (0) and the move is asked of a person; never the revision of now,
// which may be the very release that last merged the module (ADR 0601 §1). The source stamp leaves it, since
// Src is set.
cur.FPSrc = 0
}
cur.FP2, cur.None2, cur.Toolchains, cur.Packages = r.fp, r.none, r.tcs, r.pkgs
cur.Inputs2, cur.ArtifactPaths = inputs, paths
@@ -113,19 +113,31 @@ func TestAgreedToolchainChangesAGoModulesReasonWithNoMerge(t *testing.T) { // 14
if m, _ := moduleOf(t, mods, "avahi"); m.None2 != delivery.ToolchainNoReport {
t.Fatalf("before: none2 = %q", m.None2)
}
ix.mu.Lock()
ix.source.rev = 11 // the source revision of now, whose release merged nothing of avahi's
ix.mu.Unlock()
// The release that last merged avahi: its source revision names avahi's commit, so Src (and FPSrc) are 7.
merged, _ := moduleOf(t, mods, "avahi")
src := delivery.Source{Group: "g", Heads: map[string]string{merged.Repository: merged.Commit}}
if err := ix.ApplySource(context.Background(), 7, src); err != nil {
t.Fatal(err)
}
if m, _ := moduleOf(t, mods, "avahi"); m.Src != 7 || m.FPSrc != 7 {
t.Fatalf("before: src %d fp-src %d, want 7 and 7", m.Src, m.FPSrc)
}
reportToolchain(t, ix, "mesh-build-go", "novox", "go", "go1.27.1")
reportToolchain(t, ix, "mesh-build-go", "ace", "go", "go1.27.1")
m, _ := moduleOf(t, mods, "avahi")
if m.None2 != "" || m.FP2 == "" {
t.Errorf("none2 = %q fp2 = %q, want a fingerprint: no builder input is waited for (ADR 0530 §1)", m.None2, m.FP2)
}
// ADR 0601 §1: a fingerprint moved with no merge is stamped with the source revision of the moment, never the Src of
// the merge it was last merged at, so no earlier release is taken to carry it.
if m.FPSrc != 11 || m.Src == 11 {
t.Errorf("a fingerprint moved by a recompute: fp-src %d, src %d; want fp-src 11", m.FPSrc, m.Src)
// ADR 0601 §1 (review round 2): a fingerprint moved with no merge has no release that carries it: fp-src 0, not known,
// though the source revision is still the release's at the module's own Src; a source revision heard again stamps nothing.
if m.FPSrc != 0 {
t.Errorf("a fingerprint moved by a recompute: fp-src %d, want 0", m.FPSrc)
}
if err := ix.ApplySource(context.Background(), 8, src); err != nil {
t.Fatal(err)
}
if again, _ := moduleOf(t, mods, "avahi"); again.FPSrc != 0 {
t.Errorf("a source revision stamped the recomputed fingerprint: fp-src %d", again.FPSrc)
}
}