repro-surgeon
v0.2.1
Published
Shrink a failing application into an independently verified reproduction.
Downloads
456
Maintainers
Readme
Repro Surgeon
Shrink the project. Keep the failure. Hand over something runnable.
“Can you provide a minimal reproduction?” is often the hardest part of a bug report.
Repro Surgeon takes a failing npm application, removes source that isn't needed for your failure check, and exports a smaller project with its own verifier. It tests every accepted change and checks the export again with a fresh dependency installation. The reducer applies its edits to temporary copies, not your source checkout. Supplied commands retain your filesystem permissions; see the execution boundary.
No account. Repro Surgeon has no telemetry or source-upload service.
Actual bundled demonstration: 3,173 → 520 source bytes, 10 → 5 files, 115 evaluations. The assertion remains pinned. This is a small seeded example, not a framework benchmark. Replay the run and download its verified result · Method and evidence.
Try it
Requires Node.js 22.18+ and npm 10+, on Linux or macOS.
npx [email protected] demo --out ./rounding-repro
node ./rounding-repro/repro/.repro/verify.mjsNo clone or configuration needed. The first command reduces the bundled example, generates an offline report and verifies the export three times. The second runs the exported verifier independently.
Choose a new output directory for each run. Open ./rounding-repro/report.html to inspect the result. The verifier exits successfully when the application's expected failure occurs; the original application command still exits with its configured failure code. You can also explore the recorded walkthrough in your browser before installing anything.
Install the packaged release for your own projects:
npm install --global [email protected]The same package is available from the versioned GitHub release, with a checksum. You can also run npx [email protected] --help.
Reduce your application
Start from a project whose failure reproduces with a finite command and a committed npm lockfile.
repro-surgeon init ./my-app \
--match "the distinctive diagnostic from your failure" \
-- npm run build
repro-surgeon doctor ./my-app --json
repro-surgeon reduce ./my-app --out ./my-app-reproReplace the example diagnostic with text from your actual error. Use several --match fragments to identify it precisely, and --forbid to reject a known competing error. Pin your test harness or other essential source with preserve in repro-surgeon.json.
{
"version": 1,
"command": ["npm", "run", "build"],
"oracle": {
"exitCode": 1,
"allOf": ["Parsing CSS source code failed", "Unexpected end of input"],
"noneOf": ["Module not found"]
},
"preserve": ["scripts/check.mjs"],
"budget": { "maxEvaluations": 200, "maxSeconds": 900 }
}The failure check is the contract. A broad phrase such as failed can match the wrong problem. Try a fixed control and a deliberately different failure before starting an expensive run. Repeated matching output does not establish identical semantic root cause.
What you get
my-app-repro/
├── repro/ # Reduced application to inspect and share
│ ├── package.json
│ ├── package-lock.json
│ ├── … retained source
│ └── .repro/
│ ├── README.md # Runtime, command and verification instructions
│ ├── config.json
│ ├── LICENSE # License for the generated verifier code
│ ├── manifest.json # Source and metadata integrity records
│ └── verify.mjs # Runs without Repro Surgeon installed
├── report.html # Offline, searchable evidence
├── report.json # Machine-readable report
└── … private run state # Original snapshots and raw logs; keep privateThe report shows accepted, rejected and invalid trials, before/after metrics, remaining files, the exact failure check and the fresh verification outcome. Search and filters work offline.
Review the repro/ folder before sharing it. Exclusions and review findings help locate sensitive material; they do not certify that a reproduction is safe to publish. The full run directory contains original source and logs.
How the reduction works
- Establish the failure. Three uncached baseline observations must match.
- Try smaller source. Remove file groups and complements, syntax elements, JSON fields and direct npm dependencies. Keep retained dependency versions and integrity records fixed.
- Confirm every accepted candidate. Require two matching executions. Timeouts, signals, installation failures, output overflow and spawn failures are invalid, never evidence of preservation.
- Export and verify independently. Copy the result into a separate temporary directory, install dependencies afresh and check three times. The standalone verifier checks the exported file manifest as well.
The search seeks fewer source bytes, then fewer files, fewer declared dependencies and fewer total bytes. It finds the smallest candidate reached by the enabled passes within your budget; it does not promise a globally minimal program.
Stop, resume and inspect
Press Ctrl-C to checkpoint the accepted snapshot and stop child processes.
repro-surgeon resume ./my-app-repro --max-evaluations 500 --max-seconds 1800
repro-surgeon verify ./my-app-repro/repro
repro-surgeon report ./my-app-reproResume budgets are new total limits, including earlier search time and evaluations. After a normal search budget stop, the current best result still gets a separately bounded export verification. A baseline interrupted before calibration completes remains paused. Resume requires the same tool, Node, npm, platform and architecture. See troubleshooting for crash locks and incompatible environments.
Supported scope
| Works with | Boundary |
|---|---|
| Single-package npm applications | package-lock.json version 2 or 3; public portable registry dependencies |
| Deterministic command and build failures | Explicit argv, exit code, required and forbidden literal text |
| Next.js application structure | App/Pages Router detection and conservative entrypoint protection |
| JavaScript, TypeScript, JSX, TSX and JSON | Syntax-aware source edits and JSON/JSONC field removal |
| Linux and macOS | Runtime/OS matrix in CI; Windows is not yet supported |
npm workspaces, pnpm/Yarn lockfiles, shrinkwrap, local/Git/private dependencies, browser recording, and managed service startup are outside this release. Existing syntax errors can be preserved by file reduction; malformed files are skipped by structural passes. Full configuration · Architecture · Validation.
Local execution, plainly
Every baseline, candidate and verification invocation of your configured command starts with a temporary project copy as its working directory. The reducer applies its source edits to those copies. That starting directory is not a security sandbox: a command can change directory, use ../ or absolute paths, and read or write any file its process permissions allow, including the original checkout. There is no automatic path rewriting or filesystem confinement. You control and must trust the command and its dependencies.
For an additional boundary, follow the container recipe with source mounted read-only. It keeps the original mount unwritable through ordinary filesystem operations and gives the run a separate writable output directory. Read-only source is still readable; containers do not make arbitrary code harmless.
Install scripts are disabled unless you enable them. Network access is required for uncached dependencies; your command may also use the network. Common credentials, environment files, generated output and symlinks are excluded from source snapshots, not hidden from host processes. Configured checks and dependency installations inherit only operating-system essentials plus explicitly requested environment variables. init writes the requested configuration file; doctor inspects inputs and probes npm --version without running your configured command. Security policy.
Run the checks
To develop from source:
git clone https://github.com/pavangupta352/repro-surgeon.git
cd repro-surgeon
npm ci
npm run check
npm run test:package
node dist/cli.js demo --out /tmp/rounding-reproThe native suite does not fetch framework fixture dependencies. Run these optional integrations separately; they download public pinned packages and the Next.js checks take several minutes:
node scripts/validate-dependency.mjs /tmp/repro-dependency-validation
node scripts/validate-pages.mjs /tmp/repro-pages-validation
node scripts/validate-next.mjs /tmp/repro-framework-validationChoose new output directories. The scripts check fixed and different-error controls, preserve the original source, and verify the reduced exports. Measured results and limitations.
Related work and contributions
This builds on delta debugging and shares the goal of property-preserving reduction with treereduce. Replay addresses recorded execution. Repro Surgeon focuses on the path from an application source tree to an independently installable, verified reproduction. No comparative superiority is claimed.
A frozen single-file comparison against treereduce is published with inputs, controls and query counts. From the same 938-byte authored example, treereduce produced 334 bytes in 2.956 seconds and Repro Surgeon produced 248 bytes in 4.080 seconds. Both passed three fresh checks. That mixed result describes this fixture only; it is not a full-application benchmark.
Have a failure this cannot reduce reliably? A small licensed case with a precise failure check is especially useful. Read CONTRIBUTING.md, open an issue, or improve a reducer with a regression test.
Maintained by Pavan. MIT licensed.

