Add the abandon command
CI / checks (push) Skipped
CI / checks (pull_request) Successful in 1m18s
CI / checks (push) Skipped
CI / checks (pull_request) Successful in 1m18s
A4 already names abandon as one of the ways out of a halt (continue, re-plan, or abandon) and 0.2 closes a work item as completed or abandoned, but no command did it: from a gate or a question the only way to drop a task was to edit the state database. - 'abandon' ends the task from any waiting state and returns to IDLE. The move is made durable first; then the plan issue and any open milestone PR are closed with a note (branches kept), and any unresolved intent is aborted so boot reconciliation does not gate on work dropped on purpose. A Gitea failure is reported, not fatal. - Like 'status' it is a command in every state, never read as an answer or feedback. While work runs, 'stop' comes first, as before. - The restart / stranded question and the PR_OPEN hints mention it. - Spec: B1 gains the abandon edge and B2 the command. 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:
1 parent
4e8ebea26a
commit
d68e3b3a83
7 files changed
+307
-7
No files matched your search
@@ -1,4 +1,5 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
@@ -195,3 +196,40 @@ def test_intent_without_a_branch_is_unverifiable() -> None:
|
||||
resolved_at=None,
|
||||
)
|
||||
assert pull_request_reconciler(client(handler), "o/r")(blank) is None
|
||||
|
||||
|
||||
def test_closing_comments_first_then_closes_issue_and_pr() -> None:
|
||||
from nisse_dev.approvals import PlanBoard
|
||||
from nisse_dev.git import GitRepo
|
||||
from nisse_dev.publish import MilestonePublisher
|
||||
|
||||
seen: list[tuple[str, str, dict]] = []
|
||||
|
||||
def handler(request: httpx.Request) -> httpx.Response:
|
||||
body = json.loads(request.content) if request.content else {}
|
||||
seen.append((request.method, request.url.path, body))
|
||||
if request.method == "POST":
|
||||
return httpx.Response(
|
||||
201, json={"id": 5, "user": {"login": "bot"}, "body": body["body"]}
|
||||
)
|
||||
return httpx.Response(201, json={})
|
||||
|
||||
gitea = client(handler)
|
||||
PlanBoard(gitea, "o/r").close(10, "abandoned by don")
|
||||
publisher = MilestonePublisher(
|
||||
None, # type: ignore[arg-type] -- closing touches neither store nor git
|
||||
gitea,
|
||||
"o/r",
|
||||
GitRepo(Path(".")),
|
||||
base_url="https://gitea.test",
|
||||
account="bot",
|
||||
token="tok",
|
||||
)
|
||||
publisher.close_pull_request(20, "abandoned by don")
|
||||
|
||||
assert seen == [
|
||||
("POST", "/api/v1/repos/o/r/issues/10/comments", {"body": "abandoned by don"}),
|
||||
("PATCH", "/api/v1/repos/o/r/issues/10", {"state": "closed"}),
|
||||
("POST", "/api/v1/repos/o/r/issues/20/comments", {"body": "abandoned by don"}),
|
||||
("PATCH", "/api/v1/repos/o/r/pulls/20", {"state": "closed"}),
|
||||
]
|
||||
Reference in new issue
Block a user