mesh-config compare: leave out merged or closed pull requests' candidates and a module with no manifest and no mirrored keys, so compare can come out empty (issue 1953 L5d, L5e)

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
2026-11-01 03:20:48 +01:00
parent c4406da4a3
commit 021e5a96ff
2 changed files with 63 additions and 0 deletions
@@ -350,6 +350,17 @@ func (c *Config) compare() (*Comparison, error) {
c.mirrorDeclarations(&mirror)
var diffs []Difference
// A placed module no catalog manifest names (mesh-wireguard, which the mesh ships computed) whose mirror key holds
// no config key declares nothing on both sides: nothing resolves from it, so nothing differs (issue 1953, L5d).
declaresNothing := map[string]bool{}
for module, d := range mirror.Declared {
if len(d.Config) == 0 {
if _, err := c.trunkDeclarations(module); err != nil {
declaresNothing[module] = true
}
}
}
// Each placed module's declarations: `declared` against the mirror's key for it.
for _, module := range modulesOf(own.Assignments) {
var ownRaw []byte
@@ -364,6 +375,7 @@ func (c *Config) compare() (*Comparison, error) {
mirrorRaw, _ = json.Marshal(normal(d.Config))
}
switch {
case ownRaw == nil && declaresNothing[module]:
case ownRaw == nil && mirrorRaw == nil:
diffs = append(diffs, Difference{What: DiffDeclared, Module: module, Why: "neither side holds its declarations"})
case ownRaw == nil:
@@ -412,9 +424,13 @@ func (c *Config) compare() (*Comparison, error) {
if cerr != nil {
diffs = append(diffs, Difference{What: DiffPull, Why: "the indexer's config candidates cannot be read: " + cerr.Error()})
}
settled := map[string]string{} // a pull request the forge says is no longer open → how it ended
for _, k := range unionKeys(cands, own.Pulls) {
a, aok := cands[k]
b, bok := own.Pulls[k]
if c.pullSettled(firstNonEmpty(a.Pull, b.Pull), settled) {
continue // a merged or closed pull request is no candidate to agree on (the operator, 2026-11-01)
}
switch {
case !aok:
diffs = append(diffs, Difference{What: DiffPull, Pull: b.Pull, Why: "the controller told its declarations and the indexer holds no candidate"})
@@ -456,6 +472,9 @@ func (c *Config) compare() (*Comparison, error) {
diffs = append(diffs, Difference{What: DiffValue, Node: u.Node, Module: u.Module, Why: "not resolved from the mirror: " + u.Why})
}
for _, u := range own.Unresolved {
if declaresNothing[u.Module] {
continue
}
diffs = append(diffs, Difference{What: DiffValue, Node: u.Node, Module: u.Module, Why: "not resolved from its own source: " + u.Why})
}
sort.SliceStable(diffs, func(i, j int) bool {
@@ -474,6 +493,41 @@ func (c *Config) compare() (*Comparison, error) {
return cmp, nil
}
func firstNonEmpty(a, b string) string {
if a != "" {
return a
}
return b
}
// pullSettled is whether the forge says a pull request merged or closed. Without a forge, or when it does not say, the
// pull request counts as open, so its row stays (failure is loud).
func (c *Config) pullSettled(pull string, memo map[string]string) bool {
if c.Forge == nil || pull == "" {
return false
}
if v, ok := memo[pull]; ok {
return v != ""
}
owner, repo, n, err := parsePull(pull)
if err != nil {
return false
}
open, merged, _, err := c.Forge.Pull(owner, repo, n)
switch {
case err != nil:
c.logf("[mesh-config] compare: the forge does not say whether %s is open (%v); its row stays", pull, err)
memo[pull] = ""
case open:
memo[pull] = ""
case merged:
memo[pull] = "merged"
default:
memo[pull] = "closed"
}
return memo[pull] != ""
}
// normal is declarations in one encoding: a null default as none.
func normal(d map[string]Declaration) map[string]Declaration {
out := map[string]Declaration{}
@@ -88,9 +88,18 @@ func TestCompareListsEveryDifferenceAndTheTakeOverWaitsForNone(t *testing.T) {
{"a pull request only the indexer holds", func(t *testing.T, m *memStore) {
candidate(t, m, "novox/mesh-catalog#9", "h1", `{"dunst":{"gap":{"kind":"","type":"number","default":2}}}`)
}, []string{"pull:novox/mesh-catalog#9"}},
{"a candidate of a merged pull request is no difference", func(t *testing.T, m *memStore) {
candidate(t, m, "novox/mesh-catalog#11", "h1", `{"dunst":{"gap":{"kind":"","type":"number","default":2}}}`)
candidate(t, m, "novox/mesh-catalog#10", "h2", `{"dunst":{"gap":{"kind":"","type":"number","default":2}}}`)
}, []string{"pull:novox/mesh-catalog#10"}},
{"a module no manifest names and the mirror declares nothing of", func(t *testing.T, m *memStore) {
m.assign(t, "g14", "mesh-wireguard")
m.mirror(t, MirrorDeclaredRead, "mesh-wireguard", `{"module":"mesh-wireguard","settings":{}}`)
}, nil},
}
for _, tc := range cases {
c, m, r := anAgreeingMesh(t)
c.Forge = &standForge{state: map[string][2]bool{"novox/mesh-catalog#11": {false, true}}}
tc.change(t, m)
cmp, err := c.Compare()
if err != nil {