claude-dev-env 1.94.0 → 2.0.0

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 (280) hide show
  1. package/_shared/advisor/CLAUDE.md +2 -2
  2. package/_shared/advisor/advisor-protocol.md +41 -33
  3. package/_shared/advisor/scripts/config/advisor_scripts_constants/model_tier_run_validator_constants.py +17 -13
  4. package/_shared/advisor/scripts/model_tier_run_validator.py +27 -18
  5. package/_shared/advisor/scripts/tests/test_model_tier_run_validator.py +95 -25
  6. package/_shared/advisor/scripts/tests/test_tier_model_ids.py +17 -17
  7. package/_shared/advisor/scripts/tier_model_ids.py +18 -18
  8. package/_shared/pr-loop/CLAUDE.md +1 -0
  9. package/_shared/pr-loop/scripts/CLAUDE.md +2 -1
  10. package/_shared/pr-loop/scripts/README.md +1 -0
  11. package/_shared/pr-loop/scripts/code_rules_gate.py +253 -1980
  12. package/_shared/pr-loop/scripts/code_rules_gate_parts/CLAUDE.md +32 -0
  13. package/_shared/pr-loop/scripts/code_rules_gate_parts/__init__.py +7 -0
  14. package/_shared/pr-loop/scripts/code_rules_gate_parts/added_line_maps.py +268 -0
  15. package/_shared/pr-loop/scripts/code_rules_gate_parts/enforcer_loading.py +172 -0
  16. package/_shared/pr-loop/scripts/code_rules_gate_parts/gate_arguments.py +70 -0
  17. package/_shared/pr-loop/scripts/code_rules_gate_parts/gate_running.py +326 -0
  18. package/_shared/pr-loop/scripts/code_rules_gate_parts/git_blob_readers.py +85 -0
  19. package/_shared/pr-loop/scripts/code_rules_gate_parts/git_file_sets.py +331 -0
  20. package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_running.py +369 -0
  21. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/conftest.py +14 -0
  22. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_added_line_maps.py +118 -0
  23. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_enforcer_loading.py +17 -0
  24. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_gate_arguments.py +29 -0
  25. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_gate_running.py +99 -0
  26. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_git_blob_readers.py +69 -0
  27. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_git_file_sets.py +137 -0
  28. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_staged_test_running.py +116 -0
  29. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_violation_scoping.py +75 -0
  30. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_wrapper_plumb_check.py +49 -0
  31. package/_shared/pr-loop/scripts/code_rules_gate_parts/violation_scoping.py +328 -0
  32. package/_shared/pr-loop/scripts/code_rules_gate_parts/wrapper_plumb_check.py +206 -0
  33. package/_shared/pr-loop/scripts/pr_loop_shared_constants/code_rules_gate_constants.py +24 -17
  34. package/_shared/pr-loop/scripts/pr_loop_shared_constants/reviews_disabled_constants.py +1 -0
  35. package/_shared/pr-loop/scripts/reviews_disabled.py +19 -2
  36. package/_shared/pr-loop/scripts/test_code_rules_gate.py +278 -0
  37. package/_shared/pr-loop/scripts/tests/test_code_rules_gate_constants.py +6 -39
  38. package/_shared/pr-loop/scripts/tests/test_reviews_disabled.py +43 -0
  39. package/_shared/pr-loop/worker-spawn.md +186 -0
  40. package/agents/code-verifier.md +1 -1
  41. package/bin/CLAUDE.md +10 -1
  42. package/bin/ever-shipped-skills.mjs +73 -0
  43. package/bin/expand_home_directory_tokens.mjs +1 -1
  44. package/bin/install.mjs +140 -7
  45. package/bin/install.prune.test.mjs +457 -0
  46. package/docs/CODE_RULES.md +1 -1
  47. package/hooks/advisory/refactor_guard.py +3 -4
  48. package/hooks/blocking/CLAUDE.md +7 -1
  49. package/hooks/blocking/block_main_commit.py +2 -2
  50. package/hooks/blocking/claude_md_orphan_file_blocker.py +75 -699
  51. package/hooks/blocking/claude_md_orphan_file_blocker_parts/CLAUDE.md +28 -0
  52. package/hooks/blocking/claude_md_orphan_file_blocker_parts/__init__.py +1 -0
  53. package/hooks/blocking/claude_md_orphan_file_blocker_parts/config/__init__.py +1 -0
  54. package/hooks/blocking/claude_md_orphan_file_blocker_parts/config/orphan_blocker_constants.py +18 -0
  55. package/hooks/blocking/claude_md_orphan_file_blocker_parts/decision.py +81 -0
  56. package/hooks/blocking/claude_md_orphan_file_blocker_parts/references.py +307 -0
  57. package/hooks/blocking/claude_md_orphan_file_blocker_parts/scan_plan.py +124 -0
  58. package/hooks/blocking/claude_md_orphan_file_blocker_parts/subtree_scan.py +179 -0
  59. package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/conftest.py +10 -0
  60. package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/test_decision.py +34 -0
  61. package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/test_references.py +42 -0
  62. package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/test_scan_plan.py +27 -0
  63. package/hooks/blocking/claude_md_orphan_file_blocker_parts/tests/test_subtree_scan.py +30 -0
  64. package/hooks/blocking/code_rules_boolean_mustcheck.py +1 -1
  65. package/hooks/blocking/code_rules_enforcer.py +4 -0
  66. package/hooks/blocking/code_rules_mock_completeness.py +1 -1
  67. package/hooks/blocking/code_rules_optional_params.py +2 -2
  68. package/hooks/blocking/code_rules_shared.py +83 -1
  69. package/hooks/blocking/code_rules_test_assertions.py +1 -1
  70. package/hooks/blocking/code_rules_test_layout.py +9 -3
  71. package/hooks/blocking/code_rules_typeddict_stub.py +1 -1
  72. package/hooks/blocking/gh_pr_author_enforcer.py +1 -1
  73. package/hooks/blocking/inventory_intent_records/CLAUDE.md +26 -0
  74. package/hooks/blocking/inventory_intent_records/__init__.py +1 -0
  75. package/hooks/blocking/inventory_intent_records/config/__init__.py +1 -0
  76. package/hooks/blocking/inventory_intent_records/config/intent_records_constants.py +20 -0
  77. package/hooks/blocking/inventory_intent_records/records.py +271 -0
  78. package/hooks/blocking/inventory_intent_records/tests/conftest.py +10 -0
  79. package/hooks/blocking/inventory_intent_records/tests/test_records.py +80 -0
  80. package/hooks/blocking/package_inventory_stale_blocker.py +54 -384
  81. package/hooks/blocking/package_inventory_stale_blocker_parts/CLAUDE.md +26 -0
  82. package/hooks/blocking/package_inventory_stale_blocker_parts/__init__.py +1 -0
  83. package/hooks/blocking/package_inventory_stale_blocker_parts/config/__init__.py +1 -0
  84. package/hooks/blocking/package_inventory_stale_blocker_parts/config/inventory_blocker_constants.py +16 -0
  85. package/hooks/blocking/package_inventory_stale_blocker_parts/decision.py +84 -0
  86. package/hooks/blocking/package_inventory_stale_blocker_parts/inventory_detection.py +307 -0
  87. package/hooks/blocking/package_inventory_stale_blocker_parts/tests/conftest.py +10 -0
  88. package/hooks/blocking/package_inventory_stale_blocker_parts/tests/test_decision.py +38 -0
  89. package/hooks/blocking/package_inventory_stale_blocker_parts/tests/test_inventory_detection.py +61 -0
  90. package/hooks/blocking/pii_payload_scan.py +138 -42
  91. package/hooks/blocking/pii_prevention_blocker.py +185 -291
  92. package/hooks/blocking/pii_prevention_blocker_parts/CLAUDE.md +24 -0
  93. package/hooks/blocking/pii_prevention_blocker_parts/__init__.py +1 -0
  94. package/hooks/blocking/pii_prevention_blocker_parts/config/__init__.py +1 -0
  95. package/hooks/blocking/pii_prevention_blocker_parts/config/repository_resolution_constants.py +28 -0
  96. package/hooks/blocking/pii_prevention_blocker_parts/repository_exemption.py +214 -0
  97. package/hooks/blocking/pii_prevention_blocker_parts/repository_resolution.py +208 -0
  98. package/hooks/blocking/plain_language_blocker.py +138 -4
  99. package/hooks/blocking/pr_description_command_parser.py +8 -4
  100. package/hooks/blocking/precommit_code_rules_gate.py +3 -3
  101. package/hooks/blocking/sensitive_file_protector.py +114 -48
  102. package/hooks/blocking/tdd_enforcer.py +97 -601
  103. package/hooks/blocking/tdd_enforcer_parts/CLAUDE.md +30 -0
  104. package/hooks/blocking/tdd_enforcer_parts/__init__.py +1 -0
  105. package/hooks/blocking/tdd_enforcer_parts/candidate_paths.py +142 -0
  106. package/hooks/blocking/tdd_enforcer_parts/config/__init__.py +1 -0
  107. package/hooks/blocking/tdd_enforcer_parts/config/tdd_enforcer_constants.py +32 -0
  108. package/hooks/blocking/tdd_enforcer_parts/content_analysis.py +268 -0
  109. package/hooks/blocking/tdd_enforcer_parts/decisions.py +92 -0
  110. package/hooks/blocking/tdd_enforcer_parts/freshness.py +80 -0
  111. package/hooks/blocking/tdd_enforcer_parts/git_tracking.py +63 -0
  112. package/hooks/blocking/tdd_enforcer_parts/path_classification.py +119 -0
  113. package/hooks/blocking/tdd_enforcer_parts/tests/conftest.py +10 -0
  114. package/hooks/blocking/tdd_enforcer_parts/tests/test_candidate_paths.py +31 -0
  115. package/hooks/blocking/tdd_enforcer_parts/tests/test_content_analysis.py +30 -0
  116. package/hooks/blocking/tdd_enforcer_parts/tests/test_decisions.py +34 -0
  117. package/hooks/blocking/tdd_enforcer_parts/tests/test_freshness.py +28 -0
  118. package/hooks/blocking/tdd_enforcer_parts/tests/test_git_tracking.py +48 -0
  119. package/hooks/blocking/tdd_enforcer_parts/tests/test_path_classification.py +36 -0
  120. package/hooks/blocking/test_code_rules_enforcer_scratchpad.py +105 -0
  121. package/hooks/blocking/test_code_rules_shared.py +181 -0
  122. package/hooks/blocking/test_inventory_deadlock_resolution.py +154 -0
  123. package/hooks/blocking/test_pii_payload_scan.py +168 -0
  124. package/hooks/blocking/test_plain_language_blocker_allowlist.py +184 -0
  125. package/hooks/blocking/test_sensitive_file_protector.py +185 -0
  126. package/hooks/blocking/test_tdd_enforcer_restore.py +108 -0
  127. package/hooks/blocking/test_tdd_enforcer_scratchpad.py +105 -0
  128. package/hooks/blocking/tests/conftest.py +10 -0
  129. package/hooks/blocking/tests/test_pii_prevention_blocker.py +260 -0
  130. package/hooks/blocking/tests/test_repository_exemption.py +105 -0
  131. package/hooks/blocking/tests/test_repository_resolution.py +108 -0
  132. package/hooks/diagnostic/hook_log_extractor.py +12 -10
  133. package/hooks/git-hooks/post_commit.py +3 -4
  134. package/hooks/hooks_constants/CLAUDE.md +4 -2
  135. package/hooks/hooks_constants/banned_identifiers_constants.py +0 -1
  136. package/hooks/hooks_constants/code_rules_path_utils_constants.py +1 -1
  137. package/hooks/hooks_constants/harness_scratchpad_constants.py +17 -0
  138. package/hooks/hooks_constants/local_identity.py +59 -8
  139. package/hooks/hooks_constants/pii_prevention_constants.py +0 -6
  140. package/hooks/hooks_constants/plain_language_blocker_constants.py +5 -0
  141. package/hooks/hooks_constants/sensitive_file_protector_constants.py +42 -0
  142. package/hooks/hooks_constants/test_local_identity.py +105 -3
  143. package/hooks/pyproject.toml +52 -4
  144. package/hooks/session/plugin_data_dir_cleanup.py +0 -1
  145. package/hooks/validation/mypy_validator.py +2 -2
  146. package/hooks/validators/CLAUDE.md +1 -1
  147. package/hooks/validators/README.md +2 -0
  148. package/hooks/validators/health_check.py +1 -0
  149. package/hooks/validators/mypy_integration.py +2 -0
  150. package/hooks/validators/python_style_checks.py +114 -136
  151. package/hooks/validators/python_style_helpers.py +95 -0
  152. package/hooks/validators/ruff_integration.py +3 -0
  153. package/hooks/validators/test_python_style_checks.py +0 -164
  154. package/hooks/validators/test_python_style_checks_decorator_gap.py +119 -0
  155. package/hooks/validators/test_python_style_fixes.py +251 -0
  156. package/hooks/validators/test_python_style_helpers.py +125 -0
  157. package/hooks/workflow/auto_formatter.py +5 -4
  158. package/package.json +1 -1
  159. package/rules/CLAUDE.md +1 -0
  160. package/rules/anti-corollary-tests.md +69 -0
  161. package/rules/bdd.md +1 -3
  162. package/rules/code-reviews.md +1 -1
  163. package/rules/gh-paginate.md +1 -1
  164. package/rules/plain-language.md +2 -0
  165. package/scripts/CLAUDE.md +4 -0
  166. package/scripts/dev_env_scripts_constants/CLAUDE.md +6 -4
  167. package/scripts/dev_env_scripts_constants/code_review_constants.py +71 -0
  168. package/scripts/dev_env_scripts_constants/grok_worker_constants.py +435 -0
  169. package/scripts/dev_env_scripts_constants/timing.py +7 -1
  170. package/scripts/grok_headless_runner.py +294 -0
  171. package/scripts/grok_worker_preflight.py +410 -0
  172. package/scripts/invoke_code_review.py +463 -0
  173. package/scripts/resolve_worker_spawn.py +619 -0
  174. package/scripts/spawn_grok_batch.py +672 -0
  175. package/scripts/test_grok_headless_runner.py +626 -0
  176. package/scripts/test_grok_worker_preflight.py +1054 -0
  177. package/scripts/test_invoke_code_review.py +672 -0
  178. package/scripts/test_resolve_worker_spawn.py +1014 -0
  179. package/scripts/test_spawn_grok_batch.py +1017 -0
  180. package/skills/CLAUDE.md +6 -3
  181. package/skills/_shared/pr-loop/scripts/build_audit_prompt.py +72 -13
  182. package/skills/_shared/pr-loop/scripts/build_fix_prompt.py +121 -14
  183. package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +78 -0
  184. package/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +121 -0
  185. package/skills/_shared/pr-loop/scripts/test_build_fix_prompt.py +196 -6
  186. package/skills/autoconverge/CLAUDE.md +3 -3
  187. package/skills/autoconverge/SKILL.md +9 -3
  188. package/skills/autoconverge/reference/CLAUDE.md +2 -2
  189. package/skills/autoconverge/reference/convergence.md +33 -11
  190. package/skills/autoconverge/reference/stop-conditions.md +16 -5
  191. package/skills/autoconverge/workflow/CLAUDE.md +2 -1
  192. package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +7 -2
  193. package/skills/autoconverge/workflow/converge.codex-gate.test.mjs +300 -0
  194. package/skills/autoconverge/workflow/converge.contract.test.mjs +5 -5
  195. package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +29 -29
  196. package/skills/autoconverge/workflow/converge.fix-progress.test.mjs +1 -1
  197. package/skills/autoconverge/workflow/converge.mjs +202 -18
  198. package/skills/bugteam/CLAUDE.md +2 -2
  199. package/skills/bugteam/CONSTRAINTS.md +3 -2
  200. package/skills/bugteam/PROMPTS.md +7 -6
  201. package/skills/bugteam/SKILL.md +18 -13
  202. package/skills/bugteam/reference/README.md +2 -3
  203. package/skills/bugteam/reference/audit-and-teammates.md +215 -35
  204. package/skills/bugteam/reference/design-rationale.md +1 -1
  205. package/skills/bugteam/reference/obstacles/CLAUDE.md +1 -1
  206. package/skills/bugteam/reference/team-setup.md +8 -2
  207. package/skills/closeout/SKILL.md +153 -0
  208. package/skills/closeout/reference/handoff-prompt-template.md +72 -0
  209. package/skills/closeout/reference/issue-body-templates.md +108 -0
  210. package/skills/closeout/reference/pii-redaction-checklist.md +36 -0
  211. package/skills/codex-review/CLAUDE.md +46 -0
  212. package/skills/codex-review/SKILL.md +181 -0
  213. package/skills/codex-review/reference/CLAUDE.md +15 -0
  214. package/skills/codex-review/reference/cli-contract.md +253 -0
  215. package/skills/codex-review/reference/loop-integration.md +118 -0
  216. package/skills/codex-review/scripts/codex_down_classifier.py +98 -0
  217. package/skills/codex-review/scripts/codex_review_scripts_constants/CLAUDE.md +18 -0
  218. package/skills/codex-review/scripts/codex_review_scripts_constants/__init__.py +1 -0
  219. package/skills/codex-review/scripts/codex_review_scripts_constants/classifier_constants.py +35 -0
  220. package/skills/codex-review/scripts/codex_review_scripts_constants/codex_usage_probe_constants.py +86 -0
  221. package/skills/codex-review/scripts/codex_review_scripts_constants/findings_constants.py +18 -0
  222. package/skills/codex-review/scripts/codex_review_scripts_constants/run_constants.py +45 -0
  223. package/skills/codex-review/scripts/codex_usage_probe.py +573 -0
  224. package/skills/codex-review/scripts/fixtures/auth_failure_synthetic.txt +1 -0
  225. package/skills/codex-review/scripts/fixtures/config_load_failure_v0.125.0.txt +1 -0
  226. package/skills/codex-review/scripts/fixtures/freeform_findings_v0.144.3.txt +6 -0
  227. package/skills/codex-review/scripts/fixtures/model_rejection_v0.125.0.jsonl +5 -0
  228. package/skills/codex-review/scripts/fixtures/structured_findings.txt +13 -0
  229. package/skills/codex-review/scripts/fixtures/success_stream_v0.144.3.jsonl +6 -0
  230. package/skills/codex-review/scripts/fixtures/unknown_failure_synthetic.txt +1 -0
  231. package/skills/codex-review/scripts/fixtures/usage_limit_synthetic.txt +1 -0
  232. package/skills/codex-review/scripts/parse_codex_findings.py +207 -0
  233. package/skills/codex-review/scripts/run_codex_review.py +415 -0
  234. package/skills/codex-review/scripts/test_codex_down_classifier.py +143 -0
  235. package/skills/codex-review/scripts/test_codex_usage_probe.py +678 -0
  236. package/skills/codex-review/scripts/test_parse_codex_findings.py +130 -0
  237. package/skills/codex-review/scripts/test_run_codex_review.py +812 -0
  238. package/skills/codex-review/test_skill_scaffold.py +192 -0
  239. package/skills/grok-spawn/CLAUDE.md +28 -0
  240. package/skills/grok-spawn/SKILL.md +226 -0
  241. package/skills/grok-spawn/reference/flag-profiles.md +132 -0
  242. package/skills/grok-spawn/reference/worker-briefs.md +152 -0
  243. package/skills/grokify/SKILL.md +9 -1
  244. package/skills/grokify/capability-claims.test.mjs +28 -0
  245. package/skills/grokify/evals/README.md +72 -0
  246. package/skills/grokify/evals/parse-payload.test.mjs +171 -0
  247. package/skills/grokify/evals/run-capability-evals.mjs +545 -0
  248. package/skills/orchestrator/SKILL.md +32 -22
  249. package/skills/orchestrator-refresh/SKILL.md +12 -8
  250. package/skills/pr-converge/CLAUDE.md +1 -1
  251. package/skills/pr-converge/SKILL.md +34 -13
  252. package/skills/pr-converge/reference/convergence-gates.md +42 -15
  253. package/skills/pr-converge/reference/fix-protocol.md +1 -1
  254. package/skills/pr-converge/reference/ground-rules.md +1 -1
  255. package/skills/pr-converge/reference/per-tick.md +130 -42
  256. package/skills/pr-converge/reference/state-schema.md +10 -0
  257. package/skills/pr-converge/scripts/CLAUDE.md +2 -0
  258. package/skills/pr-converge/scripts/_pr_converge_path_setup.py +5 -1
  259. package/skills/pr-converge/scripts/check_convergence.py +605 -29
  260. package/skills/pr-converge/scripts/check_convergence_availability.py +232 -0
  261. package/skills/pr-converge/scripts/check_convergence_gates.py +279 -235
  262. package/skills/pr-converge/scripts/check_convergence_thread_gates.py +1 -1
  263. package/skills/pr-converge/scripts/pr_converge_scripts_constants/convergence_gate_constants.py +36 -2
  264. package/skills/pr-converge/scripts/test__pr_converge_path_setup.py +4 -0
  265. package/skills/pr-converge/scripts/test_check_convergence.py +71 -3
  266. package/skills/pr-converge/scripts/test_check_convergence_availability.py +326 -0
  267. package/skills/pr-converge/scripts/test_check_convergence_codex.py +507 -0
  268. package/skills/pr-converge/scripts/test_check_convergence_contract.py +89 -17
  269. package/skills/pr-converge/scripts/test_check_convergence_fixture.py +179 -0
  270. package/skills/pr-converge/scripts/test_check_convergence_gates.py +84 -68
  271. package/skills/pr-converge/scripts/test_check_convergence_thread_gates.py +24 -0
  272. package/skills/pr-converge/test_step5_host_branch.py +106 -0
  273. package/skills/pr-fix-protocol/SKILL.md +65 -0
  274. package/skills/pr-loop-cloud-transport/SKILL.md +2 -0
  275. package/skills/reviewer-gates/SKILL.md +7 -5
  276. package/skills/skill-builder/references/skill-modularity.md +1 -1
  277. package/skills/team-advisor/SKILL.md +16 -12
  278. package/system-prompts/software-engineer.xml +7 -6
  279. package/hooks/validators/test_verify_paths.py +0 -32
  280. package/hooks/validators/verify_paths.py +0 -57
