@pixel-point/toolcraft 0.0.16 → 0.0.18

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 (313) hide show
  1. package/package.json +1 -1
  2. package/src/generate-performance-iteration-execution.test.mjs +2 -2
  3. package/src/generate-test-demand-only-lifecycle.mjs +14 -3
  4. package/src/generate-test-dependency-sandbox.mjs +42 -5
  5. package/src/generate-test-doc-assertions.mjs +109 -69
  6. package/src/generate-test-doc-assertions.test.mjs +65 -0
  7. package/src/generate-test-doc-policy-assertions.mjs +92 -0
  8. package/src/generate-test-file-assertions.mjs +36 -118
  9. package/src/generate-test-output-assertions.mjs +95 -0
  10. package/src/generate-test-package-assertions.mjs +6 -0
  11. package/src/generate-test-performance-boundary-assertions.mjs +45 -0
  12. package/src/generate-test-product-fixture.mjs +1 -0
  13. package/src/generate-test-product-fixture.test.mjs +18 -0
  14. package/src/generate-test-product-iteration.mjs +1 -0
  15. package/src/generate-test-product-iteration.test.mjs +18 -0
  16. package/src/generate-test-runtime-boundary-assertions.mjs +158 -0
  17. package/src/generate-test-standalone-assertions.mjs +10 -0
  18. package/src/generate-test-standalone-delivery-stages.mjs +14 -6
  19. package/src/generate.test.mjs +14 -0
  20. package/templates/runtime/contracts/component-contracts.choices.test.ts +59 -12
  21. package/templates/runtime/contracts/component-contracts.choices.ts +58 -12
  22. package/templates/runtime/contracts/component-contracts.inputs.test.ts +6 -6
  23. package/templates/runtime/contracts/component-contracts.inputs.ts +6 -6
  24. package/templates/runtime/contracts/component-contracts.media-custom.test.ts +8 -2
  25. package/templates/runtime/contracts/component-contracts.media-custom.ts +8 -2
  26. package/templates/runtime/contracts/component-contracts.runtime-acceptance.test.ts +21 -6
  27. package/templates/runtime/contracts/component-contracts.runtime-labels.test.ts +7 -1
  28. package/templates/runtime/contracts/component-contracts.runtime-panels.test.ts +4 -1
  29. package/templates/runtime/contracts/component-contracts.runtime-shell.test.ts +4 -1
  30. package/templates/runtime/contracts/component-contracts.runtime.ts +15 -10
  31. package/templates/runtime/contracts/component-contracts.test.ts +2 -0
  32. package/templates/runtime/contracts/decision-contracts.test.ts +43 -4
  33. package/templates/runtime/contracts/decision-contracts.ts +10 -10
  34. package/templates/runtime/contracts/performance-verification-policy.test.ts +59 -6
  35. package/templates/runtime/contracts/performance-verification-policy.ts +5 -2
  36. package/templates/runtime/export/artifact-download.test.ts +71 -0
  37. package/templates/runtime/export/artifact-download.ts +80 -0
  38. package/templates/runtime/export/artifact-export-request.ts +23 -0
  39. package/templates/runtime/export/artifact-export-settings.test.ts +75 -0
  40. package/templates/runtime/export/artifact-export-settings.ts +96 -0
  41. package/templates/runtime/export/artifact-frame-renderer.test.ts +107 -0
  42. package/templates/runtime/export/artifact-frame-renderer.ts +96 -0
  43. package/templates/runtime/export/artifact-frame-state.test.ts +54 -0
  44. package/templates/runtime/export/artifact-frame-state.ts +44 -0
  45. package/templates/runtime/export/artifact-scene-frame.test.ts +84 -0
  46. package/templates/runtime/export/artifact-scene-frame.ts +118 -0
  47. package/templates/runtime/export/export-background.ts +46 -0
  48. package/templates/runtime/export/export-error.ts +43 -0
  49. package/templates/runtime/export/export.test.ts +49 -226
  50. package/templates/runtime/export/image-artifact-export.test.ts +111 -0
  51. package/templates/runtime/export/image-artifact-export.ts +145 -0
  52. package/templates/runtime/export/index.ts +44 -3
  53. package/templates/runtime/export/product-export-renderer.test.ts +77 -0
  54. package/templates/runtime/export/product-export-renderer.ts +63 -0
  55. package/templates/runtime/export/video-artifact-export.test.ts +166 -0
  56. package/templates/runtime/export/video-artifact-export.ts +164 -0
  57. package/templates/runtime/export/video-encoding-backend.ts +124 -0
  58. package/templates/runtime/export/video-encoding-policy.test.ts +68 -0
  59. package/templates/runtime/export/video-encoding-policy.ts +86 -0
  60. package/templates/runtime/export/video-frame-schedule.test.ts +58 -0
  61. package/templates/runtime/export/video-frame-schedule.ts +42 -0
  62. package/templates/runtime/index.ts +3 -0
  63. package/templates/runtime/model-import/model-import-limits.ts +15 -4
  64. package/templates/runtime/react/app-shell/runtime-public-api-runtime.test.tsx +291 -0
  65. package/templates/runtime/react/app-shell/runtime-public-api-test-support.ts +21 -0
  66. package/templates/runtime/react/app-shell/runtime-public-api.test.tsx +15 -304
  67. package/templates/runtime/react/app-shell/toolcraft-app.scene-export.test.tsx +41 -27
  68. package/templates/runtime/react/app-shell/toolcraft-app.tsx +39 -11
  69. package/templates/runtime/react/app-shell/toolcraft-source-asset-context.test.tsx +16 -57
  70. package/templates/runtime/react/app-shell/toolcraft-source-asset-context.tsx +75 -434
  71. package/templates/runtime/react/app-shell/toolcraft-source-asset-owner.test.ts +194 -0
  72. package/templates/runtime/react/app-shell/toolcraft-source-asset-owner.ts +227 -0
  73. package/templates/runtime/react/app-shell/toolcraft-source-asset-provider-ownership.test.tsx +243 -0
  74. package/templates/runtime/react/app-shell/toolcraft-source-asset-test-support.ts +51 -0
  75. package/templates/runtime/react/app-shell/toolcraft-unavailable-resource-proof.test.ts +138 -0
  76. package/templates/runtime/react/app-shell/toolcraft-unavailable-resource-proof.ts +378 -0
  77. package/templates/runtime/react/canvas/canvas-shell-rendering.test.tsx +76 -0
  78. package/templates/runtime/react/canvas/canvas-shell-test-utils.tsx +13 -1
  79. package/templates/runtime/react/canvas/canvas-shell.tsx +16 -1
  80. package/templates/runtime/react/canvas/product-scene-surface.test.tsx +195 -0
  81. package/templates/runtime/react/canvas/product-scene-surface.tsx +155 -0
  82. package/templates/runtime/react/canvas/runtime-scene-export.ts +1 -1
  83. package/templates/runtime/react/controls-panel/__tests__/control-conditions.test.ts +61 -0
  84. package/templates/runtime/react/controls-panel/__tests__/controls-panel.collection-actions.test.tsx +89 -0
  85. package/templates/runtime/react/controls-panel/__tests__/controls-panel.control-visibility.test.tsx +40 -19
  86. package/templates/runtime/react/controls-panel/__tests__/controls-panel.footer-actions.test.tsx +7 -12
  87. package/templates/runtime/react/controls-panel/__tests__/controls-panel.scene-export-actions.test.tsx +18 -84
  88. package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-collection.test.tsx +62 -0
  89. package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-color-bank.test.tsx +67 -0
  90. package/templates/runtime/react/controls-panel/actions/controls-panel-actions.ts +43 -87
  91. package/templates/runtime/react/controls-panel/actions/export-action-runner.ts +68 -0
  92. package/templates/runtime/react/controls-panel/conditions/control-conditions.ts +32 -119
  93. package/templates/runtime/react/controls-panel/layout/controls-panel-control-group.tsx +5 -2
  94. package/templates/runtime/react/controls-panel/layout/controls-panel-layout.tsx +10 -8
  95. package/templates/runtime/react/controls-panel/layout/controls-panel-section.tsx +3 -3
  96. package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-item-fields.test.tsx +63 -0
  97. package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-item-fields.tsx +138 -0
  98. package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-items.tsx +104 -0
  99. package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-renderer.tsx +115 -236
  100. package/templates/runtime/react/controls-panel/renderers/controls-panel-file-drop-item-controls.test.tsx +95 -0
  101. package/templates/runtime/react/controls-panel/renderers/controls-panel-file-drop-item-controls.tsx +82 -0
  102. package/templates/runtime/react/controls-panel/renderers/controls-panel-media-renderer.test.tsx +73 -1
  103. package/templates/runtime/react/controls-panel/renderers/controls-panel-media-renderer.tsx +50 -1
  104. package/templates/runtime/react/controls-panel/renderers/controls-panel-renderer-registry.test.ts +1 -1
  105. package/templates/runtime/react/controls-panel/renderers/controls-panel-renderer-registry.ts +2 -1
  106. package/templates/runtime/react/controls-panel/values/controls-panel-collection-values.ts +38 -6
  107. package/templates/runtime/react/controls-panel/values/controls-panel-value-labels.ts +1 -0
  108. package/templates/runtime/react/index.ts +4 -0
  109. package/templates/runtime/react/model-rendering/model-export.ts +1 -1
  110. package/templates/runtime/react/orientation-gizmo/orientation-gizmo-selection.ts +5 -5
  111. package/templates/runtime/react/orientation-gizmo/use-toolcraft-orientation-control-selection.ts +2 -2
  112. package/templates/runtime/react/panel-host/panel-host-runtime-placement.test.tsx +30 -0
  113. package/templates/runtime/react/panel-host/panel-host.tsx +4 -0
  114. package/templates/runtime/scene/scene-bounds.test.ts +23 -0
  115. package/templates/runtime/scene/scene-bounds.ts +32 -19
  116. package/templates/runtime/schema/app-capabilities.test.ts +4 -0
  117. package/templates/runtime/schema/canvas-render-scale.ts +62 -0
  118. package/templates/runtime/schema/collection-item-controls.ts +29 -0
  119. package/templates/runtime/schema/control-applicability.test.ts +127 -0
  120. package/templates/runtime/schema/control-applicability.ts +433 -0
  121. package/templates/runtime/schema/control-schema-normalization.ts +177 -11
  122. package/templates/runtime/schema/controls-panel-actions.ts +2 -2
  123. package/templates/runtime/schema/controls-panel-section-id.test.ts +1 -1
  124. package/templates/runtime/schema/controls-panel-section-layout.ts +14 -9
  125. package/templates/runtime/schema/controls-panel-section-roundtrip.test.ts +62 -3
  126. package/templates/runtime/schema/define-toolcraft.collection-actions-item-controls.test.ts +127 -0
  127. package/templates/runtime/schema/define-toolcraft.control-sections.test.ts +10 -4
  128. package/templates/runtime/schema/define-toolcraft.file-drop-item-controls.test.ts +98 -0
  129. package/templates/runtime/schema/define-toolcraft.file-drop-normalization.test.ts +27 -0
  130. package/templates/runtime/schema/define-toolcraft.segmented-control-fit.test.ts +20 -2
  131. package/templates/runtime/schema/define-toolcraft.setup-background.test.ts +1 -1
  132. package/templates/runtime/schema/define-toolcraft.setup-canvas.test.ts +16 -3
  133. package/templates/runtime/schema/define-toolcraft.setup-render-scale-timeline.test.ts +71 -3
  134. package/templates/runtime/schema/define-toolcraft.source-collection.test.ts +79 -0
  135. package/templates/runtime/schema/define-toolcraft.ts +1 -1
  136. package/templates/runtime/schema/runtime-setup-section.ts +24 -5
  137. package/templates/runtime/schema/schema-resolvers.ts +0 -56
  138. package/templates/runtime/schema/types.ts +72 -17
  139. package/templates/runtime/state/canvas-background-state.ts +6 -0
  140. package/templates/runtime/testing/performance-render-plan-integration.test.ts +64 -0
  141. package/templates/runtime/testing/performance-renderer-pipeline-validation.ts +18 -1
  142. package/templates/starter/AGENTS.md +18 -15
  143. package/templates/starter/NOTICE.md +6 -0
  144. package/templates/starter/docs/toolcraft/README.md +2 -1
  145. package/templates/starter/docs/toolcraft/acceptance-testing.md +23 -35
  146. package/templates/starter/docs/toolcraft/agent-worklog.md +18 -3
  147. package/templates/starter/docs/toolcraft/assembly-workflow.md +13 -5
  148. package/templates/starter/docs/toolcraft/component-rules.md +8 -6
  149. package/templates/starter/docs/toolcraft/core/control-selection.md +9 -3
  150. package/templates/starter/docs/toolcraft/core/layout.md +7 -7
  151. package/templates/starter/docs/toolcraft/core/media-upload.md +4 -2
  152. package/templates/starter/docs/toolcraft/core/performance.md +14 -3
  153. package/templates/starter/docs/toolcraft/core/runtime-boundary.md +16 -3
  154. package/templates/starter/docs/toolcraft/core/setup-export.md +49 -19
  155. package/templates/starter/docs/toolcraft/core/timeline-animation.md +4 -4
  156. package/templates/starter/docs/toolcraft/custom-controls.md +6 -4
  157. package/templates/starter/docs/toolcraft/decision-contract.md +3 -1
  158. package/templates/starter/docs/toolcraft/performance.md +20 -6
  159. package/templates/starter/docs/toolcraft/renderer-technique.md +5 -1
  160. package/templates/starter/docs/toolcraft/schema-reference.md +23 -25
  161. package/templates/starter/docs/toolcraft/workflow.md +7 -2
  162. package/templates/starter/e2e/app-browser-control-applicability-requirements.spec.ts +163 -0
  163. package/templates/starter/e2e/app-browser-control-coverage.spec.ts +33 -0
  164. package/templates/starter/e2e/app-browser-infinity-canvas-evidence.spec.ts +50 -3
  165. package/templates/starter/e2e/app-browser-orientation-evidence.spec.ts +174 -21
  166. package/templates/starter/e2e/app-browser-render-scale-evidence.spec.ts +60 -6
  167. package/templates/starter/e2e/app-browser-render-scale-requirements.spec.ts +77 -1
  168. package/templates/starter/e2e/app-browser-runtime-provenance.spec.ts +8 -0
  169. package/templates/starter/e2e/app-browser-runtime-reporter.spec.ts +35 -0
  170. package/templates/starter/e2e/app-browser-runtime-requirements.spec.ts +5 -34
  171. package/templates/starter/e2e/app-browser-semantic-evidence.spec.ts +61 -16
  172. package/templates/starter/e2e/app-browser-shell.spec.ts +13 -5
  173. package/templates/starter/e2e/app-performance-path-adapters.ts +8 -1
  174. package/templates/starter/e2e/app-performance.spec.ts +16 -9
  175. package/templates/starter/e2e/{browser-conditional-output-evidence-helpers.ts → browser-background-output-evidence.ts} +0 -68
  176. package/templates/starter/e2e/browser-control-applicability-evidence.ts +114 -0
  177. package/templates/starter/e2e/browser-infinity-canvas-evidence.ts +29 -341
  178. package/templates/starter/e2e/browser-infinity-canvas-unavailable-image-evidence.ts +370 -0
  179. package/templates/starter/e2e/browser-media-export-evidence.spec.ts +77 -0
  180. package/templates/starter/e2e/browser-media-export-evidence.ts +208 -0
  181. package/templates/starter/e2e/browser-orientation-gizmo-evidence-helpers.ts +4 -0
  182. package/templates/starter/e2e/browser-orientation-gizmo-live-preconditions.ts +86 -0
  183. package/templates/starter/e2e/browser-render-scale-evidence.ts +37 -29
  184. package/templates/starter/e2e/browser-runtime-applicability-requirements.ts +84 -0
  185. package/templates/starter/e2e/browser-runtime-evidence-reporter.ts +13 -3
  186. package/templates/starter/e2e/browser-runtime-evidence-requirements.ts +72 -35
  187. package/templates/starter/e2e/browser-semantic-evidence-test-helpers.ts +25 -0
  188. package/templates/starter/e2e/browser-standard-timeline-evidence.ts +106 -0
  189. package/templates/starter/e2e/decoded-pixel-observation.spec.ts +74 -0
  190. package/templates/starter/e2e/decoded-pixel-observation.ts +227 -0
  191. package/templates/starter/e2e/export-artifact-helpers.ts +206 -25
  192. package/templates/starter/e2e/image-artifact-inspection.spec.ts +41 -0
  193. package/templates/starter/e2e/image-artifact-inspection.ts +99 -0
  194. package/templates/starter/e2e/performance-canvas-helpers.ts +22 -21
  195. package/templates/starter/e2e/performance-canvas-quality-guard.spec.ts +312 -0
  196. package/templates/starter/e2e/performance-canvas-quality-guard.ts +196 -0
  197. package/templates/starter/e2e/performance-canvas-quality-observer.ts +351 -0
  198. package/templates/starter/e2e/performance-control-layout-helpers.ts +2 -2
  199. package/templates/starter/e2e/performance-path-adapter-contract.ts +4 -4
  200. package/templates/starter/e2e/performance-path-helpers.spec.ts +203 -70
  201. package/templates/starter/e2e/performance-path-helpers.ts +210 -91
  202. package/templates/starter/e2e/performance-pipeline-evidence-continuity.spec.ts +76 -0
  203. package/templates/starter/e2e/performance-pipeline-evidence-test-fixtures.ts +11 -2
  204. package/templates/starter/e2e/performance-pipeline-invariants.ts +47 -4
  205. package/templates/starter/e2e/performance-render-scale-runner.spec.ts +140 -38
  206. package/templates/starter/e2e/video-artifact-inspection.spec.ts +64 -0
  207. package/templates/starter/e2e/video-artifact-inspection.ts +281 -0
  208. package/templates/starter/gitignore +1 -0
  209. package/templates/starter/package.json +1 -0
  210. package/templates/starter/scripts/check-toolcraft-docs.mjs +17 -0
  211. package/templates/starter/scripts/toolcraft-contract-manifest.json +1 -0
  212. package/templates/starter/scripts/toolcraft-delivery-plan-authority.test.mjs +60 -0
  213. package/templates/starter/scripts/toolcraft-delivery-plan-errors.test.mjs +7 -2
  214. package/templates/starter/scripts/toolcraft-delivery-plan.mjs +7 -3
  215. package/templates/starter/scripts/toolcraft-product-boundary-ast.mjs +95 -103
  216. package/templates/starter/scripts/toolcraft-product-boundary-module-policy.mjs +101 -0
  217. package/templates/starter/scripts/toolcraft-product-boundary.mjs +12 -0
  218. package/templates/starter/scripts/toolcraft-product-boundary.test.mjs +0 -26
  219. package/templates/starter/scripts/toolcraft-product-control-bindings.mjs +182 -0
  220. package/templates/starter/scripts/toolcraft-product-control-boundary.mjs +146 -0
  221. package/templates/starter/scripts/toolcraft-product-control-boundary.test.mjs +186 -0
  222. package/templates/starter/scripts/toolcraft-product-evidence-boundary.test.mjs +85 -20
  223. package/templates/starter/scripts/toolcraft-product-evidence-import-policy.mjs +43 -0
  224. package/templates/starter/scripts/toolcraft-product-export-boundary.mjs +157 -0
  225. package/templates/starter/scripts/toolcraft-product-export-boundary.test.mjs +196 -0
  226. package/templates/starter/scripts/toolcraft-typescript-analysis.d.mts +73 -0
  227. package/templates/starter/scripts/toolcraft-typescript-source-evidence-structure.test.mjs +20 -0
  228. package/templates/starter/scripts/toolcraft-typescript-source-evidence.mjs +1 -0
  229. package/templates/starter/scripts/toolcraft-unavailable-resource-evidence-facade-test-helpers.mjs +318 -0
  230. package/templates/starter/scripts/toolcraft-unavailable-resource-evidence-facade.test.mjs +157 -206
  231. package/templates/starter/scripts/toolcraft-verification-inventory.mjs +1 -0
  232. package/templates/starter/scripts/toolcraft-verification-receipt.test.mjs +51 -0
  233. package/templates/starter/scripts/toolcraft-vite-env-activation.test.mjs +128 -59
  234. package/templates/starter/src/app/acceptance/artifact-export-intent.ts +130 -0
  235. package/templates/starter/src/app/acceptance/conditions.ts +1 -1
  236. package/templates/starter/src/app/acceptance/control-acceptance-context.ts +2 -2
  237. package/templates/starter/src/app/acceptance/control-acceptance-coverage.ts +6 -20
  238. package/templates/starter/src/app/acceptance/control-acceptance-kind-rules.ts +24 -5
  239. package/templates/starter/src/app/acceptance/control-acceptance-policy.ts +2 -13
  240. package/templates/starter/src/app/acceptance/control-applicability-cases.test.ts +321 -0
  241. package/templates/starter/src/app/acceptance/control-applicability-cases.ts +290 -0
  242. package/templates/starter/src/app/acceptance/control-applicability.ts +332 -0
  243. package/templates/starter/src/app/acceptance/control-layout-dependency-rules.ts +20 -9
  244. package/templates/starter/src/app/acceptance/control-layout-entity-rules.ts +4 -6
  245. package/templates/starter/src/app/acceptance/control-layout-model.ts +4 -4
  246. package/templates/starter/src/app/acceptance/control-layout-section-rules.ts +3 -10
  247. package/templates/starter/src/app/acceptance/control-parts.ts +8 -0
  248. package/templates/starter/src/app/acceptance/control-section-entity-cohesion.test.ts +215 -0
  249. package/templates/starter/src/app/acceptance/control-section-entity-cohesion.ts +132 -0
  250. package/templates/starter/src/app/acceptance/control-section-inventory.test.ts +87 -0
  251. package/templates/starter/src/app/acceptance/control-section-inventory.ts +74 -44
  252. package/templates/starter/src/app/acceptance/custom-controls.ts +11 -3
  253. package/templates/starter/src/app/acceptance/export-artifact-coverage.ts +113 -0
  254. package/templates/starter/src/app/acceptance/inline-layout.ts +64 -9
  255. package/templates/starter/src/app/acceptance/media-upload.ts +5 -1
  256. package/templates/starter/src/app/acceptance/orientation-gizmo.ts +18 -11
  257. package/templates/starter/src/app/acceptance/output-background-rules.ts +2 -2
  258. package/templates/starter/src/app/acceptance/output-export-layout-rules.ts +18 -10
  259. package/templates/starter/src/app/acceptance/output-export-model.ts +54 -11
  260. package/templates/starter/src/app/acceptance/output-export.ts +35 -12
  261. package/templates/starter/src/app/acceptance/output-video-export-rules.ts +99 -0
  262. package/templates/starter/src/app/acceptance/types.ts +30 -8
  263. package/templates/starter/src/app/acceptance/validate-coverage.ts +20 -2
  264. package/templates/starter/src/app/starter-acceptance.artifact-export-intent.test.ts +239 -0
  265. package/templates/starter/src/app/starter-acceptance.background-export.test.ts +33 -0
  266. package/templates/starter/src/app/starter-acceptance.canvas-sizing.test.ts +16 -1
  267. package/templates/starter/src/app/starter-acceptance.compound-part-coverage.test.ts +65 -0
  268. package/templates/starter/src/app/starter-acceptance.contract-fixtures.test.ts +41 -0
  269. package/templates/starter/src/app/starter-acceptance.contract-fixtures.ts +112 -16
  270. package/templates/starter/src/app/starter-acceptance.control-applicability.test.ts +224 -0
  271. package/templates/starter/src/app/starter-acceptance.control-order.test.ts +58 -3
  272. package/templates/starter/src/app/starter-acceptance.control-state.test.ts +0 -111
  273. package/templates/starter/src/app/starter-acceptance.custom-control-collections.test.ts +3 -1
  274. package/templates/starter/src/app/starter-acceptance.custom-control-valid.test.ts +1 -1
  275. package/templates/starter/src/app/starter-acceptance.export-artifact.test.ts +131 -0
  276. package/templates/starter/src/app/starter-acceptance.export-test-utils.ts +22 -0
  277. package/templates/starter/src/app/{starter-acceptance.image-video-export-settings.test.ts → starter-acceptance.image-export-settings.test.ts} +37 -9
  278. package/templates/starter/src/app/starter-acceptance.interaction-ownership.test.ts +12 -0
  279. package/templates/starter/src/app/starter-acceptance.keyframes.test.ts +14 -4
  280. package/templates/starter/src/app/starter-acceptance.media-upload.fixtures.ts +11 -1
  281. package/templates/starter/src/app/starter-acceptance.media-upload.test.ts +28 -0
  282. package/templates/starter/src/app/starter-acceptance.output-export-intent.test.ts +384 -0
  283. package/templates/starter/src/app/starter-acceptance.output-export-rules.test.ts +46 -1
  284. package/templates/starter/src/app/starter-acceptance.product-output-export.test.ts +112 -105
  285. package/templates/starter/src/app/starter-acceptance.product-readiness.test.ts +12 -0
  286. package/templates/starter/src/app/starter-acceptance.section-cohesion.test.ts +1 -1
  287. package/templates/starter/src/app/starter-acceptance.section-dependencies.test.ts +35 -24
  288. package/templates/starter/src/app/starter-acceptance.section-size.test.ts +72 -0
  289. package/templates/starter/src/app/starter-acceptance.ts +13 -2
  290. package/templates/starter/src/app/starter-acceptance.video-export-settings.test.ts +336 -0
  291. package/templates/starter/src/app/starter-acceptance.view-interaction.test.ts +8 -0
  292. package/templates/starter/src/app/starter-performance-test-utils.ts +103 -0
  293. package/templates/starter/src/app/starter-performance.gates.test.ts +231 -278
  294. package/templates/starter/src/app/starter-performance.lifecycle.test.ts +261 -0
  295. package/templates/starter/src/app/test-evidence/browser-runtime-contract.ts +4 -2
  296. package/templates/starter/src/routes/index.tsx +2 -0
  297. package/templates/ui/components/composites/tabs.tsx +2 -2
  298. package/templates/ui/components/controls/collection-actions/collection-item-groups.test.tsx +38 -0
  299. package/templates/ui/components/controls/collection-actions/collection-item-groups.tsx +36 -0
  300. package/templates/ui/components/controls/collection-actions/index.ts +2 -0
  301. package/templates/ui/components/controls/file-drop/file-drop-collection-control.tsx +137 -0
  302. package/templates/ui/components/controls/file-drop/file-drop-control.test.tsx +189 -0
  303. package/templates/ui/components/controls/file-drop/file-drop-control.tsx +81 -88
  304. package/templates/ui/components/controls/file-drop/file-drop-presentation.tsx +131 -9
  305. package/templates/ui/components/controls/file-drop/file-drop-types.ts +36 -22
  306. package/templates/ui/components/controls/file-drop/index.ts +1 -0
  307. package/templates/ui/components/controls/index.ts +3 -0
  308. package/templates/ui/components/controls/range-slider/range-slider-control.tsx +1 -1
  309. package/templates/ui/components/controls/range-slider/range-slider-value.test.ts +14 -0
  310. package/templates/ui/components/controls/range-slider/range-slider-value.ts +3 -2
  311. package/templates/runtime/export/export.ts +0 -166
  312. package/templates/starter/src/app/acceptance/condition-exclusivity.test.ts +0 -60
  313. package/templates/starter/src/app/acceptance/condition-exclusivity.ts +0 -221
