diff --git a/.antigravity/skills/code-review/SKILL.md b/.antigravity/skills/code-review/SKILL.md index 4c0d5d9..55ca75c 100644 --- a/.antigravity/skills/code-review/SKILL.md +++ b/.antigravity/skills/code-review/SKILL.md @@ -49,7 +49,7 @@ Write the following structure into `agent-code-review.md`. `N` is the review ite - One paragraph on overall risk and clarity. - Finding counts: High X, Medium Y, Low Z. -- If no High or Medium remain and no Low blockers, state: **Verdict: good to go**. Automation depends on detecting this exact string. +- If no High or Medium remain and no Low blockers, close the Summary with **Verdict: good to go** -- on its own line, or as the last sentence of the final paragraph. Automation detects this exact string, so do not hedge it with trailing prose ("good to go, but ..."). ## Findings diff --git a/.claude/commands/code-review.md b/.claude/commands/code-review.md index 57dacdd..a7e721e 100644 --- a/.claude/commands/code-review.md +++ b/.claude/commands/code-review.md @@ -48,7 +48,7 @@ Write the following structure into `agent-code-review.md`. `N` is the review ite - One paragraph on overall risk and clarity. - Finding counts: High X, Medium Y, Low Z. -- If no High or Medium remain and no Low blockers, state: **Verdict: good to go**. Automation depends on detecting this exact string. +- If no High or Medium remain and no Low blockers, close the Summary with **Verdict: good to go** -- on its own line, or as the last sentence of the final paragraph. Automation detects this exact string, so do not hedge it with trailing prose ("good to go, but ..."). ## Findings diff --git a/.codex/skills/code-review/SKILL.md b/.codex/skills/code-review/SKILL.md index 4c0d5d9..55ca75c 100644 --- a/.codex/skills/code-review/SKILL.md +++ b/.codex/skills/code-review/SKILL.md @@ -49,7 +49,7 @@ Write the following structure into `agent-code-review.md`. `N` is the review ite - One paragraph on overall risk and clarity. - Finding counts: High X, Medium Y, Low Z. -- If no High or Medium remain and no Low blockers, state: **Verdict: good to go**. Automation depends on detecting this exact string. +- If no High or Medium remain and no Low blockers, close the Summary with **Verdict: good to go** -- on its own line, or as the last sentence of the final paragraph. Automation detects this exact string, so do not hedge it with trailing prose ("good to go, but ..."). ## Findings diff --git a/.copilot/skills/code-review/SKILL.md b/.copilot/skills/code-review/SKILL.md index 4c0d5d9..55ca75c 100644 --- a/.copilot/skills/code-review/SKILL.md +++ b/.copilot/skills/code-review/SKILL.md @@ -49,7 +49,7 @@ Write the following structure into `agent-code-review.md`. `N` is the review ite - One paragraph on overall risk and clarity. - Finding counts: High X, Medium Y, Low Z. -- If no High or Medium remain and no Low blockers, state: **Verdict: good to go**. Automation depends on detecting this exact string. +- If no High or Medium remain and no Low blockers, close the Summary with **Verdict: good to go** -- on its own line, or as the last sentence of the final paragraph. Automation detects this exact string, so do not hedge it with trailing prose ("good to go, but ..."). ## Findings diff --git a/.kimi-code/skills/code-review/SKILL.md b/.kimi-code/skills/code-review/SKILL.md index 4c0d5d9..55ca75c 100644 --- a/.kimi-code/skills/code-review/SKILL.md +++ b/.kimi-code/skills/code-review/SKILL.md @@ -49,7 +49,7 @@ Write the following structure into `agent-code-review.md`. `N` is the review ite - One paragraph on overall risk and clarity. - Finding counts: High X, Medium Y, Low Z. -- If no High or Medium remain and no Low blockers, state: **Verdict: good to go**. Automation depends on detecting this exact string. +- If no High or Medium remain and no Low blockers, close the Summary with **Verdict: good to go** -- on its own line, or as the last sentence of the final paragraph. Automation detects this exact string, so do not hedge it with trailing prose ("good to go, but ..."). ## Findings diff --git a/lib/lib-review-loop b/lib/lib-review-loop index 8fadec5..30fd2a1 100644 --- a/lib/lib-review-loop +++ b/lib/lib-review-loop @@ -334,12 +334,17 @@ test_review_clean() { local content content=$(<"$REVIEW_FILE") - # Only a verdict line of its own signals clean. Emphasis is stripped so - # "**Verdict: good to go**" and "**Verdict:** good to go" both match; the - # anchors keep both quoting prose ("the report says Verdict: good to go") - # and hedged prose ("Verdict: good to go, but ...") from counting. + # The verdict must open a line -- optionally after a bullet, quote or heading + # marker -- or close a sentence at the end of one, which is where reviewers + # asked to "state it in the Summary" actually put it. Emphasis is stripped + # so "**Verdict: good to go**" and "**Verdict:** good to go" both match. + # + # What still must not count: quoting prose ("the report says Verdict: good + # to go"), because "says " is not a sentence boundary, and hedged prose + # ("Verdict: good to go, but ..."), because the trailing anchor allows only + # an optional "." or "!" after the phrase. if printf '%s\n' "$content" | tr -d '*' \ - | grep -qiE '^[[:space:]]*([-+][[:space:]]*)?verdict[[:space:]]*:[[:space:]]*good to go[[:space:]]*[.!]?[[:space:]]*$'; then + | grep -qiE '(^[[:space:]]*([-+>#]+[[:space:]]*)?|[.!?][[:space:]]+)verdict[[:space:]]*:[[:space:]]*good to go[[:space:]]*[.!]?[[:space:]]*$'; then return 0 fi diff --git a/prompts/code-review-followup.md b/prompts/code-review-followup.md index 5a599fe..fdac74a 100644 --- a/prompts/code-review-followup.md +++ b/prompts/code-review-followup.md @@ -12,4 +12,4 @@ Rules: - Do not repeat findings that were addressed, or that the developer declined with a reasonable justification. - Remove completed items; report only new or still-unresolved findings. - Overwrite `agent-code-review.md` using the same structured report format as the initial review (Summary with finding counts, Findings section, etc.), with the iteration number provided in your instructions. -- Apply the same severity definitions as the initial review. If no High or Medium issues remain and no Low severity blockers (a Low blocks only when it violates an explicit project rule), state in the Summary: **Verdict: good to go**. +- Apply the same severity definitions as the initial review. If no High or Medium issues remain and no Low severity blockers (a Low blocks only when it violates an explicit project rule), close the Summary with **Verdict: good to go** -- on its own line, or as the last sentence of the final paragraph, never hedged with trailing prose. diff --git a/prompts/code-review.md b/prompts/code-review.md index fecad0f..17bdf8e 100644 --- a/prompts/code-review.md +++ b/prompts/code-review.md @@ -44,7 +44,7 @@ Write the following structure into `agent-code-review.md`. `N` is the review ite - One paragraph on overall risk and clarity. - Finding counts: High X, Medium Y, Low Z. -- If no High or Medium remain and no Low blockers, state: **Verdict: good to go**. Automation depends on detecting this exact string. +- If no High or Medium remain and no Low blockers, close the Summary with **Verdict: good to go** -- on its own line, or as the last sentence of the final paragraph. Automation detects this exact string, so do not hedge it with trailing prose ("good to go, but ..."). ## Findings diff --git a/test/lib-review-loop.bats b/test/lib-review-loop.bats index ae6f8e4..50f0e12 100644 --- a/test/lib-review-loop.bats +++ b/test/lib-review-loop.bats @@ -304,6 +304,42 @@ EOF assert_failure } +# The prompts ask the reviewer to state the verdict "in the Summary", and agents +# oblige by ending the summary paragraph with it. Requiring a line of its own +# made every such review read as unclean: the loop then burned all five cycles on +# an already-clean diff and reported MAX ITERATIONS REACHED. +@test "test_review_clean accepts a verdict closing a summary paragraph" { + source_lib + REVIEW_FILE="$TEST_TMPDIR/review.md" + echo "The suite passes and linters are clean. Finding counts: High 0, Medium 0, Low 0. **Verdict: good to go**." > "$REVIEW_FILE" + run test_review_clean + assert_success +} + +@test "test_review_clean accepts a verdict after a sentence on a heading line" { + source_lib + REVIEW_FILE="$TEST_TMPDIR/review.md" + echo "## Verdict: good to go" > "$REVIEW_FILE" + run test_review_clean + assert_success +} + +@test "test_review_clean rejects a paragraph verdict hedged with trailing prose" { + source_lib + REVIEW_FILE="$TEST_TMPDIR/review.md" + echo "All checks ran. **Verdict: good to go, but 2 High findings remain**." > "$REVIEW_FILE" + run test_review_clean + assert_failure +} + +@test "test_review_clean still ignores a mid-sentence verdict after a period" { + source_lib + REVIEW_FILE="$TEST_TMPDIR/review.md" + echo "Re-run it. The report will say Verdict: good to go." > "$REVIEW_FILE" + run test_review_clean + assert_failure +} + @test "build_improvement_prompt includes all parameters" { source_lib run build_improvement_prompt "/path/to/plan.md" "/path/to/feedback.md" "codex" "2" "5"