@@ -28,4 +28,4 @@ Drives a draft PR to convergence by driving the internal passes to clean first
28
28
  - All findings and PR reports state verified facts only — no hedging language.
29
29
  - The GitHub MCP (`pull_request_read`, `pull_request_review_write`) is the primary path for PR inspection; `gh api` is the fallback.
30
30
  - Three step-scoped agents (`fix_executor`, `thread_sweep`, `copilot_watch`) persist across ticks via the `persistent_agents` map in loop state; each tick resumes them with `SendMessage` and spawns a fresh named agent when a stored id is dead.
31
- - The tick delegates shared mechanics to five sibling sub-skills: `reviewer-gates` (opt-out, Copilot quota, Bugbot trigger), `pr-scope-resolve` (target resolution), `pr-fix-protocol` (fix sequence + unresolved-thread sweep), `post-audit-findings` (audit posting), and `pr-loop-lifecycle` (run open/close).
31
+ - The tick delegates shared mechanics to three sibling sub-skills: `reviewer-gates` (opt-out, Copilot quota, Bugbot trigger), `pr-fix-protocol` (fix sequence + unresolved-thread sweep), and `pr-loop-lifecycle` (run open/close). Target resolution happens inline in `reference/per-tick.md` Steps 1 and 1.5. Audit posting follows the `_shared/pr-loop/post-audit-thread-contract.md` contract, run through `_shared/pr-loop/scripts/post_audit_thread.py`.
@@ -153,11 +153,12 @@ the `persistent_agents` map
153
153
  within one bounded wait, drop the map entry, spawn a fresh named agent,
