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
@@ -36,7 +36,16 @@ from nisse_core.authority.actions import (
|
||||
)
|
||||
from nisse_core.conversation.transport import InboundMessage, Transport
|
||||
from nisse_core.execution.ssh import HostKeyChanged, HostUnavailable
|
||||
from nisse_core.gitea import GiteaClient, GiteaError, Issue, LineComment, PullRequest
|
||||
from nisse_core.gitea import (
|
||||
SETTLED_MARKER,
|
||||
GiteaClient,
|
||||
GiteaError,
|
||||
Issue,
|
||||
LineComment,
|
||||
PullRequest,
|
||||
ReviewNote,
|
||||
to_resolve,
|
||||
)
|
||||
from nisse_core.knowledge import handlers as knowledge
|
||||
from nisse_core.knowledge.memory import Memory
|
||||
from nisse_core.knowledge.vault import Vault
|
||||
@@ -1058,6 +1067,24 @@ class LoopAgent:
|
||||
|
||||
# -- PR review and merge (D4, D5) -------------------------------------------
|
||||
|
||||
def _resolve_settled(
|
||||
self, item: WorkItem, repo: str, notes: list[ReviewNote]
|
||||
) -> None:
|
||||
"""Resolve the threads a reviewer's reply settled: it can't, being
|
||||
read-only (R3); this agent, the PR's author, can. A refusal leaves
|
||||
the thread open for the operator, and is tried again next round."""
|
||||
for comment_id in to_resolve(notes):
|
||||
try:
|
||||
self._gitea.resolve_comment(repo, comment_id)
|
||||
except GiteaError as exc:
|
||||
self._oplog.emit(
|
||||
"loop.resolve_failed", cause=str(exc)[:300], work_item=item.id
|
||||
)
|
||||
return
|
||||
self._oplog.emit(
|
||||
"loop.resolved", cause="settled", work_item=item.id, comment=comment_id
|
||||
)
|
||||
|
||||
def watch(self) -> None:
|
||||
"""New comments on an item's PR, and its merge or close, reach the
|
||||
item; a waiting item becomes ready to act on them. An operator's are
|
||||
@@ -1075,6 +1102,7 @@ class LoopAgent:
|
||||
except GiteaError as exc:
|
||||
self._oplog.emit("loop.watch_unavailable", cause=str(exc))
|
||||
continue
|
||||
self._resolve_settled(item, repo, notes)
|
||||
log = self._store.transcript(item.id, "operator")
|
||||
new = peers = False
|
||||
for comment in comments:
|
||||
@@ -1109,6 +1137,8 @@ class LoopAgent:
|
||||
loop = replace(loop, notes=(*loop.notes, note.key))
|
||||
if note.author == self._account:
|
||||
continue
|
||||
if SETTLED_MARKER in note.body:
|
||||
continue # it closes its thread: resolved, not answered
|
||||
if note.author not in self._gitea_operators:
|
||||
loop = self._peer_point(
|
||||
item, loop, note.key, note.author, note.where, note.body
|
||||
|
||||
Reference in new issue
Block a user