mdformat parity

cargo xtask mdformat-parity compares mdwright against mdformat (with the GFM, frontmatter, footnote, and MkDocs plugins) over an isolated corpus copy. The goal is classified compatibility, not byte identity. Every mdwright/mdformat output difference is either fixed, configured, or recorded below as intentional; otherwise the command fails as a release gate.

Use [fmt] profile = "mdformat" to ask "how close can mdwright get to mdformat while keeping verified rewrites?" The profile keeps mdformat's default wrap = keep; a project that wants mdformat with a column limit must set wrap explicitly. When wrap is an integer, mdwright enforces that line budget for breakable prose in every profile. The default stable wrap strategy uses mdformat-compatible soft-break reflow. The mdformat profile also defaults list continuation indentation to four spaces.

Status values

  • open-bug: known unresolved gap; reported as a failing release gate.
  • intentional-divergence: mdwright deliberately keeps a different byte style while preserving semantics.
  • upstream-parser-limitation: difference pinned to parser behaviour outside mdwright.
  • configured: caused by mdwright project configuration, usually generated-doc excludes.
  • fixed: should no longer appear; the xtask fails if it does.

Class is free-text and groups rows by root cause. style-option-mismatch covers remaining wrap or indentation policy differences; mdformat-semantic-drift covers cases where mdformat's output is not semantically equivalent to the source; intentional-policy covers generated files excluded by configuration.

Classifications

The table below is parsed by xtask::mdformat_parity::load_classifications: each row must have exactly seven cells. Path patterns support *, **, and prefix/** globs; find_classification returns the first matching row, so specific paths come first and catch-all ** rows last. Formatter divergences are owned by the formatter team; generated-doc exclusions are owned by docs.

CorpusPathConstructClassStatusOwnerResolution
externaljupyter_book_minimal/admonitions.mdMyST directivesmdformat-semantic-driftintentional-divergenceformattermdwright preserves MyST directive structure; mdformat with --no-validate rewrites this fixture in a way mdwright's semantic oracle rejects.
externaljupyter_book_minimal/asides.mdMyST directivesmdformat-semantic-driftintentional-divergenceformatterSame shape as admonitions.md.
externaljupyter_book_minimal/directives.mdMyST directivesmdformat-semantic-driftintentional-divergenceformatterSame shape as admonitions.md.
externaljupyter_book_minimal/blocks.mdMyST and Pandoc blocksmdformat-semantic-driftintentional-divergenceformattermdwright preserves MyST and Pandoc block structure; mdformat with --no-validate rewrites this fixture in a way mdwright's semantic oracle rejects.
mdwright-docssrc/SUMMARY.mdnested list indentationstyle-option-mismatchintentional-divergenceformattermdwright preserves the existing two-space mdBook summary nesting; mdformat rewrites nested bullets to four spaces.
mdwright-docssrc/extending/lint-rules.mdlist continuation indentationstyle-option-mismatchintentional-divergenceformatterThe repository policy keeps marker-width continuation; fmt.lists.continuation-indent = "four-space" provides the mdformat spelling when requested.
mdwright-docssrc/configuration.mdgenerated docsintentional-policyconfigureddocsGenerated by cargo xtask doc-config; excluded so source docs and generator drift checks do not fight.
mdwright-docssrc/reference/cli.mdgenerated docsintentional-policyconfigureddocsGenerated by cargo xtask doc-cli.
mdwright-docssrc/reference/diagnostic-schema.mdgenerated docsintentional-policyconfigureddocsGenerated from diagnostic schema tests.
mdwright-docssrc/rules/**generated rule docsintentional-policyconfigureddocsGenerated by cargo xtask doc-rules; rule pages intentionally contain lint violations.
mdwright-docs**prose wrapstyle-option-mismatchintentional-divergenceformatterInteger wrap now enforces a line budget for breakable prose in every profile. mdwright may wrap lines that mdformat leaves above the configured width.
release-prose-corpus**prose wrap line budgetstyle-option-mismatchintentional-divergenceformattermdwright enforces wrap = 120 for breakable prose lines. mdformat 1.0.0 leaves the observed over-budget source lines unchanged.
release-math-corpus**/*-template.mdmdformat semantic driftmdformat-semantic-driftintentional-divergenceformattermdwright preserves the source semantics; mdformat changes the rendered HTML on some template files in this corpus.
release-math-corpus**math-heavy prose and list reflowstyle-option-mismatchintentional-divergenceformattermdwright treats ordinary paragraph newlines as soft breaks and enforces over-budget breakable lines. mdformat leaves some over-budget lines unchanged.
external**prose wrapstyle-option-mismatchintentional-divergenceformatterSame as the mdwright-docs catch-all. Single oversized atomics may still exceed the target by policy.

Release use

Run against the pinned mdformat baseline:

cargo xtask mdformat-parity \
  --corpus-root docs \
  --corpus-name mdwright-docs \
  --mdwright-config .mdwright.toml \
  --mdformat-config xtask/fixtures/mdformat-parity/mdformat.toml

The mdformat config lives under xtask/fixtures/ because it is an oracle fixture, not the repository's own formatter. Output lands at target/mdwright/parity/mdformat-parity.{json,md}. A clean release run has no unclassified differences, no semantic drift, no parse errors, no idempotence failures, and no rows marked open-bug.