@pixel-point/toolcraft 0.0.14 → 0.0.15

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 (577) hide show
  1. package/README.md +13 -2
  2. package/package.json +1 -1
  3. package/scripts/prepare-pack.mjs +2 -28
  4. package/src/cli-io.mjs +174 -0
  5. package/src/cli-package-manager-flow.test.mjs +206 -0
  6. package/src/cli.mjs +7 -495
  7. package/src/cli.test.mjs +34 -177
  8. package/src/create-command.mjs +152 -0
  9. package/src/create-options.mjs +194 -0
  10. package/src/generate-test-assertions.mjs +27 -0
  11. package/src/generate-test-doc-assertions.mjs +162 -0
  12. package/src/generate-test-file-assertions.mjs +251 -0
  13. package/src/generate-test-fs-utils.mjs +59 -0
  14. package/src/generate-test-integrity-assertions.mjs +30 -0
  15. package/src/generate-test-integrity-framework-assertions.mjs +222 -0
  16. package/src/generate-test-integrity-manifest-assertions.mjs +150 -0
  17. package/src/generate-test-integrity-ownership-assertions.mjs +127 -0
  18. package/src/generate-test-integrity-test-utils.mjs +102 -0
  19. package/src/generate-test-package-assertions.mjs +75 -0
  20. package/src/generate-test-product-fixture.mjs +84 -0
  21. package/src/generate-test-product-fixture.test.mjs +73 -0
  22. package/src/generate-test-standalone-assertions.mjs +209 -0
  23. package/src/generate-transactional.test.mjs +151 -0
  24. package/src/generate.mjs +182 -102
  25. package/src/generate.test.mjs +242 -338
  26. package/src/generated-integrity-manifest.mjs +127 -0
  27. package/src/generated-integrity-manifest.test.mjs +151 -0
  28. package/src/generated-source-policy.mjs +22 -0
  29. package/src/generated-source-policy.test.mjs +35 -0
  30. package/src/generated-target-policy.mjs +55 -0
  31. package/src/generation-transaction.mjs +135 -0
  32. package/src/generation-transaction.test.mjs +74 -0
  33. package/src/package-json.mjs +18 -1
  34. package/src/package-json.test.mjs +38 -5
  35. package/src/package-manager.mjs +2 -0
  36. package/src/package-manager.test.mjs +5 -1
  37. package/src/packaged-template-fallback.test.mjs +126 -0
  38. package/src/prepare-pack-templates.mjs +34 -0
  39. package/templates/runtime/contracts/component-contract-builders.ts +95 -0
  40. package/templates/runtime/contracts/component-contracts.choices.test.ts +293 -0
  41. package/templates/runtime/contracts/component-contracts.choices.ts +322 -0
  42. package/templates/runtime/contracts/component-contracts.inputs.test.ts +210 -0
  43. package/templates/runtime/contracts/component-contracts.inputs.ts +252 -0
  44. package/templates/runtime/contracts/component-contracts.media-custom.test.ts +116 -0
  45. package/templates/runtime/contracts/component-contracts.media-custom.ts +144 -0
  46. package/templates/runtime/contracts/component-contracts.runtime-acceptance.test.ts +229 -0
  47. package/templates/runtime/contracts/component-contracts.runtime-labels.test.ts +76 -0
  48. package/templates/runtime/contracts/component-contracts.runtime-panels.test.ts +135 -0
  49. package/templates/runtime/contracts/component-contracts.runtime-shell.test.ts +148 -0
  50. package/templates/runtime/contracts/component-contracts.runtime.ts +361 -0
  51. package/templates/runtime/contracts/component-contracts.test.ts +39 -1458
  52. package/templates/runtime/contracts/component-contracts.ts +44 -1505
  53. package/templates/runtime/contracts/component-contracts.visual.test.ts +316 -0
  54. package/templates/runtime/contracts/component-contracts.visual.ts +385 -0
  55. package/templates/runtime/contracts/contract-manifest.test.ts +64 -0
  56. package/templates/runtime/contracts/decision-contracts.test.ts +29 -4
  57. package/templates/runtime/contracts/decision-contracts.ts +38 -1
  58. package/templates/runtime/index.ts +1 -0
  59. package/templates/runtime/react/{runtime-public-api.test.tsx → app-shell/runtime-public-api.test.tsx} +29 -7
  60. package/templates/runtime/react/{settings-transfer.test.ts → app-shell/settings-transfer.test.ts} +4 -4
  61. package/templates/runtime/react/{settings-transfer.ts → app-shell/settings-transfer.ts} +3 -3
  62. package/templates/runtime/react/{toolbar-panel.test.tsx → app-shell/toolbar-panel.test.tsx} +2 -2
  63. package/templates/runtime/react/{toolbar-panel.tsx → app-shell/toolbar-panel.tsx} +3 -3
  64. package/templates/runtime/react/{toolcraft-app.integration.test.tsx → app-shell/toolcraft-app.integration.test.tsx} +6 -6
  65. package/templates/runtime/react/{toolcraft-app.test.tsx → app-shell/toolcraft-app.test.tsx} +3 -3
  66. package/templates/runtime/react/{toolcraft-app.tsx → app-shell/toolcraft-app.tsx} +11 -8
  67. package/templates/runtime/react/{toolcraft-root.test.tsx → app-shell/toolcraft-root.test.tsx} +1 -1
  68. package/templates/runtime/react/{toolcraft-root.tsx → app-shell/toolcraft-root.tsx} +5 -5
  69. package/templates/runtime/react/{use-toolcraft.ts → app-shell/use-toolcraft.ts} +1 -1
  70. package/templates/runtime/react/canvas/canvas-default-media-layer.tsx +81 -0
  71. package/templates/runtime/react/canvas/canvas-media-transform.ts +33 -0
  72. package/templates/runtime/react/canvas/canvas-shell-interactions.test.tsx +156 -0
  73. package/templates/runtime/react/canvas/canvas-shell-media-rendering.test.tsx +87 -0
  74. package/templates/runtime/react/canvas/canvas-shell-rendering.test.tsx +102 -0
  75. package/templates/runtime/react/canvas/canvas-shell-test-utils.tsx +108 -0
  76. package/templates/runtime/react/canvas/canvas-shell-upload.test.tsx +106 -0
  77. package/templates/runtime/react/canvas/canvas-shell.tsx +146 -0
  78. package/templates/runtime/react/canvas/canvas-upload-routing.ts +84 -0
  79. package/templates/runtime/react/{media-file.ts → canvas/media-file.ts} +1 -1
  80. package/templates/runtime/react/canvas/use-canvas-drop-import.ts +145 -0
  81. package/templates/runtime/react/canvas/use-canvas-viewport-interactions.ts +227 -0
  82. package/templates/runtime/react/controls-panel/__tests__/control-conditions.test.ts +89 -0
  83. package/templates/runtime/react/{controls-panel-filedrop-reorder.test.tsx → controls-panel/__tests__/controls-panel-filedrop-reorder.test.tsx} +4 -4
  84. package/templates/runtime/react/controls-panel/__tests__/controls-panel.actions-layout.test.tsx +91 -0
  85. package/templates/runtime/react/controls-panel/__tests__/controls-panel.collection-actions.test.tsx +213 -0
  86. package/templates/runtime/react/controls-panel/__tests__/controls-panel.color-layout.test.tsx +366 -0
  87. package/templates/runtime/react/controls-panel/__tests__/controls-panel.color-picker-models.test.tsx +169 -0
  88. package/templates/runtime/react/controls-panel/__tests__/controls-panel.compound-layout.test.tsx +160 -0
  89. package/templates/runtime/react/controls-panel/__tests__/controls-panel.control-visibility.test.tsx +352 -0
  90. package/templates/runtime/react/controls-panel/__tests__/controls-panel.curves.test.tsx +226 -0
  91. package/templates/runtime/react/controls-panel/__tests__/controls-panel.floating-shell.test.tsx +13 -0
  92. package/templates/runtime/react/controls-panel/__tests__/controls-panel.font-picker.test.tsx +302 -0
  93. package/templates/runtime/react/controls-panel/__tests__/controls-panel.footer-actions.test.tsx +401 -0
  94. package/templates/runtime/react/controls-panel/__tests__/controls-panel.gradient-control.test.tsx +139 -0
  95. package/templates/runtime/react/controls-panel/__tests__/controls-panel.help-policy.test.tsx +103 -0
  96. package/templates/runtime/react/controls-panel/__tests__/controls-panel.image-picker.test.tsx +16 -0
  97. package/templates/runtime/react/controls-panel/__tests__/controls-panel.inline-layout.test.tsx +290 -0
  98. package/templates/runtime/react/controls-panel/__tests__/controls-panel.keyframes.test.tsx +175 -0
  99. package/templates/runtime/react/controls-panel/__tests__/controls-panel.media-upload-files.test.tsx +121 -0
  100. package/templates/runtime/react/controls-panel/__tests__/controls-panel.media-upload-image.test.tsx +363 -0
  101. package/templates/runtime/react/controls-panel/__tests__/controls-panel.media-upload-multi-image.test.tsx +105 -0
  102. package/templates/runtime/react/controls-panel/__tests__/controls-panel.range-slider-editing.test.tsx +149 -0
  103. package/templates/runtime/react/controls-panel/__tests__/controls-panel.section-shell.test.tsx +138 -0
  104. package/templates/runtime/react/controls-panel/__tests__/controls-panel.select-layout.test.tsx +148 -0
  105. package/templates/runtime/react/controls-panel/__tests__/controls-panel.setup-controls.test.tsx +189 -0
  106. package/templates/runtime/react/controls-panel/__tests__/controls-panel.slider-rendering.test.tsx +317 -0
  107. package/templates/runtime/react/controls-panel/__tests__/controls-panel.state-reset.test.tsx +137 -0
  108. package/templates/runtime/react/controls-panel/__tests__/controls-panel.structure.test.tsx +66 -0
  109. package/templates/runtime/react/controls-panel/__tests__/controls-panel.text-input.test.tsx +205 -0
  110. package/templates/runtime/react/controls-panel/__tests__/controls-panel.vector-interaction.test.tsx +388 -0
  111. package/templates/runtime/react/controls-panel/__tests__/controls-panel.vector-layout.test.tsx +155 -0
  112. package/templates/runtime/react/controls-panel/actions/controls-panel-actions.ts +172 -0
  113. package/templates/runtime/react/{control-conditions.ts → controls-panel/conditions/control-conditions.ts} +26 -3
  114. package/templates/runtime/react/{control-renderers.ts → controls-panel/control-renderers.ts} +2 -2
  115. package/templates/runtime/react/controls-panel/controls-panel.tsx +250 -0
  116. package/templates/runtime/react/controls-panel/keyframes/controls-panel-keyframes.tsx +265 -0
  117. package/templates/runtime/react/controls-panel/layout/controls-panel-collapse-storage.ts +131 -0
  118. package/templates/runtime/react/controls-panel/layout/controls-panel-help.tsx +132 -0
  119. package/templates/runtime/react/controls-panel/layout/controls-panel-inline-layout.tsx +311 -0
  120. package/templates/runtime/react/controls-panel/layout/controls-panel-layout.tsx +216 -0
  121. package/templates/runtime/react/controls-panel/layout/controls-panel-section.tsx +401 -0
  122. package/templates/runtime/react/controls-panel/renderers/controls-panel-action-renderer.tsx +137 -0
  123. package/templates/runtime/react/controls-panel/renderers/controls-panel-basic-renderers.tsx +421 -0
  124. package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-renderer.tsx +286 -0
  125. package/templates/runtime/react/controls-panel/renderers/controls-panel-compound-renderers.tsx +366 -0
  126. package/templates/runtime/react/controls-panel/renderers/controls-panel-media-renderer.tsx +173 -0
  127. package/templates/runtime/react/controls-panel/renderers/controls-panel-renderer-registry.test.ts +23 -0
  128. package/templates/runtime/react/controls-panel/renderers/controls-panel-renderer-registry.ts +55 -0
  129. package/templates/runtime/react/controls-panel/renderers/controls-panel-settings-transfer-renderer.tsx +45 -0
  130. package/templates/runtime/react/controls-panel/testing/controls-panel-test-utils.tsx +300 -0
  131. package/templates/runtime/react/controls-panel/values/controls-panel-aspect-ratio-values.ts +94 -0
  132. package/templates/runtime/react/controls-panel/values/controls-panel-collection-values.ts +87 -0
  133. package/templates/runtime/react/controls-panel/values/controls-panel-color-values.ts +82 -0
  134. package/templates/runtime/react/controls-panel/values/controls-panel-font-values.ts +69 -0
  135. package/templates/runtime/react/controls-panel/values/controls-panel-spatial-values.ts +64 -0
  136. package/templates/runtime/react/controls-panel/values/controls-panel-value-labels.ts +93 -0
  137. package/templates/runtime/react/controls-panel/values/controls-panel-value-primitives.ts +30 -0
  138. package/templates/runtime/react/controls-panel/values/controls-panel-values.ts +7 -0
  139. package/templates/runtime/react/index.ts +13 -13
  140. package/templates/runtime/react/{layer-tree.ts → layers/layer-tree.ts} +1 -1
  141. package/templates/runtime/react/layers/layers-panel-drag-drop.test.tsx +190 -0
  142. package/templates/runtime/react/layers/layers-panel-editing.test.tsx +41 -0
  143. package/templates/runtime/react/layers/layers-panel-insert-targets.test.ts +87 -0
  144. package/templates/runtime/react/layers/layers-panel-insert-targets.ts +254 -0
  145. package/templates/runtime/react/layers/layers-panel-model.ts +15 -0
  146. package/templates/runtime/react/layers/layers-panel-rendering.test.tsx +43 -0
  147. package/templates/runtime/react/layers/layers-panel-reorder.ts +148 -0
  148. package/templates/runtime/react/layers/layers-panel-row.tsx +475 -0
  149. package/templates/runtime/react/layers/layers-panel-test-utils.tsx +135 -0
  150. package/templates/runtime/react/layers/layers-panel-visibility.test.tsx +126 -0
  151. package/templates/runtime/react/layers/layers-panel.tsx +349 -0
  152. package/templates/runtime/react/layers/use-layers-panel-drag-controller.ts +327 -0
  153. package/templates/runtime/react/{panel-host-types.ts → panel-host/panel-host-types.ts} +2 -2
  154. package/templates/runtime/react/{panel-host.test.tsx → panel-host/panel-host.test.tsx} +3 -3
  155. package/templates/runtime/react/{panel-host.tsx → panel-host/panel-host.tsx} +1 -1
  156. package/templates/runtime/react/timeline/timeline-easing-editor.tsx +409 -0
  157. package/templates/runtime/react/timeline/timeline-easing-geometry.ts +42 -0
  158. package/templates/runtime/react/timeline/timeline-easing-icons.tsx +135 -0
  159. package/templates/runtime/react/timeline/timeline-easing-model.test.ts +87 -0
  160. package/templates/runtime/react/timeline/timeline-easing-model.ts +271 -0
  161. package/templates/runtime/react/timeline/timeline-easing-popover-content.tsx +227 -0
  162. package/templates/runtime/react/timeline/timeline-easing-popover-layout.ts +69 -0
  163. package/templates/runtime/react/timeline/timeline-easing-popover.tsx +60 -0
  164. package/templates/runtime/react/timeline/timeline-event-targets.ts +19 -0
  165. package/templates/runtime/react/timeline/timeline-expanded-content.tsx +299 -0
  166. package/templates/runtime/react/timeline/timeline-icon-button.tsx +51 -0
  167. package/templates/runtime/react/timeline/timeline-keyframe-row.tsx +360 -0
  168. package/templates/runtime/react/timeline/timeline-keyframes.ts +23 -0
  169. package/templates/runtime/react/timeline/timeline-panel-floating-layout.test.tsx +328 -0
  170. package/templates/runtime/react/timeline/timeline-panel-header.tsx +404 -0
  171. package/templates/runtime/react/timeline/timeline-panel-keyframes.test.tsx +90 -0
  172. package/templates/runtime/react/timeline/timeline-panel-layout.ts +30 -0
  173. package/templates/runtime/react/timeline/timeline-panel-responsive-layout.ts +182 -0
  174. package/templates/runtime/react/timeline/timeline-panel-test-utils.tsx +88 -0
  175. package/templates/runtime/react/timeline/timeline-panel-transport.test.tsx +202 -0
  176. package/templates/runtime/react/timeline/timeline-panel-upload.test.tsx +53 -0
  177. package/templates/runtime/react/timeline/timeline-panel.tsx +449 -0
  178. package/templates/runtime/react/timeline/timeline-playback-hooks.ts +254 -0
  179. package/templates/runtime/schema/assembly-contract.ts +271 -0
  180. package/templates/runtime/schema/control-schema-normalization.ts +55 -0
  181. package/templates/runtime/schema/controls-panel-actions.ts +141 -0
  182. package/templates/runtime/schema/controls-panel-layout-groups.ts +144 -0
  183. package/templates/runtime/schema/controls-panel-normalization.ts +19 -0
  184. package/templates/runtime/schema/controls-panel-section-layout.ts +140 -0
  185. package/templates/runtime/schema/controls-panel-section-titles.ts +161 -0
  186. package/templates/runtime/schema/define-toolcraft-test-utils.ts +18 -0
  187. package/templates/runtime/schema/define-toolcraft.actions.test.ts +182 -0
  188. package/templates/runtime/schema/define-toolcraft.assembly.test.ts +246 -0
  189. package/templates/runtime/schema/define-toolcraft.canvas.test.ts +150 -0
  190. package/templates/runtime/schema/define-toolcraft.control-layout.test.ts +345 -0
  191. package/templates/runtime/schema/define-toolcraft.control-sections.test.ts +304 -0
  192. package/templates/runtime/schema/define-toolcraft.setup-canvas.test.ts +69 -0
  193. package/templates/runtime/schema/define-toolcraft.setup-persistence.test.ts +66 -0
  194. package/templates/runtime/schema/define-toolcraft.setup-render-scale-timeline.test.ts +116 -0
  195. package/templates/runtime/schema/define-toolcraft.setup-settings-transfer.test.ts +291 -0
  196. package/templates/runtime/schema/define-toolcraft.ts +24 -1449
  197. package/templates/runtime/schema/panels-schema-normalization.ts +49 -0
  198. package/templates/runtime/schema/runtime-section-titles.ts +1 -0
  199. package/templates/runtime/schema/runtime-setup-section.ts +282 -0
  200. package/templates/runtime/schema/schema-resolvers.ts +168 -0
  201. package/templates/runtime/schema/types.ts +17 -0
  202. package/templates/runtime/state/canvas-reducer.ts +106 -0
  203. package/templates/runtime/state/canvas-state.ts +209 -0
  204. package/templates/runtime/state/controls-reducer.ts +277 -0
  205. package/templates/runtime/state/history-patches.ts +174 -0
  206. package/templates/runtime/state/layer-state.ts +12 -0
  207. package/templates/runtime/state/layers-reducer.ts +318 -0
  208. package/templates/runtime/state/media-reducer.ts +283 -0
  209. package/templates/runtime/state/media-state.ts +105 -0
  210. package/templates/runtime/state/panels-reducer.ts +58 -0
  211. package/templates/runtime/state/persistence-merge.ts +53 -0
  212. package/templates/runtime/state/persistence-reader-canvas.ts +27 -0
  213. package/templates/runtime/state/persistence-reader-layers.ts +73 -0
  214. package/templates/runtime/state/persistence-reader-media.ts +82 -0
  215. package/templates/runtime/state/persistence-reader-panels.ts +56 -0
  216. package/templates/runtime/state/persistence-reader-primitives.ts +27 -0
  217. package/templates/runtime/state/persistence-reader-timeline.ts +145 -0
  218. package/templates/runtime/state/persistence-reader-values.ts +40 -0
  219. package/templates/runtime/state/persistence-readers.ts +72 -0
  220. package/templates/runtime/state/persistence-shared.ts +23 -0
  221. package/templates/runtime/state/persistence-snapshot.ts +57 -0
  222. package/templates/runtime/state/persistence.ts +16 -581
  223. package/templates/runtime/state/reducer-canvas-panels.test.ts +324 -0
  224. package/templates/runtime/state/reducer-controls.test.ts +158 -0
  225. package/templates/runtime/state/reducer-layers.test.ts +306 -0
  226. package/templates/runtime/state/reducer-media-import-sizing.test.ts +197 -0
  227. package/templates/runtime/state/reducer-media-reorder-history.test.ts +116 -0
  228. package/templates/runtime/state/reducer-media-reset.test.ts +249 -0
  229. package/templates/runtime/state/reducer-media-test-utils.ts +40 -0
  230. package/templates/runtime/state/reducer-media-transform.test.ts +52 -0
  231. package/templates/runtime/state/reducer-test-utils.ts +30 -0
  232. package/templates/runtime/state/reducer-timeline.test.ts +242 -0
  233. package/templates/runtime/state/reducer.ts +57 -1785
  234. package/templates/runtime/state/timeline-reducer.ts +412 -0
  235. package/templates/runtime/state/timeline-values.test.ts +45 -0
  236. package/templates/runtime/state/timeline-values.ts +45 -0
  237. package/templates/runtime/testing/performance-browser-policy.test.ts +81 -0
  238. package/templates/runtime/testing/performance-browser-policy.ts +102 -0
  239. package/templates/runtime/testing/performance-budget-validation.ts +84 -0
  240. package/templates/runtime/testing/performance-control-classification.test.ts +106 -0
  241. package/templates/runtime/testing/performance-control-classification.ts +101 -0
  242. package/templates/runtime/testing/performance-coverage-context.ts +44 -0
  243. package/templates/runtime/testing/performance-coverage-renderer-policy.ts +221 -0
  244. package/templates/runtime/testing/performance-coverage-scenario-policy.ts +147 -0
  245. package/templates/runtime/testing/performance-coverage-target-policy.ts +121 -0
  246. package/templates/runtime/testing/performance-coverage-validator.ts +34 -0
  247. package/templates/runtime/testing/performance-export-coverage.test.ts +234 -0
  248. package/templates/runtime/testing/performance-fixture-load-profile.test.ts +360 -0
  249. package/templates/runtime/testing/performance-fixture-media.test.ts +80 -0
  250. package/templates/runtime/testing/performance-fixture-stress.test.ts +314 -0
  251. package/templates/runtime/testing/performance-fixture-validation.ts +255 -0
  252. package/templates/runtime/testing/performance-fixture-values.ts +275 -0
  253. package/templates/runtime/testing/performance-fixture-workload.test.ts +140 -0
  254. package/templates/runtime/testing/performance-load-profile-validation.ts +467 -0
  255. package/templates/runtime/testing/performance-renderer-coverage.test.ts +325 -0
  256. package/templates/runtime/testing/performance-renderer-pipeline-coverage.test.ts +115 -0
  257. package/templates/runtime/testing/performance-renderer-pipeline-interactions.test.ts +201 -0
  258. package/templates/runtime/testing/performance-renderer-pipeline-passes.test.ts +247 -0
  259. package/templates/runtime/testing/performance-renderer-pipeline-validation.ts +360 -0
  260. package/templates/runtime/testing/performance-renderer-technique-validation.ts +329 -0
  261. package/templates/runtime/testing/performance-renderer-technique.test.ts +275 -0
  262. package/templates/runtime/testing/performance-renderer-validation.ts +2 -0
  263. package/templates/runtime/testing/performance-scenario-coverage.test.ts +303 -0
  264. package/templates/runtime/testing/performance-scenario-validation.ts +49 -0
  265. package/templates/runtime/testing/performance-schema-derived-workloads.test.ts +231 -0
  266. package/templates/runtime/testing/performance-schema-queries.ts +181 -0
  267. package/templates/runtime/testing/performance-test-fixtures/index.ts +4 -0
  268. package/templates/runtime/testing/performance-test-fixtures/renderer-pipelines.ts +322 -0
  269. package/templates/runtime/testing/performance-test-fixtures/scenarios.ts +172 -0
  270. package/templates/runtime/testing/performance-test-fixtures/schemas.ts +151 -0
  271. package/templates/runtime/testing/performance-test-fixtures/stress-fixtures.ts +133 -0
  272. package/templates/runtime/testing/performance-test-fixtures.ts +1 -0
  273. package/templates/runtime/testing/performance-types.ts +338 -0
  274. package/templates/runtime/testing/performance.ts +15 -2485
  275. package/templates/starter/AGENTS.md +41 -26
  276. package/templates/starter/LICENSE.md +18 -95
  277. package/templates/starter/NOTICE.md +3 -3
  278. package/templates/starter/docs/toolcraft/README.md +5 -5
  279. package/templates/starter/docs/toolcraft/acceptance-testing.md +36 -8
  280. package/templates/starter/docs/toolcraft/assembly-workflow.md +12 -15
  281. package/templates/starter/docs/toolcraft/component-rules.md +6 -2
  282. package/templates/starter/docs/toolcraft/core/layout.md +1 -0
  283. package/templates/starter/docs/toolcraft/core/performance.md +7 -4
  284. package/templates/starter/docs/toolcraft/core/runtime-boundary.md +11 -4
  285. package/templates/starter/docs/toolcraft/core/timeline-animation.md +1 -0
  286. package/templates/starter/docs/toolcraft/custom-controls.md +8 -1
  287. package/templates/starter/docs/toolcraft/decision-contract.md +26 -22
  288. package/templates/starter/docs/toolcraft/performance.md +42 -16
  289. package/templates/starter/docs/toolcraft/schema-reference.md +34 -23
  290. package/templates/starter/docs/toolcraft/workflow.md +25 -17
  291. package/templates/starter/e2e/app-browser-acceptance-evidence.spec.ts +111 -0
  292. package/templates/starter/e2e/app-browser-control-coverage.spec.ts +118 -0
  293. package/templates/starter/e2e/app-browser-performance-evidence.spec.ts +217 -0
  294. package/templates/starter/e2e/app-browser-performance-probe.spec.ts +322 -0
  295. package/templates/starter/e2e/app-browser-proof-session.spec.ts +196 -0
  296. package/templates/starter/e2e/app-browser-runtime-evidence.spec.ts +9 -0
  297. package/templates/starter/e2e/app-browser-runtime-provenance.spec.ts +240 -0
  298. package/templates/starter/e2e/app-browser-runtime-reporter.spec.ts +180 -0
  299. package/templates/starter/e2e/app-browser-runtime-requirements.spec.ts +310 -0
  300. package/templates/starter/e2e/app-browser-semantic-evidence.spec.ts +432 -0
  301. package/templates/starter/e2e/app-browser-shell.spec.ts +171 -0
  302. package/templates/starter/e2e/app-browser-timeline-layers-reference.spec.ts +70 -0
  303. package/templates/starter/e2e/app-performance.spec.ts +0 -491
  304. package/templates/starter/e2e/browser-acceptance-outcome-helpers.ts +97 -0
  305. package/templates/starter/e2e/browser-acceptance-transition-helpers.ts +74 -0
  306. package/templates/starter/e2e/browser-conditional-output-evidence-helpers.ts +230 -0
  307. package/templates/starter/e2e/browser-control-target-helpers.ts +109 -0
  308. package/templates/starter/e2e/browser-layer-evidence-helpers.ts +229 -0
  309. package/templates/starter/e2e/browser-proof-session.ts +392 -0
  310. package/templates/starter/e2e/browser-runtime-evidence-reporter.ts +136 -0
  311. package/templates/starter/e2e/browser-runtime-evidence-requirements.ts +290 -0
  312. package/templates/starter/e2e/browser-runtime-evidence.ts +27 -0
  313. package/templates/starter/e2e/browser-state-evidence-helpers.ts +205 -0
  314. package/templates/starter/e2e/browser-timeline-evidence-helpers.ts +319 -0
  315. package/templates/starter/e2e/canvas-handle-helpers.ts +86 -4
  316. package/templates/starter/e2e/export-artifact-helpers.ts +132 -0
  317. package/templates/starter/e2e/performance-budget-helpers.ts +159 -0
  318. package/templates/starter/e2e/performance-canvas-helpers.ts +123 -0
  319. package/templates/starter/e2e/performance-control-helpers.ts +3 -0
  320. package/templates/starter/e2e/performance-control-layout-helpers.ts +161 -0
  321. package/templates/starter/e2e/performance-fixture-helpers.ts +217 -0
  322. package/templates/starter/e2e/performance-frame-probe.ts +247 -0
  323. package/templates/starter/e2e/performance-helpers.ts +6 -854
  324. package/templates/starter/e2e/performance-interaction-measurement.ts +251 -0
  325. package/templates/starter/e2e/performance-measurement-evidence.ts +72 -0
  326. package/templates/starter/e2e/performance-output-action-helpers.spec.ts +43 -0
  327. package/templates/starter/e2e/performance-output-action-helpers.ts +109 -0
  328. package/templates/starter/e2e/performance-probe-helpers.ts +12 -0
  329. package/templates/starter/e2e/performance-render-scale-helpers.ts +55 -0
  330. package/templates/starter/e2e/performance-slider-helpers.ts +271 -0
  331. package/templates/starter/e2e/product-observable-helpers.ts +72 -17
  332. package/templates/starter/e2e/stable-outcome-helpers.ts +208 -0
  333. package/templates/starter/package.json +10 -5
  334. package/templates/starter/playwright.config.ts +5 -2
  335. package/templates/starter/scripts/check-ai-skills.mjs +14 -8
  336. package/templates/starter/scripts/check-ai-skills.test.mjs +64 -0
  337. package/templates/starter/scripts/check-toolcraft-code-health.mjs +108 -0
  338. package/templates/starter/scripts/check-toolcraft-code-health.test.mjs +213 -0
  339. package/templates/starter/scripts/check-toolcraft-docs.mjs +47 -34
  340. package/templates/starter/scripts/check-toolcraft-integrity.mjs +141 -144
  341. package/templates/starter/scripts/run-browser-performance.mjs +118 -0
  342. package/templates/starter/scripts/run-browser-performance.test.mjs +53 -0
  343. package/templates/starter/scripts/toolcraft-code-health-core.mjs +297 -0
  344. package/templates/starter/scripts/toolcraft-contract-doc-integrity.mjs +77 -0
  345. package/templates/starter/scripts/toolcraft-contract-doc-integrity.test.mjs +81 -0
  346. package/templates/starter/scripts/toolcraft-contract-manifest.json +113 -0
  347. package/templates/starter/scripts/toolcraft-contract-manifest.mjs +128 -0
  348. package/templates/starter/scripts/toolcraft-contract-manifest.test.mjs +72 -0
  349. package/templates/starter/scripts/toolcraft-integrity-manifest.mjs +172 -0
  350. package/templates/starter/scripts/toolcraft-integrity-policy.mjs +60 -0
  351. package/templates/starter/scripts/toolcraft-product-boundary-ast-utils.mjs +23 -0
  352. package/templates/starter/scripts/toolcraft-product-boundary-ast.mjs +264 -0
  353. package/templates/starter/scripts/toolcraft-product-boundary-test-fixtures.mjs +16 -0
  354. package/templates/starter/scripts/toolcraft-product-boundary.mjs +243 -0
  355. package/templates/starter/scripts/toolcraft-product-boundary.test.mjs +289 -0
  356. package/templates/starter/scripts/toolcraft-product-dependency-graph.mjs +176 -0
  357. package/templates/starter/scripts/toolcraft-product-dependency-graph.test.mjs +196 -0
  358. package/templates/starter/scripts/toolcraft-product-dependency-resolution.mjs +279 -0
  359. package/templates/starter/scripts/toolcraft-product-evidence-boundary-ast.mjs +91 -0
  360. package/templates/starter/scripts/toolcraft-product-evidence-boundary.test.mjs +138 -0
  361. package/templates/starter/scripts/toolcraft-product-style-boundary.mjs +219 -0
  362. package/templates/starter/scripts/toolcraft-source-inventory.d.mts +46 -0
  363. package/templates/starter/scripts/toolcraft-source-inventory.mjs +187 -0
  364. package/templates/starter/scripts/toolcraft-source-inventory.test.mjs +132 -0
  365. package/templates/starter/scripts/toolcraft-source-ownership.mjs +167 -0
  366. package/templates/starter/scripts/toolcraft-source-ownership.test.mjs +113 -0
  367. package/templates/starter/scripts/toolcraft-static-string.mjs +104 -0
  368. package/templates/starter/scripts/toolcraft-verification-inventory.mjs +123 -0
  369. package/templates/starter/scripts/toolcraft-verification-receipt.d.mts +19 -0
  370. package/templates/starter/scripts/toolcraft-verification-receipt.mjs +284 -0
  371. package/templates/starter/scripts/toolcraft-verification-receipt.test.mjs +282 -0
  372. package/templates/starter/scripts/toolcraft-vitest-runtime-contract.d.mts +32 -0
  373. package/templates/starter/scripts/toolcraft-vitest-runtime-contract.mjs +88 -0
  374. package/templates/starter/scripts/toolcraft-vitest-runtime-contract.test.mjs +87 -0
  375. package/templates/starter/scripts/toolcraft-vitest-runtime-evidence-reporter.mjs +109 -0
  376. package/templates/starter/scripts/toolcraft-vitest-runtime-evidence-reporter.test.mjs +111 -0
  377. package/templates/starter/scripts/toolcraft-workflow-routes.mjs +314 -0
  378. package/templates/starter/scripts/toolcraft-workflow-routes.test.mjs +204 -0
  379. package/templates/starter/src/app/acceptance/actions.ts +30 -0
  380. package/templates/starter/src/app/acceptance/animation-intent.ts +184 -0
  381. package/templates/starter/src/app/acceptance/canvas-handle-acceptance.ts +70 -0
  382. package/templates/starter/src/app/acceptance/color-bank-labels.ts +164 -0
  383. package/templates/starter/src/app/acceptance/conditions.ts +80 -0
  384. package/templates/starter/src/app/acceptance/control-acceptance-context.ts +70 -0
  385. package/templates/starter/src/app/acceptance/control-acceptance-coverage.ts +271 -0
  386. package/templates/starter/src/app/acceptance/control-acceptance-kind-rules.ts +149 -0
  387. package/templates/starter/src/app/acceptance/control-acceptance-policy.ts +189 -0
  388. package/templates/starter/src/app/acceptance/control-acceptance.ts +70 -0
  389. package/templates/starter/src/app/acceptance/control-component-rules.ts +277 -0
  390. package/templates/starter/src/app/acceptance/control-labels.ts +223 -0
  391. package/templates/starter/src/app/acceptance/control-layout-dependency-rules.ts +107 -0
  392. package/templates/starter/src/app/acceptance/control-layout-entity-rules.ts +104 -0
  393. package/templates/starter/src/app/acceptance/control-layout-model.ts +159 -0
  394. package/templates/starter/src/app/acceptance/control-layout-section-rules.ts +164 -0
  395. package/templates/starter/src/app/acceptance/control-layout.ts +45 -0
  396. package/templates/starter/src/app/acceptance/control-order.ts +123 -0
  397. package/templates/starter/src/app/acceptance/control-parts.ts +47 -0
  398. package/templates/starter/src/app/acceptance/control-section-inventory.ts +183 -0
  399. package/templates/starter/src/app/acceptance/controls.ts +27 -0
  400. package/templates/starter/src/app/acceptance/coverage.ts +81 -0
  401. package/templates/starter/src/app/acceptance/custom-controls.ts +140 -0
  402. package/templates/starter/src/app/acceptance/inline-layout.ts +192 -0
  403. package/templates/starter/src/app/acceptance/media-upload.ts +55 -0
  404. package/templates/starter/src/app/acceptance/output-background-rules.ts +135 -0
  405. package/templates/starter/src/app/acceptance/output-export-actions.test.ts +76 -0
  406. package/templates/starter/src/app/acceptance/output-export-actions.ts +34 -0
  407. package/templates/starter/src/app/acceptance/output-export-layout-rules.ts +46 -0
  408. package/templates/starter/src/app/acceptance/output-export-model.ts +146 -0
  409. package/templates/starter/src/app/acceptance/output-export.ts +45 -0
  410. package/templates/starter/src/app/acceptance/output-image-export-rules.ts +87 -0
  411. package/templates/starter/src/app/acceptance/reference-runtime-coverage.ts +96 -0
  412. package/templates/starter/src/app/acceptance/reference-runtime-feature-inventory.ts +171 -0
  413. package/templates/starter/src/app/acceptance/reference-runtime-study.ts +73 -0
  414. package/templates/starter/src/app/acceptance/reference-runtime-timeline.ts +291 -0
  415. package/templates/starter/src/app/acceptance/reference-runtime.ts +99 -0
  416. package/templates/starter/src/app/acceptance/runtime-coverage.ts +290 -0
  417. package/templates/starter/src/app/acceptance/runtime-setup.ts +117 -0
  418. package/templates/starter/src/app/acceptance/section-title-rules.ts +8 -0
  419. package/templates/starter/src/app/acceptance/sections.ts +6 -0
  420. package/templates/starter/src/app/acceptance/semantic.ts +63 -0
  421. package/templates/starter/src/app/acceptance/timeline-loop.ts +21 -0
  422. package/templates/starter/src/app/acceptance/types.ts +363 -0
  423. package/templates/starter/src/app/acceptance/validate-coverage.ts +217 -0
  424. package/templates/starter/src/app/acceptance/validation-pipeline.test.ts +56 -0
  425. package/templates/starter/src/app/acceptance/validation-pipeline.ts +60 -0
  426. package/templates/starter/src/app/acceptance/video-reference-study.ts +217 -0
  427. package/templates/starter/src/app/starter-acceptance-data.ts +21 -0
  428. package/templates/starter/src/app/starter-acceptance.animation-intent.test.ts +383 -0
  429. package/templates/starter/src/app/starter-acceptance.background-export.test.ts +349 -0
  430. package/templates/starter/src/app/starter-acceptance.base-coverage.test.ts +47 -0
  431. package/templates/starter/src/app/starter-acceptance.canvas-handles.test.ts +71 -0
  432. package/templates/starter/src/app/starter-acceptance.canvas-sizing.test.ts +199 -0
  433. package/templates/starter/src/app/starter-acceptance.compound-part-coverage.test.ts +244 -0
  434. package/templates/starter/src/app/starter-acceptance.contract-fixtures.ts +63 -0
  435. package/templates/starter/src/app/starter-acceptance.control-label-context.test.ts +172 -0
  436. package/templates/starter/src/app/starter-acceptance.control-labels.test.ts +387 -0
  437. package/templates/starter/src/app/starter-acceptance.control-naming-rules.test.ts +215 -0
  438. package/templates/starter/src/app/starter-acceptance.control-order.test.ts +274 -0
  439. package/templates/starter/src/app/starter-acceptance.control-state.test.ts +275 -0
  440. package/templates/starter/src/app/starter-acceptance.curves-rules.test.ts +184 -0
  441. package/templates/starter/src/app/starter-acceptance.custom-control-collections.test.ts +200 -0
  442. package/templates/starter/src/app/starter-acceptance.custom-control-coverage.test.ts +111 -0
  443. package/templates/starter/src/app/starter-acceptance.custom-control-fit-check.test.ts +135 -0
  444. package/templates/starter/src/app/starter-acceptance.custom-control-valid.test.ts +74 -0
  445. package/templates/starter/src/app/starter-acceptance.export-test-utils.ts +107 -0
  446. package/templates/starter/src/app/starter-acceptance.framework-boundary.test.ts +327 -0
  447. package/templates/starter/src/app/starter-acceptance.image-video-export-settings.test.ts +328 -0
  448. package/templates/starter/src/app/starter-acceptance.keyframes.test.ts +242 -0
  449. package/templates/starter/src/app/starter-acceptance.layers.test.ts +203 -0
  450. package/templates/starter/src/app/starter-acceptance.media-upload.fixtures.ts +110 -0
  451. package/templates/starter/src/app/starter-acceptance.media-upload.test.ts +153 -0
  452. package/templates/starter/src/app/starter-acceptance.output-export-rules.test.ts +97 -0
  453. package/templates/starter/src/app/starter-acceptance.persistence-coverage.test.ts +134 -0
  454. package/templates/starter/src/app/starter-acceptance.product-output-export.test.ts +202 -0
  455. package/templates/starter/src/app/starter-acceptance.product-readiness-rules.test.ts +14 -0
  456. package/templates/starter/src/app/starter-acceptance.product-readiness-test-utils.ts +25 -0
  457. package/templates/starter/src/app/starter-acceptance.product-readiness.test.ts +50 -0
  458. package/templates/starter/src/app/starter-acceptance.product-worklog.test.ts +27 -0
  459. package/templates/starter/src/app/starter-acceptance.range-slider-rules.test.ts +147 -0
  460. package/templates/starter/src/app/starter-acceptance.reference-custom-timeline.test.ts +197 -0
  461. package/templates/starter/src/app/starter-acceptance.reference-foundation.test.ts +304 -0
  462. package/templates/starter/src/app/starter-acceptance.reference-test-utils.ts +102 -0
  463. package/templates/starter/src/app/starter-acceptance.reference-timeline.test.ts +267 -0
  464. package/templates/starter/src/app/starter-acceptance.schema-test-utils.ts +116 -0
  465. package/templates/starter/src/app/starter-acceptance.section-cohesion.test.ts +373 -0
  466. package/templates/starter/src/app/starter-acceptance.section-dependencies.test.ts +260 -0
  467. package/templates/starter/src/app/starter-acceptance.section-titles.test.ts +180 -0
  468. package/templates/starter/src/app/starter-acceptance.setup-readiness.test.ts +205 -0
  469. package/templates/starter/src/app/starter-acceptance.slider-rules.test.ts +470 -0
  470. package/templates/starter/src/app/starter-acceptance.slider-unit-rules.test.ts +61 -0
  471. package/templates/starter/src/app/starter-acceptance.source-test-utils.ts +43 -0
  472. package/templates/starter/src/app/starter-acceptance.test-utils.ts +21 -0
  473. package/templates/starter/src/app/starter-acceptance.text-control-kind.test.ts +89 -0
  474. package/templates/starter/src/app/starter-acceptance.timeline-playback.test.ts +264 -0
  475. package/templates/starter/src/app/starter-acceptance.timeline-test-utils.ts +56 -0
  476. package/templates/starter/src/app/starter-acceptance.toggle-pair-layout.test.ts +200 -0
  477. package/templates/starter/src/app/starter-acceptance.toggle-parameter-layout.test.ts +277 -0
  478. package/templates/starter/src/app/starter-acceptance.ts +151 -4576
  479. package/templates/starter/src/app/starter-acceptance.video-export-test-utils.ts +37 -0
  480. package/templates/starter/src/app/starter-acceptance.video-reference-study.test.ts +262 -0
  481. package/templates/starter/src/app/starter-acceptance.worklog-test-utils.ts +428 -0
  482. package/templates/starter/src/app/starter-acceptance.worklog.test.ts +283 -0
  483. package/templates/starter/src/app/starter-automated-runtime-evidence.test.ts +34 -0
  484. package/templates/starter/src/app/starter-composition.tsx +7 -0
  485. package/templates/starter/src/app/starter-performance-test-utils.ts +275 -0
  486. package/templates/starter/src/app/starter-performance.budgets.test.ts +374 -0
  487. package/templates/starter/src/app/starter-performance.gates.test.ts +128 -0
  488. package/templates/starter/src/app/starter-performance.renderer-source.test.ts +136 -0
  489. package/templates/starter/src/app/starter-performance.renderer-technique.test.ts +291 -0
  490. package/templates/starter/src/app/starter-performance.scenarios.test.ts +355 -0
  491. package/templates/starter/src/app/test-evidence/browser-runtime-contract.test.ts +253 -0
  492. package/templates/starter/src/app/test-evidence/browser-runtime-contract.ts +243 -0
  493. package/templates/starter/src/routes/index.tsx +11 -2
  494. package/templates/starter/vite.config.ts +8 -0
  495. package/templates/ui/components/controls/color/color-control-types.ts +38 -0
  496. package/templates/ui/components/controls/color/color-control.tsx +19 -437
  497. package/templates/ui/components/controls/color/color-footer.tsx +272 -0
  498. package/templates/ui/components/controls/color/color-model-slider.tsx +271 -0
  499. package/templates/ui/components/controls/color/color-opacity-input.tsx +94 -0
  500. package/templates/ui/components/controls/color/color-surface.tsx +194 -0
  501. package/templates/ui/components/controls/color/color-value-control.tsx +159 -0
  502. package/templates/ui/components/controls/color/color-value-utils.ts +170 -0
  503. package/templates/ui/components/controls/color/index.ts +10 -3
  504. package/templates/ui/components/controls/color/palette-control-controller.ts +407 -0
  505. package/templates/ui/components/controls/color/palette-control-layout.ts +14 -0
  506. package/templates/ui/components/controls/color/palette-control-types.ts +50 -0
  507. package/templates/ui/components/controls/color/palette-control-view.tsx +174 -0
  508. package/templates/ui/components/controls/color/palette-control.tsx +6 -544
  509. package/templates/ui/components/controls/color/style-guide-color-picker-color-utils.ts +39 -0
  510. package/templates/ui/components/controls/color/style-guide-color-picker-controller.ts +370 -0
  511. package/templates/ui/components/controls/color/style-guide-color-picker-hue-handlers.ts +66 -0
  512. package/templates/ui/components/controls/color/style-guide-color-picker-interaction-state.ts +49 -0
  513. package/templates/ui/components/controls/color/style-guide-color-picker-interactions.ts +2 -2
  514. package/templates/ui/components/controls/color/style-guide-color-picker-model.ts +125 -0
  515. package/templates/ui/components/controls/color/style-guide-color-picker-parts.tsx +10 -707
  516. package/templates/ui/components/controls/color/style-guide-color-picker-surface-drag.ts +93 -0
  517. package/templates/ui/components/controls/color/style-guide-color-picker-surface-geometry.ts +114 -0
  518. package/templates/ui/components/controls/color/style-guide-color-picker-surface-preview.ts +45 -0
  519. package/templates/ui/components/controls/color/style-guide-color-picker-types.ts +84 -0
  520. package/templates/ui/components/controls/color/style-guide-color-picker-view.tsx +69 -0
  521. package/templates/ui/components/controls/color/style-guide-color-picker.tsx +6 -495
  522. package/templates/ui/components/controls/curves/curves-control.tsx +4 -3
  523. package/templates/ui/components/controls/file-drop/file-drop-control.tsx +39 -515
  524. package/templates/ui/components/controls/file-drop/file-drop-empty-state.tsx +35 -0
  525. package/templates/ui/components/controls/file-drop/file-drop-file-list.tsx +160 -0
  526. package/templates/ui/components/controls/file-drop/file-drop-image-grid.tsx +175 -0
  527. package/templates/ui/components/controls/file-drop/file-drop-model.tsx +170 -0
  528. package/templates/ui/components/controls/file-drop/file-drop-single-preview.tsx +63 -0
  529. package/templates/ui/components/controls/file-drop/file-drop-types.ts +48 -0
  530. package/templates/ui/components/controls/file-drop/index.ts +2 -2
  531. package/templates/ui/components/controls/font-picker/font-picker-control.tsx +133 -906
  532. package/templates/ui/components/controls/font-picker/font-picker-footer.tsx +116 -0
  533. package/templates/ui/components/controls/font-picker/font-picker-list.tsx +194 -0
  534. package/templates/ui/components/controls/font-picker/font-picker-popover-content.tsx +191 -0
  535. package/templates/ui/components/controls/font-picker/font-picker-value.ts +222 -0
  536. package/templates/ui/components/controls/font-picker/index.ts +4 -1
  537. package/templates/ui/components/controls/font-picker/use-font-picker-preview-pipeline.ts +163 -0
  538. package/templates/ui/components/controls/font-picker/use-font-picker-virtual-list.ts +293 -0
  539. package/templates/ui/components/controls/gradient/gradient-control-utils.ts +2 -25
  540. package/templates/ui/components/controls/gradient/gradient-control.tsx +4 -464
  541. package/templates/ui/components/controls/gradient/gradient-stops-controller.ts +332 -0
  542. package/templates/ui/components/controls/gradient/gradient-stops-track.tsx +159 -0
  543. package/templates/ui/components/controls/vector/vector-control-types.ts +26 -0
  544. package/templates/ui/components/controls/vector/vector-control.tsx +10 -486
  545. package/templates/ui/components/controls/vector/vector-pad-field.tsx +211 -0
  546. package/templates/ui/components/controls/vector/vector-pad-geometry.ts +61 -0
  547. package/templates/ui/components/controls/vector/vector-pad-parts.tsx +72 -0
  548. package/templates/ui/components/controls/vector/vector-pad-variants.ts +20 -0
  549. package/templates/ui/components/controls/vector/vector-size-field.tsx +104 -0
  550. package/templates/ui/components/controls/vector/vector-value.ts +46 -0
  551. package/templates/ui/components/primitives/slider/slider-discrete-state.ts +181 -0
  552. package/templates/ui/components/primitives/slider/slider-marker-policy.ts +52 -0
  553. package/templates/ui/components/primitives/slider/slider-pointer-dragging.ts +87 -0
  554. package/templates/ui/components/primitives/slider/slider-runtime.ts +109 -0
  555. package/templates/ui/components/primitives/slider/slider-types.ts +21 -0
  556. package/templates/ui/components/primitives/slider/slider.tsx +2 -403
  557. package/templates/runtime/react/canvas-shell.test.tsx +0 -554
  558. package/templates/runtime/react/canvas-shell.tsx +0 -585
  559. package/templates/runtime/react/controls-panel.test.tsx +0 -5446
  560. package/templates/runtime/react/controls-panel.tsx +0 -3220
  561. package/templates/runtime/react/layers-panel.test.tsx +0 -487
  562. package/templates/runtime/react/layers-panel.tsx +0 -1348
  563. package/templates/runtime/react/timeline-panel.test.tsx +0 -751
  564. package/templates/runtime/react/timeline-panel.tsx +0 -3078
  565. package/templates/runtime/schema/define-toolcraft.test.ts +0 -1742
  566. package/templates/runtime/state/reducer.test.ts +0 -1703
  567. package/templates/runtime/testing/performance.test.ts +0 -3081
  568. package/templates/starter/e2e/app-browser-acceptance.spec.ts +0 -785
  569. package/templates/starter/src/app/starter-acceptance.test.ts +0 -10068
  570. package/templates/starter/src/app/starter-performance.test.ts +0 -1583
  571. package/templates/ui/components/controls/color/style-guide-color-picker-logic.ts +0 -490
  572. /package/templates/runtime/react/{storage-key-migration.ts → app-shell/storage-key-migration.ts} +0 -0
  573. /package/templates/runtime/react/{theme-runtime.tsx → app-shell/theme-runtime.tsx} +0 -0
  574. /package/templates/runtime/react/{curve-geometry.test.ts → controls-panel/__tests__/curve-geometry.test.ts} +0 -0
  575. /package/templates/runtime/react/{panel-host-config.ts → panel-host/panel-host-config.ts} +0 -0
  576. /package/templates/runtime/react/{panel-host-geometry.test.ts → panel-host/panel-host-geometry.test.ts} +0 -0
  577. /package/templates/runtime/react/{panel-host-geometry.ts → panel-host/panel-host-geometry.ts} +0 -0
@@ -0,0 +1,284 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs/promises";
4
+ import path from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import {
7
+ assertToolcraftVerificationInputsUnchanged,
8
+ collectToolcraftVerificationInputs,
9
+ createToolcraftVerificationSourceHash,
10
+ } from "./toolcraft-verification-inventory.mjs";
11
+
12
+ export {
13
+ assertToolcraftVerificationInputsUnchanged,
14
+ collectToolcraftVerificationInputs,
15
+ };
16
+
17
+ export const TOOLCRAFT_PERFORMANCE_RECEIPT_VERSION = 1;
18
+ export const TOOLCRAFT_PERFORMANCE_EXEMPTION_REASON =
19
+ "post-first-working-non-performance";
20
+
21
+ const acceptedRunners = new Set(["playwright-fallback"]);
22
+ const performanceExemptionBlockedRootFiles = new Set([
23
+ "index.html",
24
+ "npm-shrinkwrap.json",
25
+ "package-lock.json",
26
+ "package.json",
27
+ "playwright.config.ts",
28
+ "pnpm-lock.yaml",
29
+ "tsconfig.json",
30
+ "vite.config.ts",
31
+ ]);
32
+ const performanceSensitivePathPattern =
33
+ /(?:^|[/_.-])(?:animation|canvas|exports?|images?|keyframes?|layers?|media|outputs?|performance|renders?|renderers?|rendering|shaders?|timeline|uploads?|videos?|viewport|webgl|workers?)(?=$|[/_.-])/u;
34
+
35
+ function compareCodeUnits(left, right) {
36
+ return left < right ? -1 : left > right ? 1 : 0;
37
+ }
38
+
39
+ function toPosixPath(value) {
40
+ return value.split(path.sep).join("/");
41
+ }
42
+
43
+ export function getToolcraftPerformanceReceiptPath(rootDir) {
44
+ return path.join(
45
+ path.resolve(rootDir),
46
+ ".toolcraft",
47
+ "verification",
48
+ "performance.json",
49
+ );
50
+ }
51
+
52
+ async function writeReceipt(rootDir, receipt) {
53
+ const receiptPath = getToolcraftPerformanceReceiptPath(rootDir);
54
+ await fs.mkdir(path.dirname(receiptPath), { recursive: true });
55
+ const temporaryPath = `${receiptPath}.${process.pid}.tmp`;
56
+ await fs.writeFile(temporaryPath, `${JSON.stringify(receipt, null, 2)}\n`);
57
+ await fs.rename(temporaryPath, receiptPath);
58
+ return receipt;
59
+ }
60
+
61
+ export async function clearToolcraftPerformanceReceipt(rootDir) {
62
+ await fs.rm(getToolcraftPerformanceReceiptPath(rootDir), { force: true });
63
+ }
64
+
65
+ function isReceiptFileEntry(value) {
66
+ if (
67
+ typeof value !== "object" ||
68
+ value === null ||
69
+ typeof value.path !== "string" ||
70
+ typeof value.sha256 !== "string"
71
+ ) {
72
+ return false;
73
+ }
74
+ const pathSegments = value.path.split("/");
75
+ return (
76
+ value.path.length > 0 &&
77
+ !value.path.includes("\\") &&
78
+ !path.posix.isAbsolute(value.path) &&
79
+ !pathSegments.some(
80
+ (segment) => segment === "" || segment === "." || segment === "..",
81
+ ) &&
82
+ /^[a-f0-9]{64}$/u.test(value.sha256)
83
+ );
84
+ }
85
+
86
+ function getReceiptInventoryError(receipt) {
87
+ const uniquePaths = new Set(receipt.files.map((entry) => entry.path));
88
+ if (uniquePaths.size !== receipt.files.length) {
89
+ return "Toolcraft performance receipt file inventory contains duplicate paths.";
90
+ }
91
+ if (createToolcraftVerificationSourceHash(receipt.files) !== receipt.sourceHash) {
92
+ return "Toolcraft performance receipt file inventory does not produce its source hash.";
93
+ }
94
+ return undefined;
95
+ }
96
+
97
+ function getReceiptShapeError(receipt) {
98
+ if (
99
+ typeof receipt !== "object" ||
100
+ receipt === null ||
101
+ Array.isArray(receipt) ||
102
+ receipt.version !== TOOLCRAFT_PERFORMANCE_RECEIPT_VERSION ||
103
+ typeof receipt.sourceHash !== "string" ||
104
+ !Array.isArray(receipt.files) ||
105
+ !receipt.files.every(isReceiptFileEntry)
106
+ ) {
107
+ return "Toolcraft performance receipt is malformed or uses an unsupported version.";
108
+ }
109
+ if (receipt.status !== "passed" && receipt.status !== "not-required") {
110
+ return "Toolcraft performance receipt must record a passed checkpoint or typed not-required exemption.";
111
+ }
112
+ if (receipt.kind === "performance-checkpoint") {
113
+ if (receipt.status !== "passed" || !acceptedRunners.has(receipt.runner)) {
114
+ return "Toolcraft performance checkpoint receipt must be passed and name a supported runner.";
115
+ }
116
+ return getReceiptInventoryError(receipt);
117
+ }
118
+ if (receipt.kind === "performance-exemption") {
119
+ if (
120
+ receipt.status !== "not-required" ||
121
+ receipt.reasonCode !== TOOLCRAFT_PERFORMANCE_EXEMPTION_REASON ||
122
+ ![0, 1, 2].includes(receipt.verificationTier) ||
123
+ typeof receipt.baselineSourceHash !== "string" ||
124
+ !Array.isArray(receipt.changedFiles) ||
125
+ !receipt.changedFiles.every((item) => typeof item === "string")
126
+ ) {
127
+ return "Toolcraft performance exemption receipt is malformed.";
128
+ }
129
+ return getReceiptInventoryError(receipt);
130
+ }
131
+ return "Toolcraft performance receipt kind is unsupported.";
132
+ }
133
+
134
+ async function readReceipt(rootDir) {
135
+ const receiptPath = getToolcraftPerformanceReceiptPath(rootDir);
136
+ let source;
137
+ try {
138
+ source = await fs.readFile(receiptPath, "utf8");
139
+ } catch (error) {
140
+ if (error?.code === "ENOENT") return { missing: true };
141
+ throw error;
142
+ }
143
+ try {
144
+ return { receipt: JSON.parse(source) };
145
+ } catch {
146
+ return { malformed: true };
147
+ }
148
+ }
149
+
150
+ export async function validateToolcraftPerformanceReceipt({ rootDir }) {
151
+ const loaded = await readReceipt(rootDir);
152
+ if (loaded.missing) {
153
+ return [
154
+ "Toolcraft performance receipt is missing. Run the required browser performance checkpoint for the current sources.",
155
+ ];
156
+ }
157
+ if (loaded.malformed) {
158
+ return ["Toolcraft performance receipt is malformed JSON."];
159
+ }
160
+
161
+ const shapeError = getReceiptShapeError(loaded.receipt);
162
+ if (shapeError) return [shapeError];
163
+
164
+ const inventory = await collectToolcraftVerificationInputs(rootDir);
165
+ if (loaded.receipt.sourceHash !== inventory.sourceHash) {
166
+ return [
167
+ "Toolcraft performance receipt is stale because product or verification inputs changed after the recorded checkpoint.",
168
+ ];
169
+ }
170
+ return [];
171
+ }
172
+
173
+ function getChangedFiles(previousFiles, currentFiles) {
174
+ const previous = new Map(previousFiles.map((entry) => [entry.path, entry.sha256]));
175
+ const current = new Map(currentFiles.map((entry) => [entry.path, entry.sha256]));
176
+ return [...new Set([...previous.keys(), ...current.keys()])]
177
+ .filter((filePath) => previous.get(filePath) !== current.get(filePath))
178
+ .sort(compareCodeUnits);
179
+ }
180
+
181
+ function blocksToolcraftPerformanceExemption(filePath) {
182
+ const normalizedPath = toPosixPath(filePath).replace(/^\.\//u, "").toLowerCase();
183
+
184
+ return (
185
+ performanceExemptionBlockedRootFiles.has(normalizedPath) ||
186
+ normalizedPath.startsWith("public/") ||
187
+ normalizedPath.startsWith("scripts/") ||
188
+ normalizedPath.startsWith("src/toolcraft/") ||
189
+ /^src\/app\/app-composition\.[^/]+$/u.test(normalizedPath) ||
190
+ performanceSensitivePathPattern.test(normalizedPath)
191
+ );
192
+ }
193
+
194
+ export function getToolcraftPerformanceExemptionBlockedFiles(changedFiles) {
195
+ return [...new Set(changedFiles.filter(blocksToolcraftPerformanceExemption))].sort(
196
+ compareCodeUnits,
197
+ );
198
+ }
199
+
200
+ export async function writeToolcraftPerformanceExemption({
201
+ reasonCode,
202
+ rootDir,
203
+ verificationTier,
204
+ }) {
205
+ if (reasonCode !== TOOLCRAFT_PERFORMANCE_EXEMPTION_REASON) {
206
+ throw new Error(
207
+ `Toolcraft performance exemption reason must be ${TOOLCRAFT_PERFORMANCE_EXEMPTION_REASON}.`,
208
+ );
209
+ }
210
+ if (![0, 1, 2].includes(verificationTier)) {
211
+ throw new Error("Toolcraft performance exemptions are limited to verification tiers 0, 1, or 2.");
212
+ }
213
+ const loaded = await readReceipt(rootDir);
214
+ const shapeError = loaded.receipt ? getReceiptShapeError(loaded.receipt) : undefined;
215
+ if (
216
+ !loaded.receipt ||
217
+ shapeError ||
218
+ loaded.receipt.kind !== "performance-checkpoint" ||
219
+ loaded.receipt.status !== "passed"
220
+ ) {
221
+ throw new Error(
222
+ "A typed performance exemption requires a prior passed performance checkpoint receipt.",
223
+ );
224
+ }
225
+
226
+ const inventory = await collectToolcraftVerificationInputs(rootDir);
227
+ const changedFiles = getChangedFiles(loaded.receipt.files, inventory.entries);
228
+ if (changedFiles.length === 0) {
229
+ throw new Error("A performance exemption requires at least one changed verification input.");
230
+ }
231
+ const blockedFiles = getToolcraftPerformanceExemptionBlockedFiles(changedFiles);
232
+ if (blockedFiles.length > 0) {
233
+ throw new Error(
234
+ `A performance exemption cannot cover Tier 3 or Tier 4 changes: ${blockedFiles.join(", ")}. Run pnpm verify:perf for the current sources.`,
235
+ );
236
+ }
237
+ return writeReceipt(rootDir, {
238
+ baselineSourceHash: loaded.receipt.sourceHash,
239
+ changedFiles,
240
+ completedAt: new Date().toISOString(),
241
+ files: inventory.entries,
242
+ kind: "performance-exemption",
243
+ reasonCode,
244
+ sourceHash: inventory.sourceHash,
245
+ status: "not-required",
246
+ verificationTier,
247
+ version: TOOLCRAFT_PERFORMANCE_RECEIPT_VERSION,
248
+ });
249
+ }
250
+
251
+ async function runCli() {
252
+ const projectDir = path.resolve(
253
+ path.dirname(fileURLToPath(import.meta.url)),
254
+ "..",
255
+ );
256
+ const [command = "validate", ...args] = process.argv.slice(2);
257
+
258
+ if (command === "record-exemption") {
259
+ const tierArgument = args.find((argument) => argument.startsWith("--tier="));
260
+ const verificationTier = Number(tierArgument?.slice("--tier=".length));
261
+ await writeToolcraftPerformanceExemption({
262
+ reasonCode: TOOLCRAFT_PERFORMANCE_EXEMPTION_REASON,
263
+ rootDir: projectDir,
264
+ verificationTier,
265
+ });
266
+ console.log("Recorded current-source Toolcraft post-first-working performance exemption.");
267
+ return;
268
+ }
269
+ if (command !== "validate") {
270
+ throw new Error(`Unknown Toolcraft verification receipt command: ${command}.`);
271
+ }
272
+ const errors = await validateToolcraftPerformanceReceipt({ rootDir: projectDir });
273
+ if (errors.length > 0) {
274
+ throw new Error(errors.join("\n"));
275
+ }
276
+ console.log("Toolcraft performance receipt is current and valid.");
277
+ }
278
+
279
+ if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
280
+ runCli().catch((error) => {
281
+ console.error(error instanceof Error ? error.message : error);
282
+ process.exitCode = 1;
283
+ });
284
+ }
@@ -0,0 +1,282 @@
1
+ import assert from "node:assert/strict";
2
+ import fs from "node:fs/promises";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import test from "node:test";
6
+
7
+ import {
8
+ TOOLCRAFT_PERFORMANCE_RECEIPT_VERSION,
9
+ collectToolcraftVerificationInputs,
10
+ getToolcraftPerformanceExemptionBlockedFiles,
11
+ getToolcraftPerformanceReceiptPath,
12
+ validateToolcraftPerformanceReceipt,
13
+ writeToolcraftPerformanceExemption,
14
+ } from "./toolcraft-verification-receipt.mjs";
15
+ import * as receiptModule from "./toolcraft-verification-receipt.mjs";
16
+
17
+ async function createFixture() {
18
+ const rootDir = await fs.mkdtemp(path.join(os.tmpdir(), "toolcraft-receipt-"));
19
+ await fs.mkdir(path.join(rootDir, "src", "app"), { recursive: true });
20
+ await fs.mkdir(path.join(rootDir, "e2e"), { recursive: true });
21
+ await fs.writeFile(
22
+ path.join(rootDir, "src", "app", "app-schema.ts"),
23
+ 'export const schema = { mode: "initial" };\n',
24
+ );
25
+ await fs.writeFile(
26
+ path.join(rootDir, "e2e", "app-performance.spec.ts"),
27
+ 'export const scenario = "heavy";\n',
28
+ );
29
+ await fs.writeFile(
30
+ path.join(rootDir, "package.json"),
31
+ JSON.stringify({ name: "receipt-fixture", private: true }),
32
+ );
33
+ return rootDir;
34
+ }
35
+
36
+ async function writePassedCheckpointFixture(
37
+ rootDir,
38
+ { runner = "playwright-fallback" } = {},
39
+ ) {
40
+ const inventory = await collectToolcraftVerificationInputs(rootDir);
41
+ const receiptPath = getToolcraftPerformanceReceiptPath(rootDir);
42
+ await fs.mkdir(path.dirname(receiptPath), { recursive: true });
43
+ await fs.writeFile(
44
+ receiptPath,
45
+ `${JSON.stringify(
46
+ {
47
+ completedAt: new Date().toISOString(),
48
+ files: inventory.entries,
49
+ kind: "performance-checkpoint",
50
+ runner,
51
+ sourceHash: inventory.sourceHash,
52
+ status: "passed",
53
+ version: TOOLCRAFT_PERFORMANCE_RECEIPT_VERSION,
54
+ },
55
+ null,
56
+ 2,
57
+ )}\n`,
58
+ );
59
+ }
60
+
61
+ test("does not expose a reusable passed-checkpoint writer", () => {
62
+ assert.equal("writeToolcraftPerformanceReceipt" in receiptModule, false);
63
+ });
64
+
65
+ test("rejects verification inputs that change during a protected checkpoint", () => {
66
+ const assertStable = receiptModule.assertToolcraftVerificationInputsUnchanged;
67
+ assert.equal(typeof assertStable, "function");
68
+ assert.doesNotThrow(() =>
69
+ assertStable({
70
+ baseline: { entries: [], sourceHash: "same" },
71
+ current: { entries: [], sourceHash: "same" },
72
+ phase: "after build",
73
+ }),
74
+ );
75
+ assert.throws(
76
+ () =>
77
+ assertStable({
78
+ baseline: { entries: [], sourceHash: "before" },
79
+ current: { entries: [], sourceHash: "after" },
80
+ phase: "after Playwright",
81
+ }),
82
+ /verification inputs changed.*after Playwright/iu,
83
+ );
84
+ });
85
+
86
+ test("classifies obvious Tier 3 and Tier 4 paths without blocking ordinary Tier 0-2 files", () => {
87
+ assert.deepEqual(
88
+ getToolcraftPerformanceExemptionBlockedFiles([
89
+ "src/app/app-schema.ts",
90
+ "src/app/app-acceptance-data.ts",
91
+ "src/app/app-schema.test.ts",
92
+ "src/product/control-mapping.ts",
93
+ "e2e/app-controls.spec.ts",
94
+ "src/styles/panel.module.css",
95
+ "package-lock.json",
96
+ "public/source.png",
97
+ "scripts/check.mjs",
98
+ "src/toolcraft/runtime.ts",
99
+ "src/app/app-composition.tsx",
100
+ "src/app/app-performance.ts",
101
+ "src/product/product-output.ts",
102
+ "src/product/renderer.ts",
103
+ "src/product/canvas-worker.ts",
104
+ "src/product/viewport.ts",
105
+ ]),
106
+ [
107
+ "package-lock.json",
108
+ "public/source.png",
109
+ "scripts/check.mjs",
110
+ "src/app/app-composition.tsx",
111
+ "src/app/app-performance.ts",
112
+ "src/product/canvas-worker.ts",
113
+ "src/product/product-output.ts",
114
+ "src/product/renderer.ts",
115
+ "src/product/viewport.ts",
116
+ "src/toolcraft/runtime.ts",
117
+ ],
118
+ );
119
+ });
120
+
121
+ test("requires a structured receipt instead of prose-only performance claims", async (t) => {
122
+ const rootDir = await createFixture();
123
+ t.after(() => fs.rm(rootDir, { force: true, recursive: true }));
124
+ await fs.mkdir(path.join(rootDir, "docs", "toolcraft"), { recursive: true });
125
+ await fs.writeFile(
126
+ path.join(rootDir, "docs", "toolcraft", "agent-worklog.md"),
127
+ "- Run: pnpm verify:perf passed\n",
128
+ );
129
+
130
+ const errors = await validateToolcraftPerformanceReceipt({ rootDir });
131
+ assert.equal(errors.length, 1);
132
+ assert.match(errors[0], /performance receipt is missing/iu);
133
+ });
134
+
135
+ test("accepts a passed receipt only while its source inventory is current", async (t) => {
136
+ const rootDir = await createFixture();
137
+ t.after(() => fs.rm(rootDir, { force: true, recursive: true }));
138
+ await writePassedCheckpointFixture(rootDir);
139
+
140
+ assert.deepEqual(await validateToolcraftPerformanceReceipt({ rootDir }), []);
141
+
142
+ await fs.writeFile(
143
+ path.join(rootDir, "src", "app", "app-schema.ts"),
144
+ 'export const schema = { mode: "changed" };\n',
145
+ );
146
+ const staleErrors = await validateToolcraftPerformanceReceipt({ rootDir });
147
+ assert.equal(staleErrors.length, 1);
148
+ assert.match(staleErrors[0], /stale/iu);
149
+ });
150
+
151
+ test("rejects manual agent-browser receipts without automated runner proof", async (t) => {
152
+ const rootDir = await createFixture();
153
+ t.after(() => fs.rm(rootDir, { force: true, recursive: true }));
154
+ await writePassedCheckpointFixture(rootDir, { runner: "agent-browser" });
155
+
156
+ assert.match(
157
+ (await validateToolcraftPerformanceReceipt({ rootDir }))[0],
158
+ /supported runner/iu,
159
+ );
160
+ });
161
+
162
+ test("rejects a receipt whose file inventory does not produce its source hash", async (t) => {
163
+ const rootDir = await createFixture();
164
+ t.after(() => fs.rm(rootDir, { force: true, recursive: true }));
165
+ const inventory = await collectToolcraftVerificationInputs(rootDir);
166
+ const receiptPath = getToolcraftPerformanceReceiptPath(rootDir);
167
+ await fs.mkdir(path.dirname(receiptPath), { recursive: true });
168
+ await fs.writeFile(
169
+ receiptPath,
170
+ `${JSON.stringify(
171
+ {
172
+ completedAt: new Date().toISOString(),
173
+ files: [],
174
+ kind: "performance-checkpoint",
175
+ runner: "playwright-fallback",
176
+ sourceHash: inventory.sourceHash,
177
+ status: "passed",
178
+ version: TOOLCRAFT_PERFORMANCE_RECEIPT_VERSION,
179
+ },
180
+ null,
181
+ 2,
182
+ )}\n`,
183
+ );
184
+
185
+ assert.match(
186
+ (await validateToolcraftPerformanceReceipt({ rootDir }))[0],
187
+ /file inventory.*source hash/iu,
188
+ );
189
+ });
190
+
191
+ test("invalidates a checkpoint when the npm dependency graph changes", async (t) => {
192
+ const rootDir = await createFixture();
193
+ t.after(() => fs.rm(rootDir, { force: true, recursive: true }));
194
+ const packageLockPath = path.join(rootDir, "package-lock.json");
195
+ await fs.writeFile(
196
+ packageLockPath,
197
+ JSON.stringify({ lockfileVersion: 3, packages: {} }),
198
+ );
199
+ await writePassedCheckpointFixture(rootDir);
200
+
201
+ await fs.writeFile(
202
+ packageLockPath,
203
+ JSON.stringify({
204
+ lockfileVersion: 3,
205
+ packages: { "node_modules/example": { version: "2.0.0" } },
206
+ }),
207
+ );
208
+
209
+ assert.match(
210
+ (await validateToolcraftPerformanceReceipt({ rootDir }))[0],
211
+ /stale/iu,
212
+ );
213
+ });
214
+
215
+ test("rejects malformed and non-passed receipts", async (t) => {
216
+ const rootDir = await createFixture();
217
+ t.after(() => fs.rm(rootDir, { force: true, recursive: true }));
218
+ const receiptPath = getToolcraftPerformanceReceiptPath(rootDir);
219
+ await fs.mkdir(path.dirname(receiptPath), { recursive: true });
220
+ await fs.writeFile(receiptPath, "not json");
221
+ const malformedErrors = await validateToolcraftPerformanceReceipt({ rootDir });
222
+ assert.equal(malformedErrors.length, 1);
223
+ assert.match(malformedErrors[0], /malformed/iu);
224
+
225
+ await fs.writeFile(
226
+ receiptPath,
227
+ JSON.stringify({
228
+ kind: "performance-checkpoint",
229
+ files: [],
230
+ runner: "playwright-fallback",
231
+ sourceHash: "invalid",
232
+ status: "failed",
233
+ version: 1,
234
+ }),
235
+ );
236
+ const failedErrors = await validateToolcraftPerformanceReceipt({ rootDir });
237
+ assert.equal(failedErrors.length, 1);
238
+ assert.match(failedErrors[0], /passed/iu);
239
+ });
240
+
241
+ test("permits only a current typed post-first-working exemption backed by a prior pass", async (t) => {
242
+ const rootDir = await createFixture();
243
+ t.after(() => fs.rm(rootDir, { force: true, recursive: true }));
244
+ await writePassedCheckpointFixture(rootDir);
245
+ await fs.writeFile(
246
+ path.join(rootDir, "src", "app", "app-schema.ts"),
247
+ 'export const schema = { mode: "non-performance-feature" };\n',
248
+ );
249
+ await writeToolcraftPerformanceExemption({
250
+ reasonCode: "post-first-working-non-performance",
251
+ rootDir,
252
+ verificationTier: 2,
253
+ });
254
+
255
+ assert.deepEqual(await validateToolcraftPerformanceReceipt({ rootDir }), []);
256
+
257
+ await fs.writeFile(
258
+ path.join(rootDir, "e2e", "app-performance.spec.ts"),
259
+ 'export const scenario = "changed-after-exemption";\n',
260
+ );
261
+ const staleErrors = await validateToolcraftPerformanceReceipt({ rootDir });
262
+ assert.equal(staleErrors.length, 1);
263
+ assert.match(staleErrors[0], /stale/iu);
264
+ });
265
+
266
+ test("rejects exemptions for obvious Tier 3 renderer changes", async (t) => {
267
+ const rootDir = await createFixture();
268
+ t.after(() => fs.rm(rootDir, { force: true, recursive: true }));
269
+ const rendererPath = path.join(rootDir, "src", "product-renderer.ts");
270
+ await fs.writeFile(rendererPath, "export const render = () => 1;\n");
271
+ await writePassedCheckpointFixture(rootDir);
272
+ await fs.writeFile(rendererPath, "export const render = () => 2;\n");
273
+
274
+ await assert.rejects(
275
+ writeToolcraftPerformanceExemption({
276
+ reasonCode: "post-first-working-non-performance",
277
+ rootDir,
278
+ verificationTier: 2,
279
+ }),
280
+ /product-renderer\.ts.*pnpm verify:perf/iu,
281
+ );
282
+ });
@@ -0,0 +1,32 @@
1
+ export type ToolcraftVitestRuntimeRequirement = {
2
+ kind: "acceptance" | "performance";
3
+ requirementId: string;
4
+ testName: string;
5
+ };
6
+
7
+ export type ToolcraftVitestRuntimeTest = {
8
+ expectedFailure: boolean;
9
+ filePath: string;
10
+ name: string;
11
+ owner: "framework" | "product";
12
+ state: "failed" | "passed" | "pending" | "skipped";
13
+ };
14
+
15
+ export const TOOLCRAFT_VITEST_RUNTIME_EVIDENCE_VERSION: 1;
16
+ export const TOOLCRAFT_VITEST_RUNTIME_REQUIREMENTS_ANNOTATION_TYPE: string;
17
+ export const TOOLCRAFT_VITEST_RUNTIME_MARKER_TEST_NAME: string;
18
+ export const TOOLCRAFT_VITEST_RUNTIME_MARKER_FILE_NAMES: readonly string[];
19
+
20
+ export function serializeToolcraftVitestRuntimeRequirements(
21
+ requirements: readonly ToolcraftVitestRuntimeRequirement[],
22
+ ): string;
23
+
24
+ export function parseToolcraftVitestRuntimeRequirements(annotation: {
25
+ message: string;
26
+ type: string;
27
+ }): ToolcraftVitestRuntimeRequirement[] | undefined;
28
+
29
+ export function evaluateToolcraftVitestRuntimeEvidence(input: {
30
+ requirements: readonly ToolcraftVitestRuntimeRequirement[];
31
+ tests: readonly ToolcraftVitestRuntimeTest[];
32
+ }): string[];
@@ -0,0 +1,88 @@
1
+ export const TOOLCRAFT_VITEST_RUNTIME_EVIDENCE_VERSION = 1;
2
+ export const TOOLCRAFT_VITEST_RUNTIME_REQUIREMENTS_ANNOTATION_TYPE =
3
+ "toolcraft.automated-runtime-requirements";
4
+ export const TOOLCRAFT_VITEST_RUNTIME_MARKER_TEST_NAME =
5
+ "toolcraft: validate complete automated runtime coverage";
6
+ export const TOOLCRAFT_VITEST_RUNTIME_MARKER_FILE_NAMES = Object.freeze([
7
+ "starter-automated-runtime-evidence.test.ts",
8
+ "app-automated-runtime-evidence.test.ts",
9
+ ]);
10
+
11
+ export function serializeToolcraftVitestRuntimeRequirements(requirements) {
12
+ return JSON.stringify({
13
+ requirements,
14
+ version: TOOLCRAFT_VITEST_RUNTIME_EVIDENCE_VERSION,
15
+ });
16
+ }
17
+
18
+ export function parseToolcraftVitestRuntimeRequirements(annotation) {
19
+ if (
20
+ !annotation ||
21
+ annotation.type !== TOOLCRAFT_VITEST_RUNTIME_REQUIREMENTS_ANNOTATION_TYPE
22
+ ) {
23
+ return undefined;
24
+ }
25
+
26
+ try {
27
+ const payload = JSON.parse(annotation.message);
28
+ if (
29
+ payload?.version !== TOOLCRAFT_VITEST_RUNTIME_EVIDENCE_VERSION ||
30
+ !Array.isArray(payload.requirements) ||
31
+ payload.requirements.some(
32
+ (requirement) =>
33
+ !requirement ||
34
+ !["acceptance", "performance"].includes(requirement.kind) ||
35
+ typeof requirement.requirementId !== "string" ||
36
+ !requirement.requirementId.trim() ||
37
+ typeof requirement.testName !== "string" ||
38
+ !requirement.testName.trim(),
39
+ )
40
+ ) {
41
+ return undefined;
42
+ }
43
+
44
+ return payload.requirements;
45
+ } catch {
46
+ return undefined;
47
+ }
48
+ }
49
+
50
+ export function evaluateToolcraftVitestRuntimeEvidence({ requirements, tests }) {
51
+ const errors = [];
52
+
53
+ for (const requirement of requirements) {
54
+ const matchingTests = tests.filter(
55
+ (test) =>
56
+ test.owner === "product" && test.name === requirement.testName,
57
+ );
58
+
59
+ if (matchingTests.length === 0) {
60
+ errors.push(
61
+ `Missing required automated test "${requirement.testName}" for ${requirement.kind} requirement "${requirement.requirementId}".`,
62
+ );
63
+ continue;
64
+ }
65
+
66
+ if (matchingTests.length > 1) {
67
+ errors.push(
68
+ `Duplicate required automated test "${requirement.testName}" for ${requirement.kind} requirement "${requirement.requirementId}". Each requirement needs one product-owned test.`,
69
+ );
70
+ continue;
71
+ }
72
+
73
+ const [test] = matchingTests;
74
+ if (test.expectedFailure) {
75
+ errors.push(
76
+ `Required automated test "${requirement.testName}" must not use expected-failure mode in ${test.filePath}.`,
77
+ );
78
+ continue;
79
+ }
80
+ if (test.state !== "passed") {
81
+ errors.push(
82
+ `Required automated test "${requirement.testName}" must finish with status "passed"; received "${test.state}" in ${test.filePath}.`,
83
+ );
84
+ }
85
+ }
86
+
87
+ return errors;
88
+ }