Skip to content

trusted direction: only a trusted author's comment, review or inline comment counts, in pr-poll, pr-watch and pr-qa; pr-thread.mjs (#151) - #152

Merged
deanbot merged 5 commits into
mainfrom
151-trusted-direction
Nov 2, 2026
Merged

deanbot merged 5 commits into
mainfrom
151-trusted-direction

Conversation

@deanbot

@deanbot deanbot commented Nov 2, 2026

Copy link
Copy Markdown
Owner

What changed and why

An unprefixed comment, a formal review or an inline comment was taken as the operator's direction from anyone who could comment on the PR. #148 limited role-prefixed comments to trusted authors; this does the same for everything else in a PR thread.

  • lib/block.mjs: trustedItems(agents, items) keeps only a trusted author's items (trusted-authors, else allow-author-associations). It keeps nothing when the block is unreadable. ROLE_PREFIX is gone.
  • pr-poll.mjs, pr-watch.mjs, pr-qa.mjs filter every comment, review and inline comment through it before reading the thread. An outsider's item wakes no waiter, raises no NEW_*, REVIEW_COMMENTS or QA_READY signal, and is not an unanswered inline thread that holds back MERGE_READY.
  • When the block is unreadable, pr-poll sends no NEW_* signal, and the stderr line now says (MERGE_READY and comments withheld). CI_FAILING, MERGE_CONFLICT and MERGED still come through. No cursor is seeded or moved, so the next run that reads the block is a first run and doesn't replay old comments as new. This also fixes verdicts: only a trusted author's role-prefixed comment counts, in pr-poll and pr-watch (#148) #150's first-poll replay, where a blind first poll seeded nothing useful and a later run re-reported old comments. pr-qa prints NONE and keeps its state. A waiter's pass throws, so the failure is logged and retried.
  • One-shot fix in pr-poll and pr-qa: they keep an unreadable block for the rest of the run. Before this, a blind one-shot run whose pass changed state (a new CI_FAILING, say) exited 1, because the baseline pass that follows fetched the block again and threw.
  • New scripts/pr-thread.mjs --repo <owner/repo> --pr <n> prints the trusted thread, oldest first: COMMENT, REVIEW and INLINE blocks with indented bodies, then UNTRUSTED <count> (the count only, with no text and no logins), or EMPTY. It exits 2 with a pr-thread: line when the block can't be read, and then reads no comments at all. It exits 1 on bad arguments without calling gh.
  • Every executor, reviewer and QA text in the Claude Code, generic and Kiro adapters reads the thread through pr-thread.mjs. They never fetch the items it leaves out and act on nothing when it exits 2. gh pr view --comments is gone from every text except the rule that forbids it.
  • SPEC and AGENTS.md describe the rule.

Done, and the checks that show it

All of these are in scripts/test/run.mjs, section "trusted direction (#151)", unless a section is named.

  • pr-poll: an outsider's unprefixed comment, CHANGES_REQUESTED review and inline comment raise no signal, their text is printed nowhere, and MERGE_READY stands. Trusted ones are reported with their id:.
  • No trust list falls back to associations (MEMBER yes, CONTRIBUTOR no). A trusted-authors list overrides the associations.
  • Block unreadable: no NEW_*, CI_FAILING still comes through, exit 0, and none of the three cursors is seeded. The next readable run replays no history. The pr-poll section also covers MERGE_CONFLICT with the block unreadable, and the 404 and over-1 MB cases.
  • Waiters (pr-poll, pr-watch, pr-qa): untrusted activity arriving mid-wait ends in NONE at --max.
  • pr-watch one-shot: an outsider's comment gives NONE, and a trusted one after it gives REVIEW_COMMENTS:7.
  • pr-qa: an outsider's "verified by hand" gives NONE. With the block unreadable, a trusted comment waits (NONE, a pr-qa: stderr line, exit 0), then gives QA_READY:7 once the block is readable.
  • pr-thread: a mixed thread gives the exact expected output, with no outsider text or login and no pending review. Also covered: EMPTY, only-outsiders, trusted-authors, exit 2 on an unreadable block with no comment read, exit 2 on a gh failure, bad arguments, and #7.
  • Texts: every role's text carries the pr-thread rule, and no loop text reads a thread another way.

Mutation-checked, each caught by the tests above:

  • pr-qa without the trust filter;
  • pr-poll seeding the comments, reviews or inline cursor while blind (each separately);
  • pr-thread showing untrusted items;
  • pr-watch back on the prefix-only filter;
  • pr-poll without keeping the failure for the rest of a one-shot run (exit 1).

Calls a reviewer might push back on

  • The signals keep their formats. pr-poll's blocks also carry id:.
  • The model reads only trusted items, through pr-thread.mjs. Putting ids in the signal and having the model filter would still let the model read an outsider's text. This way the adapter contract doesn't change.
  • pr-qa is in scope. An outsider's "verified it by hand" would otherwise count as the operator confirming an acceptance criterion.
  • pr-watch's reviewDecision is left as GitHub computes it. I haven't verified that GitHub counts only write-access reviews there.

Known limits

  • Comments on the issue itself are not filtered. Only the PR thread is.

Restart note

All three roles (executor, reviewer, QA) need a fresh session: the texts and the signal scripts changed. Setup does not need to be re-run (setup-project.sh is unchanged).

Closes #151

@deanbot
deanbot marked this pull request as ready for review November 2, 2026 01:19
# Conflicts:
#	adapters/kiro/skills/start-executor/SKILL.md
@deanbot
deanbot merged commit 4fc1539 into main Nov 2, 2026
4 checks passed
@deanbot
deanbot deleted the 151-trusted-direction branch November 2, 2026 01:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Operator direction: only a trusted author's comment or review counts

1 participant