154
154
  record it, and continue the tick. Never abort a tick on a stale id;
155
155
  never retry the same dead id.
156
- - **Fresh every round (never persisted):** the Step 5 `/code-review high --fix`
157
- pass and the Step 6 bugteam audit (unbiased eyes each round; the
158
- enforcer needs the formal Skill call), and every `code-verifier` a
159
- named code-verifier never fires `SubagentStop`, so no verdict mints (see
160
- the named-`code-verifier` entry in the Gotchas list below).
156
+ - **Fresh every round (never persisted):** the Step 5 host-aware
157
+ `invoke_code_review.py` / `/code-review high --fix` pass and the Step 6
158
+ bugteam audit (unbiased eyes each round; the enforcer needs the formal
159
+ Skill call), and every `code-verifier` a named code-verifier never fires
160
+ `SubagentStop`, so no verdict mints (see the named-`code-verifier` entry
161
+ in the Gotchas list below).
161
162
  - **Shutdown:** at loop end (convergence or a stop condition), send each
162
163
  persistent agent a shutdown request and clear `persistent_agents` before
163
164
  the `pr-loop-lifecycle` Close.
@@ -206,11 +207,11 @@ post a fresh PR in a fresh branch based on origin main to the user.
206
207
  `pwsh` calls run through the PowerShell tool, not Bash. Bash on
