@3fn/core 13.0.0 → 14.1.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 (284) hide show
  1. package/.kiro/agents/ada-prompt.md +80 -132
  2. package/.kiro/agents/ada-prompt.md.attribution.json +45 -0
  3. package/.kiro/agents/ada.json +44 -59
  4. package/.kiro/agents/ada.json.attribution.json +13 -0
  5. package/.kiro/agents/data-prompt.md +83 -74
  6. package/.kiro/agents/data-prompt.md.attribution.json +53 -0
  7. package/.kiro/agents/data.json +31 -38
  8. package/.kiro/agents/data.json.attribution.json +13 -0
  9. package/.kiro/agents/kenya-prompt.md +83 -72
  10. package/.kiro/agents/kenya-prompt.md.attribution.json +53 -0
  11. package/.kiro/agents/kenya.json +27 -35
  12. package/.kiro/agents/kenya.json.attribution.json +13 -0
  13. package/.kiro/agents/leonardo-prompt.md +176 -234
  14. package/.kiro/agents/leonardo-prompt.md.attribution.json +45 -0
  15. package/.kiro/agents/leonardo.json +28 -36
  16. package/.kiro/agents/leonardo.json.attribution.json +13 -0
  17. package/.kiro/agents/lina-prompt.md +110 -151
  18. package/.kiro/agents/lina-prompt.md.attribution.json +53 -0
  19. package/.kiro/agents/lina.json +46 -59
  20. package/.kiro/agents/lina.json.attribution.json +13 -0
  21. package/.kiro/agents/sparky-prompt.md +89 -72
  22. package/.kiro/agents/sparky-prompt.md.attribution.json +53 -0
  23. package/.kiro/agents/sparky.json +37 -37
  24. package/.kiro/agents/sparky.json.attribution.json +13 -0
  25. package/.kiro/agents/stacy-prompt.md +74 -48
  26. package/.kiro/agents/stacy-prompt.md.attribution.json +45 -0
  27. package/.kiro/agents/stacy.json +28 -30
  28. package/.kiro/agents/stacy.json.attribution.json +13 -0
  29. package/.kiro/agents/thurgood-prompt.md +94 -138
  30. package/.kiro/agents/thurgood-prompt.md.attribution.json +45 -0
  31. package/.kiro/agents/thurgood.json +31 -35
  32. package/.kiro/agents/thurgood.json.attribution.json +13 -0
  33. package/.kiro/steering/AI-Collaboration-Principles.md +3 -3
  34. package/.kiro/steering/Civitas-System-Overview.md +7 -16
  35. package/.kiro/steering/DesignerPunk-Systems-Overview.md +6 -6
  36. package/.kiro/steering/Spec-Feedback-Protocol.md +2 -11
  37. package/.kiro/steering/Task-Completion-Protocol.md +98 -17
  38. package/.kiro/steering/core-goals.md +3 -3
  39. package/.kiro/steering/personal-note.md +1 -1
  40. package/.kiro/steering/start-up-tasks.md +17 -6
  41. package/application-mcp-server/src/index.ts +26 -0
  42. package/dist/ComponentTokens.android.kt +12 -12
  43. package/dist/ComponentTokens.ios.swift +12 -12
  44. package/dist/ComponentTokens.web.css +3 -3
  45. package/dist/DesignTokens.android.kt +1 -1
  46. package/dist/DesignTokens.dtcg.json +8 -5
  47. package/dist/DesignTokens.figma.json +2 -2
  48. package/dist/DesignTokens.ios.swift +1 -1
  49. package/dist/DesignTokens.web.css +1 -1
  50. package/dist/android/DesignTokens.android.kt +1 -1
  51. package/dist/blend/OklchBlendCalculator.js +1 -0
  52. package/dist/blend/ThemeAwareBlendUtilities.web.d.ts +13 -2
  53. package/dist/blend/ThemeAwareBlendUtilities.web.js +6 -1
  54. package/dist/browser/designerpunk.esm.js +36 -90
  55. package/dist/browser/designerpunk.esm.min.js +33 -36
  56. package/dist/browser/designerpunk.umd.js +36 -90
  57. package/dist/browser/designerpunk.umd.min.js +47 -50
  58. package/dist/browser/tokens.css +3 -3
  59. package/dist/build/tokens/defineComponentTokens.d.ts +10 -0
  60. package/dist/build/tokens/defineComponentTokens.js +26 -0
  61. package/dist/components/core/Avatar-Base/avatar.tokens.d.ts +21 -26
  62. package/dist/components/core/Avatar-Base/avatar.tokens.js +31 -34
  63. package/dist/components/core/Avatar-Base/index.d.ts +1 -1
  64. package/dist/components/core/Avatar-Base/index.js +2 -2
  65. package/dist/components/core/Avatar-Base/platforms/web/Avatar.web.js +24 -5
  66. package/dist/components/core/Button-CTA/examples/BasicUsage.d.ts +16 -28
  67. package/dist/components/core/Button-CTA/examples/BasicUsage.js +18 -43
  68. package/dist/components/core/Button-CTA/platforms/web/ButtonCTA.web.d.ts +3 -15
  69. package/dist/components/core/Button-CTA/platforms/web/ButtonCTA.web.js +9 -58
  70. package/dist/components/core/Button-CTA/types.d.ts +0 -24
  71. package/dist/components/core/Button-CTA/types.js +6 -0
  72. package/dist/components/core/Button-Icon/buttonIcon.tokens.d.ts +28 -14
  73. package/dist/components/core/Button-Icon/buttonIcon.tokens.js +35 -20
  74. package/dist/components/core/Input-Text-Base/types.d.ts +13 -1
  75. package/dist/components/core/Input-Text-Password/platforms/web/InputTextPassword.web.js +11 -2
  76. package/dist/generators/DTCGFormatGenerator.js +8 -0
  77. package/dist/generators/TokenFileGenerator.js +7 -2
  78. package/dist/integration/BuildErrorHandler.js +2 -2
  79. package/dist/ios/DesignTokens.ios.swift +1 -1
  80. package/dist/mcp/application-mcp.js +24 -0
  81. package/dist/mcp/docs-mcp.js +130 -15
  82. package/dist/mcp/product-mcp.js +25 -0
  83. package/dist/tokens/OpacityTokens.js +1 -1
  84. package/dist/tokens/component/progress.d.ts +65 -5
  85. package/dist/tokens/component/progress.js +79 -18
  86. package/dist/tokens/semantic/BlendTokens.d.ts +10 -3
  87. package/dist/tokens/semantic/BlendTokens.js +17 -5
  88. package/dist/tokens/semantic/OpacityTokens.d.ts +4 -4
  89. package/dist/tokens/semantic/OpacityTokens.js +4 -4
  90. package/dist/types/ComponentTypes.d.ts +1 -1
  91. package/dist/types/generated/TokenTypes.d.ts +1 -1
  92. package/dist/types/generated/TokenTypes.js +1 -1
  93. package/dist/validators/StemmaTokenUsageValidator.js +3 -2
  94. package/dist/web/DesignTokens.web.css +1 -1
  95. package/governance/BUILD-SYSTEM-SETUP.md +1 -2
  96. package/governance/Component-Development-Guide.md +23 -13
  97. package/governance/Component-Development-Standards.md +21 -20
  98. package/governance/Component-Family-Avatar.md +6 -7
  99. package/governance/Component-Family-Badge.md +19 -20
  100. package/governance/Component-Family-Button.md +30 -43
  101. package/governance/Component-Family-Chip.md +14 -15
  102. package/governance/Component-Family-Container.md +12 -13
  103. package/governance/Component-Family-Data-Display.md +1 -2
  104. package/governance/Component-Family-Divider.md +1 -2
  105. package/governance/Component-Family-Form-Inputs.md +65 -65
  106. package/governance/Component-Family-Icon.md +9 -10
  107. package/governance/Component-Family-Loading.md +1 -2
  108. package/governance/Component-Family-Modal.md +1 -2
  109. package/governance/Component-Family-Navigation.md +1 -2
  110. package/governance/Component-Family-Progress.md +0 -1
  111. package/governance/Component-Inheritance-Structures.md +219 -99
  112. package/governance/Component-MCP-Document-Template.md +6 -5
  113. package/governance/Component-Primitive-vs-Semantic-Philosophy.md +1 -1
  114. package/governance/Component-Quick-Reference.md +33 -33
  115. package/governance/Component-Readiness-Status.md +59 -44
  116. package/governance/Component-Templates.md +57 -61
  117. package/governance/Contract-System-Reference.md +7 -7
  118. package/governance/MCP-Integration-Guide.md +1 -1
  119. package/governance/Process-Cross-Reference-Standards.md +31 -13
  120. package/governance/Process-Development-Workflow.md +49 -59
  121. package/governance/Process-File-Organization.md +25 -28
  122. package/governance/Process-Hook-Operations.md +22 -11
  123. package/governance/Process-Orchestration-Model-Selection.md +92 -0
  124. package/governance/Process-Spec-Planning.md +98 -52
  125. package/governance/Process-Task-Type-Definitions.md +80 -4
  126. package/governance/Product-Handoff-Protocol.md +2 -0
  127. package/governance/Rosetta-System-Architecture.md +13 -11
  128. package/governance/Test-Behavioral-Contract-Validation.md +38 -31
  129. package/governance/Test-Failure-Audit-Methodology.md +1 -1
  130. package/governance/Token-Family-Accessibility.md +1 -2
  131. package/governance/Token-Family-Blend.md +18 -16
  132. package/governance/Token-Family-Blur.md +0 -1
  133. package/governance/Token-Family-Border.md +1 -2
  134. package/governance/Token-Family-Color.md +0 -1
  135. package/governance/Token-Family-Glow.md +1 -2
  136. package/governance/Token-Family-Layering.md +0 -1
  137. package/governance/Token-Family-Motion.md +1 -2
  138. package/governance/Token-Family-Opacity.md +0 -1
  139. package/governance/Token-Family-Radius.md +1 -2
  140. package/governance/Token-Family-Responsive.md +1 -2
  141. package/governance/Token-Family-Shadow.md +1 -2
  142. package/governance/Token-Family-Sizing.md +0 -1
  143. package/governance/Token-Family-Spacing.md +1 -2
  144. package/governance/Token-Family-Typography.md +1 -2
  145. package/governance/Token-Governance.md +8 -8
  146. package/governance/Token-Quick-Reference.md +47 -34
  147. package/governance/Token-Resolution-Patterns.md +1 -1
  148. package/governance/Token-Semantic-Structure.md +1 -1
  149. package/governance/Web-Authoring-Standards.md +5 -5
  150. package/governance/browser-distribution-guide.md +1 -4
  151. package/governance/classification-map.md +474 -0
  152. package/governance/completion-documentation-guide.md +23 -37
  153. package/governance/component-meta-authoring-guide.md +1 -1
  154. package/governance/cross-platform-vs-platform-specific-decision-framework.md +1 -1
  155. package/governance/platform-implementation-guidelines.md +2 -3
  156. package/governance/release-management-system.md +28 -63
  157. package/governance/rosetta-system-principles.md +8 -6
  158. package/governance/stemma-system-principles.md +18 -17
  159. package/mcp-server/src/index.ts +24 -6
  160. package/mcp-server/src/indexer/DocumentIndexer.ts +119 -9
  161. package/mcp-server/src/indexer/__tests__/bare-id-crossrefs.test.ts +250 -0
  162. package/mcp-server/src/indexer/cross-ref-parser.ts +29 -1
  163. package/mcp-server/src/indexer/index-health.ts +27 -2
  164. package/mcp-server/src/query/__tests__/find-docs-calibration.test.ts +11 -26
  165. package/mcp-server/src/relocation-integrity-gate/__tests__/relocation-integrity-gate.test.ts +72 -5
  166. package/mcp-server/src/relocation-integrity-gate/relocation-integrity-gate.ts +81 -24
  167. package/mcp-server/src/tools/list-cross-references.ts +2 -2
  168. package/package.json +24 -26
  169. package/src/__tests__/browser-distribution/css-bundling.test.ts +6 -4
  170. package/src/__tests__/console-allowlist.json +14 -0
  171. package/src/__tests__/console-fail-setup.ts +169 -0
  172. package/src/__tests__/integration/Spec107-DesignLanguageContext.test.ts +16 -0
  173. package/src/__tests__/stemma-system/behavioral-contract-validation.test.ts +70 -17
  174. package/src/__tests__/stemma-system/contract-catalog-name-validation.test.ts +28 -0
  175. package/src/__tests__/stemma-system/form-inputs-contracts.test.ts +223 -16
  176. package/src/__tests__/stemma-system/input-text-native-base-call-alignment.test.ts +298 -0
  177. package/src/blend/OklchBlendCalculator.ts +3 -0
  178. package/src/blend/ThemeAwareBlendUtilities.android.kt +3 -0
  179. package/src/blend/ThemeAwareBlendUtilities.ios.swift +3 -0
  180. package/src/blend/ThemeAwareBlendUtilities.web.ts +9 -1
  181. package/src/blend/__tests__/InteractionStateAudit.test.ts +12 -9
  182. package/src/build/errors/__tests__/ErrorHandler.integration.test.ts +8 -0
  183. package/src/build/errors/__tests__/ErrorHandler.test.ts +5 -0
  184. package/src/build/tokens/__tests__/defineComponentTokens.test.ts +113 -0
  185. package/src/build/tokens/defineComponentTokens.ts +43 -1
  186. package/src/build/workflow/__tests__/CICDIntegration.test.ts +12 -1
  187. package/src/cli/__tests__/init.test.ts +45 -11
  188. package/src/components/core/Avatar-Base/Avatar-Base.schema.yaml +1 -1
  189. package/src/components/core/Avatar-Base/__tests__/Avatar.accessibility.test.ts +121 -7
  190. package/src/components/core/Avatar-Base/__tests__/Avatar.image.test.ts +3 -0
  191. package/src/components/core/Avatar-Base/__tests__/Avatar.test.ts +15 -6
  192. package/src/components/core/Avatar-Base/avatar.tokens.ts +31 -34
  193. package/src/components/core/Avatar-Base/contracts.yaml +11 -1
  194. package/src/components/core/Avatar-Base/index.ts +1 -1
  195. package/src/components/core/Avatar-Base/platforms/web/Avatar.web.ts +24 -5
  196. package/src/components/core/Badge-Count-Base/contracts.yaml +1 -1
  197. package/src/components/core/Badge-Label-Base/contracts.yaml +1 -1
  198. package/src/components/core/Button-CTA/Button-CTA.schema.yaml +2 -12
  199. package/src/components/core/Button-CTA/README.md +3 -6
  200. package/src/components/core/Button-CTA/__tests__/ButtonCTA.test.ts +35 -89
  201. package/src/components/core/Button-CTA/__tests__/setup.test.ts +0 -2
  202. package/src/components/core/Button-CTA/__tests__/test-utils.ts +0 -2
  203. package/src/components/core/Button-CTA/contracts.yaml +6 -29
  204. package/src/components/core/Button-CTA/examples/BasicUsage.html +2 -14
  205. package/src/components/core/Button-CTA/examples/BasicUsage.tsx +17 -44
  206. package/src/components/core/Button-CTA/platforms/android/ButtonCTA.android.kt +12 -20
  207. package/src/components/core/Button-CTA/platforms/ios/ButtonCTA.ios.swift +12 -51
  208. package/src/components/core/Button-CTA/platforms/web/ButtonCTA.web.css +2 -26
  209. package/src/components/core/Button-CTA/platforms/web/ButtonCTA.web.ts +18 -71
  210. package/src/components/core/Button-CTA/types.ts +10 -28
  211. package/src/components/core/Button-Icon/buttonIcon.tokens.ts +43 -27
  212. package/src/components/core/Chip-Base/__tests__/ChipBase.test.ts +13 -0
  213. package/src/components/core/Chip-Filter/__tests__/ChipFilter.test.ts +13 -0
  214. package/src/components/core/Chip-Input/__tests__/ChipInput.test.ts +13 -0
  215. package/src/components/core/Input-Text-Base/Input-Text-Base.schema.yaml +30 -2
  216. package/src/components/core/Input-Text-Base/README.md +25 -2
  217. package/src/components/core/Input-Text-Base/__tests__/focusIndicators.test.ts +16 -15
  218. package/src/components/core/Input-Text-Base/contracts.yaml +90 -0
  219. package/src/components/core/Input-Text-Base/platforms/android/InputTextBase.android.kt +26 -12
  220. package/src/components/core/Input-Text-Base/platforms/ios/InputTextBase.ios.swift +195 -59
  221. package/src/components/core/Input-Text-Base/types.ts +13 -1
  222. package/src/components/core/Input-Text-Email/Input-Text-Email.schema.yaml +5 -1
  223. package/src/components/core/Input-Text-Email/README.md +8 -7
  224. package/src/components/core/Input-Text-Email/platforms/android/InputTextEmail.android.kt +1 -4
  225. package/src/components/core/Input-Text-Email/platforms/ios/InputTextEmail.ios.swift +2 -16
  226. package/src/components/core/Input-Text-Password/Input-Text-Password.schema.yaml +10 -3
  227. package/src/components/core/Input-Text-Password/README.md +9 -8
  228. package/src/components/core/Input-Text-Password/contracts.yaml +5 -0
  229. package/src/components/core/Input-Text-Password/platforms/android/InputTextPassword.android.kt +17 -7
  230. package/src/components/core/Input-Text-Password/platforms/ios/InputTextPassword.ios.swift +22 -20
  231. package/src/components/core/Input-Text-Password/platforms/web/InputTextPassword.web.ts +11 -2
  232. package/src/components/core/Input-Text-PhoneNumber/Input-Text-PhoneNumber.schema.yaml +5 -1
  233. package/src/components/core/Input-Text-PhoneNumber/README.md +9 -8
  234. package/src/components/core/Input-Text-PhoneNumber/platforms/android/InputTextPhoneNumber.android.kt +2 -5
  235. package/src/components/core/Input-Text-PhoneNumber/platforms/ios/InputTextPhoneNumber.ios.swift +3 -17
  236. package/src/components/core/Nav-Header-App/contracts.yaml +1 -1
  237. package/src/components/core/Nav-SegmentedChoice-Base/contracts.yaml +1 -1
  238. package/src/components/core/Progress-Indicator-Connector-Base/contracts.yaml +1 -1
  239. package/src/components/core/Progress-Indicator-Label-Base/contracts.yaml +1 -1
  240. package/src/components/core/Progress-Indicator-Node-Base/contracts.yaml +1 -1
  241. package/src/components/core/Progress-Stepper-Base/__tests__/StepperBase.test.ts +5 -2
  242. package/src/components/core/Progress-Stepper-Detailed/__tests__/StepperDetailed.test.ts +5 -2
  243. package/src/generators/DTCGFormatGenerator.ts +6 -0
  244. package/src/generators/TokenFileGenerator.ts +7 -2
  245. package/src/generators/__tests__/DTCGConfigOptions.test.ts +14 -5
  246. package/src/integration/BuildErrorHandler.ts +2 -2
  247. package/src/tokens/OpacityTokens.ts +1 -1
  248. package/src/tokens/__tests__/OpacityTokens.test.ts +3 -1
  249. package/src/tokens/__tests__/ProgressTokenCompliance.test.ts +5 -3
  250. package/src/tokens/__tests__/ProgressTokenFormulas.test.ts +11 -11
  251. package/src/tokens/__tests__/ProgressTokenTranslation.test.ts +22 -20
  252. package/src/tokens/component/progress.ts +83 -21
  253. package/src/tokens/semantic/BlendTokens.ts +26 -5
  254. package/src/tokens/semantic/OpacityTokens.ts +4 -4
  255. package/src/types/ComponentTypes.ts +1 -1
  256. package/src/types/generated/TokenTypes.ts +1 -1
  257. package/src/validators/StemmaTokenUsageValidator.ts +3 -2
  258. package/token-index/components.yaml +8 -8
  259. package/token-index/semantics.yaml +1 -2
  260. package/src/tools/release/__tests__/ChangeClassifier.test.ts +0 -133
  261. package/src/tools/release/__tests__/ChangeExtractor.test.ts +0 -222
  262. package/src/tools/release/__tests__/GitHubPublisher.test.ts +0 -240
  263. package/src/tools/release/__tests__/NotesRenderer.test.ts +0 -142
  264. package/src/tools/release/__tests__/NpmPublisher.test.ts +0 -289
  265. package/src/tools/release/__tests__/PipelineIntegration.test.ts +0 -188
  266. package/src/tools/release/__tests__/ReleasePipeline.test.ts +0 -192
  267. package/src/tools/release/__tests__/SemanticVersionValidator.test.ts +0 -49
  268. package/src/tools/release/__tests__/SummaryScanner.test.ts +0 -141
  269. package/src/tools/release/__tests__/TagResolver.test.ts +0 -91
  270. package/src/tools/release/__tests__/VersionCalculator.test.ts +0 -270
  271. package/src/tools/release/__tests__/helpers/NpmMockHelper.ts +0 -80
  272. package/src/tools/release/cli/ReleasePipeline.ts +0 -165
  273. package/src/tools/release/cli/release-tool.ts +0 -107
  274. package/src/tools/release/pipeline/ChangeClassifier.ts +0 -61
  275. package/src/tools/release/pipeline/ChangeExtractor.ts +0 -87
  276. package/src/tools/release/pipeline/NotesRenderer.ts +0 -66
  277. package/src/tools/release/pipeline/SummaryScanner.ts +0 -70
  278. package/src/tools/release/pipeline/TagResolver.ts +0 -40
  279. package/src/tools/release/pipeline/VersionCalculator.ts +0 -375
  280. package/src/tools/release/publishers/GitHubPublisher.ts +0 -228
  281. package/src/tools/release/publishers/NpmPublisher.ts +0 -196
  282. package/src/tools/release/release-config.json +0 -5
  283. package/src/tools/release/types/index.ts +0 -282
  284. package/src/tools/release/validators/SemanticVersionValidator.ts +0 -67
@@ -18,13 +18,15 @@
18
18
 
19
19
  import { TokenFileGenerator } from '../../generators/TokenFileGenerator';
20
20
  import { ComponentTokenRegistry } from '../../registries/ComponentTokenRegistry';
21
- import { getTokenContract } from '../../build/tokens';
22
21
 
23
22
  // Spec 124: defineComponentTokens no longer self-registers; the rich tokens ride back on
24
- // the branded return. We reproduce the production harvest here (recover via getTokenContract
23
+ // the branded return. We reproduce the production harvest here (recover the rich tokens
25
24
  // + register into the canonical registry) so the real TokenFileGenerator pipeline — which
26
25
  // reads ComponentTokenRegistry.getAll() — has the Progress tokens to translate.
27
- import { ProgressTokens } from '../../tokens/component/progress';
26
+ //
27
+ // Progress registers through THREE family calls (sizing / spacing / borderWidth), so the
28
+ // harvest is the concatenation helper rather than getTokenContract() of a single export.
29
+ import { getProgressRegisteredTokens } from '../../tokens/component/progress';
28
30
 
29
31
  describe('Progress Token Cross-Platform Translation', () => {
30
32
  let generator: TokenFileGenerator;
@@ -34,7 +36,7 @@ describe('Progress Token Cross-Platform Translation', () => {
34
36
 
35
37
  beforeAll(() => {
36
38
  ComponentTokenRegistry.clear();
37
- for (const token of getTokenContract(ProgressTokens) ?? []) {
39
+ for (const token of getProgressRegisteredTokens()) {
38
40
  ComponentTokenRegistry.register(token);
39
41
  }
40
42
 
@@ -91,27 +93,27 @@ describe('Progress Token Cross-Platform Translation', () => {
91
93
  describe('iOS Swift output includes progress current size tokens', () => {
92
94
  it('should reference size200 for sm current size', () => {
93
95
  expect(iosContent).toContain('nodeSizeSmCurrent');
94
- expect(iosContent).toMatch(/nodeSizeSmCurrent.*SpacingTokens.size200/);
96
+ expect(iosContent).toMatch(/nodeSizeSmCurrent.*SizingTokens.size200/);
95
97
  });
96
98
 
97
99
  it('should reference size250 for md current size', () => {
98
100
  expect(iosContent).toContain('nodeSizeMdCurrent');
99
- expect(iosContent).toMatch(/nodeSizeMdCurrent.*SpacingTokens.size250/);
101
+ expect(iosContent).toMatch(/nodeSizeMdCurrent.*SizingTokens.size250/);
100
102
  });
101
103
 
102
104
  it('should reference size300 for lg current size', () => {
103
105
  expect(iosContent).toContain('nodeSizeLgCurrent');
104
- expect(iosContent).toMatch(/nodeSizeLgCurrent.*SpacingTokens.size300/);
106
+ expect(iosContent).toMatch(/nodeSizeLgCurrent.*SizingTokens.size300/);
105
107
  });
106
108
 
107
- it('should use CGFloat type for spacing tokens', () => {
109
+ it('should use CGFloat type for dimensional tokens', () => {
108
110
  expect(iosContent).toMatch(/nodeSizeSmCurrent:\s*CGFloat/);
109
111
  });
110
112
 
111
113
  it('should reference SizingTokens for base size tokens', () => {
112
- expect(iosContent).toContain('SpacingTokens.size150');
113
- expect(iosContent).toContain('SpacingTokens.size200');
114
- expect(iosContent).toContain('SpacingTokens.size250');
114
+ expect(iosContent).toContain('SizingTokens.size150');
115
+ expect(iosContent).toContain('SizingTokens.size200');
116
+ expect(iosContent).toContain('SizingTokens.size250');
115
117
  });
116
118
  });
117
119
 
@@ -122,23 +124,23 @@ describe('Progress Token Cross-Platform Translation', () => {
122
124
  describe('Android Kotlin output includes progress current size tokens', () => {
123
125
  it('should reference size200 for sm current size', () => {
124
126
  expect(androidContent).toContain('nodeSizeSmCurrent');
125
- expect(androidContent).toMatch(/nodeSizeSmCurrent\s*=\s*SpacingTokens.size200/);
127
+ expect(androidContent).toMatch(/nodeSizeSmCurrent\s*=\s*SizingTokens.size200/);
126
128
  });
127
129
 
128
130
  it('should reference size250 for md current size', () => {
129
131
  expect(androidContent).toContain('nodeSizeMdCurrent');
130
- expect(androidContent).toMatch(/nodeSizeMdCurrent\s*=\s*SpacingTokens.size250/);
132
+ expect(androidContent).toMatch(/nodeSizeMdCurrent\s*=\s*SizingTokens.size250/);
131
133
  });
132
134
 
133
135
  it('should reference size300 for lg current size', () => {
134
136
  expect(androidContent).toContain('nodeSizeLgCurrent');
135
- expect(androidContent).toMatch(/nodeSizeLgCurrent\s*=\s*SpacingTokens.size300/);
137
+ expect(androidContent).toMatch(/nodeSizeLgCurrent\s*=\s*SizingTokens.size300/);
136
138
  });
137
139
 
138
140
  it('should reference SizingTokens for base size tokens', () => {
139
- expect(androidContent).toContain('SpacingTokens.size150');
140
- expect(androidContent).toContain('SpacingTokens.size200');
141
- expect(androidContent).toContain('SpacingTokens.size250');
141
+ expect(androidContent).toContain('SizingTokens.size150');
142
+ expect(androidContent).toContain('SizingTokens.size200');
143
+ expect(androidContent).toContain('SizingTokens.size250');
142
144
  });
143
145
  });
144
146
 
@@ -149,9 +151,9 @@ describe('Progress Token Cross-Platform Translation', () => {
149
151
  describe('Cross-platform value consistency', () => {
150
152
  it('should reference same sizing primitives for current sizes across all platforms', () => {
151
153
  const currentSizes = [
152
- { cssRef: 'size-200', swiftRef: 'SpacingTokens.size200', kotlinRef: 'SpacingTokens.size200', cssName: 'sm-current', camelName: 'nodeSizeSmCurrent' },
153
- { cssRef: 'size-250', swiftRef: 'SpacingTokens.size250', kotlinRef: 'SpacingTokens.size250', cssName: 'md-current', camelName: 'nodeSizeMdCurrent' },
154
- { cssRef: 'size-300', swiftRef: 'SpacingTokens.size300', kotlinRef: 'SpacingTokens.size300', cssName: 'lg-current', camelName: 'nodeSizeLgCurrent' },
154
+ { cssRef: 'size-200', swiftRef: 'SizingTokens.size200', kotlinRef: 'SizingTokens.size200', cssName: 'sm-current', camelName: 'nodeSizeSmCurrent' },
155
+ { cssRef: 'size-250', swiftRef: 'SizingTokens.size250', kotlinRef: 'SizingTokens.size250', cssName: 'md-current', camelName: 'nodeSizeMdCurrent' },
156
+ { cssRef: 'size-300', swiftRef: 'SizingTokens.size300', kotlinRef: 'SizingTokens.size300', cssName: 'lg-current', camelName: 'nodeSizeLgCurrent' },
155
157
  ];
156
158
 
157
159
  for (const { cssRef, swiftRef, kotlinRef, cssName, camelName } of currentSizes) {
@@ -20,26 +20,45 @@
20
20
  * @see .kiro/specs/048-progress-family/design.md (Size Variant, Token Usage sections)
21
21
  */
22
22
 
23
- import { defineComponentTokens } from '../../build/tokens';
23
+ import { defineComponentTokens, getTokenContract } from '../../build/tokens';
24
+ import type { RegisteredComponentToken } from '../../registries/ComponentTokenRegistry';
24
25
  import { spacingTokens } from '../../tokens/SpacingTokens';
25
26
  import { sizingTokens } from '../../tokens/SizingTokens';
26
27
  import { borderWidthTokens } from '../../tokens/BorderWidthTokens';
27
28
 
28
29
  /**
29
- * Progress Indicator component tokens defined using the hybrid authoring API.
30
- *
31
- * 13 tokens organized by concept:
30
+ * ONE CALL PER FAMILY.
31
+ *
32
+ * Every token registered by a single defineComponentTokens() call is stamped with that
33
+ * call's `family`, and the family drives platform output — notably the primitive class
34
+ * name emitted for reference-path tokens (TokenFileGenerator.getFamilyClassName) and the
35
+ * Android `.dp` suffix. These 10 tokens span THREE primitive families, so they require
36
+ * three calls. A single `family: 'spacing'` call previously produced
37
+ * `SpacingTokens.size150` / `SpacingTokens.borderWidth100` — members no generated platform
38
+ * file defines — the same defect fixed for Button-Icon in PR #126.
39
+ *
40
+ * The three branded results MUST NOT be spread/merged into one registration object: the
41
+ * rich metadata rides on a non-enumerable brand (src/build/tokens/defineComponentTokens.ts,
42
+ * TOKEN_CONTRACT_BRAND) that a spread silently drops. The harvest in loadComponentTokens
43
+ * collects each branded export separately. Use {@link progressTokenValues} for flat
44
+ * value lookups and {@link getProgressRegisteredTokens} for the rich metadata.
45
+ *
46
+ * All three calls declare `component: 'Progress'`, so platform output is still a single
47
+ * `ProgressTokens` Swift enum / Kotlin object.
48
+ */
49
+
50
+ /**
51
+ * Node dimension tokens — reference sizing primitives (dimensions, not spacing).
52
+ *
32
53
  * - node.size.{sm|md|lg} — base node dimensions
33
54
  * - node.size.{sm|md|lg}.current — emphasized node dimensions (+4px)
34
- * - node.gap.{sm|md|lg} — spacing between nodes
35
- * - connector.thickness — connector line width
36
55
  */
37
- export const ProgressTokens = defineComponentTokens({
56
+ export const ProgressSizingTokens = defineComponentTokens({
38
57
  component: 'Progress',
39
- family: 'spacing',
58
+ family: 'sizing',
40
59
  tokens: {
41
60
  // ========================================================================
42
- // BASE NODE SIZES — reference sizing primitives (dimensions, not spacing)
61
+ // BASE NODE SIZES
43
62
  // ========================================================================
44
63
 
45
64
  'node.size.sm': {
@@ -56,7 +75,7 @@ export const ProgressTokens = defineComponentTokens({
56
75
  },
57
76
 
58
77
  // ========================================================================
59
- // CURRENT NODE SIZES — reference sizing primitives directly (+4px emphasis)
78
+ // CURRENT NODE SIZES — +4px emphasis
60
79
  // Provides non-color visual differentiation of active position
61
80
  // ========================================================================
62
81
 
@@ -72,11 +91,18 @@ export const ProgressTokens = defineComponentTokens({
72
91
  reference: sizingTokens.size300,
73
92
  reasoning: 'Current node emphasis for lg (24px). +4px over base 20px for non-color visual differentiation.',
74
93
  },
94
+ },
95
+ });
75
96
 
76
- // ========================================================================
77
- // GAP TOKENS — spacing between nodes (gaps are spacing, not sizing)
78
- // ========================================================================
79
-
97
+ /**
98
+ * Node gap tokens — reference spacing primitives (gaps are spacing, not sizing).
99
+ *
100
+ * - node.gap.{sm|md|lg} — spacing between nodes
101
+ */
102
+ export const ProgressSpacingTokens = defineComponentTokens({
103
+ component: 'Progress',
104
+ family: 'spacing',
105
+ tokens: {
80
106
  'node.gap.sm': {
81
107
  reference: spacingTokens.space075,
82
108
  reasoning: 'Small gap between nodes (6px = 0.75× base). Tight spacing for compact pagination dots in mobile contexts.',
@@ -89,11 +115,18 @@ export const ProgressTokens = defineComponentTokens({
89
115
  reference: spacingTokens.space150,
90
116
  reasoning: 'Large gap between nodes (12px = 1.5× base). Generous spacing for detailed steppers with labels in desktop contexts.',
91
117
  },
118
+ },
119
+ });
92
120
 
93
- // ========================================================================
94
- // CONNECTOR TOKENS — line connecting nodes in steppers
95
- // ========================================================================
96
-
121
+ /**
122
+ * Connector tokens — line connecting nodes in steppers. References a borderWidth primitive.
123
+ *
124
+ * - connector.thickness — connector line width
125
+ */
126
+ export const ProgressBorderWidthTokens = defineComponentTokens({
127
+ component: 'Progress',
128
+ family: 'borderWidth',
129
+ tokens: {
97
130
  'connector.thickness': {
98
131
  reference: borderWidthTokens.borderWidth100,
99
132
  reasoning: 'Connector line thickness (1px). References borderDefault primitive for consistent border treatment across the design system.',
@@ -101,6 +134,35 @@ export const ProgressTokens = defineComponentTokens({
101
134
  },
102
135
  });
103
136
 
137
+ /**
138
+ * Flat value map across all three Progress token calls — a READ-ONLY convenience for
139
+ * value lookups (`progressTokenValues['node.size.md']`).
140
+ *
141
+ * NOT a registration surface: spreading drops the non-enumerable brand, so this object
142
+ * deliberately harvests to zero and cannot double-register. For the rich metadata use
143
+ * {@link getProgressRegisteredTokens}, never `getTokenContract(progressTokenValues)`.
144
+ */
145
+ export const progressTokenValues = {
146
+ ...ProgressSizingTokens,
147
+ ...ProgressSpacingTokens,
148
+ ...ProgressBorderWidthTokens,
149
+ };
150
+
151
+ /**
152
+ * All Progress component tokens with their rich metadata, concatenated across the three
153
+ * family calls in declaration order (sizing → spacing → borderWidth).
154
+ *
155
+ * This is the brand-safe replacement for `getTokenContract(ProgressTokens)`, which is no
156
+ * longer meaningful now that Progress registers through three calls.
157
+ */
158
+ export function getProgressRegisteredTokens(): RegisteredComponentToken[] {
159
+ return [
160
+ ...(getTokenContract(ProgressSizingTokens) ?? []),
161
+ ...(getTokenContract(ProgressSpacingTokens) ?? []),
162
+ ...(getTokenContract(ProgressBorderWidthTokens) ?? []),
163
+ ];
164
+ }
165
+
104
166
  // ============================================================================
105
167
  // Constants and Utilities
106
168
  // ============================================================================
@@ -135,19 +197,19 @@ export const progressComponentTokenNames = [
135
197
  * Validate that the progress component token count matches the expected count (13)
136
198
  */
137
199
  export function validateProgressComponentTokenCount(): boolean {
138
- return Object.keys(ProgressTokens).length === PROGRESS_COMPONENT_TOKEN_COUNT;
200
+ return Object.keys(progressTokenValues).length === PROGRESS_COMPONENT_TOKEN_COUNT;
139
201
  }
140
202
 
141
203
  /**
142
204
  * Get a single progress component token value by key
143
205
  */
144
206
  export function getProgressComponentToken(key: string): number | undefined {
145
- return (ProgressTokens as Record<string, number>)[key];
207
+ return (progressTokenValues as Record<string, number>)[key];
146
208
  }
147
209
 
148
210
  /**
149
211
  * Get all progress component token entries as key-value pairs
150
212
  */
151
213
  export function getAllProgressComponentTokens(): Array<{ name: string; value: number }> {
152
- return Object.entries(ProgressTokens).map(([name, value]) => ({ name, value }));
214
+ return Object.entries(progressTokenValues).map(([name, value]) => ({ name, value }));
153
215
  }
@@ -16,7 +16,7 @@
16
16
  * - blendHoverLighter: Hover feedback on dark backgrounds (8% lighter)
17
17
  * - blendPressedDarker: Pressed state feedback with darkening (12% darker)
18
18
  * - blendFocusSaturate: Focus state with increased saturation (8% more saturated)
19
- * - blendDisabledDesaturate: Disabled state with decreased saturation (12% less saturated)
19
+ * - blendDisabledDesaturate: DEPRECATED 2026-07-15 — DesignerPunk has no disabled states
20
20
  * - blendContainerHoverDarker: Subtle container hover feedback (4% darker)
21
21
  * - color.icon.opticalBalance: Icon optical weight compensation (8% lighter)
22
22
  *
@@ -49,6 +49,15 @@ export interface SemanticBlendToken {
49
49
 
50
50
  /** Detailed description of semantic meaning and appropriate usage */
51
51
  description: string;
52
+
53
+ /** Token is deprecated — do not use in new work; flows to DTCG $extensions.designerpunk.deprecated */
54
+ deprecated?: boolean;
55
+
56
+ /** ISO date the deprecation took effect */
57
+ deprecatedSince?: string;
58
+
59
+ /** Why the token was deprecated and what to do instead */
60
+ deprecatedReason?: string;
52
61
  }
53
62
 
54
63
  /**
@@ -111,6 +120,14 @@ export const blendTokens: Record<string, SemanticBlendToken> = {
111
120
  description: 'Blend for focus states with saturation increase (8% more saturated) - creates energized, attention-drawing appearance for focused interactive elements'
112
121
  },
113
122
 
123
+ /**
124
+ * @deprecated 2026-07-15 — DesignerPunk does not support disabled states
125
+ * (Button-CTA disabled-state adjudication, ruled REMOVE; the no-disabled-states
126
+ * philosophy holds corpus-wide). If an action is unavailable, do not render the
127
+ * component. Retained for backward compatibility; scheduled for removal in the
128
+ * next major version of @3fn/core. For non-disabled desaturation needs, use the
129
+ * generic desaturate utilities with primitive blend tokens.
130
+ */
114
131
  'blend.disabledDesaturate': {
115
132
  name: 'blend.disabledDesaturate',
116
133
  primitiveReferences: {
@@ -118,8 +135,11 @@ export const blendTokens: Record<string, SemanticBlendToken> = {
118
135
  },
119
136
  direction: BlendDirection.DESATURATE,
120
137
  category: 'interaction',
121
- context: 'Disabled state appearance - muted, inactive color',
122
- description: 'Blend for disabled states with desaturation (12% less saturated) - creates muted, inactive appearance indicating non-interactive state'
138
+ context: 'DEPRECATED - disabled states are not supported in DesignerPunk',
139
+ description: 'DEPRECATED (2026-07-15): DesignerPunk does not support disabled states — if an action is unavailable, do not render the component. Formerly: blend for disabled states with desaturation (12% less saturated). Scheduled for removal in the next major version.',
140
+ deprecated: true,
141
+ deprecatedSince: '2026-07-15',
142
+ deprecatedReason: 'No-disabled-states philosophy holds corpus-wide (Button-CTA adjudication, 2026-07-15). Unavailable actions should not be rendered; state_loading covers in-flight async actions.'
123
143
  },
124
144
 
125
145
  'blend.containerHoverDarker': {
@@ -200,8 +220,9 @@ export function validateBlendTokenCount(): boolean {
200
220
  * → Creates vibrant, attention-drawing appearance for focused elements
201
221
  *
202
222
  * 5. Disabled states?
203
- * → Use blend.disabledDesaturate (12% less saturated)
204
- * → Creates muted appearance indicating non-interactive state
223
+ * → DO NOT style disabled states. DesignerPunk does not support disabled states —
224
+ * if an action is unavailable, do not render the component (adjudicated 2026-07-15).
225
+ * → blend.disabledDesaturate is DEPRECATED and scheduled for removal at the next major.
205
226
  *
206
227
  * 6. Large container/surface hover?
207
228
  * → Use blend.containerHoverDarker (4% darker)
@@ -6,10 +6,10 @@
6
6
  * the design system while maintaining semantic meaning.
7
7
  *
8
8
  * Opacity values:
9
- * - subtle: 0.9 (90%) - Minimal transparency for subtle effects
10
- * - medium: 0.7 (70%) - Moderate transparency for overlays
11
- * - heavy: 0.5 (50%) - Strong transparency for backgrounds
12
- * - ghost: 0.3 (30%) - Maximum transparency for ghost effects
9
+ * - subtle: opacity088 (88%) - Minimal transparency for subtle effects
10
+ * - medium: opacity072 (72%) - Moderate transparency for overlays
11
+ * - heavy: opacity048 (48%) - Strong transparency for backgrounds
12
+ * - ghost: opacity032 (32%) - Maximum transparency for ghost effects
13
13
  *
14
14
  * All opacity tokens reference primitive opacity values that can be applied
15
15
  * to any color or surface for consistent transparency effects.
@@ -65,7 +65,7 @@
65
65
  * }
66
66
  * ```
67
67
  *
68
- * @see {@link https://github.com/3fn/DesignerPunkv2/blob/main/.kiro/specs/011-inset-token-renaming/design.md | Inset Token Renaming Design}
68
+ * @see {@link https://github.com/3fn/DesignerPunk/blob/main/.kiro/specs/011-inset-token-renaming/design.md | Inset Token Renaming Design}
69
69
  */
70
70
  export type InsetPadding =
71
71
  | 'inset050'
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * To regenerate: npm run generate:types
8
8
  *
9
- * Generated: 2026-07-05T14:35:59.520Z
9
+ * Generated: 2026-08-26T14:15:23.873Z
10
10
  */
11
11
 
12
12
  /**
@@ -294,9 +294,10 @@ export const TOKEN_CATEGORIES = {
294
294
  'border.default', 'border.strong',
295
295
  'radius.100', 'radius.150', 'radius.200',
296
296
  ],
297
+ // blend.disabledDesaturate removed 2026-07-15: deprecated (no-disabled-states
298
+ // philosophy) — the validator must not suggest it for new component work
297
299
  blend: [
298
- 'blend.hoverDarker', 'blend.pressedDarker',
299
- 'blend.disabledDesaturate', 'blend.iconLighter',
300
+ 'blend.hoverDarker', 'blend.pressedDarker', 'blend.iconLighter',
300
301
  ],
301
302
  };
302
303
 
@@ -1,4 +1,12 @@
1
1
  tokens:
2
+ progress.connector.thickness:
3
+ component: Progress
4
+ primitiveReferences:
5
+ value: borderWidth100
6
+ platforms:
7
+ web: '--progress-connector-thickness'
8
+ ios: ProgressTokens.connectorThickness
9
+ android: ProgressTokens.connectorThickness
2
10
  progress.node.size.sm:
3
11
  component: Progress
4
12
  primitiveReferences:
@@ -71,14 +79,6 @@ tokens:
71
79
  web: '--progress-node-gap-lg'
72
80
  ios: ProgressTokens.nodeGapLg
73
81
  android: ProgressTokens.nodeGapLg
74
- progress.connector.thickness:
75
- component: Progress
76
- primitiveReferences:
77
- value: borderWidth100
78
- platforms:
79
- web: '--progress-connector-thickness'
80
- ios: ProgressTokens.connectorThickness
81
- android: ProgressTokens.connectorThickness
82
82
  avatar.size.xs:
83
83
  component: Avatar
84
84
  primitiveReferences:
@@ -1418,8 +1418,7 @@ tokens:
1418
1418
  web: '--blend-disabled-desaturate'
1419
1419
  ios: blendDisabledDesaturate
1420
1420
  android: blend_disabled_desaturate
1421
- consumers:
1422
- - Button-CTA
1421
+ consumers: []
1423
1422
  blend.containerHoverDarker:
1424
1423
  category: interaction
1425
1424
  primitiveReferences:
@@ -1,133 +0,0 @@
1
- /**
2
- * @category evergreen
3
- * @purpose Verify ChangeClassifier maps changes to correct priority tiers
4
- */
5
-
6
- import { ChangeClassifier } from '../pipeline/ChangeClassifier';
7
- import { ExtractedChange } from '../types';
8
-
9
- describe('ChangeClassifier', () => {
10
- let classifier: ChangeClassifier;
11
-
12
- beforeEach(() => {
13
- classifier = new ChangeClassifier();
14
- });
15
-
16
- const makeChange = (overrides: Partial<ExtractedChange> = {}): ExtractedChange => ({
17
- specName: '065-test',
18
- taskTitle: 'Test task',
19
- taskType: 'Implementation',
20
- whatWasDone: 'Did something',
21
- whyItMatters: 'It matters',
22
- keyChanges: ['change 1'],
23
- impact: ['impact 1'],
24
- ...overrides,
25
- });
26
-
27
- describe('structured deliverables path', () => {
28
- it('should use deliverable priority directly', () => {
29
- const change = makeChange({
30
- deliverables: [{ priority: '🔴', type: 'Component', description: 'New ButtonCTA' }],
31
- });
32
-
33
- const results = classifier.classify([change]);
34
-
35
- expect(results[0].priority).toBe('breaking');
36
- expect(results[0].deliverableType).toBe('Component');
37
- });
38
-
39
- it('should use highest priority when multiple deliverables', () => {
40
- const change = makeChange({
41
- deliverables: [
42
- { priority: '🔵', type: 'Governance', description: 'Process update' },
43
- { priority: '🔴', type: 'Token', description: 'New color token' },
44
- { priority: '🟡', type: 'Tool', description: 'Build change' },
45
- ],
46
- });
47
-
48
- const results = classifier.classify([change]);
49
-
50
- expect(results[0].priority).toBe('breaking');
51
- expect(results[0].deliverableType).toBe('Token');
52
- });
53
-
54
- it('should map all three emoji priorities', () => {
55
- const changes = [
56
- makeChange({ deliverables: [{ priority: '🔴', type: 'Token', description: 'x' }] }),
57
- makeChange({ deliverables: [{ priority: '🟡', type: 'Tool', description: 'x' }] }),
58
- makeChange({ deliverables: [{ priority: '🔵', type: 'Governance', description: 'x' }] }),
59
- ];
60
-
61
- const results = classifier.classify(changes);
62
-
63
- expect(results[0].priority).toBe('breaking');
64
- expect(results[1].priority).toBe('prominent');
65
- expect(results[2].priority).toBe('context');
66
- });
67
- });
68
-
69
- describe('keyword heuristics fallback', () => {
70
- it('should classify token changes as breaking', () => {
71
- const change = makeChange({ taskTitle: 'Add new color token' });
72
- const results = classifier.classify([change]);
73
- expect(results[0].priority).toBe('breaking');
74
- expect(results[0].deliverableType).toBe('Token');
75
- });
76
-
77
- it('should classify component changes as breaking', () => {
78
- const change = makeChange({ whatWasDone: 'Created new component scaffold' });
79
- const results = classifier.classify([change]);
80
- expect(results[0].priority).toBe('breaking');
81
- expect(results[0].deliverableType).toBe('Component');
82
- });
83
-
84
- it('should classify tool changes as prominent', () => {
85
- const change = makeChange({ taskTitle: 'Build tool improvements' });
86
- const results = classifier.classify([change]);
87
- expect(results[0].priority).toBe('prominent');
88
- });
89
-
90
- it('should classify governance changes as context', () => {
91
- const change = makeChange({ keyChanges: ['Updated governance documentation'] });
92
- const results = classifier.classify([change]);
93
- expect(results[0].priority).toBe('context');
94
- });
95
-
96
- it('should default to context when no keywords match', () => {
97
- const change = makeChange({ taskTitle: 'Miscellaneous cleanup', whatWasDone: 'Cleaned up files', keyChanges: ['removed old stuff'] });
98
- const results = classifier.classify([change]);
99
- expect(results[0].priority).toBe('context');
100
- expect(results[0].deliverableType).toBe('Other');
101
- });
102
- });
103
-
104
- describe('sorting', () => {
105
- it('should sort by priority: breaking > prominent > context', () => {
106
- const changes = [
107
- makeChange({ taskTitle: 'Governance update', deliverables: [{ priority: '🔵', type: 'Governance', description: 'x' }] }),
108
- makeChange({ taskTitle: 'New token', deliverables: [{ priority: '🔴', type: 'Token', description: 'x' }] }),
109
- makeChange({ taskTitle: 'New tool', deliverables: [{ priority: '🟡', type: 'Tool', description: 'x' }] }),
110
- ];
111
-
112
- const results = classifier.classify(changes);
113
-
114
- expect(results[0].priority).toBe('breaking');
115
- expect(results[1].priority).toBe('prominent');
116
- expect(results[2].priority).toBe('context');
117
- });
118
- });
119
-
120
- describe('mixed structured and heuristic', () => {
121
- it('should handle mix of deliverable and no-deliverable changes', () => {
122
- const changes = [
123
- makeChange({ taskTitle: 'Misc cleanup', whatWasDone: 'Cleaned things', keyChanges: ['stuff'] }),
124
- makeChange({ deliverables: [{ priority: '🔴', type: 'Component', description: 'New component' }] }),
125
- ];
126
-
127
- const results = classifier.classify(changes);
128
-
129
- expect(results[0].priority).toBe('breaking');
130
- expect(results[1].priority).toBe('context');
131
- });
132
- });
133
- });