carlos / platform Public

moves: Ready re-checks the budget's evidence itself (Task 11 fix round 1)

The target report carries the database size and the S3 and disk
measurement times; Ready re-prices the cut from them and the source's
cross-region rate at its own now, refusing a missing, non-positive,
non-finite or expired rate, a non-finite mirror bar, a budget that admits
no attempt, or a stored attempt count above the recomputation. PutReplace
names its twins and its retry policy.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 3fca22d13f50dfc7407ca84d251ab3ab7afc343d parent ce959e1
3 files changed, +219 −30
  • docs/superpowers/plans/2026-10-06-moves-phase1-copy.md +2 −0
  • internal/moves/readiness.go +59 −2
  • internal/moves/readiness_test.go +158 −28
diff --git a/docs/superpowers/plans/2026-10-06-moves-phase1-copy.md b/docs/superpowers/plans/2026-10-06-moves-phase1-copy.md
index 1920a54c0..1d7b502fb 100644
--- a/docs/superpowers/plans/2026-10-06-moves-phase1-copy.md
+++ b/docs/superpowers/plans/2026-10-06-moves-phase1-copy.md
@@ -121,6 +121,8 @@ Columns: id, file, text, status.
| MV-N79 | internal/moves/archive/archive.go | archive: the files directory holds more than 131072 entries | pending |
| MV-N80 | internal/moves/archive/archive.go | archive: a file changed while it was being archived: <path> | pending |
| MV-N81 | internal/moves/archive/archive.go | archive: refused path: <path> is longer than 4096 bytes | pending |
+| MV-N82 | internal/moves/readiness.go | T11: the target's report carries a rate that is not a usable number | pending |
+| MV-N83 | internal/moves/readiness.go | T11: the target's report claims <n> probe attempts and its measurements admit <n> | pending |
## Plan 2
diff --git a/internal/moves/readiness.go b/internal/moves/readiness.go
index a1800d77e..c99182e2c 100644
--- a/internal/moves/readiness.go
+++ b/internal/moves/readiness.go
@@ -59,7 +59,24 @@ type TargetReport struct {
AttemptsAdmitted int `json:"attempts_admitted"`
CutBudgetS int `json:"cut_budget_s"`
Rates Rates `json:"rates"`
- Notes []string `json:"notes,omitempty"`
+ // DBMiB, S3At and DiskAt are the evidence behind Rates, so that Ready
+ // can re-price the cut and re-check freshness when it reads the report,
+ // not only when the report was written. Rates.Cross is the source's rate
+ // as the target used it; Ready prices from the source's current one.
+ DBMiB float64 `json:"db_mib"`
+ S3At time.Time `json:"s3_at"`
+ DiskAt time.Time `json:"disk_at"`
+ Notes []string `json:"notes,omitempty"`
+}
+
+// RecordBudget copies a BudgetCheck result and the measurements and database
+// size it was priced from into the report, the fields Ready re-checks.
+func (r *TargetReport) RecordBudget(dbMiB float64, m Measurements, res BudgetResult) {
+ r.DBMiB = dbMiB
+ r.S3At = m.S3.At
+ r.DiskAt = m.Disk.At
+ r.Rates = res.Rates
+ r.AttemptsAdmitted = res.AttemptsAdmitted
}
// SourceReport is what the source's box publishes at SourceReportKey.
@@ -156,7 +173,7 @@ func Ready(roundDelta, bar int64, target *TargetReport, source *SourceReport, no
if priced == 0 {
priced = MirrorBarMiB
}
- if want := BarMiB(bar); !(priced >= want) { // written so NaN fails
+ if want := BarMiB(bar); !finite(priced) || !(priced >= want) { // written so NaN fails
return false, fmt.Sprintf("T11: the cut budget was priced for a final round of %g MiB and the bar is %g MiB", priced, want)
}
if source == nil {
@@ -171,6 +188,9 @@ func Ready(roundDelta, bar int64, target *TargetReport, source *SourceReport, no
if !source.S2.OK {
return false, "S2: " + reasonOr(source.S2, "the source could not confirm its spawn state")
}
+ if why := budgetEvidence(target, source, bar, now); why != "" {
+ return false, why
+ }
if target.Inputs.FilesPlain != source.FilesPlain {
return false, fmt.Sprintf("the target checked files %s and the source now publishes %s", target.Inputs.FilesPlain, source.FilesPlain)
}
@@ -180,6 +200,34 @@ func Ready(roundDelta, bar int64, target *TargetReport, source *SourceReport, no
return true, ""
}
+// budgetEvidence re-prices the cut from the evidence the reports carry, at
+// `now`, and returns why it cannot be trusted, or "". Every rate must be a
+// positive finite number measured within MeasurementFreshness (the target's
+// S3 and disk rates by their report times, the cross-region rate by the
+// source's CrossRateAt), the cut window and database size must be usable,
+// and the recomputed budget must admit an attempt. The stored
+// AttemptsAdmitted may be lower than the recomputation (the reports are
+// refreshed on their own schedules) but never higher: a report cannot claim
+// more attempts than its own evidence buys.
+func budgetEvidence(target *TargetReport, source *SourceReport, bar int64, now time.Time) string {
+ if !usable(target.Rates.Cross) || !usable(target.Rates.S3) || !usable(target.Rates.Disk) {
+ return "T11: the target's report carries a rate that is not a usable number"
+ }
+ m := Measurements{
+ Cross: source.CrossMeasurement(),
+ S3: MeasuredRate{MiBPerS: target.Rates.S3, At: target.S3At},
+ Disk: MeasuredRate{MiBPerS: target.Rates.Disk, At: target.DiskAt},
+ }
+ res := BudgetCheck(target.DBMiB, m, bar, float64(target.CutBudgetS), now)
+ if !res.Check.OK {
+ return "T11: " + res.Check.Reason
+ }
+ if target.AttemptsAdmitted > res.AttemptsAdmitted {
+ return fmt.Sprintf("T11: the target's report claims %d probe attempts and its measurements admit %d", target.AttemptsAdmitted, res.AttemptsAdmitted)
+ }
+ return ""
+}
+
func reasonOr(c Check, fallback string) string {
if c.Reason == "" {
return fallback
@@ -294,6 +342,15 @@ func BudgetCheck(dbMiB float64, m Measurements, barBytes int64, windowSeconds fl
// that fails for any reason but absence is returned, never written over.
// Every mutable object the series writes to the deployment bucket goes
// through here.
+//
+// It has twins: putCAS in internal/edge/certsync.go (three attempts) and
+// status.WriteBox in internal/status/snapshot.go (one retry, a second
+// conflict is returned loudly). Both are the same read-etag-then-If-Match
+// loop with different policies and error wording, and neither is importable
+// from here without a dependency cycle through the packages that own them.
+// This one retries ONCE on conflict, like WriteBox: a report has a single
+// writer per pass, so two conflicts in a row mean something else is writing
+// the key, and the caller sees ErrCASConflict rather than a silent third try.
func PutReplace(ctx context.Context, s release.Store, key string, body []byte) error {
var err error
for attempt := 0; attempt < 2; attempt++ {
diff --git a/internal/moves/readiness_test.go b/internal/moves/readiness_test.go
index 639479aba..7c8a229b9 100644
--- a/internal/moves/readiness_test.go
+++ b/internal/moves/readiness_test.go
@@ -17,18 +17,41 @@ import (
"github.com/carlosframework/platform/internal/release"
)
+// passingTarget is a passing report made at `at` with real evidence: a
+// 100 MiB database priced from rates measured a minute earlier, in a 120 s
+// window. goodSource is the matching source report.
func passingTarget(at time.Time) *TargetReport {
- r := &TargetReport{V: 1, At: at, Checks: map[string]Check{}, AttemptsAdmitted: 1}
+ r := &TargetReport{V: 1, At: at, Checks: map[string]Check{}, CutBudgetS: 120}
for _, id := range AllChecks {
r.Checks[id] = Check{OK: true}
}
+ m := Measurements{
+ Cross: MeasuredRate{MiBPerS: 10, At: at.Add(-time.Minute)},
+ S3: MeasuredRate{MiBPerS: 250, At: at.Add(-time.Minute)},
+ Disk: MeasuredRate{MiBPerS: 500, At: at.Add(-time.Minute)},
+ }
+ res := BudgetCheck(100, m, 16<<20, 120, at)
+ if !res.Check.OK {
+ panic("the test fixture does not fit its own window: " + res.Check.Reason)
+ }
+ r.RecordBudget(100, m, res)
return r
}
+func sourceWith(now time.Time, s1, s2 Check) *SourceReport {
+ sr := goodSource(now)
+ sr.S1, sr.S2 = s1, s2
+ return sr
+}
+
+func goodSource(now time.Time) *SourceReport {
+ return &SourceReport{V: 1, At: now, S1: Check{OK: true}, S2: Check{OK: true}, CrossRate: 10, CrossRateAt: now.Add(-time.Minute)}
+}
+
func TestReadyNeedsFreshReports(t *testing.T) {
now := time.Date(2026, 10, 6, 9, 0, 0, 0, time.UTC)
pass := passingTarget
- src := &SourceReport{V: 1, At: now, S1: Check{OK: true}, S2: Check{OK: true}}
+ src := goodSource(now)
if ok, why := Ready(1<<20, 16<<20, pass(now.Add(-time.Minute)), src, now); !ok {
t.Fatal(why)
}
@@ -37,7 +60,8 @@ func TestReadyNeedsFreshReports(t *testing.T) {
t.Fatalf("stale report promoted: %v %s", ok, why)
}
// The same bound on the source's report.
- oldSrc := &SourceReport{V: 1, At: now.Add(-11 * time.Minute), S1: Check{OK: true}, S2: Check{OK: true}}
+ oldSrc := goodSource(now)
+ oldSrc.At = now.Add(-11 * time.Minute)
if ok, why := Ready(0, 16<<20, pass(now), oldSrc, now); ok || !strings.Contains(why, "stale") {
t.Fatalf("stale source report promoted: %v %s", ok, why)
}
@@ -50,10 +74,10 @@ func TestReadyNeedsFreshReports(t *testing.T) {
if ok, why := Ready(0, 16<<20, bad, src, now); ok || !strings.Contains(why, "T11") {
t.Fatalf("failed check: %v %s", ok, why)
}
- if ok, _ := Ready(0, 16<<20, pass(now), &SourceReport{V: 1, At: now, S1: Check{Reason: "503"}, S2: Check{OK: true}}, now); ok {
+ if ok, _ := Ready(0, 16<<20, pass(now), sourceWith(now, Check{Reason: "503"}, Check{OK: true}), now); ok {
t.Fatal("failed S1")
}
- if ok, why := Ready(0, 16<<20, pass(now), &SourceReport{V: 1, At: now, S1: Check{OK: true}, S2: Check{Reason: "strict spawn refused"}}, now); ok || !strings.Contains(why, "S2") {
+ if ok, why := Ready(0, 16<<20, pass(now), sourceWith(now, Check{OK: true}, Check{Reason: "strict spawn refused"}), now); ok || !strings.Contains(why, "S2") {
t.Fatalf("failed S2: %v %s", ok, why)
}
if ok, _ := Ready(0, 16<<20, nil, src, now); ok {
@@ -77,7 +101,7 @@ func TestReadyNeedsFreshReports(t *testing.T) {
func TestStaleReportAfterReadyDemotesNothing(t *testing.T) {
now := time.Date(2026, 10, 6, 9, 0, 0, 0, time.UTC)
target := passingTarget(now)
- src := &SourceReport{V: 1, At: now, S1: Check{OK: true}, S2: Check{OK: true}}
+ src := goodSource(now)
rec := &provision.Record{Move: &provision.MoveState{State: provision.MovePreparing}}
if ok, why := Ready(0, 16<<20, target, src, now); !ok {
@@ -114,7 +138,8 @@ func TestReadyRejectsMismatchedInputs(t *testing.T) {
mk := func(targetFiles, sourceFiles, targetEnv, sourceEnv string) (*TargetReport, *SourceReport) {
tr := passingTarget(now)
tr.Inputs = provision.MoveInputs{FilesPlain: targetFiles, EnvReport: targetEnv}
- sr := &SourceReport{V: 1, At: now, S1: Check{OK: true}, S2: Check{OK: true}, FilesPlain: sourceFiles, Env: EnvReport{V: 1, Digest: sourceEnv}}
+ sr := goodSource(now)
+ sr.FilesPlain, sr.Env = sourceFiles, EnvReport{V: 1, Digest: sourceEnv}
return tr, sr
}
tr, sr := mk("sha256:aaa", "sha256:aaa", "env-1", "env-1")
@@ -134,28 +159,134 @@ func TestReadyRejectsMismatchedInputs(t *testing.T) {
}
func TestReadyRefusesAnEstimateMadeUnderASmallerMirrorBar(t *testing.T) {
- now := time.Date(2026, 10, 6, 9, 0, 0, 0, time.UTC)
- src := &SourceReport{V: 1, At: now, S1: Check{OK: true}, S2: Check{OK: true}}
- tr := passingTarget(now)
-
- // Priced at the default 16 MiB bar (MirrorBar zero), the operator's
- // bar raised to 32 MiB: the estimate is too small for it.
- if ok, why := Ready(0, 32<<20, tr, src, now); ok || !strings.Contains(why, "T11") {
+ now := t11Now
+ src := goodSource(now)
+ // made returns a report whose budget was priced for the given bar.
+ made := func(barBytes int64) *TargetReport {
+ tr := passingTarget(now)
+ m := Measurements{
+ Cross: MeasuredRate{MiBPerS: 10, At: now.Add(-time.Minute)},
+ S3: MeasuredRate{MiBPerS: 250, At: tr.S3At},
+ Disk: MeasuredRate{MiBPerS: 500, At: tr.DiskAt},
+ }
+ res := BudgetCheck(100, m, barBytes, 120, now)
+ if !res.Check.OK {
+ t.Fatalf("%+v", res)
+ }
+ tr.RecordBudget(100, m, res)
+ return tr
+ }
+ // Priced at the 16 MiB default, the operator's bar raised to 32 MiB:
+ // the estimate is too small for it.
+ if ok, why := Ready(0, 32<<20, made(16<<20), src, now); ok || !strings.Contains(why, "T11") || !strings.Contains(why, "priced") {
t.Fatalf("under-priced estimate promoted: %v %q", ok, why)
}
- // Priced at 32 MiB, bar 32 MiB: fine. Priced at 32, bar lowered: fine.
- tr.Rates.MirrorBar = 32
- if ok, why := Ready(0, 32<<20, tr, src, now); !ok {
+ // Priced at 32 MiB: fine at 32, and fine at a lower bar.
+ if ok, why := Ready(0, 32<<20, made(32<<20), src, now); !ok {
t.Fatal(why)
}
- if ok, why := Ready(0, 8<<20, tr, src, now); !ok {
+ if ok, why := Ready(0, 8<<20, made(32<<20), src, now); !ok {
t.Fatal(why)
}
// Priced at 8, bar 16: too small.
- tr.Rates.MirrorBar = 8
- if ok, _ := Ready(0, 16<<20, tr, src, now); ok {
+ if ok, _ := Ready(0, 16<<20, made(8<<20), src, now); ok {
t.Fatal("a smaller priced bar promoted")
}
+ // A mirror bar that is not finite never promotes, nor a negative one.
+ for _, bar := range []float64{math.Inf(1), math.NaN(), -16} {
+ tr := made(16 << 20)
+ tr.Rates.MirrorBar = bar
+ if ok, _ := Ready(0, 16<<20, tr, src, now); ok {
+ t.Fatalf("mirror bar %v promoted", bar)
+ }
+ }
+}
+
+// The controller's fail-closed ruling: Ready re-checks the evidence behind
+// the budget at its own `now`, whatever the report's checks say.
+func TestReadyValidatesTheEvidenceItself(t *testing.T) {
+ now := t11Now
+ if ok, why := Ready(0, 16<<20, passingTarget(now), goodSource(now), now); !ok {
+ t.Fatal(why)
+ }
+ bad := []float64{0, -1, math.NaN(), math.Inf(1), math.Inf(-1)}
+ type c struct {
+ name string
+ mutate func(*TargetReport, *SourceReport)
+ }
+ var cases []c
+ for _, v := range bad {
+ v := v
+ cases = append(cases,
+ c{fmt.Sprintf("s3 rate %v", v), func(tr *TargetReport, _ *SourceReport) { tr.Rates.S3 = v }},
+ c{fmt.Sprintf("disk rate %v", v), func(tr *TargetReport, _ *SourceReport) { tr.Rates.Disk = v }},
+ c{fmt.Sprintf("cross rate in the source %v", v), func(_ *TargetReport, sr *SourceReport) { sr.CrossRate = v }},
+ c{fmt.Sprintf("cross rate in the target %v", v), func(tr *TargetReport, _ *SourceReport) { tr.Rates.Cross = v }},
+ )
+ }
+ expired := now.Add(-MeasurementFreshness - time.Second)
+ cases = append(cases,
+ c{"s3 time missing", func(tr *TargetReport, _ *SourceReport) { tr.S3At = time.Time{} }},
+ c{"s3 expired", func(tr *TargetReport, _ *SourceReport) { tr.S3At = expired }},
+ c{"s3 from the future", func(tr *TargetReport, _ *SourceReport) { tr.S3At = now.Add(time.Hour) }},
+ c{"disk time missing", func(tr *TargetReport, _ *SourceReport) { tr.DiskAt = time.Time{} }},
+ c{"disk expired", func(tr *TargetReport, _ *SourceReport) { tr.DiskAt = expired }},
+ c{"disk from the future", func(tr *TargetReport, _ *SourceReport) { tr.DiskAt = now.Add(time.Hour) }},
+ c{"cross time missing", func(_ *TargetReport, sr *SourceReport) { sr.CrossRateAt = time.Time{} }},
+ c{"cross expired", func(_ *TargetReport, sr *SourceReport) { sr.CrossRateAt = expired }},
+ c{"cross from the future", func(_ *TargetReport, sr *SourceReport) { sr.CrossRateAt = now.Add(time.Hour) }},
+ c{"source has measured no cross rate", func(_ *TargetReport, sr *SourceReport) { sr.CrossRate, sr.CrossRateAt = 0, time.Time{} }},
+ c{"database size NaN", func(tr *TargetReport, _ *SourceReport) { tr.DBMiB = math.NaN() }},
+ c{"database size negative", func(tr *TargetReport, _ *SourceReport) { tr.DBMiB = -1 }},
+ c{"no window", func(tr *TargetReport, _ *SourceReport) { tr.CutBudgetS = 0 }},
+ c{"database too big for the window", func(tr *TargetReport, _ *SourceReport) { tr.DBMiB = 1e6 }},
+ c{"more attempts claimed than admitted", func(tr *TargetReport, _ *SourceReport) { tr.AttemptsAdmitted = ProbeAttemptsMax + 1 }},
+ c{"no attempts claimed", func(tr *TargetReport, _ *SourceReport) { tr.AttemptsAdmitted = 0 }},
+ )
+ for _, cs := range cases {
+ tr, sr := passingTarget(now), goodSource(now)
+ cs.mutate(tr, sr)
+ ok, why := Ready(0, 16<<20, tr, sr, now)
+ if ok || !strings.Contains(why, "T11") {
+ t.Errorf("%s: ready=%v %q", cs.name, ok, why)
+ }
+ }
+
+ // Which rate is named when a measurement is missing or expired.
+ for _, w := range []struct {
+ name string
+ mutate func(*TargetReport, *SourceReport)
+ which string
+ }{
+ {"s3", func(tr *TargetReport, _ *SourceReport) { tr.S3At = expired }, "regional S3"},
+ {"disk", func(tr *TargetReport, _ *SourceReport) { tr.DiskAt = expired }, "the disk"},
+ {"cross", func(_ *TargetReport, sr *SourceReport) { sr.CrossRateAt = expired }, "the cross-region copy path"},
+ } {
+ tr, sr := passingTarget(now), goodSource(now)
+ w.mutate(tr, sr)
+ if _, why := Ready(0, 16<<20, tr, sr, now); !strings.Contains(why, "no fresh rate measurement for "+w.which) {
+ t.Errorf("%s: %q", w.name, why)
+ }
+ }
+
+ // A measurement that expires while its report is still fresh is
+ // refused: the target's report is 5 minutes old, its rates 58 minutes
+ // old when written, so an hour later than their time they are stale.
+ tr := passingTarget(now.Add(-5 * time.Minute))
+ tr.S3At, tr.DiskAt = now.Add(-58*time.Minute), now.Add(-58*time.Minute)
+ if ok, why := Ready(0, 16<<20, tr, goodSource(now), now); !ok {
+ t.Fatal(why)
+ }
+ if ok, why := Ready(0, 16<<20, tr, goodSource(now.Add(5*time.Minute)), now.Add(5*time.Minute)); ok || !strings.Contains(why, "T11") {
+ t.Fatalf("a measurement that expired under a fresh report: %v %q", ok, why)
+ }
+
+ // A stored count at or below the recomputed one is accepted.
+ tr = passingTarget(now)
+ tr.AttemptsAdmitted = 1
+ if ok, why := Ready(0, 16<<20, tr, goodSource(now), now); !ok {
+ t.Fatal(why)
+ }
}
func TestPassingNamesTheFirstFailureInIDOrder(t *testing.T) {
@@ -402,17 +533,16 @@ func TestT11BudgetCheckPricesTheOperatorsBar(t *testing.T) {
if zero.Seconds != def.Seconds {
t.Fatalf("%v vs %v", zero.Seconds, def.Seconds)
}
- // A report made by BudgetCheck is accepted by Ready at the same bar,
- // and refused at a larger one.
- src := &SourceReport{V: 1, At: t11Now, S1: Check{OK: true}, S2: Check{OK: true}}
+ // A rejected budget never promotes: recording the 4 GiB result in a
+ // report leaves it with zero attempts, and Ready refuses it.
+ src := goodSource(t11Now)
tr := passingTarget(t11Now)
- tr.Rates, tr.AttemptsAdmitted = big.Rates, 1
- if ok, why := Ready(0, 4<<30, tr, src, t11Now); !ok {
- t.Fatal(why)
+ tr.RecordBudget(100, m, big)
+ if tr.AttemptsAdmitted != 0 {
+ t.Fatalf("%d", tr.AttemptsAdmitted)
}
- tr.Rates = def.Rates
if ok, _ := Ready(0, 4<<30, tr, src, t11Now); ok {
- t.Fatal("a report priced at 16 MiB promoted under a 4 GiB bar")
+ t.Fatal("a report whose budget admits no attempt promoted")
}
}