207
208
  Windows is Git Bash which cannot execute PowerShell cmdlets. Route all
208
209
  PowerShell work through the PowerShell tool or `pwsh -NoProfile -File`.
209
- - **Cross-repo PR: route cwd into the PR worktree before `/code-review`**
210
- `/code-review high --fix` (Step 5) audits the repo of the current working
211
- directory. When the session is rooted in a different repo than the PR,
212
- `EnterWorktree` cannot re-root (it is scoped to the session's repo);
213
- resolve the PR worktree and `cd` into it per
210
+ - **Cross-repo PR: route cwd into the PR worktree before Step 5 review**
211
+ `invoke_code_review.py` and `/code-review high --fix` audit the repo of the
212
+ cwd (the helper's `--cwd`). When the session is rooted in a different repo
213
+ than the PR, `EnterWorktree` cannot re-root (it is scoped to the session's
214
+ repo); resolve the PR worktree and `cd` into it per
214
215
  [Step 1.5](reference/per-tick.md). Skipping this reviews and edits the
215
216
  wrong repo. The route is routine and automatic — never a material fork
216
217
  to pause on.
@@ -292,12 +293,32 @@ round as converged. This rule holds every tick, every loop, every PR.
292
293
  See: [`reference/per-tick.md` § CODE_REVIEW entry](reference/per-tick.md).
293
294
  Pre-condition: cwd is the Step 1.5 PR worktree on `current_head`.
294
295
  Scope: FULL `origin/main...HEAD` diff every tick (no path args, no delta cut).
296
+ Review always runs at effort high on model opus through
297
+ `invoke_code_review.py`. Mode decision inputs: host profile + session
298
+ model. Call:
299
+ `python "$HOME/.claude/scripts/invoke_code_review.py" --cwd <PR-worktree>
300
+ --session-model <alias>`. Chain mode uses that cwd and empty stdin; the
301
+ chain process never commits and never pushes. JSON stdout carries
302
+ `mode` (`in_session` | `chain`), `served_command`, `returncode`, and
303
+ `dirty_tree`. Config/host errors still emit that JSON with non-zero
304
+ `returncode` (no traceback-only failure).
295
305
 
296
306
  - [ ] **Static sweep fails** → apply shared fix protocol → push → reset markers
297
307
  → stay CODE_REVIEW → Step 5
298
- - [ ] **`/code-review high --fix` applies fixes** commit + push reset markers
299
- stay CODE_REVIEW Step 5
300
- - [ ] **clean** zero unresolved threads (else fix + resolve) →
308
+ - [ ] **`mode == in_session`** (Claude host, session model opus)run
309
+ `/code-review high --fix` in-session (no path args)
310
+ - [ ] **`mode == chain`** (any other host or non-opus session) → helper
311
+ already ran the headless review; read `returncode`,
312
+ `served_command`, and `dirty_tree` from JSON
313
+ - [ ] **failed review** (`returncode != 0`, or chain with null
314
+ `served_command`) → do not set `code_review_clean_at` → stay
315
+ CODE_REVIEW → Step 5
316
+ - [ ] **fixes applied** (`dirty_tree` true / working tree dirty) →
317
+ commit + push via shared fix protocol → reset markers → stay
318
+ CODE_REVIEW → Step 5
319
+ - [ ] **clean** (successful serve: `returncode == 0`, chain
320
+ `served_command` non-null when chain, and `dirty_tree` false) →
321
+ zero unresolved threads (else fix + resolve) →
301
322
  `code_review_clean_at = current_head` → `phase = BUGTEAM` → Step 6
302
323
 
303
324
  - [ ] **Step 6: BUGTEAM — run, decide, fix, reply, resolve**
@@ -8,11 +8,12 @@
8
8
  - [(d) Post-convergence Copilot review request](#d-post-convergence-copilot-review-request)
9
9
  - [(e) Thread-resolution gate](#e-thread-resolution-gate)
10
10
  - [(f) Mark ready and report](#f-mark-ready-and-report)
11
+ - [(g) Codex review gate (conditional-required)](#g-codex-review-gate-conditional-required)
11
12
  Run **only** after the terminal Bugbot gate confirms the HEAD
12
13
  (`bugbot_clean_at == current_head` OR `bugbot_down`), which runs just before
13
14
  these gates once Step 2 BUGTEAM reports `convergence (zero findings)` with no
14
15
  push during the bugteam tick. Gates run in order; first failure determines
15
- next-tick behavior. Mark PR ready only when all six pass.
16
+ next-tick behavior. Mark PR ready only when every gate that applies passes.
16
17
 
17
18
  **Mandatory evidence rule:** Every gate that fetches data MUST produce a
18
19
  summary of its findings before proceeding to the next gate. Gate (f) MUST
@@ -47,7 +48,7 @@ Decide (four branches; match first whose predicate holds):
47
48
  dirty). Apply the shared fix protocol ([`../../../_shared/pr-loop/fix-protocol.md`](../../../_shared/pr-loop/fix-protocol.md); skill deltas in [`fix-protocol.md`](fix-protocol.md)) in the same tick.
48
49
  Reset push-invalidated markers per [ground-rules.md](ground-rules.md) /
49
50
  [state-schema.md](state-schema.md) (all `*_clean_at`, `merge_state_status`,
50
- `bugbot_down`, `bugbot_acknowledged_at`), `phase = CODE_REVIEW`, schedule
51
+ `bugbot_down`, `bugbot_acknowledged_at`, `codex_down`), `phase = CODE_REVIEW`, schedule
51
52
  next wakeup, return. Full back-to-back-clean cycle plus all six gates must
52
53
  hold again on new HEAD.
53
54
  - **`classification == "dirty"` with empty inline comments matching
@@ -59,7 +60,7 @@ Decide (four branches; match first whose predicate holds):
59
60
  new HEAD SHA. Reset push-invalidated markers per
60
61
  [ground-rules.md](ground-rules.md) / [state-schema.md](state-schema.md)
61
62
  (all `*_clean_at`, `merge_state_status`, `bugbot_down`,
62
- `bugbot_acknowledged_at`), `phase = CODE_REVIEW`, schedule next wakeup,
63
+ `bugbot_acknowledged_at`, `codex_down`), `phase = CODE_REVIEW`, schedule next wakeup,
63
64
  return. Convergence needs full back-to-back-clean on new HEAD.
64
65
  - **`classification == "clean"` (state `APPROVED`):** Set
65
66
  `copilot_clean_at = current_head`. Record evidence: "Copilot APPROVED at <SHA>".
@@ -90,7 +91,7 @@ Decide (four branches; match first whose predicate holds):
90
91
  path — apply the shared fix protocol ([`../../../_shared/pr-loop/fix-protocol.md`](../../../_shared/pr-loop/fix-protocol.md); skill deltas in [`fix-protocol.md`](fix-protocol.md)). Reset push-invalidated markers per
91
92
  [ground-rules.md](ground-rules.md) / [state-schema.md](state-schema.md)
92
93
  (all `*_clean_at`, `merge_state_status`, `bugbot_down`,
93
- `bugbot_acknowledged_at`), `phase = CODE_REVIEW`, schedule next wakeup,
94
+ `bugbot_acknowledged_at`, `codex_down`), `phase = CODE_REVIEW`, schedule next wakeup,
94
95
  return.
95
96
  - **`classification == "dirty"` with empty inline comments matching
96
97
  `pull_request_review_id`:** Claude posted findings only in review body
@@ -99,7 +100,7 @@ Decide (four branches; match first whose predicate holds):
99
100
  shared fix protocol ([`../../../_shared/pr-loop/fix-protocol.md`](../../../_shared/pr-loop/fix-protocol.md); skill deltas in [`fix-protocol.md`](fix-protocol.md)). Reset
100
101
  push-invalidated markers per [ground-rules.md](ground-rules.md) /
101
102
  [state-schema.md](state-schema.md) (all `*_clean_at`, `merge_state_status`,
102
- `bugbot_down`, `bugbot_acknowledged_at`), `phase = CODE_REVIEW`, schedule
103
+ `bugbot_down`, `bugbot_acknowledged_at`, `codex_down`), `phase = CODE_REVIEW`, schedule
103
104
  next wakeup, return.
104
105
  - **`classification == "clean"` (state `APPROVED`):** Record evidence:
105
106
  "Claude APPROVED at <SHA>". Continue to gate (c).
@@ -127,7 +128,7 @@ Persist `mergeable_state` into `merge_state_status`. Decide:
127
128
  every prior clean state — reset push-invalidated markers per
128
129
  [ground-rules.md](ground-rules.md) / [state-schema.md](state-schema.md)
129
130
  (all `*_clean_at`, `merge_state_status`, `bugbot_down`,
130
- `bugbot_acknowledged_at`), `phase = CODE_REVIEW`, schedule next wakeup,
131
+ `bugbot_acknowledged_at`, `codex_down`), `phase = CODE_REVIEW`, schedule next wakeup,
131
132
  return. Loop re-runs from scratch on new HEAD.
132
133
  - **`mergeable_state` is `"blocked"`, `"behind"`, `"unknown"`, or `"unstable"` for
133
134
  non-conflict reasons** (required checks pending/failing for "unstable",
@@ -173,7 +174,7 @@ against `current_head`. Decide:
173
174
  Treat identically to gate (a) dirty path — apply the shared fix protocol ([`../../../_shared/pr-loop/fix-protocol.md`](../../../_shared/pr-loop/fix-protocol.md); skill deltas in [`fix-protocol.md`](fix-protocol.md)).
174
175
  Reset push-invalidated markers per [ground-rules.md](ground-rules.md) /
175
176
  [state-schema.md](state-schema.md) (all `*_clean_at`, `merge_state_status`,
176
- `bugbot_down`, `bugbot_acknowledged_at`), `phase = CODE_REVIEW`, schedule
177
+ `bugbot_down`, `bugbot_acknowledged_at`, `codex_down`), `phase = CODE_REVIEW`, schedule
177
178
  next wakeup, return.
178
179
  - **No Copilot review at `current_head` yet:** Record evidence: "No Copilot
179
180
  review at <SHA> (wait count: <N>)". Increment `copilot_wait_count`
@@ -207,7 +208,7 @@ Decide:
207
208
  shared fix protocol unresolved-thread sweep ([`../../../_shared/pr-loop/fix-protocol.md`](../../../_shared/pr-loop/fix-protocol.md) step 12; skill deltas in [`fix-protocol.md`](fix-protocol.md)). Push if any code changed → reset
208
209
  push-invalidated markers per [ground-rules.md](ground-rules.md) /
209
210
  [state-schema.md](state-schema.md) (all `*_clean_at`, `merge_state_status`,
210
- `bugbot_down`, `bugbot_acknowledged_at`), `phase = CODE_REVIEW`, schedule
211
+ `bugbot_down`, `bugbot_acknowledged_at`, `codex_down`), `phase = CODE_REVIEW`, schedule
211
212
  next wakeup, return. If only resolutions (no code changes), re-check this
212
213
  gate without resetting.
213
214
 
@@ -218,7 +219,8 @@ Decide:
218
219
  ```
219
220
  python $HOME/.claude/skills/pr-converge/scripts/check_convergence.py \
220
221
  --owner <O> --repo <R> --pr-number <N> \
221
- [--bugbot-down] [--copilot-down]
222
+ [--bugbot-down] [--copilot-down] [--codex-down] \
223
+ [--codex-clean-at <SHA>]
222
224
  ```
223
225
 
224
226
  Ready means exit `0` and the line:
@@ -233,11 +235,13 @@ Exact printed labels (script order):
233
235
  2. `bugbot review body clean` (omitted when `bugbot_down`)
234
236
  3. `bugteam_clean_at == current_head`
235
237
  4. `copilot_clean_at == current_head`
236
- 5. `zero unresolved bot threads`
237
- 6. `PR is mergeable`
238
- 7. `no pending requested reviews`
238
+ 5. `codex_clean_at == current_head` (skipped when usage is at/below threshold,
239
+ null, `codex_down`, or the `codex` opt-out token)
240
+ 6. `zero unresolved bot threads`
241
+ 7. `PR is mergeable`
242
+ 8. `no pending requested reviews`
239
243
 
240
- On label 5: `isOutdated == true` excludes the thread; bot filter is login
244
+ On label 6: `isOutdated == true` excludes the thread; bot filter is login
241
245
  substrings `cursor` | `claude` | `copilot` only. The script has no Claude
242
246
  APPROVED review gate.
243
247
 
@@ -248,7 +252,7 @@ before invoking the script; they never appear as `check_convergence.py` labels.
248
252
 
249
253
  When the script fails (exit 1), do NOT mark ready. Report the FAIL label and
250
254
  route through the matching fix path (BUGBOT for dirty reviews, rebase for
251
- merge conflicts, and so on).
255
+ merge conflicts, Codex findings via the shared fix protocol, and so on).
252
256
 
253
257
  When the script passes (exit 0):
254
258
 
@@ -258,5 +262,28 @@ Use the `update_pull_request` MCP tool:
258
262
 
259
263
  With `state.json`, append convergence row to
260
264
  `<TMPDIR>/pr-converge-<session_id>/converged.log` per `multi-pr-orchestration.md` §Memory; else skip.
261
- Report from the script's PASS lines (the seven labels above). **Omit loop
265
+ Report from the script's PASS lines (the eight labels above). **Omit loop
262
266
  pacing** per **Convergence** of active pacing workflow.
267
+
268
+ ## (g) Codex review gate (conditional-required)
269
+
270
+ Machine condition label: `codex_clean_at == current_head`.
271
+
272
+ **Threshold rule** (shared with `codex_usage_probe.py` —
273
+ `WEEKLY_USAGE_GATE_THRESHOLD_PERCENT`; never restate the numeric literal):
274
+
275
+ - When the weekly probe reports **more than** the threshold percent left: a
276
+ clean Codex review on `current_head` is required. Stamp
277
+ `codex_clean_at = current_head` after a clean skill run, and pass
278
+ `--codex-clean-at <SHA>` (or keep it in `$CLAUDE_JOB_DIR/pr-converge-state.json`)
279
+ so `check_convergence.py` can verify the stamp.
280
+ - When usage is **at or below** the threshold, or `percent_left` is null: the
281
+ gate is skipped and never blocks ready.
282
+ - When `codex_down == true`, when `CLAUDE_REVIEWS_DISABLED` lists `codex`, or
283
+ when the caller passes `--codex-down`: the gate is bypassed and never blocks.
284
+
285
+ **Agent path before the machine checklist:** run the usage probe, then when
286
+ required and not opted out, invoke the `codex-review` skill against the PR base
287
+ branch (HEAD vs base) per [per-tick.md](per-tick.md). Findings enter the shared
288
+ fix protocol; a `codex_down` classification sets `codex_down = true` and
289
+ continues without blocking.
@@ -17,7 +17,7 @@ obligations and the same-tick re-entry rule.
17
17
  - Writes `last_action: "fix_pushed"`, `current_head: <new SHA>`,
