Skip to content

Complete rule category cleanup: replace "meta" with specific categories - #302

Merged
jeduden merged 13 commits into
mainfrom
claude/rule-category-cleanup-7Ex9B
May 16, 2026
Merged

Complete rule category cleanup: replace "meta" with specific categories#302
jeduden merged 13 commits into
mainfrom
claude/rule-category-cleanup-7Ex9B

Conversation

@jeduden

@jeduden jeduden commented May 16, 2026

Copy link
Copy Markdown
Owner

Summary

Completes the implementation of plan #162 by replacing the overloaded meta rule category with narrower buckets. Adds a deprecation translation so configs that previously used categories: {meta: false} are automatically migrated to the replacement categories with a warning.

Changes

  • Updated valid categories in internal/config/config.go:

    • Removed: "meta"
    • Added: "directive", "structural" (alphabetically sorted)
  • Migrated 19 rules from "meta" to appropriate categories:

    • Directive rules (6): catalog, include, build, toc, toc-directive, recipe-safety
    • Structural rules (6): required-structure, max-file-length, markdown-flavor, no-inline-html, directory-structure, git-hook-sync
    • Prose rules (7): paragraph-readability, paragraph-structure, token-budget, conciseness-scoring, duplicated-content, emphasis-style, ambiguous-emphasis
  • Deprecation migration in internal/config/load.go:

    • categories: {meta: false} in top-level, kinds, or overrides is translated to {directive: false, structural: false, prose: false} and a deprecation warning is emitted so existing configs continue to behave correctly
  • Updated documentation:

    • internal/rules/proto.md: Updated category writer-hint to list only categories in production code
    • 19 rule README files: Updated Meta-Information category bullets
  • Updated tests: All rule test files assert exact new category values; config tests cover all three deprecation/translation paths

  • Marked plan complete: Updated plan/162_rule-category-cleanup.md status to and checked all acceptance criteria

https://claude.ai/code/session_0175qQHwsrsmYZ2ZRtqgxNXd

Copilot AI review requested due to automatic review settings May 16, 2026 08:10
@codecov

codecov Bot commented May 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.26%. Comparing base (4a38260) to head (09ae030).

Additional details and impacted files
Components Coverage Δ
Go 96.22% <100.00%> (+<0.01%) ⬆️
TypeScript 99.35% <ø> (ø)

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR completes the rule-category cleanup by replacing the overloaded meta category with more specific rule categories used by mdsmith’s rule metadata, documentation, and tests.

Changes:

  • Reclassified affected rules into directive, structural, or prose.
  • Updated rule README metadata and the rule README prototype category hint.
  • Updated category tests and marked the implementation plan complete.

Reviewed changes

Copilot reviewed 60 out of 60 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
internal/config/config.go Updates recognized category names.
internal/rules/proto.md Updates rule README category guidance.
plan/162_rule-category-cleanup.md Marks plan acceptance criteria complete.
internal/rules/*/rule.go Updates affected rule Category() values.
internal/rules/*/rule_test.go Updates category assertions for affected rules.
internal/rules/MDS*/README.md Updates rule metadata category bullets.

Comment thread internal/config/config.go
Comment thread plan/162_rule-category-cleanup.md
Comment thread plan/162_rule-category-cleanup.md

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 60 out of 60 changed files in this pull request and generated 2 comments.

Comment thread internal/config/config.go
Comment thread internal/rules/include/rule.go

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 63 out of 63 changed files in this pull request and generated 2 comments.

Comment thread internal/config/load.go Outdated
Comment thread internal/rules/recipesafety/rule.go

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 63 out of 63 changed files in this pull request and generated 1 comment.

Comment thread internal/config/load.go Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 63 out of 63 changed files in this pull request and generated 2 comments.

Comment thread internal/config/load.go Outdated
Comment thread internal/config/load.go

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 63 out of 63 changed files in this pull request and generated 2 comments.

Comment thread internal/config/load.go Outdated
Comment thread internal/config/config_test.go Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 63 out of 63 changed files in this pull request and generated no new comments.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 63 out of 63 changed files in this pull request and generated 2 comments.

Comment thread internal/config/load.go Outdated
Comment thread internal/config/config_test.go Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 63 out of 63 changed files in this pull request and generated 2 comments.

Comment thread internal/config/load.go
Comment thread internal/config/config_test.go

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 103 out of 103 changed files in this pull request and generated 1 comment.

