| id | 93 |
|---|---|
| title | Placeholder grammar — opt-in token vocabulary |
| status | ✅ |
| model | sonnet |
| summary | Lift the ad-hoc placeholder escapes (`# ?`, `## ...`, `{var}`, CUE front-matter values) into one named vocabulary that rules consult through a shared `placeholders:` Configurable setting. |
Make placeholder tokens (# ?, ## ..., {var},
CUE-pattern front-matter values) a first-class, named
vocabulary that any rule can opt into. A rule with the
placeholders: setting consults a shared helper to
treat configured tokens as opaque, not as content
violations.
This unblocks the adoption work in plan 96, which
needs the seven affected rules to stop tripping on
placeholder text in proto.md and similar files.
Files like plan/proto.md hold CUE schema patterns
in their front matter. Their bodies hold template
placeholders. Multiple rules flag those patterns as
content violations today:
first-line-headingflags# ?cross-file-reference-integrityflags[NAME](../../../docs/background/archetypes/NAME/)paragraph-readability,paragraph-structureflag the placeholder paragraphs- front-matter validation rejects CUE syntax
The current escape is ignore:, which silences every
rule. A scoped escape lets rules apply where they make
sense and skip the placeholder text where it doesn't.
Initial named tokens, registered in a central helper:
var-token—{identifier}interpolationheading-question—# ?,## ?,### ?placeholder-section—## ...cue-frontmatter— CUE pattern values in front matter (string predicates, regex literals, disjunctions)
The vocabulary is closed code — adding a token is one helper change plus per-rule opt-ins. The set is not tied to any specific kind.
Each opt-in rule exposes a placeholders: setting
through the existing Configurable interface. The
value is a list of token names. The rule treats those
tokens as opaque:
kinds:
proto:
rules:
first-line-heading:
placeholders: [var-token, heading-question]
cross-file-reference-integrity:
placeholders: [var-token]The shared helper provides:
- detection (does this AST node match a configured token?), and
- masking (rewrite the node to a content-neutral form for the rule's own analysis).
Each rule decides how to use the result. No rule references token names hardcoded in its own logic — the list comes from config.
- Rules:
first-line-heading,heading-increment,no-emphasis-as-heading,cross-file-reference-integrity,paragraph-readability,paragraph-structure,required-structure(for front-matter schema checks). - Directive consumers:
catalogfront-matter interpolation. - Engine: front-matter parsing under the
front-matter:config key. The same parser feeds thequerysubcommand, soqueryhonors the vocabulary automatically — without this, a file with CUE-pattern front matter (e.g.proto.md) fails to parse and breaksquery.
- Add the placeholder-grammar helper to a shared internal package: token registry, detection API, masking API.
- Add a
placeholders:setting to each opt-in rule viaConfigurable; default empty list. - Wire each rule's analysis to consult the helper
when its
placeholders:list is non-empty. - Wire
cataloginterpolation and engine front-matter parsing to the helper. - Document the placeholder grammar as a concept
page at
docs/background/concepts/placeholder-grammar.md(thearchetypesdoc directory is renamed in plan 98). Describe the token vocabulary, theplaceholders:rule-setting contract, and how rules opt in. Link from each opt-in rule README. mdsmith help placeholder-grammarprints a short concept page.- Unit tests per rule: with
placeholders:set, placeholder tokens produce no diagnostics; withplaceholders:empty, current behavior is unchanged. queryregression: a file in a placeholder-aware kind whose front matter contains CUE patterns parses successfully and is selectable byquery.
- The helper recognizes the four initial tokens and exposes detection + masking APIs.
- Each opt-in rule reads its
placeholders:setting viaConfigurableand consults the helper (verified by per-rule unit test). - With
placeholders:empty, every rule produces the same diagnostics it does today (regression test). - With
placeholders:set, configured tokens produce no diagnostics from that rule. -
catalogfront-matter interpolation and engine front-matter parsing honor the same vocabulary (test covers a CUE-pattern value in a<?catalog?>-eligible file). - Adding a new token is a one-file change in the helper plus per-rule opt-ins; no rule names tokens hardcoded in its logic (enforced by review).
- Concept page at
docs/background/concepts/placeholder-grammar.mddescribes the contract and is linked from each opt-in rule README. -
mdsmith help placeholder-grammarprints the concept page summary. -
mdsmith list queryparses a file with CUE-pattern front matter under a placeholder-aware kind (covered by test). - All tests pass:
go test ./... -
go tool golangci-lint runreports no issues