phase-loop-runtime 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (370) hide show
  1. phase_loop_runtime/__init__.py +20 -0
  2. phase_loop_runtime/_contract_docs/phase-loop/extraction-readiness.md +90 -0
  3. phase_loop_runtime/_contract_docs/phase-loop/granular-execution-policy.md +137 -0
  4. phase_loop_runtime/_contract_docs/phase-loop/harness-capability-matrix.md +510 -0
  5. phase_loop_runtime/_contract_docs/phase-loop/harness-skill-matrix.md +125 -0
  6. phase_loop_runtime/_contract_docs/phase-loop/harness-substrate-manifest.md +232 -0
  7. phase_loop_runtime/_contract_docs/phase-loop/pi-loop-control.md +247 -0
  8. phase_loop_runtime/_contract_docs/phase-loop/protocol.md +2759 -0
  9. phase_loop_runtime/_contract_docs/phase-loop/runtime-boundary.md +289 -0
  10. phase_loop_runtime/_contract_docs/phase-loop/spec-discovery-roots.md +47 -0
  11. phase_loop_runtime/_contract_docs/phase-loop/substrate-soak-governed-pipeline.md +42 -0
  12. phase_loop_runtime/_contract_docs/phase-loop/substrate-soak-portal-projection.md +34 -0
  13. phase_loop_runtime/_contract_docs/phase-loop/substrate-soak-regenesis.md +29 -0
  14. phase_loop_runtime/_contract_docs/phase-loop/substrate-soak-report.md +32 -0
  15. phase_loop_runtime/_contract_docs/runtime/verification-evidence-contract.md +52 -0
  16. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/borderline/borderline-mixed-signals/commands.txt +2 -0
  17. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/borderline/borderline-mixed-signals/manifest.json +16 -0
  18. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/borderline/borderline-mixed-signals/mixed.json +5 -0
  19. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/borderline/borderline-provider-timeout/manifest.json +16 -0
  20. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/borderline/borderline-provider-timeout/timeout-note.txt +2 -0
  21. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/borderline/borderline-redacted-summary/manifest.json +16 -0
  22. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/borderline/borderline-redacted-summary/redacted-summary.json +6 -0
  23. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/borderline/borderline-small-sample/manifest.json +16 -0
  24. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/borderline/borderline-small-sample/sample.json +7 -0
  25. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/borderline/borderline-threshold-edge/edge.txt +2 -0
  26. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/borderline/borderline-threshold-edge/manifest.json +16 -0
  27. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-duplicate-png/manifest.json +16 -0
  28. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-duplicate-png/shot-a.txt +1 -0
  29. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-duplicate-png/shot-b.txt +1 -0
  30. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-duplicate-png/shot-c.txt +1 -0
  31. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-missing-references/claimed-results.json +5 -0
  32. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-missing-references/manifest.json +16 -0
  33. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-subtle-low-variance/manifest.json +16 -0
  34. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-subtle-low-variance/metrics.json +9 -0
  35. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-templated-prose/findings.md +10 -0
  36. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-templated-prose/manifest.json +16 -0
  37. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-uniform-scores/manifest.json +16 -0
  38. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-uniform-scores/scores.json +4 -0
  39. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-fake/fake-uniform-scores/summary.txt +1 -0
  40. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-adoption-bundle/bundle-check.json +8 -0
  41. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-adoption-bundle/manifest.json +16 -0
  42. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-adoption-bundle/operator-note.txt +2 -0
  43. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-handoff-ledger/events-sample.jsonl +3 -0
  44. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-handoff-ledger/manifest.json +16 -0
  45. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-handoff-ledger/receipt.txt +1 -0
  46. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-runner-diff/evidence.json +13 -0
  47. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-runner-diff/manifest.json +16 -0
  48. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-runner-diff/summary.txt +2 -0
  49. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-test-matrix/manifest.json +16 -0
  50. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-test-matrix/matrix.json +9 -0
  51. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-test-matrix/notes.md +4 -0
  52. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-ui-screenshot-standin/console-summary.txt +2 -0
  53. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-ui-screenshot-standin/manifest.json +16 -0
  54. phase_loop_runtime/_test_fixtures/evidence-audit-calibration/known-real/real-ui-screenshot-standin/screenshot-standin.ppm +5 -0
  55. phase_loop_runtime/adoption_bundle.py +273 -0
  56. phase_loop_runtime/advisor_board/CONTRACTS.md +257 -0
  57. phase_loop_runtime/advisor_board/__init__.py +288 -0
  58. phase_loop_runtime/advisor_board/backing.py +137 -0
  59. phase_loop_runtime/advisor_board/backing_omnigent.py +498 -0
  60. phase_loop_runtime/advisor_board/config.py +225 -0
  61. phase_loop_runtime/advisor_board/events.py +115 -0
  62. phase_loop_runtime/advisor_board/fixtures/advisor-boards.example.toml +59 -0
  63. phase_loop_runtime/advisor_board/fixtures.py +91 -0
  64. phase_loop_runtime/advisor_board/harness_mapping.py +125 -0
  65. phase_loop_runtime/advisor_board/matrix.py +146 -0
  66. phase_loop_runtime/advisor_board/observability.py +481 -0
  67. phase_loop_runtime/advisor_board/presets.py +188 -0
  68. phase_loop_runtime/advisor_board/registries.py +309 -0
  69. phase_loop_runtime/advisor_board/resolver.py +253 -0
  70. phase_loop_runtime/advisor_board/schema.py +269 -0
  71. phase_loop_runtime/advisor_board/standin.py +166 -0
  72. phase_loop_runtime/advisor_board/validation.py +159 -0
  73. phase_loop_runtime/agent_runtime_provider.py +676 -0
  74. phase_loop_runtime/baml_modular.py +656 -0
  75. phase_loop_runtime/baml_src/dotfiles_adoption_manifest.baml +37 -0
  76. phase_loop_runtime/baml_src/dotfiles_c4_document.baml +14 -0
  77. phase_loop_runtime/baml_src/dotfiles_plan_manifest.baml +50 -0
  78. phase_loop_runtime/baml_src/dotfiles_runtime_projection.baml +16 -0
  79. phase_loop_runtime/baml_src/dotfiles_task_catalog.baml +20 -0
  80. phase_loop_runtime/baml_src/emit_phase_closeout.baml +86 -0
  81. phase_loop_runtime/baml_src/evaluate_suspected_fake_evidence.baml +36 -0
  82. phase_loop_runtime/baml_src/verification_evidence.baml +40 -0
  83. phase_loop_runtime/broker.py +181 -0
  84. phase_loop_runtime/build_bundle.py +294 -0
  85. phase_loop_runtime/capability_registry.py +835 -0
  86. phase_loop_runtime/classifier.py +87 -0
  87. phase_loop_runtime/claude_agent_view.py +625 -0
  88. phase_loop_runtime/claude_channel_sidecar.py +1086 -0
  89. phase_loop_runtime/cli.py +2599 -0
  90. phase_loop_runtime/closeout.py +865 -0
  91. phase_loop_runtime/closeout_classifier.py +120 -0
  92. phase_loop_runtime/closeout_evidence_audit.py +112 -0
  93. phase_loop_runtime/closeout_validation.py +144 -0
  94. phase_loop_runtime/closeout_validators.py +203 -0
  95. phase_loop_runtime/consiliency_gates.py +374 -0
  96. phase_loop_runtime/consiliency_ingest.py +399 -0
  97. phase_loop_runtime/consiliency_layout.py +176 -0
  98. phase_loop_runtime/consiliency_scaffold.py +305 -0
  99. phase_loop_runtime/cross_repo_channel.py +331 -0
  100. phase_loop_runtime/discovery.py +2368 -0
  101. phase_loop_runtime/dispatch_lock.py +167 -0
  102. phase_loop_runtime/doc_delta_validator.py +98 -0
  103. phase_loop_runtime/docs_audit.py +285 -0
  104. phase_loop_runtime/docs_freshness.py +468 -0
  105. phase_loop_runtime/docs_surfaces.py +150 -0
  106. phase_loop_runtime/dotfiles_profile_plugin.py +96 -0
  107. phase_loop_runtime/events.py +154 -0
  108. phase_loop_runtime/events_migration.py +96 -0
  109. phase_loop_runtime/evidence_audit.py +1082 -0
  110. phase_loop_runtime/evidence_audit_config.py +172 -0
  111. phase_loop_runtime/fleet_map.py +426 -0
  112. phase_loop_runtime/fleet_metrics.py +298 -0
  113. phase_loop_runtime/fleet_metrics_export.py +196 -0
  114. phase_loop_runtime/git_discipline.py +479 -0
  115. phase_loop_runtime/git_ops.py +122 -0
  116. phase_loop_runtime/git_topology.py +252 -0
  117. phase_loop_runtime/governed_bundle.py +137 -0
  118. phase_loop_runtime/governed_premerge.py +219 -0
  119. phase_loop_runtime/governed_review.py +264 -0
  120. phase_loop_runtime/handoff.py +932 -0
  121. phase_loop_runtime/handoff_path.py +14 -0
  122. phase_loop_runtime/injection.py +740 -0
  123. phase_loop_runtime/install_status.py +88 -0
  124. phase_loop_runtime/lane_scheduler.py +317 -0
  125. phase_loop_runtime/launcher.py +2760 -0
  126. phase_loop_runtime/lease_store.py +553 -0
  127. phase_loop_runtime/maintenance.py +401 -0
  128. phase_loop_runtime/migrate_handoffs.py +201 -0
  129. phase_loop_runtime/models.py +2144 -0
  130. phase_loop_runtime/observability.py +1290 -0
  131. phase_loop_runtime/panel_invoker.py +1638 -0
  132. phase_loop_runtime/phase_loop_drift_audit.py +388 -0
  133. phase_loop_runtime/phase_worktree_executor.py +433 -0
  134. phase_loop_runtime/pipeline_adapter/__init__.py +12 -0
  135. phase_loop_runtime/pipeline_adapter/branch_ops.py +274 -0
  136. phase_loop_runtime/pipeline_adapter/flag.py +55 -0
  137. phase_loop_runtime/pipeline_adapter/markers.py +13 -0
  138. phase_loop_runtime/pipeline_adapter/merge_policy.py +72 -0
  139. phase_loop_runtime/pipeline_adapter/ratification.py +100 -0
  140. phase_loop_runtime/pipeline_adapter/sibling_matcher.py +123 -0
  141. phase_loop_runtime/plan_ir.py +523 -0
  142. phase_loop_runtime/plan_manifest.py +415 -0
  143. phase_loop_runtime/planner_validation.py +176 -0
  144. phase_loop_runtime/profiles.py +462 -0
  145. phase_loop_runtime/prompts.py +365 -0
  146. phase_loop_runtime/provenance.py +165 -0
  147. phase_loop_runtime/publishing.py +339 -0
  148. phase_loop_runtime/py.typed +1 -0
  149. phase_loop_runtime/reconcile.py +1550 -0
  150. phase_loop_runtime/redaction.py +184 -0
  151. phase_loop_runtime/reflection_sync.py +293 -0
  152. phase_loop_runtime/release_guard.py +186 -0
  153. phase_loop_runtime/render.py +432 -0
  154. phase_loop_runtime/repo_validation.py +427 -0
  155. phase_loop_runtime/review_summary.py +150 -0
  156. phase_loop_runtime/roadmap_lint.py +425 -0
  157. phase_loop_runtime/route_log.py +59 -0
  158. phase_loop_runtime/route_policy/__init__.py +11 -0
  159. phase_loop_runtime/route_policy/fixtures/route_selection.golden.json +263 -0
  160. phase_loop_runtime/runner.py +8400 -0
  161. phase_loop_runtime/runtime_paths.py +225 -0
  162. phase_loop_runtime/runtime_projection.py +113 -0
  163. phase_loop_runtime/runtime_resources.py +36 -0
  164. phase_loop_runtime/schema_export.py +292 -0
  165. phase_loop_runtime/schemas/phase_loop_closeout.schema.json +366 -0
  166. phase_loop_runtime/skill_install.py +176 -0
  167. phase_loop_runtime/skill_inventory.py +662 -0
  168. phase_loop_runtime/skill_paths.py +42 -0
  169. phase_loop_runtime/skill_sources_plugin.py +37 -0
  170. phase_loop_runtime/skills_bundle/claude-advisor-board/README.md +1 -0
  171. phase_loop_runtime/skills_bundle/claude-advisor-board/SKILL.md +38 -0
  172. phase_loop_runtime/skills_bundle/claude-advisor-panel/README.md +1 -0
  173. phase_loop_runtime/skills_bundle/claude-advisor-panel/SKILL.md +38 -0
  174. phase_loop_runtime/skills_bundle/claude-execute-detailed/README.md +1 -0
  175. phase_loop_runtime/skills_bundle/claude-execute-detailed/SKILL.md +152 -0
  176. phase_loop_runtime/skills_bundle/claude-execute-phase/README.md +1 -0
  177. phase_loop_runtime/skills_bundle/claude-execute-phase/SKILL.md +745 -0
  178. phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/allocate_worktree_name.sh +33 -0
  179. phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/audit_lane_file_touches.py +197 -0
  180. phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/cleanup_lane_worktrees.sh +103 -0
  181. phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/parent_tree_leakage_check.sh +125 -0
  182. phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/post_merge_import_smoke.sh +62 -0
  183. phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/pre_merge_destructiveness_check.sh +127 -0
  184. phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/resolve_branch_from_sha.sh +51 -0
  185. phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/state.py +274 -0
  186. phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/sweep_stale_worktrees.sh +62 -0
  187. phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/team_teardown.sh +32 -0
  188. phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/validate_plan_doc.py +642 -0
  189. phase_loop_runtime/skills_bundle/claude-execute-phase/scripts/verify_harness.sh +96 -0
  190. phase_loop_runtime/skills_bundle/claude-phase-loop/README.md +1 -0
  191. phase_loop_runtime/skills_bundle/claude-phase-loop/SKILL.md +115 -0
  192. phase_loop_runtime/skills_bundle/claude-phase-roadmap-builder/README.md +1 -0
  193. phase_loop_runtime/skills_bundle/claude-phase-roadmap-builder/SKILL.md +439 -0
  194. phase_loop_runtime/skills_bundle/claude-phase-roadmap-builder/assets/review_prompt.md +19 -0
  195. phase_loop_runtime/skills_bundle/claude-phase-roadmap-builder/references/parallelization-heuristics.md +111 -0
  196. phase_loop_runtime/skills_bundle/claude-phase-roadmap-builder/references/roadmap-template.md +193 -0
  197. phase_loop_runtime/skills_bundle/claude-phase-roadmap-builder/scripts/validate_roadmap.py +32 -0
  198. phase_loop_runtime/skills_bundle/claude-plan-detailed/README.md +1 -0
  199. phase_loop_runtime/skills_bundle/claude-plan-detailed/SKILL.md +334 -0
  200. phase_loop_runtime/skills_bundle/claude-plan-detailed/assets/review_prompt.md +25 -0
  201. phase_loop_runtime/skills_bundle/claude-plan-phase/README.md +1 -0
  202. phase_loop_runtime/skills_bundle/claude-plan-phase/SKILL.md +776 -0
  203. phase_loop_runtime/skills_bundle/claude-plan-phase/assets/review_prompt.md +17 -0
  204. phase_loop_runtime/skills_bundle/claude-plan-phase/scripts/validate_plan_doc.py +1092 -0
  205. phase_loop_runtime/skills_bundle/claude-run-train/README.md +1 -0
  206. phase_loop_runtime/skills_bundle/claude-run-train/SKILL.md +75 -0
  207. phase_loop_runtime/skills_bundle/claude-skill-editor/README.md +1 -0
  208. phase_loop_runtime/skills_bundle/claude-skill-editor/SKILL.md +243 -0
  209. phase_loop_runtime/skills_bundle/claude-skill-editor/assets/editor_prompt.md +72 -0
  210. phase_loop_runtime/skills_bundle/claude-skill-improvement-planner/README.md +1 -0
  211. phase_loop_runtime/skills_bundle/claude-skill-improvement-planner/SKILL.md +249 -0
  212. phase_loop_runtime/skills_bundle/claude-skill-improvement-planner/assets/aggregator_prompt.md +79 -0
  213. phase_loop_runtime/skills_bundle/claude-task-contextualizer/README.md +1 -0
  214. phase_loop_runtime/skills_bundle/claude-task-contextualizer/SKILL.md +74 -0
  215. phase_loop_runtime/skills_bundle/claude-task-contextualizer/references/task-templates.md +103 -0
  216. phase_loop_runtime/skills_bundle/codex-advisor-board/README.md +1 -0
  217. phase_loop_runtime/skills_bundle/codex-advisor-board/SKILL.md +38 -0
  218. phase_loop_runtime/skills_bundle/codex-advisor-panel/README.md +1 -0
  219. phase_loop_runtime/skills_bundle/codex-advisor-panel/SKILL.md +38 -0
  220. phase_loop_runtime/skills_bundle/codex-execute-detailed/README.md +1 -0
  221. phase_loop_runtime/skills_bundle/codex-execute-detailed/SKILL.md +154 -0
  222. phase_loop_runtime/skills_bundle/codex-execute-phase/README.md +1 -0
  223. phase_loop_runtime/skills_bundle/codex-execute-phase/SKILL.md +231 -0
  224. phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/allocate_worktree_name.sh +33 -0
  225. phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/audit_lane_file_touches.py +197 -0
  226. phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/cleanup_lane_worktrees.sh +103 -0
  227. phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/parent_tree_leakage_check.sh +125 -0
  228. phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/post_merge_import_smoke.sh +62 -0
  229. phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/pre_merge_destructiveness_check.sh +127 -0
  230. phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/resolve_branch_from_sha.sh +51 -0
  231. phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/state.py +274 -0
  232. phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/sweep_stale_worktrees.sh +62 -0
  233. phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/team_teardown.sh +32 -0
  234. phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/validate_plan_doc.py +642 -0
  235. phase_loop_runtime/skills_bundle/codex-execute-phase/scripts/verify_harness.sh +96 -0
  236. phase_loop_runtime/skills_bundle/codex-phase-loop/README.md +1 -0
  237. phase_loop_runtime/skills_bundle/codex-phase-loop/SKILL.md +248 -0
  238. phase_loop_runtime/skills_bundle/codex-phase-roadmap-builder/README.md +1 -0
  239. phase_loop_runtime/skills_bundle/codex-phase-roadmap-builder/SKILL.md +150 -0
  240. phase_loop_runtime/skills_bundle/codex-phase-roadmap-builder/assets/review_prompt.md +19 -0
  241. phase_loop_runtime/skills_bundle/codex-phase-roadmap-builder/references/parallelization-heuristics.md +111 -0
  242. phase_loop_runtime/skills_bundle/codex-phase-roadmap-builder/references/roadmap-template.md +193 -0
  243. phase_loop_runtime/skills_bundle/codex-phase-roadmap-builder/scripts/validate_roadmap.py +32 -0
  244. phase_loop_runtime/skills_bundle/codex-plan-detailed/README.md +1 -0
  245. phase_loop_runtime/skills_bundle/codex-plan-detailed/SKILL.md +119 -0
  246. phase_loop_runtime/skills_bundle/codex-plan-detailed/assets/review_prompt.md +25 -0
  247. phase_loop_runtime/skills_bundle/codex-plan-phase/README.md +1 -0
  248. phase_loop_runtime/skills_bundle/codex-plan-phase/SKILL.md +307 -0
  249. phase_loop_runtime/skills_bundle/codex-plan-phase/assets/review_prompt.md +17 -0
  250. phase_loop_runtime/skills_bundle/codex-plan-phase/scripts/validate_plan_doc.py +1092 -0
  251. phase_loop_runtime/skills_bundle/codex-run-train/README.md +1 -0
  252. phase_loop_runtime/skills_bundle/codex-run-train/SKILL.md +75 -0
  253. phase_loop_runtime/skills_bundle/codex-skill-editor/README.md +1 -0
  254. phase_loop_runtime/skills_bundle/codex-skill-editor/SKILL.md +94 -0
  255. phase_loop_runtime/skills_bundle/codex-skill-editor/assets/editor_prompt.md +72 -0
  256. phase_loop_runtime/skills_bundle/codex-skill-improvement-planner/README.md +1 -0
  257. phase_loop_runtime/skills_bundle/codex-skill-improvement-planner/SKILL.md +114 -0
  258. phase_loop_runtime/skills_bundle/codex-skill-improvement-planner/assets/aggregator_prompt.md +79 -0
  259. phase_loop_runtime/skills_bundle/codex-task-contextualizer/README.md +1 -0
  260. phase_loop_runtime/skills_bundle/codex-task-contextualizer/SKILL.md +102 -0
  261. phase_loop_runtime/skills_bundle/codex-task-contextualizer/references/task-templates.md +103 -0
  262. phase_loop_runtime/skills_bundle/gemini-advisor-board/README.md +1 -0
  263. phase_loop_runtime/skills_bundle/gemini-advisor-board/SKILL.md +38 -0
  264. phase_loop_runtime/skills_bundle/gemini-advisor-panel/README.md +1 -0
  265. phase_loop_runtime/skills_bundle/gemini-advisor-panel/SKILL.md +38 -0
  266. phase_loop_runtime/skills_bundle/gemini-execute-detailed/README.md +1 -0
  267. phase_loop_runtime/skills_bundle/gemini-execute-detailed/SKILL.md +144 -0
  268. phase_loop_runtime/skills_bundle/gemini-execute-phase/README.md +1 -0
  269. phase_loop_runtime/skills_bundle/gemini-execute-phase/SKILL.md +198 -0
  270. phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/allocate_worktree_name.sh +33 -0
  271. phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/audit_lane_file_touches.py +197 -0
  272. phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/cleanup_lane_worktrees.sh +103 -0
  273. phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/parent_tree_leakage_check.sh +125 -0
  274. phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/post_merge_import_smoke.sh +62 -0
  275. phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/pre_merge_destructiveness_check.sh +127 -0
  276. phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/resolve_branch_from_sha.sh +51 -0
  277. phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/state.py +274 -0
  278. phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/sweep_stale_worktrees.sh +62 -0
  279. phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/team_teardown.sh +32 -0
  280. phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/validate_plan_doc.py +642 -0
  281. phase_loop_runtime/skills_bundle/gemini-execute-phase/scripts/verify_harness.sh +96 -0
  282. phase_loop_runtime/skills_bundle/gemini-phase-loop/README.md +1 -0
  283. phase_loop_runtime/skills_bundle/gemini-phase-loop/SKILL.md +111 -0
  284. phase_loop_runtime/skills_bundle/gemini-phase-roadmap-builder/README.md +1 -0
  285. phase_loop_runtime/skills_bundle/gemini-phase-roadmap-builder/SKILL.md +147 -0
  286. phase_loop_runtime/skills_bundle/gemini-phase-roadmap-builder/assets/review_prompt.md +19 -0
  287. phase_loop_runtime/skills_bundle/gemini-phase-roadmap-builder/references/parallelization-heuristics.md +111 -0
  288. phase_loop_runtime/skills_bundle/gemini-phase-roadmap-builder/references/roadmap-template.md +193 -0
  289. phase_loop_runtime/skills_bundle/gemini-phase-roadmap-builder/scripts/validate_roadmap.py +32 -0
  290. phase_loop_runtime/skills_bundle/gemini-plan-detailed/README.md +1 -0
  291. phase_loop_runtime/skills_bundle/gemini-plan-detailed/SKILL.md +119 -0
  292. phase_loop_runtime/skills_bundle/gemini-plan-detailed/assets/review_prompt.md +25 -0
  293. phase_loop_runtime/skills_bundle/gemini-plan-phase/README.md +1 -0
  294. phase_loop_runtime/skills_bundle/gemini-plan-phase/SKILL.md +217 -0
  295. phase_loop_runtime/skills_bundle/gemini-plan-phase/assets/review_prompt.md +17 -0
  296. phase_loop_runtime/skills_bundle/gemini-plan-phase/scripts/validate_plan_doc.py +1092 -0
  297. phase_loop_runtime/skills_bundle/gemini-run-train/README.md +1 -0
  298. phase_loop_runtime/skills_bundle/gemini-run-train/SKILL.md +75 -0
  299. phase_loop_runtime/skills_bundle/gemini-skill-editor/README.md +1 -0
  300. phase_loop_runtime/skills_bundle/gemini-skill-editor/SKILL.md +87 -0
  301. phase_loop_runtime/skills_bundle/gemini-skill-editor/assets/editor_prompt.md +72 -0
  302. phase_loop_runtime/skills_bundle/gemini-skill-improvement-planner/README.md +1 -0
  303. phase_loop_runtime/skills_bundle/gemini-skill-improvement-planner/SKILL.md +109 -0
  304. phase_loop_runtime/skills_bundle/gemini-skill-improvement-planner/assets/aggregator_prompt.md +79 -0
  305. phase_loop_runtime/skills_bundle/gemini-task-contextualizer/README.md +1 -0
  306. phase_loop_runtime/skills_bundle/gemini-task-contextualizer/SKILL.md +98 -0
  307. phase_loop_runtime/skills_bundle/gemini-task-contextualizer/references/task-templates.md +103 -0
  308. phase_loop_runtime/skills_bundle/opencode-advisor-board/README.md +1 -0
  309. phase_loop_runtime/skills_bundle/opencode-advisor-board/SKILL.md +38 -0
  310. phase_loop_runtime/skills_bundle/opencode-advisor-panel/README.md +1 -0
  311. phase_loop_runtime/skills_bundle/opencode-advisor-panel/SKILL.md +38 -0
  312. phase_loop_runtime/skills_bundle/opencode-execute-detailed/README.md +1 -0
  313. phase_loop_runtime/skills_bundle/opencode-execute-detailed/SKILL.md +144 -0
  314. phase_loop_runtime/skills_bundle/opencode-execute-phase/README.md +1 -0
  315. phase_loop_runtime/skills_bundle/opencode-execute-phase/SKILL.md +196 -0
  316. phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/allocate_worktree_name.sh +33 -0
  317. phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/audit_lane_file_touches.py +197 -0
  318. phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/cleanup_lane_worktrees.sh +103 -0
  319. phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/parent_tree_leakage_check.sh +125 -0
  320. phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/post_merge_import_smoke.sh +62 -0
  321. phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/pre_merge_destructiveness_check.sh +127 -0
  322. phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/resolve_branch_from_sha.sh +51 -0
  323. phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/state.py +274 -0
  324. phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/sweep_stale_worktrees.sh +62 -0
  325. phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/team_teardown.sh +32 -0
  326. phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/validate_plan_doc.py +642 -0
  327. phase_loop_runtime/skills_bundle/opencode-execute-phase/scripts/verify_harness.sh +96 -0
  328. phase_loop_runtime/skills_bundle/opencode-phase-loop/README.md +1 -0
  329. phase_loop_runtime/skills_bundle/opencode-phase-loop/SKILL.md +113 -0
  330. phase_loop_runtime/skills_bundle/opencode-phase-roadmap-builder/README.md +1 -0
  331. phase_loop_runtime/skills_bundle/opencode-phase-roadmap-builder/SKILL.md +147 -0
  332. phase_loop_runtime/skills_bundle/opencode-phase-roadmap-builder/assets/review_prompt.md +19 -0
  333. phase_loop_runtime/skills_bundle/opencode-phase-roadmap-builder/references/parallelization-heuristics.md +111 -0
  334. phase_loop_runtime/skills_bundle/opencode-phase-roadmap-builder/references/roadmap-template.md +193 -0
  335. phase_loop_runtime/skills_bundle/opencode-phase-roadmap-builder/scripts/validate_roadmap.py +32 -0
  336. phase_loop_runtime/skills_bundle/opencode-plan-detailed/README.md +1 -0
  337. phase_loop_runtime/skills_bundle/opencode-plan-detailed/SKILL.md +119 -0
  338. phase_loop_runtime/skills_bundle/opencode-plan-detailed/assets/review_prompt.md +25 -0
  339. phase_loop_runtime/skills_bundle/opencode-plan-phase/README.md +1 -0
  340. phase_loop_runtime/skills_bundle/opencode-plan-phase/SKILL.md +211 -0
  341. phase_loop_runtime/skills_bundle/opencode-plan-phase/assets/review_prompt.md +17 -0
  342. phase_loop_runtime/skills_bundle/opencode-plan-phase/scripts/validate_plan_doc.py +1092 -0
  343. phase_loop_runtime/skills_bundle/opencode-run-train/README.md +1 -0
  344. phase_loop_runtime/skills_bundle/opencode-run-train/SKILL.md +75 -0
  345. phase_loop_runtime/skills_bundle/opencode-skill-editor/README.md +1 -0
  346. phase_loop_runtime/skills_bundle/opencode-skill-editor/SKILL.md +87 -0
  347. phase_loop_runtime/skills_bundle/opencode-skill-editor/assets/editor_prompt.md +72 -0
  348. phase_loop_runtime/skills_bundle/opencode-skill-improvement-planner/README.md +1 -0
  349. phase_loop_runtime/skills_bundle/opencode-skill-improvement-planner/SKILL.md +109 -0
  350. phase_loop_runtime/skills_bundle/opencode-skill-improvement-planner/assets/aggregator_prompt.md +79 -0
  351. phase_loop_runtime/skills_bundle/opencode-task-contextualizer/README.md +1 -0
  352. phase_loop_runtime/skills_bundle/opencode-task-contextualizer/SKILL.md +98 -0
  353. phase_loop_runtime/skills_bundle/opencode-task-contextualizer/references/task-templates.md +103 -0
  354. phase_loop_runtime/state.py +156 -0
  355. phase_loop_runtime/state_degradation.py +136 -0
  356. phase_loop_runtime/state_ops.py +676 -0
  357. phase_loop_runtime/train_ledger.py +215 -0
  358. phase_loop_runtime/train_roadmap.py +339 -0
  359. phase_loop_runtime/train_runner.py +1197 -0
  360. phase_loop_runtime/verification_evidence.py +650 -0
  361. phase_loop_runtime/verification_evidence_validator.py +75 -0
  362. phase_loop_runtime/visual_evidence_validator.py +36 -0
  363. phase_loop_runtime/worker_pool.py +123 -0
  364. phase_loop_runtime/worktree_index.py +270 -0
  365. phase_loop_runtime-0.2.0.data/data/share/phase-loop-runtime/protocol/protocol.md +2475 -0
  366. phase_loop_runtime-0.2.0.dist-info/METADATA +106 -0
  367. phase_loop_runtime-0.2.0.dist-info/RECORD +370 -0
  368. phase_loop_runtime-0.2.0.dist-info/WHEEL +5 -0
  369. phase_loop_runtime-0.2.0.dist-info/entry_points.txt +9 -0
  370. phase_loop_runtime-0.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,2475 @@
