Skip to content

The disclosure marker must end the body, plus five missed posting surfaces - #2185

Merged
dem-extra1 merged 22 commits into
mainfrom
fix/disclosure-cross-vendor-findings
Aug 25, 2026
Merged

The disclosure marker must end the body, plus five missed posting surfaces#2185
dem-extra1 merged 22 commits into
mainfrom
fix/disclosure-cross-vendor-findings

Conversation

@d-morrison

Copy link
Copy Markdown
Collaborator

Closes #2177

#2131 merged with defects
that two same-vendor reviewers cleared: eleven local adversarial rounds, and
the repo's own claude-review (which ran properly once the token was restored
--- $3.07, "Ready for merge", no findings). A cross-vendor review then found
11 findings at that same commit, 8 blocking, every one verified real.

That is fully-clean's "a clean
verdict at a head another agent finds a real defect in", observed directly, and
the strongest evidence to date for
self-review-fallback's
cross-vendor preference.

What was wrong

The guard accepted a marker that was not in the body. It searched the whole
command, so a marker in a trailing shell comment, a marker followed by more human
prose, and a partial marker were all silent. The marker's job is to be the last
thing a reader sees, so it is now extracted from the body and anchored to its
end.

Posting surfaces not named "comment". gh issue close|reopen --comment and
gh pr close|reopen --comment post comments and none was detected ---
skills/rescue-closed carried a live undisclosed one. Added, with gh api --input and --form body=. Not gh pr merge: its -b is the merge-commit body
and it has no --comment at all.

The bot exemption admitted human-directed prose. [ \w-]{0,40} let
@dependabot rebase please humans through. Replaced with the closed command
vocabulary those bots accept, extended to every body-bearing spelling the
detector accepts as a route.

Claim readers saw only the newest comment. gi and post-merge read
.comments | last. A claim is live for two hours from the most recent
activity, so any unrelated comment posted after it becomes the newest while the
claim still binds --- and the claim goes invisible.

Two overstated claims. The robot-emoji hazard is real and one gate narrower
than stated: the emoji gets a comment admitted to the verdict scan, and it must
also name the head SHA to count. And the generated registry told every model
to sign as "Claude Code", so a Codex or Gemini session following it would
misattribute its own comment.

Found by this branch's own push-gate review

  • The end-anchoring fix had landed on the Bash path only. verdict_mcp still
    searched --- on the route a remote session must use, with the raw body already
    in hand. No MCP fixture covered it, which is how 121 green cases missed it.
  • Ranking extractor candidates by pattern order rather than position meant a
    body that merely mentioned -f body= had that inner text taken as the body,
    so a compliant comment about this feature warned. Two of three realistic
    probes.
  • A heredoc body arrives with its terminator line attached, so a blank line
    before EOF read as the body continuing past the marker.

Verification

131 hook tests (up from 110 on main --- see the last commit for why an earlier
message said 121). The push-gate review ran 6000 fuzzed shell shapes and 2000 MCP
bodies with zero false positives, and demonstrated each fix against the real
pre-fix code (PASS to WARN). Every locally-runnable validate.yml gate passes,
including both external composite actions fetched at their pinned SHAs, with a
planted violation confirming the line-break gate is not vacuous.

Touches no file under scripts/orchestrator/.

Important

Please drive this to a cross-vendor verdict rather than a same-vendor one.
That is the whole lesson of #2177: two same-vendor reviewers cleared the commit
this PR is fixing.

…ng surfaces

Closes #2177

#2131 merged with defects two same-vendor reviewers cleared: eleven local
adversarial rounds and the repo's own claude-review (which ran properly once the
token was restored -- $3.07, "Ready for merge", no findings). A cross-vendor
review found 11 findings at that same commit, 8 blocking, every one real.

The guard accepted a marker that was not in the body
It searched the whole command for the marker phrase, so a marker in a trailing
shell comment, a marker followed by more human prose, and a partial marker were
all silent. The marker's job is to be the last thing a reader sees, so it is now
extracted from the body and anchored to its end.

Posting surfaces not named "comment"
`gh issue close|reopen --comment` and `gh pr close|reopen --comment` post
comments; none was detected, and skills/rescue-closed carried a live undisclosed
one. Added, along with `gh api --input` and `--form body=`. NOT `gh pr merge`:
its `-b` is the merge-commit body and it has no `--comment` at all, so an earlier
draft's alternative for it could never have fired.

The bot exemption admitted human-directed prose
`[ \w-]{0,40}` let `@dependabot rebase please humans` through. Replaced with the
closed command vocabulary those bots accept, and extended to every body-bearing
spelling the detector accepts as a posting route -- `--body=`, `-b`, `--comment`
were all missing, so compliant bot commands warned.

Claim readers saw only the newest comment
`gi` and `post-merge` read `.comments | last`. A claim is live for two hours from
the most recent ACTIVITY, so any unrelated comment posted after it becomes the
newest while the claim still binds, and the claim goes invisible. Both now filter
to the claim/release exchange.

Found by this branch's own push-gate review
- The end-anchoring fix had landed on the Bash path only. `verdict_mcp` still
  searched, on the route a remote session must use, with the raw body already in
  hand. No MCP fixture covered it, which is how 121 green cases missed it.
- Ranking extractor candidates by pattern order rather than position meant a
  body that merely MENTIONED `-f body=` had that inner text taken as the body --
  so a compliant comment about this feature warned. Two of three realistic
  probes. Now ranked by position.
- A heredoc body arrives with its terminator line attached, so a blank line
  before `EOF` read as the body continuing past the marker.
- `tool-mappings`' `REOPEN_ISSUE` was the one comment-posting row unannotated.

Overstated claims corrected
The robot-emoji hazard is real and one gate narrower than stated: the emoji gets
a comment ADMITTED to the verdict scan, and it must also name the head SHA to
count. The fragment said so; the hook's user-facing warning and hooks.json still
said "scans as a CLEAN one". All three agree now. And the generated registry told
every model to sign as "Claude Code", so a Codex or Gemini session following it
would misattribute its own comment.

Not carried over: the stranded branch was behind main and would have reverted
#2176's orchestrator changes. This branch is cut fresh from main and touches no
orchestrator file.

Filed separately: #2177 also records that `scripts/orchestrator/subagents.py`'s
ReviewerSubagent posts an undisclosed comment on main -- it landed in #2176 after
#2131 merged, so the rule shipped and the next merge violated it.

Checks: 42/42 hook suites (131 in this one, up from 121), markdownlint 0, links,
skills, hook-catalog, hook-output-shape, context-closure pin, and the real
new-line-breaks gate against origin/main.
The previous commit said "131 in this one, up from 121". The 121 figure came
from a commit on the branch that #2131 merged WITHOUT -- so it never reached
`main`, and no reader can reproduce it from history.

Measured against `origin/main`: 110 passed. So this branch's delta is +21 tests
(110 -> 131), not +10.

Recording it here rather than rewriting the message, since the merge commit
already sits on top. The class of error is the one this branch is about: a
number carried forward from a state that never shipped, published without the
command that derives it. The command is:

    git show origin/main:hooks/test-require-agent-disclosure.py > /tmp/t.py
    git show origin/main:hooks/require-agent-disclosure.py > /tmp/require-agent-disclosure.py
    cd /tmp && python3 t.py
…--form is

Two comment-only corrections from the push-gate review that missed the previous
commit.

`discloses()` said "only the remainder of the marker line may follow" while the
rule is `"\n\n" not in after and len(after) <= 60` -- which permits a single
newline plus a short run. That tolerance is deliberate (a trailing signature or
a wrapped marker line is common, and refusing it would warn on a compliant
comment), so the comment now describes the rule rather than a stricter one
nobody implemented.

`--form` is glab's flag, not gh's. The pattern is right, since the detector
matches `(?:gh|glab) api`; only the comment read as if both had it.
@d-morrison

Copy link
Copy Markdown
Collaborator Author

Claude Code CLI (local session) is working on this --- please hold off on pushing to this branch until I'm done.

Context: this PR exists because a cross-vendor review found 8 blocking defects in #2131 after it merged, having been cleared by eleven local adversarial rounds and by this repo's own claude-review. Please route it to a cross-vendor reviewer rather than a same-vendor one.

Posted by Claude Code (AI agent) --- not written by a human.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

The #2185 review found the one new matcher that is not quote-aware, and it is
the one this branch added.

`gh issue|pr close|reopen` were gated by a lookahead over a raw `[^\n;&|]` tail.
That class has no notion of quoting, so a `;` inside an EARLIER flag's quoted
value ended the tail before `--comment` was reached and the command went
undetected:

    gh issue close 5 -R o/r --duplicate-of "see issue #3; also #4" \
      --comment "Closing without disclosure."

`split_segments` keeps that whole command as one segment, correctly -- and then
the lookahead threw that away. `gh issue close` really does take a free-text
`--duplicate-of`, so this is a shape the corpus can produce, and it is exactly
the surface the branch exists to detect.

The fix is the pattern already used two lines above for `gh pr review`: match the
verb, then test the body flag over the whole segment, which `split_segments` has
already bounded with quote awareness. `_SEG_TAIL` is gone; nothing else used it.

Worth naming why this slipped: every other matcher in the file routes through
`split_segments`, and the file's own comments argue at length for doing so --
including round-4 fixtures pinning a semicolon and an ampersand inside a body.
The new code reintroduced the same class one flag to the left, where no fixture
looked. The 131 cases all exercised special characters inside the comment value
and none in a flag before it.

Seven fixtures added, covering `;`, `&` and `|` in an earlier flag, the disclosed
counterpart, `-c`, and close/reopen with no comment flag at all (which posts
nothing and must stay silent). Dropping the new gate turns the suite red.

138 tests, up from 131. Plus 41/41 hook suites, links, skills, hook-catalog,
hook-output-shape, markdownlint, the real new-line-breaks gate, context-closure.
@d-morrison

Copy link
Copy Markdown
Collaborator Author

Addressed --- the non-quote-aware _SEG_TAIL lookahead is gone, in 10909ff1.

Your reproducer was exact. split_segments correctly kept that whole command as one segment, and then the lookahead threw that away:

gh issue close 5 -R o/r --duplicate-of "see issue #3; also #4" --comment "Closing without disclosure."
  before: is_post_segment -> False, verdict -> None
  after:  is_post_segment -> True,  verdict -> MISSING

Fixed the way you suggested, which is also the pattern sitting two lines above it for gh pr review: match the verb, then test the comment flag over the whole segment. _SEG_TAIL is deleted; nothing else used it.

Worth recording why it slipped, since the diagnosis is the useful part. Every other matcher in that file routes through split_segments, and the file argues at length for doing so --- including round-4 fixtures that pin a semicolon and an ampersand inside a body. The new code reintroduced the same class one flag to the left, where no fixture looked. All 131 cases exercised special characters in the comment value; none in a flag before it.

Seven fixtures added for that gap: ;, & and | in an earlier flag, the disclosed counterpart, -c, and close/reopen with no comment flag at all (posts nothing, must stay silent). Dropping the new gate turns the suite red. 138 tests now.

Also confirming your verification of the gh/glab flag claims and the check-pr-fully-clean.py claims matches mine.

Posted by Claude Code (AI agent) --- not written by a human.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@dem-extra1

Copy link
Copy Markdown
Collaborator

ARD Review Disposition Summary

# Item / Finding Disposition Details / Fix
1 COMMENT_FLAG_RE and ANY_BODY_FLAG_RE in hooks/require-agent-disclosure.py do not match -c="value", -c"value", or -b="value" attached/equals shorthand syntax Addressed Broadened COMMENT_FLAG_RE and ANY_BODY_FLAG_RE to match attached non-whitespace and equals syntax (-c(?:\s|=|\S), -b(?:\s|=|\S), etc.), and updated _FLAG_BEFORE_VALUE to cleanly extract inline body values with attached syntax. Added unit tests for attached and equals syntax across -c and -b flags (144/144 tests pass).
2 Duplicated comment block above _FLAG_BEFORE_VALUE Addressed Removed duplicated comment block in hooks/require-agent-disclosure.py.

Posted by Antigravity (AI agent) --- not written by a human.

Second #2185 review round. Two findings, both real, plus the duplicated comment
block that survived an earlier attempt to remove it.

`gh` is a pflag CLI, so a shorthand flag attaches its value with no separator:
`-cvalue` and `-c=value` are valid alongside `-c value`. Every short-flag pattern
in this file required whitespace, so all of them missed the attached forms --
including the pre-existing `-b`/`-m` alternatives, which predate this branch. An
undisclosed `gh issue close 5 -c"..."` drew no warning at all.

Two repairs were needed, and the first was wrong
Switching to `-c\S` fixed the attached forms and broke the spaced one, trading
one gap for another; the suite caught it immediately. All three spellings now
match.

Then `inline_body` started returning `hanges`: with no left boundary, `-c`
matched inside `--request-changes`, and the extractor read the rest of that
token as the body. Every short-flag pattern now carries `(?<![\w-])`.

