Skip to content

fix(checks): narrow three over-reaching exclusions from CD-318/319/320 - #211

Merged
TAJD merged 1 commit into
mainfrom
fix/review-batch1
Aug 10, 2026
Merged

fix(checks): narrow three over-reaching exclusions from CD-318/319/320#211
TAJD merged 1 commit into
mainfrom
fix/review-batch1

Conversation

@TAJD

@TAJD TAJD commented Aug 10, 2026

Copy link
Copy Markdown
Owner

Follow-up to #207, #208 and #210. An adversarial review of all four merged fixes found three real defects, all of the same shape: an exclusion added to kill a false positive that reaches further than it should.

1. SpellingDialect went blind to any object keyed by a CSS property name

visit_object_property returned early for a CSS-named key, skipping the whole subtree, and CSS_PROPERTY_NAMES contained a dozen words far commoner as ordinary domain keys than as CSS: content, color, order, filter, position, display, width, height, top/left/right/bottom.

Reproduced against the built binary with dialect = "british":

export const msgs = [{ role: 'user', content: 'please analyze the color of every artifact' }]; // 0 findings
export const plain = 'please analyze the color of every artifact';                             // 3 findings

Every OpenAI-shaped message array, every CMS or i18n object keyed content:, silently left the check.

Two changes: only the property's own value is skipped, and only when that value is a string literal — never the subtree. And the ambiguous single words are gone from the list. Nothing is lost by dropping them: a color value is '#fff', an order value is 2; neither has ever carried a dialect word. What remains is the hyphenated surface (background-color, transition-timing-function) plus the unambiguous roots, which is what style={{ … }} actually needs.

2. MaxLineLength silenced JSX prose

visit_jsx_text pushed the whole JSXText span as an atomic token. But JSX text is exactly what Prettier reflows at spaces:

return <p>This is a very long paragraph of ordinary English prose that any formatter would happily reflow…</p>;  // 152 cols, silent
// This is a very long comment of ordinary English prose that any formatter would happily reflow…                // 139 cols, reported

The rule #210 shipped says comments split on whitespace so long prose still reports. JSX text is the same thing and now gets the same treatment.

3. OrphanExport allocated once per import edge for a discarded value

from_test_file was computed for every incoming edge, and matches_substring allocates via .replace('\', "/") unconditionally. Under the default test_imports_count = true the non_test tally is never read, so on a large repo that is one heap allocation per edge for nothing. Now gated on the tally being wanted.

Also

  • Duplicate "accent" entry in CSS_CLASS_HYPHEN_SEGMENTS.
  • The two test cases the review named as missing: prose under a CSS-named key (the case that was broken), and a mixed test + non-test consumer under test_imports_count = false.

Not changed

Per-path options overrides still do not reach plugin checks — filed as CD-326, and a wire-protocol question rather than a bug in #209.

Verification

cargo test --workspace 1410 passed / 8 ignored, cargo clippy --workspace --all-targets -- -D warnings, cargo fmt --all -- --check, cofferdam gen-docs — all green.

Re-validated on real repos (--no-cache --no-baseline, limit 120, dialect = "british"): bestefforttools MaxLineLength 16 and SpellingDialect 85, poker-puzzle 7 and 5, personal-blog 5 and 54.

🤖 Generated with Claude Code

https://claude.ai/code/session_019afugU2bTYCtXn6Vy9dn1v

Adversarial review of the four merged fixes found three real defects.

SpellingDialect skipped an entire object property subtree whenever the
key named a CSS property, and the list included a dozen words far
commoner as ordinary domain keys. A chat message's `{ role, content }`
went completely unscanned, as did `{ content: { title: '...' } }`. Now
only the property's own string value is skipped, and the ambiguous
single words — `content`, `color`, `order`, `filter`, `position`,
`width` and friends — are gone from the list. Their CSS values are
`'#fff'` and `'0 auto'`, which never carried a dialect word, so listing
them bought nothing.

MaxLineLength treated JSX text as an atomic token, so a long paragraph
of prose in a component never reported while the identical sentence in
a comment two lines above did. JSX text reflows at spaces exactly like
a comment; it is no longer collected.

OrphanExport computed test-file membership for every import edge in the
project, allocating in `matches_substring` each time, even though the
`non_test` tally is unread under the default `test_imports_count =
true`. Now computed only when it will be used.

Also: a duplicate `accent` entry, and the two test cases the review
named as missing — prose under a CSS-named key, and a mixed test plus
non-test consumer under the strict reading.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019afugU2bTYCtXn6Vy9dn1v
@github-actions

Copy link
Copy Markdown

Criterion benchmark comparison (PR head vs base branch)

�[1m�[92m   Compiling�[0m cofferdam-checks v0.4.2 (/home/runner/work/cofferdam/cofferdam/crates/cofferdam-checks)
�[1m�[92m   Compiling�[0m cofferdam-engine v0.4.2 (/home/runner/work/cofferdam/cofferdam/crates/cofferdam-engine)
�[1m�[92m    Finished�[0m `bench` profile [optimized] target(s) in 50.97s
�[1m�[92m     Running�[0m benches/engine_bench.rs (target/release/deps/engine_bench-e0ce420cbfc0fb1d)
Gnuplot not found, using plotters backend
Benchmarking full_run_no_cache
Benchmarking full_run_no_cache: Warming up for 3.0000 s
Benchmarking full_run_no_cache: Collecting 20 samples in estimated 7.2760 s (420 iterations)
Benchmarking full_run_no_cache: Analyzing
full_run_no_cache       time:   [16.623 ms 16.687 ms 16.738 ms]
                        change: [-6.0677% -2.4984% +0.6447%] (p = 0.20 > 0.05)
                        No change in performance detected.

Benchmarking single_file_edit_incremental
Benchmarking single_file_edit_incremental: Warming up for 3.0000 s
Benchmarking single_file_edit_incremental: Collecting 20 samples in estimated 5.7284 s (120 iterations)
Benchmarking single_file_edit_incremental: Analyzing
single_file_edit_incremental
                        time:   [7.6114 ms 7.7039 ms 7.8042 ms]
                        change: [-2.1249% -0.5260% +1.1026%] (p = 0.55 > 0.05)
                        No change in performance detected.


@TAJD
TAJD merged commit 715981c into main Aug 10, 2026
18 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.

1 participant