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,225 @@
1
+ """User-editable board config loader (ABDREG, Phase 2 — lane 4).
2
+
3
+ Loads ``$XDG_CONFIG_HOME/agent-harness/advisor-boards.toml`` (the FROZEN location,
4
+ ``schema.board_config_path``; format frozen by
5
+ ``fixtures/advisor-boards.example.toml``) and layers user boards on top of the
6
+ built-in ``presets``. Contract:
7
+
8
+ * The four built-in presets are always present (base layer); a user ``[[boards]]``
9
+ with the same ``name`` overrides its preset.
10
+ * ``allow_api_key_fallback`` defaults ``False`` — a board with an ``api_key`` seat
11
+ and no opt-in is rejected by the ``Board`` schema (never-silent-key).
12
+ * **Unknown keys are a hard error, never a silent drop** — an unrecognised
13
+ top-level, board, or seat key raises ``BoardConfigError`` naming the key.
14
+ * Every board (presets AND user boards) is validated through the compatibility
15
+ matrix at load time, so an invalid ``(model, harness)`` pairing (e.g.
16
+ ``claude:gpt-5.5``) or an over-ceiling effort is rejected at CONFIG TIME with an
17
+ actionable message (``validation.validate_board``).
18
+
19
+ A missing config file is not an error: the built-in presets load on their own.
20
+ """
21
+ from __future__ import annotations
22
+
23
+ from collections.abc import Mapping
24
+ from dataclasses import dataclass
25
+ from pathlib import Path
26
+ from typing import Any
27
+
28
+ try: # Python 3.11+
29
+ import tomllib # type: ignore[import-not-found]
30
+ except ModuleNotFoundError: # Python 3.10 — the requires-python floor
31
+ import tomli as tomllib # type: ignore[no-redef]
32
+
33
+ from .validation import SeatValidationError, validate_board
34
+ from .presets import DEFAULT_BOARD_NAME, PRESETS
35
+ from .schema import (
36
+ AUTH_LANES,
37
+ PROVIDER_BACKINGS,
38
+ Board,
39
+ Seat,
40
+ board_config_path,
41
+ )
42
+
43
+ # Recognised keys — anything else is a hard error (no silent drop).
44
+ _KNOWN_TOP_KEYS: frozenset[str] = frozenset({"default_board", "boards"})
45
+ _KNOWN_BOARD_KEYS: frozenset[str] = frozenset(
46
+ {"name", "purpose", "allow_api_key_fallback", "seats"}
47
+ )
48
+ _KNOWN_SEAT_KEYS: frozenset[str] = frozenset(
49
+ {"model", "effort", "harness", "lens", "auth", "backing", "host_leg"}
50
+ )
51
+
52
+
53
+ class BoardConfigError(ValueError):
54
+ """The board config is malformed: an unknown key, a wrong-typed value, a
55
+ missing required field, or a board that fails matrix validation."""
56
+
57
+
58
+ @dataclass(frozen=True)
59
+ class BoardConfig:
60
+ """Resolved board set: the built-in presets overlaid with the user's boards,
61
+ plus the resolved ``default_board`` name."""
62
+
63
+ boards: dict[str, Board]
64
+ default_board: str
65
+
66
+ def get(self, name: str | None = None) -> Board:
67
+ """Resolve a board by name; a bare ``advisor-board`` (``name is None``)
68
+ resolves to ``default_board``. Raises ``BoardConfigError`` naming the
69
+ available boards for an unknown name."""
70
+ key = name or self.default_board
71
+ try:
72
+ return self.boards[key]
73
+ except KeyError as exc:
74
+ available = ", ".join(sorted(self.boards))
75
+ raise BoardConfigError(
76
+ f"unknown board {key!r}; available boards: {available}"
77
+ ) from exc
78
+
79
+ def names(self) -> tuple[str, ...]:
80
+ return tuple(sorted(self.boards))
81
+
82
+
83
+ def _reject_unknown(keys, allowed: frozenset[str], where: str) -> None:
84
+ unknown = sorted(set(keys) - allowed)
85
+ if unknown:
86
+ raise BoardConfigError(
87
+ f"unknown config key(s) {unknown} in {where}; "
88
+ f"recognised keys: {sorted(allowed)}"
89
+ )
90
+
91
+
92
+ def _require_bool(raw: Mapping[str, Any], key: str, default: bool, where: str) -> bool:
93
+ """Read a boolean config key STRICTLY: an absent key yields ``default``, a
94
+ present key MUST be a literal TOML boolean. Never coerce a non-bool scalar —
95
+ ``bool("false")`` is ``True``, so coercion would silently flip an opt-in gate
96
+ (e.g. a quoted ``allow_api_key_fallback = "false"`` would enable the api-key
97
+ fallback). A wrong-typed value is a hard ``BoardConfigError`` naming the key."""
98
+ if key not in raw:
99
+ return default
100
+ value = raw[key]
101
+ if not isinstance(value, bool):
102
+ raise BoardConfigError(
103
+ f"{where}: {key!r} must be a boolean (true/false), got "
104
+ f"{type(value).__name__} {value!r}"
105
+ )
106
+ return value
107
+
108
+
109
+ def _parse_seat(raw: Mapping[str, Any], where: str) -> Seat:
110
+ if not isinstance(raw, Mapping):
111
+ raise BoardConfigError(f"{where} must be a table, got {type(raw).__name__}")
112
+ _reject_unknown(raw.keys(), _KNOWN_SEAT_KEYS, where)
113
+ if "model" not in raw:
114
+ raise BoardConfigError(f"{where} is missing the required 'model' key")
115
+ if "effort" not in raw:
116
+ raise BoardConfigError(f"{where} (model={raw['model']!r}) is missing the required 'effort' key")
117
+ auth = raw.get("auth", AUTH_LANES[0])
118
+ backing = raw.get("backing", PROVIDER_BACKINGS[0])
119
+ try:
120
+ return Seat(
121
+ model=str(raw["model"]),
122
+ effort=str(raw["effort"]),
123
+ harness=(str(raw["harness"]) if raw.get("harness") is not None else None),
124
+ lens=(str(raw["lens"]) if raw.get("lens") is not None else None),
125
+ auth=str(auth),
126
+ backing=str(backing),
127
+ host_leg=_require_bool(raw, "host_leg", False, where),
128
+ )
129
+ except (ValueError, TypeError) as exc:
130
+ # Seat.__post_init__ fail-closed validation (bad effort/auth/backing) ->
131
+ # surface as a config error at load time.
132
+ raise BoardConfigError(f"{where}: {exc}") from exc
133
+
134
+
135
+ def _parse_board(raw: Mapping[str, Any], index: int) -> Board:
136
+ where = f"boards[{index}]"
137
+ if not isinstance(raw, Mapping):
138
+ raise BoardConfigError(f"{where} must be a table, got {type(raw).__name__}")
139
+ _reject_unknown(raw.keys(), _KNOWN_BOARD_KEYS, where)
140
+ if "name" not in raw:
141
+ raise BoardConfigError(f"{where} is missing the required 'name' key")
142
+ name = str(raw["name"])
143
+ seats_raw = raw.get("seats", [])
144
+ if not isinstance(seats_raw, list):
145
+ raise BoardConfigError(f"board {name!r} 'seats' must be a list of seat tables")
146
+ seats = tuple(
147
+ _parse_seat(seat, f"board {name!r} seats[{i}]") for i, seat in enumerate(seats_raw)
148
+ )
149
+ try:
150
+ return Board(
151
+ name=name,
152
+ purpose=str(raw.get("purpose", "")),
153
+ seats=seats,
154
+ allow_api_key_fallback=_require_bool(
155
+ raw, "allow_api_key_fallback", False, where
156
+ ),
157
+ )
158
+ except (ValueError, TypeError) as exc:
159
+ # Board.__post_init__ (e.g. api_key seat without opt-in) -> config error.
160
+ raise BoardConfigError(f"board {name!r}: {exc}") from exc
161
+
162
+
163
+ def load_boards(
164
+ path: Path | None = None,
165
+ *,
166
+ env: Mapping[str, str] | None = None,
167
+ matrix: Any | None = None,
168
+ validate: bool = True,
169
+ ) -> BoardConfig:
170
+ """Load the board config, layering user boards over the built-in presets.
171
+
172
+ ``path`` defaults to ``board_config_path(env)``. A missing file yields just the
173
+ presets. ``matrix`` defaults to ``matrix.default_matrix()``; pass ``validate=
174
+ False`` only for shape-parsing without availability (kept for tests). Raises
175
+ ``BoardConfigError`` for any unknown key, malformed value, or matrix-invalid
176
+ board — never a silent drop.
177
+ """
178
+ boards: dict[str, Board] = dict(PRESETS)
179
+ default_board = DEFAULT_BOARD_NAME
180
+
181
+ cfg_path = path if path is not None else board_config_path(env)
182
+ if cfg_path.exists():
183
+ with open(cfg_path, "rb") as fh:
184
+ try:
185
+ data = tomllib.load(fh)
186
+ except tomllib.TOMLDecodeError as exc:
187
+ raise BoardConfigError(f"{cfg_path} is not valid TOML: {exc}") from exc
188
+ _reject_unknown(data.keys(), _KNOWN_TOP_KEYS, str(cfg_path))
189
+ raw_boards = data.get("boards", [])
190
+ if not isinstance(raw_boards, list):
191
+ raise BoardConfigError(f"{cfg_path}: 'boards' must be an array of tables")
192
+ for i, raw in enumerate(raw_boards):
193
+ board = _parse_board(raw, i)
194
+ boards[board.name] = board # user board overrides a same-named preset
195
+ if "default_board" in data:
196
+ default_board = str(data["default_board"])
197
+
198
+ if default_board not in boards:
199
+ available = ", ".join(sorted(boards))
200
+ raise BoardConfigError(
201
+ f"default_board {default_board!r} is not a defined board; "
202
+ f"available boards: {available}"
203
+ )
204
+
205
+ if validate:
206
+ if matrix is None:
207
+ from .matrix import default_matrix
208
+
209
+ matrix = default_matrix(env=env)
210
+ for board in boards.values():
211
+ try:
212
+ validate_board(board, matrix=matrix)
213
+ except SeatValidationError as exc:
214
+ # Surface matrix-level rejections under the config error type so a
215
+ # caller catches one exception for any load-time failure.
216
+ raise BoardConfigError(str(exc)) from exc
217
+
218
+ return BoardConfig(boards=boards, default_board=default_board)
219
+
220
+
221
+ __all__ = [
222
+ "BoardConfig",
223
+ "BoardConfigError",
224
+ "load_boards",
225
+ ]
@@ -0,0 +1,115 @@
1
+ """Internal advisor-board event envelope + best-effort forwarding (IF-0-ABDFREEZE-5).
2
+
3
+ This is OUR event shape — deliberately NOT a guessed Omnigent schema. It freezes
4
+ the observability contract's two load-bearing rules:
5
+
6
+ * **launcher != observability-plane**: a natively-launched leg stays natively
7
+ launched and *emits* an ``AdvisorBoardEvent`` into a forwarded stream; it is
8
+ never relaunched through the gateway for observability's sake.
9
+ * **forwarding is async/best-effort and can NEVER delay or fail the native
10
+ leg**: ``best_effort_forward`` swallows every sink error and (by contract)
11
+ hands the event to the sink off the leg's critical path.
12
+
13
+ The MAPPING from this envelope to a concrete sink (an Omnigent v0.4.0 ingestion
14
+ endpoint, or omniagent-plus's own ui-read-model / state-ledger) is deferred to
15
+ ABDOBS — do NOT freeze against a guessed upstream schema.
16
+ """
17
+ from __future__ import annotations
18
+
19
+ from collections.abc import Mapping
20
+ from dataclasses import dataclass, field
21
+ from typing import Any, Protocol, runtime_checkable
22
+
23
+ # Bumped only on a breaking change to the envelope; sinks key off it.
24
+ EVENT_SCHEMA_VERSION = "advisor_board.event.v1"
25
+
26
+ # The frozen event kinds a board leg emits. Board-level bracket the run; seat-level
27
+ # mirror a leg's lifecycle (aligned with the runtime ``runtime.*`` names in
28
+ # agent_runtime_provider.RuntimeEvent, but named in OUR namespace).
29
+ EVENT_KINDS: tuple[str, ...] = (
30
+ "board.started",
31
+ "board.completed",
32
+ "seat.started",
33
+ "seat.text.delta",
34
+ "seat.completed",
35
+ "seat.failed",
36
+ "seat.skipped",
37
+ )
38
+
39
+
40
+ @dataclass(frozen=True)
41
+ class AdvisorBoardEvent:
42
+ """One observability event from a board run — our envelope, sink-agnostic.
43
+
44
+ ``board`` the board name (e.g. ``"default"``).
45
+ ``seat_key`` the emitting seat's stable identity (``Seat.seat_key``);
46
+ empty for ``board.*`` events.
47
+ ``vendor_family`` the seat's projected vendor family (empty for board events).
48
+ ``harness`` the seat's execution lane (empty for board events).
49
+ ``kind`` one of ``EVENT_KINDS``.
50
+ ``sequence`` monotonic per board run.
51
+ ``occurred_at`` ISO-8601 UTC timestamp (caller-supplied; frozen field only).
52
+ ``payload`` kind-specific fields (e.g. ``{"delta": ...}`` /
53
+ ``{"status": ...}``); never carries a raw API key.
54
+ """
55
+
56
+ kind: str
57
+ board: str
58
+ sequence: int
59
+ occurred_at: str
60
+ seat_key: str = ""
61
+ vendor_family: str = ""
62
+ harness: str = ""
63
+ schema_version: str = EVENT_SCHEMA_VERSION
64
+ payload: Mapping[str, Any] = field(default_factory=dict)
65
+
66
+ def __post_init__(self) -> None:
67
+ if self.kind not in EVENT_KINDS:
68
+ raise ValueError(f"event.kind {self.kind!r} not in {EVENT_KINDS}")
69
+
70
+ def to_json(self) -> dict[str, Any]:
71
+ """Stable serialization for a sink. Field set is the frozen wire contract."""
72
+ return {
73
+ "schema_version": self.schema_version,
74
+ "kind": self.kind,
75
+ "board": self.board,
76
+ "seat_key": self.seat_key,
77
+ "vendor_family": self.vendor_family,
78
+ "harness": self.harness,
79
+ "sequence": self.sequence,
80
+ "occurred_at": self.occurred_at,
81
+ "payload": dict(self.payload),
82
+ }
83
+
84
+
85
+ @runtime_checkable
86
+ class EventSink(Protocol):
87
+ """A destination for advisor-board events. The concrete mapping to Omnigent /
88
+ ui-read-model / state-ledger is ABDOBS; this only fixes the emit surface."""
89
+
90
+ def emit(self, event: AdvisorBoardEvent) -> None: ...
91
+
92
+
93
+ class NullSink:
94
+ """Default sink: drops every event. Keeps the ``default`` board's observability
95
+ a no-op (today's behavior: no forwarding) until ABDOBS wires a real sink."""
96
+
97
+ def emit(self, event: AdvisorBoardEvent) -> None: # noqa: D401 - trivial
98
+ return None
99
+
100
+
101
+ def best_effort_forward(sink: EventSink | None, event: AdvisorBoardEvent) -> bool:
102
+ """Forward ``event`` to ``sink``, swallowing EVERY error.
103
+
104
+ Returns whether the sink accepted the event; a ``None`` sink or any raised
105
+ exception returns ``False`` WITHOUT propagating — forwarding must never delay
106
+ or fail the native leg (IF-0-ABDFREEZE-5). The async dispatch (off the leg's
107
+ critical path) is ABDOBS's to wire; the never-raise guarantee is frozen here.
108
+ """
109
+ if sink is None:
110
+ return False
111
+ try:
112
+ sink.emit(event)
113
+ return True
114
+ except Exception: # best-effort: an observability failure NEVER touches the leg
115
+ return False
@@ -0,0 +1,59 @@
1
+ # Advisor Board config — FROZEN FORMAT (IF-0-ABDFREEZE-1).
2
+ #
3
+ # Location: $XDG_CONFIG_HOME/agent-harness/advisor-boards.toml
4
+ # (default ~/.config/agent-harness/advisor-boards.toml)
5
+ #
6
+ # This is the on-disk shape ABDREG's loader parses. It is a fixture only — the
7
+ # loader, board presets, and unknown-key validation land in ABDREG (Phase 2).
8
+ # A board is a named, purpose-tagged, OPEN-ENDED list of seats. A seat is a
9
+ # cognition {model, effort, harness?, lens?, auth?, backing?}, model-first: the
10
+ # harness is a defaulted-but-overridable execution lane.
11
+
12
+ # Optional: the board a bare `advisor-board` invocation resolves to.
13
+ default_board = "default"
14
+
15
+ # The default board reproduces today's 3-leg panel (byte-for-byte back-compat).
16
+ # Its three seats, in panel-leg order, render to today's exact CLI invocations:
17
+ # codex gpt-5.5 effort=max -> -c model_reasoning_effort=xhigh
18
+ # gemini "Gemini 3.1 Pro" effort=high -> model "Gemini 3.1 Pro (High)"
19
+ # claude claude-sonnet-5 effort=max -> --effort max
20
+ [[boards]]
21
+ name = "default"
22
+ purpose = "premerge-review"
23
+ allow_api_key_fallback = false
24
+
25
+ [[boards.seats]]
26
+ model = "gpt-5.5"
27
+ effort = "max"
28
+ harness = "codex" # optional; omit to resolve via default_lane(model)
29
+ auth = "subscription" # subscription (default) | api_key
30
+ backing = "homebrew" # homebrew (default) | omnigent
31
+
32
+ [[boards.seats]]
33
+ model = "Gemini 3.1 Pro"
34
+ effort = "high"
35
+ harness = "gemini"
36
+
37
+ [[boards.seats]]
38
+ model = "claude-sonnet-5"
39
+ effort = "max"
40
+ harness = "claude"
41
+
42
+ # A purpose-tagged preset with an open-ended seat list (ABDREG ships the real
43
+ # presets: default, code-review, brainstorm, doc-edit, legal-review,
44
+ # legal-strategy-review, legal-brainstorm).
45
+ [[boards]]
46
+ name = "code-review"
47
+ purpose = "code-review"
48
+ allow_api_key_fallback = false
49
+
50
+ [[boards.seats]]
51
+ model = "gpt-5.5"
52
+ effort = "max"
53
+ harness = "codex"
54
+
55
+ [[boards.seats]]
56
+ model = "claude-sonnet-5"
57
+ effort = "max"
58
+ harness = "claude"
59
+ lens = "adversarial" # optional review lens/persona
@@ -0,0 +1,91 @@
1
+ """Shared canonical fixtures (IF-0-ABDFREEZE-2 keystone).
2
+
3
+ ONE fixture set, importable from both ``src`` and ``tests``, that ABDREG
4
+ populates *from* and ABDRESOLVE / ABDHOME test *against* — so the parallel lanes
5
+ never diverge into a mock-vs-real integration cliff.
6
+
7
+ The values here are **golden expectations**, deliberately hard-coded (not derived
8
+ from ``panel_invoker``) so a change to today's panel constants trips
9
+ ``tests/test_advisor_board_backcompat.py`` instead of silently re-baselining. The
10
+ back-compat proof re-derives each default seat's invocation and asserts it equals
11
+ today's literals in ``panel_invoker`` (``DEFAULT_LEG_MODELS`` +
12
+ ``_API_KEY_VARS``).
13
+ """
14
+ from __future__ import annotations
15
+
16
+ from .schema import (
17
+ AUTH_SUBSCRIPTION,
18
+ BACKING_HOMEBREW,
19
+ Board,
20
+ Seat,
21
+ )
22
+
23
+ # The built-3 panel legs, in ``panel_invoker.PANEL_LEGS`` order — the order the
24
+ # default board's seats MUST preserve for byte-for-byte back-compat.
25
+ CANONICAL_LEG_ORDER: tuple[str, ...] = ("codex", "gemini", "claude")
26
+
27
+ # The default board's three seats — model-first, effort split out of the model
28
+ # name. These reconstruct today's ``DEFAULT_LEG_MODELS`` under
29
+ # ``harness_mapping.render_seat_invocation``:
30
+ # codex gpt-5.5 + effort max -> ``-c model_reasoning_effort=xhigh``
31
+ # gemini "Gemini 3.1 Pro" + effort high -> model ``"Gemini 3.1 Pro (High)"``
32
+ # claude claude-fable-5 + effort max -> ``--effort max``
33
+ #
34
+ # The claude seat runs Fable (``claude-fable-5``): pre-merge review is a mid-tier
35
+ # decision where being wrong is expensive, so the default review board reviews on
36
+ # Fable, not on the implementer model ``claude-sonnet-5``. This is byte-pinned to
37
+ # ``panel_invoker.DEFAULT_LEG_MODELS["claude"]`` (also Fable) by the golden proof.
38
+ DEFAULT_SEATS: tuple[Seat, ...] = (
39
+ Seat(model="gpt-5.5", effort="max", harness="codex",
40
+ auth=AUTH_SUBSCRIPTION, backing=BACKING_HOMEBREW),
41
+ Seat(model="Gemini 3.1 Pro", effort="high", harness="gemini",
42
+ auth=AUTH_SUBSCRIPTION, backing=BACKING_HOMEBREW),
43
+ Seat(model="claude-fable-5", effort="max", harness="claude",
44
+ auth=AUTH_SUBSCRIPTION, backing=BACKING_HOMEBREW),
45
+ )
46
+
47
+ DEFAULT_BOARD: Board = Board(
48
+ name="default",
49
+ purpose="premerge-review",
50
+ seats=DEFAULT_SEATS,
51
+ allow_api_key_fallback=False,
52
+ )
53
+
54
+ # Golden literals the default seats must reproduce (cross-checked in the
55
+ # back-compat test against the live ``panel_invoker`` constants).
56
+ DEFAULT_SEAT_RENDERED_MODEL: dict[str, str] = {
57
+ "codex": "gpt-5.5",
58
+ "gemini": "Gemini 3.1 Pro (High)",
59
+ "claude": "claude-fable-5",
60
+ }
61
+ DEFAULT_SEAT_EFFORT_ARGS: dict[str, tuple[str, ...]] = {
62
+ "codex": ("-c", "model_reasoning_effort=xhigh"),
63
+ "gemini": (),
64
+ "claude": ("--effort", "max"),
65
+ }
66
+
67
+ # Canonical (model x harness) pairs ABDREG's matrix + ABDRESOLVE's validation test
68
+ # against. Same-vendor-across-harness (gpt-5.5 on codex and opencode) is VALID and
69
+ # projects to one family; a cross-vendor mismatch (gpt-5.5 on claude) is INVALID.
70
+ CANONICAL_VALID_PAIRS: tuple[tuple[str, str], ...] = (
71
+ ("gpt-5.5", "codex"),
72
+ ("gpt-5.5", "opencode"),
73
+ ("claude-sonnet-5", "claude"),
74
+ ("Gemini 3.1 Pro", "gemini"),
75
+ )
76
+ CANONICAL_INVALID_PAIRS: tuple[tuple[str, str], ...] = (
77
+ ("gpt-5.5", "claude"), # openai-family model on the claude lane
78
+ ("claude-sonnet-5", "codex"), # anthropic model on the codex lane
79
+ )
80
+
81
+ # A two-same-vendor-seat board: exercises result re-keying (leg -> seat) and the
82
+ # governed reviewer != author disjointness under model-first (both seats project
83
+ # to ``codex``). Used by ABDRESOLVE / ABDHOME.
84
+ TWO_SAME_VENDOR_BOARD: Board = Board(
85
+ name="two-openai",
86
+ purpose="brainstorm",
87
+ seats=(
88
+ Seat(model="gpt-5.5", effort="high", harness="codex"),
89
+ Seat(model="gpt-5.5", effort="high", harness="opencode"),
90
+ ),
91
+ )
@@ -0,0 +1,125 @@
1
+ """Per-harness model/effort -> invocation mapping (IF-0-ABDFREEZE-1).
2
+
3
+ The v5 panel-verification found that **per-leg effort is NOT supported today** —
4
+ it is hard-coded per leg (claude ``--effort max`` panel_invoker.py:324, codex
5
+ ``model_reasoning_effort=xhigh`` :992) and for the agy/gemini leg **effort is
6
+ baked into the model-name string** (``"Gemini 3.1 Pro (High)"`` :51/:1016). The
7
+ model-first ``{model, effort}`` split therefore needs a per-harness mapping that
8
+ turns a canonical ``(model, effort)`` back into each harness's actual invocation.
9
+
10
+ This module freezes that contract. ABDHOME does the plumbing (reaching the real
11
+ CLI arg lists in `panel_invoker`); it codes against ``render_seat_invocation``.
12
+ The freeze is load-bearing for back-compat: the ``default`` board's three seats
13
+ MUST render to today's exact literals —
14
+
15
+ claude -> effort flag ``--effort max``
16
+ codex -> config override ``-c model_reasoning_effort=xhigh``
17
+ gemini -> model-name embed ``Gemini 3.1 Pro (High)``
18
+
19
+ — proven by ``tests/test_advisor_board_backcompat.py`` against the live
20
+ `panel_invoker` constants (`DEFAULT_LEG_MODELS`, the codex/claude/agy arg forms).
21
+ """
22
+ from __future__ import annotations
23
+
24
+ import re
25
+ from dataclasses import dataclass
26
+
27
+ from .schema import EFFORT_LEVELS
28
+
29
+
30
+ class EffortMappingError(NotImplementedError):
31
+ """Raised when a harness's effort mapping is not frozen here (breadth lanes
32
+ land in ABDREG/ABDHOME/ABDOMNI)."""
33
+
34
+
35
+ # Effort mechanism: HOW the effort reaches the CLI for a harness.
36
+ MECH_FLAG = "flag" # a dedicated flag, e.g. claude ``--effort <level>``
37
+ MECH_CONFIG = "config" # a ``-c key=value`` override, e.g. codex reasoning
38
+ MECH_MODEL_NAME = "model_name" # baked into the model string, e.g. agy/gemini
39
+
40
+
41
+ @dataclass(frozen=True)
42
+ class SeatInvocation:
43
+ """The frozen, harness-specific shape ``(model, effort)`` renders to.
44
+
45
+ ``model`` the model string to pass to the CLI (effort-embedded for the
46
+ ``model_name`` mechanism; otherwise the model verbatim).
47
+ ``effort_args`` extra CLI args carrying effort (empty for ``model_name``).
48
+ ``mechanism`` one of ``MECH_FLAG`` / ``MECH_CONFIG`` / ``MECH_MODEL_NAME``.
49
+ ``harness`` the execution lane this rendering targets.
50
+ """
51
+
52
+ harness: str
53
+ model: str
54
+ effort_args: tuple[str, ...]
55
+ mechanism: str
56
+
57
+
58
+ # canonical effort -> codex ``model_reasoning_effort`` token. codex's max reasoning
59
+ # is ``xhigh`` (panel_invoker.py:992), so canonical ``max`` -> ``xhigh``.
60
+ _CODEX_EFFORT: dict[str, str] = {
61
+ "low": "low",
62
+ "medium": "medium",
63
+ "high": "high",
64
+ "max": "xhigh",
65
+ }
66
+
67
+ # canonical effort -> the ``(Word)`` token agy/gemini bakes into the model name
68
+ # (panel_invoker.py:1016 uses ``(High)``).
69
+ _GEMINI_EFFORT_WORD: dict[str, str] = {
70
+ "low": "Low",
71
+ "medium": "Medium",
72
+ "high": "High",
73
+ "max": "Max",
74
+ }
75
+
76
+ # strip a trailing ``" (Effort)"`` embed so re-rendering is idempotent when a caller
77
+ # passes an already-baked model string (e.g. ``"Gemini 3.1 Pro (High)"``). Matches
78
+ # ONLY the four canonical effort words (the Title-case tokens ``render_gemini_model``
79
+ # emits) — a model whose name genuinely ends in a parenthetical (e.g.
80
+ # ``"Gemini 3.1 Pro (Preview)"``) is a DIFFERENT model and must be left untouched,
81
+ # never silently rewritten to a lower effort.
82
+ _GEMINI_EMBED_RE = re.compile(r"\s*\((?:Low|Medium|High|Max)\)\s*$")
83
+
84
+
85
+ def gemini_base_model(model: str) -> str:
86
+ """Return the gemini model with any trailing ``(Effort)`` embed removed."""
87
+ return _GEMINI_EMBED_RE.sub("", model or "").strip()
88
+
89
+
90
+ def render_gemini_model(model: str, effort: str) -> str:
91
+ """``("Gemini 3.1 Pro", "high") -> "Gemini 3.1 Pro (High)"`` — the agy leg's
92
+ effort-in-the-model-name special case. Idempotent on an already-baked model."""
93
+ _require_effort(effort)
94
+ return f"{gemini_base_model(model)} ({_GEMINI_EFFORT_WORD[effort]})"
95
+
96
+
97
+ def _require_effort(effort: str) -> None:
98
+ if effort not in EFFORT_LEVELS:
99
+ raise ValueError(f"effort {effort!r} not in {EFFORT_LEVELS}")
100
+
101
+
102
+ def render_seat_invocation(harness: str, model: str, effort: str) -> SeatInvocation:
103
+ """Freeze: turn a canonical ``(harness, model, effort)`` into its CLI invocation.
104
+
105
+ Only the built-3 homebrew lanes (claude / codex / gemini) are frozen here —
106
+ they are what the ``default`` board's back-compat proof rides on. Breadth
107
+ lanes (opencode / pi / cursor / amp) raise ``EffortMappingError`` until
108
+ ABDREG/ABDHOME/ABDOMNI populate them; a board with an unmapped lane degrades
109
+ skip-with-warning, never silently drops effort.
110
+ """
111
+ _require_effort(effort)
112
+ lane = (harness or "").lower()
113
+ if lane == "claude":
114
+ # panel_invoker.py:322-325 -> ``--model <model> --effort <level>``
115
+ return SeatInvocation(lane, model, ("--effort", effort), MECH_FLAG)
116
+ if lane == "codex":
117
+ # panel_invoker.py:991-992 -> ``--model <model> -c model_reasoning_effort=<tok>``
118
+ token = _CODEX_EFFORT[effort]
119
+ return SeatInvocation(lane, model, ("-c", f"model_reasoning_effort={token}"), MECH_CONFIG)
120
+ if lane == "gemini":
121
+ # panel_invoker.py:1016 -> effort baked into ``--model "<base> (Word)"``
122
+ return SeatInvocation(lane, render_gemini_model(model, effort), (), MECH_MODEL_NAME)
123
+ raise EffortMappingError(
124
+ f"effort mapping for harness {harness!r} is populated in ABDREG/ABDHOME/ABDOMNI"
125
+ )