1
+ # Phase-Loop Protocol
2
+
3
+ This document is the canonical shared output contract for harness-neutral
4
+ phase-loop artifacts. It freezes the artifact shapes, failure vocabulary, and
5
+ promotion semantics that every executor, adapter, and manual/operator flow must
6
+ produce or consume during the current phase-loop roadmap family.
7
+ Harness-specific launch mechanics, runtime paths, and private skill install
8
+ details stay in harness-local runtime docs.
9
+ Harness-specific path ownership for the dotfiles-hosted substrate is recorded
10
+ in `docs/phase-loop/harness-substrate-manifest.md`; this protocol remains the
11
+ schema and artifact contract.
12
+ IF-0-SUBSTRATE-1 limits downstream substrate citations to runtime code, CLI
13
+ wrappers, bridge skills, shared runner skills, protocol docs, fixtures, tests,
14
+ scripts, and canonical `.phase-loop/**` state; broader dotfiles checkout
15
+ contents are not client dependencies.
16
+ Harness workflow skill naming is recorded in
17
+ `docs/phase-loop/harness-skill-matrix.md`; that matrix freezes the
18
+ `<harness>-<workflow>` contract, Pi Agent role-style exceptions, direct route
19
+ compatibility, and the governed-pipeline `.pipeline/skills/**` namespace guard.
20
+
21
+ ## Plan Frontmatter
22
+
23
+ Execution-ready phase plans remain compatible with the existing
24
+ `phase_loop_plan_version: 1` contract:
25
+
26
+ ```yaml
27
+ ---
28
+ phase_loop_plan_version: 1
29
+ phase: <PHASE_ALIAS>
30
+ roadmap: <repo-relative roadmap path>
31
+ roadmap_sha256: <sha256 of roadmap file bytes at planning time>
32
+ phase_loop_mutation: <optional release_dispatch>
33
+ release_base_ref: <optional base ref for release dispatch, default origin/main>
34
+ source_bundle: <optional repo-relative Pipeline source bundle path>
35
+ source_bundle_sha256: <optional sha256 of Pipeline source bundle bytes>
36
+ pipeline_phase_id: <optional Pipeline phase id>
37
+ pipeline_mode: <optional standalone|pipeline_optional|pipeline_required>
38
+ ---
39
+ ```
40
+
41
+ Required fields:
42
+
43
+ - `phase_loop_plan_version`
44
+ - `phase`
45
+ - `roadmap`
46
+ - `roadmap_sha256`
47
+
48
+ Optional fields:
49
+
50
+ - `phase_loop_mutation`
51
+ - `release_base_ref`
52
+ - `source_bundle`
53
+ - `source_bundle_sha256`
54
+ - `pipeline_phase_id`
55
+ - `pipeline_mode`
56
+
57
+ `PIPELINE_PLAN_FRONTMATTER_CONTRACT` is additive. Pipeline-aware metadata is additive
58
+ metadata, not a replacement for `phase`, `roadmap`, or `roadmap_sha256`.
59
+ Existing standalone plans with only `phase_loop_plan_version: 1`,
60
+ `phase`, `roadmap`, and `roadmap_sha256` remain valid when no Pipeline mode
61
+ requires bundle metadata.
62
+
63
+ The supported `pipeline_mode` literals are:
64
+
65
+ - `standalone`
66
+ - `pipeline_optional`
67
+ - `pipeline_required`
68
+
69
+ Pipeline metadata is required only when `pipeline_mode` is `pipeline_required`.
70
+ A pipeline-required plan missing `source_bundle` or `source_bundle_sha256`, or
71
+ whose `source_bundle_sha256` no longer matches the source bundle bytes, is a
72
+ typed repairable non-human diagnostic rather than partial execution readiness.
73
+ Unknown `pipeline_mode` values fail closed as typed metadata diagnostics.
74
+
75
+ Plans without this metadata, or with metadata that no longer matches the
76
+ selected roadmap, are stale for autonomous execution and must route back
77
+ through planning instead of execution.
78
+
79
+ ## Spec Delta Closeout
80
+
81
+ `spec_delta_closeout.v1` is the metadata-only decision record used when a phase
82
+ may change reusable harness specs, runtime contracts, roadmap/plan templates, or
83
+ workflow skills. Roadmap builders name the expected policy for each phase,
84
+ phase plans copy that policy into a machine-readable `Spec Closeout Plan`,
85
+ execute-phase closeouts choose exactly one decision, and phase-loop handoffs
86
+ preserve the same decision for downstream routing.
87
+
88
+ Required fields:
89
+
90
+ - `schema`: `spec_delta_closeout.v1`
91
+ - `decision`: one of `no_spec_delta`, `roadmap_amendment`,
92
+ `canonical_spec_update`, `governed_pipeline_refresh`,
93
+ `mirror_cutover_required`, `dotfiles_skill_source_update`, or
94
+ `human_source_judgment_required`
95
+ - `target_surfaces`: repo-relative paths or globs describing the spec surfaces
96
+ affected or intentionally deferred
97
+ - `evidence_paths`: repo-relative metadata evidence, such as a phase plan,
98
+ lane closeout, verification log, or runner artifact
99
+ - `redaction_posture`: `metadata_only`
100
+ - `blocker_class`: optional frozen blocker class when the decision cannot be
101
+ completed automatically
102
+
103
+ The frozen target-surface vocabulary for dotfiles-hosted harness spec work is
104
+ `shared/phase-loop/protocol.md`, `vendor/phase-loop-runtime/protocol/protocol.md`,
105
+ `vendor/phase-loop-runtime/src/phase_loop_runtime/baml_src/emit_phase_closeout.baml`,
106
+ `codex-config/skills/**`, `claude-config/claude-skills/**`,
107
+ `gemini-config/skills/**`, `opencode-config/skills/**`,
108
+ `vendor/phase-loop-skills/**`, and `vendor/phase-loop-runtime/tests/**`.
109
+
110
+ `metadata_only` allows repo-relative paths, hashes, phase aliases, IF gates,
111
+ decision literals, artifact names, and redacted diagnostics. It forbids raw
112
+ specs, raw patch bodies, credentials, provider-supplied payloads, local environment values, and
113
+ inferred reads from ignored/private/raw evidence sources. Standalone dotfiles
114
+ phase-loop runs may emit `no_spec_delta` or `dotfiles_skill_source_update`
115
+ without Governed Pipeline, `.pipeline/**`, Portal contracts, ReGenesis files,
116
+ credentials, PMCP, owner shell setup, or sibling repo writes. Decisions that
117
+ require Governed Pipeline ingest, mirror cutover, or human source judgment are
118
+ metadata-only downstream routing signals, not dotfiles write authorization.
119
+
120
+ Missing or malformed spec-delta closeout evidence is a repairable automation
121
+ blocker with `blocker_class=contract_bug` unless the phase explicitly chooses
122
+ `human_source_judgment_required`, in which case the closeout must name the
123
+ non-secret human input required.
124
+
125
+ ## Plan-Doc-Current Heuristic
126
+
127
+ When a phase has been reopened to `planned`, the runner checks the current plan
128
+ document before dispatching another planning turn. The helper
129
+ `is_plan_doc_current(repo, phase, plan, roadmap, recent_commit_window=50)` is
130
+ true only after `find_plan_artifact(repo, phase, roadmap=roadmap)` returns the
131
+ same roadmap-matching plan path and the plan either appears in
132
+ `git log --name-only -n 50 -- <plan>` or its frontmatter includes a non-empty
133
+ `last_generated` field.
134
+
135
+ For `phase-loop run`, `phase-loop resume`, and `phase-loop dry-run`, a reopened
136
+ `planned` phase with a current plan document dispatches execution directly by
137
+ default. Operators can pass `--force-replan` to bypass this heuristic and launch
138
+ the planning turn even when the plan document is current.
139
+
140
+ The skip is auditable but non-terminal. Before launching execution, the runner
141
+ appends an event with `status: plan_skipped` and
142
+ `metadata.plan_doc_skip` containing `reason: plan_doc_current`, the
143
+ repo-relative `plan_artifact`, and `forced_replan: false`.
144
+ `plan_skipped` is valid only through `EVENT_STATUSES`; it must never be added
145
+ to `PHASE_STATUSES`, `automation.status`, closeout `terminal_status`, or
146
+ reducer phase-state outputs.
147
+
148
+ ## Run Loop Mode
149
+
150
+ `phase-loop run` and `phase-loop resume` count `--max-phases N` as dispatched actions by default.
151
+ This preserves the legacy behavior: `--max-phases 1`
152
+ launches exactly one child action, so an unplanned phase launches planning and
153
+ stops before the later execute action.
154
+
155
+ `--full-phase` changes the counting unit from dispatched actions to complete phase cycles.
156
+ In full-phase mode, `--max-phases 1 --full-phase` keeps dispatching
157
+ within the selected phase until one plan-plus-execute cycle reaches `complete`,
158
+ `blocked`, `awaiting_phase_closeout`, or another no-launch terminal state. A
159
+ phase that already has a current plan can skip planning through the
160
+ `plan_skipped` path and count the following execute launch as one complete phase
161
+ cycle. `--max-phases 2 --full-phase` completes two such phase cycles when the
162
+ roadmap has two ready phases.
163
+
164
+ Existing operators who rely on action-count behavior should keep using
165
+ `--max-phases` without `--full-phase`. Operators who intend complete phase
166
+ cycles should add `--full-phase`. When `--max-phases` is explicitly supplied
167
+ without `--full-phase`, the runner may emit a non-blocking legacy-unit hint once
168
+ per run session. `--no-deprecation-hints` suppresses that hint for `run` and
169
+ `resume`.
170
+
171
+ `PIPELINE_PROTECTED_SOURCE_CATEGORIES` freezes the protected source vocabulary
172
+ for Pipeline bridge work:
173
+
174
+ - `specs` - Pipeline specs.
175
+ - `diagrams` - Pipeline diagrams.
176
+ - `adapter_config` - Pipeline adapter config.
177
+ - `definition_files` - Pipeline definition files, including
178
+ `pipeline.definition.json`.
179
+ - `portal_contracts` - Portal contracts.
180
+ - `phase_artifacts` - Pipeline phase artifacts.
181
+
182
+ Protected-source categories remain high-level. Canonical spec adoption semantics
183
+ are expressed through optional protected-source role metadata, not by adding
184
+ new categories or making dotfiles the adoption authority.
185
+ `PIPELINE_PROTECTED_SOURCE_ROLES` freezes the adoption-sensitive role
186
+ vocabulary that source bundles may attach to protected-source entries:
187
+
188
+ - `seed_spec`
189
+ - `predecessor_spec`
190
+ - `active_canonical_spec`
191
+ - `archived_spec`
192
+ - `managed_mirror_file`
193
+ - `unmanaged_spec_input`
194
+ - `legacy_specs_bundle`
195
+ - `root_specs_intake`
196
+ - `pipeline_specs_canonical`
197
+ - `adapter_configured_intake_root`
198
+ - `mirror_manifest`
199
+ - `archive_manifest`
200
+
201
+ The upstream canonical adoption config keys are metadata-only bridge terms:
202
+ `canonical_sources.adoption_mode`,
203
+ `canonical_sources.active_canonical_root`, `canonical_sources.mirror_root`,
204
+ `canonical_sources.archive_manifest_path`,
205
+ `canonical_sources.spec_intake_roots`, and
206
+ `canonical_sources.legacy_seed_roots`. The adoption mode literals are
207
+ `track_existing`, `greenfield_single_spec`, `greenfield_spec_bundle`, and
208
+ `brownfield_existing_specs`.
209
+
210
+ Standalone `phase_loop_plan_version: 1` plans remain valid without Pipeline or
211
+ canonical adoption metadata. A pipeline-required source bundle that declares
212
+ role metadata as required must fail closed with a repairable non-human
213
+ `contract_bug` diagnostic when an adoption-sensitive role is missing, stale,
214
+ malformed, unknown, or cannot be represented in closeout metadata.
215
+
216
+ Phase-loop planners and executors may read protected sources when the selected
217
+ source bundle authorizes that context, but they must not mutate Pipeline-owned
218
+ protected sources by inference. Any Pipeline-owned write must be explicit in the
219
+ bundle policy and in the phase-plan owned-file contract.
220
+
221
+ ## Handoff Storage
222
+
223
+ Workflow skill handoffs are stored in repo-local generated state under
224
+ `.dev-skills/handoffs/<skill-name>/`. The canonical latest pointer for a skill
225
+ is resolved by `shared/phase-loop/handoff_path.py` through
226
+ `resolve_handoff_path(repo, skill_name)` and points to
227
+ `.dev-skills/handoffs/<skill-name>/latest.md`. The resolver returns a `Path`
228
+ only; callers create directories and write content.
229
+
230
+ `phase-loop migrate-handoffs [--dry-run | --apply] [--json]` is the hard-cut
231
+ migration command. It scans legacy Claude, Codex, Gemini, and OpenCode skill
232
+ handoff roots, selects only handoffs whose frontmatter matches the current
233
+ repo, and emits metadata-only records with `skill_name`, `source`, `target`,
234
+ `action`, and `status`. Dry-run mode reports planned moves without mutation.
235
+ Apply mode moves matching `latest.md` files and timestamped siblings into the
236
+ repo-local directory and is idempotent when the target already has matching
237
+ content.
238
+
239
+ Apply mode is guarded by `_quiesced(repo)`. The guard succeeds only when
240
+ `.phase-loop/state.json` has no in-flight phase states, `.phase-loop/events.jsonl`
241
+ has no recent action except `closeout` or `manual_repair`, and no
242
+ `.phase-loop/*.lock` file exists. A failed quiescence check reports the first
243
+ blocker condition and performs no moves.
244
+
245
+ Legacy harness handoff roots are read only for migration after this cutover.
246
+ Reflections remain in harness-specific `reflections/` trees and are not moved
247
+ by HANDOFFS. The root `.gitignore` excludes `/.dev-skills/` so migrated or newly
248
+ written handoffs do not become source artifacts.
249
+
250
+ ## Ledger Debug
251
+
252
+ `phase-loop status --ledger-debug` is a read-only operator diagnostic surface
253
+ for reducer-rejected ledger events. The flag belongs only to the `status`
254
+ subcommand. Default text status output remains unchanged without the flag:
255
+ operators still see only the existing `Ledger warnings: N` summary when warning
256
+ records exist.
257
+
258
+ With `--ledger-debug`, text status appends a `Rejected events` section after
259
+ the ledger warning count. Each row reports the rejected event phase, timestamp,
260
+ action, status, canonical reason, and a redacted `raw_event_summary`.
261
+
262
+ The same debug mode then appends `Duplicates skipped`. This section reports
263
+ events that matched an earlier event in the same reconcile call and were not
264
+ processed again. The zero-duplicate case is explicit as `none`.
265
+
266
+ `phase-loop status --json --ledger-debug` adds a top-level
267
+ `rejected_events` array:
268
+
269
+ ```json
270
+ [
271
+ {
272
+ "phase": "RUNNER",
273
+ "timestamp": "2026-05-23T00:00:00Z",
274
+ "action": "execute",
275
+ "status": "complete",
276
+ "reason": "provenance_mismatch",
277
+ "raw_event_summary": {
278
+ "schema_version": 2,
279
+ "source": "fixture",
280
+ "phase": "RUNNER",
281
+ "action": "execute",
282
+ "status": "complete",
283
+ "timestamp": "2026-05-23T00:00:00Z",
284
+ "roadmap_sha256_present": true,
285
+ "phase_sha256_present": true
286
+ }
287
+ }
288
+ ]
289
+ ```
290
+
291
+ The JSON field is present as `[]` in debug mode when there are no rejected
292
+ events, and absent from default JSON status output.
293
+
294
+ Debug JSON also adds `duplicates_skipped` as `[]` or as records with phase,
295
+ timestamp, action, status, automation_status, blocker_class, duplicate_key, and
296
+ redacted raw_event_summary. The field is absent from default JSON output.
297
+
298
+ The frozen ledger-debug rejection reasons are:
299
+
300
+ - `provenance_mismatch`
301
+ - `phase_missing`
302
+ - `not_in_allowed_status_set`
303
+ - `legacy_pre_schema_v2`
304
+ - `planned_without_plan_artifact`
305
+ - `blocker_supersession`
306
+
307
+ The `raw_event_summary` is an event identity summary only. It may include
308
+ schema version, source, phase, action, status, timestamp, and whether roadmap
309
+ or phase hashes were present. It must not serialize raw event payloads,
310
+ provider output, prompts, local environment contents, credentials, or arbitrary
311
+ nested metadata.
312
+
313
+ Ledger Debug is diagnostic-only. It does not repair, rewrite, or reclassify
314
+ historical events. After reading the debug output, operators continue to use
315
+ the existing reconcile, reopen, manual repair, or roadmap amendment workflows.
316
+ Persistent rejection logs and automatic repair are out of scope for this
317
+ surface.
318
+
319
+ ## Ledger Dedup
320
+
321
+ Each `reconcile(repo, roadmap)` call performs an in-memory duplicate pass over
322
+ normalized automation events after roadmap filtering and before validation or
323
+ phase-state mutation. The duplicate key is:
324
+
325
+ ```text
326
+ (timestamp, phase, action, status, automation_status, blocker_class)
327
+ ```
328
+
329
+ `phase` is uppercased before comparison. `automation_status` and
330
+ `blocker_class` are read from top-level event fields when present, otherwise
331
+ from nested automation, child_automation, terminal summary, or blocker metadata.
332
+
333
+ Dedup is first-event-wins. The first event for a key is processed normally.
334
+ Subsequent events with the same key do not append ledger warnings, do not update
335
+ phase state, do not replace closeout summaries, and are recorded on
336
+ `StateSnapshot.ledger_duplicates_skipped` in encounter order. The ledger itself
337
+ is never rewritten or truncated.
338
+
339
+ This de-noises repeated identical events only. Rejected non-duplicate events
340
+ remain visible under `Rejected events`, and genuine provenance, status, schema,
341
+ planned-artifact, or blocker-supersession warnings still contribute to
342
+ `Ledger warnings: N`. Ledger Dedup extends the v25 LEDGERDEBUG operator surface;
343
+ it does not repair historical event content.
344
+
345
+ ## Skills Bundle
346
+
347
+ The harness-neutral workflow skill source bundle lives at
348
+ `vendor/phase-loop-skills/`. Base source directories are unprefixed:
349
+ `execute-phase`, `plan-phase`, `plan-detailed`, `phase-roadmap-builder`,
350
+ `phase-loop`, `skill-editor`, `skill-improvement-planner`, and
351
+ `task-contextualizer`. Installed names retain the harness prefix, for example
352
+ `codex-execute-phase` and `claude-plan-phase`.
353
+
354
+ Harness-specific differences are escape hatches, not a second source tree.
355
+ Per-harness overlays live under
356
+ `vendor/phase-loop-skills/<skill-name>/_overrides/<harness>/` and are layered
357
+ over the unprefixed source during installation. Operators author those overlay
358
+ files explicitly; the installer does not auto-generate operator-authored
359
+ exceptions.
360
+
361
+ `phase_loop_runtime.skill_paths` exposes the resolver API used by workflow
362
+ skills and installers:
363
+
364
+ - `current_harness(harness: str | None = None) -> str`
365
+ - `resolve_skill_bundle_root(harness: str | None = None) -> Path`
366
+ - `resolve_skill_helper_root(harness: str | None = None) -> Path`
367
+ - `resolve_handoff_root(repo: Path) -> Path`
368
+ - `resolve_reflection_root(skill_name: str, harness: str | None = None) -> Path`
369
+
370
+ Resolver precedence is explicit function argument, `PHASE_LOOP_HARNESS`,
371
+ `PHASE_LOOP_SKILL_BUNDLE`, then the documented harness defaults:
372
+ `~/.claude/skills`, `~/.codex/skills`, `~/.gemini/skills`, and
373
+ `~/.config/opencode/skills`. Handoffs resolve to repo-local
374
+ `.dev-skills/handoffs/`; reflections remain under the selected harness skill
375
+ root.
376
+
377
+ `phase-loop install --harness {claude,codex,gemini,opencode}
378
+ [--source <bundle-path>] [--destination <install-root>] [--symlink|--copy]
379
+ [--dry-run|--apply]` is the metadata-only install surface. Dry-run mode reports
380
+ planned source, destination, harness, skill name, install mode, and action
381
+ without mutating destinations. Apply mode is idempotent and installs
382
+ harness-prefixed workflow skills from `vendor/phase-loop-skills/`.
383
+
384
+ `phase-loop install --status --json` is a read-only runtime visibility surface.
385
+ It never installs, replaces, copies, symlinks, deletes, or rewrites skill files.
386
+ The JSON reports per-harness skill parity, console-script availability, BAML
387
+ closeout schema availability, and `.dev-skills/` ignore readiness using
388
+ symbolic metadata only.
389
+
390
+ ## Operating Modes
391
+
392
+ The phase-loop runner supports three operating modes:
393
+
394
+ - `standalone`: local dotfiles execution. A `phase_loop_plan_version: 1` plan
395
+ with only the required `phase`, `roadmap`, and `roadmap_sha256` fields
396
+ remains valid without Pipeline metadata. Standalone runs do not require
397
+ governed-pipeline, `.pipeline/**`, Portal, Greenfield, or a source bundle.
398
+ - `pipeline_optional`: dotfiles may consume supplied Pipeline metadata and
399
+ source-bundle context when present, but missing Pipeline metadata does not
400
+ invalidate the standalone plan contract.
401
+ - `pipeline_required`: execution must fail closed before child launch when
402
+ validated Pipeline context is missing, stale, malformed, or mismatched.
403
+
404
+ Pipeline-required execution requires a validated `source_bundle`,
405
+ `source_bundle_sha256`, `pipeline_phase_id`, bundle freshness, protected-source
406
+ entries, and protected-source hash checks before execution. When
407
+ `freshness.source_bundle_hash` is a SHA-256 digest, it must match the source
408
+ bundle bytes. Protected-source entries must cite one of
409
+ `PIPELINE_PROTECTED_SOURCE_CATEGORIES`, and protected-source files must exist
410
+ with matching SHA-256 hashes.
411
+
412
+ Governed Pipeline owns adoption, source-bundle emission, canonical refresh,
413
+ replan, closeout ingest, Greenfield reduction, and Portal projection.
414
+ Governed-pipeline owns canonical source-truth refresh, source-bundle emission,
415
+ protected-source freshness, scheduling, closeout ingest, Greenfield reduction,
416
+ and Portal projection. Dotfiles consumes those inputs and emits redacted
417
+ metadata; it does not infer authority over governed-pipeline, Portal,
418
+ Greenfield, `.pipeline/**`, private evidence, raw data, credentials, or
419
+ provider-supplied payloads. Host bootstrap, Shell config, SSH setup, MCP gateway setup,
420
+ generic 1Password setup, raw-evidence, credential-bearing payloads, and local
421
+ environment values are outside the protocol substrate.
422
+ Governed-pipeline also owns canonical spec adoption, archive creation, managed
423
+ mirror refresh, source-truth reconciliation, canonical refresh, replan, and
424
+ preflight block decisions. Dotfiles may echo validated adoption role metadata
425
+ and advisory hints in closeout, but it must not make archive, mirror,
426
+ canonical refresh, replan, or block decisions.
427
+
428
+ ## Dotfiles Source And Visibility Contracts
429
+
430
+ Dotfiles source authority for governed-pipeline adoption is frozen in
431
+ `docs/dotfiles-source-authority-contract.md`. That document classifies every
432
+ top-level path with `path_glob`, `classification`, `owner`,
433
+ `ingestion_policy`, and rationale. Governed-pipeline may pull paths classified
434
+ as `authority`; it must reject `derived`, `runtime_state`, `private`, and
435
+ `out_of_scope` paths as adoption source material.
436
+
437
+ Dotfiles cross-repo visibility is frozen in
438
+ `docs/dotfiles-visibility-contract.md`. That contract exposes only adoption
439
+ inputs, redacted runtime metadata, and the operating-mode declaration. The
440
+ surface is pull-only: dotfiles does not push into governed-pipeline or Portal,
441
+ governed-pipeline must not write into dotfiles, consumers must not depend on
442
+ runtime state paths, and BAML schema contracts must be imported rather than
443
+ paraphrased.
444
+
445
+ ## Dotfiles Schema Pack
446
+
447
+ The dotfiles BAML schema pack lives under
448
+ `vendor/phase-loop-runtime/src/phase_loop_runtime/baml_src/` and freezes the direct import contracts
449
+ for downstream consumers. The authority class names are
450
+ `DotfilesAdoptionManifest`, `DotfilesRuntimeProjection`,
451
+ `DotfilesC4Document`, and `DotfilesTaskCatalog`.
452
+
453
+ Consumers import the `.baml` contracts directly or use
454
+ `phase_loop_runtime.baml_modular.export_function_schema(<class name>)` for a
455
+ dialect-clean JSON Schema projection. Protocol prose may describe the pack and
456
+ its consumers, but it must not paraphrase full field definitions as an
457
+ alternate schema source. `DotfilesAdoptionManifest` is the governed-pipeline
458
+ pull manifest shape, `DotfilesRuntimeProjection` is the redacted runtime
459
+ visibility shape, `DotfilesC4Document` carries Markdown/Mermaid source for
460
+ deterministic rendering, and `DotfilesTaskCatalog` carries audience-tagged task
461
+ entries.
462
+
463
+ After DOTADOPT, `docs/adoption/dotfiles-adoption-bundle.json` is the canonical
464
+ governed-pipeline pull-only ingestion target for dotfiles. The fixture is
465
+ generated by `generate_adoption_bundle`, validates as
466
+ `DotfilesAdoptionManifest`, and carries `sha256` digests for imported `.baml`
467
+ schema sources. This handoff does not produce canonical HTML, rendered Mermaid,
468
+ Portal views, governed-pipeline files, archives, mirrors, or any alternate
469
+ schema authority; the `.baml` files remain the schema source of truth.
470
+
471
+ ### Adoption Bundle Lifecycle
472
+
473
+ The runtime exposes `phase-loop adoption-bundle status --repo <path>` to compare
474
+ current `vendor/phase-loop-runtime/src/phase_loop_runtime/baml_src/*.baml` digests with
475
+ `docs/adoption/dotfiles-adoption-bundle.json`. It exits `0` when fresh, `1`
476
+ when stale, and `2` when the bundle or schema contract cannot be loaded.
477
+ `phase-loop adoption-bundle refresh --repo <path>` regenerates that JSON bundle
478
+ through `generate_adoption_bundle`, preserving the committed fixture metadata
479
+ for `generated_at` and `operating_mode`; it exits `0` after a successful
480
+ refresh or idempotent no-op and `1` when regeneration fails.
481
+
482
+ `.githooks/pre-commit-adoption-bundle` is the optional local automation path.
483
+ When staged BAML files are present it runs the status command, runs refresh only
484
+ for stale bundles, and stages `docs/adoption/dotfiles-adoption-bundle.json`
485
+ after a successful refresh. The hook is never installed by default; operators
486
+ opt in with `phase-loop init --install-hooks`.
487
+
488
+ In standalone mode, root `specs/**` is the default human-visible future-spec
489
+ discovery root when no phase plan, source bundle, or repo-local config
490
+ overrides it. Legacy or project-specific seed roots such as `Specs/**` are
491
+ explicit input roots only; accepted future specs should normalize toward root
492
+ `specs/**` for later governed-pipeline intake.
493
+
494
+ ## Dispatch Hints
495
+
496
+ Roadmaps and phase plans may include an optional markdown section named
497
+ `Dispatch Hints` without changing the required frontmatter contract. The parser
498
+ must treat this section as optional and fail closed when it is absent.
499
+
500
+ Supported keys:
501
+
502
+ - `preferred executors`
503
+ - `allowed executors`
504
+ - `fallback executors`
505
+ - `disabled executors`
506
+ - `required capabilities`
507
+
508
+ Supported action selectors:
509
+
510
+ - `roadmap`
511
+ - `plan`
512
+ - `execute`
513
+ - `repair`
514
+ - `review`
515
+ - `maintain-skills`
516
+
517
+ Accepted forms:
518
+
519
+ ```markdown
520
+ ## Dispatch Hints
521
+ - preferred executors: `codex`
522
+ - allowed executors: `codex`, `claude`
523
+ - fallback executors: `codex`
524
+ - disabled executors: `manual`
525
+ - required capabilities: `live_launch`, `structured_output`
526
+ - execute preferred executors: `codex`
527
+ - review allowed executors: `codex`, `claude`
528
+ ```
529
+
530
+ or action-grouped subsections such as:
531
+
532
+ ```markdown
533
+ ## Dispatch Hints
534
+ ### Default
535
+ - preferred executors: `codex`
536
+
537
+ ### Review
538
+ - allowed executors: `codex`, `claude`
539
+ ```
540
+
541
+ Dispatch hint precedence is:
542
+
543
+ 1. operator / CLI override
544
+ 2. phase-plan hints
545
+ 3. roadmap hints
546
+ 4. registry defaults
547
+
548
+ Disabled executors and required capabilities remain conservative filters: they
549
+ must not be silently ignored when a preferred executor conflicts with them.
550
+
551
+ ## Planner Validation
552
+
553
+ Planner skills validate emitted plan-document literals before writing a plan
554
+ artifact. The shared entrypoint is
555
+ `phase_loop_runtime.planner_validation.validate_plan_dispatch_hints(plan_text,
556
+ *, dispatch_capabilities=None, executors=None, product_loop_actions=None)`.
557
+ It returns metadata-only `ValidationFinding` records with `field_path`,
558
+ `literal`, `allowed_values`, and `suggested_fix`; it never writes files, mutates
559
+ runner state, prints output, or raises on invalid plan text.
560
+
561
+ The validator defaults to `DISPATCH_CAPABILITIES`, `EXECUTORS`, and
562
+ `PRODUCT_LOOP_ACTIONS` from `phase_loop_runtime.models`. It checks
563
+ `Dispatch Hints` executor and required-capability literals, `Execution Policy`
564
+ selectors and executor assignments, and closeout example literals for
565
+ `terminal_status`, `verification_status`, and `blocker_class`. Markdown body
566
+ content outside those planner-emitted protocol surfaces is not validated.
567
+
568
+ Planner skills must call the validator after the complete draft exists and
569
+ before the project-path plan document is written. A finding blocks the write and
570
+ surfaces a validation_failed closeout with `terminal_status=blocked`,
571
+ `verification_status=blocked`, `blocker_class=contract_bug`,
572
+ `human_required=false`, and a non-secret summary of the findings. This is a
573
+ source-side guard: v24 CLOSEOUTHARDEN remains the runtime soft-fail layer for
574
+ child executor closeout drift, and neither layer coerces unknown literals into
575
+ nearby valid statuses.
576
+
577
+ ## Execution Policy
578
+
579
+ Roadmaps and phase plans may include an optional `## Execution Policy` section
580
+ when executor selection also needs model, effort, work-unit defaults, fallback,
581
+ or policy source provenance. Existing artifacts do not need this section.
582
+ `Dispatch Hints` remain valid and are the executor-only fallback surface when no
583
+ execution policy is present.
584
+
585
+ The accepted syntax is line-oriented markdown:
586
+
587
+ ```markdown
588
+ ## Execution Policy
589
+ - work-unit defaults: work-unit=`lane_execute`, effort=`medium`, unsupported=`inherit_default`, inherit-default=`true`
590
+ - execute: executor=`pi`, model=`auto`, effort=`medium`, work-unit=`lane_execute`, reason=`simple bounded lane default`
591
+ - repair: executor=`claude`, model=`claude-opus-4-8`, effort=`high`, work-unit=`repair`
592
+ - SL-2: executor=`gemini`, model=`phase-loop-execute-medium`, effort=`medium`, work-unit=`lane_execute`, unsupported=`fallback`, fallback=`phase-loop-execute-medium`
593
+ ```
594
+
595
+ Supported selectors are `work-unit defaults`, `roadmap`, `plan`, `execute`,
596
+ `repair`, `review`, `maintain-skills`, and lane-specific selectors such as
597
+ `SL-2`. Lane-specific policy only resolves metadata for that lane; POLICYDSL
598
+ does not schedule lane work units.
599
+ Reducer and verification lanes use lane selectors with
600
+ `work-unit=phase_reducer` or `work-unit=phase_verify`; invented action
601
+ selectors such as `reduce` and `verify` are invalid.
602
+
603
+ Execution policy precedence is frozen as:
604
+
605
+ 1. CLI/operator override
606
+ 2. phase-plan policy
607
+ 3. roadmap policy
608
+ 4. `Dispatch Hints`
609
+ 5. registry defaults
610
+
611
+ The resolver must record policy source and override reason for model, effort,
612
+ executor, and fallback decisions. Invalid model, effort, work-unit, fallback, or
613
+ silent downgrade cases fail closed unless explicit fallback or default
614
+ inheritance is recorded.
615
+
616
+ A plan or roadmap whose `## Execution Policy` block fails to parse is recorded
617
+ as a `contract_bug` blocker carrying `path:line_number` and the offending raw
618
+ line, surfaced through `phase-loop status` and `phase-loop handoff`. The runner
619
+ stays alive and exits with code `5` (blocked), distinct from `1` (child launch
620
+ failure) and `0` (success), so operator rotation wrappers can branch on the
621
+ exit code instead of grepping stdout for `Terminal status: blocked`.
622
+
623
+ `phase-loop status --json` exposes `pipeline_mode` at the top level and the
624
+ resolved per-phase execution policy under an `execution_policy` block keyed by
625
+ phase alias, with sub-keys for `plan`, `execute`, `repair`, and `review`. Each
626
+ sub-key reports the resolved `executor`, `model`, `effort`, and `source`
627
+ (`phase-plan policy` or `roadmap policy`). Rotation wrappers consult this block
628
+ to pre-resolve executor pins before dispatching, avoiding the per-phase
629
+ `sandbox_command_restriction` failures that arise when an external rotation
630
+ pushes an executor that the plan policy pins to a different harness.
631
+
632
+ `phase-loop status --runtime-projection --json` emits the
633
+ `DotfilesRuntimeProjection` shape. The projection maps the selected
634
+ `pipeline_mode` to `operating_mode`, validates the emitted JSON through the BAML
635
+ schema parser, and must not include absolute host paths, secret references,
636
+ environment values, provider tokens, or local account identifiers. The surface
637
+ is standalone-first: it works without governed-pipeline, a source bundle,
638
+ Portal, Greenfield, or any acknowledged Pipeline contract.
639
+
640
+ ## Start Gate
641
+
642
+ Before `run`, `resume`, or `dry-run` dispatches planning, execution, lane
643
+ scheduling, work-unit mode, repair, closeout, or `launch_with_spec`, the runner
644
+ performs a cross-phase dirty start gate. The gate scans at most the last 50
645
+ ledger events, ignores malformed events and same-phase evidence, keeps the
646
+ latest dirty evidence per prior phase, and intersects `phase_owned_dirty_paths`
647
+ plus `previous_phase_owned_paths` with current git dirty paths.
648
+
649
+ When an overlap remains dirty, the runner refuses dispatch and appends
650
+ `start_gate_refused` with `blocker_class=dirty_worktree_conflict` and
651
+ `metadata.start_gate.status=refused`. The metadata names the current phase, the
652
+ offending phase, `last_event_timestamp`, `overlapping_dirty_paths`,
653
+ `scanned_events`, and operator `next_actions`: commit or stash the paths, or run
654
+ `phase-loop reconcile --phase <ALIAS> --to-status planned --reason <text>` to
655
+ record `manual_recovery` for stale dirty-state blockers. The terminal summary
656
+ is blocked and the refusal does not launch a child process.
657
+
658
+ Operators may pass `--allow-cross-phase-dirty <reason>` to `phase-loop run`,
659
+ `phase-loop resume`, or `phase-loop dry-run`. The reason is required and the
660
+ runner appends audited `metadata.start_gate.status=bypassed` before continuing.
661
+ The bypass is limited to this STARTGATE check: it does not mark verification
662
+ passed, perform recovery, auto-commit output, or bypass dirty-worktree,
663
+ Pipeline, access, repair, executor-policy, or launch blockers.
664
+
665
+ ## Reconcile Command
666
+
667
+ `phase-loop reconcile` has two distinct modes.
668
+
669
+ Completion reconcile:
670
+
671
+ `phase-loop reconcile --phase <ALIAS> [--closeout-commit <SHA>]
672
+ [--repair-summary <text>] [--verification-status passed]
673
+ [--verification-log <path>] [--recovery-mode]`
674
+
675
+ This synthesizes a v28-shape `manual_repair` event for the named phase,
676
+ recording the current `HEAD` (or the supplied SHA) as the closeout commit and
677
+ marking `clears_blocker=true`. It then re-reconciles so `phase-loop status`
678
+ reflects the cleared blocker.
679
+
680
+ The command refuses if the working tree is dirty (override with
681
+ `--allow-dirty`) so the synthesized event always references a clean closeout
682
+ commit. This compresses the post-`dirty_worktree_conflict` recovery ritual —
683
+ manually authoring the v28 P3/P4 event shape and appending to events.jsonl —
684
+ to one CLI call. Use only as a recovery tool when the executor's work is
685
+ correct but ownership classification or lane-evidence gaps left the runner
686
+ blocked; do not use to bypass legitimate verification failures.
687
+
688
+ When completion reconcile uses `--verification-status passed`, it must also
689
+ provide `--verification-log <path>` pointing at the runner-owned
690
+ `verification.json` artifact for the run. The runner validates the artifact
691
+ schema, the sibling `verification.log` SHA-256 against `log_sha256`, and every
692
+ command, env-refresh, and suite exit code before appending a completion repair
693
+ event. Remediation output and event metadata include only the artifact path,
694
+ validation code, and exit summary; raw verification log output is never copied
695
+ into reconcile metadata.
696
+
697
+ Blocked-state recovery:
698
+
699
+ `phase-loop reconcile --phase <ALIAS> --to-status planned --reason <text>`
700
+
701
+ This is an explicit blocked-state recovery transition. It is for stale
702
+ non-human dirty-state blockers only, and it records an auditable
703
+ `manual_recovery` event with `from=blocked`, `to=planned` or `to=unplanned`,
704
+ `trigger=cli`, `clears_blocker=true`, and `verification_status=not_run`.
705
+ It does not mark verification passed and is mutually exclusive with
706
+ `--verification-status passed`.
707
+
708
+ Recovery is allowed only when the selected phase currently reconciles as
709
+ `blocked` and the blocker is dirty-state-derived, such as
710
+ `dirty_worktree_conflict`, phase-owned dirty output, previous-phase-owned dirty
711
+ output, or stale dirty terminal metadata that no longer blocks current git
712
+ state. If a current plan artifact exists, replay reports the phase as
713
+ `planned`; if no current plan artifact exists, replay reports it as
714
+ `unplanned` so the operator can run the planning workflow again.
715
+
716
+ Sticky or human-required blockers are refused. This includes
717
+ `missing_secret`, `account_or_billing_setup`, `admin_approval`,
718
+ `product_decision_missing`, and `destructive_operation`. Access, product,
719
+ destructive, contract, repeated-verification, and unknown blockers require
720
+ explicit dirty-state evidence before recovery can clear stale blocker fields.
721
+
722
+ ### Recovery Mode
723
+
724
+ `phase-loop reconcile --recovery-mode` is for recovery states where the operator
725
+ intentionally needs to reconcile while the worktree is dirty. It implies the
726
+ dirty-tree override, records `manual_repair.recovery_mode=true`, and requires
727
+ explicit `--closeout-commit`, `--repair-summary`, and `--verification-status`
728
+ arguments so the audit trail does not silently inherit defaults.
729
+
730
+ Use recovery mode for parallel-race recovery when a plan doc or other recovery
731
+ artifact is dirty because another runner already produced the phase-owned
732
+ output; the repair summary should state which runner or closeout created the
733
+ dirty path. Use it for stale-event recovery when a clean closeout event exists
734
+ but the active status still reflects an older blocked event. Use it for a
735
+ manual-repair flow only after the operator has verified the repair and can name
736
+ the commit and verification result. Recovery mode does not replace legitimate
737
+ verification repair; failed verification still requires repair or a blocked
738
+ closeout, not a reconciled completion.
739
+
740
+ ## Reopen Command
741
+
742
+ `phase-loop reopen --phase <ALIAS> --reason <text> [--allow-dirty]` is the
743
+ symmetric counterpart to `reconcile`: where `reconcile` advances a `blocked`
744
+ phase to `complete`, `reopen` reverts a spurious `complete` phase back to
745
+ `planned`. Use when an executor reported a phase as complete +
746
+ `verification_status=passed` but the underlying IF gates were not actually
747
+ satisfied (e.g., a repair iteration that reported done with zero diff and no
748
+ real work).
749
+
750
+ The command appends a typed `phase_reopen` event with `status: planned` and
751
+ metadata `{reason, prior_status, prior_closeout_commit, reopen_commit}`. The
752
+ reducer recognizes `action: phase_reopen` and flips the phase back to
753
+ `planned` regardless of plan-artifact existence. Subsequent
754
+ `phase-loop run` invocations re-execute the phase.
755
+
756
+ Refuses if the phase is not currently `complete` (cannot reopen what isn't
757
+ closed). Refuses if the working tree is dirty (override with `--allow-dirty`)
758
+ so `reopen_commit` references a clean state. The `--reason` field is
759
+ required and recorded on the event for audit.
760
+
761
+ This command exists because the runner trusts the executor's reported
762
+ terminal status by default; if an executor hallucinates completion, the
763
+ runner has no way to independently verify the IF gates were satisfied. A
764
+ future "closeout-payload IF-gate cross-check" would prevent the bug at
765
+ emission time; `reopen` is the recovery path until that ships.
766
+
767
+ ## Evidence Audit Command
768
+
769
+ `phase-loop evidence-audit --repo . [--dirty-only|--full-tree|--full-tree-loose]
770
+ [--tier-2]` is an operator-callable spot-check for fake-evidence patterns in
771
+ dirty-tree artifacts. Run it before `phase-loop reconcile` on phases producing
772
+ comparison/verdict evidence (visual-fidelity diffs, audit reports, schema
773
+ validation traces).
774
+
775
+ Surfaced after the regen 2026-05-22 VISUALMATCH incident, where the
776
+ executor committed 21 artifact files that satisfied the v20 closeout
777
+ schema (terminal_status: complete, produced_if_gates populated, real
778
+ dirty_paths) but contained faked evidence: 19 "distinct" prototype
779
+ PNGs all shared one md5 hash; 19/19 similarity scores at exactly
780
+ 0.999999; boilerplate verdict markdown. v20's IF-gate Tier 1
781
+ validator (`closeout_validation.validate_produced_gates`) only checks
782
+ that produced gate names match plan `## Produces` names — it cannot
783
+ see evidence content. Operators must spot-check; `phase-loop
784
+ evidence-audit` codifies the spot-check.
785
+
786
+ Tier 1 detectors run by default:
787
+
788
+ - **`duplicate-content`** — N or more files share the same sha256.
789
+ Default threshold N=3 (`--min-duplicates`). Catches the placeholder-
790
+ duplicated pattern (e.g., the 19 identical PNGs).
791
+ - **`uniform-numeric`** — numeric arrays >= 4 elements (or object
792
+ arrays where every object has an identical numeric field) where all
793
+ values are within `--uniform-epsilon` (default 1e-6). Catches the
794
+ template-fill pattern (e.g., 19/19 entries at similarity=0.999999).
795
+ - **`missing-references`** — JSON artifacts cite path-shaped string
796
+ values that don't exist on disk. Default `--dirty-only` and `--full-tree`
797
+ scans use strict missing-reference mode: the string must have a known
798
+ data/artifact extension and appear under object key/value context that
799
+ names evidence, source, screenshot, fixture, path, reference, or artifact
800
+ material. `--full-tree-loose` is the loose forensic compatibility path; it
801
+ scans the full tree with the older liberal path-shaped string behavior.
802
+ The strict missing-reference default is calibrated to avoid code-string and
803
+ command false positives while still catching cited-but-never-created
804
+ evidence paths.
805
+
806
+ Tier 2 detectors are operator-invoked with `--tier-2`; default invocation
807
+ remains Tier 1 only. Runner closeout integration may also run Tier 2 as the
808
+ first fuzzy stage before a default-OFF Tier 3 check when closeout-time Tier 3
809
+ is explicitly enabled:
810
+
811
+ - **`loose-uniform`** — numeric arrays >= 4 elements (or object arrays
812
+ where every object has a common numeric field) whose coefficient of
813
+ variation is below `--loose-uniform-stdev-threshold` (default 1e-3).
814
+ Exact uniformity is left to the Tier 1 `uniform-numeric` detector and
815
+ is not double-reported as loose-uniform.
816
+ - **`boilerplate-text`** — text files with high non-path token overlap.
817
+ The detector normalizes whitespace and punctuation, lower-cases tokens,
818
+ strips path-shaped tokens, skips binary files, and reports groups with
819
+ overlap above `--boilerplate-token-overlap-threshold` (default 0.80)
820
+ and size at least `--boilerplate-min-group-size` (default 3). The default
821
+ threshold is calibrated against `tests/fixtures/evidence-audit-calibration/`:
822
+ known-fake boilerplate and templated prose fixtures must flag, known-real
823
+ fixtures must not flag, and borderline fixtures remain low-confidence Tier 2
824
+ uncertainty rather than Tier 1-style hard failures.
825
+ - **`size-distribution`** — sibling-directory file groups whose byte-size
826
+ coefficient of variation is below
827
+ `--size-distribution-variance-threshold` (default 0.05), with at least
828
+ `--size-distribution-min-group-size` files (default 3).
829
+
830
+ Text output renders Tier 2 findings with `tier2:` prefixes. JSON output
831
+ includes the `tier2_findings` object only when `--tier-2` is enabled.
832
+
833
+ Tier 3 is default OFF. Operator invocations use `phase-loop evidence-audit
834
+ --enable-tier-3`; runner closeout invocations use `phase-loop run
835
+ --enable-tier-3` or a per-phase config opt-in. The runner also accepts
836
+ `--tier-3-budget` and records `tier3_budget` and `tier3_calls_made` per
837
+ closeout invocation. The default budget is 3. When budget is exhausted,
838
+ remaining Tier 2 uncertain findings are recorded as
839
+ `UNCERTAIN-OPERATOR-REVIEW` without another Tier 3 call.
840
+
841
+ Tier 3 enables the `EvaluateSuspectedFakeEvidence` BAML call only for Tier 2
842
+ uncertain loose-uniform findings, after Tier 1 duplicate-content,
843
+ uniform-numeric, and missing-reference detectors do not already produce
844
+ suspect findings. Clean audits, Tier 1 suspect audits, and Tier 2
845
+ certain-suspect findings bypass Tier 3. For runner closeouts, a `fake`
846
+ verdict or a non-uncertain judgment below the effective confidence threshold
847
+ produces a non-human `contract_bug` blocker with `metadata.tier3_judgment`.
848
+ `real` at or above threshold proceeds. `uncertain`, timeout, parse failure,
849
+ or wrapper error emits warning metadata but does not automatically block.
850
+
851
+ The Tier 3 input contract is bounded: the wrapper sends a Tier 2 signal
852
+ summary, the sample artifact content truncated to 8192 bytes by default,
853
+ and expected artifact characteristics. The structured output is
854
+ `EvidenceJudgment` with `verdict`, `confidence`, `reasoning`, and
855
+ `specific_concerns`. On timeout or parse failure, the wrapper returns an
856
+ uncertain judgment with `confidence: 0.0` and redacted `tier3_call_error`
857
+ reasoning.
858
+
859
+ Every runner-triggered Tier 3 call appends an `evidence_audit_tier3` event to
860
+ `.phase-loop/events.jsonl`. Event metadata includes `prompt_sha256`,
861
+ `response_sha256`, `verdict`, `confidence`, `token_counts`, `latency_ms`, and
862
+ `estimated_cost_usd`, plus the active budget counters. Token counts and
863
+ estimated cost may be null when the current provider wrapper does not expose
864
+ usage details. The ledger shape is prepared for the downstream
865
+ `phase-loop status --tier-3-history` query surface.
866
+
867
+ Per-phase config is optional at `.phase-loop/evidence-audit.yaml`:
868
+
869
+ ```yaml
870
+ tier2_enabled: true
871
+ tier3_enabled: false
872
+ tier3_confidence_threshold: 0.85
873
+ phase_aliases_exclude_tier3:
874
+ - T2DETECTORS
875
+ - T3SCHEMA
876
+ - T3RUNNER
877
+ - T3VALIDATE
878
+ phases:
879
+ FUTUREPHASE:
880
+ tier2_enabled: true
881
+ tier3_enabled: true
882
+ tier3_confidence_threshold: 0.85
883
+ disable_detectors: []
884
+ ```
885
+
886
+ The shipped default excludes `T2DETECTORS`, `T3SCHEMA`, `T3RUNNER`, and
887
+ `T3VALIDATE` so v23 cannot trigger Tier 3 against itself even if an operator
888
+ sets the global flag. Malformed config is a repairable non-human
889
+ `contract_bug`.
890
+
891
+ Operator invocation example:
892
+
893
+ ```bash
894
+ phase-loop evidence-audit --repo . --enable-tier-3 --json
895
+ ```
896
+
897
+ Runner invocation example:
898
+
899
+ ```bash
900
+ phase-loop run --repo . --enable-tier-3 --tier-3-budget 3
901
+ ```
902
+
903
+ ### Enabling Tier 3
904
+
905
+ Operators must treat Tier 3 as an opt-in rollout path, not a default runner
906
+ mode. Before enabling it for a phase, run the non-secret calibration corpus:
907
+
908
+ ```bash
909
+ python3 tests/calibrate_tier3.py --dry-run
910
+ python3 tests/calibrate_tier3.py --confidence-threshold 0.85 --fail-on-accuracy-threshold 0.80
911
+ ```
912
+
913
+ The dry run validates fixture shape and expected outcomes without live LLM
914
+ calls. A live calibration run reports verdict, confidence, estimated token and
915
+ cost metadata, accuracy, borderline confidence distribution, recommended
916
+ confidence threshold, and total estimated cost. Use the same provider, model,
917
+ and temperature for reproducibility; confidence should normally remain within
918
+ +/-0.05 on the same fixtures.
919
+
920
+ Roll out one phase at a time through `.phase-loop/evidence-audit.yaml`, monitor
921
+ recent invocation summaries with `phase-loop status --tier-3-history`, and
922
+ rollback by disabling the phase entry if false positives, latency, or cost
923
+ exceed operator tolerance. The status-history surface only reports timestamp,
924
+ phase, verdict, confidence, cost, and latency; it must not expose raw prompts,
925
+ raw responses, artifact contents, or provider-supplied payloads.
926
+
927
+ The v23 `phase_aliases_exclude_tier3` entries for `T2DETECTORS`, `T3SCHEMA`,
928
+ `T3RUNNER`, and `T3VALIDATE` remain in place until v23 completes. Removing
929
+ those exclusions is a separate explicit operator opt-in.
930
+
931
+ Exit codes: 0 if clean (no findings), 5 if suspect findings present.
932
+ Use the exit code as a pre-reconcile gate:
933
+
934
+ ```bash
935
+ phase-loop evidence-audit --repo . && \
936
+ phase-loop reconcile --repo . --roadmap specs/phase-plans-vN.md \
937
+ --phase <ALIAS> ...
938
+ ```
939
+
940
+ ## Drift Audit Subcommand
941
+
942
+ `phase-loop closeout-drift-audit --repo . [--repo ../other] [--days 7]
943
+ [--scope closeout|all-events] [--json]` is an operator-callable pre-flight
944
+ for closeout literal drift. It scans `.phase-loop/runs/**/terminal-summary.json`
945
+ and closeout-class entries in `.phase-loop/events.jsonl`, compares
946
+ `terminal_status`, `verification_status`, `blocker_class`, executor literals,
947
+ and dispatch capabilities against the live allowlists imported from
948
+ `phase_loop_runtime.models`, and reports any literal not currently allowed.
949
+
950
+ Default scope is `closeout`. This is the normal closeout reconciliation gate
951
+ and restricts event-ledger scanning to closeout-class surfaces such as
952
+ terminal summaries, closeout metadata, automation metadata, manual repairs,
953
+ and reopen/reconcile events. `--scope all-events` is an explicit forensic mode
954
+ for wider event-ledger scans; it is not a replacement for the closeout-class
955
+ pre-flight gate.
956
+
957
+ Text output is stable for operator review: it includes the scope, days window,
958
+ cutoff timestamp, per-repo files/events scanned, malformed event counts, setup
959
+ diagnostics, and per-field literal drift sections. JSON output includes
960
+ `allowlists`, `repos`, `counts`, `drift`, and `setup_diagnostics`, so
961
+ `phase-loop closeout-drift-audit --repo . --json | python3 -m json.tool` is a
962
+ valid machine-readable smoke check.
963
+
964
+ Exit codes are:
965
+
966
+ - `0` when no drift or setup errors are found.
967
+ - `1` when drift is found, for example the recurring reproduction payload
968
+ `terminal_status: "dry_run"` without adding `dry_run` to `PHASE_STATUSES`.
969
+ - `2` when setup or input errors prevent a trustworthy scan, such as a missing
970
+ repo path, missing `.phase-loop` directory, invalid `--days`, or invalid
971
+ scope.
972
+
973
+ Example closeout gate:
974
+
975
+ ```bash
976
+ phase-loop closeout-drift-audit --repo . --days 7 --scope closeout && \
977
+ phase-loop reconcile --repo . --roadmap specs/phase-plans-vN.md \
978
+ --phase <ALIAS> ...
979
+ ```
980
+
981
+ Example cross-repo forensic scan:
982
+
983
+ ```bash
984
+ phase-loop closeout-drift-audit --repo . --repo ../governed-pipeline \
985
+ --days 14 --scope all-events --json
986
+ ```
987
+
988
+ ### Verified Dirty Closeout Auto-Recovery
989
+
990
+ When the runner has already performed a verified dirty closeout recovery, a
991
+ later `phase-loop status` reconciliation may supersede the stale non-human
992
+ blocker without requiring an operator-authored `manual_repair` event. The
993
+ current phase's latest trusted event must carry
994
+ `metadata.completion_dirty_worktree.reason:
995
+ verified_dirty_closeout_recovery`, a `metadata.closeout.closeout_commit`,
996
+ `metadata.terminal_summary.verification_status: passed`, and no
997
+ `metadata.completion_dirty_worktree.unowned_dirty_paths`.
998
+
999
+ The repository worktree must be clean before this reducer fires. A successful
1000
+ reduction marks the phase complete, clears blocker and dirty-path fields,
1001
+ preserves closeout summary metadata, and records the ledger warning reason
1002
+ `clean_verified_dirty_closeout_recovery_superseded_nonhuman_blocker`. Human
1003
+ blockers and unrelated blocker classes remain authoritative; this reducer only
1004
+ repairs stale non-human dirty-closeout blockers.
1005
+
1006
+ ### Executor Degradation Cache
1007
+
1008
+ Session-scoped executor degradation is stored at the canonical
1009
+ `.phase-loop/executor-degradation.json` path. There is no legacy
1010
+ `.codex/phase-loop/**` fallback for this sidecar. The JSON object is keyed by
1011
+ executor name, and each record has these fields: `since`, `ttl_seconds`,
1012
+ `demoted_to`, `reason`, `source_phase`, and `blocker_summary`. `demoted_to`
1013
+ is limited to `proof_gated` or `manual_only`.
1014
+
1015
+ `state_degradation.load_degradation(repo)` returns valid records and tolerates
1016
+ missing or corrupted files by returning `{}`. `record_degradation(repo,
1017
+ executor, reason, source_phase, blocker_summary, ttl_seconds,
1018
+ demoted_to="proof_gated")` validates `demoted_to` and writes with a temporary
1019
+ file plus `os.replace`. `active_degraded_executors(repo, *, now=None)` returns
1020
+ the TTL-filtered active executor set, and `clear(repo)` removes the sidecar
1021
+ idempotently. `phase-loop archive-state` does not move this cache, so session
1022
+ demotion can survive runtime ledger archival.
1023
+
1024
+ FOUND publishes this cache contract only. DISPATCH wires launcher emissions,
1025
+ dispatch filtering, and any future `--reset-capability` control.
1026
+
1027
+ ### Blocker Classification Heuristics
1028
+
1029
+ Metadata-only launcher preflight must report only redacted probe metadata:
1030
+ command availability, return code, byte counts, and boolean surface presence.
1031
+ It must not persist stdout or stderr excerpts. Missing login, token, or
1032
+ subscription signals classify as `account_or_billing_setup` with
1033
+ `suggested_ttl_seconds: 300` and `demoted_to: proof_gated`.
1034
+
1035
+ Capacity-like provider signals classify as `unretryable_external_outage` with
1036
+ `suggested_ttl_seconds: 1800` and `demoted_to: manual_only`. The frozen
1037
+ capacity patterns are `capacity`, `exhausted`, `rate.limit`, `503`, and
1038
+ `temporarily.unavailable`; `claude auth status` quota-like JSON is reduced
1039
+ through the same capacity path without storing credential or provider-supplied payload
1040
+ values.
1041
+
1042
+ ### Session Capability Degradation During Dispatch
1043
+
1044
+ `resolve_dispatch_decision(..., repo=...)` consults
1045
+ `active_degraded_executors(repo)` after live availability has been confirmed
1046
+ for a candidate and before selecting it. A session-degraded executor is skipped
1047
+ silently so a live fallback can run. If every otherwise viable live candidate
1048
+ is session-degraded, dispatch returns `blocked_reason:
1049
+ all_candidates_session_degraded` with a summary naming the action and no
1050
+ credential or provider-supplied payload values.
1051
+
1052
+ `phase-loop run --reset-capability`, `phase-loop resume --reset-capability`,
1053
+ and `phase-loop dry-run --reset-capability` clear only
1054
+ `.phase-loop/executor-degradation.json` before dispatch setup. They do not
1055
+ archive, rewrite, or reconcile `.phase-loop/state.json`,
1056
+ `.phase-loop/events.jsonl`, or legacy `.codex/phase-loop/**`.
1057
+
1058
+ ### Rotation
1059
+
1060
+ `phase-loop run`, `phase-loop resume`, and `phase-loop dry-run` accept
1061
+ `--rotate-executors <csv>`, `--rotation-mode <phase|work_unit>`, and
1062
+ `--rotation-on-policy-pin <skip|fallback-next>`. The rotation list uses executor
1063
+ names from the frozen executor vocabulary, trims whitespace, deduplicates in
1064
+ order, and fails closed with a non-human `contract_bug` blocker when the list is
1065
+ empty or contains an invalid executor.
1066
+
1067
+ Rotation injects the current cursor executor as an operator-layer preferred executor
1068
+ before `resolve_dispatch_decision(..., repo=...)`. It rotates only
1069
+ executors; model and effort still come from the profile and Execution Policy
1070
+ chain. Plan and roadmap Execution Policy pins remain higher precedence than
1071
+ rotation. A policy pin launches with its pinned executor regardless of cursor
1072
+ position.
1073
+
1074
+ `--rotation-mode phase` consumes rotation at phase launch boundaries.
1075
+ `--rotation-mode work_unit` consumes rotation at work-unit launch starts. A
1076
+ running phase or work unit keeps the executor selected at launch; rotation never
1077
+ switches an in-flight unit. `--rotation-on-policy-pin=skip` is the default and
1078
+ counts a policy pin as a consumed rotation turn. `fallback-next` preserves the
1079
+ cursor until the next non-pinned phase or work unit consumes it.
1080
+
1081
+ The accepted mode literals are `phase` and `work_unit`. The accepted
1082
+ policy-pin literals are `skip` and `fallback-next`.
1083
+
1084
+ Executor degradation remains the DISPATCH authority: candidates listed in
1085
+ `.phase-loop/executor-degradation.json` are excluded by the existing
1086
+ `active_degraded_executors(repo)` filter during final dispatch. Rotation does
1087
+ not read provider-supplied payloads or reimplement degradation. New launch events with a
1088
+ resolved dispatch decision stamp top-level `selected_executor`; old events
1089
+ without that field reduce identically.
1090
+
1091
+ Default harness policy is explicit. Simple bounded scheduler-assigned lane
1092
+ execution defaults to `executor=pi`; Claude or Anthropic model lanes default to
1093
+ Claude Code CLI unless a policy explicitly selects a Pi-wrapped Claude route
1094
+ and records the override reason. Codex and Gemini fallback routes are
1095
+ CLI-based, reason-coded, and must not silently switch to API-key command
1096
+ adapters.
1097
+
1098
+ ## Skill Namespace Contract
1099
+
1100
+ Harness-local workflow skills follow the `<harness>-<workflow>` pattern frozen
1101
+ in `docs/phase-loop/harness-skill-matrix.md`. The active harness families are
1102
+ Codex, Claude Code, Gemini CLI, and OpenCode. Direct Codex, direct Gemini, and
1103
+ direct OpenCode launcher routes remain compatibility-supported during this
1104
+ roadmap, while Claude Code continues to use the `claude -p` path.
1105
+
1106
+ Pi Agent role-style skills are explicit exceptions: `phase-loop-supervisor`,
1107
+ `phase-loop-repair`, and `phase-loop-closeout`. They are adapter roles, not a
1108
+ fifth unnormalized harness workflow family.
1109
+
1110
+ Governed-pipeline `.pipeline/skills/**` is a downstream product/runtime
1111
+ namespace outside dotfiles skill normalization. Dotfiles artifacts may mention
1112
+ canonical workflow skill names as bridge vocabulary, but dotfiles must not
1113
+ rewrite, rename, install, or validate governed-pipeline `.pipeline/skills/**`
1114
+ as `<harness>-<workflow>` skills.
1115
+
1116
+ ## Work-Unit Policy
1117
+
1118
+ WORKPOLICY freezes provider-neutral policy metadata for future model and effort
1119
+ selection. It is a contract surface only; v8 does not schedule individual lanes
1120
+ as runner-owned work units.
1121
+
1122
+ The work-unit kind vocabulary is:
1123
+
1124
+ - `roadmap_build`
1125
+ - `phase_plan`
1126
+ - `lane_execute`
1127
+ - `lane_review`
1128
+ - `phase_reducer`
1129
+ - `phase_verify`
1130
+ - `repair`
1131
+ - `closeout`
1132
+
1133
+ The normalized effort vocabulary is:
1134
+
1135
+ - `minimal`
1136
+ - `low`
1137
+ - `medium`
1138
+ - `high`
1139
+ - `xhigh`
1140
+ - `max`
1141
+
1142
+ Unsupported provider policy must resolve to exactly one explicit behavior:
1143
+
1144
+ - `block`: fail closed when the selected provider cannot honor the requested
1145
+ work-unit, model, effort, or thinking policy.
1146
+ - `fallback`: use a named fallback policy, executor, model alias, or effort
1147
+ mapping and record that fallback in launch metadata.
1148
+ - `inherit_default`: use the provider or profile default only when that default
1149
+ inheritance is explicitly recorded.
1150
+
1151
+ Silent downgrade is forbidden. A requested effort such as `xhigh` must not
1152
+ become `high` unless `fallback` or `inherit_default` was selected and recorded.
1153
+
1154
+ Provider capability normalization covers:
1155
+
1156
+ - Codex/OpenAI: accepts the normalized work-unit and effort metadata directly
1157
+ for `minimal`, `low`, `medium`, `high`, `xhigh`, and `max`.
1158
+ - Claude Code: maps normalized policy onto Claude effort controls; unsupported
1159
+ high-end distinctions such as `xhigh` require explicit fallback to `max`.
1160
+ - Gemini CLI: defaults to built-in routing aliases, using `pro` for
1161
+ planning/review and `auto` for execution/repair so Gemini CLI can apply its
1162
+ own fallback behavior. Explicit phase-loop proof runs may still use
1163
+ run-local user-scope `modelConfigs.customAliases` for
1164
+ `phase-loop-plan-high`, `phase-loop-execute-medium`, and
1165
+ `phase-loop-review-high`; those aliases carry
1166
+ `thinkingConfig.thinkingLevel` and non-secret auth selector metadata. A
1167
+ project-local `.gemini/settings.json` beside the prompt workspace is not
1168
+ sufficient evidence for custom policy injection.
1169
+ - Gemini API/OpenAI-compatible: remains metadata-only unless a future adapter
1170
+ phase explicitly owns and verifies an API path.
1171
+ - OpenCode: records normalized work-unit and effort metadata for adapter
1172
+ selection without changing current dispatch behavior.
1173
+ - Pi Agent: consumes repo-local `phase-loop-pi/**` prompts, skills,
1174
+ extensions, and `pi-config/**` installation metadata through a context-file
1175
+ launch. `executor=pi` is bounded to simple scheduler-assigned lane work and
1176
+ never owns global scheduling, runtime ledger mutation, worktree allocation,
1177
+ or merge reduction.
1178
+ - Manual handoff: non-default and selected only by operator, roadmap, or
1179
+ phase-plan policy.
1180
+ - Generic command adapters: require explicit adapter inputs and fail closed
1181
+ when policy cannot be mapped.
1182
+
1183
+ ## Automation Handoffs
1184
+
1185
+ This protocol is harness-neutral, not a blanket support claim. Operator-facing
1186
+ docs must pair it with the current maturity matrix in
1187
+ `docs/phase-loop/harness-capability-matrix.md` so shared artifact shapes are
1188
+ not mistaken for proof that every executor is live-supported.
1189
+
1190
+ ## Phase-Loop Closeout Schema (v1)
1191
+
1192
+ The canonical closeout schema (`phase_loop_closeout.v1`) is a nested object that describes the terminal state of a phase execution. It is emitted as a JSON object with these top-level fields:
1193
+
1194
+ - `schema`: Always `phase_loop_closeout.v1`.
1195
+ - `phase`: The phase alias (e.g., `RUNNER`).
1196
+ - `terminal_status`: The high-level phase outcome (`complete`, `blocked`, `failed_verification`, `human_required`, `stale_input`).
1197
+ - `automation`: An object describing the next machine steps.
1198
+ - `artifacts`: An object listing produced artifacts and plan metadata.
1199
+ - `verification`: An object describing verification status and evidence.
1200
+ - `blocker`: An object describing why a phase is blocked, if applicable.
1201
+ - `source_bundle`: An object describing the pipeline source context. Standalone
1202
+ closeout keeps this object present with `pipeline_mode: standalone` and may
1203
+ omit Pipeline-only identity fields.
1204
+ - `source_truth_impact`: An advisory object describing metadata-only
1205
+ source-truth impact hints for changed paths.
1206
+ - `lane`: Optional scheduler-owned lane closeout metadata for work-unit
1207
+ launches, containing lane identity, wave identity, worktree identity,
1208
+ verification status, changed paths, and redacted evidence refs.
1209
+
1210
+ Native v1 JSON closeout must not include deprecated root-level v5 automation aliases
1211
+ such as `status`, `next_skill`, `next_command`,
1212
+ `verification_status`, `artifact`, or `artifact_state`. Those values belong
1213
+ inside the nested `automation` object.
1214
+ Terminal-summary extraction remains a legacy compatibility path for rendered
1215
+ `automation:` blocks; it is not the native JSON fixture contract.
1216
+
1217
+ ## Native Output Schema Enforcement
1218
+
1219
+ NATIVE added `CLOSEOUT_SCHEMA` in `phase_loop_runtime.models` as the temporary
1220
+ structured-output contract before BAML became the single source of truth. The
1221
+ schema requires
1222
+ `terminal_status`, `verification_status`, `dirty_paths`, and
1223
+ `produced_if_gates`. A closeout that claims `terminal_status=complete` must
1224
+ report at least one produced IF gate at the schema layer.
1225
+
1226
+ Codex live launches that require a closeout write `CLOSEOUT_SCHEMA` to a
1227
+ temporary JSON file, append `--output-schema <path>`, record the path on
1228
+ `LaunchSpec.cleanup_paths`, and remove it after subprocess completion. Claude
1229
+ live launches that require a closeout append `--json-schema <compact-json>`
1230
+ with the same schema. Gemini, OpenCode, PI, command adapters, and manual paths
1231
+ do not receive native CLI schema flags during NATIVE.
1232
+
1233
+ The NATIVE runner still accepts legacy rendered `automation:` blocks during the
1234
+ compatibility window. Native JSON closeouts are normalized back into the shared
1235
+ automation fields before reducer logic runs.
1236
+
1237
+ ## BAML Closeout Schema
1238
+
1239
+ BAMLBASE moves the closeout-emission boundary to the declarative
1240
+ `EmitPhaseCloseout` function in
1241
+ `vendor/phase-loop-runtime/src/phase_loop_runtime/baml_src/emit_phase_closeout.baml`. The BAML source
1242
+ defines `PhaseLoopCloseoutV1` with the same root fields as the NATIVE closeout
1243
+ schema: `terminal_status`, `verification_status`, `dirty_paths`,
1244
+ `produced_if_gates`, `next_action`, blocker metadata, and
1245
+ `required_human_inputs`.
1246
+
1247
+ `phase_loop_runtime.baml_modular.build_baml_request("EmitPhaseCloseout",
1248
+ payload)` loads the vendored BAML source and returns the model-facing prompt
1249
+ plus request metadata. Harness prompt injection consumes that rendered prompt
1250
+ instead of duplicating the closeout field ceremony in each skill.
1251
+
1252
+ `phase_loop_runtime.baml_modular.parse_baml_response("EmitPhaseCloseout",
1253
+ raw_text)` parses child closeout output through the BAML runtime and then
1254
+ normalizes the typed value back into the runner's shared automation fields.
1255
+ BAML validation errors are reported as repairable non-human `contract_bug`
1256
+ blockers with non-secret summaries.
1257
+
1258
+ ### BAML Prompt Template
1259
+
1260
+ `phase_loop_runtime.baml_modular.render_baml_prompt(prompt_template,
1261
+ context_constants)` performs the repo-local prompt-template pass before BAML
1262
+ loads source text. It supports `{{ name }}` and `{{ name | join(', ') }}` for
1263
+ explicitly provided constants, without adding Jinja2 or changing BAML runtime
1264
+ syntax.
1265
+
1266
+ Closeout prompts currently expose `allowed_terminal_statuses`,
1267
+ `allowed_verification_statuses`, and `allowed_blocker_classes`. These values
1268
+ render from `phase_loop_runtime.models.PHASE_STATUSES`,
1269
+ `phase_loop_runtime.models.BLOCKER_CLASSES`, and the verification-status
1270
+ allowlist so model-facing taxonomy text stays aligned with `models.py`. The
1271
+ blocker-class rendering includes the compatibility `none` marker; closeout
1272
+ payloads should still use `null` when no blocker is present.
1273
+
1274
+ BAML runtime placeholders such as `{{ phase_alias }}`, `{{ ctx.output_format
1275
+ }}`, and control blocks remain BAML-owned and must pass through unchanged.
1276
+ Unknown taxonomy constants are repairable `BamlValidationError` failures, not
1277
+ silent downgrades to stale hard-coded prompt text.
1278
+
1279
+ ### Closeout Evidence Audit
1280
+
1281
+ Roadmaps may opt in to the post-commit closeout evidence audit with
1282
+ `closeout_evidence_audit: true` in roadmap frontmatter or in the first H2
1283
+ metadata block. When enabled, commit closeout runs the audit after the closeout
1284
+ commit lands and never amends that commit.
1285
+
1286
+ The audit compares parseable closeout claims such as `Added`, `Created`,
1287
+ `Wrote`, and `Updated` backticked symbols to the closeout commit diff. Filename
1288
+ basename matches, path-suffix matches, or identifier matches in the diff content
1289
+ count as evidence. If evidence is missing, the closeout event is downgraded to
1290
+ `blocked` with `blocker_class: closeout_evidence_drift` and the redacted
1291
+ summary shape `<N> of <M> closeout claims have no matching files in the
1292
+ closeout diff`.
1293
+
1294
+ The frozen blocker literal for this downgrade is `closeout_evidence_drift`.
1295
+ Audit metadata may record only status and counts. Blocker summaries, metadata,
1296
+ logs, and terminal summaries must not include raw commit bodies, raw diff bodies,
1297
+ secret-bearing payloads, or unmatched symbol text.
1298
+
1299
+ ### Closeout Hardening
1300
+
1301
+ `EmitPhaseCloseout` uses field-anchored enum lists for `terminal_status` and
1302
+ `verification_status`, an explicit `dry_run` negative example, a
1303
+ terminal-status decision tree, and field-pair invariants for
1304
+ `terminal_status` plus `verification_status`. `dry_run` remains an event-level
1305
+ execution mode and must not appear in a phase closeout payload.
1306
+
1307
+ Native closeout parsing first runs
1308
+ `phase_loop_runtime.discovery.parse_closeout_payload_doc(text, kind)` over the
1309
+ extracted JSON payload. Unknown `terminal_status`, `verification_status`, or
1310
+ `blocker_class` literals soft-fail into `CloseoutParseError` diagnostics before
1311
+ BAML schema parsing. The runner converts those diagnostics into non-human
1312
+ `contract_bug` blockers whose summary names the invalid literal and field.
1313
+
1314
+ Operator remediation is deliberate: patch the executor prompt when the literal
1315
+ is prompt drift, or amend the runner allowlist and reinstall the runtime when a
1316
+ new literal is intentionally added. The runtime must not coerce unknown
1317
+ closeout literals into nearby statuses.
1318
+
1319
+ ## Schema-Flow Architecture
1320
+
1321
+ `vendor/phase-loop-runtime/src/phase_loop_runtime/baml_src/emit_phase_closeout.baml` is the canonical
1322
+ closeout contract. `phase_loop_runtime.baml_modular.export_function_schema(
1323
+ "EmitPhaseCloseout")` reads that BAML function, exports the `PhaseLoopCloseoutV1`
1324
+ object shape, applies documented Codex/Claude JSON Schema dialect
1325
+ normalization, and fails with `BamlValidationError` when the BAML function or
1326
+ return class cannot be exported. Missing BAML schema export is a repairable
1327
+ non-human `contract_bug`; the runtime must not silently downgrade to a duplicate
1328
+ hand-written schema.
1329
+ The canonical helper call is `export_function_schema("EmitPhaseCloseout")`.
1330
+
1331
+ `phase_loop_runtime.models.CLOSEOUT_SCHEMA` is a compatibility import path for
1332
+ existing callers and is computed from
1333
+ `export_function_schema("EmitPhaseCloseout")` at module import time. Codex
1334
+ launches that require closeout write that schema to `--output-schema <path>`;
1335
+ Claude launches pass the same canonical schema through
1336
+ `--json-schema <compact-json>`. Gemini, OpenCode, and PI do not expose matching
1337
+ native flags, so their closeout prompts embed deterministic schema-description
1338
+ text from `inject_schema_description(prompt, schema)` with the canonical schema
1339
+ hash and ordered fields.
1340
+
1341
+ All executor closeouts still pass through `parse_closeout_payload_doc(...)`,
1342
+ `parse_baml_response("EmitPhaseCloseout", raw_text)`, and then through IF-Gate
1343
+ Tier 1 validation.
1344
+ The runner compares `produced_if_gates` with the active plan's declared
1345
+ `Produces` / `Interfaces provided` gates, so native flags, prompt embedding,
1346
+ BAML parse, and IF-gate cross-check all consume the same BAML-authored schema
1347
+ flow.
1348
+
1349
+ ### Strict Mode Transition
1350
+
1351
+ BAMLBASE ends the NATIVE compatibility window for native JSON closeouts.
1352
+ Completed closeouts that omit `produced_if_gates`, report an empty gate list,
1353
+ or otherwise violate `PhaseLoopCloseoutV1` are rejected before runner state can
1354
+ advance. Legacy rendered `automation:` blocks remain a compatibility path only
1355
+ for actions that do not emit native JSON closeouts. IF-Gate Tier 1 validation
1356
+ continues to compare the typed `produced_if_gates` list with the active phase
1357
+ plan's declared gates.
1358
+
1359
+ ## IF-Gate Tier 1 Validation
1360
+
1361
+ NATIVE adds `validate_produced_gates(plan_path, closeout_payload)` in
1362
+ `phase_loop_runtime.closeout_validation`. It extracts the active phase plan's
1363
+ declared IF gates from `Produces` and lane `Interfaces provided` declarations,
1364
+ then compares them with closeout `produced_if_gates`.
1365
+
1366
+ During the NATIVE compatibility window, a completed legacy closeout with no
1367
+ `produced_if_gates` field records a warning and remains compatible. A completed
1368
+ closeout with `produced_if_gates: []`, missing expected gates, or unexpected
1369
+ gates is blocked as repairable non-human `contract_bug`. This is the Tier 1
1370
+ scope check only; filesystem evidence verification remains out of scope.
1371
+
1372
+ #### Automation Object
1373
+
1374
+ Phase-loop aware skills and manual TUI runs must emit a machine-readable `automation` object with this exact field set:
1375
+
1376
+ ```yaml
1377
+ automation:
1378
+ status: <phase status literal>
1379
+ next_skill: <skill name or none>
1380
+ next_command: <command string or none>
1381
+ next_model_hint: <model profile key or none>
1382
+ next_effort_hint: <reasoning effort hint or none>
1383
+ human_required: <true|false>
1384
+ blocker_class: <frozen blocker class or none>
1385
+ blocker_summary: <short actionable summary or none>
1386
+ required_human_inputs: []
1387
+ verification_status: <not_run|passed|failed|blocked>
1388
+ artifact: <absolute artifact path or none>
1389
+ artifact_state: <staged|tracked|modified|unstaged|untracked|blocked|none>
1390
+ ```
1391
+
1392
+ #### Artifacts Object
1393
+
1394
+ - `plan_path`: Path to the phase plan file.
1395
+ - `plan_sha256`: SHA-256 of the phase plan file.
1396
+ - `artifact_paths`: A map of logical names to absolute paths for produced artifacts.
1397
+ - `changed_paths`: A list of repository paths modified during the phase.
1398
+ - `evidence_refs`: Metadata-only evidence references. Entries may include paths,
1399
+ labels, and hashes, but not raw transcripts, provider-supplied payloads, local
1400
+ environment values, credentials, or private evidence bytes.
1401
+
1402
+ #### Source Truth Impact Object
1403
+
1404
+ `source_truth_impact` is advisory metadata only. Impact hints are advisory:
1405
+ governed-pipeline owns canonical refresh, replan, and block decisions.
1406
+ Dotfiles must not update governed-pipeline canonical docs/specs, `.pipeline/**`,
1407
+ Portal contracts, Greenfield authority files, raw-evidence, or legacy
1408
+ `.codex/phase-loop/` state in response to these hints.
1409
+
1410
+ - `changed_path_boundaries`: A list of objects containing `path` and `category`.
1411
+ Category is one of `code`, `tests`, `docs`, `specs`,
1412
+ `active_canonical_spec`, `managed_root_mirror_spec`, `mirror_manifest`,
1413
+ `archive_manifest`, `archived_spec`, `unmanaged_spec`,
1414
+ `pipeline_sources`, `portal_contract_refs`, `greenfield_authority_refs`,
1415
+ or `unknown`. The broad `specs` category remains a compatibility literal,
1416
+ but standalone root `specs/**` paths classify as `unmanaged_spec` unless a
1417
+ validated source bundle marks them as managed mirror or archived material.
1418
+ - `canonical_refresh_recommended`: Boolean advisory signal for source-truth
1419
+ sensitive changes.
1420
+ - `canonical_refresh_reason_codes`: A list using `docs_source_truth_touched`,
1421
+ `specs_source_truth_touched`, `active_specs_touched`,
1422
+ `managed_mirror_specs_touched`, `mirror_manifests_touched`,
1423
+ `archive_manifests_touched`, `archived_specs_touched`,
1424
+ `unmanaged_specs_touched`, `adoption_contracts_touched`,
1425
+ `contract_refs_touched`, `pipeline_sources_touched`,
1426
+ `portal_contract_refs_touched`, or `greenfield_authority_refs_touched`.
1427
+ - `redaction_posture`: One of `metadata_only` or
1428
+ `rejected_forbidden_metadata`.
1429
+
1430
+ Impact and evidence metadata exclude raw patch bodies, raw transcripts, secret-like values,
1431
+ absolute private paths, provider-supplied payloads, credential-bearing payloads, local environment contents,
1432
+ and private evidence bytes. Redaction violations make the closeout
1433
+ malformed instead of preserving the forbidden content.
1434
+
1435
+ #### Verification Object
1436
+
1437
+ - `status`: One of the local verification status literals such as `passed`,
1438
+ `failed`, `blocked`, `not_run`, or `unknown`.
1439
+ - `commands`: Optional command strings used as metadata-only proof of what was
1440
+ checked.
1441
+ - `agent_reported_verification_status`: Additive metadata preserving the
1442
+ executor's self-reported verification value before runner evidence
1443
+ validation.
1444
+ - `results`: Optional metadata-only validation records. Closeout acceptance of
1445
+ `passed` is authoritative only when backed by a valid IF-0-VC-1
1446
+ `verification.json` artifact whose sibling `verification.log` hash matches
1447
+ `log_sha256` and whose command, env-refresh, and suite exit codes are all
1448
+ zero.
1449
+
1450
+ By default, `PHASE_LOOP_VERIFY_ENFORCE=hard` behavior is active: missing,
1451
+ malformed, nonzero, or tampered verification evidence blocks a passed closeout
1452
+ with blocker class `verification_evidence_missing`. Operators may set
1453
+ `PHASE_LOOP_VERIFY_ENFORCE=warn` to preserve the reported closeout while
1454
+ emitting structured warning metadata during staged adoption. Operational
1455
+ evidence amendments must use
1456
+ `verification_evidence.append_evidence_entry(doc_path, entry)`, which appends a
1457
+ fresh entry with a runner timestamp and preserves prior document bytes. A
1458
+ blocked operational gate may be re-verdicted only from a fresh entry of the
1459
+ originally specified evidence kind.
1460
+
1461
+ #### DFPARSOAK Receipt Boundary
1462
+
1463
+ DFPARSOAK is the dotfiles substrate soak for the parallel bridge. A valid
1464
+ DFPARSOAK receipt cites Greenfield `GFPARSOAK` and governed-pipeline
1465
+ `GPPARSOAK` as metadata-only upstream receipts with phase alias, repo-relative
1466
+ path, sha256 digest, produced interfaces, verification status, and redacted
1467
+ evidence refs.
1468
+
1469
+ The local wave proof uses scheduler-owned git-worktree assignment metadata and
1470
+ records Pi Agent default coverage, Claude Code CLI exception coverage, and
1471
+ Codex/Gemini fallback coverage. Fallback or default inheritance must be
1472
+ explicitly recorded; silent downgrade is invalid.
1473
+
1474
+ DFPARSOAK closeout evidence must remain redacted evidence handles or hashes. It
1475
+ must preserve no sibling-repo mutation and must not contain raw logs, raw
1476
+ transcripts, raw prompts, provider-supplied payloads, credentials, local environment contents, raw
1477
+ diffs, ignored private paths, or host-only evidence paths.
1478
+
1479
+ #### Source Bundle Object
1480
+
1481
+ - `pipeline_mode`: One of `standalone`, `pipeline_optional`, or
1482
+ `pipeline_required`.
1483
+ - `path`: Path to the source bundle JSON. Required for `pipeline_required`;
1484
+ optional or absent for standalone closeout.
1485
+ - `sha256`: SHA-256 of the source bundle. Required for `pipeline_required`;
1486
+ optional or absent for standalone closeout.
1487
+ - `phase_id`: The canonical pipeline phase ID. Required for
1488
+ `pipeline_required`; optional or absent for standalone closeout.
1489
+ - `protected_sources`: Optional metadata-only protected-source echo. Entries
1490
+ may include `path`, `category`, `sha256`, and adoption-sensitive `role`, but
1491
+ must not include raw specification bodies, raw patch bodies, provider-supplied payloads, credentials,
1492
+ local environment contents, private evidence, or absolute private paths.
1493
+
1494
+ Pipeline-required execution must fail closed before child launch when the plan
1495
+ or deterministic bridge output cannot supply matching `source_bundle.path`,
1496
+ `source_bundle.sha256`, `source_bundle.phase_id`, `source_bundle.pipeline_mode`,
1497
+ `phase`, `phase_alias`, `plan_path`, and `plan_sha256`. The resulting direct
1498
+ closeout is still a typed `phase_loop_closeout.v1` blocker with metadata-only
1499
+ diagnostics. Dotfiles reports the consumed identity; governed-pipeline remains
1500
+ the canonical source authority.
1501
+ - `pipeline_mode`: One of `standalone`, `pipeline_optional`, `pipeline_required`.
1502
+
1503
+ #### Lane Object
1504
+
1505
+ The optional `lane` object is present only when a closeout summarizes a
1506
+ runner-assigned work unit. It records scheduler-owned metadata without making
1507
+ dotfiles the scheduler, runtime ledger, worktree allocator, merge reducer, or
1508
+ authority-digest owner:
1509
+
1510
+ - `lane_id`: Lane identity selected by the phase plan.
1511
+ - `wave_id`: Wave identity assigned by the scheduler.
1512
+ - `worktree_path`: Worktree identity assigned by the scheduler.
1513
+ - `verification_status`: Work-unit verification result.
1514
+ - `changed_paths`: Repository paths changed by the work unit.
1515
+ - `evidence_refs`: Redacted evidence references such as artifact paths and
1516
+ digests; raw transcripts, credentials, private file contents, and provider
1517
+ tokens are not closeout fields.
1518
+
1519
+ When human-readable top-level handoff fields such as `artifact`,
1520
+ `artifact_state`, `next_skill`, or `next_command` are also present, they must
1521
+ agree with `automation.*` or the handoff is malformed.
1522
+
1523
+ The phase status vocabulary used by `automation.status` and reconciled state is
1524
+ frozen to `PHASE_STATUSES`:
1525
+
1526
+ - `unplanned`
1527
+ - `planned`
1528
+ - `executing`
1529
+ - `executed`
1530
+ - `awaiting_phase_closeout`
1531
+ - `complete`
1532
+ - `blocked`
1533
+ - `unknown`
1534
+
1535
+ `EVENT_STATUSES` is the event-ledger validation vocabulary. It includes all
1536
+ `PHASE_STATUSES` plus the event-only status:
1537
+
1538
+ - `plan_skipped`
1539
+
1540
+ ## Roadmap Validation
1541
+
1542
+ Roadmap-aware command-start paths run warning-only phase heading validation
1543
+ after roadmap selection and before normal execution. The validator only
1544
+ examines `### Phase ...` heading lines; it does not validate roadmap body
1545
+ content, enforce a numbering convention, rewrite roadmap files, or change event
1546
+ provenance semantics.
1547
+
1548
+ Each validation finding carries:
1549
+
1550
+ - `line_number`
1551
+ - `raw_text`
1552
+ - `reason`
1553
+ - `suggested_fix`
1554
+
1555
+ Warnings are emitted to stderr using this operator-facing shape:
1556
+
1557
+ ```text
1558
+ phase-loop roadmap warning: line <line>: <reason>; raw heading: '<heading>'; suggested fix: <fix>
1559
+ ```
1560
+
1561
+ The validator reports loose phase-heading candidates that strict
1562
+ `PHASE_HEADING_RE` would not include in phase hash lookup, duplicate phase
1563
+ aliases, and aliases outside `[A-Z][A-Z0-9._-]*`. Commands must continue with
1564
+ their existing return-code policy and stdout payloads. Common fixes are to use
1565
+ `### Phase <number> - Title (ALIAS)`, keep aliases uppercase, and give each
1566
+ phase a unique final parenthesized alias.
1567
+
1568
+ ## Event Ledger Records
1569
+
1570
+ Durable loop events are append-only records stored in the active runtime ledger.
1571
+ Shared event semantics include:
1572
+
1573
+ - `schema_version: 2`
1574
+ - `roadmap_sha256`
1575
+ - `phase_sha256`
1576
+ - event status literals from `EVENT_STATUSES`
1577
+ - blocker metadata when a blocker exists
1578
+ - optional top-level `selected_executor` when dispatch or work-unit launch
1579
+ selected an executor
1580
+ - model provenance and executor metadata when available
1581
+ - dispatch metadata when selection occurs: `selected_executor`, `source`,
1582
+ `selected_via`, `considered_executors`, `fallback_applied`,
1583
+ `blocked_reason`, and `blocked_summary`
1584
+ - optional delegation metadata when a run proposes or launches nested work:
1585
+ request contract, approval or denial decision, budget metadata, and
1586
+ parent-child lineage pointing to child artifacts without copying prompt bodies
1587
+ or collapsing native Claude team activity into runner-visible child work
1588
+
1589
+ Manual/operator events must use the same contract surface as autonomous runs.
1590
+ Legacy hashless records may remain visible for audit but must not drive future
1591
+ autonomous execution.
1592
+
1593
+ ## Hotfix Work Unit
1594
+
1595
+ `phase-loop hotfix --init-stub <path>` writes a minimal stub with `objective`
1596
+ and `verification_command` fields and exits without creating a run directory.
1597
+
1598
+ `phase-loop hotfix --reason <text> --plan <stub-path>` is the sanctioned
1599
+ emergency path for a single bounded change with no interface freeze. Anything
1600
+ that changes interfaces, roadmap scope, or downstream work uses a roadmap
1601
+ phase instead.
1602
+
1603
+ A hotfix execution creates `.phase-loop/runs/<ts>-hotfix-<slug>/`, records
1604
+ launch metadata, runs dependency-manifest env refresh plus the stub command and
1605
+ the effective suite command through IF-0-VC-1 verification evidence, validates
1606
+ the artifact with the same RG gate semantics used for execute closeout, and
1607
+ appends a closeout event containing `work_unit: hotfix`, the redacted reason,
1608
+ the plan stub, `verification_artifact_path`, `verification_log_path`, and the
1609
+ artifact validation summary. A hotfix closeout cannot report
1610
+ `verification_status: passed` unless the validation accepts the evidence
1611
+ artifact and sibling log.
1612
+
1613
+ ## Closeout Event Emission
1614
+
1615
+ After a live child executor emits a valid native closeout, the runner appends an
1616
+ executor-terminal `LoopEvent` before applying later runner-owned dirty-path or
1617
+ closeout classification. The event is append-only evidence with:
1618
+
1619
+ - `action: executor.closeout`
1620
+ - `status` equal to the executor closeout `terminal_status`
1621
+ - current `roadmap_sha256` and `phase_sha256` from
1622
+ `event_provenance(roadmap, phase)`
1623
+ - `metadata.executor_closeout_event.source_status`
1624
+ - `metadata.executor_closeout_event.verification_status`
1625
+ - `metadata.executor_closeout_event.produced_if_gates`
1626
+ - `metadata.executor_closeout_event.dirty_paths`
1627
+ - normalized child automation metadata under `metadata.child_automation`
1628
+
1629
+ Writers emit only the `executor.closeout` action for this executor-terminal
1630
+ record. Legacy ledgers that contain `action: run` with a dict-valued
1631
+ `metadata.executor_closeout_event` remain valid audit evidence; reducers
1632
+ normalize that legacy shape to `executor.closeout` at read time for identity and
1633
+ status processing without rewriting the on-disk event.
1634
+
1635
+ The executor-terminal event does not replace the later runner-classified event.
1636
+ Reducer authority remains ledger-order based: the most recent terminal event
1637
+ with valid provenance wins. A later runner-classified `blocked` event therefore
1638
+ supersedes an earlier executor-terminal `complete`, while the earlier executor
1639
+ event remains preserved for audit and recovery.
1640
+
1641
+ ## Live Adapter Contract
1642
+
1643
+ The live-adapter readiness contract is frozen around these shared code surfaces:
1644
+
1645
+ - `LaunchRequest` carries adapter input selection: repo, roadmap, phase, plan,
1646
+ model, permission policy, injection metadata, dispatch policy, and optional
1647
+ delegation lineage. Mixed-run delegation keeps the resolved
1648
+ `DispatchDecision`, typed `DelegationRequest`, and `ParentChildRunMetadata`
1649
+ on the shared request object instead of reconstructing them later. TEAMGOV
1650
+ extends this request contract with `claude_execution_mode` literals
1651
+ `solo`, `subagent`, and `agent_team`, plus optional typed
1652
+ `claude_team_policy` and `phase_team_eligibility` metadata for governed
1653
+ Claude-native collaboration.
1654
+ - `LaunchSpec` carries the reduced launch contract written to `launch.json`:
1655
+ the redacted command, availability, proof gate, promotion status, auth
1656
+ preflight mode, timeout posture, output-capture format, delivery literals
1657
+ `prompt_only`, `inline`, `stdin`, `context_file`, and `manual`, plus the
1658
+ `terminal-summary.json` artifact path contract. When an adapter needs
1659
+ executor-specific launch state such as permission posture, selected agent,
1660
+ provider-qualified model, or reasoning variant, that metadata must also stay
1661
+ in `LaunchSpec` and `launch.json` instead of being inferred later from raw
1662
+ output. The generic `command` adapter is frozen as an explicit
1663
+ `command_template` contract: it records `command_adapter_name`,
1664
+ `command_template`, `wrapped_cwd`, delivery mode, `context_path`, and
1665
+ `context_sha256`; it must fail closed when required placeholders or adapter
1666
+ inputs are missing. Governed Claude launch specs must also preserve the
1667
+ resolved `claude_execution_mode`, the typed `claude_team_policy`, and the
1668
+ evaluated `phase_team_eligibility` so unsafe native-team requests are
1669
+ rejected before launch and safe governed launches record their policy even
1670
+ when public task-list CLI flags remain unavailable.
1671
+ - `LaunchResult` carries the observed child result and the same reduced
1672
+ availability metadata back into events and monitors.
1673
+ - `ExecutorCapabilityRecord` is the frozen registry surface for per-executor
1674
+ live readiness, proof-gate status, promotion requirements, permission
1675
+ posture, auth-preflight probe mode, timeout policy, output capture, and
1676
+ terminal-summary reduction expectations. The registry vocabulary is frozen to
1677
+ `promotion_status` literals `live`, `proof_gated`, and `manual_only`; shared
1678
+ failure literals `adapter_failure` and `phase_failure`; and blocker posture
1679
+ literals `human_required` and `repairable_non_human`.
1680
+
1681
+ Later adapter phases may fill in executor-specific command vectors and
1682
+ disposable proof artifacts, but they must not move these shared fields into ad
1683
+ hoc dicts or harness-specific markdown.
1684
+
1685
+ Shared failure reduction rules are also frozen here:
1686
+
1687
+ - `adapter_failure` covers launch, output-capture, automation-closeout,
1688
+ terminal-summary, stale-handoff, and other executor-path failures where the
1689
+ selected harness could not satisfy the shared contract for the requested
1690
+ phase.
1691
+ - `phase_failure` covers requested work that ran inside the shared contract but
1692
+ still failed because the product change, test result, or verification outcome
1693
+ was genuinely unsuccessful.
1694
+ - `human_required` blockers require a true operator action such as account,
1695
+ billing, secret, admin, destructive-operation, or product-decision input.
1696
+ - `repairable_non_human` blockers are runner or adapter failures that should
1697
+ route back through repair or planning instead of being described as success.
1698
+
1699
+ ## Launch Artifacts
1700
+
1701
+ Observed launches reduce into these shared artifacts:
1702
+
1703
+ - `launch.json` records the launch request/spec metadata, redacted command,
1704
+ availability, proof gate, promotion requirements, auth-preflight posture,
1705
+ output capture, delivery metadata, `context_path`, `context_sha256`,
1706
+ `expected_skill_pack`, `skill_bundle_sha256`, `fallback_mode`, and artifact
1707
+ paths without persisting raw prompt or skill-body content. Mixed-run launch
1708
+ records must also preserve `dispatch_decision`, `delegation_request`,
1709
+ `delegation_decision`, and `parent_child` lineage metadata when present.
1710
+ Governed Claude launch metadata must additionally preserve
1711
+ `claude_execution_mode`, `claude_team_policy`, and
1712
+ `phase_team_eligibility`.
1713
+ - `phase-loop` is the neutral operator alias for the same runner implementation
1714
+ as `codex-phase-loop`; documentation and bootstrap may expose both names, but
1715
+ they must point to the same runtime contract.
1716
+ - Live Claude launches must also reduce the non-interactive `claude -p`
1717
+ response back into the shared `automation:` contract. Missing or malformed
1718
+ closeout is a repairable non-human blocker, not silent success. TEAMGOV keeps
1719
+ team creation, task creation, task list, and direct teammate messaging
1720
+ denied by default outside governed native-team mode, and native-team policy
1721
+ metadata must stay distinct from runner-brokered delegation lineage.
1722
+ - Live Gemini launches may use a minimal `--prompt` that points at the
1723
+ run-local `context.md` artifact, must set `--skip-trust` for disposable
1724
+ headless repos, and must reduce `text`, `json`, or `stream-json` output back
1725
+ into the shared `automation:` contract. Installed-skill conflicts stay
1726
+ warning-only when repo-sourced injected context succeeded.
1727
+ - Live OpenCode launches must use `opencode run` with explicit `--dir`,
1728
+ `--agent`, `--model`, `--format json`, and the shared `context.md` artifact.
1729
+ If the selected OpenCode agent posture would otherwise remain permissive, the
1730
+ runner must record that posture explicitly and refuse the launch unless an
1731
+ operator or runner policy intentionally opts in. OpenCode `json` output and
1732
+ closeout-bearing default output must both reduce back into the shared
1733
+ `automation:` contract, and installed-skill conflicts remain warning-only
1734
+ when repo-sourced injected context succeeded.
1735
+ - `.phase-loop/runs/<run-id>/context.md` is the frozen run-local context
1736
+ artifact path when the selected delivery mode requires a file. It must live
1737
+ beside `launch.json` and contain the same repo-sourced workflow bundle the
1738
+ adapter receives: workflow command, action-specific instructions, injected
1739
+ skill bodies, delegation guidance when present, and closeout requirements.
1740
+ - `terminal-summary.json` records the shared child-exit reduction used by
1741
+ closeout, repair, and monitor flows.
1742
+
1743
+ Adapters may add transport-specific metadata under additional keys, but the
1744
+ artifact filenames and their shared contract roles stay frozen.
1745
+
1746
+ ## Operator Maturity Boundaries
1747
+
1748
+ The shared protocol freezes artifact shapes, reentry semantics, delegation
1749
+ metadata, and closeout reduction across supported harnesses. It does not by
1750
+ itself promote an executor to live-supported status. Live support, experimental
1751
+ status, or manual-only posture must come from the current roadmap closeout and
1752
+ capability matrix, while this document stays limited to the common artifact and
1753
+ monitoring contract.
1754
+
1755
+ Operator-facing maturity labels remain distinct from registry promotion
1756
+ statuses:
1757
+
1758
+ - `live-supported` means the current roadmap closeout and disposable proof
1759
+ support autonomous use of that executor.
1760
+ - `proof-blocked` means the executor can still expose launch metadata or manual
1761
+ reentry surfaces, but the latest shared disposable proof did not satisfy the
1762
+ autonomous contract.
1763
+ - `experimental` means the executor contract is intentionally narrower than the
1764
+ first-class live adapters.
1765
+ - `manual-only` means manual import or operator reentry is supported without a
1766
+ current autonomous live-support claim.
1767
+
1768
+ ## Terminal Summary
1769
+
1770
+ `build_terminal_summary(...)` must emit exactly these fields:
1771
+
1772
+ - `terminal_status`
1773
+ - `terminal_blocker`
1774
+ - `verification_status`
1775
+ - `next_action`
1776
+ - `dirty_paths`
1777
+ - `phase_owned_dirty`
1778
+ - `phase_owned_dirty_paths`
1779
+ - `previous_phase_owned_paths`
1780
+ - `unowned_dirty_paths`
1781
+ - `pre_existing_dirty_paths`
1782
+ - `artifact_paths`
1783
+
1784
+ These fields are the shared child-exit reduction contract. Adapters may add
1785
+ transport-specific metadata elsewhere, but they must not rename or omit these
1786
+ summary fields.
1787
+
1788
+ ## Monitor Payloads
1789
+
1790
+ `build_notification_payload(...)` must emit exactly these top-level fields:
1791
+
1792
+ - `timestamp`
1793
+ - `repo`
1794
+ - `roadmap`
1795
+ - `event_kind`
1796
+ - `monitor_status`
1797
+ - `current_phase`
1798
+ - `current_status`
1799
+ - `human_required`
1800
+ - `blocker_class`
1801
+ - `blocker_summary`
1802
+ - `required_human_inputs`
1803
+ - `latest_heartbeat`
1804
+ - `terminal_summary`
1805
+ - `state_path`
1806
+ - `event_path`
1807
+ - `tui_handoff_path`
1808
+ - `run_log_path`
1809
+ - `recommended_action`
1810
+ - `not_run_ratio`
1811
+ - `not_run_count`
1812
+ - `sample_size`
1813
+ - `threshold`
1814
+
1815
+ This payload is the normalized machine callback surface for monitors,
1816
+ notification commands, and external supervisors.
1817
+
1818
+ ## Human-Required Blockers
1819
+
1820
+ The blocker taxonomy is frozen to these literals:
1821
+
1822
+ - `missing_secret`
1823
+ - `account_or_billing_setup`
1824
+ - `admin_approval`
1825
+ - `destructive_operation`
1826
+ - `ambiguous_roadmap_selection`
1827
+ - `product_decision_missing`
1828
+ - `dirty_worktree_conflict`
1829
+ - `branch_sync_conflict`
1830
+ - `sandbox_command_restriction`
1831
+ - `upstream_phase_unmet`
1832
+ - `contract_bug`
1833
+ - `gold_record_amendment`
1834
+ - `stalled_child_observation`
1835
+ - `repeated_verification_failure`
1836
+ - `unretryable_external_outage`
1837
+ - `stuck_loop`
1838
+ - `merge_conflict`
1839
+ - `operator_override_missing_reason`
1840
+ - `concurrent_dispatch`
1841
+
1842
+ `stuck_loop` fires when a phase has been ping-ponging in
1843
+ `(action=run, status=executing)` past the runner's iteration cap
1844
+ (default 5, via `--stuck-loop-iterations`) or time ceiling (default
1845
+ 30 minutes, via `--stuck-loop-minutes`) without converging to
1846
+ `complete` or `blocked`. The blocker's `metadata.stuck_loop` payload
1847
+ includes the `trigger` (iteration_cap or time_ceiling), iteration
1848
+ count, elapsed minutes, and first/latest executing-event timestamps.
1849
+ Resolve by either `phase-loop reopen --phase <ALIAS> --reason "..."`
1850
+ (if work isn't actually done and a re-plan is needed) or
1851
+ `phase-loop reconcile --phase <ALIAS> ...` (if the work is complete
1852
+ but the executor failed to report it).
1853
+
1854
+ Before setting `human_required=true`, the runner or skill must record safe,
1855
+ redacted access or environment probes when access is part of the blocker.
1856
+
1857
+ When live launch remains blocked behind metadata-only auth or subscription
1858
+ checks, the default blocker reduction is `account_or_billing_setup` unless a
1859
+ different frozen blocker literal is explicitly justified by the observed probe
1860
+ result.
1861
+
1862
+ ## Lane IR Plan Parser Contract
1863
+
1864
+ Execution-ready phase plans may be reduced into `PhasePlanIR` without launching
1865
+ lane work. The IR is parser-only and records:
1866
+
1867
+ - `PhasePlanIR` metadata, attached `ExecutionPolicyDocument`, dispatch hints,
1868
+ lane records, dependency edges, and typed diagnostics
1869
+ - `PhasePlanLane` identity, display name, owned files, read-only status,
1870
+ `depends_on`, `blocks`, provided interfaces, consumed interfaces, task
1871
+ buckets, verification commands, `parallel_safe`, reducer kind, and
1872
+ lane-specific execution policy
1873
+ - `LaneDependency` edges from producer or prerequisite lanes to dependent lanes
1874
+ - `LaneTaskSet` buckets for `test`, `impl`, `verify`, and `other`
1875
+ - `LaneIRDiagnostic` with `kind`, `message`, optional `lane_id`,
1876
+ `human_required=false`, and `blocker_class=contract_bug`
1877
+
1878
+ The frozen diagnostic kinds are `cycle`, `overlapping_write_ownership`,
1879
+ `unsafe_concurrent_lane`, `missing_producer_dependency`, `missing_owned_files`,
1880
+ `malformed_owned_files`, `malformed_dependencies`,
1881
+ `unsupported_lane_policy`, and `missing_lane_sections`.
1882
+
1883
+ The frozen reducer kinds are `none`, `acceptance_reducer`,
1884
+ `compatibility_reducer`, `verification_reducer`, and `summary_reducer`.
1885
+
1886
+ Malformed lane IR is a repairable non-human blocker. The parser fails closed
1887
+ for dependency cycles, overlapping write ownership, missing producer
1888
+ dependencies, malformed or missing owned-file lines, malformed dependencies,
1889
+ and unsupported lane policy literals. Existing `phase_loop_plan_version: 1`
1890
+ frontmatter remains unchanged. The LANEIR contract does not add scheduler mode,
1891
+ worktree fanout, runner-owned lane launches, reducer launches, or any change to
1892
+ coarse phase execution defaults.
1893
+
1894
+ ## Work-Unit Lifecycle
1895
+
1896
+ UNITRUN adds runner-owned work-unit records behind explicit work-unit mode while
1897
+ leaving coarse phase execution intact. A work-unit identity is frozen as
1898
+ `<phase>.<kind>.<lane-or-reducer-id>.<attempt>` and is represented by typed
1899
+ fields on `WorkUnitIdentity`: `phase`, `kind`, `lane_id`, `attempt`, and
1900
+ `work_unit_id`.
1901
+
1902
+ The frozen work-unit statuses are `pending`, `running`, `complete`, `blocked`,
1903
+ `skipped`, `superseded`, and `awaiting-closeout`. These are intentionally
1904
+ separate from phase statuses such as `planned`, `executing`, and `complete`.
1905
+
1906
+ The state snapshot may include `work_units` and `latest_work_unit`. Each
1907
+ `WorkUnitState` records identity, status, parent phase event, policy, artifact
1908
+ paths, `heartbeat_path`, `terminal_summary_path`, retry lineage, blocker
1909
+ metadata, and timestamps. Malformed work-unit state records are ignored by the
1910
+ work-unit loader rather than breaking legacy phase-level state reads.
1911
+
1912
+ The event ledger may include `event_kind: work_unit` entries. A
1913
+ `WorkUnitEventMetadata` record stores launch metadata, heartbeat path, terminal
1914
+ summary path, closeout summary, retry lineage, blocker metadata, and the current
1915
+ work-unit status. These records coexist with phase-level `LoopEvent` entries and
1916
+ must not cause older phase-level reconciliation to treat work-unit statuses as
1917
+ phase statuses.
1918
+
1919
+ The shared `automation:` closeout contract remains valid at phase level.
1920
+ Work-unit closeout adds optional work-unit fields through `WorkUnitCloseout` and
1921
+ optional `terminal-summary.work_unit` data without changing the required frozen
1922
+ terminal summary fields. A lane work-unit closeout may record `lane_id`,
1923
+ `wave_id`, `worktree_path`, `verification_status`, `changed_paths`, and
1924
+ redacted `evidence_refs`; it must not store raw transcripts, credential
1925
+ payloads, private source bytes, or provider tokens. Work-unit metrics may
1926
+ include `work_unit_metric.v1.work_unit_id`, `work_unit_metric.v1.lane_id`, and
1927
+ `work_unit_metric.v1.wave_id`.
1928
+
1929
+ Resume semantics are work-unit granular: completed units are skipped,
1930
+ non-human blocked or stale running units may be retried with a new attempt,
1931
+ stale attempts are marked `superseded`, and human-required blocked units remain
1932
+ blocked until operator action resolves them. UNITRUN does not schedule
1933
+ dependency waves or isolated worktrees; WAVESCHED owns that later behavior.
1934
+
1935
+ ## Lane Scheduler
1936
+
1937
+ WAVESCHED adds runner-owned lane scheduling behind an explicit scheduler gate.
1938
+ Lane scheduler modes are `off`, `serialized`, and `concurrent`. `off` is the
1939
+ default and preserves coarse phase execution. `serialized` may select one ready
1940
+ lane on the main worktree. `concurrent` may select multiple ready lanes only
1941
+ when writer ownership is disjoint and each writer has a `git_worktree`
1942
+ assignment.
1943
+
1944
+ `LaneWave` records `wave_id`, ordered `lane_ids`, scheduler `mode`, and
1945
+ optional `LaneWorktreeAssignment` records. `LaneWaveDecision` records status
1946
+ `ready`, `blocked`, or `empty`, plus pending, completed, blocked lane IDs, and
1947
+ typed diagnostics. `LaneWorktreeAssignment` records `lane_id`,
1948
+ `worktree_path`, `isolation_mode`, optional branch, and optional `base_sha`.
1949
+ Worktree isolation modes are `main_worktree` and `git_worktree`.
1950
+
1951
+ The scheduler-owned assignment field list accepted by dotfiles is: lane id
1952
+ (`lane_id`), wave id (`wave_id`), worktree path (`worktree_path`), base SHA
1953
+ (`base_sha`), isolation mode (`isolation_mode`), owned files (`owned_files`),
1954
+ read-only refs (`read_only_refs`), harness route (`harness_route`), model
1955
+ (`model`), effort (`effort`), and fallback reason (`fallback_reason`).
1956
+ Governed Pipeline owns scheduling, runtime ledger, worktree assignment, and
1957
+ merge reduction. Greenfield owns deterministic authority contracts, authority
1958
+ refs, and authority digests. Dotfiles consumes governed-pipeline assignments
1959
+ and Greenfield authority refs as inputs and must not promote those inputs into
1960
+ dotfiles-owned runtime authority.
1961
+
1962
+ Worktree placement uses `<WORKTREE-PATH-REDACTED>
1963
+ when `/mnt/workspace` exists; otherwise it uses default sibling placement next
1964
+ to the repo. The runner must halt between lane launches when a stop file is
1965
+ present and must not rewrite in-flight heartbeat, terminal-summary, metric, or
1966
+ closeout artifacts.
1967
+
1968
+ Concurrent scheduling is available only for scheduler-approved
1969
+ `parallel_safe` non-reducer writer waves with disjoint writable ownership and
1970
+ isolated `git_worktree` assignments. Serialized scheduling and coarse phase
1971
+ execution remain compatibility paths and do not require scheduler-owned
1972
+ worktree assignments. Unsafe concurrent selection must fail closed with typed
1973
+ diagnostics for overlapping owned files, missing worktree assignment, stale
1974
+ base SHA, active work unit, human-required blocked work unit,
1975
+ reducer-in-wave, stop-file interruption, and malformed closeout.
1976
+
1977
+ Dirty-path reduction uses `DirtyPathClassification` with classifications
1978
+ `pre_existing`, `lane_owned`, `peer_owned`, `reducer_owned`, and `unowned`.
1979
+
1980
+ Ignored, private, raw-data, credential, and evidence-source files are
1981
+ read-protected by default. Child executors may read those paths only when the
1982
+ run-local context, phase plan, or Pipeline source bundle explicitly allowlists
1983
+ the exact path or glob as a read input. Owned output paths do not imply
1984
+ permission to read ignored or private source inputs, and old memory or prior
1985
+ phase behavior is not an allowlist.
1986
+
1987
+ Before any phase or work-unit closeout claims success, the child executor must
1988
+ audit `git status --short` against the active owned-file contract. Dirty paths
1989
+ must be classified as phase/lane-owned, planning/control, pre-existing
1990
+ unrelated, or unowned. Ignored phase-owned outputs may be preserved only when
1991
+ the plan/source bundle includes an explicit allowlist or staging policy;
1992
+ otherwise the executor must report a repairable `dirty_worktree_conflict`.
1993
+
1994
+ File-rename pairs in the dirty tree — both the `R src -> dst` form that git
1995
+ emits when both sides are staged, and the unpaired `D src` + `?? dst` form
1996
+ that arises when an executor performs a filesystem-only `mv` — are detected by
1997
+ exact blob-hash equality between the deleted HEAD blob and the untracked
1998
+ working-tree file. When the destination is phase-owned, the source path is
1999
+ promoted to `phase_owned_dirty` automatically so a "sensible refactor
2000
+ instinct" move does not fire as `unowned_dirty_paths`. Detection is exact,
2001
+ not similarity-based: a move that also rewrites content is not paired, and
2002
+ must be declared in the plan's owned-file contract explicitly.
2003
+
2004
+ ## Parallel Plan Safety
2005
+
2006
+ Planning turns that run concurrently for the same roadmap may leave sibling
2007
+ phase plan documents in the worktree. A dirty path is expected sibling planning
2008
+ dirt only when it is a repo-relative `plans/phase-plan-<roadmap-version>-<alias>.md`
2009
+ artifact, `<alias>` exists in the selected roadmap, `<alias>` is not the current
2010
+ phase, and `<roadmap-version>` matches the selected roadmap filename.
2011
+
2012
+ Runner dirty-path classification must report those paths as
2013
+ `expected_sibling_dirty_paths` with `expected_sibling_dirty: true`, and must not
2014
+ also include them in `unowned_dirty_paths` or let them cause a
2015
+ `dirty_worktree_conflict`. Current-phase plan docs, foreign roadmap versions,
2016
+ alternate directories, absolute paths, path traversal, and non-plan dirt remain
2017
+ governed by the ordinary owned-file and control-path rules.
2018
+
2019
+ ## Harness Lane Workflows
2020
+
2021
+ HARNESSLANE adds a runner-owned lane assignment payload for harness-specific
2022
+ work units while preserving the coarse phase execution path. The frozen payload
2023
+ is `HarnessLaneAssignment` with `schema=harness_lane_assignment.v1` semantics:
2024
+
2025
+ - `phase`
2026
+ - `lane_id`
2027
+ - `work_unit_kind`
2028
+ - `prompt_kind`
2029
+ - `wave_id`
2030
+ - `owned_files`
2031
+ - `read_only_refs`
2032
+ - `consumed_interfaces`
2033
+ - `depends_on`
2034
+ - `execution_policy`
2035
+ - `worktree_assignment`
2036
+ - `harness_route`
2037
+ - `model`
2038
+ - `effort`
2039
+ - `fallback_reason`
2040
+ - `closeout_schema_required`
2041
+ - `reducer_kind`
2042
+ - `metadata`
2043
+
2044
+ The frozen `HarnessWorkUnitPromptKind` literals are `implementation`, `review`,
2045
+ `reducer`, `verify`, and `closeout`. Implementation prompts can edit only the
2046
+ assigned `owned_files`. Review prompts must not make production edits. Reducer
2047
+ prompts may summarize producer results and closeout state, but must not claim
2048
+ producer write ownership.
2049
+
2050
+ `build_lane_prompt_bundle`, `render_harness_lane_context`,
2051
+ `render_harness_review_context`, and `render_harness_reducer_context` render a
2052
+ single selected work unit for Codex, Claude, Gemini, OpenCode, or command
2053
+ adapters. Each bundle carries the selected lane id, owned files, consumed
2054
+ interfaces, work-unit kind, execution-policy summary, worktree assignment
2055
+ metadata, and the required shared `automation:` closeout fields. These bundles
2056
+ do not grant whole-phase implementation authority.
2057
+
2058
+ `LaunchSpec.harness_lane_assignment` and `launch.json.harness_lane_assignment`
2059
+ freeze lane metadata for live launches. `launch.json.lane_id` and
2060
+ `launch.json.work_unit_kind` are convenience copies for metrics and terminal
2061
+ summaries. Claude `subagent` and `agent_team` launches remain gated by
2062
+ team-safe lane policy, runner work-unit state, delegation broker depth/fanout
2063
+ limits, and owned-file boundaries. Gemini lane launches use built-in routing
2064
+ aliases such as `pro` and `auto` by default; explicit run-local aliases such as
2065
+ `phase-loop-execute-medium` and `phase-loop-review-high` remain opt-in proof
2066
+ surfaces and fail closed through the unsupported-policy diagnostic path when
2067
+ misspelled. OpenCode lane launches record explicit `opencode run`,
2068
+ `--dir`, `--agent`, provider-qualified `--model`, optional `--variant`,
2069
+ `--format json`, and permission posture metadata. Command adapter lane launches
2070
+ require an explicit template that includes `{context_file}`.
2071
+
2072
+ ## Closeout Modes
2073
+
2074
+ Closeout policy is frozen to:
2075
+
2076
+ - `manual`
2077
+ - `commit`
2078
+ - `push`
2079
+
2080
+ `manual` preserves verified phase-owned dirty output without mutating git
2081
+ state. `commit` may preserve only trusted phase-owned dirty paths in a local
2082
+ commit. `push` may build on that local commit only when branch/base topology is
2083
+ safe and explicit.
2084
+
2085
+ ## Roadmap Amendments
2086
+
2087
+ Execution discoveries that change downstream scope must amend the nearest
2088
+ downstream roadmap phase that is not already executing. After the amendment:
2089
+
2090
+ - reconcile against the amended roadmap before selecting the next phase
2091
+ - treat older downstream phase plans or handoffs as stale when their roadmap
2092
+ metadata no longer matches
2093
+ - regenerate any affected downstream phase plan through the planner before
2094
+ execution resumes
2095
+ - preserve prior ledger records for audit, but let later trusted events on the
2096
+ amended roadmap suppress stale mismatch noise
2097
+
2098
+ ## Delegation Broker
2099
+
2100
+ Cross-harness delegation remains runner-owned. Child runs may recommend nested
2101
+ work only through a typed delegation request contract. The frozen request shape
2102
+ includes:
2103
+
2104
+ - `request_id`
2105
+ - `product_action`
2106
+ - `target_executor`
2107
+ - `reason`
2108
+ - `owned_files`
2109
+ - `expected_output`
2110
+ - `priority`
2111
+ - optional `review_context`
2112
+ - optional `repair_context`
2113
+ - optional metadata-only `budget`
2114
+
2115
+ Delegation approval is validated in this order:
2116
+
2117
+ 1. active-loop mode
2118
+ 2. ownership boundaries
2119
+ 3. depth limit
2120
+ 4. fanout limit
2121
+ 5. budget metadata
2122
+ 6. dispatch policy
2123
+
2124
+ Denied requests must produce a typed non-human blocked outcome with a clear
2125
+ reason code and summary. Approved requests must reuse the normal runner launch
2126
+ path so launch artifacts record request metadata, resolved executor, observed
2127
+ launch path, and parent-child linkage without changing the frozen top-level
2128
+ monitor payload fields.
2129
+
2130
+ Claude-native subagents and agent teams do not implicitly create runner child
2131
+ runs. They become runner-visible child work only after a typed delegation
2132
+ request is emitted and approved through this broker contract.
2133
+
2134
+ Delegated cross-harness child work is frozen to `execute`, `repair`, and
2135
+ `review`, and approved child executors are limited to `codex` and `claude`.
2136
+ Native Claude team tasks stay internal unless they externalize through the same
2137
+ typed `DelegationRequest` broker path.
2138
+ Top-level executor switching remains an operator or runner decision, not a
2139
+ native-team side effect: choose the top-level harness through normal dispatch
2140
+ selection or `--executor`, then require typed broker approval before any child
2141
+ work crosses harness boundaries.
2142
+
2143
+ The shared mixed-run lineage surface includes:
2144
+
2145
+ - `DispatchDecision.selected_via`
2146
+ - `DispatchDecision.considered_executors`
2147
+ - typed delegation denial `reason_code`
2148
+ - `ParentChildRunMetadata.parent_executor`
2149
+ - `ParentChildRunMetadata.child_executor`
2150
+ - `ParentChildRunMetadata.child_artifact_root`
2151
+ - `ParentChildRunMetadata.child_worktree_root`
2152
+ - `ParentChildRunMetadata.child_closeout_result`
2153
+
2154
+ ## Manual Advancement and Import
2155
+
2156
+ Manual TUI runs remain valid when they emit the same shared artifact contract
2157
+ as automated runs. Shared manual rules:
2158
+
2159
+ - append a `manual` source event when phase-loop state already exists
2160
+ - keep `automation.*` aligned with the human-readable handoff
2161
+ - use `manual_repair` with `clears_blocker=true` only when a repair actually
2162
+ clears the recorded blocker
2163
+ - autonomous child executors should not edit `.phase-loop/` or claim durable
2164
+ ledger mutation unless the injected launch explicitly permits and confirms
2165
+ it; the parent runner owns blocker clearing and closeout reconciliation from
2166
+ valid shared automation closeouts
2167
+ - when a manual run amended the roadmap downstream, compute
2168
+ `roadmap_sha256` and `phase_sha256` from the amended roadmap for the current
2169
+ phase being closed instead of reusing stale plan hashes
2170
+ - installed bridge skills are recommended for manual takeover and TUI reentry,
2171
+ but repo-injected workflow bundles remain the autonomous source of truth for
2172
+ child launches
2173
+
2174
+ ## Runtime Path
2175
+
2176
+ For this roadmap family, `.phase-loop/` is the canonical durable runtime path
2177
+ for state, ledger, handoff, and observed-run artifacts. Existing
2178
+ `.codex/phase-loop/` artifacts remain a legacy read fallback so active repos are
2179
+ not stranded during migration. New writes use `.phase-loop/`.
2180
+ Legacy `.codex/phase-loop/` is never a new write target for closeout,
2181
+ delegation, source-bundle, or runner evidence artifacts.
2182
+
2183
+ `phase-loop init [--repo <path>] [--dry-run]` initializes the repo-local
2184
+ handoff storage expected by workflow skills. It idempotently adds
2185
+ `/.dev-skills/` to the target repo `.gitignore` without duplication and creates
2186
+ `.dev-skills/handoffs/` unless `--dry-run` is set.
2187
+
2188
+ ## Runtime Boundary
2189
+
2190
+ The phase-loop runtime is isolated as a coherent internal package within the
2191
+ dotfiles repository. It provides a stable CLI and Python API boundary for
2192
+ external tools and repositories.
2193
+ The authoritative boundary document is `docs/phase-loop/runtime-boundary.md`.
2194
+ The dotfiles-specific substrate path inventory is
2195
+ `docs/phase-loop/harness-substrate-manifest.md`; it is intentionally separate
2196
+ from this schema contract.
2197
+
2198
+ Key boundary properties:
2199
+ - The primary CLI entrypoint is `phase-loop` (aliased as `codex-phase-loop`).
2200
+ - The CLI supports a `version` command and `--version` flag for contract reporting.
2201
+ - Public Python modules are exposed under the `phase_loop_runtime.*` namespace.
2202
+ - Internal modules not explicitly listed in `__all__` or the boundary document
2203
+ are considered private and subject to change.
2204
+ - Durable state and events are stored under `.phase-loop/` (legacy fallback
2205
+ `.codex/phase-loop/`).
2206
+ - New writes use `.phase-loop/`.
2207
+
2208
+ ## Extraction Readiness
2209
+
2210
+ The protocol and runtime boundary are considered "Extraction Ready" when:
2211
+ 1. All public CLI commands are documented and stable.
2212
+ 2. All machine-readable artifacts follow frozen schemas.
2213
+ 3. Cross-repo compatibility fixtures exist for downstream validation.
2214
+ 4. The migration path does not break existing `dotfiles` installation.
2215
+
2216
+ This roadmap family confirms that phase-loop has met these criteria.
2217
+
2218
+ ## Cross-Repo Compatibility Fixtures
2219
+
2220
+ To ensure stable integration with downstream repositories such as `governed-pipeline`, this repository provides a set of canonical fixtures that demonstrate various phase-loop outcomes.
2221
+
2222
+ ### Fixture Location
2223
+
2224
+ Stable fixtures are located under:
2225
+ `vendor/phase-loop-runtime/tests/fixtures/phase_loop_pipeline_bridge/`
2226
+
2227
+ These fixtures are dotfiles-owned substrate. The governed-pipeline mirror
2228
+ location is `packages/pipeline-runtime/test/fixtures/phase-loop-bridge/`, and
2229
+ mirror updates, closeout ingest, canonical refresh, replan, and preflight block
2230
+ decisions are governed-pipeline-owned work. Dotfiles must not edit the
2231
+ governed-pipeline mirror path from this repository.
2232
+ Fixture and closeout examples remain metadata-only: they do not authorize raw
2233
+ evidence reads, credential-bearing payloads, provider-supplied payloads, local environment
2234
+ values, `.pipeline/**` writes, Portal writes, Greenfield writes, or broad
2235
+ dotfiles root dependencies.
2236
+
2237
+ ### Available Scenarios
2238
+
2239
+ - `complete.json`: A standard successful phase execution.
2240
+ - `blocked.json`: A phase blocked by a non-human restriction (e.g., sandbox).
2241
+ - `stale_input.json`: A phase with mismatched plan or roadmap hashes.
2242
+ - `failed_verification.json`: A phase where verification failed.
2243
+ - `human_required.json`: A phase requiring operator intervention (e.g., billing).
2244
+ - `dfbundlecloseout_standalone.json`: A standalone closeout without
2245
+ Pipeline-only source bundle path or hash identity.
2246
+ - `dfdriftsignal_canonical_refresh_recommended.json`: Advisory changed-path
2247
+ metadata recommending governed-pipeline canonical refresh.
2248
+ - `dfbundlecloseout_malformed_*.json`: Negative fixtures for malformed
2249
+ closeout, missing bundle hash, deprecated root aliases, invalid nested
2250
+ objects, invalid terminal status, and forbidden metadata.
2251
+ - `dfadoptbridge_adoption_complete.json`: Adoption bridge fixture with active
2252
+ canonical spec, managed root mirror, mirror manifest, archive manifest,
2253
+ source-bundle identity, protected-source roles, and SHA-256 evidence refs.
2254
+ - `dfadoptbridge_stale_mirror_manifest.json`: Adoption bridge fixture for
2255
+ stale mirror manifest metadata and governed-pipeline-owned refresh handling.
2256
+ - `dfadoptbridge_unmanaged_spec_input.json`: Adoption bridge fixture for
2257
+ unmanaged root `specs/**` intake as metadata-only evidence.
2258
+
2259
+ Downstream consumers should use these fixtures to verify their ingestion logic against the `phase_loop_closeout.v1` schema.
2260
+
2261
+ DFADOPTBRIDGE fixtures extend the adoption bridge matrix for governed-pipeline
2262
+ v11. They cover adoption complete, blocked adoption metadata, stale source
2263
+ bundle, stale mirror manifest, unmanaged spec input, archive manifest touched,
2264
+ standalone non-adoption, deprecated root aliases, and redaction rejection.
2265
+ Pipeline-required fixtures use `source_bundle.path`, `source_bundle.sha256`,
2266
+ `source_bundle.phase_id`, protected-source `path`, protected-source `sha256`,
2267
+ protected-source `role`, plan `sha256`, changed-path categories, advisory
2268
+ reason codes, and evidence-ref `sha256` metadata. They do not grant dotfiles
2269
+ permission to write governed-pipeline mirror paths, `.pipeline/**`, Portal
2270
+ contracts, Greenfield authority files, raw-evidence, raw data, credentials, or
2271
+ legacy `.codex/phase-loop/**` state.
2272
+
2273
+ DFADOPTSOAK is the dotfiles adoption integration release gate. It proves root
2274
+ `specs/**` standalone advisory hints, explicit non-default spec-root intake
2275
+ metadata, unconfigured non-default root non-advisory behavior,
2276
+ pipeline-required source-bundle echo, stale-input blockers, v14 bridge fixture
2277
+ retention, DFADOPTBRIDGE fixture parity, and unittest-first verification. It
2278
+ consumes governed-pipeline `CADOPTSOAK` only as read-only metadata evidence;
2279
+ governed-pipeline retains ownership of mirror copies, adoption decisions,
2280
+ archive creation, managed mirror refresh, source-truth reconciliation,
2281
+ source-bundle emission, canonical refresh, replan, and preflight block
2282
+ decisions.
2283
+
2284
+ DFFAKESMOKE adds a metadata-only local substrate receipt at
2285
+ `docs/phase-loop/dffakesmoke-substrate-receipt.md` and a fake-smoke matrix at
2286
+ `vendor/phase-loop-runtime/tests/fixtures/phase_loop_fake_smoke/matrix.json`. The receipt fields are
2287
+ `phase`, `roadmap_sha256`, `plan_path`, `fake_fixture_matrix`,
2288
+ `smoke_commands`, `work_unit_evidence_refs`, `verification_status`,
2289
+ `changed_path_boundaries`, and `redaction_posture`. These fields are
2290
+ downstream evidence refs only; governed-pipeline remains responsible for
2291
+ scheduling, runtime ledger policy, worktree assignment, closeout ingest, and
2292
+ merge reduction.
2293
+
2294
+ DFPROMPTSYNC adds a prompt-safe contract map at
2295
+ `docs/phase-loop/dfpromptsync-contract-map.md`, a readiness receipt at
2296
+ `docs/phase-loop/dfpromptsync-readiness.md`, and a fixture matrix at
2297
+ `vendor/phase-loop-runtime/tests/fixtures/phase_loop_prompt_sync/matrix.json`. Prompt bundles and harness
2298
+ lane workflows may cite schema names, field names, fixture paths, artifact
2299
+ refs, and digests from those receipts, but must not copy raw secrets, raw
2300
+ transcripts, raw patch bodies, raw provider-supplied payloads, credential file contents, local
2301
+ env values, or prompt-only containment claims.
2302
+
2303
+ ## Direct Invocation Policy
2304
+
2305
+ INVOKEOPT adds support for optional direct invocation by external systems (such as Governed Pipeline) while preserving the shared artifact contract as the primary interoperability surface.
2306
+
2307
+ ### Supported CLI Shape
2308
+
2309
+ When direct invocation is enabled, the `phase-loop` CLI exposes a deterministic shape:
2310
+
2311
+ ```bash
2312
+ phase-loop execute <phase> --bundle <path> --output <path> --mode <execute|repair|review>
2313
+ ```
2314
+
2315
+ - `<phase>`: The phase alias to execute.
2316
+ - `--bundle <path>`: Path to a `phase-source-bundle.v1` artifact.
2317
+ - `--output <path>`: Path where exactly one closeout JSON file must be written.
2318
+ - `--mode`: One of `execute`, `repair`, or `review`.
2319
+ Invalid mode literals fail at the direct CLI boundary before child launch.
2320
+
2321
+ ### Rejection Policy
2322
+
2323
+ Unsupported direct invocation must fail closed with a typed diagnostic. The following scenarios result in a `sandbox_command_restriction` or `contract_bug` blocker:
2324
+
2325
+ - Missing or invalid `<phase>`.
2326
+ - Missing `--bundle` when `pipeline_required` mode or the phase plan requires it.
2327
+ - Missing `--output` when direct invocation is attempted.
2328
+ - Invalid or unsupported `--mode`.
2329
+ - Stale `freshness.source_bundle_hash` when it is a SHA-256 digest.
2330
+ - Unknown phase IDs or aliases in the source bundle.
2331
+ - Missing or stale protected source entries.
2332
+ - Malformed `phase_loop_closeout.v1` payloads.
2333
+ - Missing or incompatible runner for the requested phase.
2334
+
2335
+ ### Output Semantics
2336
+
2337
+ Output semantics are deterministic: exactly one closeout JSON file is written
2338
+ to the path specified by `--output` for supported `execute`, `repair`, and
2339
+ `review` invocations, including typed bridge blockers detected before child
2340
+ launch. Standard output may contain human-readable logs, but machine
2341
+ integration must depend only on the output file.
2342
+
2343
+ ## DFPARSOAK Integrated Soak
2344
+
2345
+ DFPARSOAK adds the integrated parallel substrate soak source map at
2346
+ `docs/phase-loop/dfparsoak-source-map.md`, the governed-pipeline-consumable
2347
+ receipt at `docs/phase-loop/dfparsoak-receipt.md`, the operator runbook at
2348
+ `docs/phase-loop/dfparsoak-runbook.md`, and the fixture matrix at
2349
+ `vendor/phase-loop-runtime/tests/fixtures/phase_loop_dfparsoak/matrix.json`.
2350
+
2351
+ The soak closeout records `lane_id`, `wave_id`, `worktree_path`,
2352
+ `isolation_mode`, `base_sha`, `harness_route`, `work_unit_kind`, `model`,
2353
+ `effort`, `policy_source`, `fallback_reason`, verification status, changed
2354
+ paths, and redacted evidence refs. Governed Pipeline still owns scheduling and
2355
+ closeout ingest; Greenfield still owns authority schemas and contract-pack
2356
+ expectations.
2357
+
2358
+ ## Closeout Exceptions (Graduated Ownership Gate)
2359
+
2360
+ Roadmap v40 introduces a **graduated** closeout gate for the case where a phase
2361
+ verifies green (`verification_status == "passed"`) but the executor modified
2362
+ files outside the plan's declared owned-files globs. Instead of an unconditional
2363
+ hard block, beyond-ownership paths are classified and either auto-committed as a
2364
+ recorded soft exception or held for an explicit operator break-glass. This
2365
+ section freezes the shared vocabulary (PROTO); GATE and BREAKGLASS implement the
2366
+ behavior. The frozen constants live in
2367
+ `vendor/phase-loop-runtime/src/phase_loop_runtime/models.py` and are the single
2368
+ source of truth — this prose and the four harness `runtime-state.md` mirrors
2369
+ restate them and must agree.
2370
+
2371
+ ### Sensitivity taxonomy (`SENSITIVITY_CLASSES`)
2372
+
2373
+ Every unowned dirty path is mapped to one sensitivity class:
2374
+
2375
+ - **SAFE** (`SAFE_SENSITIVITY_CLASSES`): `docs`, `plans`, `handoffs`,
2376
+ `config_nonsource`. Low blast radius; may auto-pass as a soft exception when
2377
+ verification passed.
2378
+ - **UNSAFE** (`UNSAFE_SENSITIVITY_CLASSES`): `source`, `ci`, `secrets`,
2379
+ `lockfile`. Always blocks unless the operator supplies an explicit break-glass
2380
+ reason.
2381
+
2382
+ **Deny-by-default rule:** any path that matches **no** SAFE class is treated as
2383
+ UNSAFE. An unmatched/unknown path is never auto-passed. This is the safety
2384
+ substitute for separation of duties in a single-operator fleet: the classifier,
2385
+ not a human second-signature, decides what may auto-commit.
2386
+
2387
+ ### Closeout-exception record (`CloseoutException`)
2388
+
2389
+ A frozen dataclass with exactly these fields:
2390
+
2391
+ | Field | Meaning |
2392
+ |---|---|
2393
+ | `paths` | the beyond-ownership paths this exception covers |
2394
+ | `exception_kind` | a `CLOSEOUT_EXCEPTION_KINDS` member: `soft` or `break_glass` |
2395
+ | `sensitivity_class` | the `SENSITIVITY_CLASSES` member that classified the paths |
2396
+ | `reason` | operator-supplied break-glass reason (`None` for `soft`) |
2397
+ | `verification_status` | always `passed` — unverified work is never excepted |
2398
+
2399
+ - `soft` — all unowned paths were SAFE; the gate auto-commits and records the
2400
+ exception. No blocker.
2401
+ - `break_glass` — unowned paths included an UNSAFE class; commit only under an
2402
+ explicit operator reason. An empty/missing reason is the
2403
+ `operator_override_missing_reason` blocker. A verified-but-unowned UNSAFE path
2404
+ with no override is the `closeout_scope_violation` blocker.
2405
+
2406
+ ### Visibility
2407
+
2408
+ Every exception is recorded in closeout metadata under the
2409
+ `closeout.closeout_exceptions` key (`CLOSEOUT_EXCEPTIONS_METADATA_KEY`) and in
2410
+ the event ledger, with its own tally — never silently folded into a clean-pass
2411
+ count. `soft` and `break_glass` exceptions share the tally, distinguished by
2412
+ `exception_kind`.
2413
+
2414
+ ### Graduated gate (GATE)
2415
+
2416
+ `_perform_phase_closeout` classifies the beyond-ownership dirty remainder via
2417
+ `closeout_classifier.classify_unowned_path(repo_relpath) -> SensitivityVerdict`
2418
+ (`{sensitivity_class, safe}`) and splits it:
2419
+
2420
+ - **all-SAFE remainder** → the SAFE paths join the commit and are recorded as
2421
+ `soft` `CloseoutException`s (one per sensitivity class). No blocker;
2422
+ `verification_status` stays `passed`.
2423
+ - **any-UNSAFE remainder** → the UNSAFE subset blocks with `closeout_scope_violation`
2424
+ (human-required); SAFE paths in a mixed remainder still soft-commit.
2425
+
2426
+ Classifier precedence is load-bearing: UNSAFE-specific patterns (`secrets`,
2427
+ `lockfile`, `ci`) are matched before any broad SAFE rule, then `tests` → `source`
2428
+ (UNSAFE), then the narrow SAFE rules, then deny-by-default → `source`.
2429
+ `config_nonsource` is a tight filename allowlist (not a `.toml`/`.yaml`/`.json`
2430
+ suffix rule), and a bare `.txt` is docs only under `docs/`.
2431
+
2432
+ **`tests` are UNSAFE.** The taxonomy has no `tests` class; test paths only earn
2433
+ owned status via structural sibling matching upstream (`_runtime_relaxation_evidence`,
2434
+ `expanded_dirty_ownership_matches`). A test path reaching the classifier failed that
2435
+ matching, so it maps to `source` (UNSAFE) and is never auto-committed — operator
2436
+ break-glass (BREAKGLASS), not auto-commit, is the escape.
2437
+
2438
+ ### Operator break-glass (BREAKGLASS)
2439
+
2440
+ The escape for the `closeout_scope_violation` block is the
2441
+ `--closeout-allow-unowned <reason>` CLI flag (valid on `run`/`resume`/`dry-run`
2442
+ only; requires a non-empty reason, rejected pre-`run_loop`; requires `--phase`,
2443
+ which bounds the blast radius to a single phase). It threads
2444
+ `allow_unowned_reason` through `run_loop` into `_perform_phase_closeout`, where
2445
+ the UNSAFE remainder is folded into the same closeout commit as `break_glass`
2446
+ `CloseoutException`s carrying the reason — the remainder is emptied, so the
2447
+ post-commit scope block does not fire. No amend, no second commit.
2448
+
2449
+ - **`secrets` are NEVER break-glassable.** A path whose `classify_unowned_path`
2450
+ class is `secrets` (`.env*`, `*.pem`, `secrets/**`) is held back regardless of
2451
+ the reason and still blocks with `closeout_scope_violation` — a one-line reason
2452
+ must not commit a secret into history (irreversible). Break-glass folds only
2453
+ `source`/`ci`/`lockfile`.
2454
+ - **Empty reason.** The CLI rejects a blank reason before `run_loop`. For
2455
+ programmatic callers, an explicitly-empty reason reaching closeout emits the
2456
+ `operator_override_missing_reason` blocker and does NOT commit the unsafe paths.
2457
+ - **Audit / bounded blast radius.** Every break-glass commit records a
2458
+ `break_glass` `CloseoutException` (exact paths + reason, in the shared tally)
2459
+ AND a phase-scoped `closeout_allow_unowned` attestation event in the ledger.
2460
+ The audit always names what was punched through and why.
2461
+
2462
+ ### Reconcile parity (BREAKGLASS SL-2)
2463
+
2464
+ `reconcile` reads the `closeout_allow_unowned` attestation event to lift the
2465
+ `unowned_dirty_paths` bail in `_clean_verified_dirty_closeout_recovery_supersedes_blocker`
2466
+ (the **non-human** verified-dirty-closeout-recovery path) — so a phase whose
2467
+ verified dirty closeout already committed but recorded an unowned remainder
2468
+ recovers under recorded operator attestation. This is *parity*, not the primary
2469
+ escape: a live human-required `closeout_scope_violation` is broken through by the
2470
+ `--closeout-allow-unowned` rerun (which commits), not by reconcile. Attestation
2471
+ matching mirrors `_lane_ir_override`: `roadmap_sha256` + `phase_sha256` (content
2472
+ freshness) + phase + non-empty reason. A **stale** attestation (content drifted
2473
+ since it was written) no longer matches and does not authorize a later closeout;
2474
+ a recorded `secrets`-class remainder never recovers (the clean-worktree guard is
2475
+ the real backstop — SL-1 never commits a secret, so the worktree stays dirty).