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,257 @@
1
+ # Advisor Board — Frozen Contracts (Phase 1 ABDFREEZE)
2
+
3
+ Interface-freeze for the model-first, multi-harness Advisor Board
4
+ (`specs/phase-plans-v5.md`). Everything here is **additive and behavior-neutral**:
5
+ no running path changes, `panel_invoker` is untouched, and the `default` board
6
+ reproduces today's 3-leg panel byte-for-byte. Downstream phases (ABDREG,
7
+ ABDRESOLVE, ABDHOME) code against these interfaces so the fan-out integrates
8
+ without a big-bang.
9
+
10
+ Where a contract must reproduce today's behavior, the anchor line in
11
+ `phase-loop-runtime/src/phase_loop_runtime/panel_invoker.py` is cited and the
12
+ equivalence is proven by a test (not asserted in prose).
13
+
14
+ ## IF-0-ABDFREEZE-1 — Seat + Board schema (model-first) · `schema.py`, `harness_mapping.py`
15
+
16
+ - **`Seat{model, effort, harness?, lens?, auth?, backing?, host_leg?}`** — a seat
17
+ is a cognition; the harness is a defaulted-but-overridable execution *lane*, not
18
+ the primary key. `effort` is a canonical level in `EFFORT_LEVELS =
19
+ (low, medium, high, max)`. Frozen dataclass with fail-closed validation.
20
+ - **`Board{name, purpose, seats:[Seat], allow_api_key_fallback=false}`** —
21
+ named, purpose-tagged, open-ended seat list; rejects api-key seats unless the
22
+ board opts in.
23
+ - **Config format + location** — `$XDG_CONFIG_HOME/agent-harness/advisor-boards.toml`
24
+ (`board_config_path()`); shape frozen by `fixtures/advisor-boards.example.toml`.
25
+ The loader is ABDREG.
26
+ - **Per-harness model/effort mapping** — `render_seat_invocation(harness, model,
27
+ effort) -> SeatInvocation`. Freezes how `seat.effort` reaches each CLI, incl.
28
+ the **agy/gemini leg where effort is embedded in the model-name string**
29
+ (`render_gemini_model`, panel_invoker.py:1016). Built-3 lanes are concrete;
30
+ breadth lanes raise `EffortMappingError` until ABDREG/ABDHOME/ABDOMNI.
31
+ Round-trip (proven): claude→`--effort max` (:324), codex→
32
+ `-c model_reasoning_effort=xhigh` (:992), gemini→`"Gemini 3.1 Pro (High)"` (:1016).
33
+ - **Seat identity for result re-keying** — `Seat.seat_key` is a stable LABEL over
34
+ every distinguishing field (lane, model, effort, lens), so lens-only-different
35
+ seats get distinct keys. It is not a guaranteed-unique id — a board may hold two
36
+ byte-identical seats — so ABDRESOLVE keys results by **seat position** and uses
37
+ `seat_key` only as the label.
38
+ - **Host-leg identity** — `Seat.host_leg` marker + `identify_host_leg(board,
39
+ HostContext)`. A seat is the native in-process host leg only when the board runs
40
+ *inside* that harness (`HostContext.host_harness`). The standalone runner
41
+ (`host_harness=None`) has no host leg — every leg is a subprocess, exactly as
42
+ today.
43
+ - **Seat → vendor-family projection** — `vendor_family(model, harness)` /
44
+ `seat_vendor_family(seat)`, model-first with a harness-lane fallback.
45
+ Byte-consistent with `governed_review.author_vendor_for_model` (:60-75) and
46
+ `_EXECUTOR_VENDOR` (:47-53). Two same-vendor seats on different harnesses
47
+ (`gpt-5.5` on `codex` and on `opencode`) project to the same family, so the
48
+ governed reviewer≠author disjointness survives model-first. ABDHOME rewires the
49
+ governed gates onto *this* canonical function (not a copy).
50
+
51
+ ## IF-0-ABDFREEZE-2 — Registry interfaces + shared fixtures · `registries.py`, `fixtures.py`
52
+
53
+ - **Interfaces (Protocols):** `HarnessRegistry`, `ModelRegistry`,
54
+ `CompatibilityMatrix` with `is_valid(model, harness) -> (bool,
55
+ AuthAvailability)` and `default_lane(model) -> str`.
56
+ - **Frozen return types:** `HarnessSpec`, `ModelSpec`, `AuthAvailability`
57
+ (concrete, so no-silent-key is testable), `MatrixVerdict` alias.
58
+ - **Stubs:** `Stub{Harness,Model}Registry`, `StubCompatibilityMatrix` — raise
59
+ `NotImplementedError`; no six-harness data (that is ABDREG).
60
+ - **Shared canonical fixtures** (the anti-divergence keystone ABDREG populates
61
+ *from* and ABDRESOLVE/ABDHOME test *against*): `DEFAULT_BOARD`, `DEFAULT_SEATS`,
62
+ `CANONICAL_LEG_ORDER`, `CANONICAL_VALID_PAIRS`, `CANONICAL_INVALID_PAIRS`,
63
+ `TWO_SAME_VENDOR_BOARD`.
64
+
65
+ ## IF-0-ABDFREEZE-3 — Provider-backing selector + auth enforcement · `backing.py`
66
+
67
+ - **Backing selector** — `select_backing(seat, gateway_available) ->
68
+ BackingDecision`. Per-seat `homebrew | omnigent`; an `omnigent` seat with no
69
+ gateway degrades **skip-with-warning** (fail-closed — never a silent homebrew
70
+ breadth fallback).
71
+ - **Auth = active env scrubbing** — `resolve_seat_env(seat, base_env,
72
+ allow_api_key_fallback)`, freezing the `_subscription_env` pattern
73
+ (panel_invoker.py:226-230,348-353): a subscription seat scrubs **every** vendor
74
+ API-key var; an api-key seat (only behind the board opt-in) scrubs everything
75
+ then injects **only the seat vendor's** key(s). Never silent — an api-key seat
76
+ without the opt-in raises.
77
+ - **`VENDOR_API_KEY_VARS`** — the flat `_API_KEY_VARS` tuple re-keyed by vendor
78
+ family; its union equals today's tuple (proven), so scrubbing stays
79
+ byte-equivalent.
80
+
81
+ ## IF-0-ABDFREEZE-4 — Back-compat contract · `fixtures.py` + `tests/test_advisor_board_backcompat.py`
82
+
83
+ - The `default` board (`DEFAULT_BOARD`) resolves to today's three seats in
84
+ `PANEL_LEGS` order, and each seat renders to today's exact model string + effort
85
+ args (cross-checked against `panel_invoker.DEFAULT_LEG_MODELS` and the
86
+ codex/claude/agy arg forms). Full assertions (launch order, payloads, env/auth,
87
+ timeout/retry, result keys, output formatting, failure semantics, `invoke_panel`
88
+ API) land in ABDVERIFY; this ships the **scaffold + the default-board fixture**.
89
+ - `advisor-panel` stays a working alias of `advisor-board` — the rename + alias is
90
+ ABDRESOLVE; this contract only *states* the invariant.
91
+ - **Behavior-neutrality proof:** `git diff` on `panel_invoker.py` is empty and the
92
+ full existing suite is green (this package is purely additive).
93
+
94
+ ## IF-0-ABDFREEZE-5 — Observability contract · `events.py`
95
+
96
+ - **Internal envelope** — `AdvisorBoardEvent` (our shape, `EVENT_SCHEMA_VERSION =
97
+ advisor_board.event.v1`, kinds in `EVENT_KINDS`). NOT a guessed Omnigent schema.
98
+ - **launcher ≠ observability-plane** — a natively-launched leg *emits* into a
99
+ forwarded stream; it is never relaunched through the gateway for observability.
100
+ - **Forwarding is async/best-effort and can never delay or fail the native leg** —
101
+ `best_effort_forward(sink, event)` swallows every sink error and never raises;
102
+ `NullSink` keeps the default board a no-op. The mapping to a concrete sink
103
+ (Omnigent v0.4.0 endpoint, or omniagent-plus ui-read-model/state-ledger) is
104
+ deferred to ABDOBS — do not freeze against a guessed upstream schema.
105
+
106
+ ## ABDOBS — Observability forwarding (Phase 6) · `observability.py`, `panel_invoker.invoke_board`
107
+
108
+ Builds the mapping ABDFREEZE-5 deferred. **Confirmed sink:** omniagent-plus's own
109
+ `state-ledger` / `ui-read-model` (we control it) — NOT an Omnigent HTTP ingestion
110
+ endpoint. v0.4.0's HTTP surface is launcher-centric and exposes **no** ingestion
111
+ endpoint for an externally-launched (native) session, so a native leg is
112
+ *observed*, never relaunched.
113
+
114
+ - **Envelope → sink mapping** — `map_event_to_runtime_event(event, session_id)`
115
+ and `map_event_to_ledger_record(event, session_id)` project our
116
+ `AdvisorBoardEvent` onto omniagent-plus's *own frozen* wire shapes:
117
+ `runtime_event.v0.1` (`core-contracts/src/events.ts`) inside a
118
+ `state_ledger_record.v0.1`, kind `runtime_event` (`core-contracts/src/state-ledger.ts`)
119
+ — exactly what `AuditLedger.appendRuntimeEvent` (`state-ledger/src/audit-ledger.ts`)
120
+ writes. **A board run projects to a session; each seat projects to a turn.** A
121
+ per-run `sessionId` is minted (`new_session_id()` — never the board name);
122
+ `turnId` derives from the seat's frozen `seat_key` label. `redaction` is
123
+ `metadata_only` (never a raw key; `content_allowed` only for a text delta). A
124
+ `seat.failed` payload conforms to the full `runtime_failure.v0.1` (`errors.ts`)
125
+ — all of schema/category/retryable/actor/scope/message are required upstream.
126
+ NB: the record-level `recordId` / `sequence` are meaningful only for the
127
+ reference `JsonlLedgerWriter`; the real TS `AppendOnlyStore` ASSIGNS them on
128
+ append (its `AppendRecordInput` has no `sequence`), so a real binding overrides
129
+ them. The authoritative, per-session sequence is the `runtime_event` payload's.
130
+ - **Cross-language transport seam** — the ledger is TypeScript, the emit is
131
+ Python, so the boundary is `LedgerWriter` (a Protocol a real omniagent-plus
132
+ binding implements over IPC/HTTP/a shared file) + `JsonlLedgerWriter`, a
133
+ reference transport appending the exact `state_ledger_record.v0.1` records the TS
134
+ `AppendOnlyStore` ingests. We do **not** reimplement ledger internals
135
+ (retention / replay / compaction stay TS-side). This is the integration seam.
136
+ - **Async / best-effort (never delays or fails the native leg)** —
137
+ `AsyncForwardingSink.emit` does a NON-BLOCKING put and returns; a background
138
+ daemon thread does the real (slow / failing) write via `best_effort_forward`.
139
+ The never-**raise** guarantee is frozen in `events.py`; the never-**delay**
140
+ guarantee is here (unbounded queue; a bounded queue drops on full). `BoardObserver`
141
+ wraps construct+map+enqueue in a swallow-all, so even a bad kind / full queue
142
+ never touches the leg. `flush()` / `close()` drain deterministically (tests /
143
+ graceful shutdown only — never on the leg's critical path).
144
+ - **launcher ≠ observability-plane, in code** — every sink here is structurally
145
+ emit-only (no `create_session` / `send_turn`), so the observability path
146
+ *cannot* launch a leg. Combined with the frozen `enforce_native_host_leg`
147
+ (which hard-raises on a gatewayed host leg), the native host leg is observed,
148
+ never relaunched.
149
+ - **Per-workload boundary (documented + enforced)** — `WORKLOAD_BOARD` =
150
+ native launch **+ optional forward** (this path); `WORKLOAD_PHASE_EXECUTION` =
151
+ Omnigent-as-launcher (CS-2.2, out of scope here). `invoke_board(sink=...)` is
152
+ the ONLY opt-in; `sink=None` builds no envelope (default board byte-neutral).
153
+ `invoke_panel` is untouched, so the live default panel is byte-neutral by
154
+ construction.
155
+ - **Key-file note (reviewers):** the phase plan lists
156
+ `agent_runtime_provider.py`; the emit lands in `panel_invoker.invoke_board`
157
+ instead, because the envelope's vocabulary is `board.*` / `seat.*` (with
158
+ `seat_key` / `vendor_family` / `harness`) which only the board seam knows — the
159
+ provider only knows sessions/turns and cannot populate it. `observability.py`
160
+ maps our envelope onto the provider-mirrored `runtime_event.v0.1` shape, so the
161
+ provider layer is still the wire target, just not the emit site.
162
+
163
+ ## ABDPRESET — Board preset library + Fable review-path · `presets.py`, `panel_invoker.py`
164
+
165
+ The seven built-in presets (`presets.PRESETS`). Every preset self-validates against
166
+ the real matrix at `load_boards()` time (`tests/test_advisor_board_config.py`,
167
+ `tests/test_advisor_board_integration.py`).
168
+
169
+ - **Review-class = Fable, decoupled from the implementer.** Pre-merge and legal
170
+ review are mid-tier decisions where being wrong is expensive, so the review-class
171
+ boards (`default`, `code-review`, `legal-review`, `legal-strategy-review`) seat
172
+ Fable (`claude-fable-5`) on the claude lane — NOT the implementer model
173
+ `profiles.CLAUDE_IMPLEMENTER_MODEL` (`claude-sonnet-5`). `panel_invoker.DEFAULT_LEG_MODELS["claude"]`
174
+ is the SINGLE source of truth for the panel's default claude model: the claude
175
+ leg builder (`_claude_tui_command`) and the Agent-View attempt both read it, so
176
+ the *legacy* `invoke_panel` path AND the live governed gates
177
+ (`governed_review` / `governed_premerge`, which call `invoke_panel` with no model
178
+ override) review on Fable. `CLAUDE_IMPLEMENTER_MODEL` is untouched — the
179
+ implementer stays Sonnet. The `default` board (`fixtures.DEFAULT_BOARD`) is
180
+ byte-pinned to this Fable `invoke_panel` panel by the golden proof
181
+ (`tests/test_advisor_board_golden.py`); the sole sanctioned delta stays `seat_key`.
182
+ - **`code-review` = three frontier vendors, always.** codex `gpt-5.5`,
183
+ `Gemini 3.1 Pro`, and `claude-fable-5`, each on the `adversarial` lens (supersedes
184
+ the prior two-seat codex+sonnet composition).
185
+ - **Divergent-thinking boards keep Sonnet.** `brainstorm` / `doc-edit` /
186
+ `legal-brainstorm` deliberately retain `claude-sonnet-5` — a diverse voice, a
187
+ low-stakes copyedit, a cheap aggressive ideation seat — where it is the right tool.
188
+ - **Legal boards (`legal-review`, `legal-strategy-review`, `legal-brainstorm`)**
189
+ encode the PRIMARY review lens per seat. `lens` / `purpose` are free-form strings
190
+ (`schema.py`), so the legal lenses/purposes need no enum extension.
191
+ - **Catch-alls for unmodeled tasks (`general`, `solo`).** So the board library is not
192
+ limited to the pre-modeled domains: `general` is the domain-agnostic top-tier PANEL
193
+ (three frontier vendors — gpt-5.5/adversarial, Gemini 3.1 Pro/alternative,
194
+ claude-fable-5/completeness — hand it any task + brief), and `solo` is the
195
+ single-MEMBER form (one `claude-fable-5` seat) for a quick top-end opinion when a
196
+ panel is overkill. A ONE-seat board validates + resolves through `invoke_board` like
197
+ any other (bare/single seats are supported). Both default to TOP-END models: an
198
+ unanticipated task cannot be assumed low-stakes, so the safe default is frontier —
199
+ dial down explicitly (a cheaper board) when a task is known-cheap. Their lenses
200
+ (`adversarial`/`alternative`/`completeness`) and purpose (`general`) are free-form
201
+ strings, so no enum extension.
202
+ - **Deep-seat FOLLOW-ON (documented, NOT built here).** The richer legal treatment —
203
+ four lenses per seat, an apex-Opus (`claude-opus-4-8`) seat, a verify-round, and
204
+ retrieval-grounded citation-verification — is a deliberate follow-on. The current
205
+ legal boards ship the single-primary-lens-per-seat form; the deep-seat form layers
206
+ onto the same seat/board schema (no schema change) when built.
207
+
208
+ ## ABDPAR — Concurrent leg execution · `panel_invoker.invoke_board` / `invoke_panel`
209
+
210
+ `invoke_board` and `invoke_panel` fan their seats/legs out across a bounded
211
+ `ThreadPoolExecutor` (`_run_legs_ordered`), not a sequential loop — legs are blocking
212
+ subprocess I/O (the CLI wait releases the GIL), so wall-clock is `~max(leg)`, not
213
+ `sum(leg)`.
214
+
215
+ - **Parallel is the DEFAULT (opt-out, not opt-in).** Both entry points take a single
216
+ `max_concurrency: int | None = None` knob, threaded through the governed gates
217
+ (`governed_planning_gate` → `run_governed_premerge_loop` → `governed_premerge_for_run`)
218
+ so a caller CAN request sequential, while the default everywhere stays parallel:
219
+ - `None` (default) → parallel, bounded by `min(len(seats), 8)`.
220
+ - `1` → sequential (the opt-in escape hatch — debugging, a rate-limited / throttled
221
+ provider, a constrained host).
222
+ - `N` → cap concurrency at `N`.
223
+ It is the SAME thread-pool path: `max_workers = max(1, min(max_concurrency or len(seats), 8))`,
224
+ so `max_concurrency=1` degrades to one worker (strictly serial) with no separate
225
+ sequential branch. `max_concurrency` is a keyword-only, default-valued additive
226
+ extension to the frozen `invoke_panel` signature (back-compat, like `models` #66).
227
+
228
+ Frozen invariants (concurrency is a **timing-only** change — never a leg's outcome;
229
+ the golden proves byte-identity):
230
+
231
+ - **Positional order** — futures are submitted in seat/leg order and read back by
232
+ index, so `result[i]` corresponds to `seats[i]`/`legs[i]` regardless of finish
233
+ order. `resolver.key_results_by_seat` re-keys by position and the golden asserts
234
+ order + content, so this is load-bearing.
235
+ - **Fail-closed per seat** — the extracted per-seat/per-leg body returns a DEGRADED
236
+ `PanelLegResult` on any exception, so a future's `.result()` never raises and one
237
+ broken leg can never crash the pool or the board.
238
+ - **Single shared reads before the pool** — the one `GET /v1/harnesses` gateway-catalog
239
+ fetch and the seat-validation/host-leg checks stay ABOVE the pool (one fetch, shared
240
+ read); the observability emit stays AFTER, in seat order. Bounded `max_workers =
241
+ min(len(seats), 8)`.
242
+ - **Proof** — a `threading.Barrier(N)` test proves both directions without real sleeps:
243
+ the DEFAULT satisfies the barrier (all N legs in-flight at once → all OK), and
244
+ `max_concurrency=1` makes the same barrier unsatisfiable (one worker → it times out →
245
+ fail-closed DEGRADED), so the pair discriminates parallel from sequential. A third
246
+ test confirms sequential mode returns byte-identical ordered results.
247
+ - **Thread-safety of the real leg paths** — the leg execs install NO signal handlers or
248
+ timers (`signal.signal` / `alarm` / `setitimer` would raise `ValueError: signal only
249
+ works in main thread` off the main thread); the only `signal.` use is `os.killpg(pid,
250
+ SIGTERM/SIGKILL)` (a constant, thread-safe), and timeouts run on `select.select(...)`
251
+ / `subprocess.run(timeout=...)`, not `SIGALRM`. Each leg stages its own temp review
252
+ dir, so concurrent legs never share filesystem state. Verified: the real `spawn=None`
253
+ path runs inside worker threads with no signal-in-thread error.
254
+ - **Known edge (untested):** a custom board with two seats on the SAME lane (e.g. two
255
+ `claude` seats) now runs two concurrent same-lane CLI/PTY sessions — a scenario this
256
+ fan-out newly enables and nothing yet tests. The `default` board has one claude seat,
257
+ so it is unaffected.
@@ -0,0 +1,288 @@
1
+ """Advisor Board — frozen contracts (Phase 1 ABDFREEZE).
2
+
3
+ Interface-only preamble for the model-first, multi-harness Advisor Board
4
+ (specs/phase-plans-v5.md). This package ships the typed contracts + importable
5
+ stubs + shared canonical fixtures the parallel fan-out (ABDREG / ABDRESOLVE /
6
+ ABDHOME) codes against. It is ADDITIVE and behavior-neutral: nothing here touches
7
+ the running ``panel_invoker`` path.
8
+
9
+ Frozen gates (see ``CONTRACTS.md``):
10
+ * IF-0-ABDFREEZE-1 — seat/board schema, config location, per-harness model/effort
11
+ mapping, host-leg identity, seat -> vendor-family projection (``schema`` +
12
+ ``harness_mapping``).
13
+ * IF-0-ABDFREEZE-2 — registry interfaces + (model x harness) matrix API + shared
14
+ canonical fixtures (``registries`` + ``fixtures``).
15
+ * IF-0-ABDFREEZE-3 — provider-backing selector + auth-enforcement (active env
16
+ scrubbing) contract (``backing``).
17
+ * IF-0-ABDFREEZE-4 — back-compat: the ``default`` board reproduces today's 3-leg
18
+ behavior (``fixtures.DEFAULT_BOARD`` + the golden-test scaffold).
19
+ * IF-0-ABDFREEZE-5 — internal advisor-board event envelope + best-effort
20
+ forwarding (``events``); its concrete sink mapping lands in ABDOBS.
21
+
22
+ ABDOBS (Phase 6) then adds ``observability``: the envelope → omniagent-plus
23
+ state-ledger (``state_ledger_record.v0.1`` / ``runtime_event.v0.1``) mapping, an
24
+ :class:`~observability.AsyncForwardingSink` for off-thread best-effort dispatch,
25
+ and the ``LedgerWriter`` cross-language transport seam. This is the one place the
26
+ package touches ``panel_invoker`` — an OPT-IN ``sink=`` on ``invoke_board``;
27
+ ``sink=None`` stays byte-neutral.
28
+ """
29
+ from __future__ import annotations
30
+
31
+ from .schema import (
32
+ AUTH_API_KEY,
33
+ AUTH_LANES,
34
+ AUTH_SUBSCRIPTION,
35
+ BACKING_HOMEBREW,
36
+ BACKING_OMNIGENT,
37
+ CONFIG_RELATIVE_PATH,
38
+ EFFORT_LEVELS,
39
+ PROVIDER_BACKINGS,
40
+ Board,
41
+ HostContext,
42
+ Seat,
43
+ board_config_path,
44
+ identify_host_leg,
45
+ seat_vendor_family,
46
+ vendor_family,
47
+ vendor_of_harness,
48
+ vendor_of_model,
49
+ )
50
+ from .harness_mapping import (
51
+ EffortMappingError,
52
+ MECH_CONFIG,
53
+ MECH_FLAG,
54
+ MECH_MODEL_NAME,
55
+ SeatInvocation,
56
+ gemini_base_model,
57
+ render_gemini_model,
58
+ render_seat_invocation,
59
+ )
60
+ from .registries import (
61
+ DEFAULT_HARNESS_REGISTRY,
62
+ DEFAULT_MODEL_REGISTRY,
63
+ AuthAvailability,
64
+ CompatibilityMatrix,
65
+ DefaultHarnessRegistry,
66
+ DefaultModelRegistry,
67
+ HarnessRegistry,
68
+ HarnessSpec,
69
+ MatrixVerdict,
70
+ ModelRegistry,
71
+ ModelSpec,
72
+ StubCompatibilityMatrix,
73
+ StubHarnessRegistry,
74
+ StubModelRegistry,
75
+ UnknownHarnessError,
76
+ UnknownModelError,
77
+ )
78
+ from .matrix import (
79
+ DefaultCompatibilityMatrix,
80
+ default_matrix,
81
+ )
82
+ from .presets import (
83
+ DEFAULT_BOARD_NAME,
84
+ PRESET_NAMES,
85
+ PRESETS,
86
+ get_preset,
87
+ )
88
+ from .config import (
89
+ BoardConfig,
90
+ BoardConfigError,
91
+ load_boards,
92
+ )
93
+ from .backing import (
94
+ VENDOR_API_KEY_VARS,
95
+ BackingDecision,
96
+ all_vendor_key_vars,
97
+ resolve_seat_env,
98
+ select_backing,
99
+ )
100
+ from .backing_omnigent import (
101
+ OMNIGENT_FREEZE_TARGET,
102
+ HARNESS_ENDPOINT,
103
+ SESSION_ENDPOINTS,
104
+ VENDOR_KEY_HEADER_PREFIX,
105
+ OmnigentBacking,
106
+ OmnigentGatewayUnavailable,
107
+ OmnigentHttpClient,
108
+ OmnigentHttpError,
109
+ SeatRunOutcome,
110
+ classify_http_failure,
111
+ )
112
+ from .events import (
113
+ EVENT_KINDS,
114
+ EVENT_SCHEMA_VERSION,
115
+ AdvisorBoardEvent,
116
+ EventSink,
117
+ NullSink,
118
+ best_effort_forward,
119
+ )
120
+ from .observability import (
121
+ LEDGER_RECORD_KIND,
122
+ LEDGER_RECORD_SCHEMA,
123
+ RUNTIME_EVENT_SCHEMA,
124
+ RUNTIME_FAILURE_SCHEMA,
125
+ WORKLOAD_BOARD,
126
+ WORKLOAD_PHASE_EXECUTION,
127
+ AsyncForwardingSink,
128
+ BoardObserver,
129
+ CollectingSink,
130
+ JsonlLedgerWriter,
131
+ LedgerWriter,
132
+ StateLedgerSink,
133
+ map_event_to_ledger_record,
134
+ map_event_to_runtime_event,
135
+ new_session_id,
136
+ )
137
+ from .fixtures import (
138
+ CANONICAL_INVALID_PAIRS,
139
+ CANONICAL_LEG_ORDER,
140
+ CANONICAL_VALID_PAIRS,
141
+ DEFAULT_BOARD,
142
+ DEFAULT_SEAT_EFFORT_ARGS,
143
+ DEFAULT_SEAT_RENDERED_MODEL,
144
+ DEFAULT_SEATS,
145
+ TWO_SAME_VENDOR_BOARD,
146
+ )
147
+ from .resolver import (
148
+ BOARD_ALIASES,
149
+ STANDIN_BOARDS,
150
+ BoardResolutionError,
151
+ BoardResolver,
152
+ SeatSpecError,
153
+ key_results_by_seat,
154
+ parse_seat_spec,
155
+ parse_seats,
156
+ resolve_board,
157
+ seat_result_key,
158
+ )
159
+ from .validation import (
160
+ SeatValidationError,
161
+ SeatVerdict,
162
+ validate_board,
163
+ validate_seat,
164
+ )
165
+
166
+ __all__ = [
167
+ # schema
168
+ "Seat",
169
+ "Board",
170
+ "HostContext",
171
+ "EFFORT_LEVELS",
172
+ "AUTH_LANES",
173
+ "AUTH_SUBSCRIPTION",
174
+ "AUTH_API_KEY",
175
+ "PROVIDER_BACKINGS",
176
+ "BACKING_HOMEBREW",
177
+ "BACKING_OMNIGENT",
178
+ "CONFIG_RELATIVE_PATH",
179
+ "board_config_path",
180
+ "identify_host_leg",
181
+ "seat_vendor_family",
182
+ "vendor_family",
183
+ "vendor_of_harness",
184
+ "vendor_of_model",
185
+ # harness mapping
186
+ "SeatInvocation",
187
+ "render_seat_invocation",
188
+ "render_gemini_model",
189
+ "gemini_base_model",
190
+ "EffortMappingError",
191
+ "MECH_FLAG",
192
+ "MECH_CONFIG",
193
+ "MECH_MODEL_NAME",
194
+ # registries
195
+ "HarnessSpec",
196
+ "ModelSpec",
197
+ "AuthAvailability",
198
+ "MatrixVerdict",
199
+ "HarnessRegistry",
200
+ "ModelRegistry",
201
+ "CompatibilityMatrix",
202
+ "StubHarnessRegistry",
203
+ "StubModelRegistry",
204
+ "StubCompatibilityMatrix",
205
+ # registries — populated (ABDREG)
206
+ "DefaultHarnessRegistry",
207
+ "DefaultModelRegistry",
208
+ "DEFAULT_HARNESS_REGISTRY",
209
+ "DEFAULT_MODEL_REGISTRY",
210
+ "UnknownHarnessError",
211
+ "UnknownModelError",
212
+ # matrix (ABDREG) — seat/board validation is exported from validation below
213
+ "DefaultCompatibilityMatrix",
214
+ "default_matrix",
215
+ # presets + config loader (ABDREG)
216
+ "PRESETS",
217
+ "PRESET_NAMES",
218
+ "DEFAULT_BOARD_NAME",
219
+ "get_preset",
220
+ "BoardConfig",
221
+ "BoardConfigError",
222
+ "load_boards",
223
+ # backing + auth
224
+ "VENDOR_API_KEY_VARS",
225
+ "all_vendor_key_vars",
226
+ "BackingDecision",
227
+ "select_backing",
228
+ "resolve_seat_env",
229
+ # backing — omnigent transport (ABDOMNI)
230
+ "OMNIGENT_FREEZE_TARGET",
231
+ "HARNESS_ENDPOINT",
232
+ "SESSION_ENDPOINTS",
233
+ "VENDOR_KEY_HEADER_PREFIX",
234
+ "OmnigentBacking",
235
+ "OmnigentHttpClient",
236
+ "OmnigentHttpError",
237
+ "OmnigentGatewayUnavailable",
238
+ "SeatRunOutcome",
239
+ "classify_http_failure",
240
+ # events
241
+ "AdvisorBoardEvent",
242
+ "EventSink",
243
+ "NullSink",
244
+ "best_effort_forward",
245
+ "EVENT_KINDS",
246
+ "EVENT_SCHEMA_VERSION",
247
+ # observability (ABDOBS)
248
+ "WORKLOAD_BOARD",
249
+ "WORKLOAD_PHASE_EXECUTION",
250
+ "LEDGER_RECORD_SCHEMA",
251
+ "RUNTIME_EVENT_SCHEMA",
252
+ "RUNTIME_FAILURE_SCHEMA",
253
+ "LEDGER_RECORD_KIND",
254
+ "new_session_id",
255
+ "map_event_to_runtime_event",
256
+ "map_event_to_ledger_record",
257
+ "LedgerWriter",
258
+ "JsonlLedgerWriter",
259
+ "StateLedgerSink",
260
+ "CollectingSink",
261
+ "AsyncForwardingSink",
262
+ "BoardObserver",
263
+ # fixtures
264
+ "DEFAULT_BOARD",
265
+ "DEFAULT_SEATS",
266
+ "DEFAULT_SEAT_RENDERED_MODEL",
267
+ "DEFAULT_SEAT_EFFORT_ARGS",
268
+ "CANONICAL_LEG_ORDER",
269
+ "CANONICAL_VALID_PAIRS",
270
+ "CANONICAL_INVALID_PAIRS",
271
+ "TWO_SAME_VENDOR_BOARD",
272
+ # resolver (ABDRESOLVE)
273
+ "BoardResolver",
274
+ "resolve_board",
275
+ "parse_seat_spec",
276
+ "parse_seats",
277
+ "SeatSpecError",
278
+ "BoardResolutionError",
279
+ "BOARD_ALIASES",
280
+ "STANDIN_BOARDS",
281
+ "seat_result_key",
282
+ "key_results_by_seat",
283
+ # validation (ABDRESOLVE)
284
+ "validate_seat",
285
+ "validate_board",
286
+ "SeatValidationError",
287
+ "SeatVerdict",
288
+ ]
@@ -0,0 +1,137 @@
1
+ """Provider-backing selector + auth-enforcement contract (IF-0-ABDFREEZE-3).
2
+
3
+ Two orthogonal per-seat axes, frozen here:
4
+
5
+ * **backing** (``homebrew | omnigent``) — the transport. Selected per seat;
6
+ ``homebrew`` is the default and keeps the built-3 + native host leg.
7
+ * **auth** (``subscription | api_key``) — the credential lane. Subscription is
8
+ the default; api-key is reachable only behind ``Board.allow_api_key_fallback``.
9
+
10
+ **No-silent-key is enforced by ACTIVE environment scrubbing**, freezing the
11
+ existing ``_subscription_env`` pattern (panel_invoker.py:226-230,348-353) into a
12
+ per-seat, vendor-keyed contract:
13
+
14
+ * a **subscription** seat scrubs EVERY vendor API-key var from the subprocess env
15
+ / gateway payload (identical to ``_subscription_env`` today); and
16
+ * an **api-key fallback** seat scrubs everything, then injects ONLY the seat
17
+ vendor's key var(s) — never another vendor's, never silently.
18
+
19
+ ``VENDOR_API_KEY_VARS`` is the flat ``panel_invoker._API_KEY_VARS`` tuple
20
+ re-expressed keyed by vendor family, so "inject only the seat vendor's key" is
21
+ expressible. The union of its values equals the current flat tuple (asserted in
22
+ ``tests/test_advisor_board_backcompat.py``), so scrubbing stays byte-equivalent.
23
+ The reference env functions below are pure and importable; ABDHOME wires them
24
+ into the real launch/gateway env (this module changes no running path).
25
+ """
26
+ from __future__ import annotations
27
+
28
+ from collections.abc import Mapping
29
+ from dataclasses import dataclass
30
+
31
+ from .schema import (
32
+ AUTH_API_KEY,
33
+ AUTH_SUBSCRIPTION,
34
+ BACKING_HOMEBREW,
35
+ BACKING_OMNIGENT,
36
+ PROVIDER_BACKINGS,
37
+ Seat,
38
+ seat_vendor_family,
39
+ )
40
+
41
+
42
+ # Vendor family -> the provider API-key env var(s) that vendor authenticates with.
43
+ # The UNION of all values MUST equal ``panel_invoker._API_KEY_VARS`` so subscription
44
+ # scrubbing is byte-equivalent to ``_subscription_env`` today.
45
+ VENDOR_API_KEY_VARS: dict[str, tuple[str, ...]] = {
46
+ "codex": ("OPENAI_API_KEY",),
47
+ "claude": ("ANTHROPIC_API_KEY",),
48
+ "gemini": ("GEMINI_API_KEY", "GOOGLE_API_KEY", "GOOGLE_GENERATIVE_AI_API_KEY"),
49
+ }
50
+
51
+
52
+ def all_vendor_key_vars() -> tuple[str, ...]:
53
+ """Every vendor API-key var (scrub set for a subscription seat)."""
54
+ seen: list[str] = []
55
+ for vars_ in VENDOR_API_KEY_VARS.values():
56
+ for var in vars_:
57
+ if var not in seen:
58
+ seen.append(var)
59
+ return tuple(seen)
60
+
61
+
62
+ # --- backing selector -------------------------------------------------------
63
+
64
+
65
+ @dataclass(frozen=True)
66
+ class BackingDecision:
67
+ """Which transport a seat resolves to, and why. Fail-closed: an ``omnigent``
68
+ seat whose gateway is unavailable degrades to ``skip`` (never a silent
69
+ homebrew fallback for a breadth harness — hand-writing breadth defeats the
70
+ Omnigent maintenance-offload, per ABDHOME non-goals)."""
71
+
72
+ backing: str
73
+ skip: bool = False
74
+ reason: str = ""
75
+
76
+
77
+ def select_backing(seat: Seat, *, gateway_available: bool = True) -> BackingDecision:
78
+ """Freeze the selector contract: honor ``seat.backing``; an ``omnigent`` seat
79
+ with no gateway degrades skip-with-warning. ABDHOME/ABDOMNI supply the real
80
+ availability probes; this fixes the DECISION SHAPE they return."""
81
+ if seat.backing not in PROVIDER_BACKINGS:
82
+ raise ValueError(f"seat.backing {seat.backing!r} not in {PROVIDER_BACKINGS}")
83
+ if seat.backing == BACKING_OMNIGENT and not gateway_available:
84
+ return BackingDecision(BACKING_OMNIGENT, skip=True, reason="omnigent gateway unavailable")
85
+ return BackingDecision(seat.backing)
86
+
87
+
88
+ # --- auth enforcement (active env scrubbing) --------------------------------
89
+
90
+
91
+ def resolve_seat_env(
92
+ seat: Seat,
93
+ base_env: Mapping[str, str],
94
+ *,
95
+ allow_api_key_fallback: bool = False,
96
+ ) -> dict[str, str]:
97
+ """Reference implementation of the frozen no-silent-key env contract.
98
+
99
+ * Always scrub EVERY vendor API-key var from a copy of ``base_env`` (the
100
+ ``_subscription_env`` behavior — a subscription seat ends here).
101
+ * For an ``api_key`` seat, and ONLY when the board opts in
102
+ (``allow_api_key_fallback``), re-inject ONLY the seat vendor's key var(s)
103
+ from ``base_env``. Any other lane / a disallowed board leaves the env
104
+ scrubbed (fail-closed).
105
+
106
+ Raises when a seat requests the api-key lane without the board opt-in, so a
107
+ silent key can never slip through. Pure and side-effect-free; ABDHOME wires
108
+ it into the subprocess/gateway env.
109
+ """
110
+ env = {k: v for k, v in base_env.items() if k not in all_vendor_key_vars()}
111
+ if seat.auth == AUTH_SUBSCRIPTION:
112
+ return env
113
+ if seat.auth == AUTH_API_KEY:
114
+ if not allow_api_key_fallback:
115
+ raise ValueError(
116
+ f"seat {seat.seat_key} requests the api_key lane but the board did not "
117
+ "opt in (allow_api_key_fallback=False) — never-silent-key"
118
+ )
119
+ vendor = seat_vendor_family(seat)
120
+ for var in VENDOR_API_KEY_VARS.get(vendor, ()): # ONLY this vendor's key(s)
121
+ if var in base_env:
122
+ env[var] = base_env[var]
123
+ return env
124
+ raise ValueError(f"unknown seat.auth {seat.auth!r}")
125
+
126
+
127
+ __all__ = [
128
+ "VENDOR_API_KEY_VARS",
129
+ "all_vendor_key_vars",
130
+ "BackingDecision",
131
+ "select_backing",
132
+ "resolve_seat_env",
133
+ "AUTH_SUBSCRIPTION",
134
+ "AUTH_API_KEY",
135
+ "BACKING_HOMEBREW",
136
+ "BACKING_OMNIGENT",
137
+ ]