claude-code: keep two memory versions too large for one file in two, and say a text that cannot fit one value (issue 367)
mesh/merge-gate head 910bc58fe01d merged into trunk a84d0094a0a3 — pass: builds claude-code → ace, g14, novox, shanks; no bus step; every machine composes …
mesh/repo-check head 910bc58fe01d merged into trunk a84d0094a0a3 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery superseded: a newer head of the same pull request

A merged file could exceed the state's 256 KiB value; the newer now stays in the
file and the older is written beside it, each carried. A node that was away takes
the newest version when its own file holds no uncarried change (tested).
This commit is contained in:
2026-10-13 16:03:37 +02:00
parent 0096beeff9
commit 910bc58fe0
3 changed files with 153 additions and 15 deletions
@@ -594,3 +594,85 @@ func TestTheManifestDeclaresTheMemoryState(t *testing.T) {
t.Fatalf("a carrier not started says it carries: %v", st)
}
}
// replay hands one node the whole current set, as a watch begins when the node comes back.
func (s *memState) replay(t *testing.T, n *memNode) {
t.Helper()
keys, _ := s.Keys()
for _, k := range keys {
raw, rev, _, _ := s.Get(k)
if err := n.Take(k, "put", raw, rev); err != nil && !errors.Is(err, errChanged) {
t.Logf("%s taking %s: %v", n.Node, k, err)
}
}
}
// §6: a node that was away while a file changed twice takes the newest version, whose base it never saw, because
// its own file holds no change it did not carry; the version replaced is kept.
func TestANodeThatWasAwayTakesTheNewestVersion(t *testing.T) {
state, c, g14, shanks := twoNodes(t)
carriedOnBoth(t, state, c, g14, shanks, "MEMORY.md", "v1\n")
state.watchers = []*MemoryCarrier{g14.MemoryCarrier}
for _, v := range []string{"v2\n", "v3\n"} {
c.now = c.now.Add(time.Minute)
g14.write(t, project, "MEMORY.md", v, c.now)
g14.look(t)
state.pump(t)
}
state.watchers = append(state.watchers, shanks.MemoryCarrier)
state.replay(t, shanks)
if got, _ := shanks.read(t, project, "MEMORY.md"); got != "v3\n" {
t.Fatalf("the node that was away holds %q", got)
}
if !holdsText(shanks.copies(t), "v1\n") {
t.Fatal("the version replaced was not kept")
}
if len(g14.notices)+len(shanks.notices) != 0 {
t.Fatal("taking a newer version warned")
}
}
// §2, §7: two versions too large to share one file are kept in two: the newer in the file, the older beside it,
// both carried; and a text that would not fit in one value of the state is not carried.
func TestTwoVersionsTooLargeForOneFileAreKeptInTwo(t *testing.T) {
state, c, g14, shanks := twoNodes(t)
carriedOnBoth(t, state, c, g14, shanks, "big.md", "base\n")
older := strings.Repeat("from g14 ", MemoryMostBytes/9-100) + "\n"
newer := strings.Repeat("from shanks ", MemoryMostBytes/12-100) + "\n"
g14.write(t, project, "big.md", older, c.now.Add(time.Minute))
shanks.write(t, project, "big.md", newer, c.now.Add(2*time.Minute))
c.now = c.now.Add(3 * time.Minute)
g14.look(t)
shanks.look(t)
state.pump(t)
g14.look(t)
shanks.look(t)
state.pump(t)
beside := OlderBeside("big.md", "g14")
if beside != "big.older-from-g14.md" {
t.Fatalf("the older is named %q", beside)
}
for _, n := range []*memNode{g14, shanks} {
if got, _ := n.read(t, project, "big.md"); got != newer {
t.Fatalf("%s's file does not hold the newer version", n.Node)
}
if got, _ := n.read(t, project, beside); got != older {
t.Fatalf("%s does not hold the older version beside it", n.Node)
}
}
notices := append(append([]map[string]any{}, g14.notices...), shanks.notices...)
if len(notices) != 1 || !strings.Contains(notices[0]["explanation"].(string), "second file beside it") {
t.Fatalf("not one warning saying the older is beside it: %v", notices)
}
// Under the size limit, but too large once encoded: not carried, and said.
g14.write(t, project, "angles.md", strings.Repeat("<", MemoryMostBytes-10), c.now)
g14.look(t)
state.pump(t)
if _, ok := shanks.read(t, project, "angles.md"); ok {
t.Fatal("a text too large for one value was carried")
}
not, _ := g14.Status()["not carried"].(map[string]string)
if not[project+"/angles.md"] == "" {
t.Fatalf("it is not listed as not carried: %v", not)
}
}