CI reruns your whole suite for a one-line change, then a flaky test fails at random and blocks it. testrazor fixes both from artifacts your suite already emits. No account, no API key, no network.
$ testrazor impact --changed src/discount.ts selected 2 of 3 test files, 1 skipped (33%) run test/cart.test.ts run test/discount.test.ts $ testrazor flake --report run1.xml --report run2.xml 1 flaky of 3 tests over 2 runs flaky cart :: sums a cart score 1.00 $ testrazor gate --report run2.xml -q q.json result: PASS # flaky red is quarantined $ testrazor gate --report run2.xml # no quarantine result: FAIL # a real failure still blocks
The problem
Two everyday CI failures have nothing to do with your code and both cost you the same way: slow feedback and lost trust in the build.
A one-line change reruns thousands of tests for minutes. Most of them could not possibly be affected by what you touched.
A test fails at random, turns the build red and blocks a correct change. People start re-running CI until it is green, so real failures get ignored too.
Once red is sometimes noise, green stops being a signal. testrazor makes the fast path safe and keeps a real failure loud.
How impact works
Standard coverage is aggregated across a whole run, so it cannot say which test touched which line. A static import graph can, deterministically. testrazor selects the test files that transitively import a changed source file.
git diff --name-only (or an explicit --changed list from your CI).import, export ... from, require and dynamic import() specifiers across the source tree.How flake works
Across two or more runs, a test that both passes and fails is flaky and gets quarantined. A test that only ever fails is a real bug, so it is never quarantined and the gate always shows it.
test run1 run2 verdict cart::sums pass fail flaky → quarantine auth::expiry fail fail real failure → gate fails price::clamp pass pass stable score = min(passes,fails) / floor(runs/2) flaky = passes > 0 and fails > 0
In your pipeline
The composite Action runs the CLI, writes the report to the job summary and upserts a single PR comment keyed by a hidden marker so re-runs update in place. It exits with the CLI's own code, so a real failure fails the job.
- uses: zkasuran/testrazor@v1 with: args: gate --report reports/junit.xml --quarantine .testrazor/quarantine.json comment: "true"
Built with Kiro
testrazor was built with Kiro's spec-driven workflow. The .kiro/ directory is committed so you can see the process, not just the result.
Behaviour as EARS acceptance criteria, a fixed architecture and a task plan. Every module maps back to a numbered requirement.
The rules the agent followed on every file: one dependency, pure engines, the honest-scope rule.
One hook runs typecheck and tests on save, one checks that every test still maps to an acceptance criterion.
The design changed mid-build through the spec: an early draft used coverage for impact, but standard coverage cannot say which test hit which line, so it moved to an import graph. Every test name carries a @covers <req>.<n> tag, so the suite is a live traceability matrix over the requirements.
Honest scope
Anything that emits JUnit XML. jest, vitest, pytest, mocha, go test through a converter.
By resolving relative import, export and require specifiers, including .js specifiers that resolve to .ts sources.
Quick start
git clone https://github.com/zkasuran/testrazor && cd testrazor npm ci && npm run build node dist/cli.js impact --root fixtures/sample-repo --changed src/discount.ts # then try flake and gate on fixtures/sample-repo/runs/*.xml