feat: require proof-backed PR review handoff claims (Closes #395)

Reviewer final reports must not claim proof-sensitive workflow steps
unless each claim carries explicit command/tool evidence or structured
MCP result metadata:

- New reviewer_proof_backed_claims.py verifier covering the five claim
  families from the issue: inventory completeness (explicit pagination
  metadata required; page-size assumptions rejected), earlier-PR skips
  (per-PR command/tool or structured mergeability/blocker evidence),
  baseline validation (worktree path, target SHA, dirty-before, exact
  command, exact result, dirty-after), master integration (exact
  merge/rebase/simulation command), and cleanup (final git worktree
  list proof).
- PROOF_PROVENANCE_CLASSES constant distinguishes command actually run,
  MCP metadata, inherited from previous blocker state, and not checked.
- Re-export from review_proofs and wire into build_final_report as a
  downgrade check with proof_backed_claims_proven/violations fields.
- New workflow section 30A documents the rule; contract test locks the
  marker and an export test locks the re-export.
- 13 tests in tests/test_reviewer_proof_backed_claims.py covering the
  required scenarios: baseline claim without command, skipped-PR claim
  without evidence, inventory-complete from page-size assumption only,
  cleanup without final worktree proof, and a fully proof-backed report
  passing.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
2026-07-07 10:30:32 -04:00
co-authored by Claude Opus 4.8
parent 7db8298cdd
commit e1e76f0420
5 changed files with 376 additions and 0 deletions
+21
View File
@@ -1725,6 +1725,11 @@ def build_final_report(checkout_proof, inventory, validation, contamination,
if report_text
else {"proven": True, "block": False, "reasons": []}
)
proof_backed_claims = (
assess_proof_backed_handoff_report(report_text)
if report_text
else {"proven": True, "block": False, "reasons": []}
)
if baseline_validation is None and report_text:
baseline_validation = assess_reviewer_baseline_validation_proof(
report_text=report_text,
@@ -1906,6 +1911,11 @@ def build_final_report(checkout_proof, inventory, validation, contamination,
"inventory pagination or worktree fields inconsistent (#293)"
)
downgrade_reasons.extend(inventory_worktree.get("reasons", []))
if not proof_backed_claims.get("proven"):
downgrade_reasons.append(
"proof-sensitive handoff claims lack explicit evidence (#395)"
)
downgrade_reasons.extend(proof_backed_claims.get("reasons", []))
if not baseline_validation.get("proven"):
downgrade_reasons.append(
"reviewer baseline validation proof missing or failed (#325)"
@@ -2017,6 +2027,10 @@ def build_final_report(checkout_proof, inventory, validation, contamination,
"inventory_worktree_violations": list(
inventory_worktree.get("reasons") or []
),
"proof_backed_claims_proven": bool(proof_backed_claims.get("proven")),
"proof_backed_claims_violations": list(
proof_backed_claims.get("reasons") or []
),
"baseline_validation_proven": bool(baseline_validation.get("proven")),
"baseline_validation_violations": list(
baseline_validation.get("violations") or []
@@ -5355,6 +5369,13 @@ def assess_inventory_worktree_report(report_text, **kwargs):
return _assess(report_text, **kwargs)
def assess_proof_backed_handoff_report(report_text, **kwargs):
"""#395: proof-sensitive handoff claims require explicit evidence."""
from reviewer_proof_backed_claims import assess_proof_backed_handoff_report as _assess
return _assess(report_text, **kwargs)
def assess_infra_stop_handoff_report(report_text, **kwargs):
"""#289: repair handoff purity when infra_stop blocks reviewer capability."""
from reviewer_infra_stop_handoff import assess_infra_stop_handoff_report as _assess