Files
felhom-controller/controller/cmd/controller/r1176_ack_order_test.go
T

60 lines
2.2 KiB
Go

package main
import (
"go/ast"
"go/parser"
"go/token"
"testing"
)
// R-1176 (2026-10-21): the off-site apply-bridge waits only until the FLOOR is known (offsiteapply.AwaitSettle), and
// then may mint a repository password unless the box has recorded that the hub holds the household's sealed package
// (R-241's mint guard reads that record). Both facts arrive in the same report ACK, so inside OnPushResponse the
// escrow must be recorded BEFORE updater.SetFloor makes the floor known — otherwise a bridge poll landing between the
// two mints a fresh key on a rebuilt box and the household's history is set aside on its first night.
// Walks main.go's AST with comments dropped, so a commented-out call cannot satisfy it.
// COMPANION RED-PROOF: move escrowConfirmer.Reconcile below updater.SetFloor → this fails.
func TestR1176_EscrowIsRecordedBeforeTheFloorIsKnown(t *testing.T) {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "main.go", nil, 0)
if err != nil {
t.Fatal(err)
}
var escrowPos, floorPos token.Pos
ast.Inspect(f, func(n ast.Node) bool {
as, ok := n.(*ast.AssignStmt)
if !ok || len(as.Lhs) != 1 || len(as.Rhs) != 1 {
return true
}
sel, ok := as.Lhs[0].(*ast.SelectorExpr)
if !ok || sel.Sel.Name != "OnPushResponse" {
return true
}
ast.Inspect(as.Rhs[0], func(m ast.Node) bool {
call, ok := m.(*ast.CallExpr)
if !ok {
return true
}
if s, ok := call.Fun.(*ast.SelectorExpr); ok {
if x, ok := s.X.(*ast.Ident); ok {
switch {
case x.Name == "escrowConfirmer" && s.Sel.Name == "Reconcile" && escrowPos == 0:
escrowPos = call.Pos()
case x.Name == "updater" && s.Sel.Name == "SetFloor" && floorPos == 0:
floorPos = call.Pos()
}
}
}
return true
})
return true
})
if escrowPos == 0 || floorPos == 0 {
t.Fatalf("OnPushResponse no longer calls both escrowConfirmer.Reconcile (%v) and updater.SetFloor (%v) — the order is unasserted", escrowPos, floorPos)
}
if escrowPos > floorPos {
t.Fatalf("escrowConfirmer.Reconcile (%s) runs AFTER updater.SetFloor (%s): a rebuilt box can mint a fresh key before it learns the hub holds the household's package",
fset.Position(escrowPos), fset.Position(floorPos))
}
}