fix: fixer GC now closes PRs on Forgejo + deletes branches, not just DB
Root cause of 5-day pipeline stall: fixer GC marked PRs as closed in DB but never synced to Forgejo. Branches stayed alive on remote, blocking Gate 2 in batch-extract (branch exists → skip forever). Now: GC fetches PR numbers, posts audit comment, closes on Forgejo, deletes remote branch, THEN updates DB. Same pattern as _terminate_pr in evaluate.py. Pentagon-Agent: Epimetheus <3D35839A-7722-4740-B93D-51157F7D5E70>
This commit is contained in:
parent
0bedc43c94
commit
d33ddd9f3d
1 changed files with 24 additions and 6 deletions
28
lib/fixer.py
28
lib/fixer.py
|
|
@ -225,15 +225,33 @@ async def fix_cycle(conn, max_workers=None) -> tuple[int, int]:
|
||||||
# Garbage collection: close PRs with exhausted fix budget that are stuck in open.
|
# Garbage collection: close PRs with exhausted fix budget that are stuck in open.
|
||||||
# These were evaluated, rejected, fixer couldn't help, nobody closes them.
|
# These were evaluated, rejected, fixer couldn't help, nobody closes them.
|
||||||
# (Epimetheus session 2 — prevents zombie PR accumulation)
|
# (Epimetheus session 2 — prevents zombie PR accumulation)
|
||||||
_gc = conn.execute(
|
# Bug fix: must also close on Forgejo + delete branch, not just DB update.
|
||||||
"""UPDATE prs SET status = 'closed', last_error = 'fix budget exhausted — auto-closed'
|
# DB-only close caused Forgejo/DB state divergence — branches stayed alive,
|
||||||
|
# blocking Gate 2 in batch-extract for 5 days. (Epimetheus session 4)
|
||||||
|
gc_rows = conn.execute(
|
||||||
|
"""SELECT number, branch FROM prs
|
||||||
WHERE status = 'open'
|
WHERE status = 'open'
|
||||||
AND fix_attempts >= ?
|
AND fix_attempts >= ?
|
||||||
AND (domain_verdict = 'request_changes' OR leo_verdict = 'request_changes')""",
|
AND (domain_verdict = 'request_changes' OR leo_verdict = 'request_changes')""",
|
||||||
(config.MAX_FIX_ATTEMPTS + 2,), # GC threshold = mechanical + substantive budget
|
(config.MAX_FIX_ATTEMPTS + 2,),
|
||||||
|
).fetchall()
|
||||||
|
if gc_rows:
|
||||||
|
from .forgejo import api as _gc_forgejo, repo_path as _gc_repo_path
|
||||||
|
for row in gc_rows:
|
||||||
|
pr_num, branch = row["number"], row["branch"]
|
||||||
|
try:
|
||||||
|
await _gc_forgejo("POST", _gc_repo_path(f"issues/{pr_num}/comments"),
|
||||||
|
{"body": "Auto-closed: fix budget exhausted. Source will be re-extracted."})
|
||||||
|
await _gc_forgejo("PATCH", _gc_repo_path(f"pulls/{pr_num}"), {"state": "closed"})
|
||||||
|
if branch:
|
||||||
|
await _gc_forgejo("DELETE", _gc_repo_path(f"branches/{branch}"))
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning("GC: failed to close PR #%d on Forgejo: %s", pr_num, e)
|
||||||
|
conn.execute(
|
||||||
|
"UPDATE prs SET status = 'closed', last_error = 'fix budget exhausted — auto-closed' WHERE number = ?",
|
||||||
|
(pr_num,),
|
||||||
)
|
)
|
||||||
if _gc.rowcount > 0:
|
logger.info("GC: closed %d exhausted PRs (DB + Forgejo + branch cleanup)", len(gc_rows))
|
||||||
logger.info("GC: closed %d exhausted PRs", _gc.rowcount)
|
|
||||||
|
|
||||||
batch_limit = min(max_workers or config.MAX_FIX_PER_CYCLE, config.MAX_FIX_PER_CYCLE)
|
batch_limit = min(max_workers or config.MAX_FIX_PER_CYCLE, config.MAX_FIX_PER_CYCLE)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue