Skip to content

test: consolidate the scripts/lib equivalent-mutant annotations and premise pins - #1845

Merged
mrbobbytables merged 5 commits into
mainfrom
quality/equivalence-premises
Oct 23, 2026
Merged

mrbobbytables merged 5 commits into
mainfrom
quality/equivalence-premises

Conversation

@mrbobbytables

Copy link
Copy Markdown
Member

Consolidates five open, file-disjoint PRs that each annotate verified-equivalent Stryker mutants in scripts/lib/ and pin the premise behind each annotation in a test. Each original commit is cherry-picked unchanged, with one exception noted below.

Original Scope
#1816 uri-safety.mjs, url-safety.mjs (7 mutants)
#1828 svg-active-content.mjs prolog-walk termination guard
#1832 mdx-active-content.mjs (10 mutants)
#1833 project-assets.mjs (3 mutants)
#1835 architecture-content.mjs, architecture-pages.mjs, cncf-wp-api.mjs, github.mjs

Change from the originals: #1835's tests/mutation-equivalence-premises.test.mjs carried two within-file clones that pushed check:duplication to 247 against the 245 ceiling (the reason its Lint check failed). The four paginated-fetch tests now share a countPages helper, which brings the count back to the ceiling.

All five originals also predate #1841, so their Validate checks failed on the withdrawn braces advisory; this branch is based on current main.

Local verification: npm run test:unit:coverage:check (3592 tests, coverage gate green), check:duplication (245/245, 33/35), check:lint, check:unused, check:spelling, prettier --check on changed files.

Closes #1813
Closes #1827
Closes #1831
Closes #1834
Refs #1788

Supersedes #1816, #1828, #1832, #1833, #1835.

hivecommons-hive Bot and others added 5 commits October 23, 2026 12:48
…nd url-safety.mjs

Signed-off-by: scanner <280983584+hivecommons-hive[bot]@users.noreply.github.com>
`startsWithDoctype()` walks the prolog with a loop rather than a pattern
because nested lazy repetition over `<?...?>` and `<!--...-->` backtracks
exponentially, as its own comment says. The loop moved the hazard rather
than removing it: `source.indexOf(closer, index + 2)` yields -1 for a
prolog node that never closes, so without the `end === -1` return `index`
rewinds to `closer.length - 1`, the whitespace skip at the top of the loop
carries it back to the same unterminated `<?`, and the walk never ends.
`hasDoctype('\n<?xml version="1.0"')` -- a file truncated in transit
mid-declaration -- is enough to reach it, and every validator here calls
these entry points on SVG files it did not write.

Nothing pinned that guard: deleting the return, or flipping the sentinel
it compares against, left the whole suite passing. Add cases that answer
for eight truncated prologs across all four entry points, each under a
deadline of its own, because the failure is non-termination rather than a
wrong answer; and two that keep the walk doing its real job behind closed
prolog nodes.

Annotate the file's other fifteen surviving mutants as equivalent. Each
reason states a property that can be checked: `sax`'s `resume()` is
exactly the `this.error = null` the line above already did; `url.decode()`
already trims the whitespace inside `url(...)`; css-tree emits a `url(`
Function token only when the argument opens with a quote, so the
`text.toLowerCase() !== 'url('` test is already decided by the String
check beside it; `pi` is the last of the seven event types `parseXml()`
emits and the arms above take the other six. The `skipDepth` test is
split across lines so the directive covers only the redundant half.

scripts/lib/svg-active-content.mjs now scores 100% with no survivors.

Signed-off-by: quality <280983584+hivecommons-hive[bot]@users.noreply.github.com>
…lent

All ten surviving mutants in scripts/lib/mdx-active-content.mjs are
equivalent: a bound that is never reached, a guard a caller already
satisfied, an arm an earlier branch always takes first.

Each equivalence rests on a property of a different function --
literalValue()'s JSON.parse backstop, the dispatch order in scanSource(),
the line:reason dedupe at the end of findActiveContent(), the
pure-deletion contract of unwrapMdxCodeBlocks(). Nothing pinned those
properties, so a change to one would have made the annotation silently
false while the gate stayed green.

Add tests/mdx-active-content-equivalence-premises.test.mjs (26 tests)
asserting each premise, then annotate the ten mutants, each citing its
reason and the test that holds it up.

Three conditions are split across lines so a directive covers only the
redundant operand rather than silencing already-killed siblings on the
same line; the splits change no behaviour.

Closes #1831

Signed-off-by: quality <280983584+hivecommons-hive[bot]@users.noreply.github.com>
The mutation gate leaves three mutants alive in scripts/lib/project-assets.mjs
even though the file reports 100% line and region unit coverage: the '.' in the
artworkMirrorName() dot guard, and the 'https?' in each of artworkUrls()' two
harvest patterns.

All three were applied at their exact column spans and compared against the
unmutated module over a 1074-observation differential sweep of artworkUrls,
artworkPath, artworkMirrorName, artworkMirrorPath and projectAsset, crossing
six schemes with upstream, fork-ref and off-host artwork URLs, extensionless
and mixed-case filenames, query-suffixed paths and both markdown image and
link forms. None of the three changes an observable result, for two reasons:

- the harvest patterns hand every URL to artworkPath(), whose patterns are
  anchored at ^https://, so a cleartext URL the harvest admits is dropped one
  line later;
- with no dot, the extension fallback is the filename's final character, and
  no mirrorable extension is a single character.

Annotate each site with the premise it rests on, so the next sweep does not
re-verify them from scratch. An annotation whose premise quietly stopped
holding would become a silent suppression of a real gap, so both premises are
also asserted directly, following the pattern used for mdx-active-content.mjs.

Signed-off-by: quality <280983584+hivecommons-hive[bot]@users.noreply.github.com>
Triage of the five remaining Stryker survivors outside the files claimed by
open PRs. All five were applied at their exact column spans and verified
equivalent empirically, not by reasoning alone.

Four are now annotated and retired. The fifth, the catch clause in
resolvesToDirectory, is left un-annotated: a 'disable next-line' comment
cannot attach to a catch clause from inside the try block, and a wide
enough disable/restore pair would also suppress the killable BlockStatement
mutant on the try body. It carries an explanatory comment instead.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: quality <280983584+hivecommons-hive[bot]@users.noreply.github.com>
@netlify

netlify Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for endusers ready!

Name Link
🔨 Latest commit 79547da
🔍 Latest deploy log https://app.netlify.com/projects/endusers/deploys/6adb9f53dfc24ff6573fd279
😎 Deploy Preview https://deploy-preview-1845--endusers.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@hivecommons-hive

Copy link
Copy Markdown
Contributor

The End-to-end coverage failure on this PR is the shared incident tracked in #1809, not a problem with this diff: the same 6 accepted region(s) in tests/e2e/fixtures/accepted-regions.json are stale error fails on the default branch (run 39995846213 @ 1d2374f) and on sibling PR #1842. Deferred until the incident closes — the held fix PR #1810 removes the stale fixture entries. No action needed on this PR beyond a re-run once #1810 merges.


🐝 Hive Agent: scanner | Instance: hosted-available-lke648397-260827-5n31 | SHA: unknown

— hive: agent=scanner backend=copilot model=kimi-k3 copilot=1.0.88

@mrbobbytables
mrbobbytables added this pull request to the merge queue Oct 23, 2026
Merged via the queue into main with commit ac2f31b Oct 23, 2026
13 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment