New:Introducing Socket Scanning for VS Code Marketplace Extensions.Learn more →
Get Started

blastline

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

blastline

Graph-backed test impact and blast radius for CI and PRs, built on CGraph

Source
npmnpm
Version
0.7.0
Version published
Weekly downloads
1
-50%
Maintainers
1
Weekly downloads
 
Created
Source
blastline — graph-backed test impact and blast radius

npm License: MIT TypeScript CI selection escapes MCP Built on CGraph PRs welcome

Diff in · impacted tests and blast radius out · deterministic, fail-open, served by a CGraph code graph.

Contents

Why blastline? · How selection works · Benchmarks · Quick start · GitHub Action · Use with coding agents · CLI reference · Status & roadmap · Contributing · License

Why blastline?

Deciding which tests a diff needs means knowing what the change reaches — and that answer lives in the relationships between files, not in the diff. Every existing test-impact tool is locked to one build system (Bazel, Nx), one language via coverage instrumentation (pytest-testmon), or a closed SaaS. blastline computes it from a deterministic code graph instead, so it works on any repo CGraph can extract.

🎯 Impacted tests, not guessesChanged lines map to graph symbols; a transitive-dependents walk finds every test that reaches them. blastline tests main..HEAD | xargs vitest run runs exactly those.
💥 Blast radius on every PRThe GitHub Action comments each PR with the change's transitive dependents, with file:line — the reviewer sees what the diff touches before reading it.
🛡️ Safe superset, fail-openThe contract is "run at least these," never "safe to skip." Unmapped files, a stale graph, an under-extracted graph, or an oversized diff all fail open to a full run, with machine-readable reasons.
⚡ Deterministic & instantSelection is pure graph traversal: same repo state + same diff → byte-identical output, in under a millisecond on a built graph. No ML ranking, no coverage run.
🤖 Built for coding agentsblastline mcp serves blastline_tests / blastline_blast over MCP, so an agent checks what its edit reaches before opening the PR.

The pitch in one line: test-impact analysis is a graph-reachability problem — blastline is the reachability query, packaged as a CLI, a PR comment, and an MCP tool, with fail-open honesty when the graph can't vouch for a diff.

How selection works

git diff --unified=0 base..head
   → changed line ranges                (src/diff.ts)
   → innermost graph node per line      (src/mapping.ts — whole-file adds seed every symbol)
   → transitive dependents walk         (src/impact.ts — CALLS, imports, re_exports, contains, inherits)
   → intersect with test files          (src/detect.ts — JS/TS, pytest, Go, C/C++ conventions)
   → subset + blast radius, or ALL with reasons

Fail-open triggers, each a typed reason in the output:

ReasonFires when
unmapped-filea changed file has no graph node (configs, lockfiles, assets) — declare irrelevant paths with --ignore
stale-graphthe graph fails a content-root pin (--expect-root, or --daemon-verify against the live CGraph daemon), or graph.json is older than the head commit
sparse-graphthe graph averages under 3 edges per file — an under-extracted graph produces subsets that look smart and are blind, so blastline refuses
disconnected-teststests can forward-reach under 25% of the code's symbols — the graph passed the density floor but is blind for selection (how broken Go/Python extraction presents)
diff-too-largethe diff touches more files than --max-files (default 200)
graph-unavailableno readable graph.json

Pure deletions map against a --base-graph when supplied, and degrade to the file node (a superset-safe approximation) when not.

Benchmarks

Replayed the last 20 first-parent commits of two repos, scoring every selection against the tests each commit's author co-changed (methodology and full tables):

production Next.js appes-toolkit (1,508 files)
subset rate19/2018/20
co-changed tests selected21/22¹41/41
mean selection25.7% of suite4.7% of ~670 tests
deterministic (double-run)yesyes

¹ The one "miss" is a false positive of the co-change proxy itself — the author added new tests for unchanged code.

The benchmark also caught CGraph silently deleting 650 of es-toolkit's 1,508 files from the graph (CGraph #39/#40, fixed in #42) — before the fix, blastline's sparse-graph guard correctly refused to produce subsets there. That loop is the design working: guard until the graph is trustworthy, select once it is.

The safety audit

Replay benchmarks are a snapshot; the safety audit is the standing check. On every push to this repo's main, safety-audit.yml replays blastline's selection for the pushed range, runs the full suite, and records whether any failing test file fell outside the selection — an escape, the one outcome "safe superset" forbids. Each run appends a JSONL record to the safety-ledger branch and rolls the ledger into the badge above; a recorded escape turns it red and fails the run loudly. The evidence accumulates with every merge instead of resting on a one-time benchmark.

Quick start

Prerequisites: Node 20+, a CGraph binary on PATH, and a git repo.

npm install -g blastline        # or zero-install: npx blastline ...

cgraph --root ./src --out cgraph-out          # build the graph once
blastline tests main..HEAD | xargs vitest run
blastline blast main..HEAD                    # dependents with file:line

Working from source (contributors): git clone https://github.com/Nxtsoft/blastline && cd blastline && bun install && bun run build, then node dist/cli.js ….

GitHub Action

- uses: actions/checkout@v4
  with:
    fetch-depth: 0
- uses: Nxtsoft/blastline@v0
  id: blastline
  with:
    graph-path: cgraph-out/graph.json
    base-graph-command: cgraph --root . --out "$BLASTLINE_BASE_OUT"
    github-token: ${{ github.token }}   # posts/updates the PR comment
    ignore: |
      \.md$
      ^docs/

Outputs: kind (subset or all) and tests (newline-separated files), so a downstream job can run only the selected tests. The comment shows the impacted tests and a collapsible blast radius; on fail-open it says "run the full suite" and why. Supply graph-path from a cache keyed on your source tree, or let the run fail open honestly when no graph exists.

base-graph-command automates deletion mapping: the action checks out the range's base commit into a worktree, runs your graph-build command there (it must write $BLASTLINE_BASE_OUT/graph.json), and passes the result as the base graph. A PR that deletes a file then selects the surviving tests that depended on the deleted symbols, instead of failing open on an unmapped path — the deleted code exists only in the base graph, so its dependents are walked there and translated back to head paths. Skip the input and deletions keep the documented safe degradation.

Cross-repo selection over seam graphs

For microservice estates, point blastline at a CGraph seam — the fused graph that joins per-service code graphs at their wire contracts:

cgraph seam gen  --seam seam.json --graphs backend=backend/graph.json --out drop
cgraph seam fuse --seam drop/chunk_00.json   --graph backend=backend/graph.json --graph ml-api=ml-api/graph.json --out fused

blastline tests main..HEAD --repo ./ml-api --graph fused/graph.json

A provider-side change then selects consumer-side tests across the repo boundary: a schema node is anchored to its canonical file, so editing it seeds the contract, and the walk crosses RESPONDS_WITH → the endpoint → CONSUMED_AT/MIRRORED_BY (dependency-flipped — the consumer depends on the contract, not vice versa) → the consumer's call sites and mirror types → their tests. Consumer-only changes never flow backwards into the provider. Verified end-to-end against a real seam gen/seam fuse pipeline: one provider schema edit selected exactly the consumer's test, with the contract chain in the blast radius.

Use with coding agents

blastline mcp speaks MCP over stdio: newline-delimited JSON-RPC 2.0 implementing initialize, tools/list, and tools/call (protocol 2024-11-05) — the same surface CGraph's own MCP server speaks.

{
  "mcpServers": {
    "blastline": { "command": "blastline", "args": ["mcp"] }
  }
}
ToolWhat it answers
blastline_tests"Which test files does this diff reach?" — the set to run before claiming done
blastline_blast"What does this change touch, transitively?" — with file:line, before the edit is final

Both take repo plus a range or raw diff text, with graph_path, ignore, and min_density passthroughs. A kind: "all" answer means run the full suite; the reasons say why — fail-open selections are returned as data, never as protocol errors, so an agent always gets an actionable answer.

CLI reference

⌨️ commands and options
blastline tests <base>..<head> [options]     # impacted test files (list or --json)
blastline blast <base>..<head> [options]     # transitive dependents with file:line
blastline comment <base>..<head> [options]   # the PR-comment markdown
blastline mcp                                # MCP server over stdio
OptionMeaning
--repo <path>repository to diff (default: cwd)
--graph <path>CGraph graph.json for head (default: <repo>/cgraph-out/graph.json)
--base-graph <path>graph.json for base — improves pure-deletion mapping
--diff-file <path>read a unified-0 diff from a file instead of running git
--ignore <regex>repo-relative paths declared irrelevant (repeatable)
--max-files <n>fail open above this many changed files (default 200)
--min-density <n>fail open below this edges-per-file floor (default 3)
--jsonstructured output

tests/blast print one item per line (empty = clean subset with nothing impacted); on fail-open they print ALL to stdout and one JSON reason per line to stderr, exit code 0 — consumers branch on the output, not the exit code.

Status & roadmap

Scope, stated plainly: all four v1 language families are replay-verified — on their benchmarks every semantically selectable author-co-changed test was selected. TypeScript (Vitest/Jest): 41/41 on es-toolkit. Python (pytest conventions): 3/3 on itsdangerous, after CGraph#46 rebuilt Python import resolution. Go (*_test.go): 10/10 on gorilla/mux, after CGraph#47 added interface-dispatch edges (implements/dispatches_to plus the member-call rescue for names like mux's eight Matches that satisfy one interface); Go's dispatch fan-out makes its subsets larger (mean 37.7% of suite — a 2.7× reduction) — safety was chosen over selectivity. C/C++ (*_test.{c,cc,cpp,cxx} / test_*, the googletest/ctest convention): 62/62 on CGraph itself, after CGraph#52 made calls to overloaded functions edge to every member of the overload set; mean subset 22.4% of the suite, with every fail-open an honest build-system change (CMakeLists, submodule pointers). The pipeline is unit-tested (57 tests) and replay-benchmarked on six repos; the Action and MCP server are exercised end-to-end in CI.

Runner recipes per ecosystem:

blastline tests main..HEAD | xargs vitest run                                  # TS/JS
blastline tests main..HEAD | xargs pytest                                      # Python
blastline tests main..HEAD | xargs -n1 dirname | sort -u | xargs go test       # Go (tests run per package)
blastline tests main..HEAD | xargs -n1 basename | sed -E 's/\.(c|cc|cpp|cxx)$//' \
  | xargs -I{} ctest --test-dir build -R {}                                    # C/C++ (ctest name match)

Freshness pinning shipped in 0.3.0: CGraph one-shot builds embed a sha256-merkle-v1 content root, every subset carries it as provenance (CLI JSON, MCP payloads, and the PR-comment footer), --expect-root pins a selection to an exact tree, and --daemon-verify pins against the live CGraph daemon's root — verified end-to-end against a running graphd (match → subset; edited tree → fail-open naming both roots). Cross-repo selection over seam graphs shipped in 0.4.0 (see above) — the proposal roadmap is complete.

Contributing

Issues and PRs welcome. The spec-driven history lives in openspec/ — proposal, spike findings, and benchmark results — and is the fastest way to understand why the tool is shaped the way it is. bun run build && bun run test is the gate.

License

MIT.

Keywords

test-impact-analysis

FAQs

Package last updated on 20 Aug 2026

Related posts