code-review-forge 2.1.0__tar.gz → 2.4.0__tar.gz

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 (207) hide show
  1. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/PKG-INFO +113 -1
  2. code_review_forge-2.1.0/src/code_review_forge.egg-info/PKG-INFO → code_review_forge-2.4.0/README.md +100 -16
  3. code_review_forge-2.4.0/pyproject.toml +64 -0
  4. code_review_forge-2.4.0/src/code_forge/advisory.py +78 -0
  5. code_review_forge-2.4.0/src/code_forge/backend.py +532 -0
  6. code_review_forge-2.4.0/src/code_forge/cli.py +2154 -0
  7. code_review_forge-2.4.0/src/code_forge/conventions.py +155 -0
  8. code_review_forge-2.4.0/src/code_forge/conventions_resolver.py +808 -0
  9. code_review_forge-2.4.0/src/code_forge/coverage.py +173 -0
  10. code_review_forge-2.4.0/src/code_forge/daemon_state.py +489 -0
  11. code_review_forge-2.4.0/src/code_forge/detect.py +508 -0
  12. code_review_forge-2.4.0/src/code_forge/diff.py +254 -0
  13. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/errors.py +4 -0
  14. code_review_forge-2.4.0/src/code_forge/eval/__init__.py +1 -0
  15. code_review_forge-2.4.0/src/code_forge/eval/corpus.py +79 -0
  16. code_review_forge-2.4.0/src/code_forge/eval/runner.py +464 -0
  17. code_review_forge-2.4.0/src/code_forge/eval/scorer.py +297 -0
  18. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/factories.py +154 -7
  19. code_review_forge-2.4.0/src/code_forge/falsify_real.py +65 -0
  20. code_review_forge-2.4.0/src/code_forge/fixval.py +572 -0
  21. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/gate_check.py +314 -0
  22. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/git.py +110 -3
  23. code_review_forge-2.4.0/src/code_forge/graph_triage.py +566 -0
  24. code_review_forge-2.4.0/src/code_forge/init_template.py +72 -0
  25. code_review_forge-2.4.0/src/code_forge/install_hooks.py +730 -0
  26. code_review_forge-2.4.0/src/code_forge/legacy.py +274 -0
  27. code_review_forge-2.4.0/src/code_forge/llm_invoke.py +675 -0
  28. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/machine.py +447 -26
  29. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/mutation.py +185 -49
  30. code_review_forge-2.4.0/src/code_forge/outlet_c.py +102 -0
  31. code_review_forge-2.4.0/src/code_forge/outlet_resolver.py +232 -0
  32. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/parsers/__init__.py +16 -4
  33. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/parsers/_sarif.py +3 -2
  34. code_review_forge-2.4.0/src/code_forge/parsers/flake8.py +74 -0
  35. code_review_forge-2.4.0/src/code_forge/parsers/pylint.py +108 -0
  36. code_review_forge-2.4.0/src/code_forge/receipt.py +134 -0
  37. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/registry.py +9 -14
  38. code_review_forge-2.4.0/src/code_forge/reviewer_json.py +111 -0
  39. code_review_forge-2.4.0/src/code_forge/rules/forge-taint.yaml +60 -0
  40. code_review_forge-2.4.0/src/code_forge/runtime.py +364 -0
  41. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/sarif.py +18 -1
  42. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/skills/code-forge/SKILL.md +570 -54
  43. code_review_forge-2.4.0/src/code_forge/skills/code-forge/passes/pass1-qodo.md +115 -0
  44. code_review_forge-2.4.0/src/code_forge/skills/code-forge/passes/pass2-expert.md +123 -0
  45. code_review_forge-2.4.0/src/code_forge/skills/code-forge/passes/pass3-adversarial.md +166 -0
  46. code_review_forge-2.4.0/src/code_forge/skills/code-review-expert/references/code-quality-checklist.md +130 -0
  47. code_review_forge-2.4.0/src/code_forge/skills/code-review-expert/references/removal-plan.md +52 -0
  48. code_review_forge-2.4.0/src/code_forge/skills/code-review-expert/references/security-checklist.md +118 -0
  49. code_review_forge-2.4.0/src/code_forge/skills/code-review-expert/references/solid-checklist.md +65 -0
  50. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/skills/smoke-test/SKILL.md +43 -0
  51. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/state.py +27 -1
  52. code_review_forge-2.4.0/src/code_forge/taint.py +283 -0
  53. code_review_forge-2.4.0/src/code_forge/trust.py +178 -0
  54. code_review_forge-2.4.0/src/code_forge/verify.py +381 -0
  55. code_review_forge-2.1.0/README.md → code_review_forge-2.4.0/src/code_review_forge.egg-info/PKG-INFO +128 -0
  56. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_review_forge.egg-info/SOURCES.txt +77 -1
  57. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_review_forge.egg-info/requires.txt +5 -0
  58. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_review_forge.egg-info/top_level.txt +1 -0
  59. code_review_forge-2.4.0/tests/test_advisory.py +238 -0
  60. code_review_forge-2.4.0/tests/test_backend.py +1061 -0
  61. code_review_forge-2.4.0/tests/test_cli_backend_propagation.py +39 -0
  62. code_review_forge-2.4.0/tests/test_cli_detect.py +224 -0
  63. code_review_forge-2.4.0/tests/test_cli_eval.py +326 -0
  64. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_cli_hold_resume.py +5 -0
  65. code_review_forge-2.4.0/tests/test_cli_init.py +60 -0
  66. code_review_forge-2.4.0/tests/test_cli_integration.py +1252 -0
  67. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_cli_lock.py +12 -2
  68. code_review_forge-2.4.0/tests/test_cli_parser.py +400 -0
  69. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_cli_phase1_compat.py +12 -0
  70. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_cli_sarif.py +74 -0
  71. code_review_forge-2.4.0/tests/test_cli_trust.py +283 -0
  72. code_review_forge-2.4.0/tests/test_consecutive_clean.py +175 -0
  73. code_review_forge-2.4.0/tests/test_conventions.py +151 -0
  74. code_review_forge-2.4.0/tests/test_conventions_resolver.py +548 -0
  75. code_review_forge-2.4.0/tests/test_coverage.py +171 -0
  76. code_review_forge-2.4.0/tests/test_daemon_state.py +630 -0
  77. code_review_forge-2.4.0/tests/test_daemon_state_drift.py +52 -0
  78. code_review_forge-2.4.0/tests/test_detect.py +672 -0
  79. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_diff.py +150 -1
  80. code_review_forge-2.4.0/tests/test_eval_corpus.py +177 -0
  81. code_review_forge-2.4.0/tests/test_eval_runner.py +484 -0
  82. code_review_forge-2.4.0/tests/test_eval_scorer.py +227 -0
  83. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_factories.py +96 -7
  84. code_review_forge-2.4.0/tests/test_falsify_real.py +55 -0
  85. code_review_forge-2.4.0/tests/test_fixval.py +734 -0
  86. code_review_forge-2.4.0/tests/test_fixval_integration.py +483 -0
  87. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_gate_check.py +494 -0
  88. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_git.py +140 -1
  89. code_review_forge-2.4.0/tests/test_graph_triage.py +593 -0
  90. code_review_forge-2.4.0/tests/test_hook_carveout.py +245 -0
  91. code_review_forge-2.4.0/tests/test_install_hooks.py +1115 -0
  92. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_integration.py +25 -5
  93. code_review_forge-2.4.0/tests/test_legacy.py +475 -0
  94. code_review_forge-2.4.0/tests/test_legacy_integration.py +275 -0
  95. code_review_forge-2.4.0/tests/test_llm_invoke.py +1080 -0
  96. code_review_forge-2.4.0/tests/test_machine_advisory.py +174 -0
  97. code_review_forge-2.4.0/tests/test_machine_coverage.py +208 -0
  98. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_machine_local.py +156 -2
  99. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_mutation.py +290 -0
  100. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_ordering.py +4 -3
  101. code_review_forge-2.4.0/tests/test_outlet_c.py +526 -0
  102. code_review_forge-2.4.0/tests/test_outlet_resolver.py +666 -0
  103. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_parsers.py +215 -6
  104. code_review_forge-2.4.0/tests/test_r1_e2e.py +158 -0
  105. code_review_forge-2.4.0/tests/test_receipt.py +88 -0
  106. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_registry.py +47 -12
  107. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_round.py +6 -5
  108. code_review_forge-2.4.0/tests/test_runtime.py +715 -0
  109. code_review_forge-2.4.0/tests/test_runtime_drift.py +48 -0
  110. code_review_forge-2.4.0/tests/test_runtime_eval.py +769 -0
  111. code_review_forge-2.4.0/tests/test_runtime_machine.py +343 -0
  112. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_sarif.py +73 -0
  113. code_review_forge-2.4.0/tests/test_smoke_receipt.py +436 -0
  114. code_review_forge-2.4.0/tests/test_taint.py +475 -0
  115. code_review_forge-2.4.0/tests/test_taint_integration.py +202 -0
  116. code_review_forge-2.4.0/tests/test_taint_rule.py +210 -0
  117. code_review_forge-2.4.0/tests/test_trust.py +319 -0
  118. code_review_forge-2.4.0/tests/test_verify.py +305 -0
  119. code_review_forge-2.1.0/pyproject.toml +0 -36
  120. code_review_forge-2.1.0/src/code_forge/cli.py +0 -983
  121. code_review_forge-2.1.0/src/code_forge/diff.py +0 -82
  122. code_review_forge-2.1.0/src/code_forge/install_hooks.py +0 -331
  123. code_review_forge-2.1.0/tests/test_cli_integration.py +0 -184
  124. code_review_forge-2.1.0/tests/test_cli_parser.py +0 -209
  125. code_review_forge-2.1.0/tests/test_install_hooks.py +0 -597
  126. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/LICENSE +0 -0
  127. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/MANIFEST.in +0 -0
  128. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/setup.cfg +0 -0
  129. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/__init__.py +0 -0
  130. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/__main__.py +0 -0
  131. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/autofix.py +0 -0
  132. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/baseline.py +0 -0
  133. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/delta.py +0 -0
  134. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/diagnose.py +0 -0
  135. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/disposition.py +0 -0
  136. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/e2e_check.py +0 -0
  137. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/env_resolver.py +0 -0
  138. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/exit_codes.py +0 -0
  139. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/falsify.py +0 -0
  140. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/hold.py +0 -0
  141. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/lock.py +0 -0
  142. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/mode_resolver.py +0 -0
  143. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/parsers/base.py +0 -0
  144. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/parsers/checkpatch.py +0 -0
  145. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/parsers/clippy.py +0 -0
  146. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/parsers/non_ascii.py +0 -0
  147. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/parsers/ruff.py +0 -0
  148. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/parsers/semgrep.py +0 -0
  149. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/parsers/shellcheck.py +0 -0
  150. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/reporter.py +0 -0
  151. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/runner.py +0 -0
  152. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/skills/adversarial-qe/SKILL.md +0 -0
  153. {code_review_forge-2.1.0/src/code_forge/skills/code-review-expert → code_review_forge-2.4.0/src/code_forge/skills/code-forge}/references/code-quality-checklist.md +0 -0
  154. {code_review_forge-2.1.0/src/code_forge/skills/code-review-expert → code_review_forge-2.4.0/src/code_forge/skills/code-forge}/references/removal-plan.md +0 -0
  155. {code_review_forge-2.1.0/src/code_forge/skills/code-review-expert → code_review_forge-2.4.0/src/code_forge/skills/code-forge}/references/security-checklist.md +0 -0
  156. {code_review_forge-2.1.0/src/code_forge/skills/code-review-expert → code_review_forge-2.4.0/src/code_forge/skills/code-forge}/references/solid-checklist.md +0 -0
  157. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/skills/code-review-expert/SKILL.md +0 -0
  158. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/skills/kernel-fp-verify/SKILL.md +0 -0
  159. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/skills/qodo-review/SKILL.md +0 -0
  160. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/skills/smoke-test/references/boundary-cases.md +0 -0
  161. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/skills/smoke-test/references/concurrency-patterns.md +0 -0
  162. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/skills/smoke-test/references/injection-payloads.md +0 -0
  163. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/skills/smoke-test/test-library/shell/README.md +0 -0
  164. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/skills/smoke-test/test-library/shell/primitives.sh +0 -0
  165. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/skills/smoke-test/test-library/shell/primitives_test.sh +0 -0
  166. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/snapshot.py +0 -0
  167. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/source.py +0 -0
  168. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/verdict.py +0 -0
  169. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_review_forge.egg-info/dependency_links.txt +0 -0
  170. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_review_forge.egg-info/entry_points.txt +0 -0
  171. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_baseline.py +0 -0
  172. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_baseline_integration.py +0 -0
  173. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_cli_e2e_check.py +0 -0
  174. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_cli_install_skill.py +0 -0
  175. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_cli_mutation_check.py +0 -0
  176. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_delta.py +0 -0
  177. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_diagnose.py +0 -0
  178. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_dispo04_lifecycle.py +0 -0
  179. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_dispo05_promotion.py +0 -0
  180. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_dispo06_revert.py +0 -0
  181. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_disposition.py +0 -0
  182. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_e2e_check.py +0 -0
  183. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_env_resolver.py +0 -0
  184. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_escalated_frozen.py +0 -0
  185. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_exit_codes.py +0 -0
  186. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_falsify_stub.py +0 -0
  187. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_fresh_start.py +0 -0
  188. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_hold_entry.py +0 -0
  189. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_hold_ui.py +0 -0
  190. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_lock.py +0 -0
  191. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_lock_signals.py +0 -0
  192. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_machine_ci.py +0 -0
  193. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_machine_e2e.py +0 -0
  194. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_machine_l2.py +0 -0
  195. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_mode_resolver.py +0 -0
  196. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_pass_determinism.py +0 -0
  197. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_phase1_migration.py +0 -0
  198. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_phase3.py +0 -0
  199. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_promotion_tracking.py +0 -0
  200. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_pseudo_refs.py +0 -0
  201. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_runner.py +0 -0
  202. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_snapshot.py +0 -0
  203. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_source_hash.py +0 -0
  204. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_state_04_extensions.py +0 -0
  205. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_state_extensions.py +0 -0
  206. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_state_schema.py +0 -0
  207. {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_verdict.py +0 -0
@@ -1,9 +1,17 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-review-forge
3
- Version: 2.1.0
3
+ Version: 2.4.0
4
4
  Summary: 3-state quality gate for code review
5
5
  Author-email: Minxi Hou <houminxi@gmail.com>
6
6
  License-Expression: Apache-2.0
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Python :: 3.12
9
+ Classifier: Programming Language :: Python :: 3.13
10
+ Classifier: Programming Language :: Python :: 3.14
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Topic :: Software Development :: Quality Assurance
7
15
  Requires-Python: >=3.12
8
16
  Description-Content-Type: text/markdown
9
17
  License-File: LICENSE
@@ -12,6 +20,10 @@ Requires-Dist: unidiff<0.8.0,>=0.7.5
12
20
  Provides-Extra: dev
13
21
  Requires-Dist: pytest>=8.0; extra == "dev"
14
22
  Requires-Dist: mutmut<4.0,>=3.3; extra == "dev"
23
+ Requires-Dist: semgrep<1.100,>=1.0; extra == "dev"
24
+ Provides-Extra: vertex
25
+ Requires-Dist: google-auth>=2.35.0; extra == "vertex"
26
+ Requires-Dist: requests>=2.20.0; extra == "vertex"
15
27
  Dynamic: license-file
16
28
 
17
29
  # code-forge
@@ -76,6 +88,61 @@ code-forge install-skill --skill code-forge # one skill only
76
88
  code-forge install-skill --force # overwrite existing
77
89
  ```
78
90
 
91
+ ## Backend configuration
92
+
93
+ By default, code-forge uses the `claude` CLI in your PATH with the session
94
+ model (no model pin). Three environment variables control the backend:
95
+
96
+ | Variable | Purpose | Default |
97
+ |---|---|---|
98
+ | `FORGE_BACKEND` | Select a named backend from `backends.yaml` | session-default |
99
+ | `FORGE_OUTLET` | Force outlet: `cli` or `inline` | auto-detected |
100
+ | `FORGE_LLM_MODEL` | Override model for CLI backends | `claude-sonnet-4-6` |
101
+
102
+ **Quick examples:**
103
+
104
+ ```bash
105
+ # Use the default (claude CLI, session model)
106
+ code-forge review
107
+
108
+ # Pin a specific model for this run
109
+ FORGE_LLM_MODEL=claude-opus-4-5 code-forge review
110
+
111
+ # Use a named API backend from backends.yaml
112
+ FORGE_BACKEND=claude-api code-forge review
113
+
114
+ # Force inline outlet (no CLI subprocess)
115
+ FORGE_OUTLET=inline code-forge review
116
+ ```
117
+
118
+ **Named backends** (optional) are defined in `~/.config/code-forge/backends.yaml`:
119
+
120
+ ```yaml
121
+ backends:
122
+ - name: claude-api
123
+ type: api
124
+ format: anthropic
125
+ base_url: https://api.anthropic.com
126
+ api_key_env: ANTHROPIC_API_KEY
127
+ default: true
128
+ - name: openai
129
+ type: api
130
+ format: openai
131
+ base_url: https://api.openai.com/v1
132
+ api_key_env: OPENAI_API_KEY
133
+ - name: local-claude
134
+ type: cli
135
+ model: claude-opus-4-5
136
+ command: claude
137
+ ```
138
+
139
+ Full reference: [docs/configuration.md](docs/configuration.md)
140
+
141
+ Editor setup guides:
142
+ - VS Code: [docs/setup-vscode.md](docs/setup-vscode.md)
143
+ - Cursor: [docs/setup-cursor.md](docs/setup-cursor.md)
144
+ - PyCharm: [docs/setup-pycharm.md](docs/setup-pycharm.md)
145
+
79
146
  ## The pipeline
80
147
 
81
148
  ```
@@ -187,6 +254,51 @@ Symlinks each of the 6 skills from `~/.claude/skills/<name>` to this
187
254
  repo's `skills/<name>`. Hook installation is manual -- see
188
255
  `hooks/README.md` and `hooks/settings-snippet.json`.
189
256
 
257
+ ## Enabling the commit gate (R1)
258
+
259
+ `install-skill` and `./install.sh` install the review **skills** only -- they
260
+ do not set up enforcement. The R1 pre-commit gate -- the un-fakeable layer that
261
+ runs the test suite on every commit and blocks on new failures, regardless of
262
+ what the in-editor review claims -- is a separate, manual step:
263
+
264
+ 1. Add a `test:` section to `.code-forge/gate.yaml`. Without it, `gate-check`
265
+ exits with `gate.yaml must have a 'test' section`:
266
+
267
+ ```yaml
268
+ test:
269
+ command: [pytest, -q]
270
+ timeout_seconds: 900
271
+ ```
272
+
273
+ `command[0]` must be a known runner (`python3`, `python`, `pytest`, `cargo`,
274
+ `go`, `make`, `npm`, `npx`, `node`); no shell metacharacters are allowed.
275
+
276
+ 2. Install the hook:
277
+
278
+ ```bash
279
+ code-forge install-hooks
280
+ ```
281
+
282
+ This writes `.git/hooks/pre-commit` that runs `code-forge verify` (a receipt
283
+ tamper check) and then `code-forge gate-check` (the test gate).
284
+
285
+ 3. If `git config core.hooksPath` is set, `install-hooks` refuses to write to a
286
+ custom hooks path and prints a manual fallback. Add these two lines to your
287
+ existing pre-commit hook by hand:
288
+
289
+ ```sh
290
+ code-forge verify --quiet 2>/dev/null || exit 1
291
+ exec code-forge gate-check
292
+ ```
293
+
294
+ The skills give you the review passes; this gate is what makes a green verdict
295
+ mean the tests actually pass. Without it, an in-editor review that never ran can
296
+ still reach a commit. Commits that stage only non-code files (docs, config,
297
+ metadata such as `.md`, `.yaml`, `.toml`, `LICENSE`, `README`) are detected by
298
+ the hook and skip the gate automatically -- no receipts and no `--no-verify`
299
+ needed. Any staged file outside that set, including unknown extensions, re-arms
300
+ the gate for the whole commit.
301
+
190
302
  ## Hooks (reference implementations)
191
303
 
192
304
  | Hook | Trigger | Purpose |
@@ -1,19 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: code-review-forge
3
- Version: 2.1.0
4
- Summary: 3-state quality gate for code review
5
- Author-email: Minxi Hou <houminxi@gmail.com>
6
- License-Expression: Apache-2.0
7
- Requires-Python: >=3.12
8
- Description-Content-Type: text/markdown
9
- License-File: LICENSE
10
- Requires-Dist: pyyaml>=6.0
11
- Requires-Dist: unidiff<0.8.0,>=0.7.5
12
- Provides-Extra: dev
13
- Requires-Dist: pytest>=8.0; extra == "dev"
14
- Requires-Dist: mutmut<4.0,>=3.3; extra == "dev"
15
- Dynamic: license-file
16
-
17
1
  # code-forge
18
2
 
19
3
  [![PyPI version](https://img.shields.io/pypi/v/code-review-forge.svg)](https://pypi.org/project/code-review-forge/)
@@ -76,6 +60,61 @@ code-forge install-skill --skill code-forge # one skill only
76
60
  code-forge install-skill --force # overwrite existing
77
61
  ```
78
62
 
63
+ ## Backend configuration
64
+
65
+ By default, code-forge uses the `claude` CLI in your PATH with the session
66
+ model (no model pin). Three environment variables control the backend:
67
+
68
+ | Variable | Purpose | Default |
69
+ |---|---|---|
70
+ | `FORGE_BACKEND` | Select a named backend from `backends.yaml` | session-default |
71
+ | `FORGE_OUTLET` | Force outlet: `cli` or `inline` | auto-detected |
72
+ | `FORGE_LLM_MODEL` | Override model for CLI backends | `claude-sonnet-4-6` |
73
+
74
+ **Quick examples:**
75
+
76
+ ```bash
77
+ # Use the default (claude CLI, session model)
78
+ code-forge review
79
+
80
+ # Pin a specific model for this run
81
+ FORGE_LLM_MODEL=claude-opus-4-5 code-forge review
82
+
83
+ # Use a named API backend from backends.yaml
84
+ FORGE_BACKEND=claude-api code-forge review
85
+
86
+ # Force inline outlet (no CLI subprocess)
87
+ FORGE_OUTLET=inline code-forge review
88
+ ```
89
+
90
+ **Named backends** (optional) are defined in `~/.config/code-forge/backends.yaml`:
91
+
92
+ ```yaml
93
+ backends:
94
+ - name: claude-api
95
+ type: api
96
+ format: anthropic
97
+ base_url: https://api.anthropic.com
98
+ api_key_env: ANTHROPIC_API_KEY
99
+ default: true
100
+ - name: openai
101
+ type: api
102
+ format: openai
103
+ base_url: https://api.openai.com/v1
104
+ api_key_env: OPENAI_API_KEY
105
+ - name: local-claude
106
+ type: cli
107
+ model: claude-opus-4-5
108
+ command: claude
109
+ ```
110
+
111
+ Full reference: [docs/configuration.md](docs/configuration.md)
112
+
113
+ Editor setup guides:
114
+ - VS Code: [docs/setup-vscode.md](docs/setup-vscode.md)
115
+ - Cursor: [docs/setup-cursor.md](docs/setup-cursor.md)
116
+ - PyCharm: [docs/setup-pycharm.md](docs/setup-pycharm.md)
117
+
79
118
  ## The pipeline
80
119
 
81
120
  ```
@@ -187,6 +226,51 @@ Symlinks each of the 6 skills from `~/.claude/skills/<name>` to this
187
226
  repo's `skills/<name>`. Hook installation is manual -- see
188
227
  `hooks/README.md` and `hooks/settings-snippet.json`.
189
228
 
229
+ ## Enabling the commit gate (R1)
230
+
231
+ `install-skill` and `./install.sh` install the review **skills** only -- they
232
+ do not set up enforcement. The R1 pre-commit gate -- the un-fakeable layer that
233
+ runs the test suite on every commit and blocks on new failures, regardless of
234
+ what the in-editor review claims -- is a separate, manual step:
235
+
236
+ 1. Add a `test:` section to `.code-forge/gate.yaml`. Without it, `gate-check`
237
+ exits with `gate.yaml must have a 'test' section`:
238
+
239
+ ```yaml
240
+ test:
241
+ command: [pytest, -q]
242
+ timeout_seconds: 900
243
+ ```
244
+
245
+ `command[0]` must be a known runner (`python3`, `python`, `pytest`, `cargo`,
246
+ `go`, `make`, `npm`, `npx`, `node`); no shell metacharacters are allowed.
247
+
248
+ 2. Install the hook:
249
+
250
+ ```bash
251
+ code-forge install-hooks
252
+ ```
253
+
254
+ This writes `.git/hooks/pre-commit` that runs `code-forge verify` (a receipt
255
+ tamper check) and then `code-forge gate-check` (the test gate).
256
+
257
+ 3. If `git config core.hooksPath` is set, `install-hooks` refuses to write to a
258
+ custom hooks path and prints a manual fallback. Add these two lines to your
259
+ existing pre-commit hook by hand:
260
+
261
+ ```sh
262
+ code-forge verify --quiet 2>/dev/null || exit 1
263
+ exec code-forge gate-check
264
+ ```
265
+
266
+ The skills give you the review passes; this gate is what makes a green verdict
267
+ mean the tests actually pass. Without it, an in-editor review that never ran can
268
+ still reach a commit. Commits that stage only non-code files (docs, config,
269
+ metadata such as `.md`, `.yaml`, `.toml`, `LICENSE`, `README`) are detected by
270
+ the hook and skip the gate automatically -- no receipts and no `--no-verify`
271
+ needed. Any staged file outside that set, including unknown extensions, re-arms
272
+ the gate for the whole commit.
273
+
190
274
  ## Hooks (reference implementations)
191
275
 
192
276
  | Hook | Trigger | Purpose |
@@ -0,0 +1,64 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Copyright (c) 2026, Minxi Hou <houminxi@gmail.com>
3
+
4
+ [build-system]
5
+ requires = ["setuptools>=68.0"]
6
+ build-backend = "setuptools.build_meta"
7
+
8
+ [project]
9
+ name = "code-review-forge"
10
+ version = "2.4.0"
11
+ description = "3-state quality gate for code review"
12
+ readme = "README.md"
13
+ requires-python = ">=3.12"
14
+ license = "Apache-2.0"
15
+ authors = [
16
+ {name = "Minxi Hou", email = "houminxi@gmail.com"},
17
+ ]
18
+ classifiers = [
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Programming Language :: Python :: 3.13",
22
+ "Programming Language :: Python :: 3.14",
23
+ "Operating System :: OS Independent",
24
+ "Development Status :: 4 - Beta",
25
+ "Intended Audience :: Developers",
26
+ "Topic :: Software Development :: Quality Assurance",
27
+ ]
28
+ dependencies = [
29
+ "pyyaml>=6.0",
30
+ "unidiff>=0.7.5,<0.8.0",
31
+ ]
32
+
33
+ [project.optional-dependencies]
34
+ dev = [
35
+ "pytest>=8.0",
36
+ "mutmut>=3.3,<4.0",
37
+ # semgrep>=1.100 uses io_uring which fails on systems with low RLIMIT_MEMLOCK.
38
+ # Pin to <1.100 until the upstream io_uring memory issue is resolved.
39
+ "semgrep>=1.0,<1.100",
40
+ ]
41
+ vertex = [
42
+ "google-auth>=2.35.0",
43
+ "requests>=2.20.0",
44
+ ]
45
+
46
+ [project.scripts]
47
+ code-forge = "code_forge.cli:main"
48
+
49
+ [tool.setuptools.packages.find]
50
+ where = ["src"]
51
+
52
+ [tool.setuptools.package-data]
53
+ code_forge = ["skills/**/*", "skills/**/.gitkeep", "rules/**/*"]
54
+
55
+ [tool.ruff]
56
+ line-length = 105
57
+
58
+ [tool.pytest.ini_options]
59
+ markers = [
60
+ "real_api: opt-in tests that call real backends (skipped by default)",
61
+ "integration: marks tests requiring real infrastructure",
62
+ ]
63
+ pythonpath = ["src"]
64
+ norecursedirs = ["tests/eval/corpus/base_files"]
@@ -0,0 +1,78 @@
1
+ """Advisory finding type and AxisRunner Protocol.
2
+
3
+ TWO FOUNDING PRINCIPLES:
4
+
5
+ 1. Advisory findings NEVER participate in convergence, NEVER block commits.
6
+ AdvisoryFinding is a structurally separate type from StateFinding -- no
7
+ shared base class, no fingerprint, no disposition, no source field.
8
+ machine.py maintains self.advisories: list[AdvisoryFinding] independently
9
+ of self.findings: list[StateFinding]. The convergence logic in
10
+ _fixpoint_reached() operates ONLY on the StateFinding list.
11
+
12
+ 2. AxisRunner.run() intentionally receives ONLY (diff_text, repo_root): no
13
+ prior findings, no other axes' output, no review state. This is the
14
+ anti-anchoring invariant underpinning D-11's multi-run majority. Each run
15
+ sees the diff fresh, forming independent judgments. Do not widen this
16
+ signature.
17
+ """
18
+ from __future__ import annotations
19
+
20
+ from dataclasses import dataclass
21
+ from pathlib import Path
22
+ from typing import Protocol
23
+
24
+
25
+ @dataclass(frozen=True)
26
+ class AdvisoryFinding:
27
+ """A single advisory finding from a review axis.
28
+
29
+ Advisory findings are informational: they surface risks, concerns, and
30
+ observations but NEVER block the review verdict or reset the cycle
31
+ counter. They are a completely separate type from StateFinding.
32
+
33
+ Fields intentionally excluded (structural incompatibility):
34
+ - fingerprint: advisory findings are not deduplicated against blocking
35
+ - disposition: advisory findings have no CONFIRMED/FIXED/DISMISSED state
36
+ - source: advisory findings are attributed by axis, not by L0/L1/L2 tier
37
+ """
38
+
39
+ id: str
40
+ axis: str
41
+ file: str
42
+ line_range: list[int]
43
+ description: str
44
+ attribution: str
45
+
46
+
47
+ class AxisRunner(Protocol):
48
+ """Protocol for review axes (blocking or advisory).
49
+
50
+ machine.py dispatches to runners implementing this protocol.
51
+ Each axis is a separate module providing its own runner.
52
+
53
+ The run() signature is intentionally narrow: only diff_text and
54
+ repo_root. No prior findings, no review state, no other axes' output.
55
+ This prevents anchoring bias when running majority-vote evaluations
56
+ (D-11).
57
+ """
58
+
59
+ @property
60
+ def is_advisory(self) -> bool:
61
+ """True if this axis produces advisory (non-blocking) findings."""
62
+ ...
63
+
64
+ def run(
65
+ self,
66
+ diff_text: str,
67
+ repo_root: Path,
68
+ ) -> list[AdvisoryFinding]:
69
+ """Run the axis on the given diff and return findings.
70
+
71
+ Args:
72
+ diff_text: unified diff of the changes under review.
73
+ repo_root: path to the repository root.
74
+
75
+ Returns:
76
+ List of findings from this axis.
77
+ """
78
+ ...