Skip to content
dsh.fish
Bundle

dsh-reprolab

dsh-reprolab — a complete bug-to-proof workflow for DeepSeek Harness: frozen repro tests, RED/GREEN/REGRESSION gates, and replayable evidence.

Source
yuttfu
License
MIT
Updated
Updated 2 days ago

Readme

# dsh-reprolab

> A complete bug-to-proof workflow for DeepSeek Harness: frozen repro tests, RED/GREEN/REGRESSION gates, and replayable evidence.

`dsh-reprolab` (ReproLab) turns an issue, an error message or reproduction steps into auditable fix evidence:

```text
baseline code + frozen repro test        → must fail     (RED)
candidate fix + the SAME frozen test     → must pass     (GREEN)
regression check                         → no new failures (REGRESSION)
evidence report                          → replayable, redacted (REPORT)
```

ReproLab is a deterministic bug-proof executor that complements session-level discipline plugins such as dsh-doublecheck. Your Harness session writes the tests and the fix; ReproLab isolates worktrees, freezes inputs, runs the quality gates and produces the evidence.


## The nine tools

| Tool | Purpose | Key result |
|---|---|---|
| `reprolab_start` | Resolve repo, freeze baseline, create `control`/`candidate` worktrees, optionally record the baseline regression failure set | `runId`, worktree paths, baseline, `baselineRegression` |
| `reprolab_set_test` | Freeze the repro test patch + the target test command | `testPatch` hash, command hash |
| `reprolab_verify_red` | Run the frozen command in `control` and prove a genuine test failure | `verdict: valid_red`, failure `fingerprint` |
| `reprolab_set_fix` | Freeze the production-only fix patch from `candidate` | `fixPatch` hash, changed files |
| `reprolab_verify_green` | Run the exact same frozen command in `candidate` and prove it passes | `verdict: valid_green` |
| `reprolab_verify_regression` | Compare candidate failures with the recorded baseline set | `pass` / `pass_with_baseline_failures` / `regression` / `inconclusive` |
| `reprolab_status` | Structured run state, frozen hashes, report staleness, next legal actions | `nextActions` — no prose to parse |
| `reprolab_report` | Generate/refresh `report.json` + `report.md` from one shared model | report path + recomputable sha256 |
| `reprolab_abort` | Abort and keep the scene for inspection | retained paths |

A nonzero exit code alone is **never** RED: test-not-discovered, syntax errors, missing imports, timeouts, crashes and cancellations are all excluded, and RED/GREEN must use identical test-patch and command hashes.

## Installation

DeepSeek Harness `0.1.0-rc.6`, Node `^22.19.0 || >=24.0.0`.

From a packed artifact (built `dist/` included):

```sh
pnpm pack                                    # → dsh-reprolab-0.1.0.tgz
dsh plugin --profile <profile> add ./dsh-reprolab-0.1.0.tgz
dsh --profile <profile>
```

From the repository directory (dev):

```sh
dsh plugin --profile <profile> add ./dsh-reprolab
```

Both forms require the host's in-box `tools` and `subprocess` services (provided by `dsh-base` in every profile).

## Configuration

All fields are optional and defaulted by the Schemastery schema. Bundle patch rows replace the whole config per row, so restate every key when overriding.

| Key | Type | Default | Meaning |
|---|---|---|---|
| `runDir` | string | `.reprolab` | Directory (relative to repo root) for runs, worktrees, patches and reports |
| `graceMs` | number (≥50) | `5000` | SIGTERM→SIGKILL grace when terminating child process trees |
| `maxOutputBytes` | number (≥1024) | `1048576` | In-memory output cap per stream; overflow keeps the tail and spills the full stream |
| `spillMaxBytes` | number (≥1 MiB) | `16777216` | Whole-stream spill cap per stream |
| `lockStaleMs` | number (≥1000) | `300000` | Repo write-lock staleness threshold (stealing still requires a dead owner) |

## Permissions and external side effects

ReproLab writes **only inside the target repository**: `runDir/` (default `.reprolab/`) with run state, patches, reports, and `git worktree` directories. Side effects:

- **Filesystem**: creates `runDir/runs/<run-id>/`, `runDir/worktrees/<run-id>-{control,candidate}/`, `baseline.patch`, `test.patch`, `fix.patch`, `report.json`, `report.md`; reads repository files.
- **Processes**: executes Git (structured `argv`, explicit `cwd`, no shell) and the test commands **you declare** (argv arrays only, never shell strings). Cancellation/timeout kills the whole process tree.
- **Git**: creates/removes worktrees registered under `runDir/worktrees`; **never** resets, checks out, cleans or commits on your current branch. Cleanup is a separate explicit primitive (not a tool).
- **Network / telemetry / keys**: none. The plugin makes no network calls, sends no telemetry and needs no API keys.
- **Credentials**: child environments start from the host's scrubbed base (`KEY/PASSWORD/SECRET/TOKEN` names and `DSH_*` are stripped); output is redacted (tokens, Authorization, cookies, passwords, high-entropy strings) before records or reports are written.

## Quick demo (node:test)

```text
> reprolab_start { repoPath: "/path/to/repo", baselineCommand: { argv: ["node","--test"], framework: "node:test" } }
  → runId run_…, state baseline_checked, control + candidate worktree paths
# you write the repro test in the candidate worktree
> reprolab_set_test { runId, declaredTestFiles: ["bug.test.mjs"], command: { argv: ["node","--test","bug.test.mjs"], framework: "node:test" } }
  → state test_frozen, testPatch hash
> reprolab_verify_red { runId }
  → verdict valid_red, failure fingerprint, state red_verified
# you fix the production code in candidate
> reprolab_set_fix { runId }                          → state fix_frozen
> reprolab_verify_green { runId }                     → verdict valid_green
> reprolab_verify_regression { runId, command: { argv: ["node","--test"], framework: "node:test" } }
  → verdict pass (or pass_with_baseline_failures), state regression_verified
> reprolab_report { runId }                           → reportPath, reportHash (sha256 of report.json)
> reprolab_status { runId }                           → state reported, nextActions []
```

Report staleness: if any evidence input changes after reporting (e.g. the tests are re-frozen), `reprolab_status` reports `report.stale: true`.

## Compatibility

| Component | Version |
|---|---|
| DeepSeek Harness | `0.1.0-rc.6` |
| @deepseek-ai/cordis | `^4.0.1` (peer) |
| @deepseek-ai/dsh-subprocess / dsh-tools / dsh-brand | `0.1.0-rc.6` |
| @deepseek-ai/schemastery | `^3.18.1` |

All host contracts were verified first-hand against the installed official packages and the official docs snapshot.

## Known limitations

- One active (non-terminal) run per repository at a time; the write lock is fail-fast (`RUN_ALREADY_ACTIVE`), not queued.
- `pytest` and `jest` classification is based on the documented output formats (no local pytest/jest installs were available); `vitest` and `node:test` formats were captured from real runs. Python projects use `unittest` + the `generic` classifier.
- Test-runner cache artifacts (`__pycache__`, `.pyc`, `.pytest_cache`, `.coverage`, `htmlcov`, `.vite`, `node_modules/.cache`) are ignored by change detection — an allowlist, not an ignore-all.
- The repository needs at least one commit (worktrees require a baseline commit).
- `dsh-windtunnel`'s scripted adapter is currently incompatible with DSH `0.1.0-rc.6` (third-party issue). Real-host lifecycle (install/enable/disable/uninstall/reinstall) was verified through the real `dsh` CLI on a clean headless profile.

## Uninstall

```sh
dsh plugin --profile <profile> remove dsh-reprolab
```

This removes the bundle row and package. Run artifacts (`runDir/` and worktrees) are **not** deleted by uninstall — remove them explicitly with `git worktree remove` after inspecting them. Active runs terminate their child processes on plugin unload (host subprocess service disposal).

## Troubleshooting

Recovery guidance for every error code, worktree cleanup, stale locks and invalidated runs: [`docs/troubleshooting.md`](docs/troubleshooting.md). Security model: [`docs/security.md`](docs/security.md). Architecture: [`docs/architecture.md`](docs/architecture.md).

## Development

```sh
pnpm install
pnpm run check            # lint + typecheck + build + verify:manifest
pnpm pack                 # → dsh-reprolab-0.1.0.tgz (dist/, cordis.patch.yml, README, LICENSE)
```

MIT License.

Install

dsh plugin --profile web add github:yuttfu/dsh-reprolab

Profile: web

  • This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source