fix(engine): a claim word inside a longer word is not a claim
`selftest_checks-402` — a count of checks that exist — carried BADGE-STATIC-CLAIM through censuses 03, 05 and 06 because `tests?` matched the letters inside "selfTESTs". repo-mailbox disputed it every round; org-ops measured and concluded the finding was false (coord, 2026-08-12). Their proposed test was renaming the visible label to "Checks". Measured here first: that does NOT clear it, because the URL slug is scanned too. The rule was reading claim words as substrings anywhere in either. Matching word by word fixes it. Splitting on every non-alphanumeric run rather than leaning on `\b` is what avoids the opposite defect — shields.io writes a space as `_`, so `\btests\b` would have gone quiet on the genuine claim `tests-402_passing`. Both directions are pinned. Measured across all 19 local clones: 20 badge findings before, 20 after, exactly one converted (repo-mailbox WARN -> OK). No other repo moved. The count-vs-result split org-ops proposed is deliberately NOT built: the one measured case is fully explained by the substring bug, and a rule for `tests-402` that no repo has produced would be speculation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lb7XmJGLnFSX9U7tgS7fKk
This commit is contained in:
parent
9073d3535d
commit
3955b10c4d
2 changed files with 32 additions and 2 deletions
|
|
@ -556,7 +556,15 @@ export function checkVersionConsistency({ pluginVersion, readmeBadge, changelogT
|
|||
// llm-ingestion-pipeline-security. `build`/`ci`/`passing` already catch the
|
||||
// run-asserting compounds ("build status", "CI status"), so dropping the bare
|
||||
// word loses no real detection.
|
||||
const CLAIM_BADGE = /(tests?|build|ci|coverage|passing)/i;
|
||||
// Matched WORD by word, never as a substring. `selftest_checks-402` — a count
|
||||
// of checks that exist, asserting nothing about a run — fired for three
|
||||
// censuses because `tests?` matched the letters inside "selfTESTs" (org-ops,
|
||||
// 2026-08-12, on repo-mailbox's dispute). Splitting on every non-alphanumeric
|
||||
// run, rather than leaning on `\b`, is what keeps the fix from creating the
|
||||
// opposite defect: shields.io writes a space as `_`, so `\btests\b` would have
|
||||
// gone quiet on the genuine claim `tests-402_passing`.
|
||||
const CLAIM_WORD = /^(tests?|build|ci|coverage|passing)$/i;
|
||||
const claimsARun = (s) => s.split(/[^a-z0-9]+/i).some((w) => CLAIM_WORD.test(w));
|
||||
|
||||
// Counting badges needs a NARROWER rule than detecting a dishonest one. The
|
||||
// claim check reads any image, any host, on purpose. Here the opposite error
|
||||
|
|
@ -587,7 +595,7 @@ export function checkBadges({ readme, present }) {
|
|||
const linked = linkTarget !== undefined;
|
||||
const label = `${m[2]} ${m[3]}`;
|
||||
if (BADGE_URL.test(m[3])) badgeCount++;
|
||||
if (!CLAIM_BADGE.test(label)) continue;
|
||||
if (!claimsARun(label)) continue;
|
||||
if (!linked) {
|
||||
findings.push({
|
||||
level: 'WARN',
|
||||
|
|
|
|||
|
|
@ -824,6 +824,28 @@ test('a build- or CI-status badge is still caught — only bare "status" was too
|
|||
assert.equal(ci.some((x) => x.code === 'BADGE-STATIC-CLAIM'), true);
|
||||
});
|
||||
|
||||
// Reported by org-ops (coord, 2026-08-12) on behalf of repo-mailbox, which
|
||||
// carried this WARN through censuses 03, 05 and 06 and disputed it every time.
|
||||
// Measured here before changing anything: `selftest_checks-402` fired because
|
||||
// `tests?` matched the SUBSTRING inside "selfTESTs" — a count of checks that
|
||||
// exist, not an assertion that any of them passed. The rule read a claim word
|
||||
// wherever the letters appeared, so it also fired on the URL slug alone: their
|
||||
// proposed fix of renaming the visible label to "Checks" was measured NOT to
|
||||
// clear it. Only a word-level match does.
|
||||
test('a claim word inside a longer word is not a claim — `selftest` is not `tests`', () => {
|
||||
const f = checkBadges({ readme: '' });
|
||||
assert.equal(f.some((x) => x.code === 'BADGE-STATIC-CLAIM'), false);
|
||||
});
|
||||
|
||||
// The separator matters as much as the boundary: shields.io writes a space as
|
||||
// `_`, so a claim word can arrive with word characters on both sides. Matching
|
||||
// on `\b` alone would have gone quiet on a real claim while fixing the false
|
||||
// one — the worse direction of the same defect.
|
||||
test('an underscore-separated claim word is still a claim — `402_passing`', () => {
|
||||
const f = checkBadges({ readme: '' });
|
||||
assert.equal(f.some((x) => x.code === 'BADGE-STATIC-CLAIM'), true);
|
||||
});
|
||||
|
||||
// ----------------------------------------------------------- badge crowding
|
||||
|
||||
// Trockman et al., ICSE 2018 (n=294,941 npm packages) measured a non-linear
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue