burn-down Part B: 14 small rows fixed and closed across four repos (306 -> 292); no :latest in the hub build; gate list pinned; closed-id duplicates refused; R-262 subset pinned
gates / gates (push) Failing after 1m40s

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-10-05 17:10:38 +02:00
parent f5a0aeb0b8
commit b26d292a64
19 changed files with 220 additions and 35 deletions
+3 -2
View File
@@ -724,8 +724,9 @@ type hostPBSSnapshot struct {
VerifyUPID string `json:"verify_upid,omitempty"`
}
// hostBackup / hostRestoreTest mirror the agent's hub.Backup / hub.RestoreTest wire
// contract field-for-field (slice 6, doc 03 §8). DUPLICATED contract — the golden stays
// hostBackup mirrors the agent's hub.Backup wire contract field-for-field; hostRestoreTest is a deliberate
// SUBSET of hub.RestoreTest — the agent's mount_parity, mount_inventory and skipped are NOT modelled here (R-262,
// pinned by TestR262_RestoreTestFieldsAreAKnownSubset) (slice 6, doc 03 §8). DUPLICATED contract — the golden stays
// byte-identical with felhom-agent's copy and the key-set tests guard drift. The hub
// persists these via report_json (no new columns this slice) and surfaces a FAILED
// restore-test prominently (the loudest DR signal). The rich backup policy is slice 10.
@@ -0,0 +1,58 @@
package api
import (
"os"
"reflect"
"regexp"
"sort"
"strings"
"testing"
)
// R-262: hostRestoreTest is a deliberate SUBSET of the agent's hub.RestoreTest. This pins WHICH subset: the hub decodes
// exactly `hubRestoreTestFields`, and the agent fields it leaves out are exactly `knownUnmodelled`. When the agent's
// source is beside this repo (the workspace), its RestoreTest json tags must equal the union — so an agent field added
// later fails here until someone decides to model it or to list it as unmodelled. RED-PROOF: drop a field from the
// struct, or delete an entry from knownUnmodelled → this test fails.
func TestR262_RestoreTestFieldsAreAKnownSubset(t *testing.T) {
// skipped (agent v0.133.0, R-672): a skipped test arrives as Pass=false with Error "skipped: …", which the hub
// reads as a failed test with that reason — the agent's own comment calls that the honest reading.
knownUnmodelled := []string{"mount_inventory", "mount_parity", "skipped"}
var got []string
rt := reflect.TypeOf(hostRestoreTest{})
for i := 0; i < rt.NumField(); i++ {
got = append(got, strings.Split(rt.Field(i).Tag.Get("json"), ",")[0])
}
sort.Strings(got)
want := []string{"duration_seconds", "error", "pass", "scratch_vmid", "source_archive", "source_tier",
"tested_at", "verified", "warnings", "warnings_recognized"}
if !reflect.DeepEqual(got, want) {
t.Fatalf("hostRestoreTest json fields = %v, want %v", got, want)
}
for _, f := range knownUnmodelled {
for _, g := range got {
if g == f {
t.Fatalf("%s is listed as unmodelled but hostRestoreTest decodes it — update knownUnmodelled", f)
}
}
}
src, err := os.ReadFile("../../../../felhom-agent/internal/hub/report.go")
if err != nil {
t.Logf("agent source not beside this repo (%v) — the cross-repo half is not checked here", err)
return
}
body := regexp.MustCompile(`(?s)type RestoreTest struct \{(.*?)\n\}`).FindSubmatch(src)
if body == nil {
t.Fatal("type RestoreTest struct not found in felhom-agent/internal/hub/report.go")
}
var agent []string
for _, m := range regexp.MustCompile("json:\"([a-z_]+)").FindAllSubmatch(body[1], -1) {
agent = append(agent, string(m[1]))
}
sort.Strings(agent)
union := append(append([]string{}, want...), knownUnmodelled...)
sort.Strings(union)
if !reflect.DeepEqual(agent, union) {
t.Fatalf("agent RestoreTest fields %v != hub fields + knownUnmodelled %v — model the new field or list it", agent, union)
}
}