@harness-engineering/cli 2.6.0 → 2.7.0

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.
Files changed (156) hide show
  1. package/dist/agents/skills/claude-code/align-design-system/SKILL.md +174 -0
  2. package/dist/agents/skills/claude-code/align-design-system/skill.yaml +57 -0
  3. package/dist/agents/skills/claude-code/audit-brand-compliance/SKILL.md +189 -0
  4. package/dist/agents/skills/claude-code/audit-brand-compliance/skill.yaml +50 -0
  5. package/dist/agents/skills/claude-code/audit-component-anatomy/SKILL.md +181 -0
  6. package/dist/agents/skills/claude-code/audit-component-anatomy/skill.yaml +51 -0
  7. package/dist/agents/skills/claude-code/copy-craft/SKILL.md +192 -0
  8. package/dist/agents/skills/claude-code/copy-craft/skill.yaml +52 -0
  9. package/dist/agents/skills/claude-code/detect-design-drift/SKILL.md +139 -0
  10. package/dist/agents/skills/claude-code/detect-design-drift/skill.yaml +50 -0
  11. package/dist/agents/skills/claude-code/harness-accessibility/SKILL.md +10 -0
  12. package/dist/agents/skills/claude-code/harness-design-craft/SKILL.md +212 -0
  13. package/dist/agents/skills/claude-code/harness-design-craft/skill.yaml +57 -0
  14. package/dist/agents/skills/claude-code/harness-design-pipeline/SKILL.md +266 -0
  15. package/dist/agents/skills/claude-code/harness-design-pipeline/skill.yaml +70 -0
  16. package/dist/agents/skills/claude-code/knowledge-craft/SKILL.md +180 -0
  17. package/dist/agents/skills/claude-code/knowledge-craft/skill.yaml +49 -0
  18. package/dist/agents/skills/claude-code/naming-craft/SKILL.md +172 -0
  19. package/dist/agents/skills/claude-code/naming-craft/skill.yaml +51 -0
  20. package/dist/agents/skills/claude-code/security-craft/SKILL.md +205 -0
  21. package/dist/agents/skills/claude-code/security-craft/skill.yaml +58 -0
  22. package/dist/agents/skills/claude-code/spec-craft/SKILL.md +184 -0
  23. package/dist/agents/skills/claude-code/spec-craft/skill.yaml +55 -0
  24. package/dist/agents/skills/claude-code/test-craft/SKILL.md +212 -0
  25. package/dist/agents/skills/claude-code/test-craft/skill.yaml +58 -0
  26. package/dist/agents/skills/codex/align-design-system/SKILL.md +174 -0
  27. package/dist/agents/skills/codex/align-design-system/skill.yaml +57 -0
  28. package/dist/agents/skills/codex/audit-brand-compliance/SKILL.md +189 -0
  29. package/dist/agents/skills/codex/audit-brand-compliance/skill.yaml +50 -0
  30. package/dist/agents/skills/codex/audit-component-anatomy/SKILL.md +181 -0
  31. package/dist/agents/skills/codex/audit-component-anatomy/skill.yaml +51 -0
  32. package/dist/agents/skills/codex/copy-craft/SKILL.md +192 -0
  33. package/dist/agents/skills/codex/copy-craft/skill.yaml +52 -0
  34. package/dist/agents/skills/codex/detect-design-drift/SKILL.md +139 -0
  35. package/dist/agents/skills/codex/detect-design-drift/skill.yaml +50 -0
  36. package/dist/agents/skills/codex/harness-accessibility/SKILL.md +10 -0
  37. package/dist/agents/skills/codex/harness-design-craft/SKILL.md +212 -0
  38. package/dist/agents/skills/codex/harness-design-craft/skill.yaml +57 -0
  39. package/dist/agents/skills/codex/harness-design-pipeline/SKILL.md +266 -0
  40. package/dist/agents/skills/codex/harness-design-pipeline/skill.yaml +70 -0
  41. package/dist/agents/skills/codex/knowledge-craft/SKILL.md +180 -0
  42. package/dist/agents/skills/codex/knowledge-craft/skill.yaml +49 -0
  43. package/dist/agents/skills/codex/naming-craft/SKILL.md +172 -0
  44. package/dist/agents/skills/codex/naming-craft/skill.yaml +51 -0
  45. package/dist/agents/skills/codex/security-craft/SKILL.md +205 -0
  46. package/dist/agents/skills/codex/security-craft/skill.yaml +58 -0
  47. package/dist/agents/skills/codex/spec-craft/SKILL.md +184 -0
  48. package/dist/agents/skills/codex/spec-craft/skill.yaml +55 -0
  49. package/dist/agents/skills/codex/test-craft/SKILL.md +212 -0
  50. package/dist/agents/skills/codex/test-craft/skill.yaml +58 -0
  51. package/dist/agents/skills/cursor/align-design-system/SKILL.md +174 -0
  52. package/dist/agents/skills/cursor/align-design-system/skill.yaml +57 -0
  53. package/dist/agents/skills/cursor/audit-brand-compliance/SKILL.md +189 -0
  54. package/dist/agents/skills/cursor/audit-brand-compliance/skill.yaml +50 -0
  55. package/dist/agents/skills/cursor/audit-component-anatomy/SKILL.md +181 -0
  56. package/dist/agents/skills/cursor/audit-component-anatomy/skill.yaml +51 -0
  57. package/dist/agents/skills/cursor/copy-craft/SKILL.md +192 -0
  58. package/dist/agents/skills/cursor/copy-craft/skill.yaml +52 -0
  59. package/dist/agents/skills/cursor/detect-design-drift/SKILL.md +139 -0
  60. package/dist/agents/skills/cursor/detect-design-drift/skill.yaml +50 -0
  61. package/dist/agents/skills/cursor/harness-accessibility/SKILL.md +10 -0
  62. package/dist/agents/skills/cursor/harness-design-craft/SKILL.md +212 -0
  63. package/dist/agents/skills/cursor/harness-design-craft/skill.yaml +57 -0
  64. package/dist/agents/skills/cursor/harness-design-pipeline/SKILL.md +266 -0
  65. package/dist/agents/skills/cursor/harness-design-pipeline/skill.yaml +70 -0
  66. package/dist/agents/skills/cursor/knowledge-craft/SKILL.md +180 -0
  67. package/dist/agents/skills/cursor/knowledge-craft/skill.yaml +49 -0
  68. package/dist/agents/skills/cursor/naming-craft/SKILL.md +172 -0
  69. package/dist/agents/skills/cursor/naming-craft/skill.yaml +51 -0
  70. package/dist/agents/skills/cursor/security-craft/SKILL.md +205 -0
  71. package/dist/agents/skills/cursor/security-craft/skill.yaml +58 -0
  72. package/dist/agents/skills/cursor/spec-craft/SKILL.md +184 -0
  73. package/dist/agents/skills/cursor/spec-craft/skill.yaml +55 -0
  74. package/dist/agents/skills/cursor/test-craft/SKILL.md +212 -0
  75. package/dist/agents/skills/cursor/test-craft/skill.yaml +58 -0
  76. package/dist/agents/skills/gemini-cli/align-design-system/SKILL.md +174 -0
  77. package/dist/agents/skills/gemini-cli/align-design-system/skill.yaml +57 -0
  78. package/dist/agents/skills/gemini-cli/audit-brand-compliance/SKILL.md +189 -0
  79. package/dist/agents/skills/gemini-cli/audit-brand-compliance/skill.yaml +50 -0
  80. package/dist/agents/skills/gemini-cli/audit-component-anatomy/SKILL.md +181 -0
  81. package/dist/agents/skills/gemini-cli/audit-component-anatomy/skill.yaml +51 -0
  82. package/dist/agents/skills/gemini-cli/copy-craft/SKILL.md +192 -0
  83. package/dist/agents/skills/gemini-cli/copy-craft/skill.yaml +52 -0
  84. package/dist/agents/skills/gemini-cli/detect-design-drift/SKILL.md +139 -0
  85. package/dist/agents/skills/gemini-cli/detect-design-drift/skill.yaml +50 -0
  86. package/dist/agents/skills/gemini-cli/harness-accessibility/SKILL.md +10 -0
  87. package/dist/agents/skills/gemini-cli/harness-design-craft/SKILL.md +212 -0
  88. package/dist/agents/skills/gemini-cli/harness-design-craft/skill.yaml +57 -0
  89. package/dist/agents/skills/gemini-cli/harness-design-pipeline/SKILL.md +266 -0
  90. package/dist/agents/skills/gemini-cli/harness-design-pipeline/skill.yaml +70 -0
  91. package/dist/agents/skills/gemini-cli/knowledge-craft/SKILL.md +180 -0
  92. package/dist/agents/skills/gemini-cli/knowledge-craft/skill.yaml +49 -0
  93. package/dist/agents/skills/gemini-cli/naming-craft/SKILL.md +172 -0
  94. package/dist/agents/skills/gemini-cli/naming-craft/skill.yaml +51 -0
  95. package/dist/agents/skills/gemini-cli/security-craft/SKILL.md +205 -0
  96. package/dist/agents/skills/gemini-cli/security-craft/skill.yaml +58 -0
  97. package/dist/agents/skills/gemini-cli/spec-craft/SKILL.md +184 -0
  98. package/dist/agents/skills/gemini-cli/spec-craft/skill.yaml +55 -0
  99. package/dist/agents/skills/gemini-cli/test-craft/SKILL.md +212 -0
  100. package/dist/agents/skills/gemini-cli/test-craft/skill.yaml +58 -0
  101. package/dist/{agents-md-2JUQ4FE2.js → agents-md-267R2NUJ.js} +4 -4
  102. package/dist/{analyzer-VY6DJVOU-4AHIJLNS.js → analyzer-VY6DJVOU-WYKV3TTW.js} +2 -2
  103. package/dist/{architecture-CXAVNB5X.js → architecture-ZTEHGIHD.js} +6 -6
  104. package/dist/{assess-project-M626SSPN.js → assess-project-OKDW3YSK.js} +2 -1
  105. package/dist/bin/harness-mcp.js +17 -17
  106. package/dist/bin/harness.js +27 -27
  107. package/dist/{check-phase-gate-XMU6LLUQ.js → check-phase-gate-YJWFDW66.js} +5 -5
  108. package/dist/{chunk-ORNMAYHB.js → chunk-4EGPFB7V.js} +6196 -125
  109. package/dist/{chunk-HFOB2MPQ.js → chunk-67RP7MLR.js} +3 -3
  110. package/dist/{chunk-5JNSFYZU.js → chunk-6T5AYG5S.js} +6 -6
  111. package/dist/{chunk-5XLLIYYL.js → chunk-6UHDQP2N.js} +1 -1
  112. package/dist/{chunk-YP7I25SL.js → chunk-B3B64OPD.js} +1 -1
  113. package/dist/{chunk-VTTNIZJL.js → chunk-B4OLYXZ4.js} +93 -3
  114. package/dist/{chunk-6AX6R3LM.js → chunk-CXAHK5PJ.js} +9 -9
  115. package/dist/{chunk-BCFDGOMA.js → chunk-H2ZJOJ7A.js} +81 -1
  116. package/dist/{chunk-NX6A24DS.js → chunk-HLPY3RHE.js} +1641 -292
  117. package/dist/{chunk-Q6ZR2L6Q.js → chunk-HMMSWRWR.js} +2 -2
  118. package/dist/{chunk-YYRQCQPZ.js → chunk-IY2TZLY5.js} +176 -107
  119. package/dist/{chunk-I6K43QQS.js → chunk-MQG7FHXX.js} +3 -3
  120. package/dist/{chunk-43M3RLFQ.js → chunk-OLTVDPA2.js} +2 -2
  121. package/dist/{chunk-JFZOWO7D.js → chunk-OQE6ME2Z.js} +1 -1
  122. package/dist/{chunk-GWE5LL3R.js → chunk-P7EO7USC.js} +10 -10
  123. package/dist/{chunk-24KCOJJG.js → chunk-PARV3G2F.js} +1 -1
  124. package/dist/{chunk-QOKMDDBJ.js → chunk-QUPC37UB.js} +6 -6
  125. package/dist/{chunk-EPUKTTJZ.js → chunk-RC3OI5NK.js} +5 -1
  126. package/dist/{chunk-L5BCZ5XS.js → chunk-S7GEONXL.js} +1 -1
  127. package/dist/{chunk-5FDBXUFW.js → chunk-TIH53QXY.js} +1 -1
  128. package/dist/{chunk-OA6SWTU4.js → chunk-TIZ3L6CU.js} +11 -8
  129. package/dist/{chunk-GWF2OILZ.js → chunk-VG6UK6G6.js} +1 -1
  130. package/dist/{chunk-SZEFU6XC.js → chunk-W3PDVZ4I.js} +1 -1
  131. package/dist/{chunk-HYTRDAHV.js → chunk-WOXR6I3R.js} +3 -1
  132. package/dist/{chunk-K246XQ2L.js → chunk-XTIPZUPR.js} +1 -1
  133. package/dist/{chunk-HMW3VKUF.js → chunk-Z2GUITAS.js} +10 -10
  134. package/dist/{chunk-PFZEADQM.js → chunk-ZKA3TGYS.js} +79 -2
  135. package/dist/{ci-workflow-3JNDZQYD.js → ci-workflow-YGTQTNVC.js} +4 -4
  136. package/dist/{dist-QPWXPCPL.js → dist-R3TOOPJ7.js} +1 -1
  137. package/dist/{dist-OHDQBTSO.js → dist-XIJWWQ5N.js} +3 -3
  138. package/dist/{docs-5RYMDHN3.js → docs-KCTLXK2G.js} +6 -6
  139. package/dist/{engine-KZ3PPUYE.js → engine-J64WPH5K.js} +4 -4
  140. package/dist/{entropy-DQTAPSSE.js → entropy-M27JUL3V.js} +5 -5
  141. package/dist/{feedback-WH6XPQJS.js → feedback-W25QO3OL.js} +2 -2
  142. package/dist/{generate-agent-definitions-SZA4QIHN.js → generate-agent-definitions-RNMU5U5R.js} +5 -5
  143. package/dist/{glob-helper-XE2UGEOV.js → glob-helper-EX4YZKZO.js} +1 -1
  144. package/dist/{graph-loader-EQBOIHFZ.js → graph-loader-EIFEOUVI.js} +1 -1
  145. package/dist/index.d.ts +587 -6
  146. package/dist/index.js +27 -27
  147. package/dist/{loader-BNKGM23C.js → loader-HZKJ5ABV.js} +4 -4
  148. package/dist/{mcp-GZH4EYGD.js → mcp-NEAPIDTT.js} +17 -17
  149. package/dist/{performance-54TMJOEU.js → performance-3AVQUDRG.js} +6 -6
  150. package/dist/{review-pipeline-OTDDVPNY.js → review-pipeline-KA7SGUXJ.js} +4 -4
  151. package/dist/{runtime-W5THSNAL.js → runtime-IP6FVV5M.js} +4 -4
  152. package/dist/{scan-4PPP6ZXT.js → scan-LYKLM4EQ.js} +1 -1
  153. package/dist/{security-27HW7CYT.js → security-EAR4FJWI.js} +1 -1
  154. package/dist/{validate-QRVCD4GP.js → validate-EVH3UXIC.js} +5 -5
  155. package/dist/{validate-cross-check-BUAGBAPO.js → validate-cross-check-SNE3SQOB.js} +4 -4
  156. package/package.json +8 -7
@@ -0,0 +1,174 @@
1
+ # Align Design System
2
+
3
+ > Apply codemods for safe DRIFT-T001/T002/T003 token-bypass findings (replace hex / font-family / px-spacing literals with token references) and emit precise suggestions for DRIFT-T004 (deprecated tokens) and all DRIFT-P\* (primitive adoption). The FIX half of design-pipeline sub-project #1, paired with detect-design-drift.
4
+
5
+ ## When to Use
6
+
7
+ - After detect-design-drift reports DRIFT-T001/T002/T003 findings — align replaces literals with token references where the fix is unambiguous
8
+ - Before a PR that touches UI code lands — pair with detect-design-drift to surface AND fix drift in one shot
9
+ - Inside a (future) #5 design-pipeline orchestrator's convergence loop — align is the FIX step the loop runs between DETECT and VERIFY
10
+ - When you want to dry-run the fixes first (`--dry-run`) and review the diff before writing
11
+ - NOT for primitive-adoption codemods — v1 emits suggestions only for DRIFT-P\*; the prop-translation work lives in v1.x
12
+ - NOT for adding new tokens to tokens.json (no auto-add of palette entries; that's a separate intentional act)
13
+ - NOT for non-design-system fixes (use cleanup-dead-code, align-documentation, etc. for their respective domains)
14
+
15
+ ## Process
16
+
17
+ ### Phase 1: GATHER — Load drift findings
18
+
19
+ 1. **Read project configuration.** Check `harness.config.json` for:
20
+ - `design.strictness` — passes through to detect-design-drift
21
+ - `design.audit.driftDetection.*` — passes through to detect
22
+
23
+ 2. **In standalone mode (default):** invoke `detect-design-drift` internally with the same project root + strictness; receive the full `DriftFinding[]`.
24
+
25
+ 3. **In pipeline mode:** read `.harness/handoff.json` and pull `pipeline.driftFindings` (pre-classified by the orchestrator). Honor `pipeline.fixBatch` if present to limit application to a specific subset of findings (the orchestrator may apply fixes in batches across iterations).
26
+
27
+ ### Phase 2: CLASSIFY — Pre-flight safe-codemod vs suggestion
28
+
29
+ For each finding, the pre-flight classifier inspects file context and chooses:
30
+
31
+ - **DRIFT-T001 (hex)** — safe-codemod iff token import already present in the file AND hex is in single string-literal context (not a template literal or concatenation) AND exactly one palette token matches by value. Otherwise → suggestion.
32
+ - **DRIFT-T002 (font-family)** — same shape as T001 against the typography palette.
33
+ - **DRIFT-T003 (px spacing)** — safe-codemod iff token import present AND px matches a spacing token's `$value` EXACTLY (no rounding) AND not in an arithmetic expression. Otherwise → suggestion.
34
+ - **DRIFT-T004 (deprecated)** — always suggestion in v1. Migration target may not be in the token's `$description`.
35
+ - **DRIFT-P\* (primitive adoption)** — always suggestion in v1. Prop translation across `<button>` ⇄ `<Button>` is genuinely ambiguous (event handlers, ref forwarding, class merging) — codemods deferred to v1.x.
36
+
37
+ Token import discovery recognizes three forms:
38
+
39
+ - ES named: `import { tokens } from '...'`
40
+ - ES default: `import tokens from '...'`
41
+ - CJS: `const tokens = require('...')`
42
+
43
+ ### Phase 3: APPLY — Codemod or emit suggestion
44
+
45
+ For each finding classified as `safe-codemod`:
46
+
47
+ 1. Read the source file (cached per-run to avoid re-reads when multiple findings hit the same file).
48
+ 2. Locate the exact match position from the finding's `line` + `evidence.snippet`.
49
+ 3. Compute the replacement using file-extension-aware syntax:
50
+ - `.ts` / `.tsx` / `.js` / `.jsx` → `tokens.<dotted.path>`
51
+ - `.css` / `.scss` → `var(--<dotted-path-as-kebab>)`
52
+ 4. Replace in-place. Emit `FixOutcome.applied` with a structured diff (file / line / before / after).
53
+ 5. If `--dry-run`: compute the diff but DO NOT write to disk.
54
+ 6. If the file changed between detect-time and apply-time: skip with `kind: 'skipped-unsafe', reason: 'file changed since finding'`.
55
+
56
+ For each finding classified as `suggestion`: emit a human-readable description plus a preview of the suggested change. No file mutation.
57
+
58
+ ### Phase 4: REPORT — Aggregate + (pipeline-mode) handoff writeback
59
+
60
+ 1. Aggregate `FixOutcome[]` into a summary: counts by kind (applied / suggestion / skipped / failed) plus files modified and duration.
61
+ 2. Build a `catalog` of finding codes that produced codemods and codes that produced suggestions.
62
+ 3. In pipeline mode: write `pipeline.fixesApplied: FixOutcome[]` back to `.harness/handoff.json` so the orchestrator can re-verify only the affected findings on the next loop iteration.
63
+
64
+ ## Harness Integration
65
+
66
+ - **`harness align-design-system`** — the CLI entry point. `--dry-run` for preview; `--write` is the default. Standard `--json` / `--verbose` / `--quiet` flags.
67
+ - **`harness align-design-system --mode pipeline`** — orchestrator-driven mode. Reads pre-classified findings from handoff.json; writes outcomes back.
68
+ - **`mcp__harness__align_design_system`** — MCP tool for agent consumption. Same input/output shape as the function call.
69
+ - **`detect-design-drift`** — soft dependency. Standalone mode invokes detect internally; pipeline mode trusts the orchestrator to have done it.
70
+ - **`harness check-design`** — composes detect (as 3rd verifier) into a single-pass design check. align is the matching FIX step; together they form the DETECT → FIX cycle that the (future) #5 orchestrator will loop.
71
+ - **`DesignConstraintAdapter`** — align does NOT write to the graph. The graph already tracks `VIOLATES_design` edges (the findings). Re-running detect after align shows the delta — no separate fix-edge needed.
72
+
73
+ ## Success Criteria
74
+
75
+ See `docs/changes/design-pipeline/align-design-system/proposal.md` for the full 34 success criteria. Highlights:
76
+
77
+ - T001/T002/T003 codemods write to disk only when pre-flight classifier returns `safe-codemod`
78
+ - Codemods are idempotent — running twice produces zero additional changes on the second run
79
+ - Classifier downgrades to suggestion when token import is missing, when value appears in template/concatenation, or when multiple tokens share the value
80
+ - Classifier ALWAYS returns suggestion for T004 + all P\* findings (no source inspection)
81
+ - Pipeline mode reads `pipeline.driftFindings` from handoff.json; standalone mode runs detect internally
82
+ - Pipeline mode writes `pipeline.fixesApplied` back to handoff.json
83
+ - `--dry-run` produces identical `FixOutcome` shapes but never writes files
84
+ - Re-running detect after align produces strictly fewer T001/T002/T003 findings
85
+
86
+ ## Examples
87
+
88
+ ### Example: Apply a T001 codemod (hex → token reference)
89
+
90
+ **Input:**
91
+
92
+ `design-system/tokens.json` has:
93
+
94
+ ```json
95
+ { "color": { "brand": { "primary": { "$type": "color", "$value": "#0066cc" } } } }
96
+ ```
97
+
98
+ `src/Card.tsx` has:
99
+
100
+ ```ts
101
+ import { tokens } from '@/design-system/tokens';
102
+ const styles = { color: '#0066cc' }; // raw literal where token exists
103
+ ```
104
+
105
+ **Output:**
106
+
107
+ ```
108
+ src/Card.tsx
109
+ ✓ DRIFT-T001:2 — Hex color "#0066cc" should use a token reference instead of a raw literal
110
+ before: const styles = { color: "#0066cc" };
111
+ after: const styles = { color: tokens.color.brand.primary };
112
+
113
+ Summary: 1 applied, 0 suggestions, 0 skipped, 0 failed (1 files modified, 5ms)
114
+ ```
115
+
116
+ ### Example: Downgrade to suggestion (no token import)
117
+
118
+ Same finding as above, but `src/Card.tsx` does NOT import tokens. align emits a suggestion instead:
119
+
120
+ ```
121
+ src/Card.tsx
122
+ ? DRIFT-T001:2 — Hex color "#0066cc" should use a token reference instead of a raw literal
123
+
124
+ Summary: 0 applied, 1 suggestions, 0 skipped, 0 failed (0 files modified, 3ms)
125
+ ```
126
+
127
+ (Run with `--verbose` to see the suggestion text and the classifier's reason for downgrading.)
128
+
129
+ ### Example: Suggestion-only for DRIFT-P001
130
+
131
+ **Input:**
132
+
133
+ `design-system/DESIGN.md` registers `Button` in `## Component Registry`. `src/SaveButton.tsx` has:
134
+
135
+ ```tsx
136
+ export const S = () => <button onClick={() => save()}>Save</button>;
137
+ ```
138
+
139
+ **Output:**
140
+
141
+ ```
142
+ src/SaveButton.tsx
143
+ ? DRIFT-P001:1 — Raw <button> element where the registered component "Button" should be used
144
+
145
+ (use --verbose to see prop-translation suggestion)
146
+ ```
147
+
148
+ v1 never auto-applies primitive adoption — prop translation across `<button>` ⇄ `<Button>` is the kind of judgment-call that benefits from a human or LLM review.
149
+
150
+ ## Gates
151
+
152
+ - **No autofix without classifier approval.** Every codemod application goes through `classifyFinding`. If the classifier returns `suggestion`, NO file write occurs — even for the same finding code in the same file.
153
+ - **No autofix when token import is missing.** Adding the import line is its own ambiguity surface (alias? barrel? relative?). v1 skips with a suggestion.
154
+ - **No autofix for non-exact px matches.** "Round 13px to the nearest 16px" is a design decision the tool shouldn't make.
155
+ - **No autofix for primitive adoption.** v1 has no codemod for DRIFT-P\* — always suggestions.
156
+ - **No autofix in pipeline mode unless a `pipeline.driftFindings` field is present.** Empty handoff = empty run.
157
+ - **No graph writes.** align modifies source files; the graph is read-only from align's perspective.
158
+
159
+ ## Escalation
160
+
161
+ - **When a T001 finding has multiple matching tokens (ambiguous):** the classifier downgrades to suggestion. To resolve, declare a primary token in DESIGN.md `## Token Primary Resolution Overrides` (v1.x), OR pick one in the source manually and re-run.
162
+ - **When the codemod corrupts a file (rare):** every application includes a structured diff. Recover via `git checkout <file>`. If the same input repeatedly corrupts, report the case — pre-flight classifier rules are conservative by design.
163
+ - **When pipeline-mode run finds no `pipeline.driftFindings` field:** align exits cleanly with empty outcomes. The orchestrator's contract is to write the field BEFORE invoking align.
164
+ - **When `--dry-run` shows fixes you don't want applied:** scope with `--files <glob>` to apply only specific files, or invoke align in pipeline mode with a curated `pipeline.fixBatch` list.
165
+ - **When you want primitive-adoption fixes today:** apply the suggestion manually. The v1.x sub-project will add prop-translation tables + import resolution + revert-on-test-fail.
166
+ - **When align is invoked without detect having run first (standalone mode):** standalone mode runs detect internally — no manual ordering needed. Pipeline mode trusts the orchestrator to populate findings.
167
+
168
+ ## Status
169
+
170
+ **v1 — in implementation.** See:
171
+
172
+ - Spec: `docs/changes/design-pipeline/align-design-system/proposal.md`
173
+ - Roadmap entry: `design-pipeline sub-project #1` (align half) in `docs/roadmap.md`
174
+ - Sibling: `detect-design-drift` (detect half — shipped PR #396)
@@ -0,0 +1,57 @@
1
+ name: align-design-system
2
+ version: "0.1.0"
3
+ description: Apply codemods for safe DRIFT-T001/T002/T003 token-bypass findings; emit precise suggestions for DRIFT-T004 (deprecated tokens) and all DRIFT-P* (primitive adoption). FIX half of design-pipeline sub-project #1; pairs with detect-design-drift.
4
+ stability: draft
5
+ cognitive_mode: constructive-architect
6
+ triggers:
7
+ - manual
8
+ - on_pr
9
+ - on_new_feature
10
+ platforms:
11
+ - claude-code
12
+ tools:
13
+ - Bash
14
+ - Read
15
+ - Write
16
+ - Edit
17
+ - Glob
18
+ - Grep
19
+ cli:
20
+ command: harness align-design-system
21
+ args:
22
+ - name: path
23
+ description: Project root path
24
+ required: false
25
+ - name: dry-run
26
+ description: Compute diffs without writing files
27
+ required: false
28
+ - name: files
29
+ description: Optional file/glob scope (standalone mode only)
30
+ required: false
31
+ - name: mode
32
+ description: standalone (default) or pipeline (read findings from handoff.json)
33
+ required: false
34
+ mcp:
35
+ tool: run_skill
36
+ input:
37
+ skill: align-design-system
38
+ path: string
39
+ type: rigid
40
+ tier: 2
41
+ phases:
42
+ - name: gather
43
+ description: Load drift findings (run detect-design-drift in standalone mode; read pipeline.driftFindings in pipeline mode)
44
+ required: true
45
+ - name: classify
46
+ description: Per-finding pre-flight check decides safe-codemod vs suggestion
47
+ required: true
48
+ - name: apply
49
+ description: Write codemods for safe T001/T002/T003; emit suggestions for everything else
50
+ required: true
51
+ - name: report
52
+ description: Emit FixOutcome[] + aggregate summary; write pipeline.fixesApplied in pipeline mode
53
+ required: true
54
+ state:
55
+ persistent: false
56
+ depends_on:
57
+ - detect-design-drift
@@ -0,0 +1,189 @@
1
+ # Audit Brand Compliance
2
+
3
+ > Rule-based brand-semantics audit. Detects (a) tokens used in forbidden contexts per their `$extensions.harness.brand.forbidden_contexts` metadata (BRAND-T001) and (b) UI copy containing phrases listed in `DESIGN.md ## Brand Rules → voice.forbidden_phrases` (BRAND-V001). The 4th composed verifier in `harness check-design`, alongside audit-component-anatomy, design-craft critique, and detect-design-drift.
4
+
5
+ ## When to Use
6
+
7
+ - After authoring or editing `DESIGN.md ## Brand Rules` — verify the new constraints are enforceable on the existing codebase
8
+ - After adding `$extensions.harness.brand` metadata to a token — discover existing call sites in forbidden contexts
9
+ - As part of `harness validate` (fast-mode hook, gated by `design.audit.brandCompliance.enabled`)
10
+ - As the 4th composed verifier in `harness check-design` (the unified design check)
11
+ - Before a PR with UI copy or token-usage changes lands
12
+ - NOT for tone-by-context rules (deferred to v1.x — requires component-state inference)
13
+ - NOT for reading-level or sentence-length rules (deferred to v1.x — ship with tone-context)
14
+ - NOT for asset-usage rules (deferred to v1.x — requires image-tag scanning)
15
+ - NOT for semantic-token-alias enforcement (overlaps with detect-design-drift T001 — design after both have shipped)
16
+ - NOT for brand-rule authoring (use `harness-design` skill to draft DESIGN.md sections)
17
+
18
+ ## Process
19
+
20
+ ### Phase 1: LOAD — Parse the two input sources
21
+
22
+ 1. **Read project configuration.** Check `harness.config.json` for:
23
+ - `design.strictness` — `strict` / `standard` / `permissive` (default `standard`)
24
+ - `design.audit.brandCompliance.enabled` — gate (default `true`)
25
+ - `design.audit.brandCompliance.rules.{tokenMisuse,voice}` — per-rule toggles
26
+
27
+ 2. **Load `design-system/DESIGN.md` `## Brand Rules`.** The parser extracts:
28
+ - `voice.forbiddenPhrases: string[]` — used by BRAND-V001 in v1
29
+ - `voice.constant`, `voice.readingLevel`, `voice.maxSentenceWords` — parsed but unused in v1 (forward-compat)
30
+ - `toneByContext`, `assets`, `semanticTokenAliases` — parsed but unused (v1.x)
31
+ - Returns `null` when DESIGN.md absent or `## Brand Rules` section missing → BRAND-V001 silently skips.
32
+
33
+ 3. **Load `design-system/tokens.json` `$extensions.harness.brand`.** Walks the DTCG token tree capturing per-token `role`, `approved_contexts`, `forbidden_contexts`. Returns `null` when no token carries the extension → BRAND-T\* silently skips.
34
+
35
+ ### Phase 2: SCAN — Apply the two rule families
36
+
37
+ 1. **BRAND-T001 — token misuse (regex-based).** For each token whose `forbidden_contexts` is non-empty:
38
+ - Find every reference to the token's dotted path in source (recognizes three forms):
39
+ - `tokens.X.Y.Z` (JS accessor)
40
+ - `var(--X-Y-Z)` (CSS var, kebab-cased)
41
+ - `'X.Y.Z'` / `"X.Y.Z"` (string literal)
42
+ - Inspect surrounding context (same line + nearest non-blank previous and next line) for the v1 context-vocabulary keywords: `cta`, `selection`, `focus`, `data-visualization`, `decorative`, `background`, `text`, `border`, `error`, `success`, `warning`.
43
+ - If a forbidden context matches: emit BRAND-T001.
44
+
45
+ 2. **BRAND-V001 — forbidden phrases (TS Compiler API).** For each `.tsx`/`.jsx` file:
46
+ - Walk the JSX tree.
47
+ - For each `JsxText` node: case-insensitive substring scan for any forbiddenPhrase.
48
+ - For each `JsxAttribute` whose initializer is a string literal: same scan.
49
+ - Deduplicate per `(file, line, phrase)`.
50
+
51
+ ### Phase 3: REPORT — Aggregate and surface
52
+
53
+ 1. **Severity from `design.strictness`** (uses `severityFor`):
54
+ - `strict` — all findings `error`
55
+ - `standard` — BRAND-T001 `error` (declared violation), BRAND-V001 `warn` (copy nuance)
56
+ - `permissive` — all findings `info`
57
+
58
+ 2. **Aggregate `bySeverity` and `byCode`** into the standard Verifier shape: `{ findings, summary, catalog, meta }`.
59
+
60
+ 3. **Persist findings to the graph (when composed by check-design).** check-design routes brand findings through `DesignConstraintAdapter.recordFindings()` alongside anatomy / craft / drift. v1 uses the shared `VIOLATES_design` edge; v1.x may add a brand-specific edge.
61
+
62
+ ## Harness Integration
63
+
64
+ - **`harness validate`** — Fast-mode hook gated by `design.audit.brandCompliance.enabled`. Degrades gracefully on failure (single warning; other checks continue).
65
+ - **`harness check-design`** — Composes brand as the 4th verifier alongside audit-anatomy, design-craft critique, and detect-design-drift. This is the canonical invocation path.
66
+ - **`mcp__harness__audit_brand`** — MCP tool. Input: `{ path, mode, files?, designStrictness?, rules? }`. Output: `{ findings, summary, catalog, meta }`. Consumed by check-design and the (future) #5 design-pipeline orchestrator.
67
+ - **`DesignConstraintAdapter.recordFindings()`** — Generic graph persistence entry point shipped in PR #390. Brand findings reuse the adapter (no graph schema changes in v1).
68
+ - **`harness-design` skill** — Authors `DESIGN.md ## Brand Rules`. audit-brand-compliance is the matching enforcer.
69
+ - **`Verifier<F>` interface** — Extracted in this PR at the 4th-verifier threshold. Lives at `packages/cli/src/shared/verifier.ts`. Adding a 5th verifier requires only a type-alias declaration of conformance.
70
+
71
+ ## Success Criteria
72
+
73
+ See `docs/changes/design-pipeline/audit-brand-compliance/proposal.md` for the full 34 success criteria. Highlights:
74
+
75
+ - DESIGN.md parser returns `null` when section absent (silent-skip pattern)
76
+ - Token-extensions walker returns `null` when no token carries `$extensions.harness.brand`
77
+ - BRAND-T001 fires on `tokens.X`, `var(--x)`, and `'X'` reference forms
78
+ - BRAND-T001 honors approved_contexts (no finding when context is allowed)
79
+ - BRAND-V001 fires on JSX text + string-typed JSX attributes (case-insensitive)
80
+ - BRAND-V001 deduplicates per `(file, line, phrase)`
81
+ - Verifier interface extraction: anatomy / drift / brand all declare structural conformance
82
+ - `harness check-design` test extended for 4-verifier composition (zero regressions)
83
+ - MCP tool count bumps 72 → 73
84
+
85
+ ## Examples
86
+
87
+ ### Example: Token used in forbidden context
88
+
89
+ **Input:**
90
+
91
+ `design-system/tokens.json`:
92
+
93
+ ```json
94
+ {
95
+ "color": {
96
+ "brand": {
97
+ "500": {
98
+ "$type": "color",
99
+ "$value": "#3b82f6",
100
+ "$extensions": {
101
+ "harness": {
102
+ "brand": {
103
+ "role": "primary",
104
+ "approved_contexts": ["cta", "selection", "focus"],
105
+ "forbidden_contexts": ["data-visualization", "decorative"]
106
+ }
107
+ }
108
+ }
109
+ }
110
+ }
111
+ }
112
+ }
113
+ ```
114
+
115
+ `src/Chart.tsx`:
116
+
117
+ ```tsx
118
+ // data-visualization color palette
119
+ const palette = [tokens.color.brand.500, ...];
120
+ ```
121
+
122
+ **Output:**
123
+
124
+ ```
125
+ BRAND-T001 [error] src/Chart.tsx:2 — Token "color.brand.500" is used in forbidden context "data-visualization"
126
+ Fix: Token "color.brand.500" is not approved for the "data-visualization" context.
127
+ Use an approved token (allowed contexts: cta, selection, focus), or update
128
+ tokens.json $extensions.harness.brand if the policy is wrong.
129
+ ```
130
+
131
+ ### Example: Forbidden phrase in UI copy
132
+
133
+ **Input:**
134
+
135
+ `DESIGN.md`:
136
+
137
+ ```markdown
138
+ ## Brand Rules
139
+
140
+ ### Voice
141
+
142
+ forbidden_phrases:
143
+
144
+ - "click here"
145
+ - "best-in-class"
146
+ ```
147
+
148
+ `src/Cta.tsx`:
149
+
150
+ ```tsx
151
+ export const Cta = () => <a href="/x">Click here</a>;
152
+ ```
153
+
154
+ **Output:**
155
+
156
+ ```
157
+ BRAND-V001 [warn] src/Cta.tsx:1 — UI copy contains forbidden phrase "click here" — declared at DESIGN.md ## Brand Rules → Voice → forbidden_phrases
158
+ Fix: Rewrite to avoid "click here". If the phrase is unavoidable for this context,
159
+ remove it from voice.forbidden_phrases (or scope the audit) — but the default
160
+ policy is that brand voice trumps convenience.
161
+ ```
162
+
163
+ ## Gates
164
+
165
+ - **No findings without parsed inputs.** DESIGN.md absent → BRAND-V001 skips silently. tokens.json `$extensions.harness.brand` absent on every token → BRAND-T001 skips silently. Either resolver returning null is NOT a verifier failure.
166
+ - **No `.ts`/`.js` file scans for BRAND-V001.** Only `.jsx`/`.tsx` (user-visible JSX). Doc copy in `.md` is a different audience.
167
+ - **No tone-by-context inference.** v1 only matches the explicit context-vocabulary keywords against surrounding source text. v1.x adds component-state inference.
168
+ - **No autofix.** audit-only. The matching `align-brand-compliance` fix-side skill is deferred until detect signals demand.
169
+ - **No graph schema changes.** v1 reuses `VIOLATES_design` via `recordFindings()`. v1.x may add `VIOLATES_brand` edge for queryability.
170
+ - **Strictness from config, not assumed.** Read `design.strictness` from `harness.config.json`; default `standard` if absent.
171
+
172
+ ## Escalation
173
+
174
+ - **When BRAND-T001 false-positives on a far-context reference:** the v1 context inference is intentionally narrow (same line + adjacent non-blank). For a token used in a "background" context where the keyword appears 10 lines away, v1 misses it. v1.x adds richer context inference; for now, either widen the surrounding comment or accept the miss.
175
+ - **When BRAND-V001 false-positives on a substring (e.g., "as is" in "as issued"):** v1 uses substring match. Add word-boundary regex in v1.x. For now, rephrase the copy or remove the phrase from voice.forbidden_phrases.
176
+ - **When a project ships tokens with a different `$extensions` shape:** v1 reads only `harness.brand`. Document the actual shape your project uses and add it to the schema sketch in ADR 0028 — DTCG `$extensions` namespaces are vendor-prefixed and additions are forward-compatible.
177
+ - **When `harness validate` runtime exceeds 3 seconds:** Set `design.audit.brandCompliance.fastMode.maxFiles` to cap the scope. The MCP tool ignores the cap (`fast`/`full` equivalent in v1).
178
+ - **When the graph persistence fails:** Skip graph integration for that run; findings still appear in the report. The graph is a consumer, not a gate.
179
+ - **When you want tone-by-context rules today:** Manual audit until v1.x ships. Component-state inference (empty/error/success/loading) requires JSX-context analysis that's a separate brainstorm.
180
+
181
+ ## Status
182
+
183
+ **v1 — in implementation.** See:
184
+
185
+ - Spec: `docs/changes/design-pipeline/audit-brand-compliance/proposal.md`
186
+ - ADR (input schema source): `docs/knowledge/decisions/0028-brand-guidelines-source-of-truth.md`
187
+ - Roadmap entry: `design-pipeline sub-project #3` in `docs/roadmap.md`
188
+ - Sibling rule-based audits: `audit-component-anatomy` (#2), `detect-design-drift` (#1)
189
+ - Cross-cutting: extracts `Verifier<F>` interface at `packages/cli/src/shared/verifier.ts` (deferred until 4th data point — this is it)
@@ -0,0 +1,50 @@
1
+ name: audit-brand-compliance
2
+ version: "0.1.0"
3
+ description: Rule-based brand-semantics audit. Detects token misuse (BRAND-T001 via $extensions.harness.brand.forbidden_contexts) and voice violations (BRAND-V001 via DESIGN.md voice.forbidden_phrases). 4th composed verifier in harness check-design. Triggers extraction of the formal verifier interface.
4
+ stability: draft
5
+ cognitive_mode: constructive-architect
6
+ triggers:
7
+ - manual
8
+ - on_pr
9
+ - on_new_feature
10
+ platforms:
11
+ - claude-code
12
+ tools:
13
+ - Bash
14
+ - Read
15
+ - Glob
16
+ - Grep
17
+ cli:
18
+ command: harness skill run audit-brand-compliance
19
+ args:
20
+ - name: path
21
+ description: Project root path
22
+ required: false
23
+ - name: mode
24
+ description: "fast or full (equivalent in v1)"
25
+ required: false
26
+ - name: files
27
+ description: Optional list of files to scope the scan
28
+ required: false
29
+ mcp:
30
+ tool: run_skill
31
+ input:
32
+ skill: audit-brand-compliance
33
+ path: string
34
+ type: rigid
35
+ tier: 2
36
+ phases:
37
+ - name: load
38
+ description: Parse DESIGN.md ## Brand Rules and tokens.json $extensions.harness.brand
39
+ required: true
40
+ - name: scan
41
+ description: Walk JSX text/attributes for forbidden phrases; scan source for token-misuse-in-context
42
+ required: true
43
+ - name: report
44
+ description: Aggregate findings; emit BRAND-T* / BRAND-V001 with severity per design.strictness
45
+ required: true
46
+ state:
47
+ persistent: false
48
+ depends_on:
49
+ - detect-design-drift
50
+ - harness-design
@@ -0,0 +1,181 @@
1
+ # Audit Component Anatomy
2
+
3
+ > Detect missing required anatomy parts in component definitions and missing-anatomy-component patterns in composition. First programmatic enforcer of component-anatomy rules — finds what design-component-anatomy reference content prescribes.
4
+
5
+ ## When to Use
6
+
7
+ - Reviewing component-library code for completeness of slots, states, sizes
8
+ - Detecting compositional patterns where a needed anatomy component is missing (e.g., `.map()` over data with no empty branch; async actions with no loading boundary)
9
+ - After component-library changes to verify anatomy contracts still hold
10
+ - Before merging UI changes to catch anatomy regressions
11
+ - When `on_new_feature` triggers fire and the feature touches a component definition or usage
12
+ - NOT for token validation (use harness-design-system)
13
+ - NOT for accessibility compliance (use harness-accessibility — overlap is documented; this skill defers label-association findings to a11y)
14
+ - NOT for aesthetic critique or polish suggestions (use harness-design-craft)
15
+ - NOT for declared-anti-pattern enforcement (use harness-design)
16
+
17
+ ## Process
18
+
19
+ ### Phase 1: SCAN — Identify component types and run audits
20
+
21
+ 1. **Read project configuration.** Check `harness.config.json` for:
22
+ - `design.strictness` — `strict`/`standard`/`permissive` (default `standard`)
23
+ - `design.audit.componentAnatomy.enabled` — gate for the entire audit AND the harness-accessibility deferral (default `true`)
24
+ - `design.audit.componentAnatomy.catalog` — `"default"` or path to project-supplied catalog
25
+ - `design.audit.componentAnatomy.patterns` — `"all"`, `"none"`, or explicit list of pattern codes
26
+ - `design.audit.componentAnatomy.fastMode.{patterns,maxFiles}` — fast-mode controls
27
+
28
+ 2. **Load source-of-truth catalogs (resolution order, most specific wins):**
29
+ - Component author's JSDoc `@component-type X` + `@anatomy-slot ...` etc. — file-level self-declaration
30
+ - `design-system/DESIGN.md` `## Component Registry` + `## Component Anatomy Overrides` — project-level
31
+ - Built-in convention library (20 component types: Button, Input, Select, Modal/Dialog, EmptyState, Card, Tabs, Menu, Toast, Form, Accordion, Tooltip, Popover, Drawer, Slider, Switch, Checkbox, Radio, Avatar, Badge) — fallback default
32
+ - No match for a file's component-type → silent skip (no false positives)
33
+
34
+ 3. **Identify component type per file** using the same resolution order:
35
+ - JSDoc `@component-type X` tag → file IS X
36
+ - DESIGN.md Component Registry mapping → use that
37
+ - Top-level export name matches a catalog entry → use that
38
+ - No match → skip silently
39
+
40
+ 4. **Run convention audit (definition findings, `ANAT-D*` codes).** For each catalogued component file:
41
+ - Parse component definition via TypeScript Compiler API (AST)
42
+ - Extract exported component's prop type / interface
43
+ - Check that each required anatomy part (slot, state, variant, size) is exposed as a prop or sub-component
44
+ - Emit `ANAT-D{NNN}` finding for each missing required part
45
+ - Emit `ANAT-D000` info finding when JSDoc declaration diverges from catalog convention
46
+
47
+ 5. **Run pattern audit (pattern-presence findings, `ANAT-P*` codes).** For each file matching pattern targets:
48
+ - Parse via tree-sitter (`tree-sitter-typescript` + `tree-sitter-tsx`)
49
+ - Run each enabled pattern's S-expression query
50
+ - Post-process captures to confirm pattern presence (e.g., `.map()` without an empty-branch guard)
51
+ - Emit `ANAT-P{NNN}` finding for each match
52
+ - Skip patterns NOT enabled in `design.audit.componentAnatomy.patterns`
53
+
54
+ 6. **Check for harness-accessibility overlap deferral.** When `design.audit.componentAnatomy.enabled = true`, this skill OWNS label-slot definition findings; harness-accessibility defers A11Y-010 and A11Y-050 for catalogued components. Track deferrals in `meta.deferralsToHarnessDesign` count.
55
+
56
+ ### Phase 2: EVALUATE — Apply severity model
57
+
58
+ 1. **Map finding severity using `design.strictness`:**
59
+ - `strict` — all findings are `error` severity (CI blocks)
60
+ - `standard` — required-part missing → `error`; optional-part missing → `warn`; info findings → `info`
61
+ - `permissive` — all findings → `info` (nothing blocks)
62
+
63
+ 2. **Cross-reference with graph constraints.** If a graph exists at `.harness/graph/`:
64
+ - Query existing `VIOLATES_CRAFT` edges via extended `DesignConstraintAdapter`
65
+ - Identify NEW violations (not in graph) and RESOLVED violations (in graph but not in current scan)
66
+
67
+ 3. **De-duplicate via deferral.** When this skill produces a finding whose root-cause is also tracked by harness-accessibility, prefer this skill's finding (anatomy-level cause) and increment deferrals counter.
68
+
69
+ ### Phase 3: REPORT — Format and persist findings
70
+
71
+ 1. **Write VIOLATES_CRAFT edges to graph.** Each finding becomes:
72
+ - Source: component file (`code_file` node) or component (`component` node)
73
+ - Target: `design_rule` node keyed by finding code (`ANAT-D023`, `ANAT-P001`)
74
+ - Metadata: severity, line, message, evidence snippet, runId
75
+ - Idempotent: re-running the audit produces no duplicate edges
76
+
77
+ 2. **Format the report.** Grouped by component file, with finding codes linked to `docs/changes/design-pipeline/audit-component-anatomy/finding-codes.md`. Each finding includes:
78
+ - Code (e.g., `ANAT-D023`)
79
+ - Severity per `design.strictness`
80
+ - File path + line number
81
+ - Component type (if identified)
82
+ - Message + evidence snippet
83
+ - Fix hint (concrete next-step text — not "fix this")
84
+
85
+ 3. **Emit summary.** Total findings, breakdown by severity, count of `meta.deferralsToHarnessDesign`, mode (`fast`/`full`), `runId`.
86
+
87
+ ## Harness Integration
88
+
89
+ - **`harness validate`** — Fast-mode audit hook (convention catalog only; patterns are opt-in via `fastMode.patterns: true`). Findings respect `design.strictness`.
90
+ - **`mcp__harness__audit_anatomy`** — Programmatic API (input: path, mode, files, designStrictness, catalog; output: findings, summary, catalog applied, deferrals count). Consumed by harness check-design verifier (sub-project #4) and design-pipeline orchestrator (sub-project #5).
91
+ - **`DesignConstraintAdapter`** — Extended to register `ANAT-*` rule code namespace and write VIOLATES_CRAFT edges. Mirrors how harness-accessibility uses it for A11Y-\* codes.
92
+ - **`harness-accessibility`** — Coordinates via i18n-style deferral pattern. When `design.audit.componentAnatomy.enabled = true`, a11y defers A11Y-010 and A11Y-050 for catalogued components.
93
+ - **`design-component-anatomy`** (knowledge skill) — Source of convention vocabulary (slot, variant, state, size, exclusivity, required). This skill's catalog operationalizes that knowledge.
94
+
95
+ ## Success Criteria
96
+
97
+ See `docs/changes/design-pipeline/audit-component-anatomy/proposal.md` for the full 30 success criteria. Highlights:
98
+
99
+ - Convention findings produced for known component types only (silent skip for unknown — zero false positives)
100
+ - JSDoc self-declaration overrides convention; DESIGN.md overrides convention but not JSDoc
101
+ - Pattern false-positive rate ≤ 5% on the 50-fixture corpus
102
+ - harness-accessibility deferral works (one finding for one root cause, not two)
103
+ - Fast-mode runtime ≤ 3s on 500-file repo
104
+
105
+ ## Examples
106
+
107
+ ### Example: Button missing a required state
108
+
109
+ **Input:** `packages/ui/src/Button.tsx` exports a `Button` component whose prop type omits any `loading` prop.
110
+
111
+ **Output:**
112
+
113
+ ```
114
+ ANAT-D002 [error] Button.tsx — Button convention requires state:loading (exclusive)
115
+ File: packages/ui/src/Button.tsx
116
+ Component: Button (identified via export-name match)
117
+ Convention: APG/button + Radix Primitives Button
118
+ Fix: Add a `loading?: boolean` prop, OR add `@anatomy-state loading exclusive`
119
+ JSDoc tag to the component if loading is intentionally omitted.
120
+ ```
121
+
122
+ Severity is `error` under `design.strictness: standard` because the missing part is `required: true` in the Button convention.
123
+
124
+ ### Example: Empty list with no fallback (pattern-presence finding)
125
+
126
+ **Input:** `src/pages/Dashboard.tsx` contains `{items.map(item => <Card item={item} />)}` with no empty-state branch.
127
+
128
+ **Output:**
129
+
130
+ ```
131
+ ANAT-P001 [warn] Dashboard.tsx:42 — map() over data with no empty-state branch
132
+ File: src/pages/Dashboard.tsx:42
133
+ Pattern: ANAT-P001 map-without-empty
134
+ Fix: Wrap the map in a conditional that renders <EmptyState> when items.length === 0:
135
+ items.length === 0 ? <EmptyState ... /> : items.map(...)
136
+ Or extract a guard component that handles both branches.
137
+ ```
138
+
139
+ Severity is `warn` for pattern-presence findings under `design.strictness: standard`; `error` under `strict`.
140
+
141
+ ### Example: Catalogued component with JSDoc divergence
142
+
143
+ **Input:** A Tabs.tsx file has `@anatomy-slot trigger` JSDoc but the convention library says Tabs requires both `trigger` AND `panel`.
144
+
145
+ **Output:**
146
+
147
+ ```
148
+ ANAT-D000 [info] Tabs.tsx — JSDoc declaration omits 2 conventional anatomy parts
149
+ File: packages/ui/src/Tabs.tsx
150
+ Component: Tabs (identified via JSDoc @component-type)
151
+ Divergence: declared slots [trigger]; convention also expects [panel, list]
152
+ Note: JSDoc wins (resolution order #1). This is an info finding to surface
153
+ the divergence — no action required if intentional.
154
+ ```
155
+
156
+ The `ANAT-D000` info code surfaces JSDoc-vs-convention divergence so authors can confirm the divergence is intentional.
157
+
158
+ ## Gates
159
+
160
+ - **No findings without a parsed catalog.** If the convention library or DESIGN.md catalog cannot be loaded, stop with an explanatory error — do not emit speculative findings.
161
+ - **No usage-side findings in v1.** Only `ANAT-D*` (definition) and `ANAT-P*` (pattern) codes. Usage findings (`ANAT-U*`) ship in v2.
162
+ - **No autofix.** Findings include fix-hint text only; source files are never modified by this skill.
163
+ - **Strictness from config, not assumed.** Read `design.strictness` from `harness.config.json`; default to `standard` if absent.
164
+
165
+ ## Escalation
166
+
167
+ - **When a project uses a non-standard component name (e.g., `PrimaryButton` instead of `Button`).** The export-name resolver won't match. Two paths: (1) the component author adds `@component-type Button` JSDoc, or (2) the project adds the file to DESIGN.md `## Component Registry`. Both unblock the audit without touching the catalog.
168
+ - **When the convention catalog is wrong for an opinionated project.** Add a per-component override block to DESIGN.md `## Component Anatomy Overrides`. The override wins for that component type; other catalogued types behave normally.
169
+ - **When pattern-presence findings have a false-positive rate >5% in a particular project.** Disable the specific pattern via `design.audit.componentAnatomy.patterns: ["-ANAT-P003"]` (negated form). Report the false positive — pattern catalog evolves based on real-world signal.
170
+ - **When harness-accessibility produces a finding this skill should own.** Verify `design.audit.componentAnatomy.enabled = true` and the component IS in the catalog. If both, the a11y deferral is misfiring — file an issue; likely a `getCatalogTypes()` cache staleness.
171
+ - **When `harness validate` runtime exceeds 3 seconds.** Set `design.audit.componentAnatomy.fastMode.maxFiles` to cap the scope, OR set `design.audit.componentAnatomy.fastMode.patterns: false` to skip pattern runs in fast mode (patterns are full-mode only by default).
172
+ - **When a graph operation fails.** Skip graph integration for that run; emit findings to the report only. Log a warning that `VIOLATES_CRAFT` edges were not persisted. The audit's findings are still actionable; the graph is a consumer, not a gate.
173
+
174
+ ## Status
175
+
176
+ **v1 — in implementation.** See:
177
+
178
+ - Spec: `docs/changes/design-pipeline/audit-component-anatomy/proposal.md`
179
+ - Plan: `docs/changes/design-pipeline/audit-component-anatomy/plans/2026-05-23-audit-component-anatomy-plan.md`
180
+ - Finding codes: `docs/changes/design-pipeline/audit-component-anatomy/finding-codes.md`
181
+ - Roadmap entry: `design-pipeline sub-project #2` in `docs/roadmap.md`