diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0f37cb7..c85affa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,7 @@ # Contributing to dspack-export dspack-export generates [dspack](https://github.com/aestheticfunction/dspack) -v0.2 snapshots from component codebases — React + Tailwind/shadcn and +v0.4 snapshots from component codebases — React + Tailwind/shadcn and Vue 3 + Vuetify 3. Contributions — bug reports, extraction-gap reports, documentation, and code — are welcome. @@ -30,8 +30,9 @@ diffing, watch mode, CI gates, or write-back will be closed with a pointer to this section. This is what keeps the tool small, auditable, and maintained. -Deferred-but-in-scope (roadmap, PRs welcome after discussion): a merge -workflow that preserves hand-authored dspack sections across regeneration, +Shipped since 0.4.0: section-level regeneration that preserves +hand-authored dspack content (`regenerateSections()`, library API only — +a CLI flag for it is still open), Storybook enrichment (stories/snippets from the static manifest), compound component grouping into `composition.subComponents`, and additional extraction conventions — see [docs/maintainership.md](docs/maintainership.md) diff --git a/README.md b/README.md index 0b22744..38020e3 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ Then, from your design-system project (with its own dependencies installed): ```bash dspack-export init # detect conventions, write config +dspack-export init --force # overwrite an existing config dspack-export generate --config dspack-export.config.json dspack-export validate my-system.dspack.json ``` diff --git a/docs/alpha-decision.md b/docs/alpha-decision.md index 0f5276e..77e9338 100644 --- a/docs/alpha-decision.md +++ b/docs/alpha-decision.md @@ -1,5 +1,10 @@ # Alpha Decision Report (2026-06-10) +> **Historical record (alpha, 2026-06).** Kept for provenance. Two claims +> below are superseded: the tool now emits dspack **v0.4** (not v0.2), and +> regeneration **refuses** rather than overwriting hand edits (see the +> [handbook](handbook.md) and README for current behavior). + > **Status update (same day):** the private-alpha gate described in the > recommendation below was waived — no additional internal alpha users were > available, and the maintainer served as both implementer and alpha user. diff --git a/docs/handbook.md b/docs/handbook.md index c0b8e2e..dce547a 100644 --- a/docs/handbook.md +++ b/docs/handbook.md @@ -1,12 +1,12 @@ # dspack-export — Handbook -Status: **experimental** (`0.2.0-alpha.0`). Not on npm; install from this -repository. Expect rough edges — please report everything that surprises you +Status: **experimental** (`0.5.0`), published to npm as +`@aestheticfunction/dspack-export`. Expect rough edges — please report everything that surprises you (see [CONTRIBUTING](../CONTRIBUTING.md) for the issue templates to use). ## What it does -`dspack-export` generates a [dspack v0.2](https://github.com/aestheticfunction/dspack) +`dspack-export` generates a [dspack v0.4](https://github.com/aestheticfunction/dspack) snapshot of a React + Tailwind/shadcn design system: components and props (including cva variant enums and their defaults), semantic color/radius tokens from CSS custom properties, dark-theme overrides, layout breakpoints, and React @@ -60,7 +60,7 @@ ds-mcp --dspack ./your-system.dspack.json Deterministic output (reviewable diffs, golden files): set `SOURCE_DATE_EPOCH=` to pin `metadata.generatedAt`. -## Supported stack (alpha) +## Supported stack | Surface | Supported | Notes | |---|---|---| @@ -215,9 +215,12 @@ All relative paths resolve against the config file's directory. typing) fall back to AST discovery: present, but with stub descriptions and no props. - **Hand-authored dspack sections are not generated** (`patterns`, - `antiPatterns`, `whenToUse`, `accessibility`, `composition`, `constraints`) - and **regeneration overwrites the output file** — keep hand edits in a - separate copy for now (a merge workflow is on the roadmap). + `antiPatterns`, `whenToUse`, `accessibility`, `composition`, `constraints`). + **Regeneration never overwrites them**: `generate` refuses when the output + carries human-authored content, and there is deliberately no force flag. To + merge fresh extraction into an existing contract, hosts call the + `regenerateSections()` library API (see the README) — there is no CLI flag + for it yet. - **DTCG import is resolved-values-only.** Alias/reference values are skipped (resolve them in your token tool first); only `color`, `dimension`, `fontFamily`, and `fontWeight` types are mapped; other types are skipped with diff --git a/src/emit/schema/dspack.v0.4.schema.json b/src/emit/schema/dspack.v0.4.schema.json index e288828..9840c9e 100644 --- a/src/emit/schema/dspack.v0.4.schema.json +++ b/src/emit/schema/dspack.v0.4.schema.json @@ -1,1554 +1,1586 @@ { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://github.com/aestheticfunction/dspack/blob/main/schema/dspack.v0.4.schema.json", - "title": "dspack v0.4", - "description": "Schema for dspack v0.4 — a JSON format for representing design system corpora. Backward-compatible with v0.1–v0.3 documents; adds component categories (a contract-defined category registry referenced by component metadata and rules) and the required-props rule type.", - "type": "object", - "required": [ - "dspack", - "name" - ], - "properties": { - "$schema": { - "type": "string", - "description": "URI reference to this JSON Schema. Optional; consumers MUST NOT require this property." + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/aestheticfunction/dspack/blob/main/schema/dspack.v0.4.schema.json", + "title": "dspack v0.4", + "description": "Schema for dspack v0.4 \u2014 a JSON format for representing design system corpora. Backward-compatible with v0.1\u2013v0.3 documents; adds component categories (a contract-defined category registry referenced by component metadata and rules) and the required-props rule type.", + "type": "object", + "required": [ + "dspack", + "name" + ], + "properties": { + "$schema": { + "type": "string", + "description": "URI reference to this JSON Schema. Optional; consumers MUST NOT require this property." + }, + "dspack": { + "type": "string", + "const": "0.4", + "description": "Specification version. MUST be \"0.4\" for documents conforming to this version." + }, + "name": { + "type": "string", + "minLength": 1, + "description": "Human-readable name of the design system." + }, + "description": { + "type": "string", + "description": "Brief description of the design system's purpose and scope." + }, + "version": { + "type": "string", + "description": "Version of the design system content (not the spec version)." + }, + "metadata": { + "$ref": "#/$defs/metadata" + }, + "tokens": { + "type": "object", + "description": "Token definitions organized by category.", + "propertyNames": { + "pattern": "^[a-z][a-z0-9-]*$" + }, + "additionalProperties": { + "$ref": "#/$defs/tokenCategory" + } + }, + "components": { + "type": "object", + "description": "Component definitions keyed by component ID.", + "propertyNames": { + "pattern": "^[a-z][a-z0-9-]*$" + }, + "additionalProperties": { + "$ref": "#/$defs/componentEntry" + } + }, + "categories": { + "type": "object", + "description": "Contract-defined component category registry. Categories are the contract's own taxonomy (dspack bakes none in); component/sub-component metadata and category-based rule fields reference these ids. Referenced ids MUST be registered here.", + "propertyNames": { + "pattern": "^[a-z][a-z0-9-]*$" + }, + "additionalProperties": { + "$ref": "#/$defs/categoryEntry" + } + }, + "patterns": { + "type": "array", + "description": "Pattern entries describing preferred ways of combining components.", + "items": { + "$ref": "#/$defs/patternEntry" + } + }, + "antiPatterns": { + "type": "array", + "description": "Anti-pattern entries describing approaches that are deliberately ruled out.", + "items": { + "$ref": "#/$defs/antiPatternEntry" + } + }, + "intents": { + "type": "array", + "description": "Named generation intents \u2014 the vocabulary that scopes governance rules and examples. Referenced by rules[].appliesTo.intents and examples[].intent, and declared by callers when requesting generation.", + "items": { + "$ref": "#/$defs/intentEntry" + } + }, + "rules": { + "type": "array", + "description": "Machine-checkable governance rules, evaluated deterministically over dspack surface documents. Each rule is a typed, structured predicate plus a human-readable rationale. Evaluation semantics per type are normative in the v0.3 specification (the three original types) and the v0.4 specification (required-props, forbiddenCategories).", + "items": { + "$ref": "#/$defs/ruleEntry" + } + }, + "examples": { + "type": "array", + "description": "Compilable example surfaces tied to named intents. Examples serve double duty as documentation and few-shot exemplars; each surface must validate against the dspack surface schema and the contract vocabulary.", + "items": { + "$ref": "#/$defs/exampleEntry" + } + }, + "frameworkBindings": { + "type": "object", + "description": "Framework-specific information keyed by framework identifier.", + "propertyNames": { + "pattern": "^[a-z][a-z0-9-]*$" + }, + "additionalProperties": { + "$ref": "#/$defs/frameworkBinding" + } + }, + "themes": { + "type": "object", + "description": "Named sets of token overrides representing alternative visual modes.", + "propertyNames": { + "pattern": "^[a-z][a-z0-9-]*$" + }, + "additionalProperties": { + "$ref": "#/$defs/themeEntry" + } + }, + "layout": { + "$ref": "#/$defs/layoutPrimitives" + } + }, + "additionalProperties": true, + "$defs": { + "metadata": { + "type": "object", + "description": "Extensible metadata about the dspack file.", + "properties": { + "generatedBy": { + "type": "string", + "description": "Tool or process that created this file." }, - "dspack": { - "type": "string", - "const": "0.4", - "description": "Specification version. MUST be \"0.4\" for documents conforming to this version." + "generatedAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 datetime when the file was generated." }, - "name": { - "type": "string", - "minLength": 1, - "description": "Human-readable name of the design system." + "source": { + "type": "string", + "description": "URL or description of the upstream source." }, + "license": { + "type": "string", + "description": "SPDX license identifier or freeform description." + } + }, + "additionalProperties": true + }, + "tokenCategory": { + "type": "object", + "description": "A category of tokens.", + "required": [ + "values" + ], + "properties": { "description": { - "type": "string", - "description": "Brief description of the design system's purpose and scope." + "type": "string", + "description": "What this category covers." }, - "version": { - "type": "string", - "description": "Version of the design system content (not the spec version)." + "tier": { + "type": "string", + "enum": [ + "primitive", + "semantic", + "component" + ], + "description": "Default abstraction level for tokens in this category." }, - "metadata": { - "$ref": "#/$defs/metadata" + "values": { + "type": "object", + "description": "Map of token name to token entry.", + "propertyNames": { + "pattern": "^[a-z][a-z0-9-]*$" + }, + "additionalProperties": { + "$ref": "#/$defs/tokenEntry" + } + } + }, + "additionalProperties": true + }, + "tokenEntry": { + "type": "object", + "description": "A single token definition.", + "required": [ + "value" + ], + "properties": { + "value": { + "type": "string", + "description": "The resolved value of the token." }, - "tokens": { - "type": "object", - "description": "Token definitions organized by category.", - "propertyNames": { - "pattern": "^[a-z][a-z0-9-]*$" - }, - "additionalProperties": { - "$ref": "#/$defs/tokenCategory" - } + "description": { + "type": "string", + "description": "Semantic meaning of the token." }, - "components": { - "type": "object", - "description": "Component definitions keyed by component ID.", - "propertyNames": { - "pattern": "^[a-z][a-z0-9-]*$" + "type": { + "type": "string", + "description": "The value type (e.g., color, dimension, fontFamily)." + }, + "deprecated": { + "type": "boolean", + "description": "Whether this token is deprecated.", + "default": false + }, + "aliases": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Other names by which this token is known." + }, + "status": { + "oneOf": [ + { + "type": "string", + "enum": [ + "draft", + "experimental", + "stable", + "deprecated" + ] }, - "additionalProperties": { - "$ref": "#/$defs/componentEntry" + { + "$ref": "#/$defs/statusObject" } + ], + "description": "Lifecycle stage. String for uniform status, object for per-platform granularity." }, - "categories": { - "type": "object", - "description": "Contract-defined component category registry. Categories are the contract's own taxonomy (dspack bakes none in); component/sub-component metadata and category-based rule fields reference these ids. Referenced ids MUST be registered here.", - "propertyNames": { - "pattern": "^[a-z][a-z0-9-]*$" + "aliasOf": { + "oneOf": [ + { + "type": "string", + "description": "Token name that this token aliases." }, - "additionalProperties": { - "$ref": "#/$defs/categoryEntry" + { + "$ref": "#/$defs/aliasReference" } + ], + "description": "Token that this token aliases. String for unambiguous names, object for cross-category disambiguation." }, - "patterns": { - "type": "array", - "description": "Pattern entries describing preferred ways of combining components.", - "items": { - "$ref": "#/$defs/patternEntry" - } + "tier": { + "type": "string", + "enum": [ + "primitive", + "semantic", + "component" + ], + "description": "Abstraction level of this token, overriding the category default." + } + }, + "additionalProperties": true + }, + "statusObject": { + "type": "object", + "description": "Lifecycle status with per-platform granularity.", + "required": [ + "default" + ], + "properties": { + "default": { + "type": "string", + "enum": [ + "draft", + "experimental", + "stable", + "deprecated" + ], + "description": "Default lifecycle stage when no platform-specific override applies." }, - "antiPatterns": { - "type": "array", - "description": "Anti-pattern entries describing approaches that are deliberately ruled out.", - "items": { - "$ref": "#/$defs/antiPatternEntry" - } + "platforms": { + "type": "object", + "description": "Map of platform/framework ID to platform status object.", + "propertyNames": { + "pattern": "^[a-z][a-z0-9-]*$" + }, + "additionalProperties": { + "$ref": "#/$defs/platformStatus" + } + } + }, + "additionalProperties": true + }, + "platformStatus": { + "type": "object", + "description": "Lifecycle status for a specific platform.", + "required": [ + "stage" + ], + "properties": { + "stage": { + "type": "string", + "enum": [ + "draft", + "experimental", + "stable", + "deprecated" + ], + "description": "Lifecycle stage for this platform." }, - "intents": { - "type": "array", - "description": "Named generation intents — the vocabulary that scopes governance rules and examples. Referenced by rules[].appliesTo.intents and examples[].intent, and declared by callers when requesting generation.", - "items": { - "$ref": "#/$defs/intentEntry" - } + "since": { + "type": "string", + "description": "Version of the design system content at which this stage took effect." }, - "rules": { - "type": "array", - "description": "Machine-checkable governance rules, evaluated deterministically over dspack surface documents. Each rule is a typed, structured predicate plus a human-readable rationale. Evaluation semantics per type are normative in the v0.3 specification (the three original types) and the v0.4 specification (required-props, forbiddenCategories).", - "items": { - "$ref": "#/$defs/ruleEntry" - } + "migrateTo": { + "type": "string", + "description": "Component ID or token name of the recommended replacement." }, - "examples": { - "type": "array", - "description": "Compilable example surfaces tied to named intents. Examples serve double duty as documentation and few-shot exemplars; each surface must validate against the dspack surface schema and the contract vocabulary.", - "items": { - "$ref": "#/$defs/exampleEntry" - } + "note": { + "type": "string", + "description": "Prose migration guidance or context for this platform's status." + } + }, + "additionalProperties": true + }, + "aliasReference": { + "type": "object", + "description": "Structured token alias reference for cross-category disambiguation.", + "required": [ + "category", + "token" + ], + "properties": { + "category": { + "type": "string", + "description": "Token category name containing the referenced token." }, - "frameworkBindings": { - "type": "object", - "description": "Framework-specific information keyed by framework identifier.", - "propertyNames": { - "pattern": "^[a-z][a-z0-9-]*$" - }, - "additionalProperties": { - "$ref": "#/$defs/frameworkBinding" - } + "token": { + "type": "string", + "description": "Token name within that category." + } + }, + "additionalProperties": true + }, + "componentEntry": { + "type": "object", + "description": "A component definition.", + "required": [ + "name", + "description" + ], + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "Human-readable display name." + }, + "description": { + "type": "string", + "description": "What the component is for." }, - "themes": { - "type": "object", - "description": "Named sets of token overrides representing alternative visual modes.", - "propertyNames": { - "pattern": "^[a-z][a-z0-9-]*$" + "whenToUse": { + "type": "string", + "description": "Guidance on when to use this component." + }, + "whenNotToUse": { + "type": "string", + "description": "Guidance on when to choose a different component." + }, + "props": { + "type": "object", + "description": "Map of prop name to prop descriptor.", + "additionalProperties": { + "$ref": "#/$defs/propDescriptor" + } + }, + "tokens": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Token names this component depends on." + }, + "relatedComponents": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Component IDs of related components." + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Freeform classification tags." + }, + "deprecated": { + "type": "boolean", + "description": "Whether this component is deprecated.", + "default": false + }, + "deprecatedMessage": { + "type": "string", + "description": "What to use instead of this component." + }, + "status": { + "oneOf": [ + { + "type": "string", + "enum": [ + "draft", + "experimental", + "stable", + "deprecated" + ] }, - "additionalProperties": { - "$ref": "#/$defs/themeEntry" + { + "$ref": "#/$defs/statusObject" } + ], + "description": "Lifecycle stage. String for uniform status, object for per-platform granularity." + }, + "accessibility": { + "$ref": "#/$defs/accessibilityConstraints" + }, + "composition": { + "$ref": "#/$defs/compositionRules" }, - "layout": { - "$ref": "#/$defs/layoutPrimitives" + "constraints": { + "type": "array", + "description": "Structured usage constraints.", + "items": { + "$ref": "#/$defs/constraintEntry" + } + }, + "categories": { + "type": "array", + "description": "Category ids this entry belongs to; each MUST be registered in the top-level categories registry.", + "items": { + "type": "string" + }, + "minItems": 1 } + }, + "additionalProperties": true }, - "additionalProperties": true, - "$defs": { - "metadata": { - "type": "object", - "description": "Extensible metadata about the dspack file.", - "properties": { - "generatedBy": { - "type": "string", - "description": "Tool or process that created this file." - }, - "generatedAt": { - "type": "string", - "format": "date-time", - "description": "ISO 8601 datetime when the file was generated." - }, - "source": { - "type": "string", - "description": "URL or description of the upstream source." - }, - "license": { - "type": "string", - "description": "SPDX license identifier or freeform description." - } - }, - "additionalProperties": true + "propDescriptor": { + "type": "object", + "description": "Describes a single component prop.", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "description": "The value type of the prop (e.g., string, number, boolean, enum)." }, - "tokenCategory": { - "type": "object", - "description": "A category of tokens.", - "required": [ - "values" - ], - "properties": { - "description": { - "type": "string", - "description": "What this category covers." - }, - "tier": { - "type": "string", - "enum": [ - "primitive", - "semantic", - "component" - ], - "description": "Default abstraction level for tokens in this category." - }, - "values": { - "type": "object", - "description": "Map of token name to token entry.", - "propertyNames": { - "pattern": "^[a-z][a-z0-9-]*$" - }, - "additionalProperties": { - "$ref": "#/$defs/tokenEntry" - } - } - }, - "additionalProperties": true + "description": { + "type": "string", + "description": "What this prop controls." }, - "tokenEntry": { - "type": "object", - "description": "A single token definition.", - "required": [ - "value" - ], - "properties": { - "value": { - "type": "string", - "description": "The resolved value of the token." - }, - "description": { - "type": "string", - "description": "Semantic meaning of the token." - }, - "type": { - "type": "string", - "description": "The value type (e.g., color, dimension, fontFamily)." - }, - "deprecated": { - "type": "boolean", - "description": "Whether this token is deprecated.", - "default": false - }, - "aliases": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Other names by which this token is known." - }, - "status": { - "oneOf": [ - { - "type": "string", - "enum": [ - "draft", - "experimental", - "stable", - "deprecated" - ] - }, - { - "$ref": "#/$defs/statusObject" - } - ], - "description": "Lifecycle stage. String for uniform status, object for per-platform granularity." - }, - "aliasOf": { - "oneOf": [ - { - "type": "string", - "description": "Token name that this token aliases." - }, - { - "$ref": "#/$defs/aliasReference" - } - ], - "description": "Token that this token aliases. String for unambiguous names, object for cross-category disambiguation." - }, - "tier": { - "type": "string", - "enum": [ - "primitive", - "semantic", - "component" - ], - "description": "Abstraction level of this token, overriding the category default." - } - }, - "additionalProperties": true + "values": { + "type": "array", + "description": "For enum type, the allowed values. Items may be bare values or value descriptor objects.", + "items": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "$ref": "#/$defs/valueDescriptor" + } + ] + } }, - "statusObject": { - "type": "object", - "description": "Lifecycle status with per-platform granularity.", - "required": [ - "default" - ], - "properties": { - "default": { - "type": "string", - "enum": [ - "draft", - "experimental", - "stable", - "deprecated" - ], - "description": "Default lifecycle stage when no platform-specific override applies." - }, - "platforms": { - "type": "object", - "description": "Map of platform/framework ID to platform status object.", - "propertyNames": { - "pattern": "^[a-z][a-z0-9-]*$" - }, - "additionalProperties": { - "$ref": "#/$defs/platformStatus" - } - } - }, - "additionalProperties": true + "default": { + "description": "Default value of the prop." }, - "platformStatus": { - "type": "object", - "description": "Lifecycle status for a specific platform.", - "required": [ - "stage" - ], - "properties": { - "stage": { - "type": "string", - "enum": [ - "draft", - "experimental", - "stable", - "deprecated" - ], - "description": "Lifecycle stage for this platform." - }, - "since": { - "type": "string", - "description": "Version of the design system content at which this stage took effect." - }, - "migrateTo": { - "type": "string", - "description": "Component ID or token name of the recommended replacement." - }, - "note": { - "type": "string", - "description": "Prose migration guidance or context for this platform's status." - } - }, - "additionalProperties": true + "required": { + "type": "boolean", + "description": "Whether this prop must be provided.", + "default": false }, - "aliasReference": { - "type": "object", - "description": "Structured token alias reference for cross-category disambiguation.", - "required": [ - "category", - "token" - ], - "properties": { - "category": { - "type": "string", - "description": "Token category name containing the referenced token." - }, - "token": { - "type": "string", - "description": "Token name within that category." - } - }, - "additionalProperties": true + "propRole": { + "type": "string", + "enum": [ + "flag", + "dimension", + "choice", + "slot", + "handler", + "content", + "state" + ], + "description": "Semantic role of this prop." + } + }, + "additionalProperties": true + }, + "valueDescriptor": { + "type": "object", + "description": "Describes a single allowed value for an enum prop.", + "required": [ + "value" + ], + "properties": { + "value": { + "description": "The actual enum value." }, - "componentEntry": { - "type": "object", - "description": "A component definition.", - "required": [ - "name", - "description" - ], - "properties": { - "name": { - "type": "string", - "minLength": 1, - "description": "Human-readable display name." - }, - "description": { - "type": "string", - "description": "What the component is for." - }, - "whenToUse": { - "type": "string", - "description": "Guidance on when to use this component." - }, - "whenNotToUse": { - "type": "string", - "description": "Guidance on when to choose a different component." - }, - "props": { - "type": "object", - "description": "Map of prop name to prop descriptor.", - "additionalProperties": { - "$ref": "#/$defs/propDescriptor" - } - }, - "tokens": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Token names this component depends on." - }, - "relatedComponents": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Component IDs of related components." - }, - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Freeform classification tags." - }, - "deprecated": { - "type": "boolean", - "description": "Whether this component is deprecated.", - "default": false - }, - "deprecatedMessage": { - "type": "string", - "description": "What to use instead of this component." - }, - "status": { - "oneOf": [ - { - "type": "string", - "enum": [ - "draft", - "experimental", - "stable", - "deprecated" - ] - }, - { - "$ref": "#/$defs/statusObject" - } - ], - "description": "Lifecycle stage. String for uniform status, object for per-platform granularity." - }, - "accessibility": { - "$ref": "#/$defs/accessibilityConstraints" - }, - "composition": { - "$ref": "#/$defs/compositionRules" - }, - "constraints": { - "type": "array", - "description": "Structured usage constraints.", - "items": { - "$ref": "#/$defs/constraintEntry" - } - }, - "categories": { - "type": "array", - "description": "Category ids this entry belongs to; each MUST be registered in the top-level categories registry.", - "items": { - "type": "string" - }, - "minItems": 1 - } - }, - "additionalProperties": true + "description": { + "type": "string", + "description": "When to choose this value." }, - "propDescriptor": { - "type": "object", - "description": "Describes a single component prop.", - "required": [ - "type" - ], - "properties": { - "type": { - "type": "string", - "description": "The value type of the prop (e.g., string, number, boolean, enum)." - }, - "description": { - "type": "string", - "description": "What this prop controls." - }, - "values": { - "type": "array", - "description": "For enum type, the allowed values. Items may be bare values or value descriptor objects.", - "items": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "boolean" - }, - { - "$ref": "#/$defs/valueDescriptor" - } - ] - } - }, - "default": { - "description": "Default value of the prop." - }, - "required": { - "type": "boolean", - "description": "Whether this prop must be provided.", - "default": false - }, - "propRole": { - "type": "string", - "enum": [ - "flag", - "dimension", - "choice", - "slot", - "handler", - "content", - "state" - ], - "description": "Semantic role of this prop." - } - }, - "additionalProperties": true + "deprecated": { + "type": "boolean", + "description": "Whether this specific value is deprecated.", + "default": false + } + }, + "additionalProperties": true + }, + "accessibilityConstraints": { + "type": "object", + "description": "Accessibility constraints and expectations for a component.", + "properties": { + "role": { + "type": "string", + "description": "WAI-ARIA role this component fulfills." }, - "valueDescriptor": { - "type": "object", - "description": "Describes a single allowed value for an enum prop.", - "required": [ - "value" - ], - "properties": { - "value": { - "description": "The actual enum value." - }, - "description": { - "type": "string", - "description": "When to choose this value." - }, - "deprecated": { - "type": "boolean", - "description": "Whether this specific value is deprecated.", - "default": false - } - }, - "additionalProperties": true + "requiredAttributes": { + "type": "array", + "description": "HTML or ARIA attributes that must be present for correct accessible usage.", + "items": { + "$ref": "#/$defs/attributeDescriptor" + } }, - "accessibilityConstraints": { - "type": "object", - "description": "Accessibility constraints and expectations for a component.", - "properties": { - "role": { - "type": "string", - "description": "WAI-ARIA role this component fulfills." - }, - "requiredAttributes": { - "type": "array", - "description": "HTML or ARIA attributes that must be present for correct accessible usage.", - "items": { - "$ref": "#/$defs/attributeDescriptor" - } - }, - "keyboardInteractions": { - "type": "array", - "description": "Expected keyboard behaviors.", - "items": { - "$ref": "#/$defs/keyboardInteraction" - } - }, - "contrastRequirement": { - "type": "string", - "description": "Minimum contrast ratio or WCAG level." - }, - "focusManagement": { - "type": "string", - "description": "Prose description of focus behavior expectations." - }, - "labelRequirement": { - "type": "string", - "enum": [ - "required-visible", - "required-accessible-name", - "required-aria", - "optional", - "none" - ], - "description": "How the component must be labeled." - }, - "notes": { - "type": "string", - "description": "Additional accessibility guidance in prose." - } - }, - "additionalProperties": true + "keyboardInteractions": { + "type": "array", + "description": "Expected keyboard behaviors.", + "items": { + "$ref": "#/$defs/keyboardInteraction" + } }, - "attributeDescriptor": { - "type": "object", - "description": "Describes a required HTML or ARIA attribute for accessible usage.", - "required": [ - "attribute" - ], - "properties": { - "attribute": { - "type": "string", - "description": "The attribute name (e.g., aria-label, aria-describedby, id, type)." - }, - "description": { - "type": "string", - "description": "When and how to provide this attribute." - }, - "condition": { - "type": "string", - "description": "Condition under which this attribute is required." - } - }, - "additionalProperties": true + "contrastRequirement": { + "type": "string", + "description": "Minimum contrast ratio or WCAG level." }, - "keyboardInteraction": { - "type": "object", - "description": "Describes an expected keyboard behavior.", - "required": [ - "key", - "description" - ], - "properties": { - "key": { - "type": "string", - "description": "The key or key combination." - }, - "description": { - "type": "string", - "description": "What this key does in the context of this component." - } - }, - "additionalProperties": true + "focusManagement": { + "type": "string", + "description": "Prose description of focus behavior expectations." }, - "compositionRules": { - "type": "object", - "description": "Rules governing how a component composes with other components.", - "properties": { - "subComponents": { - "type": "array", - "description": "Sub-components that belong to this compound component.", - "items": { - "$ref": "#/$defs/subComponentDescriptor" - } - }, - "requiredChildren": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Component IDs or sub-component IDs that must appear as descendants." - }, - "allowedChildren": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Component IDs or sub-component IDs that may appear as direct children." - }, - "requiredParent": { - "type": "string", - "description": "Component ID or sub-component ID that must be an ancestor." - }, - "allowedParents": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Component IDs or sub-component IDs that may be the parent." - }, - "requiredSiblings": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Component IDs or sub-component IDs that must also be present among siblings." - }, - "notes": { - "type": "string", - "description": "Prose description of composition constraints not captured by structured fields." - } - }, - "additionalProperties": true + "labelRequirement": { + "type": "string", + "enum": [ + "required-visible", + "required-accessible-name", + "required-aria", + "optional", + "none" + ], + "description": "How the component must be labeled." }, - "subComponentDescriptor": { - "type": "object", - "description": "Describes a sub-component of a compound component.", - "required": [ - "id", - "name" - ], - "properties": { - "id": { - "type": "string", - "pattern": "^[a-z][a-z0-9-]*$", - "description": "Identifier for the sub-component. Should be parent-prefixed." - }, - "name": { - "type": "string", - "minLength": 1, - "description": "Human-readable display name." - }, - "description": { - "type": "string", - "description": "What this sub-component is for." - }, - "required": { - "type": "boolean", - "description": "Whether this sub-component must be present when the parent is used.", - "default": false - }, - "slot": { - "type": "string", - "description": "Named slot this sub-component fills." - }, - "acceptsChildren": { - "type": "string", - "enum": [ - "any", - "text", - "components", - "none" - ], - "description": "What this sub-component expects as children." - }, - "categories": { - "type": "array", - "description": "Category ids this entry belongs to; each MUST be registered in the top-level categories registry.", - "items": { - "type": "string" - }, - "minItems": 1 - } - }, - "additionalProperties": true + "notes": { + "type": "string", + "description": "Additional accessibility guidance in prose." + } + }, + "additionalProperties": true + }, + "attributeDescriptor": { + "type": "object", + "description": "Describes a required HTML or ARIA attribute for accessible usage.", + "required": [ + "attribute" + ], + "properties": { + "attribute": { + "type": "string", + "description": "The attribute name (e.g., aria-label, aria-describedby, id, type)." }, - "constraintEntry": { - "type": "object", - "description": "A structured usage constraint.", - "required": [ - "context", - "rule", - "severity" - ], - "properties": { - "context": { - "type": "string", - "description": "The situation or condition this constraint applies to." - }, - "rule": { - "type": "string", - "description": "What to do or not do." - }, - "severity": { - "type": "string", - "enum": [ - "must", - "should", - "should-not", - "must-not" - ], - "description": "RFC 2119 strength of the constraint." - } - }, - "additionalProperties": true + "description": { + "type": "string", + "description": "When and how to provide this attribute." }, - "patternEntry": { - "type": "object", - "description": "A pattern describing a preferred way of combining components.", - "required": [ - "id", - "name", - "description" - ], - "properties": { - "id": { - "type": "string", - "pattern": "^[a-z][a-z0-9-]*$", - "description": "Unique identifier for this pattern." - }, - "name": { - "type": "string", - "minLength": 1, - "description": "Human-readable name." - }, - "description": { - "type": "string", - "description": "What problem this pattern addresses." - }, - "intent": { - "type": "string", - "description": "The underlying design goal or UX objective." - }, - "context": { - "type": "string", - "description": "When this pattern applies." - }, - "components": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Component IDs involved in this pattern." - }, - "guidance": { - "type": "string", - "description": "Prose guidance on how to apply the pattern correctly." - }, - "relatedPatterns": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Pattern IDs of related patterns." - }, - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Freeform classification tags." - } - }, - "additionalProperties": true + "condition": { + "type": "string", + "description": "Condition under which this attribute is required." + } + }, + "additionalProperties": true + }, + "keyboardInteraction": { + "type": "object", + "description": "Describes an expected keyboard behavior.", + "required": [ + "key", + "description" + ], + "properties": { + "key": { + "type": "string", + "description": "The key or key combination." }, - "antiPatternEntry": { - "type": "object", - "description": "An anti-pattern describing an approach that is deliberately ruled out.", - "required": [ - "id", - "name", - "description", - "reason" - ], - "properties": { - "id": { - "type": "string", - "pattern": "^[a-z][a-z0-9-]*$", - "description": "Unique identifier for this anti-pattern." - }, - "name": { - "type": "string", - "minLength": 1, - "description": "Human-readable name describing what not to do." - }, - "description": { - "type": "string", - "description": "What this anti-pattern is." - }, - "reason": { - "type": "string", - "description": "Why this approach is ruled out." - }, - "severity": { - "type": "string", - "enum": [ - "must-not", - "should-not", - "discouraged" - ], - "description": "Strength of the prohibition. Defaults to should-not.", - "default": "should-not" - }, - "insteadUse": { - "type": "string", - "description": "Pattern ID of the preferred approach." - }, - "components": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Component IDs involved in this anti-pattern." - }, - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Freeform classification tags." - } - }, - "additionalProperties": true + "description": { + "type": "string", + "description": "What this key does in the context of this component." + } + }, + "additionalProperties": true + }, + "compositionRules": { + "type": "object", + "description": "Rules governing how a component composes with other components.", + "properties": { + "subComponents": { + "type": "array", + "description": "Sub-components that belong to this compound component.", + "items": { + "$ref": "#/$defs/subComponentDescriptor" + } }, - "intentEntry": { - "type": "object", - "description": "A named generation intent: what kind of UI is being requested. Intents scope governance rules and select examples.", - "required": [ - "id", - "description" + "requiredChildren": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Component IDs or sub-component IDs that must appear as descendants." + }, + "allowedChildren": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Component IDs or sub-component IDs that may appear as direct children." + }, + "requiredParent": { + "type": "string", + "description": "Component ID or sub-component ID that must be an ancestor." + }, + "allowedParents": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Component IDs or sub-component IDs that may be the parent." + }, + "requiredSiblings": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Component IDs or sub-component IDs that must also be present among siblings." + }, + "notes": { + "type": "string", + "description": "Prose description of composition constraints not captured by structured fields." + } + }, + "additionalProperties": true + }, + "subComponentDescriptor": { + "type": "object", + "description": "Describes a sub-component of a compound component.", + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^[a-z][a-z0-9-]*$", + "description": "Identifier for the sub-component. Should be parent-prefixed." + }, + "name": { + "type": "string", + "minLength": 1, + "description": "Human-readable display name." + }, + "description": { + "type": "string", + "description": "What this sub-component is for." + }, + "required": { + "type": "boolean", + "description": "Whether this sub-component must be present when the parent is used.", + "default": false + }, + "slot": { + "type": "string", + "description": "Named slot this sub-component fills." + }, + "acceptsChildren": { + "type": "string", + "enum": [ + "any", + "text", + "components", + "none" + ], + "description": "What this sub-component expects as children." + }, + "categories": { + "type": "array", + "description": "Category ids this entry belongs to; each MUST be registered in the top-level categories registry.", + "items": { + "type": "string" + }, + "minItems": 1 + } + }, + "additionalProperties": true + }, + "constraintEntry": { + "type": "object", + "description": "A structured usage constraint.", + "required": [ + "context", + "rule", + "severity" + ], + "properties": { + "context": { + "type": "string", + "description": "The situation or condition this constraint applies to." + }, + "rule": { + "type": "string", + "description": "What to do or not do." + }, + "severity": { + "type": "string", + "enum": [ + "must", + "should", + "should-not", + "must-not" + ], + "description": "RFC 2119 strength of the constraint." + } + }, + "additionalProperties": true + }, + "patternEntry": { + "type": "object", + "description": "A pattern describing a preferred way of combining components.", + "required": [ + "id", + "name", + "description" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^[a-z][a-z0-9-]*$", + "description": "Unique identifier for this pattern." + }, + "name": { + "type": "string", + "minLength": 1, + "description": "Human-readable name." + }, + "description": { + "type": "string", + "description": "What problem this pattern addresses." + }, + "intent": { + "type": "string", + "description": "The underlying design goal or UX objective." + }, + "context": { + "type": "string", + "description": "When this pattern applies." + }, + "components": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Component IDs involved in this pattern." + }, + "guidance": { + "type": "string", + "description": "Prose guidance on how to apply the pattern correctly." + }, + "relatedPatterns": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Pattern IDs of related patterns." + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Freeform classification tags." + } + }, + "additionalProperties": true + }, + "antiPatternEntry": { + "type": "object", + "description": "An anti-pattern describing an approach that is deliberately ruled out.", + "required": [ + "id", + "name", + "description", + "reason" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^[a-z][a-z0-9-]*$", + "description": "Unique identifier for this anti-pattern." + }, + "name": { + "type": "string", + "minLength": 1, + "description": "Human-readable name describing what not to do." + }, + "description": { + "type": "string", + "description": "What this anti-pattern is." + }, + "reason": { + "type": "string", + "description": "Why this approach is ruled out." + }, + "severity": { + "type": "string", + "enum": [ + "must-not", + "should-not", + "discouraged" + ], + "description": "Strength of the prohibition. Defaults to should-not.", + "default": "should-not" + }, + "insteadUse": { + "type": "string", + "description": "Pattern ID of the preferred approach." + }, + "components": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Component IDs involved in this anti-pattern." + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Freeform classification tags." + } + }, + "additionalProperties": true + }, + "intentEntry": { + "type": "object", + "description": "A named generation intent: what kind of UI is being requested. Intents scope governance rules and select examples.", + "required": [ + "id", + "description" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^[a-z][a-z0-9-]*$", + "description": "Unique identifier for this intent." + }, + "name": { + "type": "string", + "description": "Human-readable display name." + }, + "description": { + "type": "string", + "description": "What kind of requested UI this intent covers. Written for both humans and generation prompts." + }, + "relatedPatterns": { + "type": "array", + "description": "IDs of patterns that document how to satisfy this intent.", + "items": { + "type": "string" + } + }, + "tags": { + "type": "array", + "description": "Free-form tags for grouping and search.", + "items": { + "type": "string" + } + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "ruleEntry": { + "type": "object", + "description": "A machine-checkable governance rule. The type field selects the evaluation algorithm (normative semantics in the v0.3/v0.4 specs). Linters MUST fail loudly on unknown types \u2014 never skip silently. Contract severity uses RFC 2119 terms; tools map must\u2192error and should\u2192warn.", + "required": [ + "id", + "type", + "severity", + "rationale" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^rule\\.[a-z0-9.-]+$", + "description": "Unique, stable identifier for this rule (rule.* namespace)." + }, + "type": { + "type": "string", + "enum": [ + "component-choice", + "required-composition", + "forbidden-composition", + "required-props" + ], + "description": "The rule type, selecting the evaluation algorithm. New types are added in future spec versions only (additive)." + }, + "severity": { + "type": "string", + "enum": [ + "must", + "should" + ], + "description": "RFC 2119 strength. Tools map must\u2192error (triggers repair/failure) and should\u2192warn (reported only)." + }, + "rationale": { + "type": "string", + "minLength": 1, + "description": "Why this rule exists. Shown verbatim in lint findings, repair feedback, and audit reports." + }, + "appliesTo": { + "type": "object", + "description": "Scope of the rule. Absent means universal (fires for every surface).", + "properties": { + "intents": { + "type": "array", + "description": "Intent IDs this rule fires for.", + "items": { + "type": "string" + }, + "minItems": 1 + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "examples": { + "type": "array", + "description": "IDs of examples demonstrating compliance; included in repair feedback as corrected references.", + "items": { + "type": "string" + } + }, + "tags": { + "type": "array", + "description": "Free-form tags for grouping and search.", + "items": { + "type": "string" + } + } + }, + "allOf": [ + { + "if": { + "properties": { + "type": { + "const": "component-choice" + } + } + }, + "then": { + "anyOf": [ + { + "required": [ + "require" + ] + }, + { + "required": [ + "forbid" + ] + } ], "properties": { - "id": { - "type": "string", - "pattern": "^[a-z][a-z0-9-]*$", - "description": "Unique identifier for this intent." - }, - "name": { - "type": "string", - "description": "Human-readable display name." - }, - "description": { - "type": "string", - "description": "What kind of requested UI this intent covers. Written for both humans and generation prompts." - }, - "relatedPatterns": { - "type": "array", - "description": "IDs of patterns that document how to satisfy this intent.", - "items": { - "type": "string" - } - }, - "tags": { - "type": "array", - "description": "Free-form tags for grouping and search.", - "items": { - "type": "string" - } - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false + "require": { + "type": "array", + "description": "Component IDs that MUST each appear at least once in the surface.", + "items": { + "type": "string" + }, + "minItems": 1 + }, + "forbid": { + "type": "array", + "description": "Component IDs that MUST NOT appear in the surface.", + "items": { + "type": "string" + }, + "minItems": 1 + } + } + } }, - "ruleEntry": { - "type": "object", - "description": "A machine-checkable governance rule. The type field selects the evaluation algorithm (normative semantics in the v0.3/v0.4 specs). Linters MUST fail loudly on unknown types — never skip silently. Contract severity uses RFC 2119 terms; tools map must→error and should→warn.", + { + "if": { + "properties": { + "type": { + "const": "required-composition" + } + } + }, + "then": { "required": [ - "id", - "type", - "severity", - "rationale" + "component" + ], + "anyOf": [ + { + "required": [ + "requiredSubComponents" + ] + }, + { + "required": [ + "requiredProps" + ] + }, + { + "required": [ + "requiredCategories" + ] + } ], "properties": { - "id": { - "type": "string", - "pattern": "^rule\\.[a-z0-9.-]+$", - "description": "Unique, stable identifier for this rule (rule.* namespace)." - }, - "type": { - "type": "string", - "enum": [ - "component-choice", - "required-composition", - "forbidden-composition", - "required-props" - ], - "description": "The rule type, selecting the evaluation algorithm. New types are added in future spec versions only (additive)." - }, - "severity": { - "type": "string", - "enum": [ - "must", - "should" - ], - "description": "RFC 2119 strength. Tools map must→error (triggers repair/failure) and should→warn (reported only)." - }, - "rationale": { - "type": "string", - "minLength": 1, - "description": "Why this rule exists. Shown verbatim in lint findings, repair feedback, and audit reports." - }, - "appliesTo": { - "type": "object", - "description": "Scope of the rule. Absent means universal (fires for every surface).", - "properties": { - "intents": { - "type": "array", - "description": "Intent IDs this rule fires for.", - "items": { - "type": "string" - }, - "minItems": 1 - } - }, - "patternProperties": { - "^x-": {} + "component": { + "type": "string", + "description": "Component ID every instance of which is checked." + }, + "requiredSubComponents": { + "type": "array", + "description": "Sub-components that MUST appear among each matching node's descendants.", + "items": { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "description": "Sub-component ID that must be present." }, - "additionalProperties": false - }, - "examples": { - "type": "array", - "description": "IDs of examples demonstrating compliance; included in repair feedback as corrected references.", - "items": { - "type": "string" + "min": { + "type": "integer", + "minimum": 1, + "default": 1, + "description": "Minimum number of occurrences among descendants." } - }, - "tags": { - "type": "array", - "description": "Free-form tags for grouping and search.", - "items": { - "type": "string" - } - } - }, - "allOf": [ - { - "if": { - "properties": { - "type": { - "const": "component-choice" - } - } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "minItems": 1 + }, + "requiredProps": { + "type": "array", + "description": "Prop constraints that MUST hold on each matching node (or on descendant sub-component nodes when 'on' is given).", + "items": { + "type": "object", + "required": [ + "prop", + "oneOf" + ], + "properties": { + "on": { + "type": "string", + "description": "Sub-component ID the constraint applies to; absent means the matching component node itself." }, - "then": { - "anyOf": [ - { - "required": [ - "require" - ] - }, - { - "required": [ - "forbid" - ] - } - ], - "properties": { - "require": { - "type": "array", - "description": "Component IDs that MUST each appear at least once in the surface.", - "items": { - "type": "string" - }, - "minItems": 1 - }, - "forbid": { - "type": "array", - "description": "Component IDs that MUST NOT appear in the surface.", - "items": { - "type": "string" - }, - "minItems": 1 - } - } - } - }, - { - "if": { - "properties": { - "type": { - "const": "required-composition" - } - } - }, - "then": { - "required": [ - "component" - ], - "anyOf": [ - { - "required": [ - "requiredSubComponents" - ] - }, - { - "required": [ - "requiredProps" - ] - } - ], - "properties": { - "component": { - "type": "string", - "description": "Component ID every instance of which is checked." - }, - "requiredSubComponents": { - "type": "array", - "description": "Sub-components that MUST appear among each matching node's descendants.", - "items": { - "type": "object", - "required": [ - "id" - ], - "properties": { - "id": { - "type": "string", - "description": "Sub-component ID that must be present." - }, - "min": { - "type": "integer", - "minimum": 1, - "default": 1, - "description": "Minimum number of occurrences among descendants." - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "minItems": 1 - }, - "requiredProps": { - "type": "array", - "description": "Prop constraints that MUST hold on each matching node (or on descendant sub-component nodes when 'on' is given).", - "items": { - "type": "object", - "required": [ - "prop", - "oneOf" - ], - "properties": { - "on": { - "type": "string", - "description": "Sub-component ID the constraint applies to; absent means the matching component node itself." - }, - "prop": { - "type": "string", - "description": "Prop name the constraint applies to." - }, - "oneOf": { - "type": "array", - "description": "Allowed values; the prop MUST be present and take one of these.", - "minItems": 1 - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "minItems": 1 - } - } - } - }, - { - "if": { - "properties": { - "type": { - "const": "forbidden-composition" - } - } + "prop": { + "type": "string", + "description": "Prop name the constraint applies to." }, - "then": { - "required": [ - "component" - ], - "anyOf": [ - { - "required": [ - "forbiddenDescendants" - ] - }, - { - "required": [ - "forbiddenProps" - ] - }, - { - "required": [ - "forbiddenCategories" - ] - } - ], - "properties": { - "component": { - "type": "string", - "description": "Component ID every instance of which is checked." - }, - "forbiddenDescendants": { - "type": "array", - "description": "Component or sub-component IDs that MUST NOT appear among a matching node's descendants.", - "items": { - "type": "string" - }, - "minItems": 1 - }, - "forbiddenProps": { - "type": "array", - "description": "Prop values that MUST NOT be used on matching nodes (or on descendant sub-component nodes when 'on' is given).", - "items": { - "type": "object", - "required": [ - "prop", - "values" - ], - "properties": { - "on": { - "type": "string", - "description": "Sub-component ID the constraint applies to; absent means the matching component node itself." - }, - "prop": { - "type": "string", - "description": "Prop name the constraint applies to." - }, - "values": { - "type": "array", - "description": "Forbidden values for the prop.", - "minItems": 1 - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "minItems": 1 - }, - "forbiddenCategories": { - "type": "array", - "description": "Category ids: no descendant of a matching node may belong to any of these categories. Each id MUST be registered in the top-level categories registry.", - "items": { - "type": "string" - }, - "minItems": 1 - } - } + "oneOf": { + "type": "array", + "description": "Allowed values; the prop MUST be present and take one of these.", + "minItems": 1 } - }, - { - "if": { - "properties": { - "type": { - "const": "required-props" - } - } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "minItems": 1 + }, + "requiredCategories": { + "type": "array", + "minItems": 1, + "description": "Categories from which at least `min` descendants MUST appear beneath each matching node. Membership within one category is naturally OR across its components; multiple entries are independently required (AND), matching requiredSubComponents. The 2026-08-07 amendment, lifted from the \u00a76 ceiling on measured evidence.", + "items": { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "description": "Category id (must be registered in the document's categories)." }, - "then": { - "required": [ - "component" - ], - "anyOf": [ - { - "required": [ - "requiredText" - ] - }, - { - "required": [ - "requiredProps" - ] - } - ], - "properties": { - "component": { - "type": "string", - "description": "Component or sub-component ID whose instances are checked (unlike other rule types, sub-component ids are accepted here)." - }, - "within": { - "type": "string", - "description": "Optional scope: a component or sub-component ID. When present, only nodes with an ancestor matching this id are checked, and every node matching `within` MUST contain at least one node matching `component`." - }, - "requiredText": { - "const": true, - "description": "The matching node MUST carry non-empty text. Where the text may live is set by `textScope`: its own `text` field only (the default, \"self\") or anywhere in its subtree (\"subtree\")." - }, - "textScope": { - "type": "string", - "enum": [ - "self", - "subtree" - ], - "default": "self", - "description": "Where requiredText looks for the text: \"self\" (the node's own `text` field — the default) or \"subtree\" (direct text on the node or any descendant; for compound wrappers whose documented projections lift a label from within). Amendment 2026-07-04, on PR-15 evidence." - }, - "requiredProps": { - "type": "array", - "description": "Props that MUST be present directly on the matching node's `props`. Unlike required-composition's requiredProps, entries have no `on` (the rule's component IS the target) and `oneOf` is optional (presence-only when absent).", - "items": { - "type": "object", - "required": [ - "prop" - ], - "properties": { - "prop": { - "type": "string", - "description": "Prop name that must be present on the node itself." - }, - "oneOf": { - "type": "array", - "minItems": 1, - "description": "Optional allowed values; when present the prop value MUST be a member." - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "minItems": 1 - } - }, - "dependentRequired": { - "textScope": [ - "requiredText" - ] - } + "min": { + "type": "integer", + "minimum": 1, + "default": 1, + "description": "Minimum number of member descendants." } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false } - ] + } + } + } }, - "exampleEntry": { - "type": "object", - "description": "A compilable example surface tied to a named intent. Serves as documentation and as a few-shot exemplar for generation.", - "required": [ - "id", - "intent", - "surface" - ], + { + "if": { "properties": { - "id": { - "type": "string", - "pattern": "^ex\\.[a-z0-9.-]+$", - "description": "Unique identifier for this example (ex.* namespace)." - }, - "intent": { - "type": "string", - "description": "Intent ID this example demonstrates." - }, - "name": { - "type": "string", - "description": "Human-readable display name." - }, - "description": { - "type": "string", - "description": "What the example shows and why it is correct." - }, - "prompt": { - "type": "string", - "description": "A representative user request this example answers; used as the user turn in few-shot blocks." - }, - "surface": { - "type": "object", - "description": "A dspack surface document. Validated against dspack.surface.v0_1.schema.json plus the contract vocabulary by tooling; kept loose here to avoid a cross-file $ref." - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "frameworkBinding": { - "type": "object", - "description": "Framework-specific information for the design system.", + "type": { + "const": "forbidden-composition" + } + } + }, + "then": { "required": [ - "name" + "component" + ], + "anyOf": [ + { + "required": [ + "forbiddenDescendants" + ] + }, + { + "required": [ + "forbiddenProps" + ] + }, + { + "required": [ + "forbiddenCategories" + ] + } ], "properties": { - "name": { - "type": "string", - "minLength": 1, - "description": "Human-readable framework name." - }, - "package": { - "type": "string", - "description": "Primary package name." - }, - "installCommand": { - "type": "string", - "description": "How to install the framework binding." - }, - "description": { - "type": "string", - "description": "What this binding provides." - }, - "guidance": { - "type": "string", - "description": "Framework-wide guidance." - }, - "components": { - "type": "object", - "description": "Per-component framework details keyed by component ID.", - "propertyNames": { - "pattern": "^[a-z][a-z0-9-]*$" + "component": { + "type": "string", + "description": "Component ID every instance of which is checked." + }, + "forbiddenDescendants": { + "type": "array", + "description": "Component or sub-component IDs that MUST NOT appear among a matching node's descendants.", + "items": { + "type": "string" + }, + "minItems": 1 + }, + "forbiddenProps": { + "type": "array", + "description": "Prop values that MUST NOT be used on matching nodes (or on descendant sub-component nodes when 'on' is given).", + "items": { + "type": "object", + "required": [ + "prop", + "values" + ], + "properties": { + "on": { + "type": "string", + "description": "Sub-component ID the constraint applies to; absent means the matching component node itself." }, - "additionalProperties": { - "$ref": "#/$defs/componentBinding" - } - } - }, - "additionalProperties": true - }, - "componentBinding": { - "type": "object", - "description": "Framework-specific details for a single component.", - "properties": { - "importPath": { - "type": "string", - "description": "Where to import the component." - }, - "installCommand": { - "type": "string", - "description": "Component-specific install command." - }, - "exportName": { - "type": "string", - "description": "Named export if different from the component name." - }, - "guidance": { - "type": "string", - "description": "Framework-specific usage guidance for this component." - }, - "subComponents": { - "type": "object", - "description": "Map of sub-component ID to sub-component binding.", - "propertyNames": { - "pattern": "^[a-z][a-z0-9-]*$" + "prop": { + "type": "string", + "description": "Prop name the constraint applies to." }, - "additionalProperties": { - "$ref": "#/$defs/subComponentBinding" + "values": { + "type": "array", + "description": "Forbidden values for the prop.", + "minItems": 1 } - } - }, - "additionalProperties": true + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "minItems": 1 + }, + "forbiddenCategories": { + "type": "array", + "description": "Category ids: no descendant of a matching node may belong to any of these categories. Each id MUST be registered in the top-level categories registry.", + "items": { + "type": "string" + }, + "minItems": 1 + } + } + } }, - "subComponentBinding": { - "type": "object", - "description": "Framework-specific details for a sub-component.", + { + "if": { "properties": { - "exportName": { - "type": "string", - "description": "Named export for this sub-component." - }, - "importPath": { - "type": "string", - "description": "Import path if different from the parent component's import path." - } - }, - "additionalProperties": true - }, - "themeEntry": { - "type": "object", - "description": "A named set of token overrides representing an alternative visual mode.", + "type": { + "const": "required-props" + } + } + }, + "then": { "required": [ - "name", - "overrides" + "component" + ], + "anyOf": [ + { + "required": [ + "requiredText" + ] + }, + { + "required": [ + "requiredProps" + ] + } ], "properties": { - "name": { - "type": "string", - "minLength": 1, - "description": "Human-readable theme name." - }, - "description": { - "type": "string", - "description": "What this theme is for." - }, - "overrides": { - "type": "object", - "description": "Map of token reference (category.tokenName) to overridden resolved value.", - "propertyNames": { - "pattern": "^[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*$" + "component": { + "type": "string", + "description": "Component or sub-component ID whose instances are checked (unlike other rule types, sub-component ids are accepted here)." + }, + "within": { + "type": "string", + "description": "Optional scope: a component or sub-component ID. When present, only nodes with an ancestor matching this id are checked, and every node matching `within` MUST contain at least one node matching `component`." + }, + "requiredText": { + "const": true, + "description": "The matching node MUST carry non-empty text. Where the text may live is set by `textScope`: its own `text` field only (the default, \"self\") or anywhere in its subtree (\"subtree\")." + }, + "textScope": { + "type": "string", + "enum": [ + "self", + "subtree" + ], + "default": "self", + "description": "Where requiredText looks for the text: \"self\" (the node's own `text` field \u2014 the default) or \"subtree\" (direct text on the node or any descendant; for compound wrappers whose documented projections lift a label from within). Amendment 2026-07-04, on PR-15 evidence." + }, + "requiredProps": { + "type": "array", + "description": "Props that MUST be present directly on the matching node's `props`. Unlike required-composition's requiredProps, entries have no `on` (the rule's component IS the target) and `oneOf` is optional (presence-only when absent).", + "items": { + "type": "object", + "required": [ + "prop" + ], + "properties": { + "prop": { + "type": "string", + "description": "Prop name that must be present on the node itself." }, - "additionalProperties": { - "type": "string" + "oneOf": { + "type": "array", + "minItems": 1, + "description": "Optional allowed values; when present the prop value MUST be a member." } - } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "minItems": 1 + } }, - "additionalProperties": true + "dependentRequired": { + "textScope": [ + "requiredText" + ] + } + } + } + ] + }, + "exampleEntry": { + "type": "object", + "description": "A compilable example surface tied to a named intent. Serves as documentation and as a few-shot exemplar for generation.", + "required": [ + "id", + "intent", + "surface" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^ex\\.[a-z0-9.-]+$", + "description": "Unique identifier for this example (ex.* namespace)." }, - "layoutPrimitives": { - "type": "object", - "description": "Layout system primitives: breakpoints, grid, containers, and spacing scale.", - "properties": { - "breakpoints": { - "type": "object", - "description": "Named responsive breakpoints.", - "additionalProperties": { - "$ref": "#/$defs/breakpointEntry" - } - }, - "grid": { - "$ref": "#/$defs/gridConfig" - }, - "containers": { - "type": "object", - "description": "Named container width configurations.", - "additionalProperties": { - "$ref": "#/$defs/containerEntry" - } - }, - "spacingScale": { - "$ref": "#/$defs/spacingScaleConfig" - } - }, - "additionalProperties": true + "intent": { + "type": "string", + "description": "Intent ID this example demonstrates." }, - "breakpointEntry": { - "type": "object", - "description": "A responsive breakpoint definition.", - "required": [ - "minWidth" - ], - "properties": { - "minWidth": { - "type": "string", - "description": "Minimum viewport width for this breakpoint." - }, - "description": { - "type": "string", - "description": "What this breakpoint targets." - } - }, - "additionalProperties": true + "name": { + "type": "string", + "description": "Human-readable display name." }, - "gridConfig": { - "type": "object", - "description": "Grid system parameters.", - "properties": { - "columns": { - "type": "number", - "description": "Number of columns in the grid system." - }, - "gutter": { - "type": "string", - "description": "Default gutter width between columns." - }, - "margin": { - "type": "string", - "description": "Default outer margin of the grid container." - }, - "description": { - "type": "string", - "description": "Guidance on grid usage." - } - }, - "additionalProperties": true + "description": { + "type": "string", + "description": "What the example shows and why it is correct." }, - "containerEntry": { - "type": "object", - "description": "A container width configuration.", - "required": [ - "maxWidth" - ], - "properties": { - "maxWidth": { - "type": "string", - "description": "Maximum width of this container." - }, - "description": { - "type": "string", - "description": "When to use this container size." - } - }, - "additionalProperties": true + "prompt": { + "type": "string", + "description": "A representative user request this example answers; used as the user turn in few-shot blocks." }, - "spacingScaleConfig": { - "type": "object", - "description": "Spacing scale system description.", - "properties": { - "baseUnit": { - "type": "string", - "description": "The fundamental unit of the spacing scale." - }, - "description": { - "type": "string", - "description": "How the scale is constructed." - } - }, - "additionalProperties": true + "surface": { + "type": "object", + "description": "A dspack surface document. Validated against dspack.surface.v0_1.schema.json plus the contract vocabulary by tooling; kept loose here to avoid a cross-file $ref." + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "frameworkBinding": { + "type": "object", + "description": "Framework-specific information for the design system.", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "Human-readable framework name." }, - "categoryEntry": { - "type": "object", - "description": "A component category: a named role components/sub-components can declare and rules can select by.", - "required": [ - "description" - ], - "properties": { - "name": { - "type": "string", - "description": "Display name." - }, - "description": { - "type": "string", - "minLength": 1, - "description": "What membership in this category means; written for maintainers and reviewers." - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false + "package": { + "type": "string", + "description": "Primary package name." + }, + "installCommand": { + "type": "string", + "description": "How to install the framework binding." + }, + "description": { + "type": "string", + "description": "What this binding provides." + }, + "guidance": { + "type": "string", + "description": "Framework-wide guidance." + }, + "components": { + "type": "object", + "description": "Per-component framework details keyed by component ID.", + "propertyNames": { + "pattern": "^[a-z][a-z0-9-]*$" + }, + "additionalProperties": { + "$ref": "#/$defs/componentBinding" + } + } + }, + "additionalProperties": true + }, + "componentBinding": { + "type": "object", + "description": "Framework-specific details for a single component.", + "properties": { + "importPath": { + "type": "string", + "description": "Where to import the component." + }, + "installCommand": { + "type": "string", + "description": "Component-specific install command." + }, + "exportName": { + "type": "string", + "description": "Named export if different from the component name." + }, + "guidance": { + "type": "string", + "description": "Framework-specific usage guidance for this component." + }, + "subComponents": { + "type": "object", + "description": "Map of sub-component ID to sub-component binding.", + "propertyNames": { + "pattern": "^[a-z][a-z0-9-]*$" + }, + "additionalProperties": { + "$ref": "#/$defs/subComponentBinding" + } + } + }, + "additionalProperties": true + }, + "subComponentBinding": { + "type": "object", + "description": "Framework-specific details for a sub-component.", + "properties": { + "exportName": { + "type": "string", + "description": "Named export for this sub-component." + }, + "importPath": { + "type": "string", + "description": "Import path if different from the parent component's import path." + } + }, + "additionalProperties": true + }, + "themeEntry": { + "type": "object", + "description": "A named set of token overrides representing an alternative visual mode.", + "required": [ + "name", + "overrides" + ], + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "Human-readable theme name." + }, + "description": { + "type": "string", + "description": "What this theme is for." + }, + "overrides": { + "type": "object", + "description": "Map of token reference (category.tokenName) to overridden resolved value.", + "propertyNames": { + "pattern": "^[a-z][a-z0-9-]*\\.[a-z][a-z0-9-]*$" + }, + "additionalProperties": { + "type": "string" + } + } + }, + "additionalProperties": true + }, + "layoutPrimitives": { + "type": "object", + "description": "Layout system primitives: breakpoints, grid, containers, and spacing scale.", + "properties": { + "breakpoints": { + "type": "object", + "description": "Named responsive breakpoints.", + "additionalProperties": { + "$ref": "#/$defs/breakpointEntry" + } + }, + "grid": { + "$ref": "#/$defs/gridConfig" + }, + "containers": { + "type": "object", + "description": "Named container width configurations.", + "additionalProperties": { + "$ref": "#/$defs/containerEntry" + } + }, + "spacingScale": { + "$ref": "#/$defs/spacingScaleConfig" + } + }, + "additionalProperties": true + }, + "breakpointEntry": { + "type": "object", + "description": "A responsive breakpoint definition.", + "required": [ + "minWidth" + ], + "properties": { + "minWidth": { + "type": "string", + "description": "Minimum viewport width for this breakpoint." + }, + "description": { + "type": "string", + "description": "What this breakpoint targets." + } + }, + "additionalProperties": true + }, + "gridConfig": { + "type": "object", + "description": "Grid system parameters.", + "properties": { + "columns": { + "type": "number", + "description": "Number of columns in the grid system." + }, + "gutter": { + "type": "string", + "description": "Default gutter width between columns." + }, + "margin": { + "type": "string", + "description": "Default outer margin of the grid container." + }, + "description": { + "type": "string", + "description": "Guidance on grid usage." + } + }, + "additionalProperties": true + }, + "containerEntry": { + "type": "object", + "description": "A container width configuration.", + "required": [ + "maxWidth" + ], + "properties": { + "maxWidth": { + "type": "string", + "description": "Maximum width of this container." + }, + "description": { + "type": "string", + "description": "When to use this container size." + } + }, + "additionalProperties": true + }, + "spacingScaleConfig": { + "type": "object", + "description": "Spacing scale system description.", + "properties": { + "baseUnit": { + "type": "string", + "description": "The fundamental unit of the spacing scale." + }, + "description": { + "type": "string", + "description": "How the scale is constructed." + } + }, + "additionalProperties": true + }, + "categoryEntry": { + "type": "object", + "description": "A component category: a named role components/sub-components can declare and rules can select by.", + "required": [ + "description" + ], + "properties": { + "name": { + "type": "string", + "description": "Display name." + }, + "description": { + "type": "string", + "minLength": 1, + "description": "What membership in this category means; written for maintainers and reviewers." } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false } + } }