Skip to content

Professional claim wording, and every agent-posted comment discloses that it is agent-posted - #2131

Merged
dem-extra1 merged 15 commits into
mainfrom
claude/paws-off-phrasing-6c5f20
Aug 24, 2026
Merged

Professional claim wording, and every agent-posted comment discloses that it is agent-posted#2131
dem-extra1 merged 15 commits into
mainfrom
claude/paws-off-phrasing-6c5f20

Conversation

@d-morrison

@d-morrison d-morrison commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

Closes #2130

Two changes to what agent-posted forge comments say. They are one PR because they
edit the same lines --- every claim and release body takes both --- so splitting
them would guarantee a conflict on each one.

1. Professional claim wording

paws off until I'm done becomes please hold off ..., and the release marker
paws off released becomes claim released.

Every detector matches all three wordings, not just the new one. There were
two retired invariants, not one: seven skills plus the orchestrator said
paws off, and ardi --- the corpus's
highest-traffic claim emitter, run on every PR in every repo --- said back off,
since 2026-06-17. A claim expires on activity rather than age, so claims under
either retired wording can be live right now, and a matcher narrowed to the new
phrase returns nothing on them --- indistinguishable from an unclaimed thread,
which licenses exactly the parallel session the convention prevents.

All six claim readers now match hold off|paws off|back off and exclude release
terms, the exclusion being necessary because ... done --- paws off released.
contains paws off.

2. Every agent-posted comment says an agent posted it

A comment posted through gh/glab under the account holder's credentials
carries their login, avatar and MEMBER association, and reads as
type: User. Nothing in the API distinguishes it from a comment they typed ---
memories/github.md already recorded auditors making that mistake. The forge
cannot say it, so the body does:

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

The marker deliberately avoids the robot emoji. check-pr-fully-clean.py
matches that emoji as a REVIEW_BODY_MARKERS entry, so a disclosed claim comment
would be admitted into the fully-clean verdict scan as a review --- and a claim
carries no findings, so it would scan as a clean one. Verified with a
negative control: the marker returns has_review_body_marker() False on claim,
unclaim, release and bare-marker bodies; the emoji form returns True.

Two exemptions: a body another machine parses as a command (@dependabot rebase), and a comment posted under a genuine bot token, where the forge already
reports type: Bot.

Ships as shared/workflow/disclose-agent-authorship.md, sections in AGENTS.md
and CLAUDE.md, the marker at ~20 comment sites, tool-mappings.yml rows, and
hooks/require-agent-disclosure.py --- a warn-only PreToolUse guard registered
under both Bash and mcp__github__.*, with 110 tests.

It warns rather than blocks because a missing marker is cheap to repair while a
blocked gh pr comment interrupts the action that makes a claim visible, and
because --body-file, --editor and $BODY put the text where a literal scan
cannot reach --- so it reports those as unreadable rather than as missing,
never asserting more than it observed.

Review

Eleven adversarial review rounds before the first push. Findings that mattered:

  • Two "fixes" introduced defects their predecessors lacked --- a clause deleted
    as dead code that was not, and an emitter list "corrected" to include an alias
    stub for the very skill it was contrasted against.
  • The new-line-breaks CI check delegates from a pinned SHA to a floating @v2
    in another org, so reading the pinned copy predicted a pass on a branch the
    real check failed. Filed as A SHA-pinned reusable workflow delegates to a floating @v2 in another org, so the pin does not reach the script that runs #2165.
  • The derivation offered in place of an enumeration could not reach the two
    emitters least like the others. Rekeyed on the wordings.

Follow-ups filed: #2148 (three files hard-wrapped rather than semantically
broken), #2165 (the pin that does not reach the script), #2172
(clean-branches reads claims with an empty code block, so it has no matcher).

…s authorship

Closes #2130

Two changes to what agent-posted forge comments say. They edit the same lines
-- every claim/release body takes both -- so splitting them would guarantee a
conflict on each one.

1. Claim phrasing. "paws off until I'm done" becomes "please hold off ...",
   and the release marker "paws off released" becomes "claim released", across
   19 files.

   Every detector now matches BOTH wordings. Claims posted before today sit on
   open PRs and a claim stays live on activity rather than age, so an
   old-wording claim can be live right now; a matcher narrowed to the new
   phrase returns nothing on such a thread, which is indistinguishable from an
   unclaimed one -- licensing the exact parallel session the convention
   prevents. shared/workflow/claim-pr.md states when the alternation may be
   dropped.

2. Agent disclosure. A comment posted through `gh`/`glab` under the account
   holder's credentials carries their login, avatar and MEMBER association and
   reads as `type: User`, so nothing distinguishes it from one they typed --
   memories/github.md already recorded auditors making that mistake. Every
   agent-posted comment now ends with:

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

   The marker deliberately avoids the robot emoji. check-pr-fully-clean.py
   matches that emoji as a REVIEW_BODY_MARKERS entry, so a disclosed claim
   comment would be admitted into the fully-clean verdict scan as a review --
   and a claim carries no findings, so it would scan as a CLEAN one. Verified
   against the checker with a negative control: the new marker returns
   has_review_body_marker() False on claim, unclaim, release and bare-marker
   bodies, while the emoji form returns True.

   New: shared/workflow/disclose-agent-authorship.md, CLAUDE.md and AGENTS.md
   sections, and hooks/require-agent-disclosure.py -- a warn-only PreToolUse
   guard (28 tests). It warns rather than blocks because a missing marker is
   cheap to repair while a blocked `gh pr comment` interrupts the action that
   makes a claim visible, and because --body-file/-F body=@/$BODY put the text
   where a literal scan cannot see it, so it reports those as unreadable
   rather than as missing.

   skills/defer-issue's "don't add attribution" line is narrowed rather than
   reversed: it governs issue BODIES, which stay unattributed.

Exempt: a comment another machine parses as a command (`@dependabot rebase`).
Out of scope: hooks/test-remind-brief-premises.py's `grep -n paws` strings,
which are arbitrary example commands in fixtures, not the claim phrasing.

Checks: 41/41 hook suites, markdownlint 0 errors, validate-skills, check-links
(2274 links), hook-catalog, hook-output-shape, context-closure pin.
Fifteen findings from the adversarial self-review on c3bc43a. All addressed
except one deferred with a tracking issue.

Detectors
- commands/release-pr.md matched the ISSUE-form claim sentence while reading PR
  comments, and the PR-form claim is not a superstring of it -- so /release-pr
  on a PR claimed today would have found no claim and refused to post. Both it
  and shared/workflow/claim-pr.md now match the two-word invariant `hold off`
  (plus `paws off`) rather than any whole sentence, and claim-pr.md says why a
  whole-sentence matcher is the trap the rename introduces.

Hook (hooks/require-agent-disclosure.py), 28 -> 52 tests
- Segmentation was newline-splitting, which cut the trailing marker off the very
  command it discloses -- every correctly-disclosed multi-line comment warned.
  Split is now quote-aware.
- Judged per call, so one disclosed body vouched for an undisclosed sibling in a
  batched round. Now judged per command-position segment.
- Heredoc handling skipped the whole command on any heredoc, silencing
  `--body-file -` and `$(cat <<EOF)` -- the forms memories/git.md prescribes for
  bodies with backticks. Now strips heredoc bodies for ANCHORING and keeps them
  for the MARKER test, reusing warn-pr-create-without-dupe-check.py's approach.
