{"record":{"id":"4ffa3075c8aeef90","repo":"gastownhall/beads","slug":"worktree-containment-observation-is-absent-or-inva","errorCode":null,"errorMessage":"worktree containment observation is absent or invalid","messagePattern":"worktree containment observation is absent or invalid","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/worktreeremove/policy.go","lineNumber":211,"sourceCode":"\t}\n\tif facts.ManagedIgnore != IgnoreAbsent && facts.ManagedIgnore != IgnoreManaged {\n\t\treturn Plan{}, fmt.Errorf(\"managed ignore observation is absent or invalid\")\n\t}\n\tif (facts.ManagedIgnore == IgnoreManaged) != (facts.ManagedIgnoreEntry != \"\") {\n\t\treturn Plan{}, fmt.Errorf(\"managed ignore cleanup identity is absent or invalid\")\n\t}\n\tif request.Mode != Force {\n\t\tif facts.Status != Clean {\n\t\t\treturn Plan{}, fmt.Errorf(\"worktree contains modified, untracked, or ignored files\")\n\t\t}\n\t\tif facts.Comparator != ComparatorAvailable && facts.Comparator != ComparatorMissing && facts.Comparator != ComparatorNotRequired {\n\t\t\treturn Plan{}, fmt.Errorf(\"worktree comparison target observation is absent or invalid\")\n\t\t}\n\t\tif facts.Comparator != ComparatorAvailable {\n\t\t\treturn Plan{}, fmt.Errorf(\"cannot verify unpushed commits: no comparison target is available\")\n\t\t}\n\t\tif facts.Containment != Contained && facts.Containment != NotContained && facts.Containment != ContainmentNotRequired {\n\t\t\treturn Plan{}, fmt.Errorf(\"worktree containment observation is absent or invalid\")\n\t\t}\n\t\tif facts.Containment != Contained {\n\t\t\treturn Plan{}, fmt.Errorf(\"worktree HEAD is not contained in the comparison target\")\n\t\t}\n\t} else if facts.Comparator != ComparatorNotRequired || facts.Containment != ContainmentNotRequired {\n\t\treturn Plan{}, fmt.Errorf(\"worktree force-mode comparison observations are inconsistent\")\n\t}\n\tplan := Plan{approved: true, mode: request.Mode, targetPath: facts.RegisteredPath}\n\tif facts.ManagedIgnore == IgnoreManaged {\n\t\tplan.managedIgnoreEntry = facts.ManagedIgnoreEntry\n\t}\n\treturn plan, nil\n}\n\n// InvariantState is the adapter's raw observation of one independently\n// revalidated invariant.\ntype InvariantState uint8\n","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/worktreeremove/policy.go#L193-L229","documentation":"Prepare rejects the request because mode is Normal and facts.Containment is not one of Contained, NotContained, or ContainmentNotRequired. The containment observation (is the worktree HEAD an ancestor of the comparison target?) is missing or an invalid value, so unpushed-commit verification cannot run and the library fails closed.","triggerScenarios":"Calling Prepare with Mode: Normal and a zero-value or out-of-range Containment, e.g. an adapter that resolved the comparator but never ran the containment check.","commonSituations":"Custom adapters skipping the merge-base/ancestor check; tests constructing partial facts; enum drift after adding new Containment values.","solutions":["Set facts.Containment from an actual containment check (e.g. git merge-base --is-ancestor HEAD <comparator>)","Ensure the adapter assigns Contained/NotContained rather than leaving the field zero","In tests, pair ComparatorAvailable with Containment: worktreeremove.Contained"],"exampleFix":"// before\nfacts.Containment = 0 // invalid\n// after\nfacts.Containment = worktreeremove.Contained // after verifying HEAD is an ancestor of comparator","handlingStrategy":"validation","validationCode":"switch facts.Containment {\ncase worktreeremove.Contained, worktreeremove.NotContained, worktreeremove.ContainmentNotRequired:\ndefault:\n\treturn fmt.Errorf(\"containment not observed\")\n}","typeGuard":"func containmentObserved(c worktreeremove.Containment) bool {\n\treturn c == worktreeremove.Contained || c == worktreeremove.NotContained || c == worktreeremove.ContainmentNotRequired\n}","tryCatchPattern":"plan, err := worktreeremove.Prepare(req, facts)\nif err != nil && strings.Contains(err.Error(), \"containment observation is absent\") {\n\treturn fmt.Errorf(\"run the containment check (merge-base --is-ancestor) first: %w\", err)\n}","preventionTips":["Always run the ancestor check after resolving the comparator","Never leave Containment zero when Comparator is set","Validate fact pairs (Comparator+Containment) together"],"tags":["worktree","git","validation"],"backgroundTag":"incomplete-observations","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}