stacks: R-687 — an empty leg reports steps [], and a taken files_may_change step names its whole copy
gates / gates (push) Successful in 26s

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-09-25 13:24:19 +02:00
parent b6399fdf0b
commit 1c5dd07604
2 changed files with 26 additions and 3 deletions
+23 -2
View File
@@ -3,6 +3,7 @@ package stacks
import (
"bytes"
"context"
"encoding/json"
"path/filepath"
"strconv"
"strings"
@@ -227,13 +228,13 @@ func TestLeg_NeedsPersonIsNeverTaken(t *testing.T) {
// TestLeg_FilesMayChangeNeedsAWholeCopy — decision 13's other mark: taken only when a fresh WHOLE copy
// exists (the backup side's truth table, asked through FreshWholeCopy).
func TestLeg_FilesMayChangeNeedsAWholeCopy(t *testing.T) {
m, dir, _, ups, _ := legManager(t)
m, dir, _, ups, logBuf := legManager(t)
writeLadder(t, m,
ladderLineMarks(ladderA, ladderB, "proven", `{"files_may_change": true, "needs_person": null, "memory_tight": false}`),
ladderLine(ladderB, ladderC))
whole := false
legOpts(m, func(o *UpdateLegOptions) {
o.FreshWholeCopy = func(context.Context, string) (bool, string) { return whole, "fake" }
o.FreshWholeCopy = func(context.Context, string) (bool, string) { return whole, "tier 2 copy from FAKE-TIME" }
})
s := mustLeg(t, m)
if len(*ups) != 0 || legStepFor(s, "nextcloud").Reason != LegSkipFilesNoCopy {
@@ -244,6 +245,10 @@ func TestLeg_FilesMayChangeNeedsAWholeCopy(t *testing.T) {
if len(*ups) != 1 || pinOf(t, dir) != ladderB || s.Done != 1 {
t.Fatalf("with a fresh whole copy the step must be taken: ups=%v pin=%s", *ups, pinOf(t, dir))
}
// R-687 (v0.273.0): the taken step names the copy that allowed it. COMPANION RED-PROOF: drop the log line.
if !strings.Contains(logBuf.String(), "taken, a fresh whole copy exists: tier 2 copy from FAKE-TIME") {
t.Fatal("a taken files_may_change step must log which whole copy allowed it")
}
// unwired check = no whole copy (fail closed)
m2, _, _, ups2, _ := legManager(t)
writeLadder(t, m2,
@@ -452,3 +457,19 @@ func TestLegDeadline(t *testing.T) {
}
}
}
// TestR687_EmptyLegReportsEmptySteps — a leg that pressed nothing reports `"steps": []` to the hub, not
// `null` (read live 2026-09-25 from demo-hp's report). COMPANION RED-PROOF: copy with append(nil, …).
func TestR687_EmptyLegReportsEmptySteps(t *testing.T) {
m, _, _, _, _ := legManager(t)
m.leg.mu.Lock()
m.leg.last = &UpdateLegSummary{Trigger: "after-offsite", Steps: []LegStep{}}
m.leg.mu.Unlock()
b, err := json.Marshal(m.LastUpdateLegSummary())
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(b), `"steps":[]`) {
t.Fatalf("an empty leg must report steps as [], got %s", b)
}
}