| id | 137 |
|---|---|
| title | `mdsmith fix --dry-run` |
| status | 🔲 |
| model | sonnet |
| summary | Add `--dry-run` to `mdsmith fix` so agents and CI scripts can preview the file changes before writing. Emits the same diagnostics as `check` plus a per-file count of fixes that would apply. |
Let a user run mdsmith fix --dry-run and see
exactly which files would change, which rules
would fire, and how many violations each file
carries. No bytes are written. The exit code
matches what fix would have returned, so a CI
script can gate on dry-run output.
Plan C-6 in the mdbase research calls this out as a quick ergonomic win. The trigger is an agent loop or CI run that wants a safety net before writing.
Today the only preview is mdsmith check, which
reports diagnostics but does not say which would
be auto-fixed. A user who wants to know "what
will fix change?" has to diff the worktree
afterward.
The fix engine already produces a fixed-content buffer per file before writing. Gating the write behind a flag is small.
- Diff output. The flag prints which rules would
fire and how many; a textual diff per file is
out of scope. Users who want a diff can run
mdsmith fixagainst a copy. - Partial application. The flag is all-or-nothing per run. No "fix MDS001 but preview MDS006".
- A separate subcommand.
--dry-runonfixmatches the convention other CLIs use.
mdsmith fix --dry-run docs/Output, one line per file with at least one fix:
docs/api.md: would fix 3 violations (MDS001 ×2, MDS006)
docs/index.md: would regenerate <?catalog?> body
Files with no fixes do not appear. A trailing
summary matches the existing fix summary line:
stats: checked=12 fixed=0 failures=0 unfixed=4 would-fix=8
The dry-run summary keeps the existing
checked= / fixed= / failures= / unfixed=
fields for machine-parsability. fixed=0 is
always literal-zero on a dry run, since nothing
was written. would-fix=N is additive — the
count of violations a real run would have
auto-fixed. A consumer that only watches
fixed= therefore sees 0 (no surprise apply);
a consumer that watches would-fix= sees the
preview count.
--format json emits one record per file:
{"path":"docs/api.md","would_fix":3,
"rules":["MDS001","MDS006"],"diagnostics":[]}The diagnostics array carries the same shape
check --format json returns today.
The exit code is the same fix would have
returned without --dry-run:
0— every diagnostic is fixable; a real run would leave the worktree clean.- non-zero — at least one unfixable diagnostic remains.
This lets a CI step run dry-run as a gate on "fix can clean this PR".
--dry-run is additive. Default behavior is
unchanged. The new line in the summary
(would-fix=N) is suppressed on a real run.
- Add
--dry-runto thefixsubcommand flag set inrunFixincmd/mdsmith/main.go. - Gate the write step in the fix pipeline:
build the fixed buffer as today, but on
--dry-runskip the write and record the would-fix count per rule. - Update the per-file output formatter to emit
"would fix N violations" lines and the
trailing
would-fix=Nsummary stat. - Extend the JSON output struct with
would_fixandrulesfields when--dry-runis set. - Document the flag in
docs/reference/cli/fix.mdwith one worked example. - Tests:
- dry-run reports the same fix count a real run would apply (regression compares both),
- dry-run leaves the worktree byte-identical,
- dry-run exit code matches the real-run exit code on the same input,
- JSON output exposes
would_fixandrules.
-
mdsmith fix --dry-runwrites nothing to disk (regression test asserts every candidate file is byte-identical after the run). - The per-file output names each rule that would fire and how many times.
- The summary line includes
would-fix=N. The existingchecked=/fixed=/failures=/unfixed=fields are present on the same line;fixed=reads0since nothing was written. -
--format jsonexposeswould_fixandrulesper file. - Exit code matches the real-run exit code on identical input.
-
docs/reference/cli/fix.mddocuments the flag with an example. - All tests pass:
go test ./... -
go tool golangci-lint runreports no issues.