Adopting on an existing repo
The first time you run madr-lint on a repo with dozens of legacy ADRs, you get
hundreds of errors. Fixing them all before your first green build is a
non-starter — so madr-lint lets you baseline the existing violations and
enforce the rules only on new ones. This is the same pattern as
tsc-baseline, ESLint bulk
suppressions, and Betterer.
The three-step adoption
Section titled “The three-step adoption”1. See where you stand
Section titled “1. See where you stand”madr-lint# → 342 errors, 17 warnings2. Snapshot the current violations
Section titled “2. Snapshot the current violations”madr-lint --update-baseline# → Wrote 359 violations across 53 files to .madr-lint/baseline.jsonThis writes .madr-lint/baseline.json and exits 0. Commit that file.
3. Enforce from here on out
Section titled “3. Enforce from here on out”madr-lint# → 17 problems hidden by baseline (.madr-lint/baseline.json)# exit code 0Every violation already in the baseline is subtracted. Add a brand-new one — a new ADR with a missing section, or a fresh mistake in an old file — and it fails the build as normal:
madr-lint# error madr/required-sections Missing required section: "Consequences"## 1 error# exit code 1Wire step 3 into CI and you get “no new debt” enforcement from day one, while the legacy debt waits to be paid down on your schedule.
How the fingerprint works
Section titled “How the fingerprint works”A baselined violation is identified by (file path, rule, messageId) mapped to
a count — not by line number or message text. That is deliberate: it means
the baseline survives unrelated edits. Insert a paragraph at the top of an
ADR and every downstream violation shifts down a few lines, but the baseline
still absorbs them because the fingerprint never looked at lines in the first
place.
The count is what catches new debt. If a file was baselined with two
missingSection violations and a later edit introduces a third, two are
absorbed and the third is reported.
See ADR-0007 for the full design and the alternatives we rejected.
Paying down the debt
Section titled “Paying down the debt”Fix some violations, then re-snapshot:
madr-lint --update-baselineThe rewrite prunes anything you have fixed, so the baseline file shrinks by
exactly the lines you resolved — a clean, reviewable git diff. Keys are sorted
and the file uses a stable 2-space indent, so re-running --update-baseline
never produces spurious churn.
To audit everything the baseline is hiding, run without it:
madr-lint --no-baseline| Flag | Effect |
|---|---|
--update-baseline | Run a full lint (ignoring any existing baseline), rewrite .madr-lint/baseline.json, print a one-line summary, exit 0. |
--no-baseline | Ignore the baseline file entirely; report every violation. |
| (default) | Subtract .madr-lint/baseline.json when it exists; no-op when it does not. |
- The baseline lives at
.madr-lint/baseline.json, alongside the cache directory (.madr-lint/cache). Commit the baseline; the cache is safe to gitignore. - Paths in the baseline are relative to the project root with forward slashes, so the same file works across macOS, Linux, and Windows CI.
- Subtraction applies to both errors and warnings, and runs after
inline suppression. Use inline
madr-lint-disablecomments for the handful of legitimate, permanent exceptions; use the baseline for bulk legacy debt you intend to pay down. - Editing or deleting the baseline takes effect immediately — it is independent of the content-hash cache, which always stores pre-baseline results.
- A baseline file that exists but cannot be parsed is ignored with a one-line
stderrwarning (run--update-baselineto regenerate it). A missing file stays silent. --format jsonreports how many diagnostics were absorbed viasummary.baselineHidden(always present;0when no baseline is active). SARIF output is unaffected.core/internal-error(emitted when a rule itself crashes) is never baselined — it signals a bug, not debt.