fix(validate): requiredSubComponents ids resolve to components or sub-components#25
Merged
Merged
Conversation
…-components The static governance-consistency check required requiredSubComponents ids to resolve strictly in the sub-component vocabulary, while the runtime linter (dspack-gen) and the spec's own wording match descendant nodes by component id — either kind. The shipped astryx governance (rule.review-offers-alternatives, rule.option-states-attributes) relies on the runtime interpretation, so the validator has failed main since the studio governance sync (#22). Align the static check with runtime semantics: the id must be declared as a top-level component or a composition sub-component; declaration alone never satisfies the rule at lint time. `on` references remain sub-component-only per spec. Adds a negative fixture for an id absent from both vocabularies and a spec §5 sentence stating the identifier-resolution rule. Runtime satisfaction (matching descendants beneath each governed node) is unchanged and covered by dspack-gen's lint tests and F3/F4/F9 goldens. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes the static governance-consistency validation so requiredSubComponents[].id may resolve to either a top-level component id or a composition sub-component id (matching runtime lint behavior and the spec’s “matching descendants” semantics), while keeping on references sub-component-only.
Changes:
- Update
scripts/validate.mjsresolution rules:requiredSubComponentsids now resolve against both component and sub-component vocabularies;onremains sub-component-only. - Add a negative fixture ensuring
requiredSubComponentsids that resolve to neither vocabulary are rejected with the expected resolution error. - Clarify spec v0.3 §5 with an explicit identifier-resolution rule for
requiredSubComponents(without changing satisfaction semantics).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| spec/dspack-v0.3.md | Clarifies that requiredSubComponents[].id must be declared as either a component or sub-component id; matching remains by descendant node component id. |
| scripts/validate.mjs | Adjusts static resolution checks so requiredSubComponents ids may resolve to either vocabulary while keeping on sub-component-only. |
| fixtures/negative/rule-required-subcomponent-unknown-ref.dspack.json | Adds a negative fixture covering unresolved requiredSubComponents ids. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
validatehas been red on main since #22. The studio governance sync added tworequired-compositionrules (rule.review-offers-alternatives,rule.option-states-attributes) whoserequiredSubComponentsreferenceselectable-cardandmetadata-list— deliberately declared as top-level components in the Astryx contract. The static governance-consistency check required those ids to resolve strictly in the sub-component vocabulary, soexamples/astryx.dspack.jsonfailed.The static validator was the outlier: dspack-gen's runtime linter matches
requiredSubComponentsagainst descendant nodes by component id (either kind), the spec's §5 wording says "matching descendants", and the shipped governance and goldens already rely on that interpretation.Change (narrow)
scripts/validate.mjs—requiredSubComponents[].idnow resolves to either a declared top-level component or a declared composition sub-component. Resolution guards vocabulary only; satisfaction stays a runtime (S3) concern — declaration in the contract never satisfies the rule.onreferences remain sub-component-only per spec.fixtures/negative/rule-required-subcomponent-unknown-ref.dspack.json— new negative fixture: an id absent from both vocabularies is rejected with the resolution error.spec/dspack-v0.3.md§5 — one clarifying paragraph stating the identifier-resolution rule; the existing "matching descendants" semantics are untouched.Regression coverage
examples/astryx.dspack.json(the two rules +ex.plan-comparison) — positive suiteexamples/shadcn-ui.dspack.json(rule.alertdialog-requires-cancel,rule.table-carries-structure,rule.table-carries-caption) — positive suite, unchangedsrc/core/lint/lint.test.ts("Required sub-component 'alert-dialog-cancel' (min 1) not found among descendants") + violating goldens F3/F4/F9. The static harness never evaluates satisfaction (S1/S2 only, per its header), so no conflation is possible here.Verification
npm run validate: schema-compile PASS (5 schemas); astryx ✔, shadcn ✔ — examples PASS (2 documents).npm run validate -- --fixtures negative: 18/18 rejected, each for its intended reason; all pre-existing fixtures' rejection messages unchanged, new fixture rejects withrequiredSubComponents reference 'ghost-panel' does not resolve in the contract.No RFC/DX work included. Once this merges, #24 (documentation-only RFC) should go green on rebase/rerun with no changes.
🤖 Generated with Claude Code