- Missed `gh api .../comments|/replies` (the only review-reply route) and the
  `glab mr|issue comment` aliases, both verified against `glab ... --help`.
- Anchor missed `then`/`else`/`do`/`!`/backtick positions.
- The bot exemption matched a body merely STARTING with a bot handle; now
  anchored whole-body. Adds the review re-request, assembled non-contiguously
  per memories/mention-triggers.md since a diff view renders this file.
- `-F` is gh pr comment's own `--body-file` shorthand, not gh api's `-F body=@`;
  the real form was misdiagnosed as a missing marker rather than an unreadable
  body. `--editor`, `--web` and the no-body-flag interactive form likewise.
- The emoji branch fired on a body merely MENTIONING the emoji, displacing the
  applicable advice with an inapplicable one.
- No MCP coverage at all, which is the only path in a remote/web session.
- The docstring misattributed require-gh-repo-flag.py's incident (it matched too
  much, not too little).

Prose and sites
- `\n\n` inside a bash double-quoted string is two characters, not a newline, so
  three sites would have posted a run-on body. Converted to fenced blocks with
  real newlines; the one remaining instance is labelled as notation.
- skills/ard/SKILL.md's per-round summary and CLAUDE.md's feedback comment --
  the two highest-frequency comment sites -- had no marker. Both now do; ard's
  arrives via --body-file, which the guard cannot read, so it states the
  requirement itself.
- The fragment claimed chores' two Dependabot commands were the only exemption
  instances. False: ardi's review re-request is a third. Corrected, with the
  deriving query beside it rather than a recollected count.
- Marker indentation: dedenting to column 0 ends the enclosing list item, which
  closes the fence (markdownlint MD049). Source keeps its indentation and the
  fragment now says to match the marker as a substring, not a whole line.
- Semantic line breaks applied to all new prose.

Deferred: three older skill files are hard-wrapped in paragraphs pre-dating this
change. Reflowing them here would bury the real diff in unrelated churn, so it
is #2148. Note for anyone re-measuring: `--all` reports a would-change on
essentially every file including untouched ones, so it is not a conformance
measure; the default changed-line scope against origin/main is.

Checks: 52/52 hook tests, markdownlint 0 errors, links (2277), validate-skills,
hook-catalog, hook-output-shape, context-closure pin.
Twelve findings on c41f0d3. All addressed except one rebutted.

Guard was silent or wrong where it mattered most
- Registered under matcher `Bash` only, so `MCP_POST_TOOLS` and `verdict_mcp()`
  were unreachable at runtime -- dead code in exactly the population they were
  written for, since a remote/web session has no `gh` at all. hooks.json matches
  by tool name, so the fix is a second entry under `mcp__github__.*`. Three
  statements asserting MCP coverage were false until it landed.
- A heredoc body anywhere in a call vouched for every segment, so writing a doc
  that QUOTES the marker silenced a bare comment posted in the same call -- the
  exact per-segment property the notes claimed. Heredoc bodies are now replaced
  by position-keyed placeholders, so each body reaches only the segment that
  opened it. `strip_heredocs` also erased `<<`, which had been the only signal a
  segment used one.
- `gh api .../comments` matched with no method or field discriminator, so the
  review-READ that CLAUDE.md prescribes and every ARDI round runs warned. So did
  `gh pr review --approve`, which posts no prose. Both now require a body field.
  A guard that cries wolf on the common read is one nobody reads on the rare
  write.
- The bot exemption anchored to end-of-segment, so BOTH corpus sites failed:
  chores' commands carry a trailing `# COMMENT_PR`. Acting on that warning would
  mean appending prose to a body Dependabot parses.
- Missed `glab api .../notes` and `gh api graphql addDiscussionComment` entirely.

Sites and claims
- Review-thread replies (both forges), discussion comments, and
  migrate-discussion's step 3 carried no marker though the fragment names them
  in scope; two were invisible to the guard as well.
- release-pr enumerated 3 of the 5 release markers the corpus posts, so an ARDI
  release (`Done --- PR is free.`) read as unreleased and would draw a stray
  release comment. It now lists all five and gives the query to re-derive them.
- push's claim query could no longer see a release at all: the old wording made
  it free, since `paws off released` contains `paws off`, while `claim released`
  contains no claim term. A released PR read as live-claimed and the skill would
  refuse a legitimate push.
- The orchestrator posted `--` where the canonical marker has `---`, so a literal
  grep found every site but that one.
- The exemption's "derive it with this grep" could not find the third site: the
  review handle is deliberately never spelled contiguously in a source file. The
  fragment now says so and gives both queries.
- Two test labels claimed coverage their assertions did not provide.

Measured rather than asserted
- The MD049 claim was wrong. Re-measured repo-wide (the CI condition, not a
  single-file lint, which reports differently -- verify-the-right-artifact): the
  dedent raises MD049 in post-merge, MD046 in release-pr, and nothing in st.
  Worse, the marker is underscore-emphasised, so one that escapes its fence sets
  MD049's `consistent` expectation and fails untouched lines elsewhere -- which
  is what my own migrate-discussion edit did, breaking two lines 70 below it.
  Marker indentation now tracks the enclosing fence.
- Reviewer reproducers for findings 2, 3, 5 and 8 are now permanent test cases.
  61 hook tests, up from 52.

Rebutted: em dashes on 26 added lines (finding 12). Every one is in a file that
already carries 8-43 of them, and the three new files this PR adds carry none.
Converting only mine would make those files internally inconsistent. The
corpus-wide condition is already tracked as #685, #731 and #735; a fourth issue
would be a duplicate.

Checks: 41/41 hook suites (61 in this one), markdownlint 0, links, skills,
hook-catalog, hook-output-shape, context-closure pin. Merge-tree against the
7 commits main gained mid-session is clean, verified against a negative control
that returns rc=1 on a real conflict.
Twelve findings on d8216c3. All addressed.

The guard matched nothing the corpus actually writes
Two detectors added last round passed their own tests and fired on no real site,
which is fixtures-are-not-evidence exactly: both fixtures were single-line
inventions, and the WITH-marker one was vacuous -- removing the marker did not
change its result, because the marker check never ran.

- `[^\n;|&]*` cannot cross a backslash line-continuation, and every review-thread
  reply in skills/ard uses one. Both raw-API detectors were silent on the only
  sites they exist for.
- Every GraphQL comment site puts `addDiscussionComment` several lines below
  `gh api graphql`, inside a quoted query that spans newlines.
- The first repair -- skipping quoted spans atomically -- was worse: the path
  segment these detectors match (`/notes`, `/comments`) is INSIDE the quoted URL,
  so the quote-skipping alternative swallowed the thing being matched.

Now two gap classes: `_GAP` admits a line continuation, `_GAP_ML` is bounded and
non-greedy for an argument that genuinely spans lines. The fixtures are replaced
with verbatim corpus command lines, and the WITH-marker case now flips when the
marker is removed.

Misdiagnoses, both directions
- `-F body=` and `--raw-field body=` were accepted as posting routes but omitted
  from HAS_INLINE_BODY_RE, so a body in plain sight drew "cannot read" -- the
  weaker note, which invites no correction.
