Check loop.qnt's properties against the real loop (M2.1, PR D part 1)
CI / checks (push) Skipped

test_loop_properties.py walks the new loop with a seeded mix of operator
and Gitea actions (go-aheads, stale go-aheads, answers, comments, merges,
the comment-then-merge race, closes, abandon, a crash and restart) and an
adaptive scripted model, checking every loop.qnt property after every
step. It found two bugs, both fixed with regression tests: abandoning an
item left its open PR open (the model's fix 1, now in code), and after a
review fix became a follow-up PR, the next fix went to the merged branch.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE
This commit is contained in:
dongarandClaude Opus 5.5 committed 2026-10-03 14:19:19 +00:00
1 parent 21744efac1
commit 266b5dbbd7
5 files changed
+318 -4

No files matched your search

+15 -1
View File
@@ -561,8 +561,13 @@ class LoopAgent:
f"PR #{loop.pr}: {fixed.note}",
)
elif fixed.kind == "new-pr" and fixed.pr is not None:
# Later fixes go to the new PR's branch, never the merged one.
loop = replace(
loop, pr=fixed.pr.number, pr_url=fixed.pr.url, fixes=loop.fixes + 1
loop,
pr=fixed.pr.number,
pr_url=fixed.pr.url,
branch=fixed.branch,
fixes=loop.fixes + 1,
)
self._wait(
item,
@@ -636,6 +641,15 @@ class LoopAgent:
def _close(self, item: WorkItem, loop: Loop, outcome: str, note: str) -> None:
self._fact(item, f"work item {outcome}: {note}")
if loop.pr and outcome == "abandoned":
# L2: abandoning closes the item's open PR with a note.
try:
self._gitea.post_comment(self._repo, loop.pr, f"abandoned: {note}")
self._gitea.close_pull_request(self._repo, loop.pr)
except GiteaError as exc:
self._transport.post(
f"could not close PR #{loop.pr}: {exc}", thread=loop.thread
)
save(self._store, item.id, CLOSED, loop, cause=outcome)
self._store.close_work_item(item.id, outcome=outcome, cause=note)
if loop.issue: