Skip to content

test: mutation-testing pilot for server/wire-parsers (Stryker + tap-runner) - #710

Merged
lis186 merged 4 commits into
mainfrom
test/stryker-wire-parsers
Oct 20, 2026
Merged

lis186 merged 4 commits into
mainfrom
test/stryker-wire-parsers

Conversation

@lis186

@lis186 lis186 commented Oct 17, 2026

Copy link
Copy Markdown
Owner

A mutation-testing pilot (Stryker) scoped to server/wire-parsers/**. The changes are tests, config and docs only, with no production code. The new npm run test:mutation script is not part of npm test and not in CI.

Setup

  • devDependencies: @stryker-mutator/core and @stryker-mutator/tap-runner (^10). The lockfile only gains new entries; no existing package version changes.
  • Runner: the tap runner rather than the vitest runner. The suite is node:test, which the vitest runner can't execute. Each test file runs as node --require ./test/helpers/home-guard.js --test-reporter=tap <file>, so the HOME guard is kept. coverageAnalysis: perTest limits each mutant to the test files that cover it.
  • stryker.config.mjs: mutate: server/wire-parsers/**, 12 related test files listed explicitly, concurrency: 2, incremental cache at reports/stryker-incremental.json. reports/ and .stryker-tmp/ are git-ignored.
  • Docs: docs/mutation-testing.md (with a pointer from docs/testing.md).

Scores (1,209 mutants)

File Before After
anthropic.js 69.66% 98.60%
openai.js 61.98% 96.58%
index.js 100% 100%
Total 64.43% (779 killed / 350 survived / 80 no-cov) 97.19% (1175 / 29 / 5)

Time and memory (8 cores / 15 GiB, nice, concurrency 2)

  • Full run: 71–84 s. Stryker peak RSS is about 0.5 GB, the whole process tree about 0.6 GB.
  • Incremental run after a test edit: 30–40 s. With nothing changed: about 4 s.
  • MemAvailable never dropped more than about 0.5 GB (lowest was 10.3 GB).

Triage

  • Tests added: 96 tests in test/wire-parsers-{anthropic,openai}-edges.test.js, all with synthetic inputs. They cover behaviour no test was asserting:
    • where usage, response ids and tool calls are read from in the SSE stream
    • the cache_creation split (no coverage before)
    • conversation-id hashing
    • registerPromptVersion rules
    • the order in which session id, cwd and agent type are taken from headers, metadata and body
    • the Workspace Path:/CWD: regexes
    • Grok noise-path detection
    • which value wins in buildEntryFields
    • Grok priced at the xai rate, using an injected rate table
  • 34 equivalent survivors are left on purpose, each with a reason in the docs. They fall into a few groups:
    • placeholder defaults that still fail the next check
    • redundant type guards on primitive input
    • code that sets a value it already had
    • the pricing-provider argument for Claude models, and fallbacks that can't be reached
    • regex alternatives already covered by a fallback
  • // Stryker disable comments: 0. They would have required production-file edits.

Verification

  • Unit group: 2167/2167 pass.
  • stryker run --force: same scores, 71 s.
  • Note: test/launch-decision.test.js fails if CCXRAY_FAIL_CLOSED is inherited from the environment. That happens on main too.

Recommendation on expanding (each as its own follow-up)

  1. server/pricing.js + default-rates.js: next. Highest value, since they produce cost figures. Expect about 1,000 mutants, 2–3 min and about 0.6 GB. Tests should inject rates (setRateTable) or use a temp CCXRAY_PRICING_CACHE so results don't depend on the on-disk cache.
  2. server/config*: high value (context-window maths). Expect about 900 mutants and 3–5 min. Use unit tests only.
  3. Fail-closed / launch-decision: valuable but needs care. Unit tests only: 1–2 min. The real fail-open paths are only covered by e2e tests that spawn processes, which would push a run to 10–30 min, so leave those out at first. The config should strip inherited CCXRAY_* variables.

…unner)

Adds an opt-in `npm run test:mutation` (not in npm test or CI) scoped to
server/wire-parsers/**. The suite is node:test, so the tap runner is used
instead of vitest; each file runs under test/helpers/home-guard.js.

Triage of surviving mutants added two edge-case test files; score
64.43% -> 97.19% (anthropic 69.66 -> 98.60, openai 61.98 -> 96.58).
The 34 remaining survivors are equivalent and listed in
docs/mutation-testing.md. No production code changes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-17T16:48:41.563109Z 82739a6 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 82739a694c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread package.json
Comment on lines +58 to +59
"@stryker-mutator/core": "^10.0.0",
"@stryker-mutator/tap-runner": "^10.0.0",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use a mutation runner supported on Node 20

The new npm run test:mutation command installs Stryker 10, but the lockfile declares Node >=22.0.0 for both @stryker-mutator/core and the TAP runner, while this project advertises Node >=18 and its CI matrix includes Node 20. Stryker’s v10 release notes explicitly state that Node 20 support was dropped, so contributors using a supported Node 18/20 environment cannot reliably use the advertised pilot, and engine-strict installs will reject it. Pin a Node-20-compatible Stryker release or clearly separate and enforce a Node 22 requirement for this command.

Useful? React with 👍 / 👎.

@lis186
lis186 merged commit e836a4f into main Oct 20, 2026
4 checks passed
lis186 added a commit that referenced this pull request Oct 20, 2026
…ends on #710) (#714)

* test: mutation-testing pilot for server/wire-parsers (Stryker + tap-runner)

Adds an opt-in `npm run test:mutation` (not in npm test or CI) scoped to
server/wire-parsers/**. The suite is node:test, so the tap runner is used
instead of vitest; each file runs under test/helpers/home-guard.js.

Triage of surviving mutants added two edge-case test files; score
64.43% -> 97.19% (anthropic 69.66 -> 98.60, openai 61.98 -> 96.58).
The 34 remaining survivors are equivalent and listed in
docs/mutation-testing.md. No production code changes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* test: extend mutation testing to pricing.js and default-rates.js

Adds server/pricing.js and server/default-rates.js to the Stryker scope with
their unit test files. Every test process gets a nonexistent
CCXRAY_PRICING_CACHE and a no-network preload, so a mutant that breaks the
cache/TTL checks cannot download LiteLLM or touch pricing-cache.json.

New edge tests cover ratesFromLiteLLMEntry, fetchPricing's cache and
(stubbed) network paths, the synchronous context-table load, prefix matching,
cache-file validation and the 1h cache-creation rate. pricing.js 41.38% ->
83.62%, default-rates.js 65.57% -> 88.93%; remaining survivors are listed as
equivalent/unreachable in docs/mutation-testing.md.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* test: assert socket forwarding in anthropic detectSession; document Node prerequisite for Stryker pilot

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>

* test: guard net.Socket#connect in no-network preload; fix mutation doc file count

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>

---------

Co-authored-by: Claude Opus 5.5 <[email protected]>
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