Read a machine's placement once per answer of own, and say how long every answer took and every refusal, so an answer of 143 credentials is not 143 bus reads and an ask that went unanswered can be told from one never heard (issue 774)
mesh/delivery merged: source.main moved to novox/mesh-catalog@dcf3950f7b07
mesh/check being carried to b60138990b34 on dcf3950f7b07 | from 0e78909a75b9

Quick fix: the plan reader keeps the machine's one placement key for the answer, as it keeps each module's assignment (issue 1126, 2026-10-28); the second time one answer's reads per credential held own past the node-engine's 15 s.
Thorough fix (not here): the node-engine asks own only when a secret or a credential it composes from changed, and the assigner writes no want that is unchanged.
This commit is contained in:
2026-10-31 01:05:01 +01:00
parent 0e78909a75
commit b60138990b
3 changed files with 64 additions and 10 deletions
@@ -2,6 +2,7 @@ package main
import (
"errors"
"fmt"
"os"
"path/filepath"
"strings"
@@ -143,6 +144,11 @@ func TestOwnReadsEachAssignmentOnceAndSyncsItsRecordOnce(t *testing.T) {
t.Fatal(err)
}
}
// Issue 774, 2026-10-31 (ace's 143 credentials went unanswered past the node-engine's 15 s while novox's asked every
// 8 s): the machine's placement, one key, is read once per answer too, never once per credential.
placed := placementsOf(t, map[string][]string{"anchor": {"web"}})
placementReads := 0
v.Placement = PlacementReader{Keys: placed.Keys, Read: func(key string) ([]byte, error) { placementReads++; return placed.Read(key) }}
for k := range reads {
delete(reads, k)
}
@@ -161,6 +167,10 @@ func TestOwnReadsEachAssignmentOnceAndSyncsItsRecordOnce(t *testing.T) {
if len(reads) != 2 {
t.Errorf("the answer read %v, want each of anchor's two modules once", reads)
}
if placementReads != 1 {
t.Errorf("one answer of two credentials read anchor's placement %d times, want once", placementReads)
}
v.Placement = PlacementReader{}
if n := v.Store.syncs - syncs; n != 1 {
t.Errorf("one answer synced the record %d times", n)
}
@@ -182,9 +192,15 @@ func TestOwnReadsEachAssignmentOnceAndSyncsItsRecordOnce(t *testing.T) {
if err := os.Mkdir(filepath.Join(v.dir, "store", "handed.jsonl"), 0o700); err != nil {
t.Fatal(err)
}
// And the refusal is said in the vault's journal with how long it took, as every answer is.
var said []string
v.Log = func(format string, args ...any) { said = append(said, fmt.Sprintf(format, args...)) }
if a, err := v.OwnOfNode("node.anchor"); err == nil {
t.Errorf("handed with no record of it: %+v", a)
}
if last := strings.Join(said, "\n"); !strings.Contains(last, "own for node.anchor, 0 credentials asked, refused after ") {
t.Errorf("a refused own was said as %q", last)
}
}
func mustHanded(t *testing.T, v testVault) []Handing {