18
18
  `bugbot_clean_at: null`, `code_review_clean_at: null`,
19
19
  `bugteam_clean_at: null`, `copilot_clean_at: null`,
20
- `merge_state_status: null`, `bugbot_down: false`,
20
+ `merge_state_status: null`, `bugbot_down: false`, `codex_down: false`,
21
21
  `phase: "CODE_REVIEW"`, `status: "awaiting_code_review"`, `last_updated`
22
22
  (ISO-8601 UTC) to `state.json` (per §Concurrency).
23
23
  - Goes idle. Orchestrator spawns a follow-up `general-purpose` agent for the
@@ -7,7 +7,7 @@
7
7
  - **Bugbot findings on the current SHA mean fix-then-push-then-re-enter
8
8
  CODE_REVIEW,** so the internal passes re-clear the new HEAD before the terminal
9
9
  Bugbot gate runs again.
10
- - **All `*_clean_at`, `merge_state_status`, and `bugbot_down` reset on every push.**
10
+ - **All `*_clean_at`, `merge_state_status`, and `bugbot_down` / `codex_down` reset on every push.**
11
11
  - **`bugbot run` comment is load-bearing.** Literal phrase exactly —
12
12
  empirically the only re-trigger Cursor Bugbot recognizes.
13
13
  - **Production edits go through `clean-coder`, except `/code-review high --fix`.**
@@ -53,8 +53,8 @@ pull_request_read(owner=OWNER, repo=REPO, pullNumber=NUMBER, method="get") → `
53
53
  If owner/repo/number are not yet known, extract them from the PR URL.
54
54
  If `current_head` changed since last tick, reset push-invalidated markers
55
55
  per [ground-rules.md](ground-rules.md) / [state-schema.md](state-schema.md)
56
- (all `*_clean_at`, `merge_state_status`, `bugbot_down`, `bugbot_acknowledged_at`) —
57
- new HEAD invalidates prior clean and down-detection state.
56
+ (all `*_clean_at`, `merge_state_status`, `bugbot_down`, `bugbot_acknowledged_at`,
57
+ `codex_down`) — new HEAD invalidates prior clean and down-detection state.
58
58
 
59
59
  Capture `number`, `head.sha` (= `current_head`), owner/repo, branch.
60
60
 
@@ -171,9 +171,10 @@ CODE_REVIEW.
171
171
  ### `phase == CODE_REVIEW`
172
172
 
173
173
  The entry phase of every convergence tick, re-entered after any fix push. It runs
174
- a deterministic static sweep, then Claude Code's built-in `/code-review high
175
- --fix` on the full `origin/main...HEAD` diff; `/code-review` produces no GitHub
176
- review artifact, so there are no code-review threads to resolve.
174
+ a deterministic static sweep, then the built-in `/code-review high --fix` on the
175
+ full `origin/main...HEAD` diff at effort high on model opus. `/code-review`
176
+ produces no GitHub review artifact, so there are no code-review threads to
177
+ resolve.
177
178
 
178
179
  a. **Static sweep — runs first, before `/code-review`.** Run the deterministic
179
180
  gates over the full `origin/main...HEAD` changed files:
@@ -182,41 +183,85 @@ a. **Static sweep — runs first, before `/code-review`.** Run the deterministic
182
183
  shared fix protocol ([`../../../_shared/pr-loop/fix-protocol.md`](../../../_shared/pr-loop/fix-protocol.md); skill deltas in [`fix-protocol.md`](fix-protocol.md)), commit and push,
183
184
  reset push-invalidated markers per [ground-rules.md](ground-rules.md) /
184
185
  [state-schema.md](state-schema.md) (all `*_clean_at`, `merge_state_status`,
185
- `bugbot_down`, `bugbot_acknowledged_at`), stay `phase = CODE_REVIEW`, and
186
- re-run the sweep. When the sweep is clean, run `/code-review` below.
186
+ `bugbot_down`, `bugbot_acknowledged_at`, `codex_down`), stay
187
+ `phase = CODE_REVIEW`, and re-run the sweep. When the sweep is clean, run
188
+ the host-aware review below.
187
189
 
188
- b. Run Claude Code's built-in `/code-review high --fix` on the FULL
189
- `origin/main...HEAD` diff — every file the PR touches — via the
190
+ b. Run the built-in `/code-review high --fix` on the FULL `origin/main...HEAD`
191
+ diff — every file the PR touches — via the
190
192
  [local diff review](https://code.claude.com/docs/en/code-review#review-a-diff-locally).
191
- It reviews the diff and applies its findings to the working tree.
193
+ The review always runs at effort high on model opus. It reviews the diff and
194
+ applies its findings to the working tree.
192
195
 
193
196
  Before running, confirm the working directory is the PR worktree resolved
194
197
  in [Step 1.5](#step-15-resolve-the-pr-worktree-cwd-routing) — `git rev-parse
