carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package provision
2
3import (
4 "bytes"
5 "crypto/sha256"
6 "encoding/hex"
7 "encoding/json"
8 "fmt"
9 "go/ast"
10 "go/importer"
11 "go/parser"
12 "go/token"
13 "go/types"
14 "io"
15 "io/fs"
16 "os"
17 "os/exec"
18 "path/filepath"
19 "reflect"
20 "sort"
21 "strings"
22 "testing"
23)
24
25type rootReadEntry struct{ File, Unit, Kinds, Digest string }
26type rootReadScan struct {
27 Declarations map[string]string
28 Entries []rootReadEntry
29 Coverage map[string]string
30 Fields []string
31}
32
33// Match names conservatively, including method values, aliases and writes.
34// Scanning all production packages avoids an unsound static call graph for
35// callbacks, interfaces, root CLI invocations, and build-tagged root helpers.
36var rootReadIO = strings.Fields(`Open OpenFile OpenRoot OpenInRoot Openat Openat2 Openat64 OpenByHandleAt OpenTree Fdopen Create CreateTemp ReadFile ReadDir Readlink Readlinkat Read ReadAt ReadFrom ReadAll ReadBytes ReadString Readdir Readdirnames Stat Lstat Fstat Fstatat Statx Statfs Fstatfs Access Faccessat Faccessat2 EvalSymlinks Glob Walk WalkDir Mmap Sendfile CopyFileRange Splice Query QueryContext QueryRow QueryRowContext Prepare PrepareContext Syscall Syscall6 RawSyscall RawSyscall6 Command CommandContext StartProcess Exec LoadLibrary LoadDLL NewLazyDLL NewLazySystemDLL`)
37
38type rootReadPackage struct {
39 Dir, ImportPath, Export string
40 GoFiles, CgoFiles, EmbedFiles []string
41}
42
43func rootReadTyped(root string) (map[string]string, map[string]bool, error) {
44 cmd := exec.Command("go", "list", "-deps", "-export", "-json", "./...")
45 cmd.Dir = root
46 cmd.Env = append(os.Environ(), "GOOS=linux", "GOARCH=amd64", "CGO_ENABLED=0")
47 var stderr bytes.Buffer
48 cmd.Stderr = &stderr
49 raw, err := cmd.Output()
50 if err != nil {
51 return nil, nil, fmt.Errorf("census package exports: %w: %s", err, stderr.String())
52 }
53 dec := json.NewDecoder(bytes.NewReader(raw))
54 var packages []rootReadPackage
55 exports := map[string]string{}
56 for {
57 var p rootReadPackage
58 err = dec.Decode(&p)
59 if err == io.EOF {
60 break
61 }
62 if err != nil {
63 return nil, nil, err
64 }
65 packages = append(packages, p)
66 exports[p.ImportPath] = p.Export
67 }
68 sites := map[string]string{}
69 active := map[string]bool{}
70 for _, p := range packages {
71 rel, err := filepath.Rel(root, p.Dir)
72 if err != nil {
73 return nil, nil, err
74 }
75 if rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) {
76 continue
77 }
78 fset := token.NewFileSet()
79 var files []*ast.File
80 for _, name := range append(p.GoFiles, p.CgoFiles...) {
81 path := filepath.Join(p.Dir, name)
82 f, err := parser.ParseFile(fset, path, nil, 0)
83 if err != nil {
84 return nil, nil, err
85 }
86 files = append(files, f)
87 active[path] = true
88 }
89 for _, name := range p.EmbedFiles {
90 path := filepath.Join(p.Dir, name)
91 if _, ok := active[path]; !ok {
92 active[path] = false
93 }
94 }
95 if len(files) == 0 {
96 continue
97 }
98 imp := importer.ForCompiler(fset, "gc", func(path string) (io.ReadCloser, error) {
99 if exports[path] == "" {
100 return nil, fmt.Errorf("no export for %s", path)
101 }
102 return os.Open(exports[path])
103 })
104 cfg := types.Config{Importer: imp, GoVersion: "go1.26", Sizes: types.SizesFor("gc", "amd64")}
105 info := types.Info{Selections: map[*ast.SelectorExpr]*types.Selection{}, Uses: map[*ast.Ident]types.Object{}}
106 if _, err := cfg.Check(p.ImportPath, fset, files, &info); err != nil {
107 return nil, nil, fmt.Errorf("census types %s: %w", p.ImportPath, err)
108 }
109 selectorBases := map[ast.Node]bool{}
110 for _, f := range files {
111 ast.Inspect(f, func(n ast.Node) bool {
112 if s, ok := n.(*ast.SelectorExpr); ok {
113 selectorBases[s.X] = true
114 }
115 return true
116 })
117 }
118 for id, obj := range info.Uses {
119 v, ok := obj.(*types.Var)
120 if !ok || selectorBases[id] {
121 continue
122 }
123 typ := types.Unalias(v.Type())
124 for {
125 switch t := types.Unalias(typ).(type) {
126 case *types.Pointer:
127 typ = t.Elem()
128 case *types.Slice:
129 typ = t.Elem()
130 case *types.Array:
131 typ = t.Elem()
132 case *types.Map:
133 typ = t.Elem()
134 default:
135 goto peeled
136 }
137 }
138 peeled:
139 n, ok := types.Unalias(typ).(*types.Named)
140 if !ok || n.Obj().Pkg() == nil || n.Obj().Pkg().Path() != "github.com/carlosframework/platform/internal/registry" || n.Obj().Name() == "Registry" {
141 continue
142 }
143 if _, ok = n.Underlying().(*types.Struct); !ok {
144 continue
145 }
146 pos := fset.Position(id.Pos())
147 sites[fmt.Sprintf("%s@%d:%d", pos.Filename, pos.Offset, fset.Position(id.End()).Offset)] = "whole:" + n.Obj().Name()
148 }
149 for expr, sel := range info.Selections {
150 field, ok := sel.Obj().(*types.Var)
151 if !ok || !field.IsField() || field.Pkg() == nil || field.Pkg().Path() != "github.com/carlosframework/platform/internal/registry" {
152 continue
153 }
154 pos := fset.Position(expr.Pos())
155 sites[fmt.Sprintf("%s@%d:%d", pos.Filename, pos.Offset, fset.Position(expr.End()).Offset)] = "registry:" + field.Name()
156 }
157 }
158 return sites, active, nil
159}
160
161func rootReadProduction(root string) (rootReadScan, error) {
162 out := rootReadScan{Coverage: map[string]string{}, Declarations: map[string]string{}}
163 typed, active, err := rootReadTyped(root)
164 if err != nil {
165 return out, err
166 }
167 files := map[string][]byte{}
168 extra := map[string][]byte{}
169 for path, compiled := range active {
170 if compiled {
171 continue
172 }
173 rel, err := filepath.Rel(root, path)
174 if err != nil {
175 return out, err
176 }
177 body, err := os.ReadFile(path)
178 if err != nil {
179 return out, err
180 }
181 extra[filepath.ToSlash(rel)] = body
182 }
183 err = filepath.WalkDir(root, func(p string, d fs.DirEntry, err error) error {
184 if err != nil {
185 return err
186 }
187 if d.IsDir() {
188 if p != root && (strings.HasPrefix(d.Name(), ".") || strings.HasPrefix(d.Name(), "_") || d.Name() == "testdata") {
189 return filepath.SkipDir
190 }
191 return nil
192 }
193 if !strings.HasSuffix(p, ".go") || strings.HasSuffix(p, "_test.go") {
194 if strings.HasSuffix(p, ".s") || strings.HasSuffix(p, ".sh") || strings.HasSuffix(p, ".service") || strings.HasSuffix(p, ".path") || strings.HasSuffix(p, ".socket") || strings.HasSuffix(p, ".timer") || strings.HasSuffix(p, ".conf") || strings.HasSuffix(p, ".tf") || strings.HasSuffix(p, ".tftpl") || strings.HasSuffix(p, ".tmpl") || d.Name() == "go.mod" || d.Name() == "go.sum" {
195 b, e := os.ReadFile(p)
196 if e != nil {
197 return e
198 }
199 rel, e := filepath.Rel(root, p)
200 if e != nil {
201 return e
202 }
203 extra[filepath.ToSlash(rel)] = b
204 }
205 return nil
206 }
207 b, e := os.ReadFile(p)
208 if e != nil {
209 return e
210 }
211 rel, e := filepath.Rel(root, p)
212 if e != nil {
213 return e
214 }
215 files[filepath.ToSlash(rel)] = b
216 return nil
217 })
218 if err != nil {
219 return out, err
220 }
221 for path, compiled := range active {
222 if !compiled {
223 continue
224 }
225 rel, err := filepath.Rel(root, path)
226 if err != nil {
227 return out, err
228 }
229 if _, ok := files[filepath.ToSlash(rel)]; !ok {
230 return out, fmt.Errorf("production input source excluded from census: %s", path)
231 }
232 }
233 paths := make([]string, 0, len(files))
234 for p := range files {
235 paths = append(paths, p)
236 }
237 sort.Strings(paths)
238 fields := map[string]bool{}
239 // Derive names from ALL registry structs, including embedded ownership,
240 // timers, archives, and the typed registry-child transport. No field list
241 // in the test can silently omit a newly added registry column.
242 for _, p := range paths {
243 if filepath.ToSlash(filepath.Dir(p)) != "internal/registry" {
244 continue
245 }
246 f, e := parser.ParseFile(token.NewFileSet(), p, files[p], 0)
247 if e != nil {
248 return out, e
249 }
250 ast.Inspect(f, func(n ast.Node) bool {
251 s, ok := n.(*ast.StructType)
252 if !ok {
253 return true
254 }
255 for _, f := range s.Fields.List {
256 for _, n := range f.Names {
257 fields[n.Name] = true
258 }
259 if len(f.Names) == 0 {
260 fields[censusRecvName(f.Type)] = true
261 }
262 }
263 return true
264 })
265 }
266 for f := range fields {
267 out.Fields = append(out.Fields, f)
268 }
269 sort.Strings(out.Fields)
270 ioNames := map[string]bool{}
271 for _, n := range rootReadIO {
272 ioNames[n] = true
273 }
274 coverage := map[string][]string{}
275 for _, p := range paths {
276 src := files[p]
277 sum := sha256.Sum256(src)
278 dir := filepath.ToSlash(filepath.Dir(p))
279 coverage[dir] = append(coverage[dir], p+"\x00"+hex.EncodeToString(sum[:]))
280 fset := token.NewFileSet()
281 f, e := parser.ParseFile(fset, p, src, 0)
282 if e != nil {
283 return out, e
284 }
285 grouped := map[string]int{}
286 for _, decl := range f.Decls {
287 var name string
288 switch d := decl.(type) {
289 case *ast.FuncDecl:
290 name = d.Name.Name
291 if d.Recv != nil {
292 name = censusRecvName(d.Recv.List[0].Type) + "." + name
293 }
294 case *ast.GenDecl:
295 if d.Tok == token.IMPORT {
296 continue
297 }
298 if d.Lparen.IsValid() {
299 grouped[d.Tok.String()]++
300 name = fmt.Sprintf("%s#%d", d.Tok, grouped[d.Tok.String()])
301 } else {
302 switch s := d.Specs[0].(type) {
303 case *ast.ValueSpec:
304 name = d.Tok.String() + " " + s.Names[0].Name
305 case *ast.TypeSpec:
306 name = "type " + s.Name.Name
307 }
308 }
309 default:
310 continue
311 }
312 start, end := fset.Position(decl.Pos()).Offset, fset.Position(decl.End()).Offset
313 var kinds []string
314 done := map[*ast.Ident]bool{}
315 ast.Inspect(decl, func(n ast.Node) bool {
316 mark := func(kind string, pos token.Pos) {
317 kinds = append(kinds, fmt.Sprintf("%s@%d", kind, fset.Position(pos).Offset-start))
318 }
319 switch n := n.(type) {
320 case *ast.SelectorExpr:
321 if field := typed[fmt.Sprintf("%s@%d:%d", filepath.Join(root, filepath.FromSlash(p)), fset.Position(n.Pos()).Offset, fset.Position(n.End()).Offset)]; field != "" {
322 mark(field, n.Pos())
323 } else if !active[filepath.Join(root, filepath.FromSlash(p))] && fields[n.Sel.Name] {
324 mark("candidate:"+n.Sel.Name, n.Pos())
325 }
326 if ioNames[n.Sel.Name] {
327 mark("file:"+n.Sel.Name, n.Pos())
328 }
329 done[n.Sel] = true
330 case *ast.Ident:
331 if kind := typed[fmt.Sprintf("%s@%d:%d", filepath.Join(root, filepath.FromSlash(p)), fset.Position(n.Pos()).Offset, fset.Position(n.End()).Offset)]; strings.HasPrefix(kind, "whole:") {
332 mark(kind, n.Pos())
333 }
334 // Includes unqualified functions, function-field declarations, dot
335 // imports, and aliases of an input primitive. Definitions overcount.
336 if !done[n] && ioNames[n.Name] {
337 mark("file:"+n.Name, n.Pos())
338 }
339 case *ast.BasicLit:
340 if n.Kind == token.STRING && (strings.Contains(n.Value, "/data") || strings.Contains(n.Value, "CARLOS_DATA") || strings.Contains(n.Value, "DATA_DIR")) {
341 mark("data-literal", n.Pos())
342 }
343 }
344 return true
345 })
346 sum := sha256.Sum256(src[start:end])
347 out.Declarations[p+":"+name] = hex.EncodeToString(sum[:])
348 if len(kinds) == 0 {
349 continue
350 }
351 sort.Strings(kinds)
352 s := sha256.Sum256(src[start:end])
353 out.Entries = append(out.Entries, rootReadEntry{p, name, strings.Join(kinds, ","), hex.EncodeToString(s[:])})
354 }
355 }
356 // A source envelope pins even declarations that use a previously unknown
357 // input primitive, indirect reflection, inline assembly or a wrapper. A
358 // changed/new source cannot disappear through a scanner naming blind spot.
359 for p, body := range extra {
360 sum := sha256.Sum256(body)
361 dir := filepath.ToSlash(filepath.Dir(p))
362 coverage[dir] = append(coverage[dir], p+"\x00"+hex.EncodeToString(sum[:]))
363 // A shell command or unit can read data via a variable. Review the
364 // complete file as authority, rather than matching only literal /data.
365 if p != "go.mod" && p != "go.sum" {
366 out.Declarations[p+":external"] = hex.EncodeToString(sum[:])
367 out.Entries = append(out.Entries, rootReadEntry{p, "external", "file:external@0", hex.EncodeToString(sum[:])})
368 }
369 }
370 sort.Slice(out.Entries, func(i, j int) bool {
371 a, b := out.Entries[i], out.Entries[j]
372 if a.File != b.File {
373 return a.File < b.File
374 }
375 return a.Unit < b.Unit
376 })
377 for dir, rows := range coverage {
378 sort.Strings(rows)
379 s := sha256.Sum256([]byte(strings.Join(rows, "\n")))
380 out.Coverage[dir] = hex.EncodeToString(s[:])
381 }
382 return out, nil
383}
384
385type classifiedRootRead struct {
386 rootReadEntry
387 Class, Task, Basis string
388}
389
390type rootReadInventory struct {
391 Frozen map[string]classifiedRootRead
392 Removed map[string]string
393 Entries map[string]classifiedRootRead
394 Coverage map[string]string
395 Fields string
396 Legacy map[string]bool
397}
398
399func loadRootReadInventory(path string, inv *rootReadInventory, delta bool) error {
400 raw, err := os.ReadFile(path)
401 if err != nil {
402 return err
403 }
404 seen := map[string]bool{}
405 for i, line := range strings.Split(strings.TrimSpace(string(raw)), "\n") {
406 if line == "" || strings.HasPrefix(line, "#") {
407 continue
408 }
409 col := strings.Split(line, "\t")
410 key := ""
411 switch col[0] {
412 case "@legacy":
413 if len(col) != 9 || len(col[1]) != 64 {
414 return fmt.Errorf("%s:%d: legacy fingerprint", path, i+1)
415 }
416 if _, err := hex.DecodeString(col[1]); err != nil {
417 return err
418 }
419 e := classifiedRootRead{rootReadEntry: rootReadEntry{File: col[2], Unit: col[3], Kinds: col[7], Digest: col[8]}, Class: col[4], Task: col[5], Basis: col[6]}
420 if e.Class != "legacy" || rootReadLegacyFingerprint(e) != col[1] {
421 return fmt.Errorf("invalid frozen declaration %s:%s", e.File, e.Unit)
422 }
423 if inv.Frozen == nil {
424 inv.Frozen = map[string]classifiedRootRead{}
425 }
426 identity := e.File + ":" + e.Unit
427 if _, exists := inv.Frozen[identity]; exists && !delta {
428 return fmt.Errorf("duplicate frozen declaration %s", identity)
429 }
430 inv.Frozen[identity] = e
431 key = "@legacy:" + col[1]
432 if inv.Legacy == nil {
433 inv.Legacy = map[string]bool{}
434 }
435 if inv.Legacy[col[1]] {
436 return fmt.Errorf("duplicate legacy fingerprint %s", col[1])
437 }
438 inv.Legacy[col[1]] = true
439 case "@removed":
440 // H3 may own a removal only under a recorded census ruling (census
441 // ruling zddr3); it never becomes a kept owner for an authority,
442 // hint or diagnostic row, so rootReadKeptTask stays unchanged.
443 owned := rootReadKeptTask(col[3]) || (len(col) == 5 && col[3] == "H3" && strings.HasPrefix(col[4], "census-ruling-"))
444 if len(col) != 5 || !owned || strings.TrimSpace(col[4]) == "" {
445 return fmt.Errorf("%s:%d: removal needs owner and basis", path, i+1)
446 }
447 key = col[1] + ":" + col[2]
448 if inv.Removed == nil {
449 inv.Removed = map[string]string{}
450 }
451 inv.Removed[key] = col[3] + ";" + col[4]
452 key = "@removed:" + key
453 case "@fields":
454 if len(col) != 2 {
455 return fmt.Errorf("%s:%d: fields", path, i+1)
456 }
457 key = "@fields"
458 inv.Fields = col[1]
459 case "@coverage":
460 if len(col) != 3 {
461 return fmt.Errorf("%s:%d: coverage", path, i+1)
462 }
463 key = "@coverage:" + col[1]
464 inv.Coverage[col[1]] = col[2]
465 case "@remove":
466 if !delta || len(col) != 3 {
467 return fmt.Errorf("%s:%d: removal", path, i+1)
468 }
469 key = col[1] + ":" + col[2]
470 if _, ok := inv.Entries[key]; !ok {
471 return fmt.Errorf("removal of unknown %s", key)
472 }
473 delete(inv.Entries, key)
474 default:
475 if len(col) != 7 {
476 return fmt.Errorf("%s:%d: entry", path, i+1)
477 }
478 entry := classifiedRootRead{rootReadEntry: rootReadEntry{File: col[0], Unit: col[1], Kinds: col[5], Digest: col[6]}, Class: col[2], Task: col[3], Basis: col[4]}
479 key = entry.File + ":" + entry.Unit
480 if entry.Class != "authority" && entry.Class != "hint" && entry.Class != "diagnostic" && entry.Class != "legacy" {
481 return fmt.Errorf("unclassified %s", key)
482 }
483 if entry.Class == "legacy" && (entry.Task != "accepted-legacy" || !strings.HasPrefix(entry.Basis, "accepted-legacy;rev3=")) {
484 return fmt.Errorf("invalid legacy disposition %s", key)
485 }
486 if entry.Class == "authority" && !rootReadKeptTask(entry.Task) {
487 return fmt.Errorf("authority without kept-family owner %s", key)
488 }
489 if entry.Task == "" || entry.Basis == "" {
490 return fmt.Errorf("no disposition for %s", key)
491 }
492 if !delta {
493 if _, ok := inv.Entries[key]; ok {
494 return fmt.Errorf("duplicate %s", key)
495 }
496 }
497 inv.Entries[key] = entry
498 }
499 if seen[key] {
500 return fmt.Errorf("duplicate inventory row %s", key)
501 }
502 seen[key] = true
503 }
504 return nil
505}
506
507func rootReadKeptTask(tasks string) bool {
508 for _, task := range strings.Split(tasks, ",") {
509 switch task {
510 case "A", "B", "B2", "B3", "B4", "C", "D", "E1", "E2", "E3", "E4", "F", "G":
511 return true
512 }
513 }
514 return false
515}
516
517func rootReadLegacyFingerprint(e classifiedRootRead) string {
518 line := strings.Join([]string{e.File, e.Unit, e.Class, e.Task, e.Basis, e.Kinds, e.Digest}, "\t")
519 sum := sha256.Sum256([]byte(line))
520 return hex.EncodeToString(sum[:])
521}
522
523func rootReadLegacySeal(inv rootReadInventory) string {
524 var frozen []string
525 for hash := range inv.Legacy {
526 frozen = append(frozen, hash)
527 }
528 sort.Strings(frozen)
529 sum := sha256.Sum256([]byte(strings.Join(frozen, "\n")))
530 return hex.EncodeToString(sum[:])
531}
532
533func checkRootReadLegacy(inv rootReadInventory, seal string) []string {
534 var errs []string
535 if rootReadLegacySeal(inv) != seal {
536 errs = append(errs, "changed legacy freeze; separate scope ruling required")
537 }
538 for key, e := range inv.Entries {
539 if e.Class == "legacy" && !inv.Legacy[rootReadLegacyFingerprint(e)] {
540 errs = append(errs, "changed legacy root read "+key+"; reclassify before changing source or disposition")
541 }
542 }
543 sort.Strings(errs)
544 return errs
545}
546
547func compareRootReads(got rootReadScan, want rootReadInventory) []string {
548 var errs []string
549 seen := map[string]bool{}
550 for _, g := range got.Entries {
551 key := g.File + ":" + g.Unit
552 if seen[key] {
553 errs = append(errs, "duplicate scanned unit "+key)
554 }
555 seen[key] = true
556 w, ok := want.Entries[key]
557 if !ok {
558 errs = append(errs, "unclassified root read "+key+" "+g.Kinds)
559 continue
560 }
561 if w.Kinds != g.Kinds || w.Digest != g.Digest {
562 errs = append(errs, "changed root read "+key+"; review class, task, sites and digest")
563 }
564 }
565 for key := range want.Entries {
566 if !seen[key] && !(want.Entries[key].Class != "legacy" && want.Entries[key].Kinds == "" && got.Declarations[key] == want.Entries[key].Digest) {
567 errs = append(errs, "stale root read "+key)
568 }
569 }
570 for dir, hash := range got.Coverage {
571 if want.Coverage[dir] != hash {
572 errs = append(errs, "changed root source envelope "+dir)
573 }
574 }
575 for dir := range want.Coverage {
576 if _, ok := got.Coverage[dir]; !ok {
577 errs = append(errs, "stale root source envelope "+dir)
578 }
579 }
580 if strings.Join(got.Fields, ",") != want.Fields {
581 errs = append(errs, "changed registry schema")
582 }
583 sort.Strings(errs)
584 return errs
585}
586
587func TestPlan14RootReadCensus(t *testing.T) {
588 // Reads the source tree and testdata only (go list writes nothing
589 // here but the build cache), so it runs in parallel.
590 t.Parallel()
591 root := censusRoot(t)
592 got, err := rootReadProduction(root)
593 if err != nil {
594 t.Fatal(err)
595 }
596 inv, seal := rootReadChain(t, root)
597 errs := append(compareRootReads(got, inv), checkRootReadLegacy(inv, seal)...)
598 errs = append(errs, checkRootReadDeclarations(got, inv)...)
599 if len(errs) > 0 {
600 t.Fatalf("root read census: %d discrepancies\n%s\n\nmake census-card shows what changed; make census-propose NAME=<branch> CLAIMS=<file> writes the overlay and its approval card (AGENTS.md, The census)", len(errs), strings.Join(errs, "\n"))
601 }
602 counts := map[string]int{}
603 sites := 0
604 for _, e := range inv.Entries {
605 counts[e.Class]++
606 sites += len(strings.Split(e.Kinds, ","))
607 }
608 t.Logf("%d units, %d sites, %d source envelopes; classes %v", len(inv.Entries), sites, len(inv.Coverage), counts)
609}
610
611// rootReadChain loads the census inventory: the base file and every overlay
612// in order, each loaded only after its predecessor's seal is checked, then
613// the overlays the chain manifest lists (rootReadManifest). It returns the
614// inventory and the seal the last overlay leaves.
615func rootReadChain(t testing.TB, root string) (rootReadInventory, string) {
616 t.Helper()
617 return rootReadChainBefore(t, root, "")
618}
619
620// rootReadChainBefore is rootReadChain without the manifest's last overlay
621// when that overlay is the file named last (a census-propose re-run
622// proposing against the chain before its own overlay); "" loads it all.
623func rootReadChainBefore(t testing.TB, root, last string) (rootReadInventory, string) {
624 t.Helper()
625 var err error
626 inv := rootReadInventory{Entries: map[string]classifiedRootRead{}, Coverage: map[string]string{}}
627 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads.tsv"), &inv, false); err != nil {
628 t.Fatal(err)
629 }
630 // This is the explicitly pinned integrated variant, not a generic waiver.
631 // Its exact full production envelope still has to match.
632 seal := "eded8ea32c869352dd0f15b20e817ff91bdb45844c97b9c72883e603a0b1ec16"
633 _, err = os.Stat(filepath.Join(root, "internal/host/movesheldrelease_production.go"))
634 if err == nil {
635 seal = "fddd1cfd0391db80770074c47156dca161c5618d0d92da08669aea2cc22dcf9e"
636 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-moves.tsv"), &inv, true); err != nil {
637 t.Fatal(err)
638 }
639 } else if !os.IsNotExist(err) {
640 t.Fatal(err)
641 }
642 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
643 t.Fatal(errs)
644 }
645 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-merge.tsv"), &inv, true); err != nil {
646 t.Fatal(err)
647 }
648 seal = "c88a37629c95dd397beeb95f5ef101438fa884ac04dc4435aa55387b897d393c"
649 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
650 t.Fatal(errs)
651 }
652 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-fix1.tsv"), &inv, true); err != nil {
653 t.Fatal(err)
654 }
655 seal = "c3351f27f6467fc33b319b36a7e64b75b2d992232f956d9c6243cc49e0c05396"
656 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
657 t.Fatal(errs)
658 }
659 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-fix2.tsv"), &inv, true); err != nil {
660 t.Fatal(err)
661 }
662 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
663 t.Fatal(errs)
664 }
665 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-merge3.tsv"), &inv, true); err != nil {
666 t.Fatal(err)
667 }
668 seal = "65dba959f80cc47e9fd99be145ba8b24bb3b37ffaf77b47d1b9cc3e01da14b47"
669 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
670 t.Fatal(errs)
671 }
672 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-fix4.tsv"), &inv, true); err != nil {
673 t.Fatal(err)
674 }
675 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-fix5.tsv"), &inv, true); err != nil {
676 t.Fatal(err)
677 }
678 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-fix6.tsv"), &inv, true); err != nil {
679 t.Fatal(err)
680 }
681 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-zddr3.tsv"), &inv, true); err != nil {
682 t.Fatal(err)
683 }
684 // Census ruling zddr3 (#272): the exec shim's accepted-legacy rows and the
685 // three refreshed legacy rows add thirteen frozen declarations.
686 seal = "c748e02bfe907a009ef42eb544b1a44fe813f4f7c13e454be3980aec4fade568"
687 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
688 t.Fatal(errs)
689 }
690 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-hotfix281.tsv"), &inv, true); err != nil {
691 t.Fatal(err)
692 }
693 seal = "6da50872e15f7f396d23e5b1b2e044a73cd9e5c07d85c8e22252b0a1a5304bbd"
694 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
695 t.Fatal(errs)
696 }
697 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-zddr4.tsv"), &inv, true); err != nil {
698 t.Fatal(err)
699 }
700 // Census ruling zddr4 (zero-downtime rev 19, Gate F, #272): ten changed
701 // activator rows and four new ones (generation socket directories) add
702 // fourteen frozen declarations.
703 seal = "e736a5e2652cc546db02c5a385ae7da9fa8a4313d3064f6b431642431974d65d"
704 // Census overlay reserved285 (#285): envelope-only, for the reserved-sqid
705 // skip in the account allocator and its materialization log line. No
706 // root-read unit changes, so the legacy seal above stands.
707 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-reserved285.tsv"), &inv, true); err != nil {
708 t.Fatal(err)
709 }
710 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-292.tsv"), &inv, true); err != nil {
711 t.Fatal(err)
712 }
713 // Census ruling 292 (amadan #292, platform-1e, extended): the agent's
714 // shutdown gates, the legacy run unit's termination proof, the retried
715 // conditional lease release, and root's per-host ordering of legacy run
716 // starts against stops (type Server, J2,J4). Eight changed activator
717 // rows, three new proof units and the reclassified instance-control
718 // Server declaration add twelve frozen declarations.
719 seal = "3b2506dd2ab3986d0df0ceda7f596e5a46ea4d1dfbc17b1d0fd8d5f176e8038d"
720 // Census ruling 275 (amadan #275, platform-1e): envelope-only, for the SDK
721 // clients held as method values in awsinv, alerting, host, edge and
722 // steering. No root-read unit changed or was added, so the legacy seal
723 // above stands.
724 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-census-ruling-275.tsv"), &inv, true); err != nil {
725 t.Fatal(err)
726 }
727 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
728 t.Fatal(errs)
729 }
730 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-census-ruling-owed.tsv"), &inv, true); err != nil {
731 t.Fatal(err)
732 }
733 // Census ruling owed (amadan #272, zdd-owed-items, platform-1e): a cold
734 // wake's build-state record is written at its first exec, after the
735 // replica-key gate and the cgroup refusals, and the exec is decided
736 // again after the write. Four changed activator rows add four frozen
737 // declarations.
738 seal = "79db70c4c396457e563bf792027f98eeed7cef3dc54fff8abedb025e7db1dfbb"
739 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
740 t.Fatal(errs)
741 }
742 // Census ruling carlos-run (Plan 14 controller, 2026-10-14): the
743 // carlos-run branch's overlay (carlos run, #259), loaded last, after
744 // census ruling owed. It adds 59 frozen declarations: the 58 it was ruled
745 // with, and instance control's type Server, which census ruling 292 made
746 // accepted-legacy and which this overlay re-digests as main classed it.
747 // Its four instance-control rows are accepted legacy on two conditions,
748 // recorded in the overlay's header: the cmd template-equality test
749 // stays, and the cmd verb stays on refuseStagedExe.
750 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-carlos-run.tsv"), &inv, true); err != nil {
751 t.Fatal(err)
752 }
753 seal = "96e521e60dfc0b55e2bc08adbb7a7682a607a30599a8cf66e7c5689d6cf7fe5a"
754 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
755 t.Fatal(errs)
756 }
757 // Census ruling seeded-instances (Plan 14 controller, 2026-10-14): the
758 // seeded-instances branch's overlay (seeded instances, #260 and #261),
759 // loaded last, after carlos-run's. It adds 98 frozen declarations. The
760 // seeds floor's root readers are authority F,J4 and deny-only;
761 // CollectCensusSeeds and ImportJournalHosts are authority G on the
762 // condition, recorded in the overlay's header, that they only ever feed
763 // a refusal. Its last block is census ruling 292fix (Plan 14 controller,
764 // 2026-10-15), an extension of census ruling 292 for the seeded pre-land
765 // review's P2: doWake, cleanupFailedWake and reapUnprovenWake, accepted
766 // legacy as on main.
767 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-seeded-instances.tsv"), &inv, true); err != nil {
768 t.Fatal(err)
769 }
770 seal = "10e024eccd584f40b64e959a105c551302585e3e14e55104fc250dae5960898a"
771 // Census overlay hostfiles-cap-236 (amadan #236): envelope-only, for
772 // hostfiles exporting its cap rule as RestorableWithinCap. No root-read
773 // unit changed or was added, so the legacy seal above stands.
774 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-hostfiles-cap-236.tsv"), &inv, true); err != nil {
775 t.Fatal(err)
776 }
777 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
778 t.Fatal(errs)
779 }
780 // Census overlay moves-overcap-cut-236 (#236, moves' part of Paul's
781 // ruling of 2026-10-15), loaded last: the moves source round's files
782 // manifest preflight, under census ruling moves-overcap-cut-236
783 // (platform-1e, 2026-10-15). sourceRefusal and sourceRound stay
784 // accepted-legacy with the ruling's lines, on the binding condition that
785 // the preflight is deny-only (the overlay's header). The ruling's
786 // extension (fix round 1) covers archive.walk, buildPrepared and
787 // readFileBounded for the files tree's cap, on the binding condition that
788 // no read falls back to a path-based open when a root open fails. The
789 // seal moves; the internal/host and internal/moves/archive envelopes are
790 // re-pinned.
791 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-moves-overcap-cut-236.tsv"), &inv, true); err != nil {
792 t.Fatal(err)
793 }
794 seal = "fc38db001ebd8825709a8ca9c41cc0e8f165c1b1967e5967347dc9bd3556afec"
795 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
796 t.Fatal(errs)
797 }
798 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-seed.tsv"), &inv, true); err != nil {
799 t.Fatal(err)
800 }
801 // FS-R6 preserves three legacy readers; FS-R10 re-digests the test-only S3 server. Other proposals remain unapproved.
802 seal = "624e96c0f0fd397d09575e807f7347f86cbcb109b4b713eb8369f0b64622e483"
803 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
804 t.Fatal(errs)
805 }
806 // Census overlay home-part2 (amadan #236, moves into home part 2): T3's
807 // home rule (moves.CompareEnv's targetHome) and the move-portable env
808 // pin (moves.Pinned, ReportLaunch, LocalDigest; ExecBackend.LaunchLayers).
809 // Twelve changed or new units re-frozen at main's dispositions, ten of
810 // them legacy, add ten frozen declarations; Task 4's revert fix adds
811 // revertRun.probing, frozen at its sibling units' disposition, an
812 // eleventh. Task 5's move door (a home target under host claims)
813 // re-freezes Server.handleAPIInstanceMoveRequest and
814 // Server.startClaimModeMove at main's dispositions, read sets
815 // unchanged, two more. Ruled 2026-10-16 as census-ruling-home-part2
816 // (the overlay's header), on the condition that revertRun.probing's
817 // re-read accepts only the probe wake's own writes; that check
818 // re-pinned revertRun.probing at the same disposition, so the seal moved.
819 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-home-part2.tsv"), &inv, true); err != nil {
820 t.Fatal(err)
821 }
822 // Census overlay fix-empty-app-key (RULING OWED, platform-1e), loaded
823 // last: envelope-only, at main's dispositions. The apps/<sqid>/<app>/
824 // family key builders refuse an empty or invalid segment, and the box
825 // shippers skip a refused app. No root-read unit changed or was added, so
826 // the seal below is home-part2's.
827 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-fix-empty-app-key.tsv"), &inv, true); err != nil {
828 t.Fatal(err)
829 }
830 seal = "5d1b9b6addf6c9964ed18b417ee5b3d0d49fd43e1acabb775e054bba4b6e314e"
831 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
832 t.Fatal(errs)
833 }
834 // Census overlay region-ha-2a (region HA spec 2, plan 2a), loaded last.
835 // Its header says what each plan task added. The accepted-legacy rows
836 // it adds are census ruling region-ha-2a's (platform-1e), and move the
837 // seal.
838 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-region-ha-2a.tsv"), &inv, true); err != nil {
839 t.Fatal(err)
840 }
841 seal = "8198674d8809ef90ecebac55324bfd75e69fb3d73bc27b942f29ca2f43e3fe8d"
842 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
843 t.Fatal(errs)
844 }
845 // Track E precedes Part 3, which records their merged declarations.
846 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-e.tsv"), &inv, true); err != nil {
847 t.Fatal(err)
848 }
849 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-p3.tsv"), &inv, true); err != nil {
850 t.Fatal(err)
851 }
852 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-activation-tools.tsv"), &inv, true); err != nil {
853 t.Fatal(err)
854 }
855 // Census overlay region-ha-2b (region HA spec 2, plan 2b), loaded last.
856 // Its header says what each plan task added. The rows it adds are
857 // census ruling region-ha-2b's (platform-1e); its accepted-legacy rows
858 // move the seal.
859 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-region-ha-2b.tsv"), &inv, true); err != nil {
860 t.Fatal(err)
861 }
862 seal = "fc584e113d0c6786bdeb3344354ae567c112c607e68f85056352545557a91b5d"
863 // Census overlay box-publish-record (carlos system box publish-record),
864 // loaded last, under census-ruling-box-publish-record (platform-1e,
865 // R1-R4): root unreachable, the verb refuses euid 0 (R1). Envelope-only:
866 // it re-pins the internal/host and root package envelopes, adds and
867 // changes no root-read unit, and the seal stands.
868 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-box-publish-record.tsv"), &inv, true); err != nil {
869 t.Fatal(err)
870 }
871 // Census overlay claim-step6-artifacts (claim trial step 6: sign-policy,
872 // publish-identity, install-console and guard-arm's parse), loaded last.
873 // Ruled by the controller, accepted as proposed
874 // (docs/superpowers/notes/census-proposal-claim-step6-artifacts.md). It
875 // adds no accepted-legacy row, so the seal stands.
876 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claim-step6-artifacts.tsv"), &inv, true); err != nil {
877 t.Fatal(err)
878 }
879 // Census overlay claim-step6-artifacts-fix1 (fix round 1: F1 bounded ELF
880 // pre-check, F3 sums bound to the tag, F4 --out reserved before the
881 // phase), loaded last, under census-ruling-claim-step6-artifacts-fix1
882 // (platform-1e, accepted as proposed). It adds no accepted-legacy row, so
883 // the seal stands.
884 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claim-step6-artifacts-fix1.tsv"), &inv, true); err != nil {
885 t.Fatal(err)
886 }
887 // Census overlay claim-step6-artifacts-fix2 (fix round 2: F1 name caps,
888 // F5 a reserved --out file is never removed), loaded last, under
889 // census-ruling-claim-step6-artifacts-fix2 (platform-1e, accepted as
890 // proposed). It adds no accepted-legacy row, so the seal stands.
891 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claim-step6-artifacts-fix2.tsv"), &inv, true); err != nil {
892 t.Fatal(err)
893 }
894 // Census overlay claim-prev-rehearsal (install-channel --policy: arm an
895 // updater-installed box, controller ruling R1), loaded last, under
896 // census-ruling-claim-prev-rehearsal (platform-1e, accepted as proposed;
897 // docs/superpowers/notes/census-proposal-claim-prev-rehearsal.md). It
898 // adds no accepted-legacy row, so the seal stands.
899 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claim-prev-rehearsal.tsv"), &inv, true); err != nil {
900 t.Fatal(err)
901 }
902 // Census overlay claim-prev-rehearsal-fix1 (fix round 1: mandatory
903 // carlos.prev record, unfinished-update refusal, the census branch for
904 // --policy, the hardened policy read), loaded last, under
905 // census-ruling-claim-prev-rehearsal-fix1 (platform-1e, accepted as
906 // proposed; docs/superpowers/notes/census-proposal-claim-prev-rehearsal.md,
907 // "Fix round 1"). It adds no accepted-legacy row, so the seal stands.
908 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claim-prev-rehearsal-fix1.tsv"), &inv, true); err != nil {
909 t.Fatal(err)
910 }
911 // Census overlay claim-prev-rehearsal-fix2 (fix round 2: carlos.prev's
912 // judgement always finished on --policy's already-installed path),
913 // loaded last. Envelope only. Under census-ruling-claim-prev-rehearsal-fix2
914 // (platform-1e, accepted as proposed;
915 // docs/superpowers/notes/census-proposal-claim-prev-rehearsal.md,
916 // "Fix round 2"). The seal stands.
917 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claim-prev-rehearsal-fix2.tsv"), &inv, true); err != nil {
918 t.Fatal(err)
919 }
920 // Census overlay console-invite-delivery (console invite delivery),
921 // loaded last, under census-ruling-console-invite-delivery (platform-1e,
922 // R1-R5): seven units accepted legacy under the console (carlos-console)
923 // or tofu on an operator's machine, since the root carlos binary links
924 // neither internal/console nor internal/mail (R1, pinned by
925 // TestRootBinaryLinksNoConsoleOrMail); Keymail.SendApp retired by an H3
926 // census-ruling removal (R2); the rev3 tag rewritten to the ruling's
927 // name (R4). The ruling is the scope ruling the freeze needs, and the
928 // seal moves.
929 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-console-invite-delivery.tsv"), &inv, true); err != nil {
930 t.Fatal(err)
931 }
932 // Census overlay claim-untagged-pointer (install-channel --policy takes
933 // --identity, the published release identity, because the channel
934 // pointer carlos system update writes before a floor is published
935 // carries no release tag; controller ruling R1), loaded last, under
936 // census-ruling-claim-untagged-pointer (platform-1e, accepted as
937 // proposed; docs/superpowers/notes/census-proposal-claim-untagged-pointer.md):
938 // channelInstall.run and openChannelPolicy re-pinned with corrected
939 // bases at unchanged digests, sites and class F,J4, and the internal/host
940 // envelope re-pinned. It adds no accepted-legacy row, so the seal stands.
941 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claim-untagged-pointer.tsv"), &inv, true); err != nil {
942 t.Fatal(err)
943 }
944 // Census overlay claim-untagged-pointer-fix1 (review fix round 1: a
945 // missing identity object gets its own refusal; openChannelPolicy's
946 // comment names both files), loaded last. Envelope only. Under
947 // census-ruling-claim-untagged-pointer-fix1 (platform-1e, accepted as
948 // proposed; docs/superpowers/notes/census-proposal-claim-untagged-pointer.md,
949 // "Fix round 1"). The seal stands.
950 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claim-untagged-pointer-fix1.tsv"), &inv, true); err != nil {
951 t.Fatal(err)
952 }
953 // Census overlay claim-untagged-pointer-fix2 (Paul's copy approval
954 // applied: the re-approved RHB-C19 usage), loaded last. Envelope only.
955 // Under census-ruling-claim-untagged-pointer-fix2 (platform-1e, accepted
956 // as proposed; docs/superpowers/notes/census-proposal-claim-untagged-pointer.md,
957 // "Fix round 2"). The seal stands.
958 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claim-untagged-pointer-fix2.tsv"), &inv, true); err != nil {
959 t.Fatal(err)
960 }
961 // Census overlay claim-guard-umask (guard-arm's directories ignore the
962 // caller's umask), loaded last, under census-ruling-claim-guard-umask
963 // (platform-1e): RunSystemGuardArm re-pinned at its class F,J4, the new
964 // mkdirAllExact classified G,J4, and the internal/host envelope
965 // re-pinned. It adds no accepted-legacy row, so the seal stands.
966 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claim-guard-umask.tsv"), &inv, true); err != nil {
967 t.Fatal(err)
968 }
969 // Census overlay adopt-unit-root-pass-315 (amadan #315: a non-root agent
970 // hands a named unit's routes to the root pass), loaded last. Ruled by the census owner on #280
971 // (census-ruling-315, accepted as proposed): adoptHost re-pinned at its
972 // class, type passConfig gains a bool, and unitServed (new) classified
973 // with processGroup, whose membership it inverts. Both envelopes
974 // re-pinned. It adds no accepted-legacy row, so the seal stands.
975 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-adopt-unit-root-pass-315.tsv"), &inv, true); err != nil {
976 t.Fatal(err)
977 }
978 // Census overlay bootstrap-carlos-follows-316 (amadan #316: system status
979 // compares bootstrap/carlos with stable's build), loaded last. Envelope
980 // only, ruled accepted by the census owner on #280. The seal
981 // stands.
982 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-bootstrap-carlos-follows-316.tsv"), &inv, true); err != nil {
983 t.Fatal(err)
984 }
985 seal = "53b3cbb6f46d657ce32f49dad84dae79316c80da949ccf37273833eef5c5b2d7"
986 // Census overlay claim-step8-readiness (dev cohort-1 step 8: the backfill
987 // phases, leo's migration census classes and window masks, the floor and
988 // retry directories' umask, and the absent legacy journal directory),
989 // loaded last. RULED (platform-1e, 2026-10-20): accepted as proposed
990 // (docs/superpowers/notes/census-proposal-claim-step8-readiness.md),
991 // marked rev3=census-ruling-claim-step8-readiness. It adds no accepted-legacy
992 // row, so the seal stands.
993 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claim-step8-readiness.tsv"), &inv, true); err != nil {
994 t.Fatal(err)
995 }
996 // Census overlay claim-empty-cohort-fix1 (fix round 1 for
997 // claim-empty-cohort-done: Backfill.Done lists the records again before
998 // and after its write; the root migration repairs its floor directories
999 // before the first floor read), loaded last. Ruled by platform-1e, accepted as
1000 // proposed (docs/superpowers/notes/census-proposal-claim-step8-readiness.md,
1001 // "Fix round 1"). It adds no accepted-legacy row, so the seal stands.
1002 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claim-empty-cohort-fix1.tsv"), &inv, true); err != nil {
1003 t.Fatal(err)
1004 }
1005 // Census overlay claim-empty-cohort-fix2 (fix round 2: the floor repair
1006 // walks from / by descriptor and checks every ancestor before it makes
1007 // or changes anything, through walkNoFollowDir, consoleDir's walk
1008 // factored out unchanged), loaded last. Ruled by platform-1e, accepted as proposed
1009 // (docs/superpowers/notes/census-proposal-claim-step8-readiness.md,
1010 // "Fix round 2"). It adds no accepted-legacy row, so the seal stands.
1011 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claim-empty-cohort-fix2.tsv"), &inv, true); err != nil {
1012 t.Fatal(err)
1013 }
1014 // Census overlay claim-rootaws-sentinel (rootaws's scrub treats its own
1015 // inherited disabled-file sentinels as no override, so a guard-armed
1016 // box's updater can read a candidate's version), loaded last. Envelope
1017 // only, ruled by platform-1e. The seal stands.
1018 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claim-rootaws-sentinel.tsv"), &inv, true); err != nil {
1019 t.Fatal(err)
1020 }
1021 // Census overlay claim-harness-census (the migration census keeps both
1022 // pointer-digest ratchets and install-control's activation lock, the
1023 // deployment harness's 8.2 stops), loaded last. Ruled by platform-d8,
1024 // accepted as proposed; no accepted-legacy row, so the seal stands.
1025 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claim-harness-census.tsv"), &inv, true); err != nil {
1026 t.Fatal(err)
1027 }
1028 // Census overlay claim-own-child (the generation census accepts
1029 // journal-migrate's own registry child past the root-task rule, untrusted),
1030 // loaded last. Ruled by platform-d8, accepted as proposed; no
1031 // accepted-legacy row, so the seal stands.
1032 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claim-own-child.tsv"), &inv, true); err != nil {
1033 t.Fatal(err)
1034 }
1035 // Census overlay claim-ack-refresh (G10: the box refreshes its own
1036 // execution acknowledgement while the op waits on the console, and the
1037 // regional enrollment check ignores the roster-wide revision but carries
1038 // the row's quarantine revision), loaded last.
1039 // census-ruling-claim-ack-refresh: Ruled by platform-d8, accepted
1040 // (docs/superpowers/notes/census-proposal-claim-step8-readiness.md,
1041 // "Ack refresh"); no accepted-legacy row, so the seal stands.
1042 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claim-ack-refresh.tsv"), &inv, true); err != nil {
1043 t.Fatal(err)
1044 }
1045 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1046 t.Fatal(errs)
1047 }
1048 // Census overlay moves-offline (the offline operator move), loaded last.
1049 // census-ruling-moves-offline: RULED by the census owner (platform-1c,
1050 // 2026-10-20), accepted as proposed
1051 // (docs/superpowers/notes/census-proposal-moves-offline.md). Its 39 new
1052 // units run as the agent, the console or the CLI and make no root
1053 // decision, so they are proposed accepted legacy at their moves
1054 // siblings' dispositions; four changed legacy units are re-frozen and
1055 // two authority units re-pinned at main's class. 43 frozen declarations
1056 // are added, so the seal moves. The ruling's extension (platform-1c,
1057 // for 8dc2a544's release item) re-freezes landRun.release at its
1058 // disposition and accepts landRun.liveNotSealed as legacy, on the
1059 // condition that it compares the live link's Readlink target string and
1060 // follows nothing beyond the link; 44 frozen declarations in all.
1061 // OfflineStart re-pinned for a text-only helper extraction (copy gate),
1062 // 2026-10-20; no read, class or behaviour change.
1063 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-moves-offline.tsv"), &inv, true); err != nil {
1064 t.Fatal(err)
1065 }
1066 seal = "393e7f456d8f02b2eee0c683880e5f7bf696b6ee0c87f20e5c113434065bec29"
1067 // Census overlay armed-box-updates (cherry-picked from the claim branch
1068 // for v0.28.5): rootaws's scrub treats its own inherited disabled-file
1069 // sentinels as no override, and hostfloor's guarded run returns stdout
1070 // only, so a guard-armed box's updater can read a candidate's version and
1071 // plan. Loaded last, under census-ruling-claim-rootaws-sentinel
1072 // (platform-1c). No legacy row; the seal stands.
1073 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-armed-box-updates.tsv"), &inv, true); err != nil {
1074 t.Fatal(err)
1075 }
1076 // Census overlay install-console-upgrade (claims install-console
1077 // --upgrade --from: a guard-armed box's protected console can be
1078 // replaced, not only installed once), loaded last.
1079 // census-ruling-install-console-upgrade: RULED by platform-d8, accepted as proposed at da0a33b7 and b913bb65
1080 // (docs/superpowers/notes/census-proposal-install-console-upgrade.md).
1081 // runSystemClaims is re-pinned at its class, consoleSlotHolds's read
1082 // moves into consoleSlotSHA, and upgradeProtectedConsole and
1083 // writeConsoleTemp are new, all authority G,J4. Round 2 (Astra's
1084 // review): readConsoleSource's read moves into readConsoleSourceFile,
1085 // and consoleDigest and consoleCounter.Read are new, also G,J4. No
1086 // legacy row; the seal stands.
1087 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-install-console-upgrade.tsv"), &inv, true); err != nil {
1088 t.Fatal(err)
1089 }
1090 // Census overlay moves-offline-fixes (harness Run 9's defects 6 to 8 in
1091 // the offline operator move), loaded last, under
1092 // census-ruling-moves-offline-fixes (platform-1c, 2026-10-20); the
1093 // proposal names each unit's executing identity
1094 // (docs/superpowers/notes/census-proposal-moves-offline-fixes.md). Every
1095 // unit runs in the agent and makes no root decision: changed legacy
1096 // units re-frozen at main's disposition, new ones proposed accepted
1097 // legacy at their siblings'. Frozen declarations are added, so the seal
1098 // moves; main's is checked first.
1099 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1100 t.Fatal(errs)
1101 }
1102 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-moves-offline-fixes.tsv"), &inv, true); err != nil {
1103 t.Fatal(err)
1104 }
1105 seal = "826c54be9447f0a7c42386dba6be5888fc5a708bf1e5a57f2a6de6da4662a62f"
1106 // Census overlay console-switcher-filter (the console's account switcher
1107 // gains a client-side filter box and a scrolling list), loaded last.
1108 // PROPOSED-console-switcher-filter, asked of the census owner on #280.
1109 // layout.html is a legacy UI template re-frozen at its main disposition;
1110 // only browser-side CSS and script change. One frozen declaration is
1111 // added, so the seal moves; moves-offline-fixes' is checked first.
1112 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1113 t.Fatal(errs)
1114 }
1115 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-console-switcher-filter.tsv"), &inv, true); err != nil {
1116 t.Fatal(err)
1117 }
1118 seal = "a42b90d7a5c440ae8d94981fa3d80f46891e676ed0783574e193afc3534fef1a"
1119 // Paul approved this scoped inventory update on 2026-10-21. The final
1120 // independent branch review remains pending. Preserve the prior freeze
1121 // before adding the five console entries and six source envelopes.
1122 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1123 t.Fatal(errs)
1124 }
1125 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-scan-demand-revival.tsv"), &inv, true); err != nil {
1126 t.Fatal(err)
1127 }
1128 seal = "a21dba12b0f3cd0811c624ec352d6ff5c46936ef0da1d4ce9d31cdd13cc0f262"
1129 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1130 t.Fatal(errs)
1131 }
1132 // Census overlay run-lifecycle-logs-325 (amadan #325: the box's carlos
1133 // run worker emits run started and run ended as member log events
1134 // through the agent's EventSink), loaded last, after scan-demand-revival. Proposed; ruling asked of
1135 // the census owner on #280. No root read, file read or record write is
1136 // added: runAgent and runsWorker.execute are re-pinned at their class and
1137 // task, and the internal/host envelope is re-pinned. The seal moves
1138 // because execute's legacy declaration was re-pinned.
1139 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-run-lifecycle-logs-325.tsv"), &inv, true); err != nil {
1140 t.Fatal(err)
1141 }
1142 seal = "cf0a526b5f7c913160b1e6a76fa34c34dacd60cbacfd8019e736c2ab852399e3"
1143 // Census overlay design-plans-and-caps (plans 1: plan catalog, account
1144 // plans, limits record publisher and operator door), loaded last.
1145 // PROPOSED-design-plans-and-caps, asked of the census owner on #280.
1146 // New console store methods, LoadCatalog and the CLI's --sponsored read
1147 // are accepted legacy at their siblings' disposition; serve and
1148 // Store.migrate are re-frozen. Frozen declarations are added, so the
1149 // seal moves; run-lifecycle-logs-325's is checked first.
1150 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1151 t.Fatal(errs)
1152 }
1153 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-design-plans-and-caps.tsv"), &inv, true); err != nil {
1154 t.Fatal(err)
1155 }
1156 seal = "4f5e0ed6adf7d6bcefdfc9ce50599a21adb06ae3e6d49cab71835e116968df17"
1157 // Census overlay moves-offline-precopy (parallel copies in
1158 // lease.MirrorPrefix and the carlos move offline stage door), loaded
1159 // last, after design-plans-and-caps, under
1160 // census-ruling-moves-offline-precopy (the coordinator, as census owner,
1161 // 2026-10-21); the ruling names each unit's executing identity
1162 // (docs/superpowers/notes/census-proposal-moves-offline-precopy.md).
1163 // offlineSourceRevert is re-frozen at its disposition, offlineBegin
1164 // (OfflineStart's body) is new accepted legacy, and OfflineStart is
1165 // retired by an H3 census-ruling removal; offlineTakeSeal is re-frozen
1166 // for Astra's round 2. Three frozen declarations are added, so the seal
1167 // moves; design-plans-and-caps' is checked first.
1168 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1169 t.Fatal(errs)
1170 }
1171 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-moves-offline-precopy.tsv"), &inv, true); err != nil {
1172 t.Fatal(err)
1173 }
1174 seal = "940ed1bba8d911e0f57af83ecac253c77ba5e14dad590258e0ee03ec98ccb818"
1175 // Census overlay ci-speed-activator (amadan #291: CI speed), loaded last,
1176 // after moves-offline-precopy, under census-ruling-ci-speed-activator
1177 // (Paul, as census owner, 2026-10-21, accepted as proposed). Four
1178 // activator timings become package vars with the same values and
1179 // moveprobe gains a link-time grace override; only tests change them.
1180 // ExecBackend.waitRoleCgroupEmpty and
1181 // Service.startAdmitted run in the agent (user carlos), make no root
1182 // decision and are re-frozen at main's class and task with new digests;
1183 // their sites are unchanged. The internal/activator and cmd/moveprobe
1184 // envelopes are re-pinned. Two frozen declarations are added, so the seal
1185 // moves; moves-offline-precopy's is checked first.
1186 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1187 t.Fatal(errs)
1188 }
1189 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-ci-speed-activator.tsv"), &inv, true); err != nil {
1190 t.Fatal(err)
1191 }
1192 seal = "3737ebbd0ee87811839624724e552e0af02f63d70baaa0516a024440d848fdae"
1193 // Census overlay securelisten-337 (amadan #337: edge.SecureUnixListen
1194 // makes its socket owner-only with fchmod before bind instead of setting
1195 // the process umask around it), loaded last, after ci-speed-activator,
1196 // under census-ruling-securelisten-337 (Paul, as census owner,
1197 // 2026-10-21, accepted as proposed). SecureUnixListen in purge_listen_linux.go is new
1198 // accepted legacy at J4 root-input (as pendingDirs.appeared and its
1199 // caller ListenControl): one Lstat of the socket the agent has just
1200 // bound for itself to serve. The internal/edge envelope is re-pinned.
1201 // One frozen declaration is added, so the seal moves;
1202 // ci-speed-activator's is checked first.
1203 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1204 t.Fatal(errs)
1205 }
1206 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-securelisten-337.tsv"), &inv, true); err != nil {
1207 t.Fatal(err)
1208 }
1209 seal = "33a8ff46dd9fcf85664c42c42eaf01585af6c92806cb7830fa8f30fd0950c430"
1210 // Census overlay claims-on-gate-recover (a claims-on box's update gate
1211 // waits 120 s and fails fast; carlos-system-recover defers a refused
1212 // census with no journal open, accepts a service still running the
1213 // signed current or previous router build it was renamed over, retries
1214 // task-level refusals for at most 20 s and names each refusal's check,
1215 // unit, cgroup and exe), loaded last. PROPOSED-claims-on-gate-recover,
1216 // to be asked of the census owner on #280
1217 // (docs/superpowers/notes/census-proposal-claims-on-gate-recover.md).
1218 // Changed authority units re-pinned at their class and task; the
1219 // service reader's reads move into three new units at its class (E2);
1220 // the deleted-exe image proof is a new root read at F,J4, as the
1221 // guard's own image proof. No legacy row; the seal stands.
1222 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claims-on-gate-recover.tsv"), &inv, true); err != nil {
1223 t.Fatal(err)
1224 }
1225 // Census overlay claims-on-gate-recover-merge-main (the branch merged
1226 // with main at 521c6ee9), loaded last: envelope only, internal/host
1227 // re-pinned over both branches' code. The seal stands.
1228 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claims-on-gate-recover-merge-main.tsv"), &inv, true); err != nil {
1229 t.Fatal(err)
1230 }
1231 // Census overlay claim-merge-main (claim-empty-cohort-done merged with
1232 // main after moves-offline, 7af8815), loaded last: envelope only, the
1233 // internal/host re-pin over both branches' code. The seal stands.
1234 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claim-merge-main.tsv"), &inv, true); err != nil {
1235 t.Fatal(err)
1236 }
1237 // Census overlay roster-binding (design-roster-revision-holds.md rev 3
1238 // and section 7: installed state binds to hostactors.BoxBinding, not the
1239 // roster write counter), loaded last. Ruled by platform-d8
1240 // (docs/superpowers/notes/census-proposal-claim-step8-readiness.md,
1241 // "Roster binding"), marked rev3=census-ruling-roster-binding (RULED by platform-d8, 2026-10-20, accepted with conditions, all met). Changed units
1242 // are re-pinned at their existing classes, new units take their callers'
1243 // classes, servingPriorRevision is removed, and claim-ack-refresh's
1244 // productionClaimRoster.Actor row is folded in. It adds no accepted-legacy
1245 // row, so the seal stands.
1246 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-roster-binding.tsv"), &inv, true); err != nil {
1247 t.Fatal(err)
1248 }
1249 // Census overlay claim-merge-main-2 (claim-empty-cohort-done merged with
1250 // main at e0986eab), loaded last: envelope only, internal/host re-pinned
1251 // over both branches' code. The seal stands.
1252 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claim-merge-main-2.tsv"), &inv, true); err != nil {
1253 t.Fatal(err)
1254 }
1255 // Census overlay claim-router-cache (the migration census keeps the
1256 // agent's router update cache, harness G10 re-run 8.2), loaded last:
1257 // envelope only. Ruled by platform-d8, accepted as proposed; the seal
1258 // stands.
1259 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claim-router-cache.tsv"), &inv, true); err != nil {
1260 t.Fatal(err)
1261 }
1262 // Census overlay claim-fresh-install (harness G10, 2026-10-21: the
1263 // unit-shape refusal refused every fresh claim install, which has no
1264 // registry row until its own row write; fix round 2 after Astra on
1265 // 4dd4c436), loaded last. Only the installation's own work
1266 // (Reconciler.installWithWork's marked selection) may go on without a
1267 // row, checked as an empty route for the host; claimUnitShapePolicy's
1268 // reads move to claimUnitShapeCheck at the same class, and
1269 // installWithWork is re-pinned at its own. Marked
1270 // rev3=PROPOSED-claim-fresh-install; envelopes re-pinned; the seal stands.
1271 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claim-fresh-install.tsv"), &inv, true); err != nil {
1272 t.Fatal(err)
1273 }
1274 // Census overlay claim-merge-main-3 (claim-empty-cohort-done merged with
1275 // main at 6da1cd0f), loaded last: envelope only, internal/host and
1276 // internal/hostops re-pinned over both branches' code. The seal stands.
1277 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claim-merge-main-3.tsv"), &inv, true); err != nil {
1278 t.Fatal(err)
1279 }
1280 // Census overlay claim-merge-main-4 (claim-empty-cohort-done merged with
1281 // main at abcdd577, which carries claims-on-gate-recover), loaded last:
1282 // the three generation-census units both branches changed are re-pinned
1283 // at E2 over the merged code, carrying both bases; internal/host
1284 // re-pinned. The seal stands.
1285 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-claim-merge-main-4.tsv"), &inv, true); err != nil {
1286 t.Fatal(err)
1287 }
1288 // Census overlay design-fleet-internal-engines (amadan #335 plan 1: the
1289 // test-only internal/sim/engines simulation package), loaded last, after
1290 // claim-merge-main-4. RULED as census-ruling-design-fleet-internal-engines
1291 // (Paul, as census owner, 2026-10-21), accepted as proposed
1292 // (docs/superpowers/notes/census-proposal-design-fleet-internal-engines.md).
1293 // No production code changes. Its mutation harness mutate.sh is
1294 // classified as internal/sim/hostlife/mutate.sh is: accepted legacy, a
1295 // test harness pinned by the conservative external envelope, run by a
1296 // developer or CI and never by root. The internal/sim/engines envelope is
1297 // pinned. One frozen declaration is added, so the seal moves;
1298 // securelisten-337's, which every later overlay left standing, is checked
1299 // first.
1300 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1301 t.Fatal(errs)
1302 }
1303 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-design-fleet-internal-engines.tsv"), &inv, true); err != nil {
1304 t.Fatal(err)
1305 }
1306 seal = "ca73eb766db03c4820076a28e84bbf15b61135a284294feaea78ae14b9b55071"
1307 // Census overlay email-signin (the console's email sign-in: an address
1308 // with no Keymail mailbox signs in by an emailed link and code, an email
1309 // session re-confirms by email, and the Apps-inbox confirmation link is
1310 // retired), loaded last, after design-fleet-internal-engines. Proposed; every row
1311 // carries rev3=PROPOSED-email-signin and the ruling is asked of the census
1312 // owner on #280 (docs/superpowers/notes/census-proposal-email-signin.md).
1313 // Every unit runs in the console (cmd/console serve under
1314 // console.service, user carlos-console), and the root carlos binary links
1315 // neither internal/console nor internal/mail
1316 // (TestRootBinaryLinksNoConsoleOrMail). Ten changed legacy units are
1317 // re-frozen at their main disposition, eighteen new ones are accepted
1318 // legacy at their siblings' class (console SQL on its own database,
1319 // crypto/rand for an in-memory key, request URL query reads, embedded
1320 // templates), and handleConfirm, TakePendingAction and CreateSession,
1321 // which read nothing now, are retired by H3 removals. Frozen declarations
1322 // are added, so the seal moves; design-fleet-internal-engines' is checked first.
1323 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1324 t.Fatal(errs)
1325 }
1326 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-email-signin.tsv"), &inv, true); err != nil {
1327 t.Fatal(err)
1328 }
1329 seal = "b25dfda5a68d2183af759b42398f79bb471749d46e68d267545647d1a2e6046b"
1330 // Census overlay plans-2-box-limits (boxes read account limits behind the
1331 // console's plans marker; the activator's idle hook), loaded last, after
1332 // plans-2-box-limits. PROPOSED-plans-2-box-limits, asked of the census owner on
1333 // #280. The new agent units read routes and two bucket objects and only
1334 // narrow idle windows. Frozen declarations are added, so the seal moves;
1335 // email-signin's is checked first.
1336 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1337 t.Fatal(errs)
1338 }
1339 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-plans-2-box-limits.tsv"), &inv, true); err != nil {
1340 t.Fatal(err)
1341 }
1342 seal = "d044224434b0b375599a076e573c7c4164e3777ae6295abf95d9d9b9ed69e482"
1343 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1344 t.Fatal(errs)
1345 }
1346 // Census overlay console-brand-name (the console's chrome and welcome name
1347 // the deployment from CARLOS_CONSOLE_NAME), loaded last, after
1348 // plans-2-box-limits. Proposed; ruling asked of the census owner on #280. Three
1349 // templates change text only; envelopes re-pinned; no read is added. The
1350 // seal moves because the three templates' legacy declarations are
1351 // re-pinned.
1352 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-console-brand-name.tsv"), &inv, true); err != nil {
1353 t.Fatal(err)
1354 }
1355 seal = "78e18e222a8178bbe16b638c5e3811b8f64c4c2664ffd6649eb4273e72fae24e"
1356 // Census overlay db-region-forward-1 (db region forward plan 1: the box
1357 // side and the wire, dark), loaded last, after console-brand-name.
1358 // census-ruling-db-region-forward-1: accepted in full by the census
1359 // owner on #280, 2026-10-22
1360 // (docs/superpowers/notes/census-proposal-db-region-forward-1.md).
1361 // db.go runQueryContext is retired by an H3 removal; its body is
1362 // internal/dbquery RunContext, accepted legacy at the same J4 footing
1363 // with both callers named; the agent's db-reads units are accepted
1364 // legacy at J1 and J4, the worker's at J4, the probe is diagnostic, and
1365 // the two carlos-dbread units join as external units. Frozen
1366 // declarations are added, so the seal moves; console-brand-name's is
1367 // checked first.
1368 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1369 t.Fatal(errs)
1370 }
1371 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-db-region-forward-1.tsv"), &inv, true); err != nil {
1372 t.Fatal(err)
1373 }
1374 seal = "fc73854854f9e75d122ebd0eacf330d126201aa9d5c4295c634cc1c204a9168d"
1375 // Census overlay s3-change-index (amadan #336: the deployment stores bump
1376 // control/changes.json after each mutation; readers armed by
1377 // CARLOS_CHANGE_INDEX=read read records through a record view snapshot,
1378 // gate unchanged reads up to the backstop's age and run scoped passes),
1379 // loaded last, after db-region-forward-1. Proposed; rows carry
1380 // rev3=PROPOSED-s3-change-index and the ruling,
1381 // census-ruling-s3-change-index, is asked of the census owner on #280.
1382 // The units run in the agent (user carlos) or the console, or are store
1383 // methods shared as their siblings; root's carlos adopt reaches only
1384 // PassFilter's pointer gate, which it never arms. Four frozen units that
1385 // now read nothing (DirStore.Put, PutFrom and DeleteIfMatch, whose bodies
1386 // moved into raw methods, and telemetrySwitches) are retired by H3
1387 // removals. Frozen declarations are added, so the seal moves;
1388 // db-region-forward-1's is checked first.
1389 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1390 t.Fatal(errs)
1391 }
1392 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-s3-change-index.tsv"), &inv, true); err != nil {
1393 t.Fatal(err)
1394 }
1395 seal = "e7c6062c0e1d29833edda7bd9953282a52edbb45ddbe3cd00a447ec5d61d9b8a"
1396 // Census overlay db-region-forward-2 (db region forward plan 2: the
1397 // console and CLI for carlos db query and query --at), loaded last,
1398 // after s3-change-index. census-ruling-db-region-forward-2: accepted in
1399 // full by the census owner on #280, 2026-10-22
1400 // (docs/superpowers/notes/census-proposal-db-region-forward-2.md). The
1401 // CLI's read of a refused reads-route answer (dbforward.go
1402 // dbQueryForward) and the console's read of the request body to EOF
1403 // (readDBReadBody) are accepted legacy at J4 as main's units are;
1404 // cmd/console serve, NewServer, dbdoor doorError and the
1405 // deployment-buckets module are re-frozen at main's disposition with
1406 // this branch's change appended. Frozen declarations change, so the
1407 // seal moves; s3-change-index's is checked first.
1408 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1409 t.Fatal(errs)
1410 }
1411 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-db-region-forward-2.tsv"), &inv, true); err != nil {
1412 t.Fatal(err)
1413 }
1414 seal = "bd4cc1909225cd574c2c609f0cd02177076ddb5c1476d9cf5e178be05acccae1"
1415 // Census overlay plans-3a-creation-caps (the console refuses creates past
1416 // an account's plan limits), loaded last, after db-region-forward-2.
1417 // PROPOSED-plans-3a-creation-caps, asked of the census owner on #280. Two
1418 // new console store counts, handleAPICreateApp re-frozen, the console
1419 // envelope re-pinned. Frozen declarations are added, so the seal moves;
1420 // db-region-forward-2's is checked first.
1421 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1422 t.Fatal(errs)
1423 }
1424 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-plans-3a-creation-caps.tsv"), &inv, true); err != nil {
1425 t.Fatal(err)
1426 }
1427 seal = "dc7dbb4f562fe31556e7ed1e09fcfb380f551b45a444e94e72662f0b202c605b"
1428 // Census overlay db-region-forward-copy (Luna's approved copy for the
1429 // forwarded db read, 2026-10-23), loaded last, after
1430 // plans-3a-creation-caps. Envelope re-pins only (. and internal/console:
1431 // changed sentence constants); no read is added, removed or changed, so
1432 // the seal does not move. census-ruling-db-region-forward-copy, accepted
1433 // on #280, 2026-10-23
1434 // (docs/superpowers/notes/census-proposal-db-region-forward-copy.md).
1435 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1436 t.Fatal(errs)
1437 }
1438 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-db-region-forward-copy.tsv"), &inv, true); err != nil {
1439 t.Fatal(err)
1440 }
1441 // Census overlay static-redirects (static sites honour a _redirects
1442 // file), loaded last, after db-region-forward-copy. Proposed; ruling
1443 // asked of the census owner on #280. PackDir and staticSite.serveTree are
1444 // re-frozen; staticSite.serveFile takes serveTree's Open, and
1445 // staticSite.loadRedirects reads the tree's _redirects once per version
1446 // swap. Every read stays inside the extracted, verified tree. Frozen
1447 // declarations are added, so the seal moves; plans-3a-creation-caps's
1448 // (unchanged by db-region-forward-copy) is checked first.
1449 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1450 t.Fatal(errs)
1451 }
1452 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-static-redirects.tsv"), &inv, true); err != nil {
1453 t.Fatal(err)
1454 }
1455 seal = "65857c29501dc7676f52921bea79d08217542ecb1d775c67d20a3460c851d831"
1456 // Census overlay db-region-forward-3 (db region forward plan 3: carlos
1457 // db pull and pull --at for an instance in another region), loaded last,
1458 // after static-redirects. census-ruling-db-region-forward-3, accepted in
1459 // full by the census owner on #280, 2026-10-23
1460 // (docs/superpowers/notes/census-proposal-db-region-forward-3.md). The
1461 // worker's pull units (holdAndSend, verifyLTX) are accepted legacy at J4
1462 // inside its sandbox, the CLI's (dbPullForward, fileSink.chunk,
1463 // openDBPull) at J4 as the person, RestoreLocal's context-checked reads
1464 // (ctxReadCloser.Read, round 1) at J4 as downloaded.Read is;
1465 // ServeWorker and dbQueryForward are re-frozen with the pull appended. Frozen declarations are added, so
1466 // the seal moves; static-redirects' is checked first.
1467 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1468 t.Fatal(errs)
1469 }
1470 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-db-region-forward-3.tsv"), &inv, true); err != nil {
1471 t.Fatal(err)
1472 }
1473 seal = "79cb56b4c7d3a8e155d1eff1902715d818fcf4c09b1d8a82921c413b116938a9"
1474 // Census overlay wake-latency-1 (wake latency pass 1), loaded last,
1475 // after db-region-forward-3. census-ruling-wake-latency-1, accepted as
1476 // proposed by the census owner on #280, 2026-10-24
1477 // (docs/superpowers/notes/census-proposal-wake-latency-1.md). doWake,
1478 // wake and startUnitAt are re-frozen with per-step wake timing appended:
1479 // clock reads and journal lines, no read added. The internal/activator
1480 // and internal/instancectl envelopes are re-pinned. Frozen declarations
1481 // are added, so the seal moves; db-region-forward-3's is checked first.
1482 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1483 t.Fatal(errs)
1484 }
1485 if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-wake-latency-1.tsv"), &inv, true); err != nil {
1486 t.Fatal(err)
1487 }
1488 seal = "09e20ea4bbc534710334e632e903878656dabfb5817d4d96c6e7c56508172148"
1489 return rootReadManifest(t, root, inv, seal, last)
1490}
1491
1492func TestPlan14RootReadCensusRejectsDrift(t *testing.T) {
1493 entry := rootReadEntry{File: "internal/host/new.go", Unit: "rootPass", Kinds: "registry:Caps@10", Digest: strings.Repeat("a", 64)}
1494 base := rootReadInventory{Entries: map[string]classifiedRootRead{}, Coverage: map[string]string{}}
1495 if got := compareRootReads(rootReadScan{Entries: []rootReadEntry{entry}}, base); len(got) == 0 {
1496 t.Fatal("unclassified read accepted")
1497 }
1498 base.Entries[entry.File+":"+entry.Unit] = classifiedRootRead{rootReadEntry: entry, Class: "authority", Task: "E4", Basis: "root-route"}
1499 if got := compareRootReads(rootReadScan{Entries: []rootReadEntry{entry}}, base); len(got) != 0 {
1500 t.Fatal(got)
1501 }
1502 for _, what := range []string{"body", "site", "removed", "source"} {
1503 t.Run(what, func(t *testing.T) {
1504 changed := entry
1505 scan := rootReadScan{Entries: []rootReadEntry{changed}}
1506 switch what {
1507 case "body":
1508 scan.Entries[0].Digest = strings.Repeat("b", 64)
1509 case "site":
1510 scan.Entries[0].Kinds += ";registry:Unit@25"
1511 case "removed":
1512 scan.Entries = nil
1513 case "source":
1514 scan.Coverage = map[string]string{"internal/host": "new primitive"}
1515 }
1516 if got := compareRootReads(scan, base); len(got) == 0 {
1517 t.Fatal("changed read accepted")
1518 }
1519 })
1520 }
1521}
1522
1523// Census ruling zddr3: H3 owns a removal only with a census-ruling basis,
1524// and never owns an authority row.
1525func TestPlan14RemovedH3NeedsCensusRuling(t *testing.T) {
1526 for name, tc := range map[string]struct {
1527 row string
1528 load bool
1529 }{
1530 "ruling": {"@removed\tinternal/cgroup/cgroup.go\tManager.startIn\tH3\tcensus-ruling-zddr3: placement moved into the shim.", true},
1531 "no ruling": {"@removed\tinternal/cgroup/cgroup.go\tManager.startIn\tH3\tplacement moved into the shim.", false},
1532 "inner": {"@removed\tinternal/cgroup/cgroup.go\tManager.startIn\tH3\tsee census-ruling-zddr3", false},
1533 "authority": {"internal/cgroup/cgroup.go\tManager.startIn\tauthority\tH3\tcensus-ruling-zddr3\tfile:Open@1\t" + strings.Repeat("a", 64), false},
1534 "other owner": {"@removed\tinternal/cgroup/cgroup.go\tManager.startIn\tH4\tcensus-ruling-zddr3: placement moved into the shim.", false},
1535 } {
1536 t.Run(name, func(t *testing.T) {
1537 path := filepath.Join(t.TempDir(), "overlay.tsv")
1538 if err := os.WriteFile(path, []byte(tc.row+"\n"), 0o644); err != nil {
1539 t.Fatal(err)
1540 }
1541 inv := rootReadInventory{Entries: map[string]classifiedRootRead{}, Coverage: map[string]string{}}
1542 err := loadRootReadInventory(path, &inv, true)
1543 if tc.load && err != nil {
1544 t.Fatal(err)
1545 }
1546 if !tc.load && err == nil {
1547 t.Fatal("row loaded without a census-ruling basis or kept owner")
1548 }
1549 })
1550 }
1551}
1552
1553// Census ruling zddr3: an H3 census-ruling removal retires a still-declared
1554// unit only while the scan finds no read in it. Every other removal of a
1555// still-declared unit fails as before, and a retired unit that reads again
1556// is an unclassified root read that needs a fresh classification.
1557func TestPlan14RetiredDeclarationNeedsNoReads(t *testing.T) {
1558 e := classifiedRootRead{rootReadEntry: rootReadEntry{File: "internal/cgroup/cgroup.go", Unit: "Manager.startIn", Kinds: "file:Open@40", Digest: strings.Repeat("a", 64)}, Class: "legacy", Task: "accepted-legacy", Basis: "accepted-legacy;rev3=J1;basis=placement"}
1559 key := e.File + ":" + e.Unit
1560 body := strings.Repeat("b", 64)
1561 inv := rootReadInventory{Entries: map[string]classifiedRootRead{}, Coverage: map[string]string{}, Legacy: map[string]bool{rootReadLegacyFingerprint(e): true}, Frozen: map[string]classifiedRootRead{key: e}, Removed: map[string]string{key: "H3;census-ruling-zddr3: no longer reads"}}
1562 present := []string{"removed legacy declaration still present " + key}
1563
1564 // Still declared, no reads: retired.
1565 quiet := rootReadScan{Declarations: map[string]string{key: body}}
1566 if errs := checkRootReadDeclarations(quiet, inv); len(errs) != 0 {
1567 t.Fatal(errs)
1568 }
1569 if errs := compareRootReads(quiet, inv); len(errs) != 0 {
1570 t.Fatal(errs)
1571 }
1572
1573 // (a) Still declared and still reading: the census-ruling basis does not help.
1574 reading := rootReadScan{Entries: []rootReadEntry{{File: e.File, Unit: e.Unit, Kinds: "file:Open@40", Digest: body}}, Declarations: map[string]string{key: body}}
1575 if errs := checkRootReadDeclarations(reading, inv); !reflect.DeepEqual(errs, present) {
1576 t.Fatalf("retired unit with reads: %v", errs)
1577 }
1578 // Re-reading: the retired entry gives no silent pass.
1579 if errs := compareRootReads(reading, inv); !reflect.DeepEqual(errs, []string{"unclassified root read " + key + " file:Open@40"}) {
1580 t.Fatalf("retired unit reading again: %v", errs)
1581 }
1582
1583 // (b) Any removal that is not H3 with a census-ruling basis fails as before.
1584 for _, removal := range []string{"C; removed obsolete delegate after reviewed root authority conversion", "E4;census-ruling-zddr3: no longer reads", "H3;no longer reads", "H3; census-ruling-zddr3: no longer reads"} {
1585 inv.Removed[key] = removal
1586 if errs := checkRootReadDeclarations(quiet, inv); !reflect.DeepEqual(errs, present) {
1587 t.Fatalf("%q retired a still-declared unit: %v", removal, errs)
1588 }
1589 }
1590
1591 // Still classified: fails even with no reads.
1592 inv.Removed[key] = "H3;census-ruling-zddr3: no longer reads"
1593 inv.Entries[key] = e
1594 if errs := checkRootReadDeclarations(quiet, inv); !reflect.DeepEqual(errs, present) {
1595 t.Fatalf("classified unit retired: %v", errs)
1596 }
1597}
1598
1599func TestPlan14LegacyFreezeRequiresReclassification(t *testing.T) {
1600 e := classifiedRootRead{rootReadEntry: rootReadEntry{File: "internal/host/old.go", Unit: "oldRootRead", Kinds: "registry:Unit@10", Digest: strings.Repeat("a", 64)}, Class: "legacy", Task: "accepted-legacy", Basis: "accepted-legacy;rev3=J1;basis=root-route"}
1601 key := e.File + ":" + e.Unit
1602 inv := rootReadInventory{Entries: map[string]classifiedRootRead{key: e}, Legacy: map[string]bool{rootReadLegacyFingerprint(e): true}}
1603 seal := rootReadLegacySeal(inv)
1604 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1605 t.Fatal(errs)
1606 }
1607 for _, change := range []string{"body", "site", "basis", "task", "new"} {
1608 t.Run(change, func(t *testing.T) {
1609 changed := e
1610 switch change {
1611 case "body":
1612 changed.Digest = strings.Repeat("b", 64)
1613 case "site":
1614 changed.Kinds = "registry:Caps@10"
1615 case "basis":
1616 changed.Basis += ";excuse"
1617 case "task":
1618 changed.Task = "J4"
1619 case "new":
1620 changed.File = "internal/host/new.go"
1621 }
1622 inv.Entries[key] = changed
1623 // Even a fully refreshed source inventory must fail while legacy.
1624 if errs := compareRootReads(rootReadScan{Entries: []rootReadEntry{changed.rootReadEntry}}, rootReadInventory{Entries: map[string]classifiedRootRead{changed.File + ":" + changed.Unit: changed}}); len(errs) != 0 {
1625 t.Fatal(errs)
1626 }
1627 if errs := checkRootReadLegacy(inv, seal); len(errs) == 0 {
1628 t.Fatal("changed legacy accepted")
1629 }
1630 inv.Legacy[rootReadLegacyFingerprint(changed)] = true
1631 if errs := checkRootReadLegacy(inv, seal); len(errs) == 0 {
1632 t.Fatal("refreshed freeze accepted")
1633 }
1634 delete(inv.Legacy, rootReadLegacyFingerprint(changed))
1635 for _, class := range []string{"authority", "hint", "diagnostic"} {
1636 promoted := changed
1637 promoted.Class = class
1638 promoted.Task = "E4"
1639 promoted.Basis = "reviewed independent grant binding"
1640 inv.Entries[key] = promoted
1641 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1642 t.Fatal(errs)
1643 }
1644 }
1645 inv.Entries[key] = e
1646 })
1647 }
1648}
1649
1650// Frozen identities survive removal of every recognized input primitive.
1651func checkRootReadDeclarations(scan rootReadScan, inv rootReadInventory) []string {
1652 var errs []string
1653 for key, frozen := range inv.Frozen {
1654 digest, exists := scan.Declarations[key]
1655 current, classified := inv.Entries[key]
1656 removal := inv.Removed[key]
1657 if removal != "" {
1658 // Census ruling zddr3: an H3 census-ruling removal may retire a
1659 // unit that is still declared only when this scan finds no read in
1660 // it. The basis text is never evidence; the scan is.
1661 retired := exists && strings.HasPrefix(removal, "H3;census-ruling-") && !rootReadScanned(scan, key)
1662 if (exists && !retired) || classified {
1663 errs = append(errs, "removed legacy declaration still present "+key)
1664 }
1665 continue
1666 }
1667 if !exists || !classified {
1668 errs = append(errs, "legacy declaration needs explicit reclassification or removal "+key)
1669 continue
1670 }
1671 if current.Class == "legacy" && (digest != frozen.Digest || rootReadLegacyFingerprint(current) != rootReadLegacyFingerprint(frozen)) {
1672 errs = append(errs, "changed legacy declaration "+key)
1673 }
1674 if current.Class != "legacy" && current.Digest != digest {
1675 errs = append(errs, "changed reclassified declaration "+key)
1676 }
1677 }
1678 for key, removal := range inv.Removed {
1679 if strings.HasSuffix(removal, ";census-ruling-J4") || strings.HasSuffix(removal, ";census-ruling-activation-tools-removal") {
1680 if _, exists := scan.Declarations[key]; exists || inv.Entries[key].Class != "" {
1681 errs = append(errs, "removed declaration still present "+key)
1682 }
1683 continue
1684 }
1685 if _, ok := inv.Frozen[key]; !ok {
1686 errs = append(errs, "removal of unfrozen declaration "+key)
1687 }
1688 }
1689 sort.Strings(errs)
1690 return errs
1691}
1692
1693// rootReadScanned reports whether the scan has a read entry for the unit.
1694func rootReadScanned(scan rootReadScan, key string) bool {
1695 for _, e := range scan.Entries {
1696 if e.File+":"+e.Unit == key {
1697 return true
1698 }
1699 }
1700 return false
1701}
1702
1703func TestPlan14J4RemovalRequiresAbsentDeclaration(t *testing.T) {
1704 key := "root.go:dead"
1705 scan := rootReadScan{Declarations: map[string]string{}}
1706 inv := rootReadInventory{Entries: map[string]classifiedRootRead{}, Removed: map[string]string{key: "E2;census-ruling-J4"}}
1707 if errs := checkRootReadDeclarations(scan, inv); len(errs) != 0 {
1708 t.Fatal(errs)
1709 }
1710 scan.Declarations[key] = "digest"
1711 if len(checkRootReadDeclarations(scan, inv)) == 0 {
1712 t.Fatal("live removed declaration accepted")
1713 }
1714 delete(scan.Declarations, key)
1715 inv.Entries[key] = classifiedRootRead{Class: "authority"}
1716 if len(checkRootReadDeclarations(scan, inv)) == 0 {
1717 t.Fatal("retained removed row accepted")
1718 }
1719 delete(inv.Entries, key)
1720 inv.Removed[key] = "E2;unruled"
1721 if len(checkRootReadDeclarations(scan, inv)) == 0 {
1722 t.Fatal("unruled removal accepted")
1723 }
1724}
1725
1726func TestPlan14ActivationToolsRemovalRequiresAbsentDeclaration(t *testing.T) {
1727 key := "root.go:dead"
1728 scan := rootReadScan{Declarations: map[string]string{}}
1729 inv := rootReadInventory{Entries: map[string]classifiedRootRead{}, Removed: map[string]string{key: "G,J4;census-ruling-activation-tools-removal"}}
1730 if errs := checkRootReadDeclarations(scan, inv); len(errs) != 0 {
1731 t.Fatal(errs)
1732 }
1733 scan.Declarations[key] = "digest"
1734 if len(checkRootReadDeclarations(scan, inv)) == 0 {
1735 t.Fatal("live removed declaration accepted")
1736 }
1737 delete(scan.Declarations, key)
1738 inv.Entries[key] = classifiedRootRead{Class: "authority"}
1739 if len(checkRootReadDeclarations(scan, inv)) == 0 {
1740 t.Fatal("retained removed row accepted")
1741 }
1742 delete(inv.Entries, key)
1743 inv.Removed[key] = "E2;unruled"
1744 if len(checkRootReadDeclarations(scan, inv)) == 0 {
1745 t.Fatal("unruled removal accepted")
1746 }
1747}
1748
1749// rootReadChainManifest lists the overlays loaded after the chain written
1750// out in rootReadChain, in order, one per line: the overlay's file name
1751// under testdata and the seal it leaves. census-propose appends to it
1752// (rootReadPropose), so a new overlay needs no edit to this file.
1753const rootReadChainManifest = "internal/provision/testdata/plan14-root-reads-chain.tsv"
1754
1755type rootReadChainLink struct{ File, Seal string }
1756
1757func readRootReadChainManifest(path string) ([]rootReadChainLink, error) {
1758 raw, err := os.ReadFile(path)
1759 if err != nil {
1760 return nil, err
1761 }
1762 var links []rootReadChainLink
1763 for i, line := range strings.Split(strings.TrimSpace(string(raw)), "\n") {
1764 if line == "" || strings.HasPrefix(line, "#") {
1765 continue
1766 }
1767 col := strings.Split(line, "\t")
1768 if len(col) != 2 || len(col[1]) != 64 || strings.ContainsAny(col[0], "/\\") {
1769 return nil, fmt.Errorf("%s:%d: want <overlay file name>\\t<seal>", path, i+1)
1770 }
1771 if _, err := hex.DecodeString(col[1]); err != nil {
1772 return nil, fmt.Errorf("%s:%d: seal: %v", path, i+1, err)
1773 }
1774 links = append(links, rootReadChainLink{col[0], col[1]})
1775 }
1776 return links, nil
1777}
1778
1779// rootReadManifest loads the manifest's overlays onto inv, each after the
1780// seal before it is checked, exactly as rootReadChain loads its own. A
1781// non-empty last leaves that overlay out, and only when it is the last.
1782func rootReadManifest(t testing.TB, root string, inv rootReadInventory, seal, last string) (rootReadInventory, string) {
1783 t.Helper()
1784 links, err := readRootReadChainManifest(filepath.Join(root, rootReadChainManifest))
1785 if err != nil {
1786 t.Fatal(err)
1787 }
1788 for i, l := range links {
1789 if last != "" && l.File == last {
1790 if i != len(links)-1 {
1791 t.Fatalf("%s is not the last overlay in %s: propose under a new name", last, rootReadChainManifest)
1792 }
1793 break
1794 }
1795 if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 {
1796 t.Fatalf("before overlay %s: %v", l.File, errs)
1797 }
1798 if err := loadRootReadInventory(filepath.Join(root, "internal/provision/testdata", l.File), &inv, true); err != nil {
1799 t.Fatal(err)
1800 }
1801 seal = l.Seal
1802 }
1803 return inv, seal
1804}
1805