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.
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/PKG-INFO +113 -1
- code_review_forge-2.1.0/src/code_review_forge.egg-info/PKG-INFO → code_review_forge-2.4.0/README.md +100 -16
- code_review_forge-2.4.0/pyproject.toml +64 -0
- code_review_forge-2.4.0/src/code_forge/advisory.py +78 -0
- code_review_forge-2.4.0/src/code_forge/backend.py +532 -0
- code_review_forge-2.4.0/src/code_forge/cli.py +2154 -0
- code_review_forge-2.4.0/src/code_forge/conventions.py +155 -0
- code_review_forge-2.4.0/src/code_forge/conventions_resolver.py +808 -0
- code_review_forge-2.4.0/src/code_forge/coverage.py +173 -0
- code_review_forge-2.4.0/src/code_forge/daemon_state.py +489 -0
- code_review_forge-2.4.0/src/code_forge/detect.py +508 -0
- code_review_forge-2.4.0/src/code_forge/diff.py +254 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/errors.py +4 -0
- code_review_forge-2.4.0/src/code_forge/eval/__init__.py +1 -0
- code_review_forge-2.4.0/src/code_forge/eval/corpus.py +79 -0
- code_review_forge-2.4.0/src/code_forge/eval/runner.py +464 -0
- code_review_forge-2.4.0/src/code_forge/eval/scorer.py +297 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/factories.py +154 -7
- code_review_forge-2.4.0/src/code_forge/falsify_real.py +65 -0
- code_review_forge-2.4.0/src/code_forge/fixval.py +572 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/gate_check.py +314 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/git.py +110 -3
- code_review_forge-2.4.0/src/code_forge/graph_triage.py +566 -0
- code_review_forge-2.4.0/src/code_forge/init_template.py +72 -0
- code_review_forge-2.4.0/src/code_forge/install_hooks.py +730 -0
- code_review_forge-2.4.0/src/code_forge/legacy.py +274 -0
- code_review_forge-2.4.0/src/code_forge/llm_invoke.py +675 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/machine.py +447 -26
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/mutation.py +185 -49
- code_review_forge-2.4.0/src/code_forge/outlet_c.py +102 -0
- code_review_forge-2.4.0/src/code_forge/outlet_resolver.py +232 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/parsers/__init__.py +16 -4
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/parsers/_sarif.py +3 -2
- code_review_forge-2.4.0/src/code_forge/parsers/flake8.py +74 -0
- code_review_forge-2.4.0/src/code_forge/parsers/pylint.py +108 -0
- code_review_forge-2.4.0/src/code_forge/receipt.py +134 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/registry.py +9 -14
- code_review_forge-2.4.0/src/code_forge/reviewer_json.py +111 -0
- code_review_forge-2.4.0/src/code_forge/rules/forge-taint.yaml +60 -0
- code_review_forge-2.4.0/src/code_forge/runtime.py +364 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/sarif.py +18 -1
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/skills/code-forge/SKILL.md +570 -54
- code_review_forge-2.4.0/src/code_forge/skills/code-forge/passes/pass1-qodo.md +115 -0
- code_review_forge-2.4.0/src/code_forge/skills/code-forge/passes/pass2-expert.md +123 -0
- code_review_forge-2.4.0/src/code_forge/skills/code-forge/passes/pass3-adversarial.md +166 -0
- code_review_forge-2.4.0/src/code_forge/skills/code-review-expert/references/code-quality-checklist.md +130 -0
- code_review_forge-2.4.0/src/code_forge/skills/code-review-expert/references/removal-plan.md +52 -0
- code_review_forge-2.4.0/src/code_forge/skills/code-review-expert/references/security-checklist.md +118 -0
- code_review_forge-2.4.0/src/code_forge/skills/code-review-expert/references/solid-checklist.md +65 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/skills/smoke-test/SKILL.md +43 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/state.py +27 -1
- code_review_forge-2.4.0/src/code_forge/taint.py +283 -0
- code_review_forge-2.4.0/src/code_forge/trust.py +178 -0
- code_review_forge-2.4.0/src/code_forge/verify.py +381 -0
- code_review_forge-2.1.0/README.md → code_review_forge-2.4.0/src/code_review_forge.egg-info/PKG-INFO +128 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_review_forge.egg-info/SOURCES.txt +77 -1
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_review_forge.egg-info/requires.txt +5 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_review_forge.egg-info/top_level.txt +1 -0
- code_review_forge-2.4.0/tests/test_advisory.py +238 -0
- code_review_forge-2.4.0/tests/test_backend.py +1061 -0
- code_review_forge-2.4.0/tests/test_cli_backend_propagation.py +39 -0
- code_review_forge-2.4.0/tests/test_cli_detect.py +224 -0
- code_review_forge-2.4.0/tests/test_cli_eval.py +326 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_cli_hold_resume.py +5 -0
- code_review_forge-2.4.0/tests/test_cli_init.py +60 -0
- code_review_forge-2.4.0/tests/test_cli_integration.py +1252 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_cli_lock.py +12 -2
- code_review_forge-2.4.0/tests/test_cli_parser.py +400 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_cli_phase1_compat.py +12 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_cli_sarif.py +74 -0
- code_review_forge-2.4.0/tests/test_cli_trust.py +283 -0
- code_review_forge-2.4.0/tests/test_consecutive_clean.py +175 -0
- code_review_forge-2.4.0/tests/test_conventions.py +151 -0
- code_review_forge-2.4.0/tests/test_conventions_resolver.py +548 -0
- code_review_forge-2.4.0/tests/test_coverage.py +171 -0
- code_review_forge-2.4.0/tests/test_daemon_state.py +630 -0
- code_review_forge-2.4.0/tests/test_daemon_state_drift.py +52 -0
- code_review_forge-2.4.0/tests/test_detect.py +672 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_diff.py +150 -1
- code_review_forge-2.4.0/tests/test_eval_corpus.py +177 -0
- code_review_forge-2.4.0/tests/test_eval_runner.py +484 -0
- code_review_forge-2.4.0/tests/test_eval_scorer.py +227 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_factories.py +96 -7
- code_review_forge-2.4.0/tests/test_falsify_real.py +55 -0
- code_review_forge-2.4.0/tests/test_fixval.py +734 -0
- code_review_forge-2.4.0/tests/test_fixval_integration.py +483 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_gate_check.py +494 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_git.py +140 -1
- code_review_forge-2.4.0/tests/test_graph_triage.py +593 -0
- code_review_forge-2.4.0/tests/test_hook_carveout.py +245 -0
- code_review_forge-2.4.0/tests/test_install_hooks.py +1115 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_integration.py +25 -5
- code_review_forge-2.4.0/tests/test_legacy.py +475 -0
- code_review_forge-2.4.0/tests/test_legacy_integration.py +275 -0
- code_review_forge-2.4.0/tests/test_llm_invoke.py +1080 -0
- code_review_forge-2.4.0/tests/test_machine_advisory.py +174 -0
- code_review_forge-2.4.0/tests/test_machine_coverage.py +208 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_machine_local.py +156 -2
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_mutation.py +290 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_ordering.py +4 -3
- code_review_forge-2.4.0/tests/test_outlet_c.py +526 -0
- code_review_forge-2.4.0/tests/test_outlet_resolver.py +666 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_parsers.py +215 -6
- code_review_forge-2.4.0/tests/test_r1_e2e.py +158 -0
- code_review_forge-2.4.0/tests/test_receipt.py +88 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_registry.py +47 -12
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_round.py +6 -5
- code_review_forge-2.4.0/tests/test_runtime.py +715 -0
- code_review_forge-2.4.0/tests/test_runtime_drift.py +48 -0
- code_review_forge-2.4.0/tests/test_runtime_eval.py +769 -0
- code_review_forge-2.4.0/tests/test_runtime_machine.py +343 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_sarif.py +73 -0
- code_review_forge-2.4.0/tests/test_smoke_receipt.py +436 -0
- code_review_forge-2.4.0/tests/test_taint.py +475 -0
- code_review_forge-2.4.0/tests/test_taint_integration.py +202 -0
- code_review_forge-2.4.0/tests/test_taint_rule.py +210 -0
- code_review_forge-2.4.0/tests/test_trust.py +319 -0
- code_review_forge-2.4.0/tests/test_verify.py +305 -0
- code_review_forge-2.1.0/pyproject.toml +0 -36
- code_review_forge-2.1.0/src/code_forge/cli.py +0 -983
- code_review_forge-2.1.0/src/code_forge/diff.py +0 -82
- code_review_forge-2.1.0/src/code_forge/install_hooks.py +0 -331
- code_review_forge-2.1.0/tests/test_cli_integration.py +0 -184
- code_review_forge-2.1.0/tests/test_cli_parser.py +0 -209
- code_review_forge-2.1.0/tests/test_install_hooks.py +0 -597
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/LICENSE +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/MANIFEST.in +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/setup.cfg +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/__init__.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/__main__.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/autofix.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/baseline.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/delta.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/diagnose.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/disposition.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/e2e_check.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/env_resolver.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/exit_codes.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/falsify.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/hold.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/lock.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/mode_resolver.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/parsers/base.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/parsers/checkpatch.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/parsers/clippy.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/parsers/non_ascii.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/parsers/ruff.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/parsers/semgrep.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/parsers/shellcheck.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/reporter.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/runner.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/skills/adversarial-qe/SKILL.md +0 -0
- {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
- {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
- {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
- {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
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/skills/code-review-expert/SKILL.md +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/skills/kernel-fp-verify/SKILL.md +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/skills/qodo-review/SKILL.md +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/skills/smoke-test/references/boundary-cases.md +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/skills/smoke-test/references/concurrency-patterns.md +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/skills/smoke-test/references/injection-payloads.md +0 -0
- {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
- {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
- {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
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/snapshot.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/source.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_forge/verdict.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_review_forge.egg-info/dependency_links.txt +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/src/code_review_forge.egg-info/entry_points.txt +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_baseline.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_baseline_integration.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_cli_e2e_check.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_cli_install_skill.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_cli_mutation_check.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_delta.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_diagnose.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_dispo04_lifecycle.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_dispo05_promotion.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_dispo06_revert.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_disposition.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_e2e_check.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_env_resolver.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_escalated_frozen.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_exit_codes.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_falsify_stub.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_fresh_start.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_hold_entry.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_hold_ui.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_lock.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_lock_signals.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_machine_ci.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_machine_e2e.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_machine_l2.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_mode_resolver.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_pass_determinism.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_phase1_migration.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_phase3.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_promotion_tracking.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_pseudo_refs.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_runner.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_snapshot.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_source_hash.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_state_04_extensions.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_state_extensions.py +0 -0
- {code_review_forge-2.1.0 → code_review_forge-2.4.0}/tests/test_state_schema.py +0 -0
- {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.
|
|
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 |
|
code_review_forge-2.1.0/src/code_review_forge.egg-info/PKG-INFO → code_review_forge-2.4.0/README.md
RENAMED
|
@@ -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
|
[](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
|
+
...
|