feat: enforce reconciler PR-close proof fields in final reports (Closes #306)

Closes #306.

The dedicated reconciler close path (profile, gated close tool, ancestor
proof, tests) already shipped across #301/#304/#309/#310, but the
final-report validator did not require a reconciler close to prove itself.
A handoff could report `PRs closed: #N` while omitting the close
capability, ancestor proof, or linked-issue result and still grade A.

This adds the missing report-time enforcement.

Changes:
- final_report_validator.py — new `reconcile.close_proof_fields` rule
  (`_rule_reconcile_close_proof`). Fires only when a PR close is reported
  (via the `PRs closed` field or a `reconciler_close_lock`), then blocks
  unless the handoff carries close capability proof (gitea.pr.close),
  ancestor proof, PR close result, and linked-issue result. Comment-only
  and blocked reconciliations are unaffected. New optional
  `reconciler_close_lock` kwarg on `assess_final_report_validator`.
- tests/test_final_report_validator.py — TestReconcilerCloseProof (6 cases):
  full-proof close passes; missing capability / ancestor / linked-issue
  result each block; session close lock requires proof; comment-only
  needs no close proof.
- reconcile-landed-pr.md — §18A documents the enforced gate.

Validation:

  venv/bin/python -m pytest tests/test_final_report_validator.py \
    tests/test_reconciler_close_gate.py tests/test_already_landed_reconcile.py \
    tests/test_reconcile_already_landed_pr_tool.py \
    tests/test_reconciliation_workflow.py tests/test_review_proofs.py -q

289 passed.

Worktree: branches/issue-306-reconciler-close-proof

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
2026-07-07 13:03:23 -04:00
co-authored by Claude Opus 4.8
parent 1a1e679246
commit b9e5cd0f57
3 changed files with 159 additions and 0 deletions
@@ -341,6 +341,24 @@ Include:
* confirmation that no normal review, approval, request-changes, or merge was
performed
## 18A. Reconciler close proof is enforced (#306)
When a reconciler run closes a PR, the final-report validator
(`final_report_validator` rule `reconcile.close_proof_fields`) **blocks** the
handoff unless it carries all four close proofs. The prompt is guidance; the
MCP validator is the authority.
A close is detected from `PRs closed: #<n>` (or a session close lock). Once a
close is reported, the handoff must include:
* `Capabilities proven:` naming `gitea.pr.close` — the exact close capability
* `Ancestor proof:` — the landed/ancestor proof for the closed PR
* `PRs closed:` — the PR close result (the closed PR number)
* `Linked issue live status:` (or `Issues closed:`) — the linked-issue result
Comment-only and blocked reconciliations (no PR close) are unaffected: the rule
returns no finding when nothing was closed.
## 19. Local artifact and report consistency rule
Do not create local walkthrough, notes, markdown, JSON, or report artifacts