- The variable-expansion clause covered `--body`/`--message` but not `-b`/`-m`,
  so a compliant `-b "$BODY"` was told its marker was missing.
- `-F body="@file"` reported MISSING; the `@` sigil is routinely quoted.
- EMOJI_DISCLOSURE_RE lacked word boundaries, so "CI regenerated" and "badge
  rewritten" matched and got told to swap markers rather than add one.
- split_segments applied plain single-quote rules to ANSI-C `$'...'`, reading the
  quote as closed and splitting the body on its newlines.

Detectors and sites
- push's alternation missed post-merge's release wording, so a released PR read
  as live-claimed and push would refuse a legitimate push -- the exact outcome
  the prose beside it says the alternation prevents.
- post-merge matched a whole claim sentence, which the rule added four files away
  forbids, and its quoted prefix used `---` while its own emitter four steps
  below posts an em-dash.
- tool-mappings.md -- the registry CLAUDE.md designates the single source of
  truth, and the substitution point for the very remote sessions the MCP
  registration exists to cover -- had no marker in any template.

False claims corrected
- The markdownlint cause claim was wrong. markdownlint-cli2 UNIONS a
  command-line path with the config globs (verified: 573 files either way), so
  there is no single-file scope to get wrong. The real cause was my own
  measurement: it grepped rule codes from the whole run without filtering by
  filename, so a different broken file's MD049 was attributed to each file in
  turn. metacognitive-monitoring's cause check, gone unasked.
- ard's "nothing will warn you" was false; the guard warns, weakly.
- The marker's searchable invariant is `(ai agent)`, not the full line -- the
  literal full line cannot find a Codex- or Gemini-posted comment, returning
  nothing, indistinguishable from an undisclosed thread. Named in the fragment
  with the query.
- A comment posted under a genuine BOT token needs no marker, since the forge
  discloses it there. The fragment's scope sentence did not carve that out.
  The test is the token, not the workflow, with the query to settle it.
- release-pr said the corpus "posts five" release markers; one is retired.

Checks: 41/41 hook suites (70 in this one, up from 61), markdownlint 0, links,
skills, hook-catalog, hook-output-shape, context-closure pin, codex wrappers
re-synced.
Eleven findings on fffc9aa. All addressed.

The fix from round 3 introduced a bug the code it replaced did not have
post-merge's claim check now matches the two-word invariant `paws off`, and the
retired release marker is `... done --- paws off released.`, which contains it.
The sentence matcher that preceded it did not collide. So a released PR read as
claimed, the conflict sweep skipped it, and the conflict went unresolved with
nothing reporting why. It now checks the same comment for a release term first.

The raw-API detectors were still wrong, for a third distinct reason
Rounds 2 and 3 each tried one regex spanning the gap between `gh api` and its
comment path. `[^\n;|&]*` could not cross a line continuation. `[^;&]{0,400}?`
put the COMMENT BODY inside the gap, so an ordinary semicolon in the prose, an
ampersand, or a body over 400 characters made the detector silent -- on exactly
the longer, human-looking replies the rule targets. And the round-3 fixture
added to stop testing "single-line inventions" used a 12-character placeholder
with no punctuation, so it passed on the one input that concealed it.

Replaced with a two-part test over the whole segment, which the quote-aware
splitter has already bounded to one command: an anchored `gh|glab api`, a
comment-bearing target, and a body field or a GraphQL comment mutation. Order
independence falls out, which also fixes `gh api -f body=... <url>`. As a side
effect the polynomial blowup the reviewer measured (7.47s on 8000 `/comments`
substrings) is gone with the gap regexes -- 0.008s on the same input.

Other misdiagnoses
- `(?<!-)-F\s+(?!body=)\S` was meant for gh pr comment's `-F <file>` shorthand
  and fired on any `-F`, so `gh api ... -F in_reply_to=5 -F body="..."` -- the
  corpus's own review-reply shape -- reported "cannot read" over a visible body.
  Narrowed to a bare token with no `=`.
- verdict_mcp synthesized `--body "<body>"` to reuse the shell-shaped exemption
  pattern, so a `"` inside the body closed the synthetic argument early and
  `@dependabot rebase" and a long note for the humans...` took the exemption.
  The MCP path now matches the raw body. The Bash path had a fixture against
  this shape; reconstructing syntax to reuse a matcher is what reopened it.

False claims corrected
- "there is no single-file scope to get wrong" is false: `--no-globs` is in
  markdownlint-cli2's own `--help` and gives exactly that (573 files versus 1,
  measured). The union half was right. Named the flag, since it removes the
  contamination the weaker remedy works around.
- The `.user.type` check gave only the issues endpoint, which 404s on a
  review-thread comment -- a surface the fragment names in scope two paragraphs
  above. Both routes now given, with what the 404 means.
- The scope list said "an issue filed on the user's behalf" while three other
  sites in this diff say issue BODIES stay unattributed. Narrowed to comments.
- tool-mappings' COMMENT_DISCUSSION row said no MCP tool exists;
  `mcp__github__discussion_comment_write` does, and this hook covers it.
- The MCP_POST_TOOLS comment cited tool-mappings as the source of its five-tool
  list; that file names four. Said so rather than implying derivation.
- The README row described one of the three verdicts the hook emits, omitting
  the unreadable-body one, which is the commoner in this corpus.

Checks: 41/41 hook suites (77 in this one, up from 70), markdownlint 0, links,
skills, hook-catalog, hook-output-shape, context-closure pin, codex wrappers
re-synced, and `bash -n` parses all 17 marker-carrying shell blocks.
Ten findings on a9ff133. All addressed.

A generated file, edited at the wrong end
tool-mappings.md is generated from tool-mappings.yml, so the previous round's
edits to it were silently reverted by the next sync -- AGENTS.md's "canonical
sources vs generated output" rule, broken while adding rows to the registry
CLAUDE.md calls the single source of truth. The marker note now lives in
tool-mappings.yml and in the generator's own preamble, and survives a regen.
The COMMENT_DISCUSSION row also said no MCP tool existed;
mcp__github__discussion_comment_write does.

A fix applied to one of two sites carrying the same defect
This round's own docstring explains why `[^\n;|&]*` had to go: it cannot cross a
backslash line-continuation. The identical bound survived in the `gh pr review`
lookahead, so a review whose body flag sat on a continuation line -- the shape
skills/ard uses everywhere -- went silent. The body-flag test now runs over the
whole segment, where the continuation is already absorbed.

A false premise, twice cited
The fragment and the hook both claimed the review handle is "never spelled
contiguously in a source file, because a diff view would summon the bot". False:
242 occurrences across this corpus's markdown, including AGENTS.md, CLAUDE.md and
README.md, none of which has dispatched a run -- and memories/mention-triggers.md
states the gate over comment, review and issue BODIES, not file contents. The
real reason the command-shaped grep misses ardi's site is mundane: that site is
prose. The passage now says so and gives the second query plainly.

Six properties no test pinned
Removing any of these passed 77/77: three of the five MCP tools, the /notes and
/discussions targets, the env-var prefix in the anchor, and the ANSI-C `$'...'`
branch a prior round added as a fix. All are now pinned, and all eight mutations
are confirmed CAUGHT by re-running the suite against each mutant. The first
/discussions fixture was itself masked -- its path also contained /comments -- so
it uses GitLab's create-a-thread route, where /discussions is the only marker.

Removed rather than fixed
The GraphQL early return was justified by a body-as-variable case that does not
occur here: every GraphQL comment site supplies `-f body='...'`, so the branch
decided nothing while classifying any command that merely NAMED the mutation as a
post. Deleting it passed the suite unchanged and removes a false positive.

Smaller
- `-F key=value` is a typed field, not a body-file; narrowed so a review reply's
  `-F in_reply_to=5` no longer downgrades a visible body to the weaker note.
- `--body=`/`--message=` equals forms read as inline rather than unreadable.
- claim-pr's canonical matcher carried the release collision its own consumers
  document and fix: `paws off released` matches `paws off`, so a released PR read
  as claimed in every reader that follows the fragment rather than post-merge.
- "One exemption" was stated in three always-loaded places while the fragment
  defines two; the bot-identity one is now named in all of them.
- The issue-body pointer cited a scope line that omitted issue bodies.
- A duplicated eight-line comment block in the new hook.

Checks: 41/41 hook suites (92 in this one, up from 77), markdownlint 0, links,
skills, hook-catalog, hook-output-shape, context-closure pin, codex wrappers
re-synced from the yml.
Fourteen findings on de50078. All addressed. This round's differential over all
804 fenced code blocks in the tree showed zero verdict changes from the previous
head, so the guard's behaviour on what the corpus actually writes is stable; the
findings are gaps rather than regressions.

Invisible to the guard
- The QUOTED whole-argument field form. `API_BODY_FIELD_RE` required `body=` to
  follow whitespace directly, so `-F "body=@<file>"` -- the registry's own
  canonical reply command, and the line this change annotates -- was not merely
  weakened to the "cannot read" note but completely silent. The corpus writes
  the quoted spelling for sibling flags too.
- `-F "in_reply_to=5"` still downgraded a visible body. The optional quote gave
  the engine a backtracking path: skip the quote, fail to find `key=` at `"`,
  satisfy the negation. Matched as a token with no `=` in it instead.

Removed rather than kept
- `/replies` is dead. GitHub's reply route is `.../comments/<id>/replies`, so it
  always contains `/comments` -- which is why two attempts at a fixture for it
  were masked by their own paths. An alternative no fixture can isolate implies
  a route that does not exist.
- Three `UNREADABLE_RE`/`ANY_BODY_FLAG_RE` alternatives were subsumed when
  `HAS_INLINE_BODY_RE` gained `[^\s"'$]`, and their comments described behaviour
  the code no longer had.

Restored, with a real discriminator
The GraphQL branch was deleted last round because "the branch decided nothing" --
a claim about the corpus, applied to a detector that sees whatever an agent
writes. A mutation carrying its body in the query text or an `--input` file was
silent. It is back, keyed on `mutation` beside the name, so executing one is
distinguished from a comment mentioning one.

The registry, again
- COMMENT_DISCUSSION's new MCP mapping omitted the required `method`, on the one
  operation where the registry is the only path for a remote session.
- Three sibling discussion rows were stale in exactly the way this round
  corrected a fourth: LIST_DISCUSSIONS, VIEW_DISCUSSION and ANSWER_DISCUSSION
  all said no MCP tool existed. Verified against the server's tool list, which
  is what the hook's own docstring says to do.

Claim readers
`gi` and `claim-pr`'s GitLab sweep were left on the claim invariant alone,
against the rule written four files away -- so `... done --- paws off released.`
read as a live claim and `gi` would skip a released issue permanently. All six
claim readers now exclude release terms.

Untested properties, and two that could not be tested
Six more survived deletion with the suite green: the `systemMessage` key (which
`check-hook-output-shape.py` checks for Stop hooks only), `MARKER_RE`'s
attribution prefix, `strip_heredocs`'s opener tail, `_ANCHOR`'s `(`/`{`/backtick
positions, `verdict_mcp`'s isinstance guard, and `/replies`. Five are now pinned
and confirmed CAUGHT by mutation; `/replies` was removed instead.

False and unsupported claims
- The published derivation grep put `--include` after `--`, so both flags were
  read as file operands and the search ran unfiltered -- returning its own test
  fixtures as apparent sites, in the passage whose thesis is that one query does
  not derive the set.
- "242 times" was a count from a tree predating the sentence, with no deriving
  command beside it. Re-derived at this commit and the command published.
- The previous commit claimed to have removed a duplicated comment block; it had
  not. Removed now.
- AGENTS.md's exclusion list omitted issue bodies while its inclusion list named
  issue comments -- and non-Claude agents read AGENTS.md instead of CLAUDE.md.

Prose and budget
- Em dashes on lines authored this round converted to ASCII, EXCEPT inside
  quoted literal comment bodies: `<lane> done - claim released.` is the text
  that reaches GitHub, and changing it desynchronizes the corpus from the string
  its matchers agree on.
- CLAUDE.md restated the whole mechanism beside the fragment carrying it;
  trimmed to the rule, the marker, and the emoji constraint (1516 -> 1171
  bytes). AGENTS.md keeps the longer copy deliberately, since agents reading it
  never load the fragment. The always-loaded pool remains over its advisory
  budget, which predates this change.

Checks: 41/41 hook suites (105 in this one, up from 92), markdownlint 0, links,
skills, hook-catalog, hook-output-shape, context-closure pin, and
tool-mappings.md is idempotent under a second regen.
… dead

Seven findings on 781d286, two of them blocking. All addressed.

A "dead code" deletion that was not dead
Round 6 removed the short-flag `$`-interpolation clause on the reasoning that
HAS_INLINE_BODY_RE had taken it over, and narrowed the field-form clause so it
could no longer cross a quote or a space. Neither held: that pattern rejects only
a value BEGINNING with `$`, so a MID-STRING expansion fell through and reported a
missing marker over a body the check never read -- an assertion beyond what it
observed, and the opposite verdict from `--body` on the identical body.

    UNREADABLE -> MISSING   gh pr comment 5 -b "pre $VAR post"
    UNREADABLE -> MISSING   gh pr comment 5 -f body="pre $VAR post"
    UNREADABLE -> MISSING   gh pr comment 5 -F "body=pre $VAR post"

The fixture that licensed the deletion was named "-b with an expanded variable is
unreadable" and only exercised `-b "$BODY"`, the whole-value form, which still
passed. The name generalized past the check. Both clauses are restored, four
mid-string fixtures added, and deleting either clause now goes red.

A count that refuted itself
The figure was published beside a `git grep` command that is itself an `@claude`
occurrence in a markdown file, so shipping the command incremented the number it
measured -- wrong at round 5 and wrong again at round 6, in opposite directions,
and failing on first contact for a reader invited to re-run it. The count now
excludes this file, in both the sentence and the command, so it is stable under
edits to the file that states it. Verified: the sentence says 248 and the command
returns 248.

Contradictions between the corpus and itself
- The guard carried the mention-gate rationale that the fragment added in this
  same branch calls "false twice over" -- shipping the refutation and the refuted
  claim side by side, with the refuted one in the file a maintainer reads first.
  The handle stays concatenated for a narrower and true reason, now stated.
- "share an id space but not a route" contradicted the 404 two lines below it.
  If the id space were shared the wrong route would return a different comment,
  which is a worse failure than the one described.
- The guard implements one of the two declared exemptions, and nothing said so.
  Whether a token belongs to an app or to a person is not in the command text, so
  no lexical check can decide it; the docstring now names the gap and its one
  visible consequence.
- memories/github-mcp-tools.md carries the same pre-change warning
  memories/github.md got a pointer for, and had none.
- The name-substitution instruction is the one path that can reintroduce the
  collision the emoji ban prevents: `code review` is a REVIEW_BODY_MARKERS entry,
  so an agent named for code review would reintroduce it through its own name.
  Both AGENTS.md and the fragment now say to check the substituted name too.

Checks: 41/41 hook suites (109 in this one, up from 105), markdownlint 0, links,
skills, hook-catalog, hook-output-shape, context-closure pin, and tool-mappings
regenerates byte-identical.
One blocking finding on 0fff5eb, plus four non-blocking. All addressed.

There were three retired claim wordings, not one
`ardi` posted `Driving this PR to clean --- back off until done.` since
2026-06-17, and this branch retired it in c3bc43a without adding it to the
back-compat alternation -- so the five matchers this branch rewrote all read
`hold off|paws off` and were blind to it.

`ardi` is the corpus's highest-traffic claim emitter, run on every PR in every
repo, so a session claiming a PR through it left a claim that `/push`'s check 3
could not see: the query returns empty, which is indistinguishable from an
unclaimed thread, and the session pushes over a live claim. That is verbatim the
failure this branch's own added prose describes. `/release-pr` had the mirror
failure and would decline to post the release.

The prose was false in the same commit that proved it: claim-pr.md said the body
"said 'paws off until I'm done' until 2026-08-24", and release-pr.md called
`paws off` "the pre-2026-08-24 invariant". Both are true of claim-pr's own body
and false of the corpus. All six matchers now carry `hold off|paws off|back off`.

The method that missed it, named and replaced
Six skills agreed on `paws off`, so enumerating the retired set from the files
in front of me returned six confirmations and one silent omission -- the one file
that disagreed was the one not consulted. claim-pr.md now publishes a git-log
derivation over history instead of a list, verified to return all three, with a
Don't naming the enumeration method as the cause.

Non-blocking
- The migrate-discussion MD049 measurement does not reproduce under the same
  harness that reproduces the other three exactly. The structural hazard is real
  and the linter's coverage of it is not established; the passage now says that
  rather than claiming the linter catches it.
- Two count-based self-references ("four steps below", "step 3 below") replaced
  with stable ones.
- A single-quoted `$` is reported unreadable though bash does not expand it.
  Kept: the `--body`/`--message` clause has always behaved this way, so the short
  forms match rather than diverge, and it errs toward the weaker note rather than
  toward asserting something about text never read. Pinned as a test so the
  choice is visible as a choice.

Verification carried over from the review: a differential of verdict() against
781d286 over 7,514 synthetic commands showed 456 differences, all in the
intended MISSING -> UNREADABLE direction, and zero across 831 fenced blocks in
the tree -- with a negative control showing the corpus sweep fires on 25 blocks,
so the zero is a result rather than a detector that never ran.

Checks: 41/41 hook suites (110 in this one), markdownlint 0, links, skills,
hook-catalog, hook-output-shape, context-closure pin, tool-mappings idempotent.
…d wrong

The pre-push review reported 8 lines failing `validate / new-line-breaks`.
Running the checker locally returned exit 0, so I nearly rebutted it. The
rebuttal would have been wrong, and the way it was wrong is the finding.

`.github/workflows/validate.yml` pins the reusable workflow to a SHA in
`Morrison-Lab/gha`. That workflow's own step then runs
`d-morrison/gha/check-new-line-breaks@v2` -- a different org, a floating tag --
so the pin fixes the caller and nothing about the script that executes. The two
differ materially: 340 lines versus 637, no clause-break rule versus one on by
default, and on this branch exit 0 versus exit 1 with 8 findings. Reading the
pinned copy to predict CI gives the wrong answer confidently, since that
artifact exists, is fetchable at the named SHA, and runs clean.

That is verify-the-right-artifact's "a checkout for the run" shape, and
pr-on-claim already records the same delegation trap for a reusable workflow's
trigger conditions. Nothing said it applies to what the workflow RUNS. Filed as
#2165, with the measured table and three fix options.

The eight lines, all mine, all long with a mid-line semicolon: AGENTS.md 196 and
211, memories/github.md 199, shared/workflow/claim-pr.md 96/114/143, and
skills/post-merge/SKILL.md 324/325. Split at their clause boundaries.

Most came from my own `scripts/semantic-line-breaks.py --write` runs, which JOIN
wrapped lines -- the opposite direction from this check, and it exits 0 either
way. So running the local tool to satisfy one convention manufactured failures
in the other, and no local signal reported it. Worth knowing before the next
reflow pass.

Two more surfaced only after the first fix: an `...` inside a quotation reads as
a sentence end, so anything following it on the line counts as a second
sentence. Rewording the quotations to drop the ellipsis cleared both; a
bracketed `[...]` elision did not, since it terminates a sentence too.

Also from the same review, non-blocking:
- The retired-wording enumeration was wrong in both directions -- `handoff`
  never said "paws off until I'm done" (it said "still claimed, paws off."), and
  `gip`, `iterate` and the orchestrator were omitted. Corrected, two lines above
  the Don't that forbids enumerating from the files in front of you.
- "There were three retired wordings" was uncountable: there are two retired
  two-word invariants, and the third is a wording only if claim SENTENCES are
  counted, which the next subsection tells the reader not to do. Reworded to
  name the emitters and the two invariants.

Verified with the script CI actually runs (`d-morrison/gha@v2`, NLB_FAIL=true,
base = merge-base): "No lines missing semantic breaks", exit 0. Plus 41/41 hook
suites (110 in this one), markdownlint 0, links, skills, hook-catalog,
hook-output-shape, vendored drift, context-closure pin, tool-mappings idempotent.
…vation

One blocking finding on 9565d9f, and it landed in the paragraph about this
exact mistake.

The correction that repeated the error it corrects
The previous commit widened the retired-wording enumeration from six emitters to
nine, and one of the three it added was `iterate` -- a twelve-line alias stub
whose whole body points at `ardi`. It carries no claim wording at all, and it IS
`ardi`, which the next two lines name as the emitter that said something else.
So the sentence put the same skill on both sides of its own contrast, inside the
passage whose subject is that enumerating from the files in front of you fails
silently. `gip` and the orchestrator, the other two additions, are genuine.

That commit was billed as a line-break fix. Expanding a factual enumeration
inside it is how the error got in without review attention.

Also from the same round, non-blocking
- "Three retired wordings" against "two predecessors" was a granularity shift
  between full strings and two-word invariants, never stated, and "All three now
  read" lost its antecedent when the sentence was split into two groups. Both
  now count invariants, which is the unit every matcher uses.
- The derivation command offered in place of the enumeration missed two of the
  emitters the prose names: `handoff` opens a multi-line body so its closing
  quote is on another line, and the orchestrator is a `.py` outside the
  `skills/*/SKILL.md` pathspec. Widened the pathspec and matched the opening
  quote only. Verified it now returns both retired invariants.
- Filed #2172: `clean-branches` checks for work claims with an EMPTY code block,
  so it has no matcher and no release-term handling. It was invisible to this
  branch's sweep by construction -- it names no wording, so a wording-based grep
  cannot find it -- and its failure direction is a deletion rather than a skip.

Verified with the script CI actually runs (`d-morrison/gha@v2`, not the pinned
`Morrison-Lab/gha` copy, per #2165): no lines missing semantic breaks. Plus
110/110 hook tests, links, skills, markdownlint 0, context-closure pin, and a
grep confirming no emitter anywhere still posts a retired wording.
One blocking finding on 5aa36bb, in the same paragraph as the last two.

The derivation offered in place of an enumeration could not reach two of the
emitters the prose beside it names. Keying on `--(body|message) "` looks tighter
and misses exactly the emitters least like the others: `gip` states its claim as
quoted prose inside a worker brief, and the orchestrator builds the body as a
Python f-string on a different line from the flag. So a reader following the
instruction to derive rather than enumerate would have re-derived a six-emitter
set and dropped those two -- the failure the section's own Don't describes.

Now keyed on the wordings across the widened pathspec. Verified per emitter: the
new pattern returns hits for the orchestrator, `gip`, `pr-on-claim`, `handoff`,
`claim-pr` and `ardi`; the old one returned zero for the first two. The cost is
that it also returns matcher and prose lines, so it wants a skim rather than a
count -- stated in the text rather than left for the reader to discover.

Also corrected the two stale "six" counts the enumeration fix left behind:
seven skills carried `paws off`, eight emitters counting the orchestrator.
`commands/release-pr.md`'s was added by this branch, so it was a new false count
rather than an inherited one.

Verified with the script CI actually runs: no lines missing semantic breaks.
Plus 110/110 hook tests, links, skills, markdownlint 0, hook-catalog,
hook-output-shape, context-closure pin.
@d-morrison
d-morrison marked this pull request as ready for review August 24, 2026 22:59
…ranch's words

`main` gained eight commits, one of them a996c0b acting on #2148 --- the issue
this branch filed for the three skill files it declined to reflow, precisely
because reflowing them inside this PR would have buried the real diff in churn.
So the conflict is the expected consequence of having deferred correctly, and it
resolves the way that intends: take main's reflow wholesale, then reapply the
word-level changes on top.

- skills/ardia: main's reflowed bullet, with `a still-live "paws off" claim
  comment stands` narrowed to `a still-live claim comment stands`.
- skills/config-ai: main's reflow, with `claim-pr`'s "paws off" comment` narrowed
  to `claim-pr`'s claim comment`.
- skills/gip: main's reflow, with the claim wording moved to `please hold off`
  and the agent-disclosure marker line re-added.

Verified after resolution: no retired wording survives in any of the three, no
conflict markers remain, the real new-line-breaks gate passes (main's reflow is
what satisfies it here, not mine), and 110/110 hook tests, links, skills,
markdownlint, hook-catalog and the context-closure pin are all green.
@github-actions

This comment has been minimized.

@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 from the requesting conversation, so it is visible here rather than only in chat:

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

@github-actions

github-actions Bot commented Aug 24, 2026

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

2026-08-24 23:31 UTC

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@d-morrison

Copy link
Copy Markdown
Collaborator Author

/review

@github-actions

Copy link
Copy Markdown
Contributor

👀 Claude Review Dispatchedrun reviewing PR #2131 at b744d6a.

@github-actions

Copy link
Copy Markdown
Contributor

Claude finished reviewView run


Code review — #2131

Summary of changes: Two related changes bundled together (per the author's own PR note, both edit the same lines): (1) rewords the "paws off" claim-comment convention to more professional language ("please hold off …") across ~20 skill/doc files, while preserving backward-compatible detection of the retired paws off/back off wordings; and (2) introduces a new corpus-wide rule (shared/workflow/disclose-agent-authorship.md) requiring every agent-posted forge comment to end with a _Posted by Claude Code (AI agent) --- not written by a human._ marker, backed by a new warn-only PreToolUse hook (hooks/require-agent-disclosure.py, dual-registered for Bash and mcp__github__.*) with an extensive 110-case test suite (hooks/test-require-agent-disclosure.py).

Verification performed:

  • Ran python3 hooks/test-require-agent-disclosure.py — all 110 cases pass.
  • Ran python3 scripts/validate-skills.py and python3 scripts/check-links.py — clean (0 broken links, all skills/manifests valid).
  • Confirmed hooks/hooks.json is valid JSON, and the Bash vs mcp__github__.* registrations for require-agent-disclosure.py are correctly scoped (no double-firing on one tool call).
  • Confirmed the new marker text doesn't collide with scripts/check-pr-fully-clean.py's REVIEW_BODY_MARKERS/REVIEW_AGENT_MARKERS tuples, as the diff claims.
  • Confirmed no live/unintentional leftover paws off or back off wording remains outside the deliberately-preserved historical/backward-compat references.
  • Fed several additional hand-crafted edge cases (escaped quotes, for-loop bodies, case-insensitive marker match, a comment body that itself quotes gh pr comment) through guard.verdict() beyond the shipped test suite — all behaved correctly (warn where expected, silent where expected).
  • Verified the two grep commands documented in disclose-agent-authorship.md actually produce the output the prose describes (finds exactly the two Dependabot sites plus the doc's own quoting line).
  • Checked the new LIST_DISCUSSIONS/VIEW_DISCUSSION/COMMENT_DISCUSSION/ANSWER_DISCUSSION MCP tool names added to tool-mappings.yml/tool-mappings.md against MCP_POST_TOOLS in the hook — consistent, and mcp__github__discussion_comment_write is the one used in both places.
  • Confirmed no other code in the repo calls guard.verdict() besides the test file, matching its documented "kept for the test suite" purpose.

Findings: None that meet the high-signal bar (compile/parse errors, definite wrong-result logic, or clear unambiguous CLAUDE.md violations). This diff is almost entirely prose/documentation plus one well-isolated, warn-only hook with unusually thorough self-testing — the PR's own history (11 adversarial review rounds pre-push, per the claim comment) and the round-by-round comments baked into the test file (# round-2 review finding 8, # round-6: ...) show the near-misses I would normally look for (whole-sentence claim matching, heredoc body attribution, per-segment vs per-call judging, -F vs --body-file unreadable-vs-missing distinction, MCP tool coverage) were already found and fixed in earlier rounds, and my independent probing did not surface anything beyond that.

Two very minor, non-blocking observations (not filed as findings since neither is a defect):

  • The hook intentionally does not implement the "genuine bot token" exemption (documented explicitly in its own docstring as a known, accepted false-positive on skills/claude-agent-workflow/SKILL.md's in-workflow reply) — this is disclosed honestly in the code, so not a finding.
  • shared/workflow/claim-pr.md's "Removing it is a deliberate later edit, not tidying to do in passing" note about eventually dropping the paws off/back off back-compat alternation is a good practice worth keeping in mind for a future cleanup PR, but is out of scope here.

Verdict

Ready for merge

Reviewed commit: b744d6a

@github-actions

Copy link
Copy Markdown
Contributor

💰 Cost: $3.0713 (review) — run

@dem-extra1
dem-extra1 merged commit c3da9e1 into main Aug 24, 2026
17 checks passed
@dem-extra1
dem-extra1 deleted the claude/paws-off-phrasing-6c5f20 branch August 24, 2026 23:30
d-morrison added a commit that referenced this pull request Aug 25, 2026
/#2185 (#2207)

* ums: learnings from three review rounds plus a cross-vendor pass on #2185

Five entries, from PR #2131/#2185's review lifecycle:

- self-review-fallback.md + .cases.md: a CLEAN same-vendor verdict is a
  cross-vendor trigger, not only a failed one. Two same-vendor readings
  (11 pre-push adversarial rounds, and claude-review's "Ready for merge")
  cleared #2131 at b744d6a; codex then returned 11 findings, 8 blocking.
  Supplies the missing half of the existing case record, which names its
  own limit as covering a reviewer that was down rather than clean.
- adversarial-self-review.md: a PR's visible review history is rationale
  you cannot withhold. The claude-review verdict named the prior rounds
  and the test file's round-N markers in its own justification.
- least-flexible-tool.md: third occurrence of the regex-instead-of-lexer
  class, recorded per ums's recurrence step. Filed as #2189.
- algorithmatize-checks.md: two more mutation misdiagnoses, both under
  outcomes already listed; count recorded, plus when to check an anchor.
- fixtures-are-not-evidence.md: where the specification is a written
  rule, quote its literal text into the fixture.
- claim-pr.md: second occurrence of the concurrent-session collision,
  with different parents rather than matching ones.

Two adversarial review rounds ran pre-push; round 1 returned 11 findings
and round 2 returned 10, all addressed.

* ums: correct the #2185 causal history, the verification count, and three overreaching claims

Round-3 adversarial review findings, all addressed:
- least-flexible-tool.md: at 10909ff the regex was `-c\s`, which cannot
  match mid-word. The mid-word false positive was created by the widening to
  attached/= forms, and three rounds then patched the boundary. Restated as
  one widening forcing three narrowings, which is the same rule from the
  other side.
- adversarial-self-review.md: nine verification steps, not ten (derived from
  the comment body, not restated from a reviewer's count); exact quotation
  where the prose said "in its words"; two bullets reworded to name
  observable actions rather than mental states.
- self-review-fallback.cases.md: the case record asserted "why it probed no
  further", which the sibling section added in the same commit explicitly
  retracts; now scoped to the verdict's justification. A third live
  explanation (a different findings threshold) added.
- algorithmatize-checks.md: the anchor-matched-nothing case belongs to the
  inapplicable-mutation outcome, not outcome four; Don't half added.
- fixtures-are-not-evidence.md: cite the rule's file, not a volatile line.

* ums: stop narrating a branched commit history, and split the two mutation cases

Round-4 adversarial review findings:
- least-flexible-tool.md: cf195e4's parent is 10909ff, not 3b8d04e --
  the two are concurrent siblings merged by 5c577a5, so no linear 'three
  rounds then patched' sequence exists. Three attempts at that narrative
  were each wrong in a new way. Rewritten to the claims that are derivable:
  the matcher's start state, its end state, the three lookbehind forms, and
  the count. Drops --request-changes from the false-positive pair, since
  COMMENT_FLAG_RE gates close/reopen and never sees a gh pr review segment.
- algorithmatize-checks.md: the second instance is the parent entry's
  exception, not an example of it -- the mutation was fine and the suite
  lacked a discriminating fixture. Split, and the entry's ordering marked
  as a default the pass-condition entry's identity check settles.
- self-review-fallback.cases.md: deduped a cross-reference stated twice in
  seven lines.
- 'denies'/'contradict'/'by construction' softened to what the evidence
  carries.

* ums: derive the order from git rather than advising against it, and drop an inert evidence item

Round-5 adversarial review findings:
- least-flexible-tool.md: the 'order is unrecoverable' framing was a
  rationalization of three earlier failed narrations, and contradicted the
  same passage's own ordered account. The order IS recoverable in one
  command per commit; the entry now says to run 'git log -1 --format=%P'
  before narrating a fix history, which is the lesson four rounds actually
  taught. Count corrected to one writing plus two rewrites, and the
  intermediate unanchored form named, since the final regex correctly does
  not match the compliant command the passage cites.
- claim-pr.md: '--comment=' was inert -- '--comment\b' already matches
  '--comment=x' because the boundary sits between t and '='. Executed both
  hook revisions to confirm. Replaced with the two verified items, and the
  inert one kept as the reason to execute rather than read both diffs.
- self-review-fallback.md: 'depth in one family' imports
  learn-from-review-findings' term for a converging series' search space to
  describe a vendor blind spot, which spans families -- the cited record's
  own round markers span several. Reworded to the vendor's reachable region.
- algorithmatize-checks.md: heading no longer calls both rows misdiagnosed,
  which the body supports for neither; the two discriminating questions are
  now stated once, in order.
- adversarial-self-review.md: dropped an unsourced statistical claim.
- self-review-fallback.cases.md: named the referent behind 'it answered
  twice over', and restored the justification-versus-effort scoping clause.

* ums: drop the causal chain the entry never needed, and quote the regex that actually warned

Round-6 adversarial review findings. Five rounds each found a factual error
in a different narration of which #2185 commit responded to which, while the
count and the regex forms survived every round untouched -- so this applies
the entry's own thesis to itself and changes the shape rather than tuning
the same knob a sixth time.

- least-flexible-tool.md: states what each revision WAS and drops what each
  was a RESPONSE to. The widened form is now 3b8d04e's actual
  '-c(?:\s|=|\S)', which is the only revision that warns on the compliant
  command (executed against all four); the previously quoted form shipped
  already anchored and matches nothing. The six rounds are recorded as the
  entry's second lesson, with 'git merge-base --is-ancestor' as the
  instrument, since 'git log --format=%P' reports immediate parents only and
  cannot separate a sibling from a descendant four commits down.
- claim-pr.md: named the two commits instead of theirs/mine, and the Do
  bullet now says to execute each side rather than read its diff, which is
  the lesson the paragraph above it actually teaches.
- algorithmatize-checks.md: one row was misread, not both; named the
  mutation instead of a pronoun whose nearest antecedent was the anchor.
- self-review-fallback.cases.md: the threshold reading is not the only one
  with a cheap remedy.

* ums: state the four forms without any causal or self-congratulatory framing

Round-7 adversarial review findings:
- least-flexible-tool.md: 'went in to stop that' and 'a widening forced a run
  of narrowings' were the same causal claim the entry says it dropped, and
  git refutes it (cf195e4 branched from 10909ff, not from 3b8d04e). The
  entry now lists four forms and asserts nothing about which answered which.
  The self-referential paragraph claimed only the causal chain ever broke and
  named five prior narrations; both were false and both flattered the fix, so
  it is cut to the checkable core. Boundary form pinned to 15b63d9 rather
  than to a moving branch head, and the --is-ancestor bullet now names its
  operand order, which decides the answer.
- claim-pr.md: 'their --comment= alternative' had cf195e4 as its nearest
  antecedent, which is the side that dropped it; named the commit and the
  direction. Deduped a clause repeated near-verbatim two lines apart.
- self-review-fallback.cases.md: dropped a cost figure not sourced by
  anything the record links, and which carried no weight.
- algorithmatize-checks.md: the new Do now names the sibling Do that
  prescribes the stronger remedy, and says why a check is still needed.

* ums: the eleven rounds did not read the reviewed head, and four edits produced five forms

Round-8 adversarial review findings, the first two of them factual errors in
the case record's headline:

- self-review-fallback.cases.md: 'two same-vendor readings cleared that head'
  was false of one of them. The claim comment says eleven rounds ran before
  the FIRST push, and four substantive commits landed after it, three of them
  changing matcher or derivation logic. Only claude-review read b744d6a.
  Restated as one verdict at the head plus eleven rounds of same-vendor depth
  on an earlier state, which is what the record can support.
  self-review-fallback.md's 'eleven of them and one of them' inherited the
  same reading and is corrected with it.
- least-flexible-tool.md: four edits produce five forms, and the passage said
  four forms while enumerating five. Separated the two counts.
  The meta-paragraph claimed the entry attributes nothing, while the sentence
  seven lines above attributes the quote-boundary form to the false positive
  its own commit message names -- a linear successor, so the attribution is
  sound and the meta-claim was the overreach.
  'the layer that answers the question' hedged to 'would answer', since #2189
  is a proposal and shlex.split raises on unbalanced quotes.
  --is-ancestor's exit status read three-valued, per errexit-is-not-uniform.
- self-review-fallback.md: two framing overreaches, a scope claim over
  sentences that carry no trigger, and 'no artifact at all' over a case whose
  primary produced a full verdict comment.

* ums: derive the pre-push gap from the branch's own commit messages

Round-9 adversarial review findings:
- self-review-fallback.cases.md: 'four substantive commits earlier'
  overstated the gap ~4x, in the record's own favour. The branch's commit
  messages name the state each round read (594fdce: 'One blocking finding
  on 5aa36bb'), so the last state read is 5aa36bb -- one branch commit
  (9 insertions, 4 deletions) plus the origin/main merge from the reviewed
  head. Recorded as the narrow gap it is, which strengthens the record
  rather than weakening it: the eleven rounds had substantially read the
  work codex found eight blocking defects in. Also fixed the cell's other
  defect, that eleven rounds read eleven different states so no single
  value could be right; and disambiguated 'readings' from 'explanations'.
- least-flexible-tool.md: 'where a token begins' is refuted by the
  passage's own second edit, which asks what may follow the flag; widened
  to 'boundaries'. Attribution sentence given its real subject.
- self-review-fallback.md: the narrowed scope claim still read as 'every
  trigger-naming sentence prescribes cross-vendor', which is false of three
  paragraphs above it that prescribe a self-review.
- algorithmatize-checks.md: named ANY_BODY_FLAG_RE instead of a pronoun
  whose nearest antecedent was POST_RE.
- claim-pr.md: 'no merge in it at all' is false one commit back on the
  3b8d04e side; scoped to between the two fixes.

* ums: weaken three sentences to the claims their arguments actually need

Round-10 adversarial review findings. The reviewer's closing observation is
the fix: across ten rounds each repair to a sentence broke it on a new axis,
because the sentences were carrying more precision than the argument needed.

- least-flexible-tool.md: 'linear successor' is false -- every path from
  cf195e4 to 9336348 runs through the 5c577a5 merge, which the same
  paragraph names. Ancestry is what the attribution needs and what the
  entry's own Do bullet tests; --is-ancestor exits 0. Also disambiguated
  'the preceding quote', which read as a quotation given earlier.
- self-review-fallback.md: dropped the four-item appositive, which omitted
  the 'no review workflow configured' failure mode and listed 'contradicting
  itself', which the passage above names in order to exclude it. The head
  claim is true and self-sufficient.
- claim-pr.md: 'no merge between the two fixes' is still false -- ed03e06
  is a main-merge inside the divergence on the 3b8d04e side, and is why the
  parents differ. 'Matching parents nowhere in sight' is the contrast the
  section actually draws.
- self-review-fallback.cases.md: 'reading' carried a review-pass sense and
  an interpretation sense five lines apart; the latter is now 'explanation'
  throughout. Named the noun behind 'Its remedy'. And the codex inference is
  now derived rather than hedged: every file codex raised a blocking finding
  in is byte-identical at 5aa36bb and b744d6a.

* ums: derive the untouched-file set instead of typing it out

Round-11 adversarial review finding. The hand-typed list of files codex
raised blocking findings in did not match what #2177 records, in both
directions: it omitted shared/workflow/disclose-agent-authorship.md and
skills/rescue-closed/SKILL.md, and included AGENTS.md, which #2177 names as
the authority being violated rather than as a site. The conclusion happened
to survive because both omitted files are also unchanged, which is a wrong
derivation reaching a true conclusion by luck -- the exact shape the entry
around it warns about, and the class round 10 was weakening sentences to
eliminate.

Replaced with the intersection, published as the command that computes it:
the files #2185 changed, against the files that moved between the last state
the rounds read and the branch's own last commit. Empty. Only the
origin/main merge touches any of them, and only hooks/hooks.json, from
another PR's work rather than this branch's.

* ums: describe the derived set as the superset it is

Round-12 finding: 'the files #2185 changed to address those findings' is a
restrictive clause that is false of at least one member -- #2185 also carries
an unrelated preferences.md learning. The set is #2185's whole diff, which is
deliberately wider, and width is the conservative direction when the result
is an empty intersection. Said so.

Also strengthened the merge leg's warrant. It rested on authorship ('somebody
else's work'), where what the conclusion needs is that no line the rounds read
changed. 'git diff 5aa36bb b744d6a -- hooks/hooks.json' removes zero lines,
which supplies it directly.

* style: break eight added lines at their mid-line semicolons

CI's check-new-line-breaks runs with NLB_CLAUSE_BREAKS=true and
NLB_CLAUSE_MIN_LENGTH=80, which flags a line of 80+ characters carrying a
mid-line semicolon. scripts/semantic-line-breaks.py does not implement that
rule and in fact wants these eight lines rejoined, so the local tool cannot
be run over this diff without turning the check red again. CI is the
authority here; validate.yml runs check-new-line-breaks against content and
runs semantic-line-breaks.py only through its own unit tests.

* ums: scope the COMMENT_FLAG_RE claim to the unmerged branch, and fix a wrong direction

claude-review round 1 on ff5a9da, both findings verified against the repo:

- least-flexible-tool.md: the entry opened with a present-tense claim that
  COMMENT_FLAG_RE decides the close/reopen comment gate. It does not exist on
  main -- 'git grep COMMENT_FLAG_RE origin/main' returns nothing, and its
  introducing commit 10909ff is not an ancestor of main. It lives only on
  #2185, still open. Once this PR merges, a reader grepping the codebase for
  the construct the entry describes finds nothing. Scoped to that branch and
  dated, per timestamp-volatile-claims.
- self-review-fallback.cases.md: 'in the section linked below' pointed
  forward at nothing -- the file ends three sentences later, and the
  adversarial-self-review link it meant sits two paragraphs above. Named the
  fragment and the direction, per forward-references.
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.

Replace the "paws off" claim phrasing with professional wording (detectors must match both)

2 participants