@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,182 @@
1
+ import ts from "typescript";
2
+
3
+ const workspaceUiPrimitiveModulePattern =
4
+ /^@repo\/ui(?:$|\/(?:src\/)?(?:components\/)?primitives(?:\/|$))/u;
5
+
6
+ function isToolcraftPublicUiPrimitiveModule(moduleSpecifier) {
7
+ const normalizedSpecifier = moduleSpecifier.replaceAll("\\", "/");
8
+
9
+ return (
10
+ workspaceUiPrimitiveModulePattern.test(normalizedSpecifier) ||
11
+ /^[#@]\/toolcraft\/ui$/u.test(normalizedSpecifier) ||
12
+ /^[#@]\/toolcraft\/ui\/primitives(?:\/|$)/u.test(normalizedSpecifier) ||
13
+ /^[#@]\/toolcraft\/ui\/components\/primitives(?:\/|$)/u.test(
14
+ normalizedSpecifier,
15
+ )
16
+ );
17
+ }
18
+
19
+ function unwrapExpression(node) {
20
+ let current = node;
21
+
22
+ while (
23
+ ts.isAwaitExpression(current) ||
24
+ ts.isParenthesizedExpression(current) ||
25
+ ts.isAsExpression(current) ||
26
+ ts.isTypeAssertionExpression(current) ||
27
+ ts.isSatisfiesExpression(current) ||
28
+ ts.isNonNullExpression(current)
29
+ ) {
30
+ current = current.expression;
31
+ }
32
+
33
+ return current;
34
+ }
35
+
36
+ function getImportModuleSpecifier(declaration) {
37
+ if (ts.isImportSpecifier(declaration)) {
38
+ const importDeclaration = declaration.parent.parent.parent;
39
+ return ts.isImportDeclaration(importDeclaration) &&
40
+ ts.isStringLiteralLike(importDeclaration.moduleSpecifier)
41
+ ? importDeclaration.moduleSpecifier.text
42
+ : null;
43
+ }
44
+
45
+ if (ts.isNamespaceImport(declaration)) {
46
+ const importDeclaration = declaration.parent.parent;
47
+ return ts.isImportDeclaration(importDeclaration) &&
48
+ ts.isStringLiteralLike(importDeclaration.moduleSpecifier)
49
+ ? importDeclaration.moduleSpecifier.text
50
+ : null;
51
+ }
52
+
53
+ if (ts.isImportClause(declaration)) {
54
+ const importDeclaration = declaration.parent;
55
+ return ts.isImportDeclaration(importDeclaration) &&
56
+ ts.isStringLiteralLike(importDeclaration.moduleSpecifier)
57
+ ? importDeclaration.moduleSpecifier.text
58
+ : null;
59
+ }
60
+
61
+ return null;
62
+ }
63
+
64
+ export function createToolcraftUiInputBindingTracker({
65
+ checker,
66
+ resolveStaticString,
67
+ }) {
68
+ const bindingKinds = new Map();
69
+ const resolvingSymbols = new Set();
70
+
71
+ function classifyExpression(expression) {
72
+ const current = unwrapExpression(expression);
73
+
74
+ if (ts.isIdentifier(current)) {
75
+ const symbol = checker.getSymbolAtLocation(current);
76
+ return symbol ? classifySymbol(symbol) : null;
77
+ }
78
+
79
+ if (
80
+ ts.isPropertyAccessExpression(current) &&
81
+ current.name.text === "Input" &&
82
+ classifyExpression(current.expression) === "namespace"
83
+ ) {
84
+ return "input";
85
+ }
86
+
87
+ if (
88
+ ts.isCallExpression(current) &&
89
+ current.arguments.length > 0 &&
90
+ (current.expression.kind === ts.SyntaxKind.ImportKeyword ||
91
+ (ts.isIdentifier(current.expression) &&
92
+ current.expression.text === "require"))
93
+ ) {
94
+ const moduleSpecifier = resolveStaticString(current.arguments[0]);
95
+ return moduleSpecifier &&
96
+ isToolcraftPublicUiPrimitiveModule(moduleSpecifier)
97
+ ? "namespace"
98
+ : null;
99
+ }
100
+
101
+ return null;
102
+ }
103
+
104
+ function classifyDeclaration(declaration) {
105
+ if (ts.isImportSpecifier(declaration)) {
106
+ const importedName = declaration.propertyName?.text ?? declaration.name.text;
107
+ const moduleSpecifier = getImportModuleSpecifier(declaration);
108
+ return importedName === "Input" &&
109
+ moduleSpecifier &&
110
+ isToolcraftPublicUiPrimitiveModule(moduleSpecifier)
111
+ ? "input"
112
+ : null;
113
+ }
114
+
115
+ if (ts.isNamespaceImport(declaration)) {
116
+ const moduleSpecifier = getImportModuleSpecifier(declaration);
117
+ return moduleSpecifier &&
118
+ isToolcraftPublicUiPrimitiveModule(moduleSpecifier)
119
+ ? "namespace"
120
+ : null;
121
+ }
122
+
123
+ if (ts.isImportClause(declaration)) {
124
+ const moduleSpecifier = getImportModuleSpecifier(declaration);
125
+ return moduleSpecifier &&
126
+ isToolcraftPublicUiPrimitiveModule(moduleSpecifier) &&
127
+ /(?:^|\/)input(?:\.[cm]?[jt]sx?)?$/iu.test(moduleSpecifier)
128
+ ? "input"
129
+ : null;
130
+ }
131
+
132
+ if (
133
+ ts.isImportEqualsDeclaration(declaration) &&
134
+ ts.isExternalModuleReference(declaration.moduleReference) &&
135
+ declaration.moduleReference.expression &&
136
+ ts.isStringLiteralLike(declaration.moduleReference.expression) &&
137
+ isToolcraftPublicUiPrimitiveModule(declaration.moduleReference.expression.text)
138
+ ) {
139
+ return "namespace";
140
+ }
141
+
142
+ if (ts.isVariableDeclaration(declaration) && declaration.initializer) {
143
+ return classifyExpression(declaration.initializer);
144
+ }
145
+
146
+ if (
147
+ ts.isBindingElement(declaration) &&
148
+ !declaration.dotDotDotToken &&
149
+ (declaration.propertyName?.getText() ?? declaration.name.getText()) ===
150
+ "Input"
151
+ ) {
152
+ const variableDeclaration = declaration.parent.parent;
153
+ return ts.isVariableDeclaration(variableDeclaration) &&
154
+ variableDeclaration.initializer &&
155
+ classifyExpression(variableDeclaration.initializer) === "namespace"
156
+ ? "input"
157
+ : null;
158
+ }
159
+
160
+ return null;
161
+ }
162
+
163
+ function classifySymbol(symbol) {
164
+ if (bindingKinds.has(symbol)) return bindingKinds.get(symbol);
165
+ if (resolvingSymbols.has(symbol)) return null;
166
+
167
+ resolvingSymbols.add(symbol);
168
+ const bindingKind =
169
+ symbol.declarations
170
+ ?.map(classifyDeclaration)
171
+ .find((candidate) => candidate !== null) ?? null;
172
+ resolvingSymbols.delete(symbol);
173
+ bindingKinds.set(symbol, bindingKind);
174
+ return bindingKind;
175
+ }
176
+
177
+ function isTrackedInputTag(tagName) {
178
+ return classifyExpression(tagName) === "input";
179
+ }
180
+
181
+ return { isTrackedInputTag };
182
+ }
@@ -0,0 +1,146 @@
1
+ import ts from "typescript";
2
+
3
+ import { createToolcraftUiInputBindingTracker } from "./toolcraft-product-control-bindings.mjs";
4
+
5
+ const workspacePrivateControlModulePattern =
6
+ /^@repo\/ui\/(?:src\/)?(?:components\/controls(?:\/|$)|controls\/)/u;
7
+
8
+ const forbiddenInputTypes = new Map([
9
+ ["checkbox", "checkbox or switch"],
10
+ ["color", "color or colorOpacity"],
11
+ ["file", "fileDrop"],
12
+ ["radio", "segmented or select"],
13
+ ["range", "slider or rangeSlider"],
14
+ ]);
15
+
16
+ function normalizeSpecifier(value) {
17
+ return value.replaceAll("\\", "/");
18
+ }
19
+
20
+ export function isToolcraftPrivateControlImplementationModule({
21
+ moduleSpecifier,
22
+ resolvedSpecifier,
23
+ }) {
24
+ const normalizedSpecifier = normalizeSpecifier(moduleSpecifier);
25
+ const normalizedResolvedSpecifier = resolvedSpecifier
26
+ ? normalizeSpecifier(resolvedSpecifier)
27
+ : "";
28
+
29
+ return (
30
+ workspacePrivateControlModulePattern.test(normalizedSpecifier) ||
31
+ /^[#@]\/toolcraft\/ui\/(?:components\/)?controls\//u.test(
32
+ normalizedSpecifier,
33
+ ) ||
34
+ /^[#@]\/toolcraft\/ui\/components\/controls(?:\/|$)/u.test(
35
+ normalizedSpecifier,
36
+ ) ||
37
+ /\/src\/toolcraft\/ui\/components\/controls(?:\/|$)/u.test(
38
+ normalizedResolvedSpecifier,
39
+ ) ||
40
+ /\/packages\/ui\/src\/components\/controls(?:\/|$)/u.test(
41
+ normalizedResolvedSpecifier,
42
+ )
43
+ );
44
+ }
45
+
46
+ function getJsxTagName(tagName) {
47
+ if (ts.isIdentifier(tagName)) return tagName.text;
48
+ if (ts.isPropertyAccessExpression(tagName)) return tagName.name.text;
49
+ return null;
50
+ }
51
+
52
+ export function createToolcraftProductControlInspector({
53
+ checker,
54
+ getNodeLocation,
55
+ repoPath,
56
+ resolveStaticString,
57
+ sourceFile,
58
+ }) {
59
+ const { isTrackedInputTag } = createToolcraftUiInputBindingTracker({
60
+ checker,
61
+ resolveStaticString,
62
+ });
63
+
64
+ function createViolation(node, message) {
65
+ return {
66
+ ...getNodeLocation(sourceFile, node),
67
+ kind: "native-control-recreation",
68
+ message,
69
+ repoPath,
70
+ };
71
+ }
72
+
73
+ function getInputType(attributes) {
74
+ let inputType = "text";
75
+ for (const property of attributes.properties) {
76
+ if (ts.isJsxSpreadAttribute(property)) {
77
+ inputType = null;
78
+ continue;
79
+ }
80
+ if (!ts.isIdentifier(property.name) || property.name.text !== "type") {
81
+ continue;
82
+ }
83
+ if (!property.initializer) {
84
+ inputType = null;
85
+ } else if (ts.isStringLiteral(property.initializer)) {
86
+ inputType = property.initializer.text;
87
+ } else if (
88
+ ts.isJsxExpression(property.initializer) &&
89
+ property.initializer.expression
90
+ ) {
91
+ inputType = resolveStaticString(property.initializer.expression) ?? null;
92
+ } else {
93
+ inputType = null;
94
+ }
95
+ }
96
+ return inputType?.toLowerCase() ?? null;
97
+ }
98
+
99
+ function inspectNode(node) {
100
+ if (!ts.isJsxOpeningElement(node) && !ts.isJsxSelfClosingElement(node)) {
101
+ return [];
102
+ }
103
+
104
+ const tagName = getJsxTagName(node.tagName);
105
+ if (tagName === "select") {
106
+ return [
107
+ createViolation(
108
+ node.tagName,
109
+ "Product source must not recreate the built-in Select with a native <select>. Declare a select schema control.",
110
+ ),
111
+ ];
112
+ }
113
+ if (tagName === "textarea") {
114
+ return [
115
+ createViolation(
116
+ node.tagName,
117
+ "Product source must not recreate built-in text or code controls with a native <textarea>. Declare a text or code schema control.",
118
+ ),
119
+ ];
120
+ }
121
+
122
+ if (tagName !== "input" && !isTrackedInputTag(node.tagName)) return [];
123
+
124
+ const inputType = getInputType(node.attributes);
125
+ if (inputType === null) {
126
+ return [
127
+ createViolation(
128
+ node.tagName,
129
+ "Product Input type must be statically resolvable so the Toolcraft boundary can verify that it does not recreate a built-in control.",
130
+ ),
131
+ ];
132
+ }
133
+
134
+ const builtInSchemaType = forbiddenInputTypes.get(inputType);
135
+ if (!builtInSchemaType) return [];
136
+
137
+ return [
138
+ createViolation(
139
+ node.tagName,
140
+ `Product source must not recreate a built-in control with input type "${inputType}". Declare the built-in ${builtInSchemaType} schema control.`,
141
+ ),
142
+ ];
143
+ }
144
+
145
+ return { inspectNode };
146
+ }
@@ -0,0 +1,186 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+
4
+ import { evaluateToolcraftProductBoundary } from "./toolcraft-product-boundary.mjs";
5
+ import { createToolcraftProductBoundaryFixture as createFixture } from "./toolcraft-product-boundary-test-fixtures.mjs";
6
+
7
+ const workspaceUiModule = ["@", "repo/ui"].join("");
8
+
9
+ test("finds built-in controls through every module form", async (context) => {
10
+ const rootDir = await createFixture(context, {
11
+ "src/features/control-bridge.ts": `
12
+ export { SliderControl as ProductSlider } from "@repo/ui/controls";
13
+ export { Color as ProductColor } from "@/toolcraft/ui";
14
+ `,
15
+ "src/features/dynamic.ts": `
16
+ export async function loadControls() {
17
+ return import("@/toolcraft/ui/components/controls/slider");
18
+ }
19
+ `,
20
+ "src/features/namespace.ts": `
21
+ import * as Controls from "@repo/ui";
22
+ export const Slider = Controls.Slider;
23
+ `,
24
+ });
25
+
26
+ const result = await evaluateToolcraftProductBoundary({ rootDir });
27
+
28
+ assert.deepEqual(
29
+ result.violations.map((violation) => violation.kind),
30
+ [
31
+ "built-in-control",
32
+ "built-in-control",
33
+ "built-in-control-implementation",
34
+ "built-in-control",
35
+ ],
36
+ );
37
+ });
38
+
39
+ test("rejects every deep import path into built-in control implementations", async (context) => {
40
+ const rootDir = await createFixture(context, {
41
+ "src/features/direct.tsx": `
42
+ import { ColorPickerPopover } from "@/toolcraft/ui/components/controls/color/color-picker-popover";
43
+ export const Direct = ColorPickerPopover;
44
+ `,
45
+ "src/features/directory-index.ts": `
46
+ import * as PrivateControls from "${workspaceUiModule}/components/controls";
47
+ export const DirectoryIndex = PrivateControls;
48
+ `,
49
+ "src/features/dynamic.ts": `
50
+ export const loadPrivateControl = () => import("${workspaceUiModule}/components/controls/color/color-value-utils");
51
+ `,
52
+ "src/features/namespace.ts": `
53
+ import * as PrivateColor from "@/toolcraft/ui/components/controls/color";
54
+ export const Namespace = PrivateColor;
55
+ `,
56
+ "src/features/reexport.ts": `
57
+ export { getCommittedHexColor } from "@/toolcraft/ui/components/controls/color/color-value-utils";
58
+ `,
59
+ "src/features/require.ts": `
60
+ export const privateControl = require("@/toolcraft/ui/components/controls/color/color-picker-popover");
61
+ `,
62
+ "src/features/workspace-source.ts": `
63
+ import { ColorPickerPopover } from "${workspaceUiModule}/src/components/controls/color/color-picker-popover";
64
+ export const WorkspaceSource = ColorPickerPopover;
65
+ `,
66
+ });
67
+
68
+ const result = await evaluateToolcraftProductBoundary({ rootDir });
69
+
70
+ assert.equal(result.violations.length, 7);
71
+ assert.equal(
72
+ result.violations.every(
73
+ (violation) => violation.kind === "built-in-control-implementation",
74
+ ),
75
+ true,
76
+ );
77
+ assert.equal(
78
+ result.violations.every((violation) =>
79
+ /deep control implementation|public schema control/u.test(
80
+ violation.message,
81
+ ),
82
+ ),
83
+ true,
84
+ );
85
+ });
86
+
87
+ test("rejects the badge color-control copy at both private imports", async (context) => {
88
+ const rootDir = await createFixture(context, {
89
+ "src/features/badge-color-control.tsx": `
90
+ import { ColorPickerPopover } from "@/toolcraft/ui/components/controls/color/color-picker-popover";
91
+ import { getCommittedHexColor } from "@/toolcraft/ui/components/controls/color/color-value-utils";
92
+ export const BadgeColorControl = { ColorPickerPopover, getCommittedHexColor };
93
+ `,
94
+ });
95
+
96
+ const result = await evaluateToolcraftProductBoundary({ rootDir });
97
+
98
+ assert.deepEqual(
99
+ result.violations.map(({ column, kind, line, repoPath }) => ({
100
+ column,
101
+ kind,
102
+ line,
103
+ repoPath,
104
+ })),
105
+ [
106
+ {
107
+ column: 7,
108
+ kind: "built-in-control-implementation",
109
+ line: 2,
110
+ repoPath: "src/features/badge-color-control.tsx",
111
+ },
112
+ {
113
+ column: 7,
114
+ kind: "built-in-control-implementation",
115
+ line: 3,
116
+ repoPath: "src/features/badge-color-control.tsx",
117
+ },
118
+ ],
119
+ );
120
+ });
121
+
122
+ test("rejects native and kit-primitive recreations of built-in controls", async (context) => {
123
+ const rootDir = await createFixture(context, {
124
+ "src/features/kit-inputs.tsx": `
125
+ import { Input as FieldInput } from "@/toolcraft/ui/primitives";
126
+ import * as Primitives from "@/toolcraft/ui/primitives";
127
+ const AliasedInput = FieldInput;
128
+ const { Input: RequiredInput } = require("@/toolcraft/ui/primitives");
129
+ export const Color = <FieldInput type="color" />;
130
+ export const File = <AliasedInput type={"file"} />;
131
+ export const Range = <Primitives.Input type="range" />;
132
+ export const Radio = <RequiredInput type="radio" />;
133
+ export function Dynamic({ kind }) {
134
+ return <FieldInput type={kind} />;
135
+ }
136
+ `,
137
+ "src/features/native.tsx": `
138
+ const rangeType = "range";
139
+ export const Range = <input type={rangeType} />;
140
+ export const Checkbox = <input type="checkbox" />;
141
+ export const Radio = <input type="radio" />;
142
+ export const Select = <select><option>One</option></select>;
143
+ export const Notes = <textarea />;
144
+ `,
145
+ "src/features/private-primitive.tsx": `
146
+ import PrimitiveInput from "${workspaceUiModule}/components/primitives/input";
147
+ export const PrivatePrimitiveColor = <PrimitiveInput type="color" />;
148
+ `,
149
+ });
150
+
151
+ const result = await evaluateToolcraftProductBoundary({ rootDir });
152
+
153
+ assert.equal(result.violations.length, 11);
154
+ assert.equal(
155
+ result.violations.every(
156
+ (violation) => violation.kind === "native-control-recreation",
157
+ ),
158
+ true,
159
+ );
160
+ });
161
+
162
+ test("allows generic text inputs, buttons, canvas, and product components", async (context) => {
163
+ const rootDir = await createFixture(context, {
164
+ "src/features/safe-controls.tsx": `
165
+ import { Button, Input as FieldInput } from "@/toolcraft/ui/primitives";
166
+ function ProductInput() { return <div>Product value</div>; }
167
+ function ShadowedInput(FieldInput) { return <FieldInput type="color" />; }
168
+ export const Safe = (
169
+ <>
170
+ <FieldInput type="text" />
171
+ <input type="email" />
172
+ <input type="hidden" />
173
+ <Button>Run</Button>
174
+ <button type="button">Local action</button>
175
+ <canvas />
176
+ <ProductInput />
177
+ <ShadowedInput />
178
+ </>
179
+ );
180
+ `,
181
+ });
182
+
183
+ const result = await evaluateToolcraftProductBoundary({ rootDir });
184
+
185
+ assert.deepEqual(result.violations, []);
186
+ });
@@ -12,6 +12,44 @@ const starterRoot = path.resolve(
12
12
  path.dirname(fileURLToPath(import.meta.url)),
13
13
  "..",
14
14
  );
15
+ const unavailableImageEvidenceFacadePath =
16
+ "e2e/browser-infinity-canvas-evidence.ts";
17
+ const unavailableImageEvidencePrivatePath =
18
+ "e2e/browser-infinity-canvas-unavailable-image-evidence.ts";
19
+
20
+ async function evaluateUnavailableImageEvidenceImport(context, specifier) {
21
+ const rootDir = await createFixture(context, {
22
+ "e2e/app-canvas.spec.ts": `
23
+ import { createToolcraftUnavailableImageResourceFixture } from "${specifier}";
24
+ void createToolcraftUnavailableImageResourceFixture;
25
+ `,
26
+ [unavailableImageEvidenceFacadePath]: `
27
+ export {
28
+ createToolcraftUnavailableImageResourceFixture,
29
+ } from "./browser-infinity-canvas-unavailable-image-evidence";
30
+ `,
31
+ [unavailableImageEvidencePrivatePath]: `
32
+ export function createToolcraftUnavailableImageResourceFixture() {}
33
+ `,
34
+ "tsconfig.json": JSON.stringify({
35
+ compilerOptions: {
36
+ baseUrl: ".",
37
+ paths: {
38
+ "@private-proof": [`./${unavailableImageEvidencePrivatePath}`],
39
+ "@public-proof": [`./${unavailableImageEvidenceFacadePath}`],
40
+ },
41
+ },
42
+ }),
43
+ });
44
+
45
+ return evaluateToolcraftProductBoundary({
46
+ protectedFilePaths: [
47
+ unavailableImageEvidenceFacadePath,
48
+ unavailableImageEvidencePrivatePath,
49
+ ],
50
+ rootDir,
51
+ });
52
+ }
15
53
 
16
54
  test("protects every starter helper that writes reserved runtime evidence", async () => {
17
55
  const e2eRoot = path.join(starterRoot, "e2e");
@@ -201,27 +239,54 @@ test("allows product layer specs to use the public proof facade without reserved
201
239
  assert.deepEqual(result.violations, []);
202
240
  });
203
241
 
204
- test("allows product specs to use the unavailable-resource facade but rejects its reserved bridge", async (context) => {
205
- const allowedRoot = await createFixture(context, {
206
- "e2e/app-canvas.spec.ts": `
207
- import {
208
- createToolcraftUnavailableImageResourceFixture,
209
- expectToolcraftInfinityCanvasUnavailableImageExportEvidence,
210
- } from "./browser-infinity-canvas-evidence";
211
- void createToolcraftUnavailableImageResourceFixture;
212
- void expectToolcraftInfinityCanvasUnavailableImageExportEvidence;
213
- `,
214
- "e2e/browser-infinity-canvas-evidence.ts": `
215
- export function createToolcraftUnavailableImageResourceFixture() {}
216
- export async function expectToolcraftInfinityCanvasUnavailableImageExportEvidence() {}
217
- `,
218
- });
219
- const allowed = await evaluateToolcraftProductBoundary({
220
- protectedFilePaths: ["e2e/browser-infinity-canvas-evidence.ts"],
221
- rootDir: allowedRoot,
222
- });
223
- assert.deepEqual(allowed.violations, []);
242
+ test("rejects relative and configured-alias imports of private unavailable-image evidence", async (context) => {
243
+ const results = await Promise.all(
244
+ [
245
+ "./browser-infinity-canvas-unavailable-image-evidence",
246
+ "@private-proof",
247
+ ].map((specifier) =>
248
+ evaluateUnavailableImageEvidenceImport(context, specifier),
249
+ ),
250
+ );
251
+ assert.deepEqual(
252
+ results.map((result) =>
253
+ result.violations.map((violation) => violation.kind),
254
+ ),
255
+ [
256
+ ["reserved-runtime-evidence"],
257
+ ["reserved-runtime-evidence"],
258
+ ],
259
+ );
260
+ for (const result of results) {
261
+ assert.match(result.violations[0].message, /browser-infinity-canvas-evidence/u);
262
+ }
263
+ });
264
+
265
+ test("allows relative and configured-alias imports of the public unavailable-image facade", async (context) => {
266
+ for (const specifier of [
267
+ "./browser-infinity-canvas-evidence",
268
+ "@public-proof",
269
+ ]) {
270
+ const result = await evaluateUnavailableImageEvidenceImport(
271
+ context,
272
+ specifier,
273
+ );
274
+ assert.deepEqual(result.violations, []);
275
+ }
276
+ });
277
+
278
+ test("normalizes private unavailable-image evidence import paths before enforcing policy", async (context) => {
279
+ const result = await evaluateUnavailableImageEvidenceImport(
280
+ context,
281
+ "./nested/../browser-infinity-canvas-unavailable-image-evidence",
282
+ );
283
+ assert.deepEqual(
284
+ result.violations.map((violation) => violation.kind),
285
+ ["reserved-runtime-evidence"],
286
+ );
287
+ });
224
288
 
289
+ test("rejects product access to the reserved unavailable-resource bridge", async (context) => {
225
290
  const rejectedRoot = await createFixture(context, {
226
291
  "e2e/app-canvas.spec.ts": `
227
292
  const fixtureEvent =
@@ -0,0 +1,43 @@
1
+ const PRIVATE_EVIDENCE_MESSAGE =
2
+ "Product-owned source must use the protected public evidence facade instead of importing its private implementation module.";
3
+
4
+ export const toolcraftProductEvidenceModulePolicies = Object.freeze([
5
+ Object.freeze({
6
+ capability: "unavailable-image-resource-evidence",
7
+ privateModuleRepoPath:
8
+ "e2e/browser-infinity-canvas-unavailable-image-evidence.ts",
9
+ publicFacadeRepoPath: "e2e/browser-infinity-canvas-evidence.ts",
10
+ }),
11
+ ]);
12
+
13
+ const privateEvidencePolicyByRepoPath = new Map(
14
+ toolcraftProductEvidenceModulePolicies.map((policy) => [
15
+ policy.privateModuleRepoPath,
16
+ policy,
17
+ ]),
18
+ );
19
+
20
+ function normalizeRepoPath(repoPath) {
21
+ return String(repoPath).replaceAll("\\", "/").replace(/^\.\//u, "");
22
+ }
23
+
24
+ export function createToolcraftPrivateEvidenceImportViolation({
25
+ importerRepoPath,
26
+ moduleImport,
27
+ }) {
28
+ if (moduleImport.resolution !== "resolved") return null;
29
+ const policy = privateEvidencePolicyByRepoPath.get(
30
+ normalizeRepoPath(moduleImport.resolvedRepoPath),
31
+ );
32
+ if (!policy) return null;
33
+
34
+ return {
35
+ column: moduleImport.column,
36
+ kind: "reserved-runtime-evidence",
37
+ line: moduleImport.line,
38
+ message:
39
+ `${PRIVATE_EVIDENCE_MESSAGE} Import ${policy.publicFacadeRepoPath} ` +
40
+ `for ${policy.capability}.`,
41
+ repoPath: importerRepoPath,
42
+ };
43
+ }