@@ -0,0 +1,332 @@
1
+ import {
2
+ areToolcraftPredicatesProvablyExclusive,
3
+ areToolcraftValuesEqual,
4
+ doesToolcraftPredicateMatchValue,
5
+ getToolcraftApplicabilityPredicates,
6
+ type ResolvedToolcraftControlSchema,
7
+ type ToolcraftControlPredicateSchema,
8
+ } from "@repo/toolcraft-runtime";
9
+
10
+ import type { ToolcraftAcceptanceValidationContext } from "./validation-pipeline";
11
+
12
+ export type ToolcraftApplicabilitySelectorValue = boolean | number | string;
13
+
14
+ export type ToolcraftApplicabilitySelectorDomain =
15
+ | Readonly<{
16
+ status: "supported";
17
+ values: readonly ToolcraftApplicabilitySelectorValue[];
18
+ }>
19
+ | Readonly<{
20
+ reason: string;
21
+ status: "unsupported";
22
+ }>;
23
+
24
+ const numericOperators = [
25
+ "greaterThan",
26
+ "greaterThanOrEqual",
27
+ "lessThan",
28
+ "lessThanOrEqual",
29
+ ] as const;
30
+
31
+ function addUniqueValue(
32
+ values: ToolcraftApplicabilitySelectorValue[],
33
+ value: unknown,
34
+ ): void {
35
+ if (
36
+ (typeof value === "boolean" ||
37
+ typeof value === "number" ||
38
+ typeof value === "string") &&
39
+ !values.some((existing) => areToolcraftValuesEqual(existing, value))
40
+ ) {
41
+ values.push(value);
42
+ }
43
+ }
44
+
45
+ function getPredicateFiniteValues(
46
+ predicate: ToolcraftControlPredicateSchema,
47
+ ): unknown[] {
48
+ return [
49
+ ...(Object.prototype.hasOwnProperty.call(predicate, "equals")
50
+ ? [predicate.equals]
51
+ : []),
52
+ ...(Object.prototype.hasOwnProperty.call(predicate, "notEquals")
53
+ ? [predicate.notEquals]
54
+ : []),
55
+ ...(predicate.oneOf ?? []),
56
+ ...(predicate.notOneOf ?? []),
57
+ ];
58
+ }
59
+
60
+ function getDiscreteSliderDomain(
61
+ control: ResolvedToolcraftControlSchema,
62
+ predicates: readonly ToolcraftControlPredicateSchema[],
63
+ ): ToolcraftApplicabilitySelectorDomain {
64
+ if (
65
+ control.type !== "slider" ||
66
+ control.variant !== "discrete" ||
67
+ typeof control.min !== "number" ||
68
+ typeof control.max !== "number" ||
69
+ typeof control.step !== "number" ||
70
+ !Number.isFinite(control.min) ||
71
+ !Number.isFinite(control.max) ||
72
+ !Number.isFinite(control.step) ||
73
+ control.max < control.min ||
74
+ control.step <= 0
75
+ ) {
76
+ return {
77
+ reason: `${control.target} is not a bounded discrete scalar slider`,
78
+ status: "unsupported",
79
+ };
80
+ }
81
+
82
+ const { max, min, step } = control;
83
+ const candidates: number[] = [];
84
+ const clampAligned = (value: number): number => {
85
+ const clamped = Math.min(max, Math.max(min, value));
86
+ const stepIndex = Math.round((clamped - min) / step);
87
+ const aligned = Math.min(max, Math.max(min, min + stepIndex * step));
88
+ return Number(aligned.toFixed(12));
89
+ };
90
+ const addCandidate = (value: unknown): void => {
91
+ if (typeof value !== "number" || !Number.isFinite(value)) {
92
+ return;
93
+ }
94
+
95
+ for (const candidate of [value - step, value, value + step]) {
96
+ const aligned = clampAligned(candidate);
97
+
98
+ if (!candidates.includes(aligned)) {
99
+ candidates.push(aligned);
100
+ }
101
+ }
102
+ };
103
+
104
+ addCandidate(min);
105
+ addCandidate(max);
106
+ addCandidate(control.defaultValue);
107
+
108
+ for (const predicate of predicates) {
109
+ for (const value of getPredicateFiniteValues(predicate)) {
110
+ addCandidate(value);
111
+ }
112
+ for (const operator of numericOperators) {
113
+ addCandidate(predicate[operator]);
114
+ }
115
+ }
116
+
117
+ return {
118
+ status: "supported",
119
+ values: candidates.sort((left, right) => left - right),
120
+ };
121
+ }
122
+
123
+ export function getToolcraftApplicabilitySelectorDomain(
124
+ control: ResolvedToolcraftControlSchema,
125
+ predicates: readonly ToolcraftControlPredicateSchema[],
126
+ ): ToolcraftApplicabilitySelectorDomain {
127
+ if (
128
+ control.type === "select" ||
129
+ control.type === "segmented" ||
130
+ control.type === "tabs"
131
+ ) {
132
+ const values: ToolcraftApplicabilitySelectorValue[] = [];
133
+
134
+ for (const option of control.options ?? []) {
135
+ addUniqueValue(values, option.value);
136
+ }
137
+
138
+ return values.length > 0
139
+ ? { status: "supported", values }
140
+ : {
141
+ reason: `${control.target} has no declared selector options`,
142
+ status: "unsupported",
143
+ };
144
+ }
145
+
146
+ if (control.type === "imagePicker") {
147
+ const values: ToolcraftApplicabilitySelectorValue[] = [];
148
+
149
+ for (const item of control.items ?? []) {
150
+ addUniqueValue(values, item.value);
151
+ }
152
+
153
+ return values.length > 0
154
+ ? { status: "supported", values }
155
+ : {
156
+ reason: `${control.target} has no declared image picker items`,
157
+ status: "unsupported",
158
+ };
159
+ }
160
+
161
+ if (control.type === "switch" || control.type === "checkbox") {
162
+ return { status: "supported", values: [false, true] };
163
+ }
164
+
165
+ return getDiscreteSliderDomain(control, predicates);
166
+ }
167
+
168
+ function getInvalidFinitePredicateValues(
169
+ predicates: readonly ToolcraftControlPredicateSchema[],
170
+ domain: readonly ToolcraftApplicabilitySelectorValue[],
171
+ ): unknown[] {
172
+ const values: unknown[] = [];
173
+
174
+ for (const predicate of predicates) {
175
+ for (const value of getPredicateFiniteValues(predicate)) {
176
+ if (
177
+ !domain.some((candidate) =>
178
+ areToolcraftValuesEqual(candidate, value),
179
+ ) &&
180
+ !values.some((candidate) =>
181
+ areToolcraftValuesEqual(candidate, value),
182
+ )
183
+ ) {
184
+ values.push(value);
185
+ }
186
+ }
187
+ }
188
+
189
+ return values;
190
+ }
191
+
192
+ function predicatesArePairwiseExclusive(
193
+ predicates: readonly ToolcraftControlPredicateSchema[],
194
+ ): boolean {
195
+ for (let leftIndex = 0; leftIndex < predicates.length; leftIndex += 1) {
196
+ for (
197
+ let rightIndex = leftIndex + 1;
198
+ rightIndex < predicates.length;
199
+ rightIndex += 1
200
+ ) {
201
+ const left = predicates[leftIndex];
202
+ const right = predicates[rightIndex];
203
+
204
+ if (
205
+ left &&
206
+ right &&
207
+ areToolcraftPredicatesProvablyExclusive(left, right)
208
+ ) {
209
+ return true;
210
+ }
211
+ }
212
+ }
213
+
214
+ return false;
215
+ }
216
+
217
+ export function getToolcraftControlApplicabilityErrors({
218
+ controls,
219
+ productReadiness,
220
+ }: Pick<
221
+ ToolcraftAcceptanceValidationContext,
222
+ "controls" | "productReadiness"
223
+ >): string[] {
224
+ if (productReadiness.mode !== "product") {
225
+ return [];
226
+ }
227
+
228
+ const errors: string[] = [];
229
+ const controlsByTarget = new Map(
230
+ controls.map(({ control }) => [control.target, control] as const),
231
+ );
232
+
233
+ for (const { control } of controls) {
234
+ const { applicability } = control;
235
+
236
+ if (applicability.origin === "implicit") {
237
+ errors.push(
238
+ `${control.target} must declare explicit applicability as always or conditional.`,
239
+ );
240
+ continue;
241
+ }
242
+
243
+ if (applicability.origin === "legacy") {
244
+ errors.push(
245
+ `${control.target} uses legacy visibleWhen; product controls must declare explicit applicability.`,
246
+ );
247
+ }
248
+
249
+ const predicates = getToolcraftApplicabilityPredicates(applicability);
250
+ const predicatesByTarget = new Map<
251
+ string,
252
+ ToolcraftControlPredicateSchema[]
253
+ >();
254
+
255
+ for (const predicate of predicates) {
256
+ const selector = controlsByTarget.get(predicate.target);
257
+
258
+ if (!selector) {
259
+ errors.push(
260
+ `${control.target} predicate target "${predicate.target}" does not exist.`,
261
+ );
262
+ continue;
263
+ }
264
+
265
+ if (selector.target === control.target) {
266
+ errors.push(`${control.target} applicability cannot gate itself.`);
267
+ continue;
268
+ }
269
+
270
+ const targetPredicates = predicatesByTarget.get(predicate.target) ?? [];
271
+ targetPredicates.push(predicate);
272
+ predicatesByTarget.set(predicate.target, targetPredicates);
273
+ }
274
+
275
+ for (const [selectorTarget, targetPredicates] of predicatesByTarget) {
276
+ const selector = controlsByTarget.get(selectorTarget);
277
+
278
+ if (!selector) {
279
+ continue;
280
+ }
281
+
282
+ const domain = getToolcraftApplicabilitySelectorDomain(
283
+ selector,
284
+ targetPredicates,
285
+ );
286
+
287
+ if (domain.status === "unsupported") {
288
+ errors.push(
289
+ `${selector.target} is not a supported applicability selector: ${domain.reason}.`,
290
+ );
291
+ continue;
292
+ }
293
+
294
+ if (
295
+ selector.type === "select" ||
296
+ selector.type === "segmented" ||
297
+ selector.type === "tabs" ||
298
+ selector.type === "imagePicker" ||
299
+ selector.type === "switch" ||
300
+ selector.type === "checkbox"
301
+ ) {
302
+ for (const invalidValue of getInvalidFinitePredicateValues(
303
+ targetPredicates,
304
+ domain.values,
305
+ )) {
306
+ errors.push(
307
+ `${control.target} applicability value ${JSON.stringify(invalidValue)} is not an option of ${selector.target}.`,
308
+ );
309
+ }
310
+ }
311
+
312
+ if (predicatesArePairwiseExclusive(targetPredicates)) {
313
+ errors.push(`${control.target} applicability is unsatisfiable.`);
314
+ continue;
315
+ }
316
+
317
+ if (
318
+ !domain.values.some((value) =>
319
+ targetPredicates.every((predicate) =>
320
+ doesToolcraftPredicateMatchValue(predicate, value),
321
+ ),
322
+ )
323
+ ) {
324
+ errors.push(
325
+ `${control.target} has no satisfying value in ${selector.target}.`,
326
+ );
327
+ }
328
+ }
329
+ }
330
+
331
+ return errors;
332
+ }
@@ -1,6 +1,9 @@
1
1
  import type {
2
2
  ToolcraftControlConditionSchema,
3
- ToolcraftControlSchema,
3
+ ResolvedToolcraftControlSchema,
4
+ } from "@repo/toolcraft-runtime";
5
+ import {
6
+ getToolcraftApplicabilityPredicates,
4
7
  } from "@repo/toolcraft-runtime";
5
8
 
6
9
  import type { ToolcraftControlLayoutFacts } from "./control-layout-model";
@@ -17,7 +20,7 @@ function normalizeToolcraftConditionValue(value: unknown): string | null {
17
20
 
18
21
  function getToolcraftConditionBranchTexts(
19
22
  condition: ToolcraftControlConditionSchema,
20
- gateControl: ToolcraftControlSchema,
23
+ gateControl: ResolvedToolcraftControlSchema,
21
24
  ): string[] {
22
25
  const rawValues =
23
26
  "equals" in condition
@@ -44,7 +47,7 @@ function sectionTitleLooksLikeDependencyBranch({
44
47
  sectionTitle,
45
48
  }: {
46
49
  condition: ToolcraftControlConditionSchema;
47
- gateControl: ToolcraftControlSchema;
50
+ gateControl: ResolvedToolcraftControlSchema;
48
51
  sectionTitle: string | undefined;
49
52
  }): boolean {
50
53
  const sectionText = normalizeToolcraftSemanticText(sectionTitle);
@@ -68,10 +71,18 @@ export function getToolcraftControlDependencyGroupingErrors(
68
71
  const errors: string[] = [];
69
72
 
70
73
  for (const item of facts.visibleControls) {
71
- for (const [conditionName, condition] of [
72
- ["visibleWhen", item.control.visibleWhen],
73
- ["disabledWhen", item.control.disabledWhen],
74
- ] as const) {
74
+ const conditions = [
75
+ ...getToolcraftApplicabilityPredicates(
76
+ item.control.applicability,
77
+ ).map(
78
+ (condition) => ["applicability", condition] as const,
79
+ ),
80
+ ...(item.control.disabledWhen
81
+ ? [["disabledWhen", item.control.disabledWhen] as const]
82
+ : []),
83
+ ];
84
+
85
+ for (const [conditionName, condition] of conditions) {
75
86
  if (!condition || !item.loosePrefix) {
76
87
  continue;
77
88
  }
@@ -86,7 +97,7 @@ export function getToolcraftControlDependencyGroupingErrors(
86
97
  gateControl.loosePrefix !== null &&
87
98
  gateControl.loosePrefix === item.loosePrefix;
88
99
  const looksLikeBranchSection =
89
- conditionName === "visibleWhen" &&
100
+ conditionName === "applicability" &&
90
101
  sectionTitleLooksLikeDependencyBranch({
91
102
  condition,
92
103
  gateControl: gateControl.control,
@@ -98,7 +109,7 @@ export function getToolcraftControlDependencyGroupingErrors(
98
109
  }
99
110
 
100
111
  errors.push(
101
- `${item.sectionLabel} / ${item.controlId} is gated by ${conditionName} target "${condition.target}" in ${gateControl.sectionLabel}, but it belongs to the same dependency group. Keep selectors and their dependent controls in one semantic section when they describe one product entity or branch; use visibleWhen for branch-specific controls inside that section instead of splitting branch controls into their own section. Do not use disabledWhen for product controls.`,
112
+ `${item.sectionLabel} / ${item.controlId} is gated by ${conditionName} target "${condition.target}" in ${gateControl.sectionLabel}, but it belongs to the same dependency group. Keep selectors and their dependent controls in one semantic section when they describe one product entity or branch; use conditional applicability for branch-specific controls inside that section instead of splitting branch controls into their own section. Do not use disabledWhen for product controls.`,
102
113
  );
103
114
  }
104
115
  }
@@ -2,10 +2,8 @@ import {
2
2
  getToolcraftFontPickerOwnedTypographyPart,
3
3
  } from "./control-labels";
4
4
  import type { ToolcraftControlLayoutFacts } from "./control-layout-model";
5
- import {
6
- getToolcraftSectionInventoryById,
7
- hasToolcraftInventorySplitEvidence,
8
- } from "./control-section-inventory";
5
+ import { hasToolcraftInventoryEntityAgreement } from "./control-section-entity-cohesion";
6
+ import { getToolcraftSectionInventoryById } from "./control-section-inventory";
9
7
  import { getControlLabelText } from "./controls";
10
8
  import type { ToolcraftControlSectionInventoryEntry } from "./types";
11
9
 
@@ -60,13 +58,13 @@ function getToolcraftProductEntitySplitErrors({
60
58
  for (const [prefix, sections] of facts.strictPrefixSections) {
61
59
  if (
62
60
  sections.size > 1 &&
63
- !hasToolcraftInventorySplitEvidence({ sectionInventoryById, sections })
61
+ !hasToolcraftInventoryEntityAgreement({ sectionInventoryById, sections })
64
62
  ) {
65
63
  const sectionLabels = [...sections].map(
66
64
  (sectionId) => facts.sectionLabelsById.get(sectionId) ?? sectionId,
67
65
  );
68
66
  errors.push(
69
- `Controls for product entity "${prefix}" are split across sections: ${sectionLabels.join(", ")}. Keep controls for the same product entity in one semantic section unless the Control Section Inventory declares workflowStage and splitReason for every split section.`,
67
+ `Controls for target family "${prefix}" are split across sections: ${sectionLabels.join(", ")}. Assign one shared entityId when the sections edit one logical entity; the entity cohesion validator decides whether that split is allowed.`,
70
68
  );
71
69
  }
72
70
  }
@@ -1,6 +1,6 @@
1
1
  import type {
2
2
  ResolvedToolcraftAppSchema,
3
- ToolcraftControlSchema,
3
+ ResolvedToolcraftControlSchema,
4
4
  } from "@repo/toolcraft-runtime";
5
5
 
6
6
  import { isToolcraftProductSectionControl } from "./controls";
@@ -12,7 +12,7 @@ import {
12
12
  } from "./semantic";
13
13
 
14
14
  export type ToolcraftControlLayoutControlEntry = {
15
- control: ToolcraftControlSchema;
15
+ control: ResolvedToolcraftControlSchema;
16
16
  controlId: string;
17
17
  loosePrefix: string | null;
18
18
  sectionLabel: string;
@@ -21,7 +21,7 @@ export type ToolcraftControlLayoutControlEntry = {
21
21
  };
22
22
 
23
23
  export type ToolcraftControlLayoutSectionFact = {
24
- controls: readonly [string, ToolcraftControlSchema][];
24
+ controls: readonly [string, ResolvedToolcraftControlSchema][];
25
25
  sectionLabel: string;
26
26
  sectionId: string;
27
27
  sectionLoosePrefixes: ReadonlySet<string>;
@@ -41,7 +41,7 @@ export type ToolcraftControlLayoutFacts = {
41
41
  };
42
42
 
43
43
  function getToolcraftControlSemanticCluster(
44
- control: ToolcraftControlSchema,
44
+ control: ResolvedToolcraftControlSchema,
45
45
  ): string {
46
46
  return (
47
47
  control.semanticGroup?.trim() ||
@@ -7,6 +7,7 @@ import {
7
7
  getToolcraftGenericControlLabelError,
8
8
  } from "./control-labels";
9
9
  import type { ToolcraftControlLayoutFacts } from "./control-layout-model";
10
+ import { TOOLCRAFT_DENSE_SECTION_MIN_CONTROLS } from "./control-section-entity-cohesion";
10
11
  import {
11
12
  controlTypeSectionTitlePattern,
12
13
  genericControlSectionTitlePattern,
@@ -15,9 +16,6 @@ import {
15
16
  const broadControlSectionTitlePattern =
16
17
  /^(animation|export|flow|icon|logo|motion|output|scene|shape|shapes|text|typography|visual|visuals)$/i;
17
18
 
18
- const maxPreferredControlsPerSection = 7;
19
- const maxHardControlsPerSection = 10;
20
-
21
19
  export function getToolcraftControlLayoutSectionInvariantErrors(
22
20
  facts: ToolcraftControlLayoutFacts,
23
21
  ): string[] {
@@ -55,7 +53,7 @@ export function getToolcraftControlLayoutSectionInvariantErrors(
55
53
  .map(([controlId]) => controlId);
56
54
 
57
55
  if (
58
- controls.length > maxPreferredControlsPerSection &&
56
+ controls.length >= TOOLCRAFT_DENSE_SECTION_MIN_CONTROLS &&
59
57
  missingSemanticGroups.length > 0
60
58
  ) {
61
59
  errors.push(
@@ -135,7 +133,7 @@ export function getToolcraftControlLayoutSectionHeuristicErrors(
135
133
  sectionTitle !== undefined && broadControlSectionTitlePattern.test(sectionTitle);
136
134
 
137
135
  if (
138
- controls.length > maxPreferredControlsPerSection &&
136
+ controls.length >= TOOLCRAFT_DENSE_SECTION_MIN_CONTROLS &&
139
137
  hasBroadSectionTitle &&
140
138
  semanticClusters.size >= 3
141
139
  ) {
@@ -144,11 +142,6 @@ export function getToolcraftControlLayoutSectionHeuristicErrors(
144
142
  );
145
143
  }
146
144
 
147
- if (controls.length > maxHardControlsPerSection && semanticClusters.size > 1) {
148
- errors.push(
149
- `${sectionLabel} has ${controls.length} controls across ${semanticClusters.size} semantic clusters (${clusterList}). Controls-panel sections should stay discrete; split sections that grow past ${maxHardControlsPerSection} controls unless every control edits one tightly scoped entity.`,
150
- );
151
- }
152
145
  }
153
146
 
154
147
  return errors;
@@ -10,6 +10,12 @@ export function getRequiredToolcraftControlPartCoverage(
10
10
  return ["anchorGrid.position"];
11
11
  case "channelMixer":
12
12
  return ["channelMixer.activeChannel", "channelMixer.values"];
13
+ case "collectionActions":
14
+ return [
15
+ "collectionActions.add",
16
+ "collectionActions.remove",
17
+ "collectionActions.items",
18
+ ];
13
19
  case "curves":
14
20
  return control.variant === "single"
15
21
  ? ["curves.points"]
@@ -39,6 +45,8 @@ export function getRequiredToolcraftControlPartCoverage(
39
45
  return ["rangeInput.start", "rangeInput.end"];
40
46
  case "rangeSlider":
41
47
  return ["rangeSlider.lower", "rangeSlider.upper"];
48
+ case "sourceCollection":
49
+ return ["sourceCollection.items"];
42
50
  case "vector":
43
51
  return ["vector.x", "vector.y"];
44
52
  default: