Skip to content

Commit 2eede5c

Browse files
jedudenclaude
andauthored
schema: unify section entry shape under heading: discriminator (plan 156) (#295)
Plan 156 collapses the section-entry vocabulary to one discriminator (`heading:` — null, string, or mapping) with a single matcher (`regex:` as a Go RE2 body with `\#(digits)` and `\#(fmvar(name))` helpers) and one cardinality field (`repeat: { min, max }`). Hard cutover: `aliases:`, `required:`, `{unlisted: true}`, scope-level `repeats:`/`sequential:`/ `min:`/`max:`, and `require.filename:` all parse-error with a "removed; see plan 156" diagnostic naming the replacement. Core changes: - internal/schema: new Matcher / Repeat structs, parse_inline.go / parse_file.go rewritten for the new shape, matcher.go centralises RE2 compilation with a bounded cache keyed on the pattern plus a frontmatter fingerprint (collision-safe via strconv.Quote). - validate.go: matchScope state machine (step / claimMatch / handleNonMatch / flagExtrasBeyondMax / finishRun) drives contiguous-run claiming with min/max enforcement, broad-and- after-min yield, out-of-order recovery, and non-contiguous flagging via claimedScopeMatches (claimCounts tracks per-scope occurrences so overlapping matchers don't inflate counts). - ScopeRunIndices helper shared with validate_content.go, acronyms.go's walkRanges, and requiredstructure/scope_rules.go so per-scope walkers honour the same run / yield semantics. - acronyms.go walkRanges surfaces the matched heading text so scope-name allowlists work with disjunctive regexes (`Symptoms|Indicators` + `scope: ["Indicators"]`). Config and fixtures: - .mdsmith.yml inline schemas migrated to the new shape. - .mdsmith.pinned.yml restates the same inline schemas in the pre-156 form so the mdsmith-fixed-version CI gate (pinned at v0.15.0) can lint the tree via `-c`; merge-queue.yml swaps it in over .mdsmith.yml with `git update-index --skip-worktree` to keep the worktree clean for merge-queue-action's git ops. - MDS020 good/bad fixtures updated to the new shape. - docs/guides/schemas.md and docs/reference/section-schema.md rewritten; the `aliases: [A, B]` → `regex: 'A|B'` row sits in prose because GFM's pipe-escape inside code spans renders inconsistently. - Reference acknowledges that MDS020's file-schema path still uses the legacy parseSchema pipeline; the new parser is the in-memory shape behind inline schemas. Regression coverage (TestPlan156_*): RegexMatchesRenderedPlainText, DigitsCaptureSequential, FmvarInterpolates, RepeatBoundsEnforced, RepeatMaxEnforcedInOpenSchema, RejectsUnknownInterpHelper, RepeatYieldsToOptionalLaterScope, SequentialDiagOnPartialRun, FmFingerprintCollisionGuard, RepeatSpansDeeperHeadings, FlagExtrasBeyondMaxSkipsDeeper, RejectsMultipleDigitsInline, OptionalSpecificClaimsOwnSlot, FlagsExtrasMatchingClaimedScope, OutOfOrderSequentialDiagFires, OptionalYieldsToBroadFollower, ScopeRunStopsAtBoundary, FlagsExtrasInIterationStream, UnboundedRepeatDoesNotFlagAsExceeded, BroadMatcherYieldsBeforeMin, LateClaimFlagsRepeatMin, WrongLevelMatchCountsTowardRepeat, RejectsInvalidFmvarPath, OptionalMatcherSkipsTolerated, BroadRepeatYieldsAcronymScope, BroadRepeatYieldsToLaterScopeInPerScopeWalkers, RejectsMultipleNTokensProto, AcronymScopeOnRepeatedScope, ContentOnRepeatedScope, RulesOnRepeatedScope, AcronymScopeMatchesByHeadingText, OutOfOrderRunCountsAvailableMatches, NonContiguousClaimedScopeFlagged, LateClaimChildRecursionStopsAtParentLevel, OverlappingMatcherDoesNotInflateClaimCount. https://claude.ai/code/session_012GGH62fZUzLuzP8T4ocGkJ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 4704dc5 commit 2eede5c

38 files changed

Lines changed: 5574 additions & 1230 deletions

.github/copilot-instructions.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ row: "- [{summary}](../{filename})"
9494
- [Built-in Markdown conventions, the rule presets each one applies, and how user config layers on top via deep-merge.](../docs/reference/conventions.md)
9595
- [Glob pattern syntax across mdsmith config, directives, and CLI argument expansion, with the supported exclusion semantics for each surface.](../docs/reference/globs.md)
9696
- [Named field-type shortcuts for inline schema frontmatter values — the registered names, the canonical CUE each one resolves to, and example usage.](../docs/reference/schema-types.md)
97-
- [Section-schema reference: the entry-shape vocabulary used in inline `kinds.<name>.schema:` blocks and `proto.md` files. Covers the `heading:` discriminator, the `regex:` matcher (a CUE expression with `digits` and `fmvar` helpers), the `repeat: {min, max}` cardinality field, and the matching algorithm.](../docs/reference/section-schema.md)
97+
- [Section-schema reference for inline `kinds.<name>.schema:` blocks. Covers the `heading:` discriminator, the `regex:` matcher (a Go RE2 body with `\#(digits)` and `\#(fmvar(...))` helpers), the `repeat: {min, max}` cardinality field, and the matching algorithm. `proto.md` files are parsed into the same shape by the schema package, but MDS020's file-schema check still uses its legacy parser; see the proto.md section below for what is and is not migrated.](../docs/reference/section-schema.md)
9898
<?/catalog?>
9999

100100
### Development Workflow
@@ -224,6 +224,12 @@ layout](https://go.dev/doc/modules/layout):
224224
punctuation
225225
- Prefer returning errors over panicking
226226

227+
#### Defensive Code
228+
229+
Add a defensive branch only when you can drive it
230+
red/green. Write the failing test first. Then add
231+
the code that takes the branch.
232+
227233
#### Test Fixtures
228234

229235
Rule test fixtures live in

.github/workflows/ci.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,13 @@ jobs:
182182
with:
183183
persist-credentials: false
184184
- uses: ./.github/actions/setup-mdsmith-pinned-version
185-
- run: mdsmith check .
185+
# Plan 156 reshaped the inline schema vocabulary; the pinned
186+
# baseline binary (v0.15.0) cannot parse the new form in
187+
# .mdsmith.yml. .mdsmith.pinned.yml restates the inline
188+
# schemas in the pre-156 shape so the pinned binary can lint
189+
# the tree. Delete this -c flag (and .mdsmith.pinned.yml)
190+
# once setup-mdsmith-pinned-version advances past v0.15.0.
191+
- run: mdsmith check -c .mdsmith.pinned.yml .
186192

187193
demo:
188194
uses: ./.github/workflows/record-demo.yml

.github/workflows/merge-queue.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,24 @@ jobs:
3636
persist-credentials: false
3737

3838
- uses: ./.github/actions/setup-mdsmith-pinned-version
39+
# The pinned merge driver / pre-merge-commit hook installer
40+
# reads .mdsmith.yml to derive merge-driver attribute globs;
41+
# the merge driver's `run` step (invoked by git during a
42+
# merge) does the same. v0.15.0 cannot parse plan 156's
43+
# inline schema vocabulary, so the workflow swaps in
44+
# .mdsmith.pinned.yml — a config restated in the pre-156
45+
# shape — for the entire job lifetime. `update-index
46+
# --skip-worktree` keeps the swap invisible to git so the
47+
# later checkout/merge operations performed by
48+
# merge-queue-action don't trip "local changes would be
49+
# overwritten" or try to restore the new-shape config
50+
# mid-merge. Remove this block once
51+
# setup-mdsmith-pinned-version advances past v0.15.0 (and
52+
# delete .mdsmith.pinned.yml).
53+
- name: Use pinned-binary config for merge driver
54+
run: |
55+
cp .mdsmith.pinned.yml .mdsmith.yml
56+
git update-index --skip-worktree .mdsmith.yml
3957
- name: Install mdsmith merge driver and pre-merge-commit hook
4058
run: |
4159
mdsmith merge-driver install

0 commit comments

Comments
 (0)