New contributors should start with docs/EXAMPLES.md to see the tool in action, then pick a scoped GitHub issue from docs/GOOD_FIRST_ISSUES.md. Comment on the issue before starting so overlapping work stays visible. Bug reports, usage questions, feature requests, and benchmark proposals use the repository issue templates. Support guidance is collected in SUPPORT.md, and all participation is governed by CODE_OF_CONDUCT.md.
When diagnosing a new fixture, run repomin doctor first (see
docs/DOCTOR.md) to confirm the command and selected adapter
before adding reducer or benchmark changes.
Maintainers preparing a GitHub Release should follow docs/RELEASING.md. It is intentionally separate from the contributor rules because release artifacts require version, checksum, and installation verification.
ReproMin is intentionally organized around small extension points:
- manifest adapters for Maven, Gradle, Python/Pipenv, npm, Composer, MSBuild, Bundler, Cargo, Go, and additional build systems;
- failure oracles for stack traces, test reports, crashes, and flaky failures;
- source reducers backed by parser or compiler syntax trees;
- execution backends for containers and remote workers;
- public benchmark repositories with known reduction targets.
From the repository root, run the standard local checks with one command:
python3 scripts/check_contribution.pyThe preflight checks Markdown files for valid UTF-8, LF line endings, and paired
fenced code blocks, then runs Ruff, byte-compilation, and the complete unit-test
suite without changing tracked source files. The repository's .gitattributes
also asks Git to check out common text files with LF endings; the explicit check
catches files imported with a different encoding or line ending. Its Python and
Ruff caches are cleaned up from a temporary directory after each run. The
documentation check can also be run by itself:
python3 scripts/check_docs.pyInstall Ruff first when it is not already available
(python3 -m pip install ruff). For a documentation-only change, --skip-lint
is available; explain skipped checks in the pull request. When a change adds or
updates an offline fixture, include the benchmark regression too:
python3 scripts/check_contribution.py --with-benchmarksThe benchmark command remains network-free and may skip fixtures whose optional toolchain is not installed. The individual commands below are still useful when diagnosing a failing check.
The repomin report compare command is deliberately smaller than a benchmark
dashboard. Changes must keep the comparison read-only: validate each report,
never read payload contents, execute a recorded command, or contact a service.
Keep the output allow-list free of paths, commands, match expressions, logs,
environment metadata, signatures, fingerprints, and timing fields. Any new
field needs a documented privacy and compatibility reason, a deterministic
renderer test, and an explicit statement of whether it is numeric or
categorical context. Preserve the descriptive_only boundary and add a warning
when a changed execution or sampling condition can make adjacent values hard
to compare.
Run the focused checks while iterating:
PYTHONPATH=src python3 -m unittest tests.test_report_compare tests.test_cli -vUse docs/REPORT_SCHEMA.md as the contract source and update the README,
examples, and changelog when the public comparison fields change. Performance
measurements belong in the dependency-free benchmark tooling, not in report
comparison.
Benchmarks are the most useful way to contribute a reproducible user workflow.
Start with the benchmark proposal template
and get agreement on the oracle contract before writing the fixture. Keep the
fixture self-contained, deterministic, network-free, and small enough to run
in CI. Add a fixture README.md, an expected minimized payload, and an
integration assertion in tests/test_offline_benchmarks.py. Run the focused
benchmark locally with python3 benchmarks/run_offline.py --only <name> and
include its output in the pull request description.
A public fixture or case study does not by itself authorize contacting another project. Before delivering evidence upstream, read that project's contribution and AI-assistance policies. Disclose material agent involvement in the first message. If the recipient accepts only human-created work or asks not to continue, stop the outreach and keep the result as local evidence unless they later invite it. Never describe a posted fixture as adopted, accepted, or useful to the recipient without an explicit response supporting that claim.
Changes to a reducer must include a test proving both sides of its contract:
the intended failure remains, and a different failure is rejected. Reducers
must never modify the input repository or overwrite an existing output path.
Tool-owned report.json and REPOMIN.md must remain in the sibling
OUTPUT.repomin metadata directory, never inside the exported payload. Tests
that exercise export or reporting must assert both paths and keep payload
file/byte accounting independent of metadata.
An enabled reducer must return at a local fixed point. Add a non-monotonic test when one accepted edit can unlock an earlier rejected target; the global dirty worklist relies on that local contract and only requeues components changed by other reducers.
Hierarchical batching is an oracle-cost optimization, never an acceptance shortcut. Every batch must run as one ordinary candidate. After acceptance, rediscover targets from the new tree; after rejection, split deterministically until the reducer reaches its singleton policy. Multi-file and multi-range batches must validate all inputs before the first write and roll back a partial write. A parallel union of independently passing candidates is a new candidate and must pass its own oracle run before promotion.
Changes to batching, epoch behavior, component ordering, or fixed-point
semantics require a new REDUCTION_STRATEGY value. The strategy must remain in
both the report and persistent-session identity so checkpoints cannot silently
resume under different reduction semantics.
Failure signature extractors must normalize unstable presentation details but retain enough identity to reject a different failure of the same broad class. Tests must cover repeated baselines, a matching candidate, and a near-match with a different message or origin frame.
Process failure signatures must come from the observed return code, never from localized shell output. Keep direct POSIX signals distinct from positive shell/container exit codes, normalize signed and unsigned Windows statuses to the same 32-bit value, and exclude timeout/resource results. Tests must include a real signal-terminated subprocess, exact candidate matching, checkpoint restore, and tamper rejection.
Execution backends must preserve command output and exit behavior, terminate child workloads on timeout, avoid promoting command side effects, and report infrastructure failures separately from the requested failure. Security defaults and any host resources exposed to a backend must be documented. Mutable runner references must be resolved before sampling and both the original reference and immutable identity must be checkpointed. Resume tests must prove that identity drift is rejected before another oracle command runs.
Changes to repeated candidate sampling must preserve both the fixed-size rule and the stopping contract. Count-only candidates may accept as soon as their minimum pass count is observed. Rate-gated early acceptance must require the count minimum, the Jeffreys beta-binomial mixture anytime lower bound, and a planned-size exact one-sided gate that still passes when every remaining sample is treated as a failure. A candidate reaching its maximum sample count uses the fixed-size exact rule; baseline and final validation must still run all configured samples. Never use a fixed-time interval as repeated-prefix evidence.
The anytime confidence sequence uses the candidate's allocated alpha. Without
run-wide control this is 1 - confidence and has per-candidate coverage only.
With --run-confidence C, family j uses at most
(1-C)/(j(j+1)), additionally capped by the base alpha. Tests must exhaustively enumerate small Bernoulli
sample trees to bound the probability of ever crossing, cover count-only and
rate-plus-count early acceptance, prove that the worst-case exact guard keeps
early decisions inside the fixed-N acceptance set, and exercise cases where
the count and anytime gates cross at different samples. An observed timeout or
resource exhaustion must win over acceptance at the same prefix. Tests must
also show that skipped suffix runs cannot report a hypothetical future resource
failure and that final validation still performs the full run count.
Run-wide family allocation must happen after confirming a changed tree and
before sampling. No-ops consume nothing; deterministic parallel candidates,
combinations, and changed cache/duplicate candidates consume distinct indices.
Checkpoint the allocated window before commands and never reuse its indices on
resume. Use exact rational comparisons to ensure binary rounding cannot increase
alpha. Tests must cover harmonic sums, adaptive small-family error probability,
unattainable and unrepresentable families, parallel numbering, early acceptance
at the allocated confidence, interrupted resume, tamper rejection, and final
validation at the last accepted family's confidence. A policy change requires a
new CANDIDATE_FAMILY_CONTROL_POLICY value.
A baseline rate gate combined with Java, Python, or process signature learning must keep signature discovery separate from rate evidence. The first extractable basic-pass fixes the signature; only later planned slots enter the exact rate gate, while the count threshold still spans all configured baseline runs. Tests must cover competing signatures and prove that the observed mode is not tested as though it had been fixed before sampling. Count-only signature mode must retain its existing stable-mode semantics.
Sampling report and checkpoint tests must cover
candidate_early_acceptances, candidate_early_rejections, and the combined
candidate_samples_saved count. Accepted events must preserve
oracle_anytime_lower_bound, oracle_early_acceptance, family index,
candidate confidence, and actual binary alpha, including across
resume, while older checkpoints default missing fields safely. Repeated
candidate sampling must continue to use fresh repository copies and bypass the
single-result content cache.
Final holdout certification is a separate statistical contract. Never reuse a
baseline, candidate, combination, or ordinary final-validation sample as
holdout evidence. Freeze the cleaned artifact, failure signature, runner
identity, N, target rate, confidence, and policy before the first command; run
all N fresh copies without cache or early stopping; and gate with the exact
one-sided binomial test rather than a rounded displayed bound. Timeout and
resource exhaustion are non-passes and hard vetoes. Holdout samples must not
enter candidate or reducer phase counters, and their results must never trigger
another mutation or candidate choice.
Persistent holdout changes must preserve the write-ahead protocol: checkpoint an
in-flight index before starting its command, checkpoint its result before moving
to the next index, and conservatively burn an unresolved in-flight slot on
resume. Successful, unsuccessful, and aborted attempts are terminal within a
session. Tests must cover known Clopper-Pearson values, exact attainability,
small-sample coverage, fresh-copy isolation, full fixed-size execution, resource
vetoes, artifact binding, interrupted resume, terminal idempotence, legacy
checkpoint behavior, and a report that keeps ordinary final_* statistics
separate. A policy or decision-rule change requires a new
HOLDOUT_CERTIFICATION_POLICY value.
Certified export recovery must never overwrite evidence speculatively. Tests must cover a crash after payload export, a crash after sidecar creation, exact payload fingerprint reuse, missing-sidecar reconstruction, and rejection of partial or mismatched payload/metadata without additional holdout samples.
Documentation and report fields must state the actual claim: a one-sided lower
confidence bound on oracle pass probability in the recorded environment,
conditional on fresh iid samples. Do not describe it as code correctness,
production reliability, proof that a regex identifies one bug, or protection
against repeated attempts in new sessions. Family-wise control may be claimed
only when --run-confidence is enabled, and only for the conditional
per-candidate sampling model documented in the architecture.
Phase-statistics changes must preserve both accounting identities:
attempts = no_op + rejected + accepted + superseded + aborted
oracle_sample_uses = oracle_samples + cache_hits
Here superseded is oracle-positive but unpromoted, and oracle_samples counts
actual command samples rather than logical cache uses. Tests must cover no-ops,
rejection, concurrent positives, a passing and failing combination, cache reuse,
candidate early stopping, mutation/oracle interruption, persistent resume, and
an active pass recovered as aborted. Never fabricate unavailable legacy phase
history; report it with partial coverage.
Source analyzers may report candidate ranges, but only ReductionSession may
apply and accept mutations. A candidate range must include a content hash so a
stale AST position cannot modify different source text. Replacement candidates
must derive their selected/replacement ranges from the parser and include the
replacement bytes in target identity; source-level regular-expression edits
are not accepted.
Candidates that coordinate multiple ranges, whether in one file or across files, must validate every path, range, content hash, and overlap constraint before writing the first file. Apply edits from the highest byte offset to the lowest within each file, and add a test in which one stale edit rejects the whole candidate without partially modifying another file.
Symbol-aware candidates must use compiler identity rather than matching names
or textual signatures. Unresolved symbols must never be guessed. A parameter
reference or a method/constructor reference is a blocker for its group, while
anonymous-class construction blocks every source constructor of its base type.
Record constructors and unsupported dispatch families must not produce groups.
Closed source override families must be represented by one atomic change set
covering every source declaration and resolved call argument.
If a source type hierarchy or any method-invocation, constructor-expression,
or member-reference path has an ERROR type, disable all coordinated
candidates for that analysis pass rather than skipping only that node;
syntax-only candidates may still be reported.
Keep the Java analysis helper compilable with javac --release 11. Do not use
compiler-tree or language-model APIs introduced after Java 11 without an
explicit compatibility design. The Java test matrix must include an actual JDK
11 compiler/runtime lane; compiling on a newer JDK with --release 11 checks API
and class-file compatibility but not JDK 11 javac model or diagnostic behavior.
Tests for symbol work must cover overload identity, cross-file links, private and
static methods, ordinary constructors, varargs ranges, stale grouped edits,
nested calls, and dispatch eligibility. Instance-method coverage must include an
explicitly final method, a method closed by a final ordinary top-level or
member class, and a source-local override family with a final leaf; current
overrides and interface implementations (including external contracts), prospective
post-removal overrides or implementations, generic-erasure or bridge clashes,
open virtual and native methods, and enum, record, local, and anonymous owners
must remain excluded. Continue to cover anonymous-class and record-constructor
exclusions, global ERROR-type fallback, and recoverable unresolved symbols
that must not be guessed.
Node manifest changes must use the strict JSON structure parser rather than
regular-expression replacement. Tests must cover first, middle, and last object
members, array entries, nested overrides/resolutions, duplicate-key and
non-standard-JSON rejection, stale content hashes, and a real oracle command
that keeps one dependency while removing unrelated package entries. Lockfiles
and runtime metadata must remain outside the adapter's mutation set.
Composer manifest changes must use the same strict JSON structure parser rather
than regular-expression replacement. Tests must cover requirement categories,
scripts, repository array entries, first/middle/last removals, duplicate-key
and non-standard-JSON rejection, stale hashes, and an offline structural oracle.
Autoload maps, arbitrary extra metadata, and composer.lock must remain
outside the adapter's mutation set.
MSBuild manifest changes must use XML parsing and stable item identity rather than regular-expression replacement. Tests must cover package, project, framework, source/content item categories, first/middle/last removals, stale subtree hashes, namespaced XML, malformed XML fail-closed behavior, and an entity-declaration rejection, and an offline structural oracle. Property groups, imports, conditions, arbitrary metadata, and lockfiles must remain outside the adapter's mutation set.
Ruby manifest changes must use the balanced line scanner and stable content
hashes rather than regular-expression replacement. Tests must cover single-line
and parenthesized calls, grouped declarations, comments/strings, multiline and
block exclusions, first/middle/last removals, stale hashes, and a real Ruby
oracle. Arbitrary Ruby code and Gemfile.lock must remain outside the
adapter's mutation set.
Cargo manifest changes must use structured TOML tokens and stable content-hashed
ranges. Tests must cover root, target-specific, development, and build
dependency tables, workspace members/exclude arrays, first/middle/last
removals, stale hashes, and a real offline cargo oracle. Cargo.lock, feature
lists, and unrelated metadata must remain outside the adapter's mutation set.
Go manifest changes must use line-structured directive parsing rather than
regular-expression replacement. Tests must cover single-line and block forms
of require/replace, exclude and retract, unclosed-block fail-closed
behavior, stale hashes, and an offline go run oracle. Workspace use and
workspace-level replace entries are also eligible targets; go.sum, module
declarations, Go version/toolchain directives, and other go.work metadata
must remain outside the adapter's mutation set.
Tests for coordinated parameter removal must distinguish static analysis from
the reproduction oracle. Direct method and constructor references are compiler
blockers. Reflection, MethodHandles.Lookup, generated or JNI/framework calls,
and precompiled external callers require oracle tests that exercise those paths;
the test command should compile affected source and use --java-exception when
exception identity is part of the contract. Do not treat an accepted reproduction
as proof of source compatibility, ABI compatibility, compilation, or unexercised
behavior.
Changes to Java classpath handling must preserve its host-side analysis-only
boundary. Each repeated --java-classpath PATH is an atomic entry, including on
platforms where the filename contains the normal path separator character;
never split one value into a path list. Resolve relative entries against the
original source, retain precedence order, and reject missing, unreadable,
unsupported, or duplicate physical entries (including symlink and hardlink
aliases). Tests must cover canonicalization, order, duplicate and invalid paths,
file and directory content fingerprints,
recursive path/type/mode hashing, rejection of nested symlinks and special
files, and resume rejection after either the configured paths or their contents
change. A top-level symlink resolves to its canonical target; regular files do
not require a particular extension or archive format before being passed to
javac.
Classpath tests must also prove that entries are forwarded to the host compiler
without modifying the oracle command or Docker mounts. Include a dependency
that enables otherwise-missing attribution, and assert that an external binary
ExecutableElement cannot supply the declaration role of a source group or
become a mutation target. ReproMin must not invoke Maven, Gradle, or another
build tool to discover the classpath.
Run the test suite with:
PYTHONPATH=src python3 -m unittest discover -s tests -vIf pytest is already available in your development environment, the shorter
pytest -q command is also supported. The repository configuration limits
collection to tests/ and adds the src/ layout automatically; benchmark
fixture tests are intentionally run through benchmarks/run_offline.py.
To inspect branch coverage locally, install the CI-only coverage tool and run:
python3 -m pip install coverage
PYTHONPATH=src python3 -m coverage run --branch -m unittest discover -s tests
python3 -m coverage report --show-missingThe preflight command above also runs linting and byte-compilation in temporary cache directories. To run only those static checks, use:
python3 scripts/check_contribution.py --skip-testsRun the network-free benchmark regression with:
python3 benchmarks/run_offline.pyThe runner verifies each offline fixture in a disposable output directory,
independently reruns its oracle, and skips fixtures whose toolchain is not
installed. CI runs the same command as the offline-benchmarks job.
The repository deliberately ignores E501 line-length diagnostics while
enforcing Ruff's E and F correctness rules. Existing long strings and
fixture commands are often clearer when kept intact; formatting-only rewrites
should not obscure reducer behavior.