nisse-review marks a reply that settles its thread; the PR's author resolves it
The reviewer is read-only (R3), so Gitea refuses it resolving a thread. Now each reply says whether it settles its thread, and a settled reply carries <!-- nisse-review: settled -->. nisse-dev, as the author, resolves every comment on that thread's line when it watches the PR, and doesn't take the settled reply as a point to answer. scripts/resolve_settled.py does the same for PRs made by hand. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk
This commit is contained in:
1 parent
6b85e5a039
commit
33d030590d
11 files changed
+384
-12
No files matched your search
@@ -78,6 +78,8 @@ class Forge:
|
||||
self.approved: dict[int, list[Approval]] = {}
|
||||
self.status: dict[str, str] = {} # commit -> combined check state
|
||||
self.agent_merged: list[int] = []
|
||||
self.resolved: list[int] = [] # line comments the agent resolved
|
||||
self.refuse_resolve = False
|
||||
|
||||
# intake
|
||||
def assigned_issues(self, repo: str, assignee: str) -> list[Issue]:
|
||||
@@ -171,6 +173,11 @@ class Forge:
|
||||
def post_comment(self, repo: str, index: int, body: str) -> None:
|
||||
self.posted.append((index, body))
|
||||
|
||||
def resolve_comment(self, repo: str, comment_id: int) -> None:
|
||||
if self.refuse_resolve:
|
||||
raise GiteaError("gitea POST resolve returned 403")
|
||||
self.resolved.append(comment_id)
|
||||
|
||||
def post_review(self, repo: str, index: int, *, body, commit, comments=()) -> int:
|
||||
if self.refuse_inline:
|
||||
raise GiteaError("gitea POST reviews returned 422: line not in diff")
|
||||
|
||||
@@ -18,7 +18,7 @@ from test_loop_milestones import item as the_item
|
||||
from test_loop_milestones import world as world # noqa: PLC0414 -- the fixture
|
||||
from test_loop_trust import agent_for
|
||||
|
||||
from nisse_core.gitea import Comment, LineComment, ReviewNote
|
||||
from nisse_core.gitea import SETTLED_MARKER, Comment, LineComment, ReviewNote
|
||||
from nisse_core.log.canonical import Fact
|
||||
from nisse_dev.loop.items import MERGE, READY, WAITING, loop_of
|
||||
|
||||
@@ -244,3 +244,52 @@ def test_a_peer_neither_merges_nor_instructs(world: dict[str, Any]) -> None:
|
||||
]
|
||||
assert not any("merge it" in getattr(e.event, "text", "") for e in operator)
|
||||
assert loop_of(the_item(world)).wait == MERGE
|
||||
|
||||
|
||||
# --- settled threads ------------------------------------------------------------
|
||||
|
||||
|
||||
def settled_thread(forge: Forge, pr: int) -> None:
|
||||
"""A point on a line, nisse-dev's answer, and the reviewer conceding."""
|
||||
forge.notes[pr] = [
|
||||
ReviewNote("line-11", REVIEWER, "Split on any whitespace?", "text.py:3"),
|
||||
ReviewNote("line-12", "nisse-dev", "split() already does.", "text.py:3"),
|
||||
ReviewNote("line-13", REVIEWER, f"Conceded.\n\n{SETTLED_MARKER}", "text.py:3"),
|
||||
]
|
||||
|
||||
|
||||
def test_a_settled_thread_is_resolved_not_answered(world: dict[str, Any]) -> None:
|
||||
forge: Forge = world["forge"]
|
||||
agent, _, pr = published(world)
|
||||
settled_thread(forge, pr)
|
||||
forge.notes[pr].append(ReviewNote("line-14", REVIEWER, "Still: a test?", "a.py:1"))
|
||||
agent.watch()
|
||||
assert forge.resolved == [11, 12, 13]
|
||||
keys = [p[1] for p in loop_of(the_item(world)).points]
|
||||
assert "line-13" not in keys and "line-14" in keys # the concession needs no answer
|
||||
|
||||
|
||||
def test_a_resolved_thread_is_not_resolved_again(world: dict[str, Any]) -> None:
|
||||
forge: Forge = world["forge"]
|
||||
agent, _, pr = published(world)
|
||||
settled_thread(forge, pr)
|
||||
forge.notes[pr] = [
|
||||
ReviewNote(n.key, n.author, n.body, n.where, resolved=True)
|
||||
for n in forge.notes[pr]
|
||||
]
|
||||
agent.watch()
|
||||
assert forge.resolved == []
|
||||
|
||||
|
||||
def test_a_refused_resolve_leaves_the_thread_and_is_tried_again(
|
||||
world: dict[str, Any],
|
||||
) -> None:
|
||||
forge: Forge = world["forge"]
|
||||
agent, _, pr = published(world)
|
||||
settled_thread(forge, pr)
|
||||
forge.refuse_resolve = True
|
||||
agent.watch()
|
||||
assert forge.resolved == []
|
||||
forge.refuse_resolve = False
|
||||
agent.watch()
|
||||
assert forge.resolved == [11, 12, 13]
|
||||
Reference in new issue
Block a user