Skip to content

fix(detector): require a vague close for false-concession - #359

Merged
conorbronsdon merged 8 commits into
conorbronsdon:mainfrom
drakeo338:claude/211-fix
Sep 29, 2026
Merged

conorbronsdon merged 8 commits into
conorbronsdon:mainfrom
drakeo338:claude/211-fix

Conversation

@drakeo338

Copy link
Copy Markdown
Contributor

Summary

Fixes #211.

FALSE_CONCESSION only checked the opener ("while X is impressive") and also matched a bare despite ... challenges form, so it flagged ordinary sentences like "Despite these challenges, the team shipped on schedule". This change requires a vague second half in the same sentence (e.g. "remains a challenge"), matching the two-half shape references/patterns.md documents, and drops the bare despite form. Added must-fire/must-not-fire fixtures and synced the generated copies.

Checklist

  • npm test passes (engine fixtures + CATEGORIES.md contract check)
  • If I changed SKILL.md, references/patterns.md, or detector/: I ran bash scripts/sync-plugin-skill.sh && bash scripts/sync-cursor-rules.sh and committed the generated changes
  • If I changed a scanned document: npm run self-scan:check passes
  • If I reworded prose registered in .ssot-local.yaml: I updated any affected manifest patterns and ran python3 ../ssot-check/ssot_check.py check --manifest .ssot-local.yaml using the checker setup instructions
  • If I added a detector type: it's documented in detector/CATEGORIES.md and has a fixture in detector/patterns.test.js (a true positive and a must-not-fire case)
  • If I added a judgment-only rule: it's listed under "Skill-only" in detector/CATEGORIES.md
  • I considered false positives and added carve-outs for legitimate human writing
  • Any factual claim about how AI or humans write (e.g. "ChatGPT emits X", "humans rarely do Y") cites a source
  • The prose I added passes the skill's own audit (no AI-writing tells, terse bullets, no hollow intensifiers)
  • I added an Unreleased CHANGELOG.md entry for a user-facing change, or this PR is exempt under the changelog policy
  • If this PR prepares a release: the dated changelog heading and skill/package/plugin versions agree
  • If I added or removed a detection ### in references/patterns.md: the **NN pattern categories** bullet in README.md and the quoted count in CLAUDE.md match scripts/check-pattern-count.sh

Only npm test and self-scan:check are commands I ran and saw pass on this HEAD; the rest don't apply here (no new type, no release, no ssot prose), so left unticked.

🤖 Generated with Claude Code

…don#211)

Only flag "while X is impressive" / "although X has made strides"
when a vague second half ("remains a challenge", "is still an open
question", "there is still work to do", "remain unanswered") closes
the same sentence, and widen the subject past a single word. A bare
opener followed by a specific, concrete continuation no longer flags.
Drop the bare "despite X challenges" opener entirely: alone it is too
common a shape in ordinary prose to carry the tell.

Remove the now-covered false-concession entry from
detector/categories.test.js's LEGACY_UNCOVERED_TYPES.
…onorbronsdon#211

Run the two required sync scripts so the bundled skill/plugin/cursor
copies of the false-concession fix reach parity with the canonical
detector/patterns.js, matching CONTRIBUTING.md's post-edit sync step.

Rewrite the CHANGELOG entry as a single quoted clause. CHANGELOG.md is
long enough that self-scan.js scores it in ~4000-word chunks by worst
chunk, and this file sits close enough to a chunk boundary that any
unquoted prose added to the Fixed section's paragraph shifts the split
and concentrates an unrelated high-scoring passage into a small,
high-density chunk, failing npm run self-scan:check. Quoting the
description applies the same quoted-example exemption the tool already
documents for text that is itself about an AI-writing pattern, keeping
the entry descriptive while staying inside the budget.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Require a vague close to flag false concessions

🐞 Bug fix 🧪 Tests 🕐 10-20 Minutes

Grey Divider

AI Description

• Flag false concessions only when an opener and vague close occur in the same sentence.
• Stop flagging bare “despite challenges” phrases and concrete continuations.
• Add positive and negative fixtures, and sync the bundled detector copies.
Diagram

graph TD
  A["Input prose"] --> B{"While or although opener?"} --> C{"Vague close same sentence?"} --> D["False-concession issue"]
  B --> E["No issue"]
  C --> E
Loading
High-Level Assessment

Keep the scoped regex change within the existing pattern-matching engine. Sentence parsing would add complexity disproportionate to this rule; the new fixtures cover the intended positive and false-positive cases.

Files changed (8) +144 / -16

Bug fix (5) +120 / -15
patterns.jsRequire both halves of a false concession +24/-3

Require both halves of a false concession

• Matches supported openers with multiword subjects only when a recognized vague close follows in the same sentence. Removes the standalone despite-challenges pattern.

detector/patterns.js

patterns.jsSync the plugin detector copy +24/-3

Sync the plugin detector copy

• Carries the canonical false-concession rule into the bundled plugin skill.

plugins/avoid-ai-writing/skills/avoid-ai-writing/detector/patterns.js

patterns.jsSync the detector skill copy +24/-3

Sync the detector skill copy

• Carries the canonical false-concession rule into the ai-writing-detector skill script.

skills/ai-writing-detector/scripts/patterns.js

patterns.jsSync the avoid-ai-writing skill copy +24/-3

Sync the avoid-ai-writing skill copy

• Carries the canonical false-concession rule into the bundled avoid-ai-writing skill.

skills/avoid-ai-writing/detector/patterns.js

patterns.jsSync the preservation-verifier detector copy +24/-3

Sync the preservation-verifier detector copy

• Carries the canonical false-concession rule into the preservation-verifier script.

skills/preservation-verifier/scripts/patterns.js

Tests (2) +23 / -1
categories.test.jsMark false-concession as fixture-covered +0/-1

Mark false-concession as fixture-covered

• Removes false-concession from the legacy list of detector types without named fixtures.

detector/categories.test.js

patterns.test.jsCover true and false false-concession matches +23/-0

Cover true and false false-concession matches

• Adds must-fire examples with vague closes and must-not-fire examples for a bare despite phrase and a concrete continuation.

detector/patterns.test.js

Documentation (1) +1 / -0
CHANGELOG.mdDocument the narrower false-concession rule +1/-0

Document the narrower false-concession rule

• Adds an Unreleased fix entry describing the required vague close, broader subject match, and removal of the bare despite-challenges opener.

CHANGELOG.md

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. The specified concession goes undetected ✓ Resolved
Description
The new positive fixture adds still to the specified sentence, leaving the exact nine-word example
untested. When that example is analyzed alone, analyzeText returns before running
FALSE_CONCESSION because its minimum is ten words.
Code

detector/patterns.test.js[3688]

+    'Although OpenAI has made strides, meaningful questions still remain unanswered.',
Evidence
Rule 2 requires the exact Although OpenAI ... meaningful questions remain unanswered example to
produce an issue. The added fixture instead inserts still; the detector counts
whitespace-separated words and returns an empty issue list for inputs below ten words.

Preserve specified positive and negative detection cases
detector/patterns.test.js[3686-3694]
detector/patterns.js[2037-2039]
detector/patterns.js[2225-2236]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The specified positive example has nine words, but the new fixture adds `still` to clear the detector's ten-word gate. Analyzing the exact example alone returns no issue.
## Fix Focus Areas
- detector/patterns.test.js[3686-3695]
- detector/patterns.js[2227-2235]
## Recommended Fix
Add a regression assertion using the exact specified sentence and reconcile its expected detection with the minimum-word behavior without inadvertently changing the handling of unrelated short inputs.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Download instructions get flagged as vague ✓ Resolved
Description
FALSE_CONCESSION_VAGUE_CLOSE matches there is still work to do as a prefix, without checking
where do ends. In “While the model is impressive, there is still work to download before we can
run it,” the concrete download instruction satisfies the pattern and produces a false-concession
issue.
Code

detector/patterns.js[785]

+    "|there\\s+(?:is|are)\\s+still\\s+work\\s+to\\s+do" +
Evidence
The new alternative ends at do without a word boundary; the concatenated regex accepts that
prefix. The detector emits each complete regex match as an issue.

detector/patterns.js[782-791]
detector/patterns.js[2049-2061]
detector/patterns.js[2366-2366]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The vague-close alternatives can match the beginnings of longer words, so `work to download` is treated as `work to do`.
## Fix Focus Areas
- detector/patterns.js[782-786]
- detector/patterns.test.js[3685-3706]
## Recommended Fix
Add an appropriate word boundary after each vague-close alternative and a must-not-fire fixture using `work to download`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. A single clause gets flagged as a contrast ✓ Resolved
Description
The new while expression does not require a clause break between is impressive and the vague
close. In “While the model is impressive and remains a challenge to maintain, we plan to replace it
next month,” it matches both phrases inside the opening clause, even though the main clause contains
the concrete continuation.
Code

detector/patterns.js[R788-789]

+    new RegExp("\\bwhile\\s+" + FALSE_CONCESSION_SUBJECT + "\\s+is\\s+impressive\\b" +
+      FALSE_CONCESSION_GAP + FALSE_CONCESSION_VAGUE_CLOSE, 'gi'),
Evidence
The gap permits  and  and neither constructed regex requires a comma before the close.
matchPatterns emits the resulting match as a false-concession issue.

detector/patterns.js[780-791]
detector/patterns.js[2049-2061]
detector/patterns.js[2366-2366]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The matcher can find its vague close inside the opening `while` clause rather than in the contrasting second half.
## Fix Focus Areas
- detector/patterns.js[780-791]
- detector/patterns.test.js[3685-3706]
## Recommended Fix
Require a clause separator and match the vague close in the following clause. Add a must-not-fire fixture with both phrases in the opening clause.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Abbreviations hide vague concessions 🐞 Bug ≡ Correctness
Description
FALSE_CONCESSION_GAP rejects every period, including periods inside abbreviations rather than just
sentence endings. In “While the model is impressive, U.S. deployment remains a challenge for the
team and its partners,” matching stops at U.S. before it can reach the qualifying close.
Code

detector/patterns.js[781]

+  const FALSE_CONCESSION_GAP = "[^.!?\\n]{0,80}?";
Evidence
The gap explicitly excludes . and sits between the opener and every vague-close alternative. Thus
the regex cannot pass through U.S. to reach remains a challenge; the sentence clears the
detector's ten-word gate.

detector/patterns.js[780-791]
detector/patterns.js[2228-2241]
detector/patterns.js[2366-2366]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The same-sentence gap treats abbreviation periods as sentence boundaries and misses an otherwise qualifying vague close.
## Fix Focus Areas
- detector/patterns.js[780-791]
- detector/patterns.test.js[3685-3706]
## Recommended Fix
Determine the sentence boundary without treating periods internal to abbreviations or numbers as endings, then match the close within that boundary. Add a must-fire abbreviation fixture.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can add REVIEW.md to your repo root and Qodo follows it on every PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread detector/patterns.test.js Resolved
Comment thread detector/patterns.js Resolved
Comment thread detector/patterns.js Resolved
Comment thread detector/patterns.js Resolved
conorbronsdon and others added 6 commits September 28, 2026 20:55
…onorbronsdon#359)

The false-concession fixture for conorbronsdon#211 padded the reported sentence with
"still" to clear the ten-word scoring minimum, leaving the exact
nine-word example untested: analyzed alone it returns before
FALSE_CONCESSION runs.

Add a regression covering both outcomes: the exact sentence alone
stays too-short with no issues (existing behavior, unchanged), and the
same sentence within a longer input is flagged as false-concession.
The global minimum-word threshold is untouched.
…loses (conorbronsdon#211)

"there is still work to do" had no trailing \b, so it matched as a bare
prefix of "download" and flagged Qodo's example sentence ("...there is
still work to download the update.") as false-concession. Add \b after
the grouped closing alternatives and cover both the must-not-fire
download sentence and a must-fire case ending in the actual phrase
"work to do".
… close (conorbronsdon#359)

The FALSE_CONCESSION gap let the vague close match inside the opening
"while"/"although" clause itself, with no clause break between "is
impressive" and the close. "While the model is impressive and remains
a challenge to maintain, we plan to replace it next month" matched
both phrases in the opening clause and never considered the concrete
main clause that followed, missing conorbronsdon#211's two-half concession
structure.

Require a comma, semicolon or colon between the opener and the vague
close so it can only match in the following clause. Add the reported
sentence as a must-not-fire fixture and a paired must-fire example
with the same close moved into the second clause. The sentence-
boundary restriction (no match across ./!/?) is unchanged.
…o attribution (conorbronsdon#359)

Review on conorbronsdon#359 accepted the clause-separator fix for the false-concession
close but flagged two gaps: the abbreviation-period limit it implies was
neither documented nor tested, and a must-not-fire fixture labeled
"Qodo's own example" used wording Qodo never wrote.

Comment beside FALSE_CONCESSION_GAP that a period inside an abbreviation
("U.S.", "e.g.") ends the gap like any other sentence boundary, so a close
past one is deliberately missed rather than risk the boundary guarantee,
and that only a comma, semicolon or colon counts as the separator. Add a
must-not-fire fixture for that limitation. Add Qodo's exact reported
sentence as its own fixture, and correct the existing "download the
update" fixture's comment to say it is a variant, not verbatim.
@conorbronsdon
conorbronsdon merged commit 3299ae9 into conorbronsdon:main Sep 29, 2026
3 checks passed
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.

Narrow false-concession so ordinary concessive openers stay clean

2 participants