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 "fmt"
5 "go/ast"
6 "go/parser"
7 "go/token"
8 "go/types"
9 "io/fs"
10 "os"
11 "path/filepath"
12 "sort"
13 "strings"
14 "sync"
15 "testing"
16
17 "golang.org/x/tools/go/packages"
18)
19
20type inputFamily struct {
21 Owner string
22 Hostile, Rename, Erasure, Retry, Positive string
23}
24
25// Mixed declarations retain every protected effect: their family is the sorted
26// product of these named A-G families, never the first matching owner alone.
27// Empty witness slots are explicit acceptance gaps and fail coverage.
28var inputFamilies = map[string]inputFamily{
29 "A": {"A", "TestPlan14HostileOwnership", "TestPlan14RenameKeepsDescriptor", "TestPlan14RemoveCapability", "TestPlan14DescendRetriesEveryAncestorSync", "TestPlan14AuthorityFilePrivateAncestors"},
30 "B": {"B", "TestPlan14ForgedHealthyCannotAdmit", "TestPlan14ForgedHealthyCannotAdmit", "TestPlan14HealthyErasureRequiresProof", "TestPlan14HealthyDuplicateRetryDurability", "TestPlan14ForgedHealthyCannotAdmit"},
31 "B2": {"B", "TestPlan14ForgedHealthyCannotBind", "TestPlan14ForgedHealthyCannotBind", "TestPlan14HealthyErasureRequiresProof", "TestPlan14HealthyDuplicateRetryDurability", "TestPlan14ForgedHealthyCannotAdmit"},
32 "B3": {"B", "TestPlan14ProofBindingProvenance", "TestPlan14ProofBindingProvenance", "TestPlan14ProofBindingProvenance", "TestPlan14HealthyDuplicateRetryDurability", "TestPlan14AdoptionCanonicalReadiness"},
33 "B4": {"B", "TestPlan14ForgedHealthyCannotAdmit", "TestPlan14ForgedHealthyCannotAdmit", "TestPlan14HealthyErasureRequiresProof", "TestPlan14HealthyDuplicateRetryDurability", "TestPlan14HealthyDuplicateRetryDurability"},
34 "C": {"C", "TestPlan14RootFences", "TestPlan14RootFences", "TestPlan14RootFences", "TestPlan14InventoryProcessCrash", "TestPlan14HeldRevalidatesCanonicalBindingUnderGuard"},
35 "D": {"D", "TestPlan14ExecutionHostileCensusRootRunner", "TestPlan14ExecutionServingRequiresRootSettlement", "TestPlan14ExecutionUpdateExclusion", "TestPlan14ExecutionRecoveryAfterProcessCrash", "TestPlan14ExecutionProductionSettlement"},
36 "E1": {"E", "TestPlan14RootHistoryProductionPass", "TestPlan14RootHistoryLegacyTampering", "TestPlan14RootHistoryLegacyTampering", "TestPlan14HistoryRetirementProcessCrash", "TestPlan14RootHistoryProductionPass"},
37 "E2": {"E", "TestPlan14GenerationPrivateJournalRootRunner", "TestPlan14GenerationPayloadPhysicalRootRunner", "TestPlan14GenerationDeletionCannotUnpin", "TestPlan14GenerationCompletenessDurability", "TestPlan14GenerationInstalledUnitRootRunner"},
38 "E3": {"E", "TestPlan14SwapFailureHostileRootRunner", "TestPlan14SwapFailureSurvivesLegacyTampering", "TestPlan14SwapFailureSurvivesLegacyTampering", "TestPlan14SwapFailureHostileRootRunner", "TestPlan14SwapFailureVerifiedRetry"},
39 "F": {"F", "TestPlan14RootFloorCrashOrderingRootRunner", "TestPlan14FloorRiseWithoutPlatformUpdateRootRunner", "TestPlan14RootFloorPublicDenySurvivesPrivateLoss", "TestPlan14RootFloorSyscallCrashOrdering", "TestPlan14RootFloorBootSelectors"},
40 "G": {"G", "TestPlan14RootMigrationHistoricEvidence", "TestPlan14RootMigrationHistoricRootRunner", "TestPlan14RootMigrationHistoricRootRunner", "TestPlan14RootMigrationCrashResume", "TestPlan14RootMigrationBootstrapRootRunner"},
41}
42
43func inputFamilyFor(e classifiedRootRead) ([]string, error) {
44 var names []string
45 seen := map[string]bool{}
46 for _, owner := range strings.Split(e.Task, ",") {
47 if owner == "J1" || owner == "J2" || owner == "J3" || owner == "J4" || owner == "E4" {
48 continue
49 }
50 family, ok := inputFamilies[owner]
51 if !ok {
52 return nil, fmt.Errorf("unknown family %q", owner)
53 }
54 if len(family.Owner) != 1 || family.Owner[0] < 'A' || family.Owner[0] > 'G' {
55 return nil, fmt.Errorf("family %s has no A-G owner", owner)
56 }
57 if !seen[owner] {
58 names = append(names, owner)
59 seen[owner] = true
60 }
61 }
62 if len(names) == 0 {
63 return nil, fmt.Errorf("no A-G family")
64 }
65 sort.Strings(names)
66 return names, nil
67}
68
69func inputInventory(t *testing.T) rootReadInventory {
70 t.Helper()
71 inv := rootReadInventory{Entries: map[string]classifiedRootRead{}, Coverage: map[string]string{}}
72 // Use the very same ordered overlay list as the legacy-seal test.
73 f, err := parser.ParseFile(token.NewFileSet(), "plan14_p3_census_test.go", nil, 0)
74 if err != nil {
75 t.Fatal(err)
76 }
77 var paths []string
78 ast.Inspect(f, func(n ast.Node) bool {
79 if s, ok := n.(*ast.BasicLit); ok && s.Kind == token.STRING {
80 name := strings.Trim(s.Value, "\"")
81 if strings.HasPrefix(name, "plan14-root-reads") && strings.HasSuffix(name, ".tsv") && !strings.Contains(name, "/") {
82 paths = append(paths, name)
83 }
84 }
85 return true
86 })
87 seen := map[string]bool{}
88 for _, name := range paths {
89 if seen[name] {
90 continue
91 }
92 seen[name] = true
93 if err := loadRootReadInventory(filepath.Join("testdata", name), &inv, len(seen) > 1); err != nil {
94 t.Fatal(err)
95 }
96 }
97 if len(seen) < 21 {
98 t.Fatal("missing production overlays")
99 }
100 return inv
101}
102
103func inputTests(root string) (map[string]bool, error) {
104 out := map[string]bool{}
105 err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
106 if err != nil {
107 return err
108 }
109 if d.IsDir() && path != root && (strings.HasPrefix(d.Name(), ".") || d.Name() == "testdata") {
110 return filepath.SkipDir
111 }
112 if d.IsDir() || !strings.HasSuffix(path, "_test.go") {
113 return nil
114 }
115 f, err := parser.ParseFile(token.NewFileSet(), path, nil, 0)
116 if err != nil {
117 return err
118 }
119 for _, d := range f.Decls {
120 if fn, ok := d.(*ast.FuncDecl); ok && fn.Recv == nil && strings.HasPrefix(fn.Name.Name, "Test") && fn.Type.Params.NumFields() == 1 {
121 out[fn.Name.Name] = true
122 }
123 }
124 return nil
125 })
126 return out, err
127}
128
129// This is a conservative, typed production call/reference graph. Function values
130// count as possible calls; interface dispatch includes only implementing methods.
131// Type/var declarations use references (not imaginary calls). Tests never enter
132// the graph. Every accepted row records its reachable immediate predecessor.
133func inputCallers(root string) (map[string]string, error) {
134 // Each platform's load type-checks the whole module (most of this
135 // test's time), and the three are independent, so they run side by
136 // side. The merge below still takes them in this fixed order, so a key
137 // reached on several platforms records the same caller as before.
138 platforms := []string{"linux", "darwin", "windows"}
139 loaded := make([]map[string]string, len(platforms))
140 errs := make([]error, len(platforms))
141 var wg sync.WaitGroup
142 for i, platform := range platforms {
143 wg.Go(func() { loaded[i], errs[i] = inputPlatformCallers(root, platform) })
144 }
145 wg.Wait()
146 out := map[string]string{}
147 for i, platform := range platforms {
148 callers, err := loaded[i], errs[i]
149 if err != nil {
150 return nil, err
151 }
152 for key, caller := range callers {
153 if out[key] == "" {
154 out[key] = platform + ":" + caller
155 }
156 }
157 }
158 return out, nil
159}
160func inputPlatformCallers(root, platform string) (map[string]string, error) {
161 cfg := &packages.Config{Dir: root, Mode: packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | packages.NeedSyntax | packages.NeedTypes | packages.NeedTypesInfo | packages.NeedImports, Env: append(os.Environ(), "GOOS="+platform, "GOARCH=amd64", "CGO_ENABLED=0")}
162 pkgs, err := packages.Load(cfg, "./...")
163 if err != nil {
164 return nil, err
165 }
166 if packages.PrintErrors(pkgs) > 0 {
167 return nil, fmt.Errorf("production package loading failed")
168 }
169 type decl struct {
170 key string
171 node ast.Node
172 pkg *packages.Package
173 }
174 var decls []decl
175 objects := map[types.Object]string{}
176 methods := map[string][]*types.Func{}
177 graph := map[string]map[string]bool{}
178 add := func(a, b string) {
179 if a == "" || b == "" || a == b {
180 return
181 }
182 if graph[a] == nil {
183 graph[a] = map[string]bool{}
184 }
185 graph[a][b] = true
186 }
187 for _, p := range pkgs {
188 for _, f := range p.Syntax {
189 file, _ := filepath.Rel(root, p.Fset.Position(f.Pos()).Filename)
190 file = filepath.ToSlash(file)
191 grouped := map[token.Token]int{}
192 for _, d := range f.Decls {
193 name := ""
194 var defs []types.Object
195 switch d := d.(type) {
196 case *ast.FuncDecl:
197 name = d.Name.Name
198 if obj, ok := p.TypesInfo.Defs[d.Name].(*types.Func); ok {
199 defs = append(defs, obj)
200 sig := obj.Type().(*types.Signature)
201 if sig.Recv() != nil {
202 r := sig.Recv().Type()
203 if ptr, ok := r.(*types.Pointer); ok {
204 r = ptr.Elem()
205 }
206 if n, ok := r.(*types.Named); ok {
207 name = n.Obj().Name() + "." + name
208 }
209 methods[obj.Name()] = append(methods[obj.Name()], obj)
210 }
211 }
212 case *ast.GenDecl:
213 if d.Tok == token.IMPORT {
214 continue
215 }
216 if d.Lparen.IsValid() {
217 grouped[d.Tok]++
218 name = fmt.Sprintf("%s#%d", d.Tok, grouped[d.Tok])
219 } else {
220 switch s := d.Specs[0].(type) {
221 case *ast.TypeSpec:
222 name = "type " + s.Name.Name
223 case *ast.ValueSpec:
224 name = d.Tok.String() + " " + s.Names[0].Name
225 }
226 }
227 ast.Inspect(d, func(n ast.Node) bool {
228 if id, ok := n.(*ast.Ident); ok {
229 if obj := p.TypesInfo.Defs[id]; obj != nil {
230 defs = append(defs, obj)
231 }
232 }
233 return true
234 })
235 }
236 if name == "" {
237 continue
238 }
239 key := file + ":" + name
240 decls = append(decls, decl{key, d, p})
241 for _, obj := range defs {
242 objects[obj] = key
243 }
244 }
245 }
246 }
247 for _, d := range decls {
248 ast.Inspect(d.node, func(n ast.Node) bool {
249 if call, ok := n.(*ast.CallExpr); ok && len(call.Args) == 2 {
250 if sel, ok := call.Fun.(*ast.SelectorExpr); ok {
251 obj := d.pkg.TypesInfo.Uses[sel.Sel]
252 if obj != nil && obj.Pkg() != nil && obj.Pkg().Path() == "encoding/json" && obj.Name() == "Unmarshal" {
253 for _, method := range inputJSONMethods(d.pkg.TypesInfo.TypeOf(call.Args[1]), map[types.Type]bool{}) {
254 add(d.key, objects[method])
255 }
256 }
257 }
258 }
259 if id, ok := n.(*ast.Ident); ok {
260 add(d.key, objects[d.pkg.TypesInfo.Uses[id]])
261 }
262 if s, ok := n.(*ast.SelectorExpr); ok {
263 if sel := d.pkg.TypesInfo.Selections[s]; sel != nil {
264 if iface, ok := sel.Recv().Underlying().(*types.Interface); ok {
265 if method, ok := sel.Obj().(*types.Func); ok {
266 for _, candidate := range methods[method.Name()] {
267 sig := candidate.Type().(*types.Signature)
268 if types.Implements(sig.Recv().Type(), iface) || types.Implements(types.NewPointer(sig.Recv().Type()), iface) {
269 add(d.key, objects[candidate])
270 }
271 }
272 }
273 }
274 }
275 }
276 return true
277 })
278 // The embedded unit is an input to the reachable installer declaration.
279 if gd, ok := d.node.(*ast.GenDecl); ok && gd.Doc != nil {
280 for _, c := range gd.Doc.List {
281 if strings.HasPrefix(c.Text, "//go:embed ") {
282 for _, pattern := range strings.Fields(strings.TrimPrefix(c.Text, "//go:embed ")) {
283 matches, _ := filepath.Glob(filepath.Join(root, filepath.Dir(strings.Split(d.key, ":")[0]), pattern))
284 for _, path := range matches {
285 rel, _ := filepath.Rel(root, path)
286 add(d.key, filepath.ToSlash(rel)+":external")
287 }
288 }
289 }
290 }
291 }
292 }
293 // The console is a separate shipped executable. Its floor admission and
294 // control-store writers were explicitly classified as authority; they do
295 // not become unreachable because they are outside the carlos binary.
296 reached := map[string]string{"main.go:main": "root CLI entrypoint", "cmd/console/main.go:main": "console service entrypoint"}
297 queue := []string{"main.go:main", "cmd/console/main.go:main"}
298 for len(queue) > 0 {
299 from := queue[0]
300 queue = queue[1:]
301 var next []string
302 for to := range graph[from] {
303 next = append(next, to)
304 }
305 sort.Strings(next)
306 for _, to := range next {
307 if _, ok := reached[to]; !ok {
308 reached[to] = from
309 queue = append(queue, to)
310 }
311 }
312 }
313 return reached, nil
314}
315
316// encoding/json invokes these typed callbacks through reflection, outside the
317// repository call graph. Follow only types passed to actual Unmarshal calls.
318func inputJSONMethods(typ types.Type, seen map[types.Type]bool) []types.Object {
319 if typ == nil || seen[typ] {
320 return nil
321 }
322 seen[typ] = true
323 var out []types.Object
324 for _, receiver := range []types.Type{typ, types.NewPointer(typ)} {
325 methods := types.NewMethodSet(receiver)
326 for i := 0; i < methods.Len(); i++ {
327 m := methods.At(i).Obj()
328 if m.Name() == "UnmarshalJSON" {
329 out = append(out, m)
330 }
331 }
332 }
333 switch t := typ.(type) {
334 case *types.Named:
335 out = append(out, inputJSONMethods(t.Underlying(), seen)...)
336 case *types.Alias:
337 out = append(out, inputJSONMethods(types.Unalias(t), seen)...)
338 case *types.Pointer:
339 out = append(out, inputJSONMethods(t.Elem(), seen)...)
340 case *types.Slice:
341 out = append(out, inputJSONMethods(t.Elem(), seen)...)
342 case *types.Array:
343 out = append(out, inputJSONMethods(t.Elem(), seen)...)
344 case *types.Map:
345 out = append(out, inputJSONMethods(t.Elem(), seen)...)
346 case *types.Struct:
347 for i := 0; i < t.NumFields(); i++ {
348 out = append(out, inputJSONMethods(t.Field(i).Type(), seen)...)
349 }
350 }
351 return out
352}
353
354type inputExemption struct {
355 Ruling string
356 Pending string
357}
358
359var inputExemptions = map[string]inputExemption{
360 "internal/host/claimservingpark_other.go:newServingParkFS": {Ruling: "activation-scope-2026-10-16; run12: non-Linux refusal-only seed backend; production constructor refuses before allocation"},
361 "internal/host/claimservingpark_other.go:servingParkFS.Capture": {Ruling: "activation-scope-2026-10-16; run12: non-Linux refusal-only seed backend; production constructor refuses before allocation"},
362 "internal/host/claimservingpark_other.go:servingParkFS.CheckParked": {Ruling: "activation-scope-2026-10-16; run12: non-Linux refusal-only seed backend; production constructor refuses before allocation"},
363 "internal/host/claimservingpark_other.go:servingParkFS.Delete": {Ruling: "activation-scope-2026-10-16; run12: non-Linux refusal-only seed backend; production constructor refuses before allocation"},
364 "internal/host/claimservingpark_other.go:servingParkFS.Move": {Ruling: "activation-scope-2026-10-16; run12: non-Linux refusal-only seed backend; production constructor refuses before allocation"},
365 "internal/host/claimservingpark_other.go:servingParkFS.Prepare": {Ruling: "activation-scope-2026-10-16; run12: non-Linux refusal-only seed backend; production constructor refuses before allocation"},
366 "internal/host/claimservingreboot_prepare_linux.go:servingParkRoot.prepareServingReboot": {Ruling: "activation-scope-2026-10-16; run12: frozen standalone preparation entrypoint; production recovery uses prepareOrCommitServingReboot"},
367 "internal/hostbox/servingpark_transport.go:ServingParkClient.ReplayUncertain": {Ruling: "activation-scope-2026-10-16; run12: frozen explicit readback/replay entrypoint; enabled requests use journalSend"},
368 "internal/host/rootmovesfloor.go:rootMovesFloors.reconstruct": {Ruling: "P3-R4.6"},
369 "internal/host/rootmovesfloor_authorization.go:rootMovesFloors.authorizeReconstruction": {Ruling: "P3-R4.6"},
370 "internal/host/rootmovesfloor_authorization.go:rootMovesFloors.authorizedReconstruction": {Ruling: "P3-R4.6"},
371 "internal/hostclaim/relocation.go:StartRelocation": {Ruling: "R-E2a"},
372 "internal/hostrelocate/participant.go:Participant.Sweep": {Ruling: "R-E2a"},
373 "internal/hostrelocate/worker.go:Worker.Start": {Ruling: "R-E2a"},
374 // This inventory stops at activation-tools, so seed's row outlives the
375 // deleted function; the roster-binding overlay removes it from the full
376 // census and declares servingPriorBinding at the same class.
377 "internal/host/claimservinghandover.go:servingPriorRevision": {Ruling: "census-ruling-roster-binding: deleted, renamed servingPriorBinding (equality on the box binding), which takes over all its callers"},
378}
379
380// Update this checkpoint status when merging E's completion report. The 4a
381// exemption must be removed before either Part 2 or Part 3 lands.
382var inputTrackEComplete = map[string]bool{"4a": false}
383
384func checkInputExemptions(inv rootReadInventory, callers map[string]string, exemptions map[string]inputExemption, completed map[string]bool) []string {
385 var failures []string
386 for key, ex := range exemptions {
387 e, exists := inv.Entries[key]
388 if !exists || e.Class != "authority" || inv.Removed[key] != "" {
389 failures = append(failures, key+": exemption has no authority declaration")
390 }
391 if ex.Ruling == "" {
392 failures = append(failures, key+": exemption has no ruling")
393 }
394 if callers[key] != "" {
395 failures = append(failures, key+": exempt unit now has a production caller; remove exemption and supply coverage")
396 }
397 if ex.Pending != "" && completed[ex.Pending] {
398 failures = append(failures, key+": temporary exemption survived completed track E item "+ex.Pending)
399 }
400 }
401 return failures
402}
403
404func inputActivationEnabled(e classifiedRootRead) bool {
405 if inputExemptions[e.File+":"+e.Unit].Ruling != "" {
406 return true
407 }
408 for _, prefix := range []string{
409 "internal/hostrelocate/", "internal/hostclaim/relocat",
410 "internal/host/relocation", "internal/activator/worker",
411 } {
412 if strings.HasPrefix(e.File, prefix) {
413 return false
414 }
415 }
416 for _, owner := range strings.Split(e.Task, ",") {
417 if owner != "E4" && owner != "J1" && owner != "J2" && owner != "J3" && owner != "J4" {
418 return true
419 }
420 }
421 return false
422}
423
424func checkInputRow(e classifiedRootRead, callers map[string]string, tests map[string]bool) []string {
425 if e.Class != "authority" || !inputActivationEnabled(e) {
426 return nil
427 }
428 key := e.File + ":" + e.Unit
429 families, err := inputFamilyFor(e)
430 if err != nil {
431 return []string{key + ": " + err.Error()}
432 }
433 var failures []string
434 if callers[key] == "" && inputExemptions[key].Ruling == "" {
435 failures = append(failures, key+": no production caller reachable from root entrypoint")
436 }
437 for _, name := range families {
438 f := inputFamilies[name]
439 for slot, test := range []string{f.Hostile, f.Rename, f.Erasure, f.Retry, f.Positive} {
440 if test == "" || !tests[test] {
441 failures = append(failures, "family "+name+" missing "+[]string{"hostile", "rename", "erasure", "retry", "positive"}[slot]+" fixture "+test)
442 }
443 }
444 }
445 return failures
446}
447
448func TestPlan14RootInputInventoryCoverage(t *testing.T) {
449 // Reads the source tree and read-only package maps only, and spends
450 // most of its time type-checking the module, so it runs in parallel
451 // rather than holding up the package's serial tests.
452 t.Parallel()
453 root := censusRoot(t)
454 inv := inputInventory(t)
455 tests, err := inputTests(root)
456 if err != nil {
457 t.Fatal(err)
458 }
459 callers, err := inputCallers(root)
460 if err != nil {
461 t.Fatal(err)
462 }
463 failures := checkInputExemptions(inv, callers, inputExemptions, inputTrackEComplete)
464 var report []string
465 for key, e := range inv.Entries {
466 if inv.Removed[key] != "" {
467 continue
468 }
469 failures = append(failures, checkInputRow(e, callers, tests)...)
470 if e.Class == "authority" {
471 family, familyErr := inputFamilyFor(e)
472 if familyErr != nil {
473 family = []string{e.Task}
474 }
475 mode := "enabled"
476 if !inputActivationEnabled(e) {
477 mode = "report-only"
478 }
479 report = append(report, fmt.Sprintf("%s\t%s\t%s\t%s\t%s\t%s", mode, e.File, e.Unit, strings.Join(family, "+"), callers[e.File+":"+e.Unit], e.Basis))
480 }
481 }
482 sort.Strings(report)
483 for _, row := range report {
484 t.Log("J4\t" + row)
485 }
486 path := os.Getenv("PLAN14_J4_REPORT")
487 if path == "" {
488 path = filepath.Join(t.TempDir(), "plan14-root-input-report.tsv")
489 }
490 if err := os.WriteFile(path, []byte("scope\tfile\tunit\tfamily\tcaller\tbasis\n"+strings.Join(report, "\n")+"\n"), 0600); err != nil {
491 t.Fatal(err)
492 }
493 t.Logf("J4 report: %s", path)
494 sort.Strings(failures)
495 last := ""
496 for _, failure := range failures {
497 if failure != last {
498 t.Error(failure)
499 last = failure
500 }
501 }
502 t.Logf("authority coverage: %d reachable declarations; %d failures", len(callers), len(failures))
503}
504
505func TestPlan14RootInputInventoryCoverageMutations(t *testing.T) {
506 e := classifiedRootRead{rootReadEntry: rootReadEntry{File: "root.go", Unit: "effect"}, Class: "authority", Task: "A,J4"}
507 callers := map[string]string{"root.go:effect": "main.go:main"}
508 tests := map[string]bool{}
509 for _, f := range inputFamilies {
510 for _, name := range []string{f.Hostile, f.Rename, f.Erasure, f.Retry, f.Positive} {
511 tests[name] = true
512 }
513 }
514 if errors := checkInputRow(e, callers, tests); len(errors) != 0 {
515 t.Fatal(errors)
516 }
517 delete(tests, inputFamilies["A"].Positive)
518 if len(checkInputRow(e, callers, tests)) == 0 {
519 t.Fatal("removed fixture accepted")
520 }
521 tests[inputFamilies["A"].Positive] = true
522 e.Task = "unknown"
523 if len(checkInputRow(e, callers, tests)) == 0 {
524 t.Fatal("unknown family accepted")
525 }
526 e.Task = "A"
527 delete(callers, "root.go:effect")
528 if len(checkInputRow(e, callers, tests)) == 0 {
529 t.Fatal("orphan accepted")
530 }
531 e.Class = "legacy"
532 if len(checkInputRow(e, callers, tests)) != 0 {
533 t.Fatal("legacy entered J4")
534 }
535}
536
537func TestPlan14RootInputExemptions(t *testing.T) {
538 inv := rootReadInventory{Entries: map[string]classifiedRootRead{}}
539 for key := range inputExemptions {
540 inv.Entries[key] = classifiedRootRead{Class: "authority"}
541 }
542 tests := map[string]bool{}
543 for _, name := range []string{inputFamilies["A"].Hostile, inputFamilies["A"].Rename, inputFamilies["A"].Erasure, inputFamilies["A"].Retry, inputFamilies["A"].Positive} {
544 tests[name] = true
545 }
546 for key := range inputExemptions {
547 parts := strings.SplitN(key, ":", 2)
548 row := classifiedRootRead{rootReadEntry: rootReadEntry{File: parts[0], Unit: parts[1]}, Class: "authority", Task: "A"}
549 if errs := checkInputRow(row, nil, tests); len(errs) != 0 {
550 t.Fatal("callerless exemption refused", errs)
551 }
552 if len(checkInputRow(row, nil, nil)) == 0 {
553 t.Fatal("exemption waived family fixtures")
554 }
555 }
556 callers := map[string]string{}
557 if errs := checkInputExemptions(inv, callers, inputExemptions, nil); len(errs) != 0 {
558 t.Fatal(errs)
559 }
560 for key := range inputExemptions {
561 t.Run(key, func(t *testing.T) {
562 callers[key] = "main.go:main"
563 if len(checkInputExemptions(inv, callers, inputExemptions, nil)) == 0 {
564 t.Fatal("production wiring escaped exemption guard")
565 }
566 delete(callers, key)
567 e := inv.Entries[key]
568 delete(inv.Entries, key)
569 if len(checkInputExemptions(inv, callers, inputExemptions, nil)) == 0 {
570 t.Fatal("stale exemption accepted")
571 }
572 inv.Entries[key] = e
573 })
574 }
575 pending := map[string]inputExemption{"internal/host/claimunit_binding_source.go:readClaimUnitShapes": {Ruling: "pending track E item 4a", Pending: "4a"}}
576 if len(checkInputExemptions(inv, callers, pending, map[string]bool{"4a": true})) == 0 {
577 t.Fatal("completed E4a accepted temporary exemption")
578 }
579 if len(checkInputExemptions(inv, callers, map[string]inputExemption{"unknown": {}}, nil)) == 0 {
580 t.Fatal("unruled exemption accepted")
581 }
582}
583
584func TestPlan14RootInputExemptionGraphMutation(t *testing.T) {
585 root := t.TempDir()
586 write := func(name, body string) {
587 t.Helper()
588 path := filepath.Join(root, name)
589 if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
590 t.Fatal(err)
591 }
592 if err := os.WriteFile(path, []byte(body), 0600); err != nil {
593 t.Fatal(err)
594 }
595 }
596 write("go.mod", "module fixture/root\n\ngo 1.24\n")
597 write("main.go", "package main\nfunc main(){}\n")
598 write("internal/hostclaim/relocation.go", "package hostclaim\nfunc StartRelocation(){}\n")
599 key := "internal/hostclaim/relocation.go:StartRelocation"
600 inv := rootReadInventory{Entries: map[string]classifiedRootRead{key: {Class: "authority"}}}
601 exemptions := map[string]inputExemption{key: inputExemptions[key]}
602 callers, err := inputCallers(root)
603 if err != nil {
604 t.Fatal(err)
605 }
606 if errs := checkInputExemptions(inv, callers, exemptions, nil); len(errs) != 0 {
607 t.Fatal(errs)
608 }
609 write("main.go", "package main\nimport \"fixture/root/internal/hostclaim\"\nfunc main(){hostclaim.StartRelocation()}\n")
610 callers, err = inputCallers(root)
611 if err != nil {
612 t.Fatal(err)
613 }
614 if callers[key] == "" || len(checkInputExemptions(inv, callers, exemptions, nil)) == 0 {
615 t.Fatal("production relocation wiring escaped the exemption")
616 }
617}
618
619func TestPlan14ActivationInventoryScope(t *testing.T) {
620 e := classifiedRootRead{rootReadEntry: rootReadEntry{File: "root.go", Unit: "effect"}, Class: "authority", Task: "E4,J4"}
621 if inputActivationEnabled(e) || len(checkInputRow(e, nil, nil)) != 0 {
622 t.Fatal("dropped E4 slots enforced")
623 }
624 for _, owner := range []string{"A", "B", "B2", "B3", "B4", "C", "D", "E1", "E2", "E3", "F", "G"} {
625 e.Task = owner + ",E4,J4"
626 if !inputActivationEnabled(e) || len(checkInputRow(e, nil, nil)) == 0 {
627 t.Fatal("enabled mixed family waived", owner)
628 }
629 f := inputFamilies[owner]
630 for _, absent := range []string{f.Hostile, f.Rename, f.Erasure, f.Retry, f.Positive} {
631 tests := map[string]bool{}
632 for _, name := range []string{f.Hostile, f.Rename, f.Erasure, f.Retry, f.Positive} {
633 tests[name] = true
634 }
635 delete(tests, absent)
636 if len(checkInputRow(e, map[string]string{"root.go:effect": "main.go:main"}, tests)) == 0 {
637 t.Fatal("missing enabled fixture accepted", owner, absent)
638 }
639 }
640 }
641 e.File, e.Unit, e.Task = "internal/hostrelocate/worker.go", "Worker.disabled", "unknown"
642 if inputActivationEnabled(e) || len(checkInputRow(e, nil, nil)) != 0 {
643 t.Fatal("frozen family enforced")
644 }
645 e.Unit, e.Task = "Worker.Start", "C,D"
646 if !inputActivationEnabled(e) || len(checkInputRow(e, nil, nil)) == 0 {
647 t.Fatal("exemption escaped scope")
648 }
649}
650