Comment thread internal/rules/proto.md Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 103 out of 103 changed files in this pull request and generated 1 comment.

Comment thread internal/rules/proto.md
@jeduden
jeduden requested a review from Copilot May 16, 2026 10:07
@jeduden
jeduden force-pushed the claude/rule-category-cleanup-7Ex9B branch from ec6f144 to cd566e0 Compare May 16, 2026 10:07
claude added 13 commits May 16, 2026 10:08
…tural

Splits meta into narrower buckets so Category() usefully partitions
the rule set. Updates rule.go, rule_test.go, and each README's
Meta-Information bullet for all 19 affected rules. Adds directive
and structural to config.ValidCategories; drops meta. Updates
internal/rules/proto.md writer-hint comment to match.

Closes plan/162_rule-category-cleanup.md.

https://claude.ai/code/session_0175qQHwsrsmYZ2ZRtqgxNXd
…Category

Adds detectMetaCategoryDeprecations to emit a human-readable
deprecation message when any categories block still references
the old meta key, mirroring the existing no-follow-symlinks /
archetypes deprecation pattern.

Tightens internal/rules/include/rule_test.go TestCategory from
NotEmpty to an exact "directive" assertion so the value cannot
regress silently.

https://claude.ai/code/session_0175qQHwsrsmYZ2ZRtqgxNXd
When a config contains categories: {meta: false}, expand it to
{directive: false, structural: false, prose: false} (where not already
set) so the user's disable intent is preserved after the rename.
The deprecation message still fires to prompt the config update.

Updates tests to assert both the warning and the translated values.

https://claude.ai/code/session_0175qQHwsrsmYZ2ZRtqgxNXd
…n messages

Multiple overrides each containing meta: false would append the
deprecation message once per matching override. Flip warned after
the first match, mirroring the kinds loop behaviour.

Adds two tests: one for multiple overrides (verifies single emission
and translates all), one for top-level + kind together (covers the
!warned=false branch in the kinds loop).

https://claude.ai/code/session_0175qQHwsrsmYZ2ZRtqgxNXd
… per-name

prose was a pre-existing category; setting prose: false would also
disable rules (proper-names, forbidden-text, etc.) that were never
in meta. Instead:
- Only set directive: false and structural: false via category toggle
  (both are entirely new, so no pre-existing rules are affected).
- Disable the 7 rules that moved from meta to prose individually
  (paragraph-readability, paragraph-structure, token-budget,
  conciseness-scoring, duplicated-content, emphasis-style,
  ambiguous-emphasis), initializing the rules map if nil.

Updates deprecation message and all five meta-category tests.

https://claude.ai/code/session_0175qQHwsrsmYZ2ZRtqgxNXd
…opt-in rules

categories: {meta: true} only enabled the category filter; it did not
opt in default-disabled rules. Inserting Enabled: true for moved prose
rules (conciseness-scoring, duplicated-content, emphasis-style,
ambiguous-emphasis) after Merge would unexpectedly activate those checks.

Only call applyMovedProseRules when meta value is false (disabling).
Adds TestLoad_MetaCategoryTrueDoesNotEnableOptInProseRules to cover
the meta: true path.

https://claude.ai/code/session_0175qQHwsrsmYZ2ZRtqgxNXd
detectMetaCategoryDeprecations had complexity 32 (limit 30). Extract
migrateMetaCategory and applyMovedProseRules helpers, collect all
migration results and emit the deprecation once at the end rather
than per-location. Complexity drops to ~8.

https://claude.ai/code/session_0175qQHwsrsmYZ2ZRtqgxNXd
Category-to-category translation and per-rule materialization both have
fundamental layering issues: explicit RuleCfg{Enabled:false} inserted at
load time cannot be overridden by a later kind/override meta: true toggle,
breaking the merge semantics that the old meta category relied on.

The correct behavior is to warn once when meta appears anywhere in the
config and let the user update their config. meta: false is now inert
(no rule returns "meta", so ApplyCategories is unaffected), which means
rules that were disabled via meta: false are re-enabled after upgrade —
the user sees new lint failures and the deprecation message tells them
what to fix.

Removes translateMetaCategory, applyMovedProseRules, and migrateMetaCategory.
Replaces all six meta-migration tests with five simpler warn-only tests.

https://claude.ai/code/session_0175qQHwsrsmYZ2ZRtqgxNXd
Adds a `category:` field to the frontmatter of all 58 rule READMEs
(MDS001–MDS058) and to both proto schema files (proto.md and
directive-proto.md). The proto.md schema constrains the value to a CUE
disjunction of the 11 ValidCategories, so `mdsmith check` now enforces
valid category values via required-structure — the same mechanism that
already validates id, name, status, description, and nature.

directive-proto.md constrains category to '"directive"' (the only valid
value for the four directive rule READMEs).

https://claude.ai/code/session_0175qQHwsrsmYZ2ZRtqgxNXd
The proto.md comment implied the category list was automatically
sourced from config.ValidCategories. Reword to state the CUE union in
this file's front matter is hand-kept in sync with that constant —
there is no code path binding the two.

https://claude.ai/code/session_0175qQHwsrsmYZ2ZRtqgxNXd
@jeduden
jeduden force-pushed the claude/rule-category-cleanup-7Ex9B branch from cd566e0 to 09ae030 Compare May 16, 2026 10:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 103 out of 103 changed files in this pull request and generated no new comments.

@jeduden
jeduden merged commit 024dad8 into main May 16, 2026
19 checks passed
jeduden pushed a commit that referenced this pull request May 16, 2026
Adds the composition engine so a file resolved by multiple kinds
can get the union of every kind's required-structure schema
instead of the last one winning.

- internal/schema.Compose merges frontmatter (CUE conjunction for
  shared keys), sections (merge by heading label; `## ...` slots,
  bare `?`, preamble stay distinct), Closed (stricter wins),
  Matcher cardinality (required-by-any wins), Filename (first
  non-empty; conflicts error), CrossReferences/Acronyms/Index
  (acronyms: document-wide scope wins). Built against the
  plan-156 #295 unified `heading:` discriminator model.
- The config merge layer accumulates each layer's `schema:` /
  `inline-schema:` into an append-mode `schema-sources` list via
  the new rule.SettingsTranslator interface, so internal/config
  carries no rule-name special case (mirrors rule.ListMerger).
- MDS020 loads every source, composes them, validates the
  composed schema; single-source keeps the legacy file/inline
  paths; multi-source Fix writes the composed Index side-output.
- docs: schemas guide gains a "Composition across kinds" worked
  example; cross-system doc records the contract.

