fix(iterate-pr): stop content-classifying review summaries, fix nit punctuation - #311
Conversation
…unctuation
categorizeComment's content fallback had two measured defects: HIGH patterns
matched a word anywhere with no regard for negation ("not a blocker" filed
high), and nit[:\s]/suggestion[:\s]/etc. required a colon or space right
after the word, so "Nit," missed and landed in medium.
Review summaries are now bucketed structurally instead of by content: a
CHANGES_REQUESTED from a non-author reviewer stays high, an explicit
h:/m:/l: marker still wins, otherwise the summary is surfaced but filed low
so it doesn't inflate needs_attention. Summaries narrate findings and will
always contain finding vocabulary, frequently negated, so no pattern list
survives being run over them — the findings themselves still arrive
separately as inline threads and are classified individually.
The inline-comment fallback (still used for review threads and issue
comments) gets word boundaries on the bracketed-class LOW tokens
(nit/suggestion/optional/minor/style) so punctuation stops mattering, plus a
short negation window before HIGH/LOW pattern matches so "not a blocker" and
"no security issue" stop counting as findings.
detectLogaf (the explicit-marker path) is untouched and still wins over
content everywhere, including in review summaries.
Fixes #309
Filing a marker-less summary as `low` fixed the false `high` and introduced a false prompt. `low` means "an optional suggestion, ask the user which to address": step 3 presents low items as a numbered list and `action_required` says so. Measured before this change, a review whose own conclusion was "I did not find any correctness bugs" produced: action_required: "Review low-priority suggestions - ask user which to address" which asks someone to triage a summary that proposes no work. Summaries now go to a `review_summary` bucket, counted as `summary.review_summaries` and reported in `action_required` as nothing at all. Surfaced and countable without being actionable, the same shape `review_in_progress` already uses, and the same reason: some things a caller needs to see are not things a caller needs to act on. `review_summary` is included in the `review_bot_feedback` and `self_review_feedback` tallies even though it is not a priority bucket. Those answer "where did this come from", not "how urgent is it", and leaving it out silently zeroed `self_review_feedback` for an author whose only note is a summary, which is the ordinary shape of a self-review. An explicit `h:`/`m:`/`l:` marker still wins, in a summary as anywhere else, and a reviewer's CHANGES_REQUESTED is still `high` on the review state.
|
@claude /review |
|
Claude finished @thecodedrift's task in 5m 22s —— View job Review completeReview mode: incremental — read 0 prior review thread(s) before reviewing.
FindingsPosted as inline comments (all
Nothing else surfaced past verification — the negation-window sizing (24 chars), the word-boundary fix for |
All four points addressed:
All three code fixes (1-3) were mutation-checked: broke each, confirmed the corresponding new test failed, restored the fix, confirmed it passed again. Full suite (369 tests) and — AI Coding Agent |
Addresses PR #311 review feedback (3 distinct findings, each posted by two review runs, 6 threads total): - `NEGATORS` only covered `not|no|non|without|isn't|is not`, so contractions and bare negative words ("won't", "doesn't", "can't", "cannot", "never", "nothing", etc.) still read as unnegated and reached `high`. Widened the alternation to cover them explicitly, since `\b` doesn't split on an apostrophe the way it splits on a space. - `matchesUnnegated` used a non-global `pattern.exec`, which always returns the left-most match. A negated first occurrence of a HIGH/LOW word was read as covering the whole body, silently dropping a later, genuine occurrence of the same word ("not a blocker overall, but there's a real blocker in the retry logic"). Now clones each pattern with a global flag and checks every occurrence. - The module's top-of-file docblock still said a review summary "defaults to low absent a marker" after a prior commit moved that default to its own `review_summary` bucket. Updated the Categories list and the self-review/review-summary sections to match SKILL.md and the categorizeReviewSummary JSDoc, which were already correct. Also caught in the same review round: SKILL.md's step-3 LOGAF-priority list never mentioned the review_summary bucket at all, so an agent following it literally had no cue to ever process one. Added a "surface, never a fix and never a prompt" entry, and listed review_summary under "when to reply." Each code fix is covered by a new test and was mutation-checked: broke it, confirmed the new test failed, restored it, confirmed the suite passed again.
Summary
categorizeCommentin.agents/skills/iterate-pr/scripts/fetch_pr_feedback.cjshad two measured defects in its content fallback (used when no explicith:/m:/l:marker is present):blocker,security issue,critical, …) matched anywhere in the body with no regard for what preceded them, so a clean review's own closing sentence — "not a blocker", "no security issue" — got filedhigh. Measured on the real review summary of test(cli): cover the tested/failed/refused split on a mixed verify/test run #307.nit[:\s]required a colon or whitespace immediately after the word, so the commonNit,spelling missed and landed inmedium, the bucket the skill auto-fixes without prompting. Measured on a real inline comment from test(cli): cover PlatformBinaryResolution.source and asMatchMode's refusal #304.Fix
CHANGES_REQUESTEDfrom a non-author reviewer still stayshigh(unchanged); an explicith:/m:/l:marker still wins; otherwise the summary is surfaced but filedlowso it doesn't inflateneeds_attention. This applies to both human and review-bot summaries — the test(cli): cover the tested/failed/refused split on a mixed verify/test run #307 misfire was a bot's own review summary. The findings themselves still arrive separately as inline review-thread comments and are classified individually, so nothing is lost.nit,suggestion,optional,minor,style) word boundaries (\bnit\b) so punctuation stops mattering, and refuses a HIGH/LOW match preceded by a negator (not/no/non/without/isn't/is not) within a 24-character window, so "not a blocker" and "no security issue" stop counting as findings.detectLogaf(the explicit-marker path) is untouched, and an explicit marker still wins over everything, including in review summaries — covered by a new test.Self-review summaries stay surfaced and flagged
self_review: true(a PR author can't formally request changes on their own PR);review_in_progressand its precedence inaction_requiredare untouched.Test plan
NODE_OPTIONS= pnpm test:scripts— 364 tests pass (was 356; added tests for negation,Nit,punctuation, marker precedence, and structural review-summary bucketing; updated one existing test whose expected bucket intentionally changed frommediumtolow)NODE_OPTIONS= pnpm lint— passes (typecheck + eslint + built-CLI house-style check)NODE_OPTIONS= node .agents/skills/iterate-pr/scripts/fetch_pr_feedback.cjs --pr 307against the real, merged PR —summary.high: 0,summary.needs_attention: 0, confirming the clean review no longer reads as high-priorityFixes #309