Skip to content

Commit 757bbab

Browse files
committed
Harden contract and schema rules
1 parent a619768 commit 757bbab

10 files changed

Lines changed: 305 additions & 83 deletions

File tree

docs/contract/anatomy.md

Lines changed: 98 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
---
2-
title: Contract - Anatomy
2+
title: Contract: Anatomy
33
---
44

5-
# Contract - Anatomy
5+
# Contract: Anatomy
66

77
These are the three layers we use so components do not depend on raw palette values.
88

@@ -57,6 +57,87 @@ Rules:
5757
- Alias variables: for usage in UI.
5858
- Component variables: for controlled overrides when needed.
5959

60+
## No mapped layer
61+
62+
VDS defines three layers only. Base, Alias, Component.
63+
64+
Requirements:
65+
66+
- VDS implementations MUST NOT add a fourth layer between Alias and Base.
67+
- Brand and theme selection MUST happen by file selection or by modes on Alias variables.
68+
- Alias variables SHOULD NOT exist only to redirect a base value under a second name.
69+
70+
Example (conformant):
71+
72+
```json
73+
// tokens/brand-a/color.json
74+
{
75+
"color": {
76+
"surface": {
77+
"brand": { "$type": "color", "$value": "{color.brand.primary}" }
78+
}
79+
}
80+
}
81+
```
82+
83+
```json
84+
// tokens/brand-b/color.json
85+
{
86+
"color": {
87+
"surface": {
88+
"brand": { "$type": "color", "$value": "{color.brand.primary}" }
89+
}
90+
}
91+
}
92+
```
93+
94+
Example (non-conformant):
95+
96+
```json
97+
{
98+
"mapped": {
99+
"brand": {
100+
"primary": { "$type": "color", "$value": "{color.blue.500}" }
101+
}
102+
},
103+
"color": {
104+
"surface": {
105+
"brand": { "$type": "color", "$value": "{mapped.brand.primary}" }
106+
}
107+
}
108+
}
109+
```
110+
111+
Example selection (CSS):
112+
113+
```css
114+
@layer base, brand;
115+
@import "variables-base.css" layer(base);
116+
@import "variables-brand-a.css" layer(brand);
117+
```
118+
119+
Guidance:
120+
121+
- Treat the file tree as the selection boundary. The folder name picks the brand and mode.
122+
- Keep alias values direct. One alias hop from base is the default.
123+
- Do not add a mapped collection in a design tool panel. Use alias modes or file selection.
124+
- Use CSS cascade layers to select brand output at consumption time.
125+
- File selection rule selects brands and modes by file selection.
126+
127+
Why this is faster:
128+
129+
- A mapped layer forces a second naming decision for every semantic token.
130+
- A mapped layer adds one more reference hop for every resolution.
131+
- The three layer graph keeps review scope small and keeps pickers focused.
132+
- No extra collection to review, audit, or keep in sync.
133+
- CSS handles layout and motion. Tokens stay focused on values and intent.
134+
135+
## Contract posture
136+
137+
- Variable JSON in version control is the contract.
138+
- CI validates structure, naming, references, and modes.
139+
- Contract changes are reviewed before merge. See [Governance](../governance/overview).
140+
60141
## Formal Invariants
61142

62143
These invariants MUST be maintained for Variable Design Standard (VDS) conformance. Violations are non-conformant.
@@ -70,6 +151,7 @@ These invariants MUST be maintained for Variable Design Standard (VDS) conforman
70151
- Base variables MUST NOT be consumed directly by components (unless explicitly allowed)
71152

72153
**Example (conformant)**:
154+
73155
```json
74156
{
75157
"color": {
@@ -88,13 +170,14 @@ These invariants MUST be maintained for Variable Design Standard (VDS) conforman
88170
```
89171

90172
**Example (non-conformant)**:
173+
91174
```json
92175
{
93176
"color": {
94177
"gray": {
95178
"900": {
96179
"$type": "color",
97-
"$value": "{color.gray.800}" // Base variable referencing another base variable
180+
"$value": "{color.gray.800}" // Base variable referencing another base variable
98181
}
99182
}
100183
}
@@ -110,27 +193,29 @@ These invariants MUST be maintained for Variable Design Standard (VDS) conforman
110193
- Alias variables form the semantic abstraction layer
111194

112195
**Example (conformant)**:
196+
113197
```json
114198
{
115199
"color": {
116200
"text": {
117201
"primary": {
118202
"$type": "color",
119-
"$value": "{color.gray.900}" // References base variable
203+
"$value": "{color.gray.900}" // References base variable
120204
}
121205
}
122206
}
123207
}
124208
```
125209

126210
**Example (non-conformant)**:
211+
127212
```json
128213
{
129214
"color": {
130215
"text": {
131216
"primary": {
132217
"$type": "color",
133-
"$value": "{component.button.color.text}" // Alias referencing component variable
218+
"$value": "{component.button.color.text}" // Alias referencing component variable
134219
}
135220
}
136221
}
@@ -146,6 +231,7 @@ These invariants MUST be maintained for Variable Design Standard (VDS) conforman
146231
- Component variables provide fine-grained control when needed
147232

148233
**Example (conformant)**:
234+
149235
```json
150236
{
151237
"component": {
@@ -154,7 +240,7 @@ These invariants MUST be maintained for Variable Design Standard (VDS) conforman
154240
"background": {
155241
"default": {
156242
"$type": "color",
157-
"$value": "{color.surface.brand}" // References alias variable
243+
"$value": "{color.surface.brand}" // References alias variable
158244
}
159245
}
160246
}
@@ -164,6 +250,7 @@ These invariants MUST be maintained for Variable Design Standard (VDS) conforman
164250
```
165251

166252
**Example (non-conformant)**:
253+
167254
```json
168255
{
169256
"component": {
@@ -172,7 +259,7 @@ These invariants MUST be maintained for Variable Design Standard (VDS) conforman
172259
"background": {
173260
"default": {
174261
"$type": "color",
175-
"$value": "{color.gray.900}" // Component variable referencing base directly
262+
"$value": "{color.gray.900}" // Component variable referencing base directly
176263
}
177264
}
178265
}
@@ -190,16 +277,18 @@ These invariants MUST be maintained for Variable Design Standard (VDS) conforman
190277
- Flattening destroys the dependency graph and breaks theme switching
191278

192279
**Example (conformant output)**:
280+
193281
```json
194282
{
195283
"color.text.primary": "{color.gray.900}"
196284
}
197285
```
198286

199287
**Example (non-conformant output)**:
288+
200289
```json
201290
{
202-
"color.text.primary": "#1a1a1a" // Flattened - reference chain lost
291+
"color.text.primary": "#1a1a1a" // Flattened - reference chain lost
203292
}
204293
```
205294

@@ -220,6 +309,7 @@ If anatomy rules are ignored:
220309
- Semantic intent is lost (developers guess meaning from value)
221310
- Component variables reference base variables (tight coupling, hard to refactor)
222311
- Alias layer is skipped (no semantic abstraction)
312+
- Mapped layers appear (extra decision and more reference hops)
223313

224314
## Out of scope
225315

docs/contract/composite-types.md

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ title: Composite Types
66

77
Composite types combine multiple primitive types into structured values. They represent complex design decisions like borders, shadows, and typography styles.
88

9+
## Requirements
10+
11+
- Composite variables MUST use an object in `$value`.
12+
- The `$value` object MUST match the property list for that composite type.
13+
- Each property value MUST be a literal of the expected type or a reference to one.
14+
915
## Border
1016

1117
`$type: "border"`
@@ -50,9 +56,9 @@ Stroke style values:
5056

5157
Property-level references:
5258

53-
- `{variable.width}` - border width
54-
- `{variable.color}` - border color
55-
- `{variable.style}` - border style
59+
- `{variable.width}`: border width
60+
- `{variable.color}`: border color
61+
- `{variable.style}`: border style
5662

5763
## Transition
5864

@@ -92,9 +98,9 @@ Example:
9298

9399
Property-level references:
94100

95-
- `{variable.duration}` - transition duration
96-
- `{variable.delay}` - transition delay
97-
- `{variable.timingFunction}` - timing function
101+
- `{variable.duration}`: transition duration
102+
- `{variable.delay}`: transition delay
103+
- `{variable.timingFunction}`: timing function
98104

99105
## Shadow
100106

@@ -141,11 +147,11 @@ Example:
141147

142148
Property-level references:
143149

144-
- `{variable.color}` - shadow color
145-
- `{variable.offsetX}` - horizontal offset
146-
- `{variable.offsetY}` - vertical offset
147-
- `{variable.blur}` - blur radius
148-
- `{variable.spread}` - spread radius
150+
- `{variable.color}`: shadow color
151+
- `{variable.offsetX}`: horizontal offset
152+
- `{variable.offsetY}`: vertical offset
153+
- `{variable.blur}`: blur radius
154+
- `{variable.spread}`: spread radius
149155

150156
## Gradient
151157

@@ -244,13 +250,32 @@ Example:
244250
}
245251
```
246252

253+
## Failure modes
254+
255+
If composite rules are ignored:
256+
257+
- Missing required fields for a composite type
258+
- Property-level references point to incompatible types
259+
- Consumers cannot render the composite correctly
260+
261+
## Validation checklist
262+
263+
- [ ] Each composite includes all required fields for its type
264+
- [ ] Each field value matches the expected primitive type
265+
- [ ] Property-level references resolve to matching fields
266+
267+
## Out of scope
268+
269+
- Runtime rendering rules for composites
270+
- Tool-specific composite extensions
271+
247272
Property-level references:
248273

249-
- `{variable.fontFamily}` - font family
250-
- `{variable.fontSize}` - font size
251-
- `{variable.fontWeight}` - font weight
252-
- `{variable.letterSpacing}` - letter spacing
253-
- `{variable.lineHeight}` - line height
274+
- `{variable.fontFamily}`: font family
275+
- `{variable.fontSize}`: font size
276+
- `{variable.fontWeight}`: font weight
277+
- `{variable.letterSpacing}`: letter spacing
278+
- `{variable.lineHeight}`: line height
254279

255280
## Composite type validation
256281

@@ -421,4 +446,3 @@ A composite type is valid if:
421446
- Custom composite types (use `$extensions` for metadata)
422447
- Composite type coercion
423448
- Runtime composite type validation libraries (use DTCG-compliant validators)
424-

docs/contract/dtcg-alignment.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ Variable Design Standard (VDS) is DTCG 2025.10 compliant. What that means and wh
1010

1111
Variable Design Standard (VDS) uses the Design Tokens Community Group (DTCG) format 2025.10 as its base format. Variable Design Standard (VDS) extends DTCG with modes and convenience formats. Files using only DTCG features are strictly compliant. Files using modes or string shortcuts for dimension/duration are Variable Design Standard (VDS) format.
1212

13+
## Requirements
14+
15+
- Variable JSON MUST follow DTCG 2025.10 structure.
16+
- `$type` and `$value` MUST exist on every variable.
17+
- References MUST use curly brace syntax in Variable Design Standard (VDS) files.
18+
- JSON Pointer references MAY be supported for DTCG compliance.
19+
- Modes in `$value` are a Variable Design Standard (VDS) extension.
20+
1321
## What DTCG provides
1422

1523
DTCG 2025.10 defines:
@@ -61,6 +69,30 @@ Variable Design Standard (VDS) extends DTCG format with:
6169
4. Validation that checks references resolve
6270
5. Governance that treats renames as breaking changes
6371

72+
## Examples
73+
74+
Strict DTCG:
75+
76+
```json
77+
{
78+
"$type": "color",
79+
"$value": {
80+
"colorSpace": "srgb",
81+
"components": [0, 0.4, 0.8],
82+
"hex": "#0066cc"
83+
}
84+
}
85+
```
86+
87+
Variable Design Standard (VDS) extension:
88+
89+
```json
90+
{
91+
"$type": "color",
92+
"$value": "#0066cc"
93+
}
94+
```
95+
6496
## Strict DTCG compliance
6597

6698
For strict DTCG 2025.10 compliance, use:
@@ -93,3 +125,10 @@ If you ignore DTCG compliance:
93125
- Runtime validation libraries (use DTCG-compliant validators)
94126
- Format conversion tools (use adapters)
95127
- Tool-specific features not in DTCG spec
128+
129+
## Validation checklist
130+
131+
- [ ] All variables include `$type` and `$value`
132+
- [ ] References in Variable Design Standard (VDS) files use `{path}` syntax
133+
- [ ] JSON Pointer references are only used for DTCG compliance
134+
- [ ] Modes in `$value` are documented as a Variable Design Standard (VDS) extension

0 commit comments

Comments
 (0)