195
198
  --show-toplevel` is that checkout and `git rev-parse HEAD` equals
196
199
  `current_head` — with no uncommitted edits. When the session is rooted in a
197
200
  different repo than the PR, the `cd` from Step 1.5 supplies this; the
198
- persisted working directory is what `/code-review` audits. Then invoke
199
- `/code-review high --fix` with no path arguments so it audits the whole branch
200
- diff against `origin/main`. Do not delta-scope to commits added since the
201
- prior clean SHA, do not scope to a single file, do not scope to bugbot's
202
- flagged paths. A partial-scope round does not count and cannot set
203
- `code_review_clean_at`. Invoke `/code-review high --fix` so the pre-catch pass
204
- gets broad coverage regardless of the session's current effort.
201
+ persisted working directory is the cwd the review audits.
205
202
 
206
- c. Decide (two branches; match first whose predicate holds):
203
+ Route every CODE_REVIEW pass through the host-aware helper
204
+ `invoke_code_review.py`. Mode decision inputs are the host profile (detected
205
+ by the helper) and the caller's session model short alias:
207
206
 
208
- - **`/code-review` applied fixes (working tree changed):** Commit the
207
+ ```bash
208
+ python "$HOME/.claude/scripts/invoke_code_review.py" \
209
+ --cwd "$(git rev-parse --show-toplevel)" \
210
+ --session-model <session-model-alias>
211
+ ```
212
+
213
+ The helper prints one JSON object on stdout only:
214
+ `{mode, served_command, returncode, dirty_tree}`. Chain mode sets cwd to the
215
+ PR worktree and redirects stdin from the empty stream so the spawn does not
216
+ wait for interactive input. The chain process never commits and never pushes
217
+ — commit and push belong to this step via the shared fix protocol. On
218
+ `ChainConfigurationError` or host `ValueError`, the helper still prints that
219
+ JSON shape (non-zero `returncode`, null `served_command`) and exits non-zero
220
+ — never a traceback-only failure.
221
+
222
+ Match the first mode whose predicate holds:
223
+
224
+ - **`mode == "in_session"`** (Claude host and session model is opus): run
225
+ `/code-review high --fix` in this session with no path arguments so it
226
+ audits the whole branch diff against `origin/main`. After it returns, a
227
+ non-empty `git status --porcelain` means fixes applied (`dirty_tree`
228
+ equivalent). Treat a failed in-session slash command the same as a failed
229
+ review: do not set `code_review_clean_at`.
230
+ - **`mode == "chain"`** (any other host, or a Claude session on any model
231
+ other than opus): the helper already ran the headless review
232
+ (`claude -p "/code-review high --fix" --model opus` through the chain
233
+ runner) with cwd set to the PR worktree. Read `returncode`,
234
+ `served_command`, and `dirty_tree` from the JSON. A successful serve is
235
+ `returncode == 0` with a non-null `served_command`. `dirty_tree` true
236
+ means fixes applied; `dirty_tree` false is clean only after a successful
237
+ serve.
238
+
239
+ Do not delta-scope to commits added since the prior clean SHA, do not scope
240
+ to a single file, do not scope to bugbot's flagged paths. A partial-scope
241
+ round does not count and cannot set `code_review_clean_at`.
242
+
243
+ c. Decide (three branches; match first whose predicate holds):
244
+
245
+ - **Failed review (`returncode != 0`, or chain mode with null
246
+ `served_command`):** The review did not complete a successful serve. Do
247
+ not set `code_review_clean_at`. Stay `phase = CODE_REVIEW`, schedule next
248
+ wakeup, return. A failed chain often leaves `dirty_tree` false — that is
249
+ not a clean stamp.
250
+ - **Fixes applied (working tree dirty / `dirty_tree` true):** Commit the
209
251
  applied fixes in one commit → push, following the shared fix protocol
210
252
  commit and push steps ([`../../../_shared/pr-loop/fix-protocol.md`](../../../_shared/pr-loop/fix-protocol.md)). Reset
211
253
  push-invalidated markers per [ground-rules.md](ground-rules.md) /
212
254
  [state-schema.md](state-schema.md) (all `*_clean_at`, `merge_state_status`,
213
- `bugbot_down`, `bugbot_acknowledged_at`). Stay `phase = CODE_REVIEW`,
214
- schedule next wakeup, return. Every fix push re-enters the internal
215
- passes on the new HEAD.
216
- - **Clean (no changes applied):** Set
255
+ `bugbot_down`, `bugbot_acknowledged_at`, `codex_down`). Stay
256
+ `phase = CODE_REVIEW`, schedule next wakeup, return. Every fix push
257
+ re-enters the internal passes on the new HEAD.
258
+ - **Clean (successful serve: `returncode == 0`, chain `served_command`
259
+ non-null when `mode == chain`, and `dirty_tree` false):** Set
217
260
  `code_review_clean_at = current_head`, `phase = BUGTEAM`. Continue
218
261
  BUGTEAM in same tick — back-to-back convergence requires code-review and
219
- bugteam clean on the same HEAD before the terminal gates run.
262
+ bugteam clean on the same HEAD before the terminal gates run. Helper
263
+ contract: `is_code_review_clean_stamp_allowed` is true only for this
264
+ branch.
220
265
 
221
266
  ### `phase == BUGTEAM`
222
267
 
@@ -263,8 +308,8 @@ pushed commits during its run. `current_head` from Step 1 is stale:
263
308
  If `new_head != current_head`, set `current_head = new_head` and reset
264
309
  push-invalidated markers per [ground-rules.md](ground-rules.md) /
265
310
  [state-schema.md](state-schema.md) (all `*_clean_at`, `merge_state_status`,
266
- `bugbot_down`, `bugbot_acknowledged_at`). New commits invalidate prior
267
- clean and down-detection state.
311
+ `bugbot_down`, `bugbot_acknowledged_at`, `codex_down`). New commits
312
+ invalidate prior clean and down-detection state.
268
313
 
269
314
  c. Inspect bugteam outcome. Reports `convergence (zero findings)` or list
270
315
  of unfixed findings with file:line.
@@ -283,8 +328,8 @@ never falsely terminates:
283
328
  ([`../../../_shared/pr-loop/fix-protocol.md`](../../../_shared/pr-loop/fix-protocol.md); skill deltas in [fix-protocol.md](fix-protocol.md)). Reset push-invalidated markers
284
329
  per [ground-rules.md](ground-rules.md) / [state-schema.md](state-schema.md)
285
330
  (all `*_clean_at`, `merge_state_status`, `bugbot_down`,
286
- `bugbot_acknowledged_at`), `phase = CODE_REVIEW`, schedule next wakeup,
287
- return.
331
+ `bugbot_acknowledged_at`, `codex_down`), `phase = CODE_REVIEW`, schedule
332
+ next wakeup, return.
288
333
 
289
334
  ### `phase == BUGBOT` (terminal gate)
290
335
 
@@ -295,8 +340,9 @@ passes are clean; Bugbot confirms the HEAD, then the convergence gates run.
295
340
  `python "$HOME/.claude/_shared/pr-loop/scripts/reviews_disabled.py" --reviewer bugbot`
296
341
 
297
342
  - Exit 0 (Bugbot disabled for this run — the default, unless
298
- `CLAUDE_REVIEWS_ENABLED` lists `bugbot`) → set `bugbot_down = true`, advance to
299
- the [convergence gates](convergence-gates.md) in the same tick with the Bugbot
343
+ `CLAUDE_REVIEWS_ENABLED` lists `bugbot`) → set `bugbot_down = true`, run the
344
+ [Codex review step](#codex-review-step-conditional), advance to the
345
+ [convergence gates](convergence-gates.md) in the same tick with the Bugbot
300
346
  gate bypassed; skip steps a–c below.
301
347
  - Exit 1 (`CLAUDE_REVIEWS_ENABLED` lists `bugbot` and `CLAUDE_REVIEWS_DISABLED`
302
348
  does not) → go to step a.
@@ -344,18 +390,19 @@ c. Decide (four branches; match first whose predicate holds):
344
390
  Bugbot gate next tick.
345
391
  - **`commit_id == current_head` AND zero unaddressed inline AND review
346
392
  body clean:** Set `bugbot_clean_at = current_head`, reset
347
- `inline_lag_streak = 0`, advance to the [convergence
348
- gates](convergence-gates.md) in the same tick.
393
+ `inline_lag_streak = 0`, run the [Codex review step](#codex-review-step-conditional)
394
+ then advance to the [convergence gates](convergence-gates.md) in the same
395
+ tick.
349
396
  - **`commit_id == current_head` with unaddressed inline findings:**
350
397
  Apply the shared fix protocol ([`../../../_shared/pr-loop/fix-protocol.md`](../../../_shared/pr-loop/fix-protocol.md); skill deltas in [`fix-protocol.md`](fix-protocol.md)).
351
398
  Reset `inline_lag_streak = 0` and push-invalidated markers per
352
399
  [ground-rules.md](ground-rules.md) / [state-schema.md](state-schema.md)
353
400
  (all `*_clean_at`, `merge_state_status`, `bugbot_down`,
354
- `bugbot_acknowledged_at`), `phase = CODE_REVIEW`. With `state.json`: the
355
- clean-coder teammate executes the fix, writes `state.json`, goes idle; the
356
- next tick re-enters CODE_REVIEW on the new HEAD. No `state.json`
357
- (single-PR): the lead executes it, stays `phase = CODE_REVIEW`. Schedule
358
- next wakeup, return.
401
+ `bugbot_acknowledged_at`, `codex_down`), `phase = CODE_REVIEW`. With
402
+ `state.json`: the clean-coder teammate executes the fix, writes
403
+ `state.json`, goes idle; the next tick re-enters CODE_REVIEW on the new
404
+ HEAD. No `state.json` (single-PR): the lead executes it, stays
405
+ `phase = CODE_REVIEW`. Schedule next wakeup, return.
359
406
 
360
407
  ### `phase == COPILOT_WAIT`
361
408
 
@@ -386,9 +433,9 @@ b. Decide (three branches; match first whose predicate holds):
386
433
  no inline threads. Reset push-invalidated markers per
387
434
  [ground-rules.md](ground-rules.md) / [state-schema.md](state-schema.md)
388
435
  (all `*_clean_at`, `merge_state_status`, `bugbot_down`,
389
- `bugbot_acknowledged_at`). **Set `phase = CODE_REVIEW`** (NOT COPILOT_WAIT)
390
- — every fix push re-enters the internal passes on the new HEAD. Schedule
391
- next wakeup, return.
436
+ `bugbot_acknowledged_at`, `codex_down`). **Set `phase = CODE_REVIEW`**
437
+ (NOT COPILOT_WAIT) — every fix push re-enters the internal passes on the
438
+ new HEAD. Schedule next wakeup, return.
392
439
  - **No Copilot review at `current_head` yet:** Increment
393
440
  `copilot_wait_count` (init 0 on COPILOT_WAIT entry; reset to 0 on
394
441
  every push and on every successful Copilot review). `>= 3` → hard
@@ -401,6 +448,43 @@ back-to-back-clean guarantee (the internal code-review and bugteam passes both
401
448
  clean on the same HEAD before the terminal gates re-open) only holds when every
402
449
  fix commit re-enters through CODE_REVIEW.
403
450
 
451
+ ## Codex review step (conditional)
452
+
453
+ Run once the terminal Bugbot gate has confirmed HEAD (or set `bugbot_down`) and
454
+ **before** the [convergence gates](convergence-gates.md) machine checklist.
455
+ Uses the `codex-review` skill wrapper against the PR **base** branch (HEAD vs
456
+ base), never an invented commit range.
457
+
458
+ 1. **Opt-out / down gate.**
459
+ `python "$HOME/.claude/_shared/pr-loop/scripts/reviews_disabled.py" --reviewer codex`
460
+ - Exit 0 → set `codex_down = true`, skip the skill, continue to convergence
461
+ gates (export `CLAUDE_REVIEWS_DISABLED` including `codex` before the
462
+ checklist so `check_convergence.py` bypasses without flags).
463
+ - Exit 1 → continue.
464
+
465
+ 2. **Usage probe.**
466
+ `python "$HOME/.claude/skills/codex-review/scripts/codex_usage_probe.py"`
467
+ - When `percent_left` is null or not strictly above the probe threshold
468
+ constant (`WEEKLY_USAGE_GATE_THRESHOLD_PERCENT`): skip Codex; do not set
469
+ `codex_clean_at`; continue to convergence gates (the machine checklist
470
+ skips the condition on the same rule).
471
+ - When above threshold: continue to the skill.
472
+
473
+ 3. **Skill wrapper (HEAD vs base).** Invoke `codex-review` (or read
474
+ `../../codex-review/SKILL.md` when `Skill` is not invokable) so the wrapper
475
+ reviews the diff against the PR base branch at `current_head`.
476
+
477
+ 4. **Classify.**
478
+ - `clean` → set `codex_clean_at = current_head`; write the stamp into
479
+ `$CLAUDE_JOB_DIR/pr-converge-state.json` (and pass `--codex-clean-at` into
480
+ `check_convergence.py` when invoking the checklist).
481
+ - `findings` → apply the shared fix protocol; reset push-invalidated markers
482
+ (all `*_clean_at`, `merge_state_status`, `bugbot_down`,
483
+ `bugbot_acknowledged_at`, `codex_down`); `phase = CODE_REVIEW`; schedule
484
+ next wakeup; return.
485
+ - `down` / `codex_down` → set `codex_down = true`; continue to convergence
486
+ gates without blocking ready.
487
+
404
488
  ## Step 3: Re-trigger bugbot
405
489
 
406
490
  - [ ] **Availability gate.** Enforced at BUGBOT entry (see `### phase == BUGBOT`).