Deferred: wiring directive-rule-readme to compose on top of
rule-readme. main now keeps Meta-Information last with Pattern
before it (#295/#302); appending directive-proto.md's Pattern
after rule-readme's Meta-Information would order it wrong. That
schema restructuring (review comment 2) is tracked separately;
.mdsmith.yml and directive-proto.md stay on main's standalone
directive-rule-readme schema for now.

Full suite, lint, and mdsmith check green.
jeduden pushed a commit that referenced this pull request May 16, 2026
Adds the composition engine so a file resolved by multiple kinds
can get the union of every kind's required-structure schema
instead of the last one winning.

- internal/schema.Compose merges frontmatter (CUE conjunction for
  shared keys), sections (merge by heading label; `## ...` slots,
  bare `?`, preamble stay distinct), Closed (stricter wins),
  Matcher cardinality (required-by-any wins), Filename (first
  non-empty; conflicts error), CrossReferences/Acronyms/Index
  (acronyms: document-wide scope wins). Built against the
  plan-156 #295 unified `heading:` discriminator model.
- The config merge layer accumulates each layer's `schema:` /
  `inline-schema:` into an append-mode `schema-sources` list via
  the new rule.SettingsTranslator interface, so internal/config
  carries no rule-name special case (mirrors rule.ListMerger).
- MDS020 loads every source, composes them, validates the
  composed schema; single-source keeps the legacy file/inline
  paths; multi-source Fix writes the composed Index side-output.
- docs: schemas guide gains a "Composition across kinds" worked
  example; cross-system doc records the contract.

Deferred: wiring directive-rule-readme to compose on top of
rule-readme. main now keeps Meta-Information last with Pattern
before it (#295/#302); appending directive-proto.md's Pattern
after rule-readme's Meta-Information would order it wrong. That
schema restructuring (review comment 2) is tracked separately;
.mdsmith.yml and directive-proto.md stay on main's standalone
directive-rule-readme schema for now.

Full suite, lint, and mdsmith check green.
jeduden added a commit that referenced this pull request May 16, 2026
* Plan 156: composable required-structure schemas (engine)

Adds the composition engine so a file resolved by multiple kinds
can get the union of every kind's required-structure schema
instead of the last one winning.

- internal/schema.Compose merges frontmatter (CUE conjunction for
  shared keys), sections (merge by heading label; `## ...` slots,
  bare `?`, preamble stay distinct), Closed (stricter wins),
  Matcher cardinality (required-by-any wins), Filename (first
  non-empty; conflicts error), CrossReferences/Acronyms/Index
  (acronyms: document-wide scope wins). Built against the
  plan-156 #295 unified `heading:` discriminator model.
- The config merge layer accumulates each layer's `schema:` /
  `inline-schema:` into an append-mode `schema-sources` list via
  the new rule.SettingsTranslator interface, so internal/config
  carries no rule-name special case (mirrors rule.ListMerger).
- MDS020 loads every source, composes them, validates the
  composed schema; single-source keeps the legacy file/inline
  paths; multi-source Fix writes the composed Index side-output.
- docs: schemas guide gains a "Composition across kinds" worked
  example; cross-system doc records the contract.

Deferred: wiring directive-rule-readme to compose on top of
rule-readme. main now keeps Meta-Information last with Pattern
before it (#295/#302); appending directive-proto.md's Pattern
after rule-readme's Meta-Information would order it wrong. That
schema restructuring (review comment 2) is tracked separately;
.mdsmith.yml and directive-proto.md stay on main's standalone
directive-rule-readme schema for now.

Full suite, lint, and mdsmith check green.

* test: cover compose.go mergeMatcher/cloneContent branches

codecov/changes flagged 8 uncovered lines in internal/schema/
compose.go — the schema-model port's mergeMatcher and cloneContent
helpers. Add targeted same-package unit tests for: a/b nil matcher
arms, min/max widening (required-wins, wider-max, optional-both,
bounded+unbounded), Sequential OR, and the Columns deep-copy
branch. compose.go is now 100% line and branch covered (gobco
clean); full suite, lint, and mdsmith check green.

* fix: preserve dual-schema-source guard through layer translation

Copilot review (PR #288): when a single config layer sets both a
non-empty `schema:` and a non-empty `inline-schema:`,
extractSchemaSourceFromSettings returned at the `schema` arm and
TranslateLayerSettings then stripped both keys, silently dropping
the inline source. The rule's rejectDualSchemaSettings guard in
ApplySettings was bypassed because translation removed the keys
before ApplySettings ran, and top-level cfg.Rules / overrides /
convention presets are not covered by validateKindSchemaSources.

TranslateLayerSettings now detects a dual-source layer
(hasDualSchemaSource, mirroring rejectDualSchemaSettings'
non-empty semantics) and passes the layer through untouched, so
the keys survive deep-merge and the existing guard still surfaces
the original "cannot set both" config error. Cross-layer
composition is unaffected — the check only fires when one map
carries both. Added regression tests; new code is 100% line and
branch covered.

* test: direct branch unit tests for archetype/schema-source/kinds

isLikelyArchetypeName, extractSchemaSourceFromSettings, and
EffectiveKinds were only exercised indirectly via call sites,
leaving codecov/changes flagging per-file coverage drift. Add
table-driven unit tests that hit every return path directly so
the three functions report 100% line and branch coverage.

https://claude.ai/code/session_01C4XwUp4AkhzqjrvSSHMMZS

* fix: intersect composed cardinality and error on disjoint ranges

mergeMatcher widened the run-length max (took the larger of the two
maxima), which broke the composition contract "every input's
constraint holds": composing 1..3 with 5..10 silently yielded 5..10,
dropping the ..3 cap. Make cardinality a true intersection — min is
the larger bound, max is the smaller (0 = unbounded), and disjoint
ranges return a composition error, mirroring how conflicting filename
patterns surface. Thread the error through mergeScopes and
composeSectionLists; flatten the latter behind a section accumulator
so the added error paths stay within the complexity budget.

Also relocate the misplaced TestApplySettings_SchemaSourcesList doc
comment to its function so it no longer stacks above an unrelated
test.

https://claude.ai/code/session_01C4XwUp4AkhzqjrvSSHMMZS

* docs: file plan 169 for rule-README Meta-Information sync

PR #288 review raised that Meta-Information must be the terminal
section and its bullets should render from frontmatter. The
rule-readme schema permits later sections and MDS020's file-schema
path still uses the legacy parser, so frontmatter body-sync is
unwired. Scope that out of the plan-156 PR into its own plan rather
than expanding #288's blast radius across all rule READMEs.

https://claude.ai/code/session_01C4XwUp4AkhzqjrvSSHMMZS

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants