80 lines
2.9 KiB
Text
80 lines
2.9 KiB
Text
package runs
|
|
|
|
// P8-REVIEW axis 3, REFUTER probe. Read-only over the zone: adds no production code.
|
|
//
|
|
// It re-runs the finder's claim B ("a stalled settlement is invisible to EVERY operator surface")
|
|
// against the surfaces the finder did not ask: `tm_platform_oldest_hold_seconds` (Observe) and
|
|
// `pgstore.OpenReservations`, which is what `tmplatformctl balance --user` prints.
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"textmachine/platform/internal/ingest"
|
|
"textmachine/platform/internal/pgstore"
|
|
)
|
|
|
|
func TestRefuteAStalledSettlementIsSeenByTheHoldSurfaces(t *testing.T) {
|
|
f := newFixture(t, "20", 500)
|
|
run, err := f.svc.Start(f.ctx, StartRequest{UserID: "u1", BookID: f.bookID(t), CeilingChapters: 10})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := f.svc.Spawn(f.ctx, run.ID); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
a := f.lastAttempt(t, run.ID)
|
|
if err := writeExitMarker2(t, f, run.ID, a); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
f.engine.set(ingest.StatusReport{TotalUnits: 10, Done: 10}, nil)
|
|
if err := f.svc.Sweep(f.ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
open, err := f.store.UnsettledRuns(f.ctx, f.svc.now())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(open) != 1 {
|
|
t.Fatalf("%d unsettled runs", len(open))
|
|
}
|
|
// Count it to the threshold exactly as the finder did.
|
|
for i := 1; i <= StalledAfter; i++ {
|
|
if _, err := f.store.DeferRun(f.ctx, open[0].AttemptID,
|
|
f.svc.now().Add(backoff(i)), "the engine did not answer"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
// The finder's fixture ran in under a second, so `now() - opened_at` rounded to zero and the
|
|
// oldest-hold gauge READ zero for a reason that has nothing to do with what it can see. Age the
|
|
// hold by three hours — the state a frozen settlement actually produces — and ask again.
|
|
if _, err := f.store.Pool().Exec(f.ctx,
|
|
`update reservations set opened_at = now() - interval '3 hours' where state = 'open'`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
o, err := f.store.Observe(f.ctx, StalledAfter)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Logf("tm_platform_runs_stalled -> %d", o.StalledRuns)
|
|
t.Logf("tm_platform_oldest_hold_seconds -> %.0f", o.OldestHoldSeconds)
|
|
holds, err := f.store.OpenReservations(f.ctx, "u1")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// This is verbatim what `tmplatformctl balance --user` prints (cmd/tmplatformctl/main.go:243-250).
|
|
acct := f.account(t)
|
|
t.Logf("tmplatformctl balance --user u1 -> reserved %s (open holds, already deducted)", acct.Reserved.USD())
|
|
for _, r := range holds {
|
|
t.Logf("tmplatformctl balance --user u1 -> hold %s on book %s since %s (run %s)",
|
|
r.Amount.USD(), r.BookID, r.OpenedAt.UTC().Format(time.RFC3339), r.EngineRunID)
|
|
}
|
|
if o.OldestHoldSeconds < 3600 || len(holds) == 0 {
|
|
t.Fatalf("NOT REFUTED: oldest_hold=%.0f holds=%d", o.OldestHoldSeconds, len(holds))
|
|
}
|
|
}
|
|
|
|
func writeExitMarker2(t *testing.T, f *fixture, runID string, a pgstore.LiveRun) error {
|
|
t.Helper()
|
|
return writeExitMarker(t, f, runID, a)
|
|
}
|