@@ -413,10 +497,14 @@ fix commit re-enters through CODE_REVIEW.
413
497
  (`../../reviewer-gates/SKILL.md` § Gate 3) against `current_head` — the
414
498
  silent-pass pre-check, the already-queued check, the trigger comment, and
415
499
  the acknowledge check, with their rationale. Map its outcomes:
416
- - [ ] Silent pass → set `bugbot_clean_at = current_head`, advance to the [convergence gates](convergence-gates.md) same tick
500
+ - [ ] Silent pass → set `bugbot_clean_at = current_head`, run the
501
+ [Codex review step](#codex-review-step-conditional), advance to the
502
+ [convergence gates](convergence-gates.md) same tick
417
503
  - [ ] Already queued → skip posting, wait for completion, advance to Step 4
418
504
  - [ ] Trigger acknowledged (`bugbot_acknowledged_at` recorded) → advance to Step 4
419
- - [ ] Bugbot down → set `bugbot_down = true`, advance to the [convergence gates](convergence-gates.md) same tick
505
+ - [ ] Bugbot down → set `bugbot_down = true`, run the
506
+ [Codex review step](#codex-review-step-conditional), advance to the
507
+ [convergence gates](convergence-gates.md) same tick
420
508
 
421
509
  ## Step 4: Loop pacing
422
510
 
@@ -33,6 +33,16 @@ live ONLY in the single-PR `$CLAUDE_JOB_DIR/pr-converge-state.json` file
33
33
  Reset to `null` on every push.
34
34
  - `copilot_clean_at`: HEAD SHA where Copilot last reported clean, or `null`.
35
35
  Reset to `null` on every push.
36
+ - `codex_clean_at`: HEAD SHA where the Codex review skill last reported clean,
37
+ or `null`. Reset to `null` on every push. The machine checklist requires this
38
+ stamp to equal `current_head` only when weekly usage is above the probe
39
+ threshold (see [convergence-gates.md](convergence-gates.md)).
40
+ - `codex_down`: boolean, init `false`. Set `true` when the Codex skill
41
+ classifies `codex_down`, when `CLAUDE_REVIEWS_DISABLED` lists `codex`, or when
42
+ the agent passes `--codex-down` into `check_convergence.py`. While `true`,
43
+ the Codex gate never blocks ready. Reset to `false` on every push (same
44
+ push-invalidation rule as `bugbot_down`); the availability / opt-out check
45
+ re-applies on the next Codex entry.
36
46
  - `merge_state_status`: last-observed `mergeable_state` from
37
47
  `pull_request_read(method="get")` (e.g. `clean`, `dirty`, `blocked`,
38
48
  `behind`, `unknown`, `unstable`), or `null` before the first check. Reset
@@ -8,6 +8,7 @@ Python helper scripts for the `pr-converge` skill, plus their tests and a PowerS
8
8
  |---|---|
9
9
  | `check_bugbot_ci.py` | Checks bugbot CI check-run status on a given SHA |
10
10
  | `check_convergence.py` | Evaluates whether all convergence gates pass on the current HEAD |
11
+ | `check_convergence_availability.py` | Resolves reviewer waivers from flag, disk-authoritative settings (env fallback), and the availability/quota probe, with waived / enforced / probe_error_reason states |
11
12
  | `check_convergence_gates.py` | GitHub REST leaf checks (review and Bugbot) the convergence gates call |
12
13
  | `check_convergence_thread_gates.py` | GitHub GraphQL and REST leaf checks (review threads and pending reviewers) the convergence gates call |
13
14
  | `check_pending_reviews.py` | Fetches pending review requests and reviewer states |
@@ -19,6 +20,7 @@ Python helper scripts for the `pr-converge` skill, plus their tests and a PowerS
19
20
  | `conftest.py` | Puts the scripts directory on `sys.path` so pytest collects the suite |
20
21
  | `test_check_bugbot_ci.py` | Tests for `check_bugbot_ci.py` |
21
22
  | `test_check_convergence.py` | Tests for `check_convergence.py` |
23
+ | `test_check_convergence_availability.py` | Tests for `check_convergence_availability.py` |
22
24
  | `test_check_convergence_contract.py` | Contract pins for `check_convergence.py` gate wiring |
23
25
  | `test_check_convergence_gates.py` | Tests for `check_convergence_gates.py` |
24
26
  | `test_check_convergence_thread_gates.py` | Tests for `check_convergence_thread_gates.py` |
@@ -10,10 +10,12 @@ from pathlib import Path
10
10
 
11
11
  _scripts_directory = Path(__file__).resolve().parent
12
12
  _skill_directory = _scripts_directory.parent
13
- _claude_dev_env_directory = _scripts_directory.parent.parent.parent
13
+ _skills_directory = _skill_directory.parent
14
+ _claude_dev_env_directory = _skills_directory.parent
14
15
  _shared_pr_loop_scripts_directory = (
15
16
  _claude_dev_env_directory / "_shared" / "pr-loop" / "scripts"
16
17
  )
18
+ _codex_review_scripts_directory = _skills_directory / "codex-review" / "scripts"
17
19
 
18
20
  if str(_scripts_directory) not in sys.path:
19
21
  sys.path.insert(0, str(_scripts_directory))
@@ -21,3 +23,5 @@ if str(_skill_directory) not in sys.path:
21
23
  sys.path.insert(0, str(_skill_directory))
22
24
  if str(_shared_pr_loop_scripts_directory) not in sys.path:
23
25
  sys.path.insert(0, str(_shared_pr_loop_scripts_directory))
26
+ if str(_codex_review_scripts_directory) not in sys.path:
27
+ sys.path.insert(0, str(_codex_review_scripts_directory))