feat: block issue closure on unproven expected pre-existing failure (#529)
Delivers #529 acceptance criterion 6: controller issue closure must be
blocked when the closure report calls a non-zero test-suite exit an
"expected pre-existing"/baseline failure without pre-merge proof.
- controller_closure_baseline_proof.py: assess_controller_closure_baseline_proof
reuses the #533 pre-merge baseline verifier; empty report -> skipped/allowed,
clean pass -> allowed, proven baseline -> allowed, unproven baseline -> block.
- gitea_close_issue: optional closure_report param; fails closed (no state PATCH)
when the gate blocks.
- final_report_validator: new controller_close task kind (alias close_issue)
wired to the pre-merge baseline proof rule so a closure can be pre-checked.
- Tests: tests/test_controller_closure_baseline_proof.py plus two
gitea_close_issue gate tests.
Scope: criteria 2/3 (non-zero exit not a clean pass; baseline claims need
proof) are already enforced on master via premerge_baseline_proof (#533) and
the reviewer schema rules. Criteria 1/4/5 (post-merge moot canonical wording
and validation:* process-state labels) remain follow-up work.
Validation: full suite 2365 passed, 6 skipped; the 9 remaining failures
(tests/test_config.py TestAuthIntegration, tests/test_credentials.py
TestGetCredentials, test_issue_540 reviewer-role) are baseline-proven —
identical failures on clean prgs/master 6913ac9 (keychain/env dependent),
unrelated to this change.
Refs #529
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
@@ -6070,6 +6070,7 @@ def gitea_close_issue(
|
||||
host: str | None = None,
|
||||
org: str | None = None,
|
||||
repo: str | None = None,
|
||||
closure_report: str | None = None,
|
||||
) -> dict:
|
||||
"""Close an issue by setting its state to 'closed'.
|
||||
|
||||
@@ -6079,6 +6080,9 @@ def gitea_close_issue(
|
||||
host: Override the Gitea host.
|
||||
org: Override the owner/organization.
|
||||
repo: Override the repository name.
|
||||
closure_report: Optional validation/closure summary. When it claims a
|
||||
non-zero test-suite exit is an "expected pre-existing"/baseline
|
||||
failure without pre-merge proof, the close fails closed (#529).
|
||||
|
||||
Returns:
|
||||
dict with 'success' boolean and 'message'.
|
||||
@@ -6088,6 +6092,25 @@ def gitea_close_issue(
|
||||
if blocked:
|
||||
return blocked
|
||||
verify_preflight_purity(remote, task="close_issue")
|
||||
|
||||
# #529: block closure that buries an unproven non-zero suite exit as an
|
||||
# "expected pre-existing failure". Skipped when no closure report is given.
|
||||
from controller_closure_baseline_proof import (
|
||||
assess_controller_closure_baseline_proof,
|
||||
)
|
||||
closure_gate = assess_controller_closure_baseline_proof(closure_report)
|
||||
if closure_gate["block"]:
|
||||
return {
|
||||
"success": False,
|
||||
"blocked": True,
|
||||
"message": (
|
||||
f"Issue #{issue_number} close blocked (#529): closure report "
|
||||
"claims an expected pre-existing/baseline failure without "
|
||||
"pre-merge proof."
|
||||
),
|
||||
"reasons": closure_gate["reasons"],
|
||||
"safe_next_action": closure_gate["safe_next_action"],
|
||||
}
|
||||
h, o, r = _resolve(remote, host, org, repo)
|
||||
auth = _auth(h)
|
||||
url = f"{repo_api_url(h, o, r)}/issues/{issue_number}"
|
||||
|
||||
Reference in New Issue
Block a user