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
30
lib/fixer.py
30
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.
|
||||
# These were evaluated, rejected, fixer couldn't help, nobody closes them.
|
||||
# (Epimetheus session 2 — prevents zombie PR accumulation)
|
||||
_gc = conn.execute(
|
||||
"""UPDATE prs SET status = 'closed', last_error = 'fix budget exhausted — auto-closed'
|
||||
# Bug fix: must also close on Forgejo + delete branch, not just DB update.
|
||||
# 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'
|
||||
AND fix_attempts >= ?
|
||||
AND (domain_verdict = 'request_changes' OR leo_verdict = 'request_changes')""",
|
||||
(config.MAX_FIX_ATTEMPTS + 2,), # GC threshold = mechanical + substantive budget
|
||||
)
|
||||
if _gc.rowcount > 0:
|
||||
logger.info("GC: closed %d exhausted PRs", _gc.rowcount)
|
||||
(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,),
|
||||
)
|
||||
logger.info("GC: closed %d exhausted PRs (DB + Forgejo + branch cleanup)", len(gc_rows))
|
||||
|
||||
batch_limit = min(max_workers or config.MAX_FIX_PER_CYCLE, config.MAX_FIX_PER_CYCLE)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue