DEV Community

Blake Yang
Blake Yang

Posted on

Ship a One-Command Repro Script Before Maintainers Read an OSS Diff

A contributor pasted a twelve-file diff under an issue that described a CLI exiting zero on invalid UTF-8 input. The maintainer cloned the fork on a clean runner and could not trigger the failure with the commands in the description. Three review comments later, the conversation still concerned local virtualenvs, Python minor versions, and a fixture that never reached the repository. The patch may have been correct, yet the project had no command a stranger could run to watch the bug happen.

Open-source review stalls when the reproduction lives only in the author's shell history. Maintainers need a script that fails on the reported revision, passes after the patch, and names every environment assumption in plain text. This article records that packet as a review artifact, then shows how a free-tier model pass can check issue-to-command traceability without rewriting the patch.

Treat the Issue as a Contract, Not as Flavor Text

Issue templates already collect version strings, operating systems, install steps, and expected versus actual output. Contributors often skip that structure and jump into a refactor that also happens to mention the bug. The safer order is to freeze a reproduction contract before any production file changes, then refuse to expand the diff until that contract fails on current HEAD.

The contract is a short table, not a narrative. Each row must be something a maintainer can execute without guessing paths or secrets. Rows that cannot be turned into a command do not belong in the first patch.

Contract field Example freeze Reject if missing
Upstream revision git rev-parse HEAD at clone time "latest main" with no SHA
Runtime python3.12 from the project's documented range Author's private conda env
Input printf '\xff' > /tmp/bad.bin "a weird file I have locally"
Command ./cli parse /tmp/bad.bin IDE click-path only
Actual now exit 0 and empty stderr screenshot without exit code
Expected after patch exit 2 and invalid utf-8 on stderr "should feel more correct"

Copy that table into REPRO.md beside the future patch. Do not describe hoped-for architecture in this file. Architecture notes wait until the command fails for a stranger.

Build a Maintainer-Shaped Script Before Touching Library Code

A reproduction script should pin the revision, create an isolated directory, install only documented extras, and exit non-zero while the bug still exists. The script is the first commit on the contribution branch, even when the production fix is still unknown. Maintainers can then run one command on the author's branch and on main without reading the diff.

#!/usr/bin/env bash
# repro.sh — must fail on the buggy revision, pass after the fix.
set -euo pipefail

ROOT="$(cd "$(dirname "$0")" && pwd)"
REV="${REV:-$(git -C "$ROOT" rev-parse HEAD)}"
WORKDIR="$(mktemp -d /tmp/oss-repro.XXXXXX)"
trap 'rm -rf "$WORKDIR"' EXIT

git -C "$ROOT" archive "$REV" | tar -x -C "$WORKDIR"
cd "$WORKDIR"

python3.12 -m venv .venv
# shellcheck disable=SC1091
source .venv/bin/activate
python -m pip install -e ".[dev]" >/tmp/repro-install.log

printf '\xff' > /tmp/bad.bin
set +e
./.venv/bin/cli parse /tmp/bad.bin >/tmp/repro-out.txt 2>/tmp/repro-err.txt
STATUS=$?
set -e

echo "rev=$REV exit=$STATUS"
if [[ "$STATUS" -eq 0 ]]; then
  echo "BUG STILL PRESENT: invalid input was accepted" >&2
  exit 1
fi
grep -q 'invalid utf-8' /tmp/repro-err.txt
echo "repro satisfied"
Enter fullscreen mode Exit fullscreen mode

Mark the script executable and run it against the issue revision before writing a fix. The first run should print BUG STILL PRESENT and exit 1. If it prints repro satisfied on main, the issue is already fixed or the contract is wrong, and no library patch should ship.

chmod +x repro.sh
git switch -c fix/invalid-utf8-exit-code
git add repro.sh REPRO.md
git commit -m "test: add maintainer repro for invalid UTF-8 exit code"
REV=$(git rev-parse HEAD) ./repro.sh; echo "first-run exit=$?"
Enter fullscreen mode Exit fullscreen mode

Keep generated virtualenvs and /tmp fixtures out of git. The script creates those paths on each run so reviewers do not inherit the author's machine. If the project needs a compiler flag or a locale, put that export in the script rather than in a blog comment.

Fail the Same Assertion in the Project Test Runner

A shell repro is necessary for maintainers who will not open an IDE. It is not a substitute for the suite that CI already knows how to execute. After the script fails, add one test in the project's normal layout that encodes the same input, command, and exit contract.

# tests/test_invalid_utf8_exit.py
from pathlib import Path
import subprocess
import sys

def test_parse_rejects_invalid_utf8(tmp_path: Path) -> None:
    payload = tmp_path / "bad.bin"
    payload.write_bytes(b"\xff")
    proc = subprocess.run(
        [sys.executable, "-m", "cli", "parse", str(payload)],
        capture_output=True,
        text=True,
        check=False,
    )
    assert proc.returncode == 2
    assert "invalid utf-8" in proc.stderr.lower()
Enter fullscreen mode Exit fullscreen mode

Run that file alone until it fails for the documented reason, not for an import error. Import failures mean the repro still depends on unpublished helpers. Only then is a production edit in scope.

python -m pytest tests/test_invalid_utf8_exit.py -q
# expected on main: 1 failed, assertion on returncode or stderr
Enter fullscreen mode Exit fullscreen mode

Patch Against the Contract, Then Re-run Both Gates

Limit the production change to the code path the repro actually exercises. Wide cleanups belong on a later branch after the bug is closed. After the edit, the same repro.sh must invert its meaning: the bug-present branch of the script should no longer trigger, and the pytest file should pass in isolation and with the project's default target.

# after the smallest library edit
./repro.sh && python -m pytest tests/test_invalid_utf8_exit.py -q
git add src/cli/parse.py tests/test_invalid_utf8_exit.py
git commit -m "fix: reject invalid UTF-8 with exit 2"
Enter fullscreen mode Exit fullscreen mode

If repro.sh still exits 1, the patch did not implement the contract, even if unit tests elsewhere turned green. If pytest passes while repro.sh fails, the suite is mocking away the install path maintainers will use. Both results block the pull request until they agree.

Map Each Issue Sentence to a Hunk Before Asking for Review

Maintainers reject AI-shaped patches when the diff argues with the issue. A mapping file prevents that drift. Write REVIEW_MAP.md with one bullet per issue claim, the command that witnesses it, and the file hunk that implements it. Claims without a command stay out of the pull request body.

# REVIEW_MAP.md
- Claim: invalid byte sequence must not exit 0
  Witness: `./repro.sh` on this branch exits 0 after the fix commit
  Hunk: `src/cli/parse.py` decoder error path
- Claim: stderr names the encoding failure
  Witness: `grep -q 'invalid utf-8' /tmp/repro-err.txt`
  Hunk: `src/cli/parse.py` error formatter
- Non-claim: no public CLI flag renamed in this patch
  Witness: `git diff main -- src/cli/flags.py` is empty
Enter fullscreen mode Exit fullscreen mode

A second reader can check that mapping without touching the working tree. Disclosure: This article was prepared as part of MonkeyCode's product outreach. Contributors who already use MonkeyCode's free model access and free server option can paste the issue text, repro.sh, and the unified diff into that workspace and ask only whether each claim has a failing-then-passing command. The workflow does not depend on that product, and this article does not add model names, quotas, or hardware claims beyond those two operator-supplied options.

Keep the model prompt narrow so it cannot invent extra refactors. The useful question is whether the packet is internally consistent, not whether the code looks stylish.

You are checking a maintainer reproduction packet.
Do not propose new features or drive-by cleanups.
Issue text, REPRO.md, repro.sh, REVIEW_MAP.md, and git diff follow.
List every issue claim that lacks a command or a hunk.
List every diff hunk that matches no issue claim.
If the script would pass on the buggy revision, say so explicitly.
Enter fullscreen mode Exit fullscreen mode

Treat the model output as a checklist against REVIEW_MAP.md. If it reports an unmatched hunk, delete that hunk or move it to a follow-up issue. If it reports a missing witness, extend repro.sh instead of arguing in prose.

Decision Table for Stopping Work

Observation Action Do not
repro.sh passes on main Close as already fixed or rewrite the contract Ship a speculative cleanup
Script fails on missing compiler Record the toolchain in REPRO.md and the script Ask maintainers to "use my laptop"
Pytest green, script red Drop mocks that hide install layout Trust local IDE runners
Model flags an extra hunk Revert that hunk before review Explain the extra hunk in the PR essay
Contract needs network or secrets Split into a follow-up with documented credentials Put tokens in the repro script

Limitations and Who Should Skip This Packet

The one-command packet assumes the bug is deterministic, local, and expressible as process input plus exit status or files. Timing races, GPU kernels, and hardware-specific faults need a different harness, often with logging and multiple iterations. This workflow also assumes the project already documents an install path that a clean checkout can follow.

Contributors should not use this packet as a replacement for the project's required CI jobs. A green repro.sh on one Python minor version does not prove the matrix the maintainers actually ship. People working on security issues with non-public fixtures should keep those fixtures out of a public repro.sh and follow the project's private disclosure process instead.

Teams that already have a hermetic nix develop or container entrypoint can wrap that entrypoint rather than inventing a second installer. The artifact that matters is still a single command whose exit code flips with the patch. Free model review of the mapping is optional and can be skipped when the packet is shorter than a screen.

The pull request body then stays short: link the issue, paste the one command, and attach REVIEW_MAP.md. Maintainers can reproduce before they argue about style. Contributors who already keep a free coding workspace can run the same packet there as optional verification, then still wait for the project's own runner before claiming the bug is gone.

Top comments (0)