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,399 @@
1
+ """CS-0.11 -- brownfield ingestion: shape-to-conform, then verify.
2
+
3
+ `phase-loop consiliency-ingest --repo <path>` looks at whether the repo
4
+ already has a `.consiliency/manifest.json` -- the single detection/consent
5
+ point the whole `.consiliency` stack shares (see
6
+ :func:`consiliency_layout.find_consiliency_manifest`) -- and picks one of two
7
+ disjoint branches:
8
+
9
+ * **SHAPE** (manifest absent): a brownfield repo hasn't been touched yet.
10
+ This is CONSENT-GATED on an explicit ``--adopt``/``adopt=True`` flag -- an
11
+ unflagged repo is a pure no-op, nothing is read beyond the one existence
12
+ check and nothing is written. When adopted, this module delegates the base
13
+ layout entirely to the CS-0.5 scaffolder (:func:`consiliency_scaffold.scaffold`)
14
+ -- it never reimplements doc placement -- and then layers a CS-0.12
15
+ (contract 0.2.0) adoption profile and a PROPOSED governed-set allowlist
16
+ onto the manifest scaffold() just wrote, in the same first-writer pass.
17
+ The proposal is conservative: only the paths the required-documents
18
+ registry composed for the declared archetype(s) -- i.e. exactly the rows
19
+ scaffold() itself declared in ``documents`` -- are proposed. Nothing
20
+ ambiguous is auto-claimed, and the default ignore-set (scratchpads,
21
+ other-harness namespaces such as `.phase-loop/`, `.claude/`, `.codex/`,
22
+ ...) is never a candidate, defensively re-checked here even though the
23
+ required-documents registry can never itself emit an ignored path.
24
+ * **VERIFY** (manifest present): every subsequent pass, including a pass
25
+ over a hand-corrupted `.consiliency/`. This module NEVER rewrites; it runs
26
+ the CS-0.6 L0 gates (:func:`consiliency_gates.scan_consiliency_gates`)
27
+ as-is and additionally labels each declared document against the CS-0.12
28
+ governance-scope decision (governed / foreign / present-nonconforming),
29
+ again read-only. Detection is manifest-FILE-presence, not
30
+ manifest-schema-validity, so a corrupted manifest is flagged (via the
31
+ existing layout-validity gate) and never mistaken for "absent" -- it can
32
+ never accidentally re-trigger the shape branch and overwrite a human's
33
+ repair.
34
+
35
+ Governance-scope decision (CS-0.12 / contract 0.2.0): :func:`evaluate_governance_scope`
36
+ is a pure function over (adoption profile, governed_set, ignore_set, facet,
37
+ subject) implementing the ``governance_scope_scenario`` conformance surface
38
+ the vendored contract ships (``consiliency_contract``'s
39
+ ``conformance/vectors/{adoption,governed-set,ignore-set,doc-label}-*.json``).
40
+ Branch order, kept in sync with those vectors:
41
+
42
+ 1. no adoption profile -> ungoverned (``not-adopted``)
43
+ 2. adoption profile present but ``adopted: false`` -> ungoverned (``adoption-declined``)
44
+ 3. requested facet not in ``adopted_scope`` -> ungoverned (``out-of-scope-facet``)
45
+ 4. path matches the ignore-set (default + repo-declared) -> ungoverned
46
+ (``ignored``) -- this overrides the governed-set allowlist; it is the
47
+ safety floor scratchpads and other-harness docs sit behind.
48
+ 5. path matches no governed_set selector -> ungoverned (``undeclared-ungoverned``);
49
+ a present-but-undeclared subject is additionally labeled ``foreign``.
50
+ 6. otherwise -> governed (``declared``); an ``observed_label`` of
51
+ ``present-nonconforming`` on the subject additionally warns without
52
+ changing the governed verdict.
53
+ """
54
+ from __future__ import annotations
55
+
56
+ import fnmatch
57
+ import json
58
+ from dataclasses import dataclass
59
+ from pathlib import Path, PurePosixPath
60
+ from typing import Any, Mapping, Sequence
61
+
62
+ from jsonschema import Draft202012Validator
63
+
64
+ from consiliency_contract import load_registry
65
+
66
+ from .consiliency_gates import scan_consiliency_gates
67
+ from .consiliency_layout import (
68
+ ARCHETYPE_IDS,
69
+ contract_version_status_schema,
70
+ find_consiliency_manifest,
71
+ installed_contract_version,
72
+ interface_declaration_schema,
73
+ load_consiliency_manifest,
74
+ manifest_path,
75
+ manifest_schema,
76
+ )
77
+ from .consiliency_scaffold import ScaffoldResult, scaffold
78
+
79
+ #: The `adopted_scope` facets CS-0.6 actually gates today (presence,
80
+ #: local-integrity, layout-validity, version-skew all live under the
81
+ #: `.consiliency/` LAYOUT and are enforced by the L0 GATES). The contract's
82
+ #: adoptionProfile also allows `projections`/`cert`, but nothing in
83
+ #: agent-harness enforces those facets yet -- claiming them here would be
84
+ #: consent theater, so this module only ever declares scope it backs.
85
+ _ADOPTED_SCOPE_ENFORCED: tuple[str, ...] = ("layout", "gates")
86
+
87
+ #: Manifest document ids whose target artifact is machine-generated JSON with
88
+ #: a real vendored schema -- the only L0 surface honest enough to support a
89
+ #: content-conformance label. Prose docs are presence-only by design (see
90
+ #: consiliency_scaffold's module docstring): this module never judges
91
+ #: hand-authored markdown, so it never labels a prose doc nonconforming.
92
+ _SCHEMA_CHECKED_DOC_IDS: dict[str, Any] = {
93
+ "contract-version-status": contract_version_status_schema,
94
+ "interface-declaration": interface_declaration_schema,
95
+ }
96
+
97
+ _MESSAGES: dict[str, str] = {
98
+ "governance.not_adopted": "Repo has no adoption profile; the document is ungoverned.",
99
+ "governance.adoption_declined": "Adoption is explicitly declined (adopted:false); the document is ungoverned.",
100
+ "governance.out_of_scope_facet": "The requested facet is not in adopted_scope; the document is ungoverned for this facet.",
101
+ "governance.ignored": "Path matches the ignore-set; it is ungoverned and never ingested, overriding the governed_set match.",
102
+ "governance.undeclared": "No governed_set selector matches the document; it is ungoverned.",
103
+ "governance.foreign": "Present artifact is not in the governed set; labeled foreign (governed:false).",
104
+ "governance.governed": "Document is declared in the governed set and within an adopted scope facet.",
105
+ "governance.present_nonconforming": "Governed document is present but does not conform to its declared class.",
106
+ }
107
+
108
+
109
+ def _default_ignore_set() -> tuple[str, ...]:
110
+ return tuple(load_registry("default_ignore_set").get("namespaces", ()))
111
+
112
+
113
+ def _path_ignored(path: str, ignore_set: Sequence[str]) -> bool:
114
+ """Default-ignore-set matching rule (`consiliency_contract`'s registry):
115
+ a metachar-free entry ending in `/` is a bare directory name and matches
116
+ at ANY depth; anything containing a glob metacharacter is a glob
117
+ evaluated against the whole repo-relative path."""
118
+ parts = PurePosixPath(path).parts
119
+ for entry in ignore_set:
120
+ has_metachar = any(ch in entry for ch in "*?[")
121
+ if not has_metachar and entry.endswith("/"):
122
+ if entry.rstrip("/") in parts[:-1]:
123
+ return True
124
+ elif fnmatch.fnmatch(path, entry):
125
+ return True
126
+ return False
127
+
128
+
129
+ def _selector_matches(selector: Mapping[str, Any], subject: Mapping[str, Any]) -> bool:
130
+ by = selector.get("by")
131
+ value = str(selector.get("value") or "")
132
+ if by == "path":
133
+ return str(subject.get("path") or "") == value
134
+ if by == "glob":
135
+ return fnmatch.fnmatch(str(subject.get("path") or ""), value)
136
+ if by == "class":
137
+ return str(subject.get("class") or "") == value
138
+ return False
139
+
140
+
141
+ def evaluate_governance_scope(
142
+ *,
143
+ adoption: Mapping[str, Any] | None,
144
+ governed_set: Sequence[Mapping[str, Any]] = (),
145
+ ignore_set: Sequence[str] = (),
146
+ facet: str | None = None,
147
+ subject: Mapping[str, Any],
148
+ ) -> dict[str, Any]:
149
+ """Pure CS-0.12 governance-scope decision. See module docstring for the
150
+ branch order this implements against the vendored contract's
151
+ `governance_scope_scenario` conformance vectors."""
152
+
153
+ def _decision(*, governed: bool, reason: str, code: str, status: str = "accepted", labels: tuple[str, ...] = ()) -> dict[str, Any]:
154
+ result: dict[str, Any] = {
155
+ "schema": "consiliency.conformance_decision.v1",
156
+ "status": status,
157
+ "maturity": "presence-only",
158
+ "findings": [{"code": code, "severity": "warn" if status == "warn" else "info", "message": _MESSAGES[code]}],
159
+ "governed": governed,
160
+ "reason": reason,
161
+ }
162
+ if labels:
163
+ result["labels"] = list(labels)
164
+ return result
165
+
166
+ if adoption is not None and adoption.get("adopted") is False:
167
+ return _decision(governed=False, reason="adoption-declined", code="governance.adoption_declined")
168
+ if not adoption or not adoption.get("adopted"):
169
+ return _decision(governed=False, reason="not-adopted", code="governance.not_adopted")
170
+
171
+ adopted_scope = tuple(adoption.get("adopted_scope") or ())
172
+ if facet is not None and facet not in adopted_scope:
173
+ return _decision(governed=False, reason="out-of-scope-facet", code="governance.out_of_scope_facet")
174
+
175
+ if _path_ignored(str(subject.get("path") or ""), ignore_set):
176
+ return _decision(governed=False, reason="ignored", code="governance.ignored")
177
+
178
+ if not any(_selector_matches(selector, subject) for selector in governed_set):
179
+ if subject.get("observed_label") == "foreign":
180
+ return _decision(governed=False, reason="undeclared-ungoverned", code="governance.foreign", labels=("foreign",))
181
+ return _decision(governed=False, reason="undeclared-ungoverned", code="governance.undeclared")
182
+
183
+ if subject.get("observed_label") == "present-nonconforming":
184
+ return _decision(
185
+ governed=True, reason="declared", code="governance.present_nonconforming",
186
+ status="warn", labels=("present-nonconforming",),
187
+ )
188
+ return _decision(governed=True, reason="declared", code="governance.governed")
189
+
190
+
191
+ def _primary_archetype(mode: str, archetypes: tuple[str, ...]) -> str:
192
+ """The contract's `adoptionProfile.archetype` is singular (one enum
193
+ value, including `baseline-only`), while `declaration.archetypes` is a
194
+ set. When more than one archetype is declared, this picks the first in
195
+ registry order -- the same precedence `compose_required_documents`
196
+ already uses to resolve composition order -- as the profile's headline
197
+ archetype. This is a judgment call: the manifest's own `declaration`
198
+ remains the source of truth for the full set; `adoption.archetype` is
199
+ only ever a single-value summary of it."""
200
+ if mode == "baseline-only" or not archetypes:
201
+ return "baseline-only"
202
+ for candidate in ARCHETYPE_IDS:
203
+ if candidate in archetypes:
204
+ return candidate
205
+ return archetypes[0]
206
+
207
+
208
+ def _propose_governed_set(manifest: Mapping[str, Any]) -> list[dict[str, Any]]:
209
+ ignore_set = _default_ignore_set()
210
+ selectors: list[dict[str, Any]] = []
211
+ seen: set[str] = set()
212
+ for entry in manifest.get("documents", []):
213
+ path = entry.get("path")
214
+ if not path or path in seen:
215
+ continue
216
+ # Defensive: the required-documents registry can never itself emit
217
+ # an ignored path, but a governed-set proposal must never claim one
218
+ # even if that invariant ever drifts.
219
+ if _path_ignored(str(path), ignore_set):
220
+ continue
221
+ seen.add(path)
222
+ selectors.append({"by": "path", "value": path})
223
+ return selectors
224
+
225
+
226
+ def _observe_document_label(repo: Path, entry: Mapping[str, Any]) -> str | None:
227
+ """The only L0-honest content signal this module computes: whether a
228
+ machine-generated JSON artifact (status.json / interfaces.json)
229
+ validates against its own vendored schema. Prose docs are never judged
230
+ -- this module doesn't invent a class-conformance detector for
231
+ hand-authored markdown."""
232
+ path = entry.get("path")
233
+ if not path:
234
+ return None
235
+ file_path = repo / str(path)
236
+ if not file_path.is_file():
237
+ return None # absence is the CS-0.6 presence gate's concern, not a conformance label.
238
+ schema_loader = _SCHEMA_CHECKED_DOC_IDS.get(str(entry.get("id")))
239
+ if schema_loader is None:
240
+ return None
241
+ try:
242
+ payload = json.loads(file_path.read_text(encoding="utf-8"))
243
+ except (OSError, ValueError):
244
+ return "present-nonconforming"
245
+ errors = list(Draft202012Validator(schema_loader()).iter_errors(payload))
246
+ return "present-nonconforming" if errors else None
247
+
248
+
249
+ @dataclass(frozen=True)
250
+ class IngestResult:
251
+ repo: Path
252
+ mode: str # "shape" | "verify" | "skipped"
253
+ dry_run: bool
254
+ adopted: bool
255
+ manifest_path: Path
256
+ scaffold: dict[str, Any] | None
257
+ gate_scan: dict[str, Any] | None
258
+ governed_set: tuple[dict[str, Any], ...]
259
+ document_labels: tuple[dict[str, Any], ...]
260
+ findings: tuple[dict[str, Any], ...]
261
+
262
+ def to_json(self) -> dict[str, Any]:
263
+ return {
264
+ "repo": str(self.repo),
265
+ "mode": self.mode,
266
+ "dry_run": self.dry_run,
267
+ "adopted": self.adopted,
268
+ "manifest_path": str(self.manifest_path),
269
+ "scaffold": self.scaffold,
270
+ "gate_scan": self.gate_scan,
271
+ "governed_set": list(self.governed_set),
272
+ "document_labels": list(self.document_labels),
273
+ "findings": list(self.findings),
274
+ }
275
+
276
+
277
+ def ingest(
278
+ repo: str | Path,
279
+ *,
280
+ adopt: bool = False,
281
+ mode: str = "baseline-only",
282
+ archetypes: tuple[str, ...] = (),
283
+ modifiers: tuple[str, ...] = (),
284
+ repo_id: str | None = None,
285
+ display_name: str | None = None,
286
+ dry_run: bool = False,
287
+ ) -> IngestResult:
288
+ repo = Path(repo)
289
+ existing = find_consiliency_manifest(repo)
290
+ if existing is not None:
291
+ return _verify(repo, existing_manifest_path=existing, dry_run=dry_run)
292
+
293
+ target_manifest_path = manifest_path(repo)
294
+ if not adopt:
295
+ return IngestResult(
296
+ repo=repo, mode="skipped", dry_run=dry_run, adopted=False,
297
+ manifest_path=target_manifest_path, scaffold=None, gate_scan=None,
298
+ governed_set=(), document_labels=(),
299
+ findings=(
300
+ {
301
+ "code": "adoption.not_requested",
302
+ "severity": "info",
303
+ "message": "No .consiliency/manifest present and --adopt was not passed; repo left untouched.",
304
+ },
305
+ ),
306
+ )
307
+ return _shape(
308
+ repo, mode=mode, archetypes=archetypes, modifiers=modifiers,
309
+ repo_id=repo_id, display_name=display_name, dry_run=dry_run,
310
+ )
311
+
312
+
313
+ def _shape(
314
+ repo: Path,
315
+ *,
316
+ mode: str,
317
+ archetypes: tuple[str, ...],
318
+ modifiers: tuple[str, ...],
319
+ repo_id: str | None,
320
+ display_name: str | None,
321
+ dry_run: bool,
322
+ ) -> IngestResult:
323
+ scaffold_result: ScaffoldResult = scaffold(
324
+ repo, mode=mode, archetypes=archetypes, modifiers=modifiers,
325
+ repo_id=repo_id, display_name=display_name, dry_run=dry_run,
326
+ )
327
+ target_manifest_path = scaffold_result.manifest_path
328
+
329
+ if dry_run:
330
+ # Mirror scaffold()'s own dry-run contract: nothing on disk, report
331
+ # what WOULD happen using the same rows the (unwritten) manifest
332
+ # would have declared.
333
+ placeholder_docs = [{"path": p} for p in (*scaffold_result.created_paths, *scaffold_result.referenced_paths)]
334
+ proposed = _propose_governed_set({"documents": placeholder_docs})
335
+ return IngestResult(
336
+ repo=repo, mode="shape", dry_run=True, adopted=True,
337
+ manifest_path=target_manifest_path, scaffold=scaffold_result.to_json(),
338
+ gate_scan=None, governed_set=tuple(proposed), document_labels=(), findings=(),
339
+ )
340
+
341
+ manifest = json.loads(target_manifest_path.read_text(encoding="utf-8"))
342
+ proposed = _propose_governed_set(manifest)
343
+ manifest["adoption"] = {
344
+ "adopted": True,
345
+ "contract_version": installed_contract_version(),
346
+ "archetype": _primary_archetype(mode, archetypes),
347
+ "adopted_scope": list(_ADOPTED_SCOPE_ENFORCED),
348
+ }
349
+ manifest["governed_set"] = proposed
350
+ Draft202012Validator(manifest_schema()).validate(manifest)
351
+ target_manifest_path.write_text(json.dumps(manifest, indent=2, sort_keys=True) + "\n", encoding="utf-8")
352
+
353
+ gate_scan = scan_consiliency_gates(repo)
354
+ return IngestResult(
355
+ repo=repo, mode="shape", dry_run=False, adopted=True,
356
+ manifest_path=target_manifest_path, scaffold=scaffold_result.to_json(),
357
+ gate_scan=gate_scan, governed_set=tuple(proposed), document_labels=(), findings=(),
358
+ )
359
+
360
+
361
+ def _verify(repo: Path, *, existing_manifest_path: Path, dry_run: bool) -> IngestResult:
362
+ gate_scan = scan_consiliency_gates(repo)
363
+ manifest = load_consiliency_manifest(repo)
364
+ document_labels: list[dict[str, Any]] = []
365
+ findings: list[dict[str, Any]] = []
366
+ governed_set: tuple[dict[str, Any], ...] = ()
367
+ adopted = False
368
+
369
+ if manifest is not None:
370
+ governed_set = tuple(manifest.get("governed_set") or ())
371
+ adoption = manifest.get("adoption")
372
+ adopted = bool(adoption and adoption.get("adopted"))
373
+ ignore_set = _default_ignore_set()
374
+ for entry in manifest.get("documents", []):
375
+ path = entry.get("path")
376
+ if not path:
377
+ continue
378
+ observed_label = _observe_document_label(repo, entry)
379
+ subject = {"kind": "doc", "path": path, "class": entry.get("class"), "observed_label": observed_label}
380
+ decision = evaluate_governance_scope(
381
+ adoption=adoption, governed_set=list(governed_set),
382
+ ignore_set=ignore_set, facet="layout", subject=subject,
383
+ )
384
+ document_labels.append({"doc_id": entry.get("id"), "path": path, **decision})
385
+ if decision["status"] == "warn":
386
+ findings.append(
387
+ {
388
+ "doc_id": entry.get("id"),
389
+ "path": path,
390
+ "code": decision["findings"][0]["code"],
391
+ "message": decision["findings"][0]["message"],
392
+ }
393
+ )
394
+
395
+ return IngestResult(
396
+ repo=repo, mode="verify", dry_run=dry_run, adopted=adopted,
397
+ manifest_path=existing_manifest_path, scaffold=None, gate_scan=gate_scan,
398
+ governed_set=governed_set, document_labels=tuple(document_labels), findings=tuple(findings),
399
+ )
@@ -0,0 +1,176 @@
1
+ """Shared `.consiliency/` layout constants and lookup helpers (CS-0.5/CS-0.6).
2
+
3
+ Single source of truth for where the `.consiliency/` artifacts live and how a
4
+ manifest is composed against the vendored `consiliency_contract` package data.
5
+ The scaffolder (``consiliency_scaffold``), the L0 gates
6
+ (``consiliency_gates``), and the runner's consent check must all agree on
7
+ this path -- drift here would be a silent bug (an operator could scaffold a
8
+ manifest the gates never find).
9
+
10
+ Version-gated DUAL-READ (CS-0.5 scope): this module is purely additive. It
11
+ never reads or writes ``.phase-loop/`` or ``.pipeline/``, and nothing in the
12
+ existing runtime is rewired to prefer `.consiliency/` yet -- that fallback
13
+ seam is for CS-0.12 once the adoption-profile consent check lands. Today,
14
+ `.consiliency/` and legacy layouts simply coexist.
15
+ """
16
+ from __future__ import annotations
17
+
18
+ import json
19
+ from dataclasses import dataclass
20
+ from pathlib import Path
21
+ from typing import Any, Mapping
22
+
23
+ from consiliency_contract import CONTRACT_VERSION, load_registry, load_schema
24
+
25
+ #: Repo-relative root for all Consiliency-standard artifacts.
26
+ CONSILIENCY_DIR = ".consiliency"
27
+ #: Filenames within CONSILIENCY_DIR, pinned to the shapes used by the
28
+ #: contract's own conformance vectors (manifest-valid-product.json uses
29
+ #: ".consiliency/status.json" and ".consiliency/interfaces.json").
30
+ MANIFEST_FILENAME = "manifest.json"
31
+ STATUS_FILENAME = "status.json"
32
+ INTERFACES_FILENAME = "interfaces.json"
33
+ #: Stub documents the scaffolder is allowed to author live under this
34
+ #: sub-namespace so they can never collide with a repo's own doc layout.
35
+ STUB_DOCS_SUBDIR = "docs"
36
+
37
+ ARCHETYPE_IDS: tuple[str, ...] = ("product", "service", "library", "infra", "tooling-meta", "experiment", "document")
38
+ MODIFIER_IDS: tuple[str, ...] = ("data-bearing", "public", "regulated", "user-facing")
39
+
40
+
41
+ def consiliency_root(repo: Path) -> Path:
42
+ return Path(repo) / CONSILIENCY_DIR
43
+
44
+
45
+ def manifest_path(repo: Path) -> Path:
46
+ return consiliency_root(repo) / MANIFEST_FILENAME
47
+
48
+
49
+ def status_path(repo: Path) -> Path:
50
+ return consiliency_root(repo) / STATUS_FILENAME
51
+
52
+
53
+ def interfaces_path(repo: Path) -> Path:
54
+ return consiliency_root(repo) / INTERFACES_FILENAME
55
+
56
+
57
+ def find_consiliency_manifest(repo: str | Path) -> Path | None:
58
+ """The one place that decides whether a repo has opted into Consiliency.
59
+
60
+ Every consumer (scaffolder overwrite checks, all four L0 gates, and the
61
+ runner's top-of-loop/closeout hooks) MUST call this rather than
62
+ re-deriving the path, so the CS-0.6 consent gate ("act only on repos that
63
+ HAVE a `.consiliency/manifest`") is enforced identically everywhere.
64
+ """
65
+ path = manifest_path(Path(repo))
66
+ return path if path.is_file() else None
67
+
68
+
69
+ def load_consiliency_manifest(repo: str | Path) -> dict[str, Any] | None:
70
+ """Parsed manifest, or ``None`` when absent OR unparsable.
71
+
72
+ Unparsable is folded into "no consent" rather than raised -- a corrupt
73
+ manifest must never crash the loop; the layout-validity gate is what
74
+ reports that condition as a finding.
75
+ """
76
+ path = find_consiliency_manifest(repo)
77
+ if path is None:
78
+ return None
79
+ try:
80
+ return json.loads(path.read_text(encoding="utf-8"))
81
+ except (OSError, ValueError):
82
+ return None
83
+
84
+
85
+ @dataclass(frozen=True)
86
+ class RequiredDocRow:
87
+ id: str
88
+ doc_class: str
89
+ required: bool
90
+ maturity_floor: str
91
+ l0_stub_allowed: bool
92
+ l0_note: str | None = None
93
+ source: str = "baseline" # baseline | archetype:<id> | modifier:<id>
94
+
95
+
96
+ class RequiredDocumentConflict(ValueError):
97
+ """Two composed rows share an id but are not byte-identical."""
98
+
99
+
100
+ def compose_required_documents(
101
+ *,
102
+ mode: str,
103
+ archetypes: tuple[str, ...] = (),
104
+ modifiers: tuple[str, ...] = (),
105
+ ) -> tuple[RequiredDocRow, ...]:
106
+ """Compose the required-document set per the registry's own composition
107
+ order: baseline first, then archetypes in REGISTRY order (not input
108
+ order), then modifiers in registry order. Byte-identical duplicate ids are
109
+ de-duplicated; conflicting duplicate ids fail (registry policy)."""
110
+ if mode not in ("baseline-only", "archetyped"):
111
+ raise ValueError(f"invalid declaration mode: {mode!r}")
112
+ registry = load_registry("required_documents")
113
+ archetype_registry = load_registry("archetypes")
114
+ registry_archetype_order = [entry["id"] for entry in archetype_registry["archetypes"]]
115
+ registry_modifier_order = [entry["id"] for entry in archetype_registry["modifiers"]]
116
+
117
+ rows_by_id: dict[str, RequiredDocRow] = {}
118
+ raw_by_id: dict[str, dict[str, Any]] = {}
119
+
120
+ def _add(raw: Mapping[str, Any], source: str) -> None:
121
+ doc_id = raw["id"]
122
+ if doc_id in raw_by_id and raw_by_id[doc_id] != dict(raw):
123
+ raise RequiredDocumentConflict(
124
+ f"required-document id {doc_id!r} conflicts between {rows_by_id[doc_id].source!r} and {source!r}"
125
+ )
126
+ if doc_id in raw_by_id:
127
+ return # byte-identical duplicate -- de-dupe silently.
128
+ raw_by_id[doc_id] = dict(raw)
129
+ rows_by_id[doc_id] = RequiredDocRow(
130
+ id=doc_id,
131
+ doc_class=raw["class"],
132
+ required=bool(raw.get("required", True)),
133
+ maturity_floor=raw["maturity_floor"],
134
+ l0_stub_allowed=bool(raw.get("l0_stub_allowed", False)),
135
+ l0_note=raw.get("l0_note"),
136
+ source=source,
137
+ )
138
+
139
+ for raw in registry["baseline"]:
140
+ _add(raw, "baseline")
141
+ if mode == "archetyped":
142
+ for archetype_id in registry_archetype_order:
143
+ if archetype_id not in archetypes:
144
+ continue
145
+ for raw in registry.get("archetypes", {}).get(archetype_id, ()):
146
+ _add(raw, f"archetype:{archetype_id}")
147
+ for modifier_id in registry_modifier_order:
148
+ if modifier_id not in modifiers:
149
+ continue
150
+ for raw in registry.get("modifiers", {}).get(modifier_id, ()):
151
+ _add(raw, f"modifier:{modifier_id}")
152
+ return tuple(rows_by_id[doc_id] for doc_id in raw_by_id)
153
+
154
+
155
+ def installed_contract_version() -> str:
156
+ return CONTRACT_VERSION
157
+
158
+
159
+ def manifest_schema() -> dict[str, Any]:
160
+ return load_schema("manifest")
161
+
162
+
163
+ def contract_version_status_schema() -> dict[str, Any]:
164
+ return load_schema("contract_version_status")
165
+
166
+
167
+ def interface_declaration_schema() -> dict[str, Any]:
168
+ return load_schema("interface_declaration")
169
+
170
+
171
+ def version_skew_protocol() -> dict[str, Any]:
172
+ return load_schema("version_skew_protocol")
173
+
174
+
175
+ def loop_gate_protocol() -> dict[str, Any]:
176
+ return load_schema("loop_gate_protocol")