@adobe/design-data-spec 3.1.0 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/conformance/diff/cross-format/expected.json +2 -2
- package/conformance/diff/deprecated-new-token/new/tokens.tokens.json +1 -1
- package/conformance/diff/matched-gaining-deprecated/expected.json +1 -1
- package/conformance/diff/matched-gaining-deprecated/new/tokens.tokens.json +1 -1
- package/conformance/diff/replaced-by-pairing/expected.json +8 -8
- package/conformance/diff/replaced-by-pairing/old/tokens.tokens.json +5 -3
- package/conformance/diff/reverted-token/old/tokens.tokens.json +1 -1
- package/conformance/generation/ctr-legacy-key/expected/button.json +8 -0
- package/conformance/generation/ctr-legacy-key/expected/tokens.json +7 -0
- package/conformance/generation/ctr-legacy-key/input/tokens.tokens.json +8 -0
- package/conformance/generation/ctr-legacy-key/relationships/button.json +14 -0
- package/conformance/generation/deprecated-token/input/tokens.tokens.json +5 -3
- package/conformance/generation/mode-set-edit/input/tokens.tokens.json +8 -4
- package/conformance/generation/renamed-token/input/tokens.tokens.json +4 -2
- package/conformance/invalid/SPEC-010/dataset.json +4 -2
- package/conformance/invalid/SPEC-010/expected-errors.json +1 -1
- package/conformance/invalid/SPEC-010/tokens.tokens.json +4 -2
- package/conformance/invalid/SPEC-011/dataset.json +7 -5
- package/conformance/invalid/SPEC-011/expected-errors.json +1 -1
- package/conformance/invalid/SPEC-011/tokens.tokens.json +7 -5
- package/conformance/invalid/SPEC-012/dataset.json +1 -1
- package/conformance/invalid/SPEC-012/expected-errors.json +1 -1
- package/conformance/invalid/SPEC-012/tokens.tokens.json +1 -1
- package/conformance/invalid/SPEC-013/dataset.json +1 -1
- package/conformance/invalid/SPEC-013/tokens.tokens.json +1 -1
- package/conformance/invalid/SPEC-014/dataset.json +1 -1
- package/conformance/invalid/SPEC-014/tokens.tokens.json +1 -1
- package/conformance/invalid/SPEC-036/dataset.json +1 -1
- package/conformance/invalid/SPEC-037/dataset.json +3 -3
- package/conformance/invalid/SPEC-051/dataset.json +16 -0
- package/conformance/invalid/SPEC-051/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-052/dataset.json +24 -0
- package/conformance/invalid/SPEC-052/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-053/dataset.json +26 -0
- package/conformance/invalid/SPEC-053/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-054/dataset.json +24 -0
- package/conformance/invalid/SPEC-054/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-055/dataset.json +16 -0
- package/conformance/invalid/SPEC-055/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-056/dataset.json +22 -0
- package/conformance/invalid/SPEC-056/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-057/dataset.json +21 -0
- package/conformance/invalid/SPEC-057/expected-errors.json +10 -0
- package/conformance/valid/SPEC-014/dataset.json +1 -1
- package/conformance/valid/SPEC-036/dataset.json +2 -2
- package/conformance/valid/SPEC-037/dataset.json +6 -6
- package/conformance/valid/SPEC-051/dataset.json +42 -0
- package/conformance/valid/lifecycle-with-last-modified.json +1 -1
- package/package.json +1 -1
- package/rules/rules.yaml +98 -2
- package/schemas/component.schema.json +4 -4
- package/schemas/relationship.schema.json +228 -0
- package/schemas/token.schema.json +38 -48
- package/spec/agent-surface.md +13 -13
- package/spec/authoring-workflow.md +39 -39
- package/spec/dataset-layout.md +1 -1
- package/spec/evolution.md +20 -20
- package/spec/index.md +2 -0
- package/spec/relationship-format.md +103 -0
- package/spec/token-format.md +39 -27
package/spec/agent-surface.md
CHANGED
|
@@ -25,19 +25,19 @@ The surface targets three consumer shapes:
|
|
|
25
25
|
|
|
26
26
|
**NORMATIVE:** A conforming implementation MUST expose the following operations. Transport-specific naming (CLI subcommand vs MCP tool name vs skill action) MAY differ; the semantics MUST NOT.
|
|
27
27
|
|
|
28
|
-
| Operation | Reads | Returns
|
|
29
|
-
| -------------------- | ------------------------------------------------------ |
|
|
30
|
-
| `resolve_token` | property + mode set context | winning token (literal or resolved alias) with file/UUID/specificity
|
|
31
|
-
| `query_tokens` | filter expression (see [Query](query.md)) | matching token list
|
|
32
|
-
| `validate_usage` | candidate token document or fragment | `ValidationReport` (Layer 1 + Layer 2 diagnostics)
|
|
33
|
-
| `describe_component` | component identifier | component contract (anatomy, options, states, tokenBindings); see [#832](https://github.com/adobe/spectrum-design-data/discussions/832) and [Phase 6.7](#describe_component-return-shape)
|
|
34
|
-
| `suggest_token` | natural-language intent + optional property hint | ranked candidate tokens with rationale (RECOMMENDED, not NORMATIVE in v1)
|
|
35
|
-
| `get_guidance` | token UUID, component identifier, or anatomy reference | attached document blocks (Phase 9 / RFC-D); falls back to empty list pre-RFC-D
|
|
36
|
-
| `diff_datasets` | two dataset roots | `DiffReport` per [Diff](diff.md)
|
|
37
|
-
| `write_token` | token object + optional rationale string | updated
|
|
38
|
-
| `write_component` | component object + optional rationale string | updated dataset-root component file (RECOMMENDED, not NORMATIVE in v1; scheduled to become MUST — see [Scheduled promotion](authoring-workflow.md#scheduled-promotion))
|
|
39
|
-
|
|
40
|
-
**NORMATIVE:** `validate_usage`, `resolve_token`, `query_tokens`, `diff_datasets`, and `
|
|
28
|
+
| Operation | Reads | Returns | Backed by |
|
|
29
|
+
| -------------------- | ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
30
|
+
| `resolve_token` | property + mode set context | winning token (literal or resolved alias) with file/UUID/specificity | `cascade::resolve` |
|
|
31
|
+
| `query_tokens` | filter expression (see [Query](query.md)) | matching token list | `query::filter` |
|
|
32
|
+
| `validate_usage` | candidate token document or fragment | `ValidationReport` (Layer 1 + Layer 2 diagnostics) | `validate::validate_*` |
|
|
33
|
+
| `describe_component` | component identifier | component contract (anatomy, options, states, tokenBindings); see [#832](https://github.com/adobe/spectrum-design-data/discussions/832) and [Phase 6.7](#describe_component-return-shape) | (Phase 6 contract) |
|
|
34
|
+
| `suggest_token` | natural-language intent + optional property hint | ranked candidate tokens with rationale (RECOMMENDED, not NORMATIVE in v1) | registry + query |
|
|
35
|
+
| `get_guidance` | token UUID, component identifier, or anatomy reference | attached document blocks (Phase 9 / RFC-D); falls back to empty list pre-RFC-D | document blocks |
|
|
36
|
+
| `diff_datasets` | two dataset roots | `DiffReport` per [Diff](diff.md) | `diff::semantic_diff` |
|
|
37
|
+
| `write_token` | token object + optional rationale string | updated dataset-root token file + `product-context.json` (**NORMATIVE** — MUST, promoted with the Phase B foundation-corpus write target; see [Scheduled promotion](authoring-workflow.md#scheduled-promotion)) | `write::write_token` — shipped: `design-data write-token` (CLI) / `authoring_session_commit` (MCP) |
|
|
38
|
+
| `write_component` | component object + optional rationale string | updated dataset-root component file (RECOMMENDED, not NORMATIVE in v1; scheduled to become MUST — see [Scheduled promotion](authoring-workflow.md#scheduled-promotion)) | `write::write_component` — Phase B scheduled; not yet implemented |
|
|
39
|
+
|
|
40
|
+
**NORMATIVE:** `validate_usage`, `resolve_token`, `query_tokens`, `diff_datasets`, `describe_component`, and `write_token` MUST be implemented in a conforming agent surface. `suggest_token`, `get_guidance`, and `write_component` are RECOMMENDED. `write_token` was promoted to MUST now that the Phase B foundation-corpus write target has shipped; `write_component` remains RECOMMENDED pending component authoring support — see [Authoring workflow — Scheduled promotion](authoring-workflow.md#scheduled-promotion).
|
|
41
41
|
|
|
42
42
|
**RECOMMENDED:** When `write_token` or `write_component` is invoked, the implementation SHOULD capture a `rationale` argument from the agent session context and record it in both the token's inline `rationale` field and the product context document's `overrides[].rationale` or `extensions.tokens[].rationale`. See [Product context — Agent capture behavior](product-context.md#agent-capture-behavior).
|
|
43
43
|
|
|
@@ -35,20 +35,20 @@ Per [Evolution — Legacy format contract](evolution.md#legacy-format-contract),
|
|
|
35
35
|
|
|
36
36
|
The following tools constitute the normative authoring surface:
|
|
37
37
|
|
|
38
|
-
| Tool | Form
|
|
39
|
-
| -------------------------- |
|
|
40
|
-
| `design-data` CLI | `design-data write-token`
|
|
41
|
-
| `design-data-tui` | interactive token naming + creation wizard
|
|
42
|
-
| MCP authoring session | `start_authoring_session` / `authoring_session_commit` tools | Shipped (RFC [#973](https://github.com/adobe/spectrum-design-data/discussions/973))
|
|
43
|
-
| Design Data management app | future browser-based tool
|
|
38
|
+
| Tool | Form | Status | Scope |
|
|
39
|
+
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
|
40
|
+
| `design-data` CLI | `design-data write-token` + cascade mutation/mode-set subcommands (edit/deprecate/rename/alias-rewire/remove, add-mode/rename-mode/remove-mode/create-mode-set/remove-mode-set) | Shipped — cascade foundation-corpus token + mode-set authoring (Phase B, epic [`spectrum-design-data-122`](https://github.com/adobe/spectrum-design-data/issues/122)) | Component/field/registry authoring not yet shipped — see [Per-category authoring contracts](#per-category-authoring-contracts) |
|
|
41
|
+
| `design-data-tui` | interactive token naming + creation wizard | Shipped (RFC [#973](https://github.com/adobe/spectrum-design-data/discussions/973)); writes cascade `*.tokens.json` directly (Phase B) | Component/field/registry authoring not yet shipped |
|
|
42
|
+
| MCP authoring session | `start_authoring_session` / `authoring_session_commit` tools, plus `edit_token`/`deprecate_token`/`rename_token`/`rewire_alias`/`remove_token`/mode-set tools | Shipped (RFC [#973](https://github.com/adobe/spectrum-design-data/discussions/973)); writes cascade `*.tokens.json` directly (Phase B) | Component/field/registry authoring not yet shipped |
|
|
43
|
+
| Design Data management app | future browser-based tool | Not yet shipped | Full CRUD across all categories |
|
|
44
44
|
|
|
45
45
|
**RECOMMENDED:** Authors SHOULD use the TUI or MCP authoring session rather than editing cascade JSON files directly. Tooling enforces UUID uniqueness, name-object field decomposition, and referential integrity that is difficult to maintain manually.
|
|
46
46
|
|
|
47
47
|
### Scheduled promotion {#scheduled-promotion}
|
|
48
48
|
|
|
49
|
-
The
|
|
49
|
+
The CLI/TUI/MCP write path now targets the foundation Spectrum corpus (`packages/design-data/tokens/*.tokens.json`, via `design_data_core::write::cascade_target_filename`) rather than the legacy product-layer files (`foundation.json`, `platform.json`, `product.json`). This redirect was **Phase B** work and has shipped (epic [`spectrum-design-data-122`](https://github.com/adobe/spectrum-design-data/issues/122), closed).
|
|
50
50
|
|
|
51
|
-
**NORMATIVE:**
|
|
51
|
+
**NORMATIVE:** All authoring tools described above MUST write to the dataset root, not to legacy layer files. The `write_token` operation in [Agent-readable surface](agent-surface.md) is now **required** (MUST) for the foundation-corpus write target; `write_component` remains RECOMMENDED pending component authoring support (not yet shipped — see [Per-category authoring contracts](#per-category-authoring-contracts)). The promotion is tracked in RFC [#625](https://github.com/adobe/spectrum-design-data/discussions/625). This mirrors the SPEC-017 escalation precedent in [Token format](token-format.md#string-name-escape-hatch--spec-017-severity-schedule).
|
|
52
52
|
|
|
53
53
|
## Lifecycle operations
|
|
54
54
|
|
|
@@ -56,19 +56,19 @@ The following table defines the **target token-authoring contract**: the complet
|
|
|
56
56
|
|
|
57
57
|
### Token lifecycle operations
|
|
58
58
|
|
|
59
|
-
| Operation | Description
|
|
60
|
-
| ----------------------- |
|
|
61
|
-
| **create** | Introduce a new token to the dataset. Assign a fresh UUID. Populate name object, value or alias `$ref`, `introduced` version.
|
|
62
|
-
| **edit** | Update a token's value, alias target, rationale, or name-object fields. Preserve UUID.
|
|
63
|
-
| **deprecate** | Set `
|
|
64
|
-
| **rename** | Assign a new name object. Introduce a `
|
|
65
|
-
| **alias-rewire** | Change the `$ref` target UUID of an alias token. Verify the new target resolves in the cascade.
|
|
66
|
-
| **mode-set management** | Add, rename, or remove a mode-set entry. Update affected `mode` fields across tokens.
|
|
67
|
-
| **remove** | Delete a token that has passed its migration window. Verify no `$ref` in the dataset resolves to the removed UUID.
|
|
59
|
+
| Operation | Description | Required fields |
|
|
60
|
+
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
|
|
61
|
+
| **create** | Introduce a new token to the dataset. Assign a fresh UUID. Populate name object, value or alias `$ref`, `lifecycle.introduced` version. | `uuid`, `name`, `value` or `$ref` |
|
|
62
|
+
| **edit** | Update a token's value, alias target, rationale, or name-object fields. Preserve UUID. | `uuid` (for identity lookup) |
|
|
63
|
+
| **deprecate** | Set `lifecycle.deprecatedIn` to the current spec version string; optionally set `lifecycle.replacedBy` and `lifecycle.deprecatedComment`. | `lifecycle.deprecatedIn`, `uuid` |
|
|
64
|
+
| **rename** | Assign a new name object. Introduce a `lifecycle.replacedBy` pointer on the old token (or retire it). Preserve UUID on the renamed token. | Name-object fields, `lifecycle.replacedBy` |
|
|
65
|
+
| **alias-rewire** | Change the `$ref` target UUID of an alias token. Verify the new target resolves in the cascade. | `$ref` |
|
|
66
|
+
| **mode-set management** | Add, rename, or remove a mode-set entry. Update affected `mode` fields across tokens. | Mode-set file + affected token entries |
|
|
67
|
+
| **remove** | Delete a token that has passed its migration window. Verify no `$ref` in the dataset resolves to the removed UUID. | n/a |
|
|
68
68
|
|
|
69
|
-
**NORMATIVE:** A conforming authoring tool MUST assign UUIDs at creation time and MUST NOT change the UUID of an existing token during any edit, deprecate, rename, or alias-rewire operation. UUID stability is the identity contract that allows `$ref`, `
|
|
69
|
+
**NORMATIVE:** A conforming authoring tool MUST assign UUIDs at creation time and MUST NOT change the UUID of an existing token during any edit, deprecate, rename, or alias-rewire operation. UUID stability is the identity contract that allows `$ref`, `lifecycle.replacedBy`, and external consumers to reference tokens across versions.
|
|
70
70
|
|
|
71
|
-
**NORMATIVE:** A conforming authoring tool MUST write a valid `introduced` version on create, using the declared spec version of the active dataset (`specVersion` field in `dataset.json` or `.design-data.toml`).
|
|
71
|
+
**NORMATIVE:** A conforming authoring tool MUST write a valid `lifecycle.introduced` version on create, using the declared spec version of the active dataset (`specVersion` field in `dataset.json` or `.design-data.toml`).
|
|
72
72
|
|
|
73
73
|
**NORMATIVE:** A conforming authoring tool MUST validate the written dataset against Layer 1 (JSON Schema) and Layer 2 (semantic rules) before persisting the write. A write operation that produces a Layer 1 error MUST be rejected.
|
|
74
74
|
|
|
@@ -78,14 +78,14 @@ The following table defines the **target token-authoring contract**: the complet
|
|
|
78
78
|
|
|
79
79
|
The following per-category contracts specify what the authoring surface authors in each registered directory and which validation rules gate the output. Detailed authoring workflows per category are specified in separate subsections of this document as Phase A work progresses.
|
|
80
80
|
|
|
81
|
-
| Category | Directory | Authoring status
|
|
82
|
-
| ---------- | ------------- |
|
|
83
|
-
| Tokens | `tokens/` | Shipped
|
|
84
|
-
| Components | `components/` | Not yet shipped (`write_component` deferred — [Agent surface](agent-surface.md))
|
|
85
|
-
| Fields | `fields/` | Not yet shipped
|
|
86
|
-
| Mode sets | `mode-sets/` |
|
|
87
|
-
| Guidelines | `guidelines/` | Not yet shipped
|
|
88
|
-
| Registry | `registry/` | Not yet shipped (vocabulary is hand-maintained)
|
|
81
|
+
| Category | Directory | Authoring status | Validation gate |
|
|
82
|
+
| ---------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
|
|
83
|
+
| Tokens | `tokens/` | Shipped — create, edit, deprecate, rename, alias-rewire, remove (Phase B, epic [`spectrum-design-data-122`](https://github.com/adobe/spectrum-design-data/issues/122)) | SPEC-001–017, SPEC-041, SPEC-042, SPEC-043 |
|
|
84
|
+
| Components | `components/` | Not yet shipped (`write_component` deferred — [Agent surface](agent-surface.md)) | SPEC-018–040 |
|
|
85
|
+
| Fields | `fields/` | Not yet shipped | SPEC-042, SPEC-043 |
|
|
86
|
+
| Mode sets | `mode-sets/` | Shipped — add/rename/remove-mode, create/remove-mode-set (Phase B, epic [`spectrum-design-data-122`](https://github.com/adobe/spectrum-design-data/issues/122)) | SPEC-005, SPEC-008, SPEC-041 |
|
|
87
|
+
| Guidelines | `guidelines/` | Not yet shipped as a manual authoring surface; generated via extended transformer (Phase 10, beads `ek4`) | SPEC-045, SPEC-046 |
|
|
88
|
+
| Registry | `registry/` | Not yet shipped (vocabulary is hand-maintained) | SPEC-033, SPEC-034, SPEC-035 |
|
|
89
89
|
|
|
90
90
|
### Token authoring contract
|
|
91
91
|
|
|
@@ -95,20 +95,20 @@ Tokens are authored in `tokens/**/*.tokens.json`. Files may be nested arbitraril
|
|
|
95
95
|
|
|
96
96
|
**Required at creation:** A conforming authoring tool MUST write:
|
|
97
97
|
|
|
98
|
-
| Field
|
|
99
|
-
|
|
|
100
|
-
| `name`
|
|
101
|
-
| `uuid`
|
|
102
|
-
| `value` or `$ref`
|
|
103
|
-
| `$schema`
|
|
104
|
-
| `introduced`
|
|
98
|
+
| Field | Requirement | Notes |
|
|
99
|
+
| ---------------------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
100
|
+
| `name` | REQUIRED | Name object with at least `property`; MUST be decomposed via the `fields/` catalog — see [Taxonomy-aware authoring](#taxonomy-aware-authoring) |
|
|
101
|
+
| `uuid` | REQUIRED | Fresh UUID v4 assigned by the tool; MUST NOT change for the lifetime of the token |
|
|
102
|
+
| `value` or `$ref` | REQUIRED (exactly one) | Literal value or alias reference to another token's UUID |
|
|
103
|
+
| `$schema` | RECOMMENDED | Token-type schema URI (e.g. `color.json`, `typography.json`) from `packages/design-data-spec/schemas/` |
|
|
104
|
+
| `lifecycle.introduced` | RECOMMENDED | Spec version string of the active dataset at creation time |
|
|
105
105
|
|
|
106
106
|
**Validation gate:** SPEC-001–017 (name, value, lifecycle, tech-debt), SPEC-041 (mode-set
|
|
107
107
|
conformance), SPEC-042 (field-scope), SPEC-043 (domain-required-fields).
|
|
108
108
|
|
|
109
|
-
**Edit and lifecycle operations (Phase B):** Edit, deprecate, rename, alias-rewire, mode-set
|
|
109
|
+
**Edit and lifecycle operations (Phase B, shipped):** Edit, deprecate, rename, alias-rewire, mode-set
|
|
110
110
|
management, and remove are specified in [Lifecycle operations](#lifecycle-operations) and are
|
|
111
|
-
implemented
|
|
111
|
+
implemented (epic [`spectrum-design-data-122`](https://github.com/adobe/spectrum-design-data/issues/122), closed).
|
|
112
112
|
|
|
113
113
|
***
|
|
114
114
|
|
|
@@ -134,8 +134,8 @@ be named with the component's `name` field value (e.g. `button.json` for `name:
|
|
|
134
134
|
cross-references), SPEC-034 (category registry sync), SPEC-035 (anatomy-term registry sync),
|
|
135
135
|
SPEC-038–040 (lifecycle, display name, schema).
|
|
136
136
|
|
|
137
|
-
**Authoring status:** Not yet shipped — `write_component`
|
|
138
|
-
[Scheduled promotion](#scheduled-promotion)).
|
|
137
|
+
**Authoring status:** Not yet shipped — `write_component` was out of scope for Phase B (tokens and
|
|
138
|
+
mode-sets only; see [Scheduled promotion](#scheduled-promotion)) and remains unscheduled.
|
|
139
139
|
|
|
140
140
|
***
|
|
141
141
|
|
|
@@ -261,7 +261,7 @@ authoring is Phase C scope; vocabulary additions today follow the manual process
|
|
|
261
261
|
|
|
262
262
|
1. Write all authored artifacts to the dataset root's registered directories (not to legacy output files).
|
|
263
263
|
2. Assign UUIDs at creation time and preserve them across all subsequent operations.
|
|
264
|
-
3. Write a valid `introduced` version on all created artifacts.
|
|
264
|
+
3. Write a valid `lifecycle.introduced` version on all created artifacts.
|
|
265
265
|
4. Validate written artifacts against Layer 1 (JSON Schema) and Layer 2 (semantic rules) before persisting.
|
|
266
266
|
5. Support structured name-object field decomposition using the `fields/` catalog for token creation.
|
|
267
267
|
|
package/spec/dataset-layout.md
CHANGED
|
@@ -43,7 +43,7 @@ A dataset is rooted at a single **dataset root** directory. The following table
|
|
|
43
43
|
Tooling that operates on "the current dataset" (rather than an explicit path) **MUST** resolve the dataset root using the following precedence. The first match wins; later tiers are only consulted when an earlier tier does not resolve a value.
|
|
44
44
|
|
|
45
45
|
1. **Explicit override** — a path passed directly by the caller (CLI positional argument or `--*-path` flag, environment variable). Explicit overrides always win.
|
|
46
|
-
2. **Config file** — a `.design-data.toml` discovered by walking **up** the ancestor chain from the working directory. A `[source]` block
|
|
46
|
+
2. **Config file** — a `.design-data.toml` discovered by walking **up** the ancestor chain from the working directory. A `[source]` block names where the foundation dataset comes from: `type = "path"` (a dataset root resolved relative to the config file's directory) or `type = "github"` (a repo pinned by exactly one of `tag`, `branch`, or `sha`, fetched as a release tarball over HTTPS). An optional **top-level** `manifest` key (source-independent, resolved relative to the config file) points at a Layer 2 platform `manifest.json` that cascades on top of whichever source is used. This is the explicit, portable way to point a project at a dataset outside its own tree.
|
|
47
47
|
3. **In-repo probing** — when running inside a monorepo checkout, probe for the standard layout relative to the working directory (`packages/design-data/tokens` and one level up). This preserves the in-repo workflow with zero configuration.
|
|
48
48
|
4. **Embedded snapshot** — when no dataset is found on disk, tooling MAY fall back to a snapshot of the foundation dataset embedded in the binary, materialized to a local cache directory.
|
|
49
49
|
|
package/spec/evolution.md
CHANGED
|
@@ -12,36 +12,36 @@ Tokens progress through the following lifecycle stages:
|
|
|
12
12
|
introduced → active → deprecated → planned removal → removed
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
| Stage | Token state
|
|
16
|
-
| ------------------- |
|
|
17
|
-
| **Introduced** | Token first appears in the dataset. `introduced` field records the version.
|
|
18
|
-
| **Active** | Token is current and recommended for use. No `
|
|
19
|
-
| **Deprecated** | Token is no longer recommended. `
|
|
20
|
-
| **Planned removal** | `plannedRemoval` records the target version. The token remains in the dataset but consumers should complete migration.
|
|
21
|
-
| **Removed** | Token is deleted from the dataset. Consumers that still reference it will break.
|
|
15
|
+
| Stage | Token state |
|
|
16
|
+
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
17
|
+
| **Introduced** | Token first appears in the dataset. `lifecycle.introduced` field records the version. |
|
|
18
|
+
| **Active** | Token is current and recommended for use. No `lifecycle` field (or no `deprecatedIn` within it). |
|
|
19
|
+
| **Deprecated** | Token is no longer recommended. `lifecycle.deprecatedIn` records the version. Consumers receive warnings. `lifecycle.replacedBy` points to the successor token(s) when a direct replacement exists. |
|
|
20
|
+
| **Planned removal** | `lifecycle.plannedRemoval` records the target version. The token remains in the dataset but consumers should complete migration. |
|
|
21
|
+
| **Removed** | Token is deleted from the dataset. Consumers that still reference it will break. |
|
|
22
22
|
|
|
23
23
|
### Lifecycle fields
|
|
24
24
|
|
|
25
25
|
See [Token format — Lifecycle and metadata](token-format.md#lifecycle-and-metadata) for the full field definitions and normative rules.
|
|
26
26
|
|
|
27
|
-
### What `
|
|
27
|
+
### What `lifecycle.replacedBy` guarantees
|
|
28
28
|
|
|
29
|
-
When a token carries `
|
|
29
|
+
When a token carries `lifecycle.replacedBy`:
|
|
30
30
|
|
|
31
31
|
* Each target UUID **MUST** resolve to an existing token in the dataset (rule `SPEC-010`).
|
|
32
32
|
* The target token **SHOULD NOT** itself be deprecated. Chains of replacements (A replaced by B, B replaced by C) are discouraged; authors should point directly to the final replacement.
|
|
33
33
|
* For a single UUID (1:1 replacement), consumers can mechanically rewrite references.
|
|
34
|
-
* For an array of UUIDs (one-to-many split), the `
|
|
34
|
+
* For an array of UUIDs (one-to-many split), the `lifecycle.deprecatedComment` **MUST** explain which replacement applies in which context.
|
|
35
35
|
|
|
36
36
|
## Migration windows
|
|
37
37
|
|
|
38
|
-
**NORMATIVE:** A deprecated token **MUST** remain in the published dataset for at least **two minor versions** after the version recorded in `
|
|
38
|
+
**NORMATIVE:** A deprecated token **MUST** remain in the published dataset for at least **two minor versions** after the version recorded in `lifecycle.deprecatedIn` before it may be removed.
|
|
39
39
|
|
|
40
40
|
**EXAMPLE:** A token deprecated in `3.2.0` may not be removed until `3.4.0` at the earliest. Removal in a major version (e.g. `4.0.0`) is always permitted regardless of how recently the token was deprecated.
|
|
41
41
|
|
|
42
42
|
**RATIONALE:** Two minor versions gives consumers at least two release cycles to migrate. The major-version escape hatch allows accumulated deprecations to be cleaned up in a coordinated breaking release.
|
|
43
43
|
|
|
44
|
-
If `plannedRemoval` is set, it overrides the default window — the token will be removed in the specified version (which must not precede the `
|
|
44
|
+
If `lifecycle.plannedRemoval` is set, it overrides the default window — the token will be removed in the specified version (which must not precede the `deprecatedIn` version).
|
|
45
45
|
|
|
46
46
|
## Change classification
|
|
47
47
|
|
|
@@ -52,7 +52,7 @@ The specification follows [Semantic Versioning](https://semver.org/) for its pub
|
|
|
52
52
|
* New tokens added to the dataset
|
|
53
53
|
* New optional fields added to token schema
|
|
54
54
|
* New validation rules added to the rule catalog
|
|
55
|
-
* Tokens deprecated (with `
|
|
55
|
+
* Tokens deprecated (with `lifecycle.deprecatedIn` field)
|
|
56
56
|
* Rule severity relaxed (error → warning)
|
|
57
57
|
* New enum values added to registries
|
|
58
58
|
|
|
@@ -79,13 +79,13 @@ The `@adobe/spectrum-tokens` package continues to publish tokens in the **legacy
|
|
|
79
79
|
|
|
80
80
|
### Lifecycle field mapping
|
|
81
81
|
|
|
82
|
-
| Cascade format
|
|
83
|
-
|
|
|
84
|
-
| `
|
|
85
|
-
| `
|
|
86
|
-
| `introduced`
|
|
87
|
-
| `plannedRemoval`
|
|
88
|
-
| `
|
|
82
|
+
| Cascade format | Legacy format |
|
|
83
|
+
| -------------------------------------------------- | ------------------------------------- |
|
|
84
|
+
| `lifecycle.deprecatedIn: "3.2.0"` (version string) | `deprecated: true` (boolean) |
|
|
85
|
+
| `lifecycle.replacedBy: "<uuid>"` | `renamed: "<target-token-name>"` |
|
|
86
|
+
| `lifecycle.introduced` | Not emitted |
|
|
87
|
+
| `lifecycle.plannedRemoval` | Not emitted |
|
|
88
|
+
| `lifecycle.deprecatedComment` | `deprecated_comment` (passed through) |
|
|
89
89
|
|
|
90
90
|
### Output-generator determinism
|
|
91
91
|
|
package/spec/index.md
CHANGED
|
@@ -28,6 +28,7 @@ The specification defines:
|
|
|
28
28
|
14. **Dataset layout** — normative directory structure of a dataset (`tokens/`, `components/`, `fields/`, `mode-sets/`, `registry/`, `guidelines/`), discovery algorithm, and optional root descriptor ([Dataset layout](dataset-layout.md)).
|
|
29
29
|
15. **Guideline documents** — standalone JSON files representing non-component design guidance pages (color, typography, motion, spacing, principles, etc.); each wraps page metadata and a `documentBlocks` body ([Guideline format](guideline-format.md)).
|
|
30
30
|
16. **Authoring workflow** — normative contract for authoring design data via tooling: authoritative source location, lifecycle operations (create / edit / deprecate / rename / alias-rewire / mode-set management), taxonomy-aware decomposition requirement, and output-generation obligations ([Authoring workflow](authoring-workflow.md)).
|
|
31
|
+
17. **Relationship format** — Component/Token Relationship (CTR): the anonymous-token entity unifying `tokenBindings` and token name-object scope fields, explicit relationship context, options validation, and interim legacy-compatibility fields ([Relationship format](relationship-format.md)).
|
|
31
32
|
|
|
32
33
|
## Conformance
|
|
33
34
|
|
|
@@ -83,6 +84,7 @@ Full governance (compatibility tiers, migration, CLI `--spec-version`) is discus
|
|
|
83
84
|
| [Dataset layout](dataset-layout.md) | Normative dataset directory structure, discovery algorithm, optional root descriptor, and SPEC-044 structural pre-check. |
|
|
84
85
|
| [Guideline format](guideline-format.md) | Standalone guideline document shape: metadata fields, `category` enum, `related` cross-references, and required `documentBlocks` body (SPEC-045/046). |
|
|
85
86
|
| [Authoring workflow](authoring-workflow.md) | Normative authoring contract: authoritative source location, lifecycle operations, taxonomy-aware decomposition, and output-generation obligations. |
|
|
87
|
+
| [Relationship format](relationship-format.md) | Component/Token Relationship (CTR): shape, explicit relationship context, options validation, and interim legacy-compatibility fields (SPEC-051–057). |
|
|
86
88
|
|
|
87
89
|
## JSON Schema `$id` and versioning
|
|
88
90
|
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Relationship format (Component/Token Relationship — CTR)
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
A Component/Token Relationship (CTR) is an anonymous token that unifies the two mechanisms that today independently connect components and tokens:
|
|
6
|
+
|
|
7
|
+
1. **`tokenBindings`** on a component declaration (component-declares-usage direction; see [component-format.md#token-bindings](component-format.md#token-bindings)).
|
|
8
|
+
2. **Name-object scope fields** on a token (`component`, `variant`, `anatomy`, `state`, and arbitrary option keys; token-declares-scope direction, validated today by SPEC-018, SPEC-019, SPEC-020, SPEC-022, and SPEC-040).
|
|
9
|
+
|
|
10
|
+
Rather than encoding component/part/option context inside a token's `name` string, a CTR carries its value (or `$ref` alias) alongside an explicit `scope` object naming the component, part, property, and option scope it belongs to, plus an optional `context` string carrying a human-readable label (the same role `tokenBindings[].context` plays today — e.g. mapping to a Figma Token Group label). CTR entries live under `relationships/*.json`, each file a JSON array of CTR objects (see [`relationship.schema.json`](../schemas/relationship.schema.json)).
|
|
11
|
+
|
|
12
|
+
**NORMATIVE:** This document defines the CTR **foundation** — shape, validation rules, and interim legacy-compatibility fields. It does not migrate existing token or component data; `tokenBindings` and `componentBindings` remain in the schemas and are **NOT** removed by this chapter (deferred to a future migration phase).
|
|
13
|
+
|
|
14
|
+
## Shape
|
|
15
|
+
|
|
16
|
+
Each CTR is one of two subtypes, mirroring the token `oneOf` split (see [token-format.md](token-format.md)):
|
|
17
|
+
|
|
18
|
+
* **Value-owning CTR** (`ctrWithValue`) — carries a literal `value`, like a token.
|
|
19
|
+
* **Relationship-only CTR** (`ctrWithRef`) — carries a `$ref` alias to another token or CTR `uuid`, instead of an owned value.
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
[
|
|
23
|
+
{
|
|
24
|
+
"scope": {
|
|
25
|
+
"component": "button",
|
|
26
|
+
"part": "label",
|
|
27
|
+
"property": "color",
|
|
28
|
+
"options": { "variant": "accent", "state": ["hover"] }
|
|
29
|
+
},
|
|
30
|
+
"context": "Label color, accent variant, hover",
|
|
31
|
+
"value": "#0060e0",
|
|
32
|
+
"uuid": "5b1a8e2e-9e2f-4b7a-9b2e-1a2b3c4d5e6f"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"scope": {
|
|
36
|
+
"component": "checkbox",
|
|
37
|
+
"property": "corner-radius"
|
|
38
|
+
},
|
|
39
|
+
"$ref": "5b1a8e2e-9e2f-4b7a-9b2e-1a2b3c4d5e6f"
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Scope fields
|
|
45
|
+
|
|
46
|
+
| Field | Required | Type | Description |
|
|
47
|
+
| ----------------- | -------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
48
|
+
| `scope.component` | yes | string | Component name (kebab-case). **MUST** match the `name` of a declared component in the dataset (rule SPEC-051, mirrors SPEC-018). |
|
|
49
|
+
| `scope.part` | no | string | Anatomy part name. **MUST** match a declared anatomy part on the referenced component when present (rule SPEC-052, mirrors SPEC-020). |
|
|
50
|
+
| `scope.property` | yes | string | The stylistic attribute this relationship describes (e.g. `color`, `width`, `padding`). |
|
|
51
|
+
| `scope.options` | no | object | Option-scoped narrowing. Each `options.<key>` value **MUST** validate against the referenced component's `options.<key>.values` (rule SPEC-053 — the headline CTR rule, stricter than the token-side SPEC-040 warning). `options.state` is the exception: an ordered array of atomic state ids, validated against the component's declared states (rule SPEC-054, mirrors SPEC-022). |
|
|
52
|
+
| `context` | no | string | Human-readable label for how this CTR is used (mirrors `tokenBindings[].context`; maps to a Figma Token Group label). Purely descriptive — not validated. |
|
|
53
|
+
|
|
54
|
+
Layer 1 (`relationship.schema.json`) only enforces shape: `scope.options` is an object, `scope.options.state` (when present) is an array of strings, and other option values are typically strings. It does **not** enforce which option values are valid — that is a Layer 2 (Rust, `sdk/core`) relational rule, because it requires cross-referencing the component catalog.
|
|
55
|
+
|
|
56
|
+
## Value-owning vs. relationship-only
|
|
57
|
+
|
|
58
|
+
| Field | Subtype | Description |
|
|
59
|
+
| ------- | -------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
60
|
+
| `value` | `ctrWithValue` | Literal value owned by this CTR, same value-type narrowing as a token's `value` (`$valueType`). |
|
|
61
|
+
| `$ref` | `ctrWithRef` | Alias target. **MUST** resolve to a token or CTR `uuid` in the dataset (rule SPEC-055, mirrors SPEC-001/SPEC-027). |
|
|
62
|
+
|
|
63
|
+
A CTR **MUST NOT** declare both `value` and `$ref` (enforced at Layer 1 via `not: { required: [...] }`, mirroring `token.schema.json`).
|
|
64
|
+
|
|
65
|
+
## Identity
|
|
66
|
+
|
|
67
|
+
| Field | Required | Type | Description |
|
|
68
|
+
| ------ | -------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
69
|
+
| `uuid` | no | string (uuid) | **MUST** be globally unique across all relationship entries within the same cascade layer (rule SPEC-056, mirrors SPEC-004). Required for a CTR to be a valid `$ref` target. |
|
|
70
|
+
|
|
71
|
+
## Legacy fields (interim)
|
|
72
|
+
|
|
73
|
+
To keep `packages/tokens/src` (the legacy generated output, produced by `design-data migrate legacy-output` / `sdk/core/src/legacy.rs`) byte-identical while this foundation lands, a CTR that has a legacy counterpart carries transitional fields so the existing legacy generator can still reproduce that output:
|
|
74
|
+
|
|
75
|
+
| Field | Required | Type | Description |
|
|
76
|
+
| ----------- | -------- | ------------- | ----------------------------------------------------------------------------------------------------------- |
|
|
77
|
+
| `legacyKey` | no | string | Pins the exact flat key written to legacy output, mirroring the token name-object `legacyKey` escape hatch. |
|
|
78
|
+
| `setUuid` | no | string (uuid) | Identifies the legacy color-set entry this CTR belongs to. Only meaningful alongside `legacyKey`. |
|
|
79
|
+
| `setSchema` | no | string | Names the legacy color-set schema this CTR's set entry conforms to. Only meaningful alongside `setUuid`. |
|
|
80
|
+
|
|
81
|
+
**NORMATIVE:** A CTR that has no legacy counterpart **SHOULD NOT** carry `legacyKey`/`setUuid`/`setSchema` — these fields exist solely to bridge the interim period before the legacy generator is retired or rewritten to consume CTRs directly. Rule SPEC-057 (`ctr-legacykey-present-if-legacy`, warning) is an advisory placeholder documenting this intent; it does not attempt to detect "should have a legacy counterpart" automatically, since that determination belongs to the (future) generator-side migration work, not this foundation.
|
|
82
|
+
|
|
83
|
+
These fields are transitional. Once the legacy generator (or its replacement) reads CTRs directly, `legacyKey`/`setUuid`/`setSchema` are expected to be removed in a later spec version.
|
|
84
|
+
|
|
85
|
+
## Relationship to `tokenBindings` / `componentBindings`
|
|
86
|
+
|
|
87
|
+
CTRs are designed to eventually supersede both `tokenBindings` (on components, see [component-format.md#token-bindings](component-format.md#token-bindings)) and the token-side `componentBindings` reverse index (see [token-format.md#component-bindings](token-format.md#component-bindings)), by combining both directions — and the token name-object scope fields — into a single first-class relationship record with an explicit `context`.
|
|
88
|
+
|
|
89
|
+
**NORMATIVE:** This chapter does **NOT** remove or deprecate `tokenBindings` or `componentBindings`. Both remain valid and required as-is. Migrating existing data onto CTRs, and any eventual removal of the superseded mechanisms, is out of scope for this foundation and deferred to a separate migration phase.
|
|
90
|
+
|
|
91
|
+
## SPEC rules
|
|
92
|
+
|
|
93
|
+
The following rules are added to the Layer 2 rule catalog (`rules/rules.yaml`) by this chapter. New CTR rules start at SPEC-051 to avoid collision with the existing catalog (SPEC-001–SPEC-050).
|
|
94
|
+
|
|
95
|
+
| Rule ID | Name | Severity | Assert |
|
|
96
|
+
| -------- | --------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
97
|
+
| SPEC-051 | `ctr-component-exists` | error | CTR `scope.component` value **MUST** match the `name` of a declared component in the dataset. |
|
|
98
|
+
| SPEC-052 | `ctr-part-valid` | error | CTR `scope.part` value **MUST** match the `name` of a declared anatomy part on the referenced component (when present). |
|
|
99
|
+
| SPEC-053 | `ctr-option-valid` | error | CTR `scope.options.<key>` value **MUST** match a value in the declared `options.<key>.values` list for the referenced component (when that list exists). |
|
|
100
|
+
| SPEC-054 | `ctr-state-valid` | error | CTR `scope.options.state` array elements **MUST** match the `name` of a declared state on the referenced component (when state declarations are present). |
|
|
101
|
+
| SPEC-055 | `ctr-ref-resolves` | error | CTR `$ref` value **MUST** resolve to a declared token or relationship `uuid` in the dataset. |
|
|
102
|
+
| SPEC-056 | `ctr-uuid-unique` | error | CTR `uuid` values **MUST** be unique across all relationship entries within the same cascade layer. |
|
|
103
|
+
| SPEC-057 | `ctr-legacykey-present-if-legacy` | warning | Advisory placeholder: a CTR that round-trips through the legacy generator **SHOULD** carry `legacyKey`. Generator-side "should have a legacy counterpart" detection is deferred; this rule documents intent rather than enforcing it structurally. |
|
package/spec/token-format.md
CHANGED
|
@@ -134,18 +134,25 @@ When **`value`** is present, it **MUST** conform to the declared value type for
|
|
|
134
134
|
|
|
135
135
|
### Lifecycle and metadata
|
|
136
136
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
|
145
|
-
|
|
|
146
|
-
| `
|
|
147
|
-
| `
|
|
148
|
-
| `
|
|
137
|
+
Version lifecycle fields are grouped under an OPTIONAL nested `lifecycle` object, mirroring the
|
|
138
|
+
component schema's `lifecycle` pattern (see [Component format](component-format.md)). This
|
|
139
|
+
implements the token lifecycle model described in
|
|
140
|
+
[#623](https://github.com/adobe/spectrum-design-data/discussions/623) and the evolution policy in
|
|
141
|
+
[Evolution](evolution.md). Inspired by Swift's `@available` attribute, Kotlin's `@Deprecated`, and
|
|
142
|
+
OpenAPI 3.3's deprecation model.
|
|
143
|
+
|
|
144
|
+
| Field | Type | Description |
|
|
145
|
+
| ----------------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
|
146
|
+
| `uuid` | string (UUID) | Stable unique id for rename tracking and diffs. |
|
|
147
|
+
| `lifecycle.introduced` | string (version) | Spec version when the token was first added (e.g. `"1.0.0"`). |
|
|
148
|
+
| `lifecycle.deprecatedIn` | string (version) | Spec version when the token was deprecated (e.g. `"3.2.0"`). Truthy = deprecated. |
|
|
149
|
+
| `lifecycle.deprecatedComment` | string | Human-readable deprecation explanation and migration guidance. |
|
|
150
|
+
| `lifecycle.replacedBy` | string (UUID) or array of string (UUID) | UUID(s) of the replacement token(s). Single string for 1:1 replacement; array for one-to-many splits. |
|
|
151
|
+
| `lifecycle.plannedRemoval` | string (version) | Spec version when the token will be removed. If omitted, defaults to the next major version after `deprecatedIn`. |
|
|
152
|
+
| `private` | boolean | Not part of public API surface. |
|
|
153
|
+
| `rationale` | string | Why this token has its current value. Intended for product-layer authoring context; see [Product context](product-context.md). |
|
|
154
|
+
|
|
155
|
+
`private` and `rationale` stay flat (not version-lifecycle concepts).
|
|
149
156
|
|
|
150
157
|
#### Lifecycle example
|
|
151
158
|
|
|
@@ -154,38 +161,43 @@ The following OPTIONAL fields implement the token lifecycle model described in [
|
|
|
154
161
|
"name": { "component": "button", "object": "background", "property": "color", "variant": "primary" },
|
|
155
162
|
"value": "#0265dc",
|
|
156
163
|
"uuid": "aaaaaaaa-0001-4000-8000-000000000001",
|
|
157
|
-
"
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
164
|
+
"lifecycle": {
|
|
165
|
+
"introduced": "1.0.0",
|
|
166
|
+
"deprecatedIn": "3.2.0",
|
|
167
|
+
"deprecatedComment": "Use action-background-default instead.",
|
|
168
|
+
"replacedBy": "bbbbbbbb-0002-4000-8000-000000000001",
|
|
169
|
+
"plannedRemoval": "4.0.0"
|
|
170
|
+
}
|
|
162
171
|
}
|
|
163
172
|
```
|
|
164
173
|
|
|
165
174
|
#### Normative rules
|
|
166
175
|
|
|
167
|
-
**NORMATIVE:** If `
|
|
176
|
+
**NORMATIVE:** If `lifecycle.deprecatedIn` is present, `lifecycle.deprecatedComment` **SHOULD** be present.
|
|
168
177
|
|
|
169
|
-
**NORMATIVE:** If `
|
|
178
|
+
**NORMATIVE:** If `lifecycle.replacedBy` is an array, `lifecycle.deprecatedComment` is **REQUIRED** — the comment **MUST** explain which replacement applies in which context.
|
|
170
179
|
|
|
171
|
-
**NORMATIVE:** If `
|
|
180
|
+
**NORMATIVE:** If `lifecycle.replacedBy` is present, `lifecycle.deprecatedIn` **MUST** be present.
|
|
172
181
|
|
|
173
|
-
**NORMATIVE:** If `plannedRemoval` is present, `
|
|
182
|
+
**NORMATIVE:** If `lifecycle.plannedRemoval` is present, `lifecycle.deprecatedIn` **MUST** be present, and the `plannedRemoval` version **MUST NOT** precede the `deprecatedIn` version.
|
|
174
183
|
|
|
175
|
-
**NORMATIVE:** Each UUID in `
|
|
184
|
+
**NORMATIVE:** Each UUID in `lifecycle.replacedBy` **MUST** resolve to an existing token in the dataset (see rule `SPEC-010`).
|
|
176
185
|
|
|
177
186
|
#### Legacy format mapping
|
|
178
187
|
|
|
179
188
|
When generating legacy-format output from cascade tokens:
|
|
180
189
|
|
|
181
|
-
* `
|
|
182
|
-
* `
|
|
183
|
-
* `
|
|
190
|
+
* `lifecycle.deprecatedIn: "3.2.0"` (or any truthy value) maps to flat `deprecated: true`
|
|
191
|
+
* `lifecycle.deprecatedComment` maps to flat `deprecated_comment` (copied verbatim)
|
|
192
|
+
* `lifecycle.replacedBy: "<uuid>"` maps to flat `renamed: "<target-token-name>"` (resolved via UUID lookup)
|
|
193
|
+
* `lifecycle.plannedRemoval` and `lifecycle.introduced` have no legacy equivalent and are not emitted
|
|
194
|
+
* The `lifecycle` wrapper itself is never emitted — legacy format has no nested wrapper
|
|
184
195
|
|
|
185
196
|
When migrating legacy-format tokens to cascade:
|
|
186
197
|
|
|
187
|
-
* `deprecated: true` maps to `
|
|
188
|
-
* `
|
|
198
|
+
* `deprecated: true` maps to `lifecycle.deprecatedIn: "unknown"` (authors should backfill the actual version)
|
|
199
|
+
* `deprecated_comment` maps to `lifecycle.deprecatedComment` (copied verbatim)
|
|
200
|
+
* `renamed: "<name>"` maps to `lifecycle.replacedBy: "<uuid>"` (resolved via name lookup across all files in the migrated input set). If the rename target is not found in the scanned corpus, the field is dropped — `lifecycle.replacedBy` must be set manually in that case
|
|
189
201
|
|
|
190
202
|
### `specVersion`
|
|
191
203
|
|