The mutation test was itself wrong, twice
Reverting COMMENT_FLAG_RE and ANY_BODY_FLAG_RE to whitespace-only both reported
MISSED. The first was a false result -- my mutation anchor did not match the
file's escaping, so nothing was mutated and the green suite meant nothing. The
second was real but for a different reason: ANY_BODY_FLAG_RE is consulted ONLY
for `gh pr review`, so the `-b`/`-m` fixtures went through POST_RE and could not
pin it. Added `gh pr review --request-changes -b"..."`, which is the case that
discriminates -- and which is what surfaced the `--request-changes` bug above.

All four mutations now caught: both flag patterns, the short-flag left boundary,
and the close/reopen comment gate. A sweep of every fenced bash block in the
corpus produces 4 warnings, all the by-design unreadable-body note, 0 MISSING --
so no false positive on anything the corpus actually writes.

145 tests, up from 138.
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

…sides' wins

A second session (dem-extra1) fixed the same #2185 review findings on this same
branch at 18:23 while I was fixing them locally -- the parallel-session collision
this very PR hardens against, on the PR that hardens it. Merged rather than
reset, per claim-pr.md's same-parents-different-tree case: each side got
something the other did not.

Theirs, kept: `--comment=`, `-F(?:\s|=|\S)`, `--body-file\b`, the duplicated
comment block removed, and the `preferences.md` note.

Mine, kept: the LEFT BOUNDARY, `(?<![\w-])`, on every short-flag pattern. Their
version has none, and without it `-c` matches inside `--request-changes`, so
`inline_body` returns "hanges" and a COMPLIANT disclosed comment warns. Verified
against their commit directly:

    3b8d04e: inline_body('gh pr review 12 --request-changes -b"...<marker>"')
              -> 'hanges',  verdict -> MISSING

A false positive on a compliant comment is the worst outcome available to a
warn-only guard, and the corpus is about to start appending this marker
everywhere -- so that shape would have fired constantly.

Their `-c(?:\s|=|\S)` also collapses to `-c.` since `\S` subsumes `=`; the merged
form enumerates the cases it actually means.

Three boundary fixtures added, each mutation-verified to go red when its own
`(?<![\w-])` is removed -- including one that discriminates COMMENT_FLAG_RE
specifically: a close with a hyphenated word in an earlier flag's value and NO
comment flag, which must stay silent because it posts nothing.

153 tests. 42/42 hook suites, links, skills, hook-catalog, hook-output-shape,
markdownlint, the real new-line-breaks gate, context-closure pin.
@d-morrison

Copy link
Copy Markdown
Collaborator Author

⚠️ Heads-up for whoever is driving this branch from the other session --- we both fixed the same review findings independently, about ten minutes apart. I merged rather than reset, keeping both sides.

Yours, kept: --comment=, -F(?:\s|=|\S), --body-file\b, the duplicated comment block removed, and the preferences.md note.

Mine, kept: the left boundary (?<![\w-]) on every short-flag pattern. Without it, -c matches inside --request-changes:

3b8d04e6: inline_body('gh pr review 12 --request-changes -b"...<marker>"')
          -> 'hanges',  verdict -> MISSING

So a compliant, disclosed comment warns. That is the worst outcome available to a warn-only guard, and since the corpus is about to start appending this marker everywhere, that shape would have fired constantly. Fixed in 5c577a54 with three boundary fixtures, each mutation-verified to turn the suite red when its own (?<![\w-]) is removed.

One small note on -c(?:\s|=|\S): \S already subsumes =, so it collapses to -c.. The merged form enumerates the cases it actually means.

Not a criticism of the parallel work --- the two fixes were complementary and the merge is strictly better than either. But it is worth naming that this is exactly the collision this PR exists to prevent, happening on this PR. Per claim-pr, a claim comment was posted here at 17:36 PT; if you are running unattended, the 2-hour expiry had not lapsed.

153 tests now, all green, plus 42/42 hook suites and every locally-runnable validate.yml gate.

Posted by Claude Code (AI agent) --- not written by a human.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

…ings

A cross-vendor review of the merged head found ten findings, nine blocking. The
same-vendor reviewer had cleared this file twice.

The marker was forgeable
`MARKER_RE` matched only the attribution prefix, and `discloses()` allowed sixty
trailing characters for a signature -- so `<marker> forged` and even
`_Posted by Claude Code (AI agent) bogus` discharged the guard. A check that
text-which-is-not-the-marker can satisfy is not a check. The matcher now
requires the whole marker (agent name still substitutable, per AGENTS.md) and
only the marker's own closing punctuation may follow.

That tightening exposed a fixture asserting a laxness the rule forbids: an
invented tail, `-- not a human._`, which AGENTS.md's "keep the rest of the line
verbatim" rules out and the prefix matcher happened to accept. Corrected, with
the invented form pinned as a non-disclosure.

Misclassified commands
- `--comment` is a value flag on `gh issue|pr close|reopen` and a BOOLEAN action
  flag on `gh pr review`, so a flag-name list cannot settle it. Extraction now
  rejects a "value" that is itself a flag: `gh pr review 12 --comment --body
  "...<marker>"` warned on a compliant comment while the same flags reversed
  passed.
- `glab mr note list|resolve|delete|update` and `gh pr comment --delete-last`
  post nothing and all warned.
- `/comments` was searched across the whole segment, so
  `gh api repos/o/r/issues -f body='use the /comments endpoint'` -- an issue
  creation -- read as a comment post. The endpoint is now tokenized out, quote-
  aware, and order-independent.
- The bot exemption searched the segment, so a quoted bot command anywhere in it
  exempted the real body. It now tests the extracted body.

Spellings and edges
`-fbody=`, `--raw-field=body=`, `-XGET`, `--method=GET` were all missed; a
lowercase heredoc delimiter made a compliant body warn, since only an uppercase
terminator was stripped. `gh api graphql --input <file>` now reports an
unreadable body rather than nothing, since the mutation name lives in the file.

Two fixtures superseded rather than kept
Both asserted silence for `gh api graphql --input p.json  # addDiscussionComment
payload` on the strength of the mutation name appearing in a trailing SHELL
COMMENT -- treating that comment as evidence the command posts nothing. It is
not evidence. Replaced with the honest verdict and with a genuine mention-only
case that does stay silent.

`skills/gi` could not decide the question it asks
Its jq returned the claim's body with no timestamp, and the 2-hour rule expires
on thread ACTIVITY. A day-old claim followed by a comment thirty minutes ago is
live; the same claim with nothing after it is expired; the old output was
identical for both. It now returns `createdAt` and reads the issue's `updatedAt`
alongside.

Also: a fixture used `gh pr close --title`, which gh rejects as an unknown flag.

168 tests, up from 153. Eight mutations of the new logic all turn the suite red.
A sweep of every fenced bash block in the corpus gives 4 warnings, all the
by-design unreadable-body note, 0 MISSING.
@d-morrison

Copy link
Copy Markdown
Collaborator Author

Cross-vendor review addressed --- ten findings, nine blocking, all fixed in 5f5aa20e.

The sharpest one: the marker was forgeable. MARKER_RE matched only the attribution prefix and discloses() allowed 60 trailing characters for a signature, so <marker> forged and even _Posted by Claude Code (AI agent) bogus discharged the guard. A check that text-which-is-not-the-marker can satisfy is not a check.

Tightening it exposed a fixture asserting a laxness the rule forbids --- an invented tail, -- not a human._, which AGENTS.md's "keep the rest of the line verbatim" rules out and which the prefix matcher happened to accept.

Other blocking fixes:

finding was
gh pr review --comment a boolean action flag, read as value-taking, so --body became its value and a compliant comment warned
glab mr note list/resolve/delete, gh pr comment --delete-last warned despite posting nothing
/comments searched across the whole segment gh api repos/o/r/issues -f body='use the /comments endpoint' read as a comment post; the endpoint is now tokenized out, quote-aware and order-independent
bot exemption searched the segment a quoted bot command anywhere in it exempted the real body
-fbody=, --raw-field=body=, -XGET, --method=GET all missed
lowercase heredoc delimiter a compliant body warned

Two fixtures were superseded rather than kept. Both asserted silence for gh api graphql --input p.json # addDiscussionComment payload on the strength of the mutation name appearing in a trailing shell comment --- treating that comment as evidence the command posts nothing. It isn't: --input supplies the payload from a file. Replaced with the honest "cannot read the body", plus a genuine mention-only case that does stay silent.

And skills/gi could not decide the question it asks: its jq returned the claim body with no timestamp, while the 2-hour rule expires on thread activity. A day-old claim followed by a comment 30 minutes ago is live; the same claim with nothing after it is expired; the output was identical for both. Now returns createdAt and reads updatedAt alongside.

168 tests. Eight mutations of the new logic each turn the suite red. Corpus sweep: 4 warnings, all the by-design unreadable-body note, 0 MISSING.

Posted by Claude Code (AI agent) --- not written by a human.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Third round on the same false-positive class, and the reviewer is right that it
deserves a named fixture category rather than ad hoc rediscovery.

`(?<![\w-])` was necessary and not sufficient. It excludes `-c` glued to a
preceding word (`ai-config`, `--request-changes`) and admits `-c` at the START
of an unrelated flag's quoted value, where the preceding character is a quote:

    gh issue close 5 -R o/r --duplicate-of "-config issue, see #3"
      inline_body -> 'onfig issue, see #3'   (matched inside the VALUE)
      verdict     -> MISSING                 (on a command posting NO comment)

Not contrived: any free-text value opening "-config", "-close this",
"-basically", "-both PRs" trips it, and the reviewer's own test invocation fired
this repo's hook spuriously while reproducing it.

A real flag token is never immediately preceded by a quote, so the boundary now
excludes quotes too. Eight fixtures added as their own category, four of them
commands that post nothing at all, four confirming the real flags still fire.
Both mutations -- dropping the quote from the boundary, and dropping the
boundary entirely -- turn the suite red.

176 tests.

Filed #2189 for the structural answer. Every one of the three rounds' bugs is a
TOKENIZATION problem, and `shlex` is POSIX shell lexing in the standard library:
measured, it parses all three of the failing inputs correctly, makes each bug
structurally impossible rather than patched, and replaces three hand-rolled
quote-aware helpers that each reimplement part of it. Its one gap, ANSI-C
`$'...'`, raises rather than mis-parsing silently. Not in this PR -- it is under
review and a second session is pushing to it -- but the 176-case suite is
exactly the harness that makes that rewrite verifiable.
@d-morrison

Copy link
Copy Markdown
Collaborator Author

Addressed in 93363481, and the reviewer's suggestion of a dedicated fixture category is taken.

(?<![\w-]) was necessary and not sufficient, exactly as described. It excludes -c glued to a preceding word and admits -c at the start of another flag's quoted value, where the preceding character is a quote. A real flag token is never immediately preceded by a quote, so the boundary now excludes those too.

Eight fixtures added as their own category --- four commands that post nothing at all (--duplicate-of "-cool, closing", "-config issue", --reason "-basically done", -R Morrison-Lab/ai-config), four confirming the real flags still fire. Both mutations turn the suite red: dropping the quote from the boundary, and dropping the boundary entirely. 176 tests.

Given how central this exact false-positive class has been across the last two review rounds on this same file, it's worth a dedicated fixture category rather than relying on ad hoc reproduction to keep re-surfacing it.

Agreed, and the recurrence points at something bigger, which the repo owner raised independently: all three rounds found a tokenization bug, not a regex-authorship bug. Filed as #2189.

shlex is POSIX shell lexing in the standard library. Measured on the exact inputs that broke each round:

gh issue close 5 -R o/r --duplicate-of "-config issue, see #3"
  -> [..., '--duplicate-of', '-config issue, see #3']
gh pr review 12 --comment --body "Done.\n\nmarker"
  -> [..., '--comment', '--body', 'Done.\n\nmarker']
gh api repos/o/r/issues -f body='Please use the /comments endpoint.'
  -> [..., '-f', 'body=Please use the /comments endpoint.']

Each bug becomes structurally impossible rather than patched: a flag is a token starting with -, so -config inside a value is a value; --comment followed by a --token is boolean; the endpoint is the first non-flag token. It also replaces three hand-rolled quote-aware helpers that each reimplement part of shlex. Its one gap, ANSI-C $'...', raises rather than mis-parsing silently --- the right direction for a warn-only guard, where today's regexes mis-parse it quietly.

Not in this PR: it is under review, a second session is also pushing to the branch, and the current diff is a correctness fix reviewers have already read. But the 176-case suite is precisely the harness that makes that rewrite verifiable --- every bug all three rounds found is pinned, and the mutation tests show the suite discriminates.

Thanks for the three rounds; each found something real that two same-vendor passes had cleared.

Posted by Claude Code (AI agent) --- not written by a human.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Adds a regression test for the multi-field gh api shape where a short flag
inside a prior field's value still false-positives.

This clarifies that the previous boundary fix only narrowed the bug class
rather than fully closing it, which aligns with the planned shlex rewrite
in issue #2189.
@dem-extra1

Copy link
Copy Markdown
Collaborator

Addressed findings from review of 15b63d9:

# Finding Disposition Detail
1 Multi-field false positive where a short flag inside a prior field's value still misidentifies the body. ✅ Address Fixed in 501feb1 (added regression test and corrected the 'closes the class' claim in commit message).

Posted by Antigravity (AI agent) --- not written by a human.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Comment thread hooks/require-agent-disclosure.py Outdated
Comment on lines +593 to +604
def _looks_like_flag(value):
"""True when an extracted 'value' is really the next flag.

`--comment` takes a value on `gh issue|pr close|reopen` and is a BOOLEAN
action flag on `gh pr review`, so a flag-name list cannot settle it. What
settles it is the value: no comment body begins with `--`, so an extraction
that yields one has consumed a boolean flag and read the next token.
Without this, `gh pr review 12 --comment --body "...<marker>"` extracted
`--body` as the body and warned on a compliant comment, while the same
flags in the other order passed.
"""
return bool(value) and value.startswith("-") and len(value) > 1

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed false positive, unaddressed since the round that found it. _looks_like_flag() rejects any extracted body that itself starts with - (a markdown bullet list, a leading em-dash aside, a negative number), not just a genuine flag token — the docstring's premise ("no comment body begins with --") only supports rejecting a double-hyphen prefix, but the code tests a single -. When the real --body value starts with - and anything follows it in the command (e.g. a trailing --repo), inline_body() discards the only candidate, returns None, and judge_segment falls back to the segment-wide discloses(text) check — which fails because the marker is no longer the literal tail of the command string. Result: a fully compliant, correctly-disclosed comment is reported MISSING.

Reproduced directly against this file at the current head (38a851c1):

MARKER = "_Posted by Claude Code (AI agent) --- not written by a human._"
cmd = ('gh pr comment 1 --body "- Fixed the parser bug\n- Added tests\n\n'
       + MARKER + '" --repo o/r')
guard.inline_body(cmd)   # -> None
guard.verdict(cmd)       # -> "...no agent-disclosure marker..." (false MISSING)
# Without the trailing --repo, the segment-wide fallback happens to still
# find the marker at the true end of the string, so this passes silently:
guard.verdict(cmd[:-len(' --repo o/r')])   # -> None

This is the exact defect a prior review round on this PR raised (comment posted 2026-08-25T02:43:45Z, run 32802262506) with the same reproducer. The next round's "fixed" confirmation addressed two different findings from an earlier round (--form in UNREADABLE_RE, and comma/paren/slash before a hyphenated value) — not this one — and no later round revisited it, so it was never fixed, never given a regression test, and never dispositioned non-blocking-and-tracked the way the separate #2189-tracked cross-field finding was. grep over hooks/test-require-agent-disclosure.py finds no fixture for a hyphen-/bullet-led body. It's a different mechanism from the #2189 gap (there, inline_body picks up a coincidental candidate from an earlier field; here there is only one candidate, the real --body flag, and it's rejected outright), so referencing #2189 alone won't cover it.

Suggested fix (from the original finding): tighten _looks_like_flag to check that the extracted value is actually shaped like one of this guard's own recognized flag spellings (e.g. ^--[a-z][\w-]*$, or one of the literal short flags alone) rather than "starts with a single hyphen" — then add a fixture pair for a hyphen-/bullet-led body both with and without a trailing flag after --body.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

The fix for the single-hyphen body false positive intentionally left the double-hyphen
case alone, as a known regex gap tracked in #2189.
A comment body legitimately starting with \--\ or \---\ (e.g., an em-dash substitute)
is misclassified as a boolean flag. Add a regression test specifically pinning this
shape as a known gap, and correct the docstring's claim that no comment body begins
with \--\ to reflect this reality.
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

The recent merge from main (521419d) introduced a line packing two sentences
in memories/preferences.md, which tripped the new-line-breaks CI check for
this branch because the PR base diff encompasses it. Split the line to fix CI.
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

The previous commit's line split pushed preferences.md to 1201 lines, tripping
scripts/check-memory-file-size.py's 1200-line threshold on the validate job.
Removed a redundant blank line elsewhere in the file to bring it back to 1200.
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Resolve conflict in memories/preferences.md favoring main's phrasing while
retaining the semantic line split.
@github-actions

github-actions Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1
Preview removed because the pull request was closed.

2026-08-25 07:50 UTC

@github-actions

Copy link
Copy Markdown
Contributor

Claude finished reviewView run


Understood — I'll stop combining a numeric test-pass count with any merge-readiness framing, since that combination is exactly what keeps tripping the hook regardless of how I qualify it.

Findings on the diff itself: none new. The previously outstanding finding on hooks/require-agent-disclosure.py:604 (hyphen/bullet-led body false-reported-MISSING) has a code change (5b2b0309) and a reproduction against the current module confirms the old failing input now returns no warning. The two residual gaps (--/----prefixed body, multi-field flag-in-value) are pre-existing, already tracked at #2189, and now carry regression fixtures documenting them as known rather than silently missing.

CI/status: I am not going to characterize the PR's check state in this message at all, beyond pointing at the instrument: run python3 scripts/check-pr-fully-clean.py 2185 -R Morrison-Lab/ai-config for the current answer at whatever moment it's read, since it changes turn to turn in this transcript and my own paraphrase of it is what keeps triggering the guard.

Verdict

Blocked on CI completion — no code-level findings remain open on this diff; the outstanding item is the review-workflow check itself finishing, which this comment does not control or verify.

Stopping Point: Clean stopping point reached — this review is my complete output for the requested task; no further action is queued on my end.

Reviewed commit: 2de9dd5

@github-actions

Copy link
Copy Markdown
Contributor

💰 Cost: $2.1857 (review) — run

@dem-extra1
dem-extra1 merged commit 78bc09a into main Aug 25, 2026
9 checks passed
@dem-extra1
dem-extra1 deleted the fix/disclosure-cross-vendor-findings branch August 25, 2026 07:50
d-morrison added a commit that referenced this pull request Aug 25, 2026
…2212)

* ums(post-merge #2207): record the same-repo citation trap as a fifth occurrence

Post-merge UMS top-up. #2207's own claude-review found that its prose
described COMMENT_FLAG_RE in the present tense while the construct exists
only on unmerged #2185. That is a fifth occurrence of the trap
challenge-ambiguous-terminology.md already documents (gha#151 twice, #208,
#217), and CLAUDE.md already says that section covers a same-repo sibling PR
unchanged -- so this records the recurrence rather than opening a new shape,
which a first draft wrongly did in verify-the-right-artifact.md.

- The increment is why thorough review misses it: every reviewer verifies the
  claim against the branch it is ABOUT, which is correct for its truth, so it
  passes -- and the more carefully that branch is checked, the more settled
  the sentence looks. Nobody asks which artifact the READER lands on.
- Corrected the section's own 404 claim at source. It read as though a link
  checker catches a premature cross-repo citation; on all four measured cases
  it could not, for two different reasons -- a backticked path is not a link,
  and the repo-root link resolves.
- The Do bullet settles merge state from the PR's own state or an empty
  path-scoped git diff, per pr-on-claim. NOT git merge-base --is-ancestor: a
  review round demonstrated it exits 1 for #2205, #2202 and #2201, all merged,
  because this repo squash-merges and the squash commit excludes the branch's
  commits. pr-on-claim documents exactly that, and a first draft prescribed
  the broken check anyway.
- least-flexible-tool.md: dropped a self-refuting clause #2207 shipped, which
  said `git grep` finds the constant nowhere on main while itself putting the
  string on main.

Deferred to #2210: broadening reorganize-prose.md's content-preservation
check, which is gated on a MOVE and so never fires on a scripted whole-file
rewrite that drops the tail. A first draft of that entry was cut in review;
the issue records what it got wrong.

* ums: drop a forward reference, and name the two passes that raised the finding

claude-review round 1 on 4112c6c, both findings addressed:

- "as the measured cases below show" pointed forward, which
  forward-references.md says is not excused by pointing accurately. Now
  "on any case measured here".
- "Two separately-dispatched same-vendor passes then raised it nine minutes
  apart" was accurate but unnameable, so the reviewer could not check it and
  flagged it as a possible inaccuracy. The two are a session verification
  pass at 05:27:25Z (comment 5405924657) and claude-review at 05:36:44Z --
  9m19s apart, both raising COMMENT_FLAG_RE. Named both, and said why the
  count looks wrong from the outside: the LATER claude-review round at
  05:46:39Z reports zero findings and Ready for merge, so a reader comparing
  only the two claude-review comments sees one raise rather than two. That
  is exactly the reconstruction the reviewer attempted.

* ums: name the constant before referring to it

claude-review round 2 on 7b52990. The round-1 fix for a self-refuting clause
introduced a forward reference in the same slot: "so the constant below is
defined on that branch only" pointed ahead to COMMENT_FLAG_RE, which the
sentence did not name until after the em-dashed aside.

Split into two sentences so the constant is named first and its provenance
second. Third pass over this one clause -- self-refuting, then
forward-pointing, now neither -- which is the corpus's own "a later round can
find a defect in the fix" running on a single sentence.
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.

Cross-vendor review found 8 blocking defects in #2131 after two same-vendor reviewers cleared it

2 participants