| id | 95 |
|---|---|
| title | Kind/rule resolution observability via `kinds` subcommand |
| status | ✅ |
| model | opus |
| summary | Replace `mdsmith config kinds/show/why` with a top-level `kinds` subcommand parallel to `archetypes` (which is being removed by plan 98). Adds per-leaf provenance, `check --explain`, and first-class `--json` output. |
Make it easy to answer "why is this rule applied this
way to this file?". The CLI surface is a top-level
kinds subcommand that exposes:
- declared kinds and their merged bodies,
- the resolved kind list and merged rule config for a file (with provenance per leaf setting),
- the full merge chain for a single rule on a single file,
- a
--jsonform of each, and - a
check --explainflag that attaches the same provenance trailer to each diagnostic.
kinds is parallel in shape to today's archetypes
subcommand, which plan 98 removes. Together the two
plans collapse overlapping concepts into one.
Plan 92 introduces kinds; plan 93 layers per-rule
placeholders: settings; plan 96 starts applying
them. As the rule config grows from "global +
overrides" to "global + kinds + assignment +
overrides", a flagged file's effective config becomes
hard to reproduce by reading .mdsmith.yml alone.
Provenance makes this debuggable.
For every effective rule setting on a given file, mdsmith tracks the chain of layers that produced its final value. Provenance is per leaf, not per rule-block: every individual scalar/list field is tagged separately. Layers:
default— the rule's built-in defaultkinds.<name>— set by the named kind's bodyoverrides[i]— set by the i-th override entryfront-matter override— set by the file's own front matter
Per-leaf granularity matters because plan 97 (deep- merge) makes nested settings come from different layers; the data model is the same shape now and then. Today, under block-replace, every leaf in a rule's final config carries the same source — that's a valid output of the per-leaf model, not a special case.
mdsmith kinds list [--json]
Print declared kinds with their merged bodies.
mdsmith kinds show <name> [--json]
Print the merged body of one kind (replaces
archetypes show).
mdsmith kinds path <name>
Print the filesystem path of the kind's
required-structure.schema, if any (replaces
archetypes path).
mdsmith kinds resolve <file> [--json]
Print the resolved kind list and merged rule
config for a file, with provenance per leaf.
mdsmith kinds why <file> <rule> [--json]
Print the full merge chain for one rule on one
file: every layer, including no-ops, with the
value at each step.
$ mdsmith check --explain plan/92_…md
plan/92_…md:11:1 MDS022 file too long (305 > 300)
└─ max-file-length.max=300 (default); kind 'plan'
did not override
Trailer per diagnostic, scoped to the rule that
fired. Same provenance source as kinds resolve.
--json on every subcommand and on check --explain
emits a structured form. Schema is stable enough for
an LSP / VS Code extension to consume. Fields cover
file path, effective kind list (with sources), and
per-leaf settings with their merge chains.
- Add a per-leaf provenance tracker to the
config-merge pipeline. Each leaf setting's final
value carries a list
[{layer, value, source}]. - Add
mdsmith kinds list(text +--json). - Add
mdsmith kinds show <name>andmdsmith kinds path <name>. - Add
mdsmith kinds resolve <file>rendering the resolved kind list and per-leaf provenance summary; add--json. - Add
mdsmith kinds why <file> <rule>rendering the full merge chain for a single rule; add--json. - Add
--explainflag tocheckandfix. After each diagnostic, print a one-line trailer naming the rule and the winning source of the setting that triggered the flag; in--jsonoutput the diagnostic carries anexplanationobject. - Document the JSON schema briefly in
docs/reference/cli.md. -
mdsmith help kinds-cliprints the subcommand summary.
-
mdsmith kinds listprints declared kinds with their merged bodies. -
mdsmith kinds show <name>prints one kind's merged body; exits 2 on unknown name. -
mdsmith kinds path <name>prints the path of the kind'srequired-structure.schema:if set; exits 2 otherwise. -
mdsmith kinds resolve <file>prints the resolved kind list and merged rule config; every leaf is tagged with its source (default / kind name / override / front-matter) (covered by test). -
mdsmith kinds why <file> <rule>prints the full merge chain — every layer that did or did not touch each leaf — for a single rule on a single file (covered by test). -
mdsmith check --explainprints, after each diagnostic, a trailer naming the rule and the source of the setting that triggered it (covered by test). -
--jsonon eachkindssubcommand and oncheck --explainproduces a stable structured form documented indocs/reference/cli.md(schema regression test). - No new state is required of rule implementations; provenance lives in the merge pipeline only.
-
mdsmith help kinds-clisummarizes the subcommand surface. - All tests pass:
go test ./... -
go tool golangci-lint runreports no issues