@pixel-point/toolcraft 0.0.18 → 0.0.19

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 (384) hide show
  1. package/package.json +1 -1
  2. package/src/generate-demand-only-lifecycle.test.mjs +9 -1
  3. package/src/generate-performance-iteration-execution.test.mjs +3 -3
  4. package/src/generate-test-delivery-architecture-assertions.mjs +11 -73
  5. package/src/generate-test-demand-only-lifecycle.mjs +34 -36
  6. package/src/generate-test-dependency-sandbox.mjs +4 -1
  7. package/src/generate-test-doc-assertions.mjs +55 -53
  8. package/src/generate-test-doc-assertions.test.mjs +1 -1
  9. package/src/generate-test-doc-policy-assertions.mjs +1 -1
  10. package/src/generate-test-export-doc-assertions.mjs +53 -0
  11. package/src/generate-test-file-assertions.mjs +51 -8
  12. package/src/generate-test-integrity-assertions.mjs +5 -2
  13. package/src/generate-test-integrity-manifest-assertions.mjs +16 -5
  14. package/src/generate-test-integrity-ownership-assertions.mjs +36 -4
  15. package/src/generate-test-package-assertions.mjs +4 -0
  16. package/src/generate-test-product-fixture.mjs +1 -1
  17. package/src/generate-test-product-fixture.test.mjs +35 -38
  18. package/src/generate-test-product-iteration.mjs +0 -1
  19. package/src/generate-test-product-iteration.test.mjs +0 -1
  20. package/src/generate-test-runtime-boundary-assertions.mjs +20 -0
  21. package/src/generate-test-standalone-assertions.mjs +0 -16
  22. package/src/generate-test-standalone-delivery-stages.mjs +2 -86
  23. package/src/generate.test.mjs +4 -0
  24. package/src/generated-integrity-manifest.test.mjs +5 -2
  25. package/src/generated-source-policy.test.mjs +0 -4
  26. package/src/package-json.mjs +5 -0
  27. package/src/package-json.test.mjs +21 -0
  28. package/src/package-manager.mjs +2 -0
  29. package/src/package-manager.test.mjs +8 -0
  30. package/src/packaged-template-fallback-helpers.mjs +254 -0
  31. package/src/packaged-template-fallback.test.mjs +121 -46
  32. package/src/packaged-template-runtime-assertions.mjs +150 -0
  33. package/templates/runtime/contracts/component-contracts.choices.test.ts +18 -3
  34. package/templates/runtime/contracts/component-contracts.choices.ts +8 -3
  35. package/templates/runtime/contracts/component-contracts.inputs.ts +2 -1
  36. package/templates/runtime/contracts/component-contracts.runtime-acceptance.test.ts +18 -4
  37. package/templates/runtime/contracts/component-contracts.runtime-shell.test.ts +1 -1
  38. package/templates/runtime/contracts/component-contracts.runtime.ts +7 -4
  39. package/templates/runtime/contracts/component-contracts.visual.test.ts +20 -0
  40. package/templates/runtime/contracts/component-contracts.visual.ts +4 -0
  41. package/templates/runtime/contracts/decision-contracts.test.ts +18 -12
  42. package/templates/runtime/contracts/decision-contracts.ts +4 -4
  43. package/templates/runtime/contracts/performance-verification-policy.test.ts +12 -12
  44. package/templates/runtime/contracts/performance-verification-policy.ts +8 -8
  45. package/templates/runtime/export/artifact-download.ts +1 -0
  46. package/templates/runtime/export/artifact-frame-renderer.ts +2 -15
  47. package/templates/runtime/export/artifact-frame-state.ts +16 -0
  48. package/templates/runtime/export/artifact-scene-frame.test.ts +3 -3
  49. package/templates/runtime/export/artifact-scene-frame.ts +3 -3
  50. package/templates/runtime/export/export-error.ts +5 -0
  51. package/templates/runtime/export/export-renderer-coverage.ts +54 -0
  52. package/templates/runtime/export/image-artifact-export.ts +2 -2
  53. package/templates/runtime/export/index.ts +13 -0
  54. package/templates/runtime/export/product-export-renderer.test.ts +38 -4
  55. package/templates/runtime/export/product-export-renderer.ts +0 -41
  56. package/templates/runtime/export/product-svg-export-renderer.ts +21 -0
  57. package/templates/runtime/export/svg-artifact-export.test.ts +98 -0
  58. package/templates/runtime/export/svg-artifact-export.ts +120 -0
  59. package/templates/runtime/export/svg-document.test.ts +221 -0
  60. package/templates/runtime/export/svg-document.ts +400 -0
  61. package/templates/runtime/export/svg-policy.ts +47 -0
  62. package/templates/runtime/index.ts +1 -0
  63. package/templates/runtime/react/app-shell/runtime-public-api.test.tsx +10 -0
  64. package/templates/runtime/react/app-shell/settings-transfer.test.ts +21 -0
  65. package/templates/runtime/react/app-shell/toolcraft-app.scene-export.test.tsx +46 -1
  66. package/templates/runtime/react/app-shell/toolcraft-app.tsx +7 -2
  67. package/templates/runtime/react/canvas/canvas-shell-interactions.test.tsx +30 -0
  68. package/templates/runtime/react/canvas/canvas-shell-pinch-interactions.test.tsx +155 -0
  69. package/templates/runtime/react/canvas/canvas-shell-rendering.test.tsx +1 -1
  70. package/templates/runtime/react/canvas/canvas-shell.tsx +16 -5
  71. package/templates/runtime/react/canvas/canvas-viewport-geometry.ts +133 -0
  72. package/templates/runtime/react/canvas/use-canvas-viewport-interactions.ts +285 -36
  73. package/templates/runtime/react/controls-panel/__tests__/controls-panel.color-applicability-layout.test.tsx +134 -0
  74. package/templates/runtime/react/controls-panel/__tests__/controls-panel.color-layout.test.tsx +16 -1
  75. package/templates/runtime/react/controls-panel/__tests__/controls-panel.render-isolation.test.tsx +2 -0
  76. package/templates/runtime/react/controls-panel/__tests__/controls-panel.scene-export-actions.test.tsx +39 -0
  77. package/templates/runtime/react/controls-panel/__tests__/controls-panel.setup-controls.test.tsx +3 -3
  78. package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-collection.test.tsx +1 -4
  79. package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-color-bank.test.tsx +2 -2
  80. package/templates/runtime/react/controls-panel/__tests__/controls-panel.vector-interaction.test.tsx +6 -6
  81. package/templates/runtime/react/controls-panel/actions/controls-panel-actions.ts +2 -2
  82. package/templates/runtime/react/controls-panel/actions/export-action-runner.ts +40 -11
  83. package/templates/runtime/react/controls-panel/layout/controls-panel-layout.tsx +31 -2
  84. package/templates/runtime/react/controls-panel/layout/controls-panel-section.tsx +4 -1
  85. package/templates/runtime/react/controls-panel/renderers/controls-panel-action-renderer.tsx +2 -1
  86. package/templates/runtime/react/controls-panel/renderers/controls-panel-basic-renderers.tsx +2 -52
  87. package/templates/runtime/react/controls-panel/values/controls-panel-color-values.ts +1 -9
  88. package/templates/runtime/react/controls-panel/values/controls-panel-spatial-values.ts +7 -2
  89. package/templates/runtime/react/orientation-gizmo/orientation-gizmo-math.ts +9 -69
  90. package/templates/runtime/schema/artifact-export-actions.test.ts +47 -0
  91. package/templates/runtime/schema/artifact-export-actions.ts +49 -0
  92. package/templates/runtime/schema/types.ts +1 -0
  93. package/templates/runtime/state/canvas-background-state.ts +1 -16
  94. package/templates/runtime/state/canvas-state.ts +32 -20
  95. package/templates/runtime/state/control-value-codecs.test.ts +98 -0
  96. package/templates/runtime/state/control-value-codecs.ts +700 -0
  97. package/templates/runtime/state/control-value-normalization.test.ts +1 -1
  98. package/templates/runtime/state/control-value-normalization.ts +127 -135
  99. package/templates/runtime/state/controls-reducer.ts +26 -3
  100. package/templates/runtime/state/create-template-state.test.ts +30 -0
  101. package/templates/runtime/state/create-template-state.ts +52 -31
  102. package/templates/runtime/state/orientation-pose.ts +80 -0
  103. package/templates/runtime/state/persistence-control-values.test.ts +59 -0
  104. package/templates/runtime/state/reducer-controls.test.ts +45 -0
  105. package/templates/runtime/state/reducer-media-reset.test.ts +1 -1
  106. package/templates/runtime/state/reducer-timeline.test.ts +70 -0
  107. package/templates/runtime/state/timeline-reducer.ts +40 -2
  108. package/templates/runtime/testing/performance-schema-queries.ts +2 -2
  109. package/templates/starter/AGENTS.md +21 -22
  110. package/templates/starter/docs/toolcraft/README.md +6 -6
  111. package/templates/starter/docs/toolcraft/acceptance-testing.md +20 -20
  112. package/templates/starter/docs/toolcraft/agent-worklog.md +88 -1
  113. package/templates/starter/docs/toolcraft/assembly-workflow.md +7 -6
  114. package/templates/starter/docs/toolcraft/component-rules.md +2 -2
  115. package/templates/starter/docs/toolcraft/core/layout.md +6 -1
  116. package/templates/starter/docs/toolcraft/core/media-upload.md +1 -1
  117. package/templates/starter/docs/toolcraft/core/performance.md +8 -10
  118. package/templates/starter/docs/toolcraft/core/reference-study.md +80 -19
  119. package/templates/starter/docs/toolcraft/core/runtime-boundary.md +2 -1
  120. package/templates/starter/docs/toolcraft/core/setup-export.md +43 -13
  121. package/templates/starter/docs/toolcraft/decision-contract.md +2 -2
  122. package/templates/starter/docs/toolcraft/performance.md +8 -10
  123. package/templates/starter/docs/toolcraft/renderer-technique.md +2 -2
  124. package/templates/starter/docs/toolcraft/schema-reference.md +8 -8
  125. package/templates/starter/docs/toolcraft/workflow.md +14 -14
  126. package/templates/starter/e2e/app-browser-infinity-canvas-evidence.spec.ts +38 -0
  127. package/templates/starter/e2e/app-browser-motion-reference-requirements.spec.ts +411 -0
  128. package/templates/starter/e2e/app-browser-proof-session.spec.ts +85 -0
  129. package/templates/starter/e2e/app-browser-runtime-requirements.spec.ts +62 -0
  130. package/templates/starter/e2e/app-browser-selection-scope-evidence.spec.ts +137 -0
  131. package/templates/starter/e2e/browser-infinity-canvas-svg-evidence.ts +42 -0
  132. package/templates/starter/e2e/browser-layer-evidence-helpers.ts +15 -36
  133. package/templates/starter/e2e/browser-product-raster-snapshot.ts +213 -0
  134. package/templates/starter/e2e/browser-proof-session.ts +43 -15
  135. package/templates/starter/e2e/browser-proof-surface-action.ts +79 -0
  136. package/templates/starter/e2e/browser-proof-types.ts +15 -0
  137. package/templates/starter/e2e/browser-runtime-evidence-requirements.ts +22 -6
  138. package/templates/starter/e2e/browser-selection-scope-evidence.ts +269 -0
  139. package/templates/starter/e2e/browser-semantic-evidence-test-helpers.ts +97 -0
  140. package/templates/starter/e2e/browser-svg-export-evidence.spec.ts +79 -0
  141. package/templates/starter/e2e/browser-svg-export-evidence.ts +152 -0
  142. package/templates/starter/e2e/export-artifact-helpers.ts +70 -0
  143. package/templates/starter/e2e/product-observable-helpers.ts +8 -129
  144. package/templates/starter/e2e/svg-artifact-inspection.spec.ts +136 -0
  145. package/templates/starter/e2e/svg-artifact-inspection.ts +331 -0
  146. package/templates/starter/e2e/svg-download-test-fixtures.ts +34 -0
  147. package/templates/starter/e2e/toolcraft-delivery-catalog-reporter.ts +198 -15
  148. package/templates/starter/e2e/toolcraft-feature-verification-reporter.spec.ts +149 -0
  149. package/templates/starter/e2e/toolcraft-feature-verification-reporter.ts +223 -0
  150. package/templates/starter/package.json +2 -0
  151. package/templates/starter/scripts/check-toolcraft-docs.mjs +1 -0
  152. package/templates/starter/scripts/create-toolcraft-motion-reference-study.mjs +233 -0
  153. package/templates/starter/scripts/create-toolcraft-motion-reference-study.test.mjs +459 -0
  154. package/templates/starter/scripts/playwright-test-title-selection.d.mts +45 -0
  155. package/templates/starter/scripts/run-browser-performance-test-helpers.mjs +0 -27
  156. package/templates/starter/scripts/run-browser-performance.mjs +0 -6
  157. package/templates/starter/scripts/run-browser-performance.test.mjs +5 -13
  158. package/templates/starter/scripts/run-delivery-verification-test-helpers.mjs +0 -34
  159. package/templates/starter/scripts/run-delivery-verification.test.mjs +135 -31
  160. package/templates/starter/scripts/run-feature-verification.mjs +212 -0
  161. package/templates/starter/scripts/run-feature-verification.test.mjs +226 -0
  162. package/templates/starter/scripts/toolcraft-checkpoint-delivery-state.mjs +21 -8
  163. package/templates/starter/scripts/toolcraft-checkpoint-delivery-state.test.mjs +32 -92
  164. package/templates/starter/scripts/toolcraft-checkpoint-transaction.mjs +28 -6
  165. package/templates/starter/scripts/toolcraft-checkpoint-transaction.test.mjs +8 -63
  166. package/templates/starter/scripts/toolcraft-delivery-anchor.mjs +28 -8
  167. package/templates/starter/scripts/toolcraft-delivery-anchor.test.mjs +50 -61
  168. package/templates/starter/scripts/toolcraft-delivery-architecture-inventory.mjs +0 -4
  169. package/templates/starter/scripts/toolcraft-delivery-architecture-policy.mjs +0 -1
  170. package/templates/starter/scripts/toolcraft-delivery-evidence.test.mjs +2 -3
  171. package/templates/starter/scripts/toolcraft-delivery-executor.mjs +5 -1
  172. package/templates/starter/scripts/toolcraft-delivery-executor.test.mjs +5 -12
  173. package/templates/starter/scripts/toolcraft-delivery-functional-context.d.mts +1 -48
  174. package/templates/starter/scripts/toolcraft-delivery-functional-context.mjs +2 -30
  175. package/templates/starter/scripts/toolcraft-delivery-functional-context.test.mjs +4 -166
  176. package/templates/starter/scripts/toolcraft-delivery-functional-initial.test.mjs +4 -20
  177. package/templates/starter/scripts/toolcraft-delivery-lifecycle.mjs +43 -192
  178. package/templates/starter/scripts/toolcraft-delivery-performance-iteration-lifecycle.test.mjs +79 -440
  179. package/templates/starter/scripts/toolcraft-delivery-plan-authority.test.mjs +102 -297
  180. package/templates/starter/scripts/toolcraft-delivery-plan-construction.mjs +46 -97
  181. package/templates/starter/scripts/toolcraft-delivery-plan-test-helpers.mjs +125 -0
  182. package/templates/starter/scripts/toolcraft-delivery-plan-validation.test.mjs +58 -0
  183. package/templates/starter/scripts/toolcraft-delivery-plan.d.mts +19 -31
  184. package/templates/starter/scripts/toolcraft-delivery-plan.mjs +254 -252
  185. package/templates/starter/scripts/toolcraft-delivery-plan.test.mjs +29 -457
  186. package/templates/starter/scripts/toolcraft-delivery-receipt-performance.test.mjs +1 -1
  187. package/templates/starter/scripts/toolcraft-delivery-receipt-strictness.test.mjs +3 -72
  188. package/templates/starter/scripts/toolcraft-delivery-receipt-test-helpers.mjs +7 -36
  189. package/templates/starter/scripts/toolcraft-delivery-receipt.d.mts +3 -5
  190. package/templates/starter/scripts/toolcraft-delivery-receipt.mjs +15 -31
  191. package/templates/starter/scripts/toolcraft-delivery-receipt.test.mjs +28 -20
  192. package/templates/starter/scripts/toolcraft-delivery-receipt.types.test.mts +22 -30
  193. package/templates/starter/scripts/toolcraft-feature-verification-plan.d.mts +20 -0
  194. package/templates/starter/scripts/toolcraft-feature-verification-plan.mjs +146 -0
  195. package/templates/starter/scripts/toolcraft-feature-verification-plan.test.mjs +96 -0
  196. package/templates/starter/scripts/toolcraft-functional-proof-model.d.mts +3 -18
  197. package/templates/starter/scripts/toolcraft-functional-proof-model.mjs +39 -127
  198. package/templates/starter/scripts/toolcraft-functional-proof-model.test.mjs +25 -362
  199. package/templates/starter/scripts/toolcraft-functional-proof-model.types.test.mts +6 -83
  200. package/templates/starter/scripts/toolcraft-functional-proof-primitives.d.mts +11 -0
  201. package/templates/starter/scripts/toolcraft-functional-proof-primitives.mjs +61 -0
  202. package/templates/starter/scripts/toolcraft-functional-proof-primitives.test.mjs +43 -0
  203. package/templates/starter/scripts/toolcraft-integrity-policy.mjs +13 -0
  204. package/templates/starter/scripts/toolcraft-integrity-test-utils.mjs +1 -1
  205. package/templates/starter/scripts/toolcraft-layer-evidence-facade.test.mjs +58 -22
  206. package/templates/starter/scripts/toolcraft-motion-reference-analysis-protocol.mjs +111 -0
  207. package/templates/starter/scripts/toolcraft-motion-reference-analysis-protocol.test.mjs +116 -0
  208. package/templates/starter/scripts/toolcraft-motion-reference-artifacts.d.mts +37 -0
  209. package/templates/starter/scripts/toolcraft-motion-reference-artifacts.mjs +308 -0
  210. package/templates/starter/scripts/toolcraft-motion-reference-artifacts.test.mjs +420 -0
  211. package/templates/starter/scripts/toolcraft-motion-reference-artifacts.types.test.mts +50 -0
  212. package/templates/starter/scripts/toolcraft-motion-reference-command-options.mjs +195 -0
  213. package/templates/starter/scripts/toolcraft-motion-reference-command-options.test.mjs +224 -0
  214. package/templates/starter/scripts/toolcraft-motion-reference-contact-sheet.mjs +122 -0
  215. package/templates/starter/scripts/toolcraft-motion-reference-contact-sheet.test.mjs +153 -0
  216. package/templates/starter/scripts/toolcraft-motion-reference-evidence-assembly.mjs +270 -0
  217. package/templates/starter/scripts/toolcraft-motion-reference-evidence.test.mjs +432 -0
  218. package/templates/starter/scripts/toolcraft-motion-reference-ffmpeg-output.mjs +275 -0
  219. package/templates/starter/scripts/toolcraft-motion-reference-ffmpeg-output.test.mjs +294 -0
  220. package/templates/starter/scripts/toolcraft-motion-reference-group-inventory.mjs +148 -0
  221. package/templates/starter/scripts/toolcraft-motion-reference-image-filter-graph.mjs +101 -0
  222. package/templates/starter/scripts/toolcraft-motion-reference-image-filter-graph.test.mjs +124 -0
  223. package/templates/starter/scripts/toolcraft-motion-reference-image-source.mjs +259 -0
  224. package/templates/starter/scripts/toolcraft-motion-reference-image-source.test.mjs +338 -0
  225. package/templates/starter/scripts/toolcraft-motion-reference-image-timing.mjs +96 -0
  226. package/templates/starter/scripts/toolcraft-motion-reference-image-timing.test.mjs +81 -0
  227. package/templates/starter/scripts/toolcraft-motion-reference-lock-recovery.test.mjs +144 -0
  228. package/templates/starter/scripts/toolcraft-motion-reference-media-source.mjs +165 -0
  229. package/templates/starter/scripts/toolcraft-motion-reference-media-source.test.mjs +299 -0
  230. package/templates/starter/scripts/toolcraft-motion-reference-publication-discovery.test.mjs +142 -0
  231. package/templates/starter/scripts/toolcraft-motion-reference-publication-isolation.test.mjs +234 -0
  232. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal-schema.mjs +122 -0
  233. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal-store.mjs +89 -0
  234. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal-store.test.mjs +74 -0
  235. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal.mjs +264 -0
  236. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal.test.mjs +377 -0
  237. package/templates/starter/scripts/toolcraft-motion-reference-publication-lease.mjs +254 -0
  238. package/templates/starter/scripts/toolcraft-motion-reference-publication-lease.test.mjs +130 -0
  239. package/templates/starter/scripts/toolcraft-motion-reference-publication-staging.mjs +128 -0
  240. package/templates/starter/scripts/toolcraft-motion-reference-publication-staging.test.mjs +209 -0
  241. package/templates/starter/scripts/toolcraft-motion-reference-publication.fixtures.mjs +88 -0
  242. package/templates/starter/scripts/toolcraft-motion-reference-publication.mjs +249 -0
  243. package/templates/starter/scripts/toolcraft-motion-reference-publication.test.mjs +433 -0
  244. package/templates/starter/scripts/toolcraft-motion-reference-review-output.mjs +38 -0
  245. package/templates/starter/scripts/toolcraft-motion-reference-review-output.test.mjs +29 -0
  246. package/templates/starter/scripts/toolcraft-motion-reference-root-safety.test.mjs +84 -0
  247. package/templates/starter/scripts/toolcraft-motion-reference-roots.mjs +83 -0
  248. package/templates/starter/scripts/toolcraft-motion-reference-sampling.mjs +283 -0
  249. package/templates/starter/scripts/toolcraft-motion-reference-sampling.test.mjs +480 -0
  250. package/templates/starter/scripts/toolcraft-motion-reference-stage-registry.mjs +39 -0
  251. package/templates/starter/scripts/toolcraft-motion-reference-stage-registry.test.mjs +59 -0
  252. package/templates/starter/scripts/toolcraft-motion-reference-stage.mjs +71 -0
  253. package/templates/starter/scripts/toolcraft-motion-reference-stage.test.mjs +61 -0
  254. package/templates/starter/scripts/toolcraft-motion-review-numeric.mjs +74 -0
  255. package/templates/starter/scripts/toolcraft-motion-review-numeric.test.mjs +65 -0
  256. package/templates/starter/scripts/toolcraft-motion-review-partitioning.mjs +268 -0
  257. package/templates/starter/scripts/toolcraft-motion-review-partitioning.test.mjs +329 -0
  258. package/templates/starter/scripts/toolcraft-motion-review-protected-units.mjs +120 -0
  259. package/templates/starter/scripts/toolcraft-motion-review-protected-units.test.mjs +111 -0
  260. package/templates/starter/scripts/toolcraft-performance-escalation-policy.test.mjs +77 -345
  261. package/templates/starter/scripts/toolcraft-performance-receipt-validation.test.mjs +19 -21
  262. package/templates/starter/scripts/toolcraft-product-boundary-ast.mjs +1 -1
  263. package/templates/starter/scripts/toolcraft-product-export-boundary.mjs +10 -1
  264. package/templates/starter/scripts/toolcraft-product-export-boundary.test.mjs +5 -1
  265. package/templates/starter/scripts/toolcraft-product-observable-facade.test.mjs +46 -1
  266. package/templates/starter/scripts/toolcraft-receipt-boundary.test.mjs +0 -1
  267. package/templates/starter/scripts/toolcraft-source-inventory.d.mts +5 -0
  268. package/templates/starter/scripts/toolcraft-source-inventory.mjs +25 -14
  269. package/templates/starter/scripts/toolcraft-source-inventory.test.mjs +48 -0
  270. package/templates/starter/scripts/toolcraft-source-ownership.mjs +0 -1
  271. package/templates/starter/scripts/toolcraft-source-ownership.test.mjs +30 -5
  272. package/templates/starter/scripts/toolcraft-verification-receipt-test-helpers.mjs +5 -26
  273. package/templates/starter/scripts/toolcraft-verification-receipt.d.mts +0 -7
  274. package/templates/starter/scripts/toolcraft-verification-receipt.mjs +3 -47
  275. package/templates/starter/scripts/toolcraft-verification-receipt.test.mjs +6 -87
  276. package/templates/starter/scripts/toolcraft-vitest-runtime-contract.d.mts +19 -0
  277. package/templates/starter/scripts/toolcraft-vitest-runtime-contract.mjs +107 -0
  278. package/templates/starter/scripts/toolcraft-vitest-runtime-contract.test.mjs +114 -0
  279. package/templates/starter/scripts/toolcraft-vitest-runtime-evidence-reporter.mjs +13 -2
  280. package/templates/starter/scripts/toolcraft-vitest-runtime-evidence-reporter.test.mjs +110 -0
  281. package/templates/starter/src/app/acceptance/artifact-export-intent.ts +51 -20
  282. package/templates/starter/src/app/acceptance/canvas-coverage.ts +1 -0
  283. package/templates/starter/src/app/acceptance/color-bank-labels.ts +11 -15
  284. package/templates/starter/src/app/acceptance/color-row-grouping.ts +33 -0
  285. package/templates/starter/src/app/acceptance/control-acceptance-coverage.ts +0 -11
  286. package/templates/starter/src/app/acceptance/control-acceptance-policy.ts +2 -3
  287. package/templates/starter/src/app/acceptance/control-component-rules.ts +0 -10
  288. package/templates/starter/src/app/acceptance/control-labels.ts +30 -1
  289. package/templates/starter/src/app/acceptance/control-layout-section-rules.ts +18 -0
  290. package/templates/starter/src/app/acceptance/export-artifact-coverage.ts +25 -17
  291. package/templates/starter/src/app/acceptance/feature-verification-selection.test.ts +295 -0
  292. package/templates/starter/src/app/acceptance/feature-verification-selection.ts +161 -0
  293. package/templates/starter/src/app/acceptance/infinity-canvas.ts +10 -0
  294. package/templates/starter/src/app/acceptance/interaction-ownership-intent.ts +19 -1
  295. package/templates/starter/src/app/acceptance/interaction-ownership.ts +18 -2
  296. package/templates/starter/src/app/acceptance/motion-reference-evidence-validation.mjs +65 -0
  297. package/templates/starter/src/app/acceptance/motion-reference-evidence-windows.mjs +301 -0
  298. package/templates/starter/src/app/acceptance/motion-reference-evidence.d.mts +11 -0
  299. package/templates/starter/src/app/acceptance/motion-reference-evidence.mjs +145 -0
  300. package/templates/starter/src/app/acceptance/motion-reference-study-behaviors.ts +162 -0
  301. package/templates/starter/src/app/acceptance/motion-reference-study-coverage.ts +206 -0
  302. package/templates/starter/src/app/acceptance/motion-reference-study-identity.ts +129 -0
  303. package/templates/starter/src/app/acceptance/motion-reference-study-partitions.ts +186 -0
  304. package/templates/starter/src/app/acceptance/motion-reference-study.ts +90 -0
  305. package/templates/starter/src/app/acceptance/output-export-actions.test.ts +9 -1
  306. package/templates/starter/src/app/acceptance/output-export-actions.ts +14 -22
  307. package/templates/starter/src/app/acceptance/output-export-layout-rules.ts +5 -1
  308. package/templates/starter/src/app/acceptance/output-export-model.ts +4 -0
  309. package/templates/starter/src/app/acceptance/output-export.ts +4 -1
  310. package/templates/starter/src/app/acceptance/reference-study-types.ts +167 -17
  311. package/templates/starter/src/app/acceptance/runtime-coverage.ts +6 -1
  312. package/templates/starter/src/app/acceptance/selection-scope.test.ts +200 -0
  313. package/templates/starter/src/app/acceptance/selection-scope.ts +151 -0
  314. package/templates/starter/src/app/acceptance/transfer-mode-types.ts +114 -0
  315. package/templates/starter/src/app/acceptance/types.ts +43 -118
  316. package/templates/starter/src/app/acceptance/validate-coverage.ts +14 -3
  317. package/templates/starter/src/app/starter-acceptance-data.ts +1 -0
  318. package/templates/starter/src/app/starter-acceptance.animation-intent.test.ts +3 -0
  319. package/templates/starter/src/app/starter-acceptance.artifact-export-intent.test.ts +81 -8
  320. package/templates/starter/src/app/starter-acceptance.background-export.test.ts +2 -0
  321. package/templates/starter/src/app/starter-acceptance.canvas-sizing.test.ts +2 -0
  322. package/templates/starter/src/app/starter-acceptance.color-row-grouping.test.ts +118 -0
  323. package/templates/starter/src/app/starter-acceptance.compound-part-coverage.test.ts +1 -1
  324. package/templates/starter/src/app/starter-acceptance.contract-fixtures.ts +1 -0
  325. package/templates/starter/src/app/starter-acceptance.control-applicability.test.ts +1 -0
  326. package/templates/starter/src/app/starter-acceptance.control-label-context.test.ts +1 -0
  327. package/templates/starter/src/app/starter-acceptance.control-labels.test.ts +78 -3
  328. package/templates/starter/src/app/starter-acceptance.control-naming-rules.test.ts +77 -1
  329. package/templates/starter/src/app/starter-acceptance.custom-control-fit-check.test.ts +1 -1
  330. package/templates/starter/src/app/starter-acceptance.export-artifact.test.ts +74 -3
  331. package/templates/starter/src/app/starter-acceptance.export-test-utils.ts +5 -1
  332. package/templates/starter/src/app/starter-acceptance.image-export-settings.test.ts +2 -0
  333. package/templates/starter/src/app/starter-acceptance.interaction-ownership.test.ts +19 -3
  334. package/templates/starter/src/app/starter-acceptance.layers.test.ts +2 -1
  335. package/templates/starter/src/app/starter-acceptance.media-upload.test.ts +28 -0
  336. package/templates/starter/src/app/starter-acceptance.motion-reference-evidence.test.ts +17 -0
  337. package/templates/starter/src/app/starter-acceptance.motion-reference-identity.test.ts +163 -0
  338. package/templates/starter/src/app/starter-acceptance.motion-reference-mapping.test.ts +133 -0
  339. package/templates/starter/src/app/starter-acceptance.motion-reference-ownership.test.ts +121 -0
  340. package/templates/starter/src/app/starter-acceptance.motion-reference-partitions.test.ts +210 -0
  341. package/templates/starter/src/app/starter-acceptance.motion-reference-test-utils.ts +313 -0
  342. package/templates/starter/src/app/starter-acceptance.output-export-intent.test.ts +78 -4
  343. package/templates/starter/src/app/starter-acceptance.product-output-export.test.ts +6 -1
  344. package/templates/starter/src/app/starter-acceptance.product-readiness.test.ts +18 -1
  345. package/templates/starter/src/app/starter-acceptance.product-worklog.test.ts +123 -2
  346. package/templates/starter/src/app/starter-acceptance.reference-custom-timeline.test.ts +2 -0
  347. package/templates/starter/src/app/starter-acceptance.reference-foundation.test.ts +8 -0
  348. package/templates/starter/src/app/starter-acceptance.reference-timeline.test.ts +7 -0
  349. package/templates/starter/src/app/starter-acceptance.section-cohesion.test.ts +2 -0
  350. package/templates/starter/src/app/starter-acceptance.timeline-playback.test.ts +5 -0
  351. package/templates/starter/src/app/starter-acceptance.ts +34 -8
  352. package/templates/starter/src/app/starter-acceptance.video-export-settings.test.ts +2 -0
  353. package/templates/starter/src/app/starter-acceptance.video-reference-study.test.ts +34 -236
  354. package/templates/starter/src/app/starter-acceptance.view-interaction.test.ts +4 -0
  355. package/templates/starter/src/app/starter-acceptance.worklog-test-utils.ts +122 -6
  356. package/templates/starter/src/app/starter-acceptance.worklog.test.ts +152 -16
  357. package/templates/starter/src/app/starter-performance.gates.test.ts +20 -18
  358. package/templates/starter/src/app/starter-performance.lifecycle.test.ts +22 -6
  359. package/templates/starter/src/app/test-evidence/browser-runtime-contract.ts +3 -0
  360. package/templates/starter/tsconfig.json +1 -0
  361. package/templates/starter/scripts/toolcraft-browser-impact-selection.mjs +0 -26
  362. package/templates/starter/scripts/toolcraft-delivery-framework-refresh.test.mjs +0 -141
  363. package/templates/starter/scripts/toolcraft-delivery-functional-changed.test.mjs +0 -468
  364. package/templates/starter/scripts/toolcraft-delivery-functional-model-lifecycle.test.mjs +0 -254
  365. package/templates/starter/scripts/toolcraft-delivery-functional-semantic-regression.test.mjs +0 -135
  366. package/templates/starter/scripts/toolcraft-delivery-performance-iteration-durability.test.mjs +0 -329
  367. package/templates/starter/scripts/toolcraft-delivery-plan-errors.test.mjs +0 -430
  368. package/templates/starter/scripts/toolcraft-delivery-plan-functional-model.test.mjs +0 -358
  369. package/templates/starter/scripts/toolcraft-functional-proof-regression-fixtures.mjs +0 -298
  370. package/templates/starter/scripts/toolcraft-verification-impact-inventory.d.mts +0 -62
  371. package/templates/starter/scripts/toolcraft-verification-impact-inventory.mjs +0 -344
  372. package/templates/starter/scripts/toolcraft-verification-impact-inventory.test.mjs +0 -204
  373. package/templates/starter/scripts/toolcraft-verification-impact-performance-candidates.test.mjs +0 -210
  374. package/templates/starter/scripts/toolcraft-verification-impact-resolution.mjs +0 -344
  375. package/templates/starter/scripts/toolcraft-verification-impact-resolution.test.mjs +0 -270
  376. package/templates/starter/scripts/toolcraft-verification-impact-semantic-resolution.test.mjs +0 -449
  377. package/templates/starter/scripts/toolcraft-verification-impact-support-resolution.test.mjs +0 -195
  378. package/templates/starter/scripts/toolcraft-verification-impact.d.mts +0 -132
  379. package/templates/starter/scripts/toolcraft-verification-impact.mjs +0 -169
  380. package/templates/starter/scripts/toolcraft-verification-impact.test.mjs +0 -300
  381. package/templates/starter/scripts/toolcraft-verification-input-roles.mjs +0 -197
  382. package/templates/starter/scripts/toolcraft-verification-input-roles.test.mjs +0 -225
  383. package/templates/starter/src/app/acceptance/video-reference-study.ts +0 -217
  384. package/templates/starter/src/app/starter-verification-impact.json +0 -15
@@ -0,0 +1,137 @@
1
+ import { expect, test } from "@playwright/test";
2
+
3
+ import { createToolcraftBrowserProofSession } from "./browser-proof-session";
4
+ import { expectToolcraftSelectionScopedControl } from "./browser-selection-scope-evidence";
5
+ import {
6
+ attachedEvidenceTypes,
7
+ editSyntheticSelectedEntity,
8
+ mountSyntheticSelectionScene,
9
+ } from "./browser-semantic-evidence-test-helpers";
10
+
11
+ const propertyTarget = "selectedShape.fill";
12
+ const selectionTarget = "selection.activeShape";
13
+ const entityA = {
14
+ entityId: "shape-a",
15
+ selector: '[data-proof-entity="shape-a"]',
16
+ } as const;
17
+ const entityB = {
18
+ entityId: "shape-b",
19
+ selector: '[data-proof-entity="shape-b"]',
20
+ } as const;
21
+
22
+ async function createSelectionProofFixture(
23
+ page: Parameters<typeof createToolcraftBrowserProofSession>[0],
24
+ ) {
25
+ await page.goto("/");
26
+ const session = await createToolcraftBrowserProofSession(page);
27
+ await mountSyntheticSelectionScene(page, {
28
+ controlValue: "#371C4D",
29
+ fills: { "shape-a": "#A65F15", "shape-b": "#371C4D" },
30
+ selectedEntityId: "shape-b",
31
+ });
32
+
33
+ return {
34
+ observePropertyValue: session.observe((root) =>
35
+ JSON.parse(root.getAttribute("data-proof-selection-scope") ?? "null")
36
+ .controlValue,
37
+ ),
38
+ observeSelectedEntityId: session.observe((root) =>
39
+ String(
40
+ JSON.parse(root.getAttribute("data-proof-selection-scope") ?? "null")
41
+ .selectedEntityId,
42
+ ),
43
+ ),
44
+ proofSession: session,
45
+ };
46
+ }
47
+
48
+ function createSelectionActions(
49
+ session: Awaited<
50
+ ReturnType<typeof createSelectionProofFixture>
51
+ >["proofSession"],
52
+ ) {
53
+ return {
54
+ selectEntityA: session.surfaceAction(selectionTarget, {
55
+ selector: entityA.selector,
56
+ surface: "canvas",
57
+ }),
58
+ selectEntityB: session.surfaceAction(selectionTarget, {
59
+ selector: entityB.selector,
60
+ surface: "canvas",
61
+ }),
62
+ };
63
+ }
64
+
65
+ test("selection-scoped control proves two-direction entity isolation", async ({
66
+ page,
67
+ }, testInfo) => {
68
+ const fixture = await createSelectionProofFixture(page);
69
+ const attachmentCount = testInfo.attachments.length;
70
+
71
+ await expectToolcraftSelectionScopedControl({
72
+ ...fixture,
73
+ ...createSelectionActions(fixture.proofSession),
74
+ editEntityA: fixture.proofSession.controlAction(
75
+ propertyTarget,
76
+ (_control, currentPage) =>
77
+ editSyntheticSelectedEntity(currentPage, "#00AAFF"),
78
+ ),
79
+ editEntityB: fixture.proofSession.controlAction(
80
+ propertyTarget,
81
+ (_control, currentPage) =>
82
+ editSyntheticSelectedEntity(currentPage, "#FF44AA"),
83
+ ),
84
+ entityA,
85
+ entityB,
86
+ propertySurface: "panel",
87
+ propertyTarget,
88
+ requirementId: "shape.selected-fill",
89
+ selectionSurface: "canvas",
90
+ selectionTarget,
91
+ stabilityIntervalMs: 0,
92
+ });
93
+
94
+ expect(attachedEvidenceTypes(testInfo, attachmentCount)).toEqual([
95
+ "product-observable-change",
96
+ "selection-scoped-control",
97
+ ]);
98
+ });
99
+
100
+ test("selection-scoped control rejects cross-entity mutation without evidence", async ({
101
+ page,
102
+ }, testInfo) => {
103
+ const fixture = await createSelectionProofFixture(page);
104
+ const attachmentCount = testInfo.attachments.length;
105
+
106
+ await expect(
107
+ expectToolcraftSelectionScopedControl({
108
+ ...fixture,
109
+ ...createSelectionActions(fixture.proofSession),
110
+ editEntityA: fixture.proofSession.controlAction(
111
+ propertyTarget,
112
+ async (_control, currentPage) => {
113
+ await editSyntheticSelectedEntity(currentPage, "#00AAFF");
114
+ await currentPage
115
+ .locator(entityB.selector)
116
+ .evaluate((entity) => {
117
+ (entity as HTMLElement).style.background = "#FFFFFF";
118
+ });
119
+ },
120
+ ),
121
+ editEntityB: fixture.proofSession.controlAction(
122
+ propertyTarget,
123
+ (_control, currentPage) =>
124
+ editSyntheticSelectedEntity(currentPage, "#FF44AA"),
125
+ ),
126
+ entityA,
127
+ entityB,
128
+ propertySurface: "panel",
129
+ propertyTarget,
130
+ requirementId: "shape.cross-entity-fill",
131
+ selectionSurface: "canvas",
132
+ selectionTarget,
133
+ stabilityIntervalMs: 0,
134
+ }),
135
+ ).rejects.toThrow();
136
+ expect(testInfo.attachments).toHaveLength(attachmentCount);
137
+ });
@@ -0,0 +1,42 @@
1
+ import { expect } from "@playwright/test";
2
+
3
+ import { attachToolcraftBrowserRuntimeEvidence } from "./browser-runtime-evidence";
4
+ import type { ToolcraftSvgArtifactInspection } from "./export-artifact-helpers";
5
+ import { assertToolcraftInspectedSvgArtifact } from "./svg-artifact-inspection";
6
+
7
+ export async function expectToolcraftInfinityCanvasSvgExportEvidence(
8
+ artifacts: Readonly<{
9
+ finite: ToolcraftSvgArtifactInspection;
10
+ infinite: ToolcraftSvgArtifactInspection;
11
+ }>,
12
+ options: Readonly<{
13
+ expectedFiniteSize: Readonly<{ height: number; width: number }>;
14
+ expectedInfiniteSize: Readonly<{ height: number; width: number }>;
15
+ requirementId: string;
16
+ target: string;
17
+ }>,
18
+ ): Promise<void> {
19
+ assertToolcraftInspectedSvgArtifact(artifacts.finite);
20
+ assertToolcraftInspectedSvgArtifact(artifacts.infinite);
21
+ expect(artifacts.finite).toMatchObject(options.expectedFiniteSize);
22
+ expect(artifacts.infinite).toMatchObject(options.expectedInfiniteSize);
23
+
24
+ for (const artifact of [artifacts.finite, artifacts.infinite]) {
25
+ expect(artifact.byteLength).toBeGreaterThan(100);
26
+ expect(artifact.contentHash).toMatch(/^[a-f0-9]{64}$/u);
27
+ expect(artifact.mediaType).toBe("image/svg+xml");
28
+ expect(artifact.vectorElementCount).toBeGreaterThan(0);
29
+ }
30
+
31
+ expect({ height: artifacts.infinite.height, width: artifacts.infinite.width })
32
+ .not.toEqual({
33
+ height: artifacts.finite.height,
34
+ width: artifacts.finite.width,
35
+ });
36
+
37
+ await attachToolcraftBrowserRuntimeEvidence({
38
+ evidenceType: "infinity-scene-bounds-svg-export",
39
+ requirementId: options.requirementId,
40
+ target: options.target,
41
+ });
42
+ }
@@ -11,6 +11,10 @@ import {
11
11
  type ToolcraftBrowserAction,
12
12
  type ToolcraftBrowserObservation,
13
13
  } from "./browser-proof-session";
14
+ import {
15
+ expectToolcraftSelectionScopedControl,
16
+ type ToolcraftSelectionScopedControlOptions,
17
+ } from "./browser-selection-scope-evidence";
14
18
 
15
19
  export type ToolcraftLayerCollectionObservation = {
16
20
  layerIds: readonly string[];
@@ -22,12 +26,6 @@ export type ToolcraftLayerGroupingObservation =
22
26
  groupSignature: string;
23
27
  };
24
28
 
25
- export type ToolcraftLayerSelectedControlObservation = {
26
- controlValue: unknown;
27
- outputSignature: string;
28
- selectedLayerId: string;
29
- };
30
-
31
29
  export type ToolcraftLayerSelectionObservation = {
32
30
  selectedLayerId: string;
33
31
  };
@@ -223,37 +221,18 @@ export async function expectToolcraftLayerGrouping(
223
221
  return after;
224
222
  }
225
223
 
224
+ export type ToolcraftSelectedLayerControlOptions =
225
+ ToolcraftSelectionScopedControlOptions;
226
+
226
227
  export async function expectToolcraftSelectedLayerControl(
227
- observeControl: ToolcraftBrowserObservation<ToolcraftLayerSelectedControlObservation>,
228
- action: ToolcraftBrowserAction,
229
- expected: ToolcraftLayerSelectedControlObservation,
230
- options: ToolcraftSemanticEvidenceOptions,
231
- ): Promise<ToolcraftLayerSelectedControlObservation> {
232
- const target = requireLayerActionTarget(action, options.requirementId);
233
- validateIdentifier(expected.selectedLayerId, "Selected-layer control requires a layer id.");
234
- validateIdentifier(
235
- expected.outputSignature,
236
- "Selected-layer control requires product-output semantics.",
237
- );
238
- const { after, before } = await expectToolcraftExpectedOutcomeAfterAction(
239
- observeControl,
240
- action,
241
- expected,
242
- createToolcraftSemanticTransitionOptions(
243
- `Selected-layer control "${options.requirementId}" should edit the selected layer output.`,
244
- options,
245
- ),
246
- );
247
- expect(before.selectedLayerId).toBe(after.selectedLayerId);
248
- expect(before.controlValue).not.toEqual(after.controlValue);
249
- expect(before.outputSignature).not.toBe(after.outputSignature);
250
- await attachLayerEvidence(
251
- "media-lifecycle",
252
- "layer-selected-layer-controls",
253
- options.requirementId,
254
- target,
255
- );
256
- return after;
228
+ options: ToolcraftSelectedLayerControlOptions,
229
+ ): Promise<void> {
230
+ await expectToolcraftSelectionScopedControl(options);
231
+ await attachToolcraftBrowserRuntimeEvidence({
232
+ evidenceType: "layer-selected-layer-controls",
233
+ requirementId: options.requirementId,
234
+ target: options.propertyTarget,
235
+ });
257
236
  }
258
237
 
259
238
  export async function expectToolcraftLayerMediaLifecycle(
@@ -0,0 +1,213 @@
1
+ import { expect, type Locator, type Page } from "@playwright/test";
2
+
3
+ const maxRasterDimension = 4096;
4
+ const maxRasterPixelArea = 8_388_608;
5
+ const screenshotOptions = Object.freeze({
6
+ animations: "disabled" as const,
7
+ caret: "hide" as const,
8
+ scale: "css" as const,
9
+ type: "png" as const,
10
+ });
11
+ const warmedSelectors = new WeakMap<Page, Set<string>>();
12
+
13
+ export type ToolcraftProductRasterRegion = Readonly<{
14
+ height: number;
15
+ width: number;
16
+ x: number;
17
+ y: number;
18
+ }>;
19
+
20
+ export type ToolcraftProductRasterProbe = Readonly<{
21
+ region?: ToolcraftProductRasterRegion;
22
+ selector: string;
23
+ }>;
24
+
25
+ export type ToolcraftResolvedProductRasterProbe = Readonly<{
26
+ bounds: ToolcraftProductRasterRegion;
27
+ capture: () => Promise<string>;
28
+ locator: Locator;
29
+ }>;
30
+
31
+ function validateRegion(
32
+ region: ToolcraftProductRasterRegion,
33
+ ownerWidth: number,
34
+ ownerHeight: number,
35
+ label: string,
36
+ ): void {
37
+ if (
38
+ !Number.isFinite(region.x) ||
39
+ !Number.isFinite(region.y) ||
40
+ !Number.isFinite(region.width) ||
41
+ !Number.isFinite(region.height) ||
42
+ region.x < 0 ||
43
+ region.y < 0 ||
44
+ region.width <= 0 ||
45
+ region.height <= 0 ||
46
+ region.x + region.width > ownerWidth ||
47
+ region.y + region.height > ownerHeight
48
+ ) {
49
+ throw new Error(
50
+ `Raster probe "${label}" requires a finite positive region inside its visible selector.`,
51
+ );
52
+ }
53
+ }
54
+
55
+ async function decodeRasterSnapshot(
56
+ page: Page,
57
+ raster: Buffer,
58
+ region: ToolcraftProductRasterRegion | undefined,
59
+ selector: string,
60
+ ): Promise<string> {
61
+ const snapshot = await page.evaluate(
62
+ async ({ encoded, maxDimension, maxPixelArea, probeRegion, selector }) => {
63
+ const binary = atob(encoded);
64
+ const bytes = Uint8Array.from(
65
+ binary,
66
+ (character) => character.charCodeAt(0),
67
+ );
68
+ const bitmap = await createImageBitmap(
69
+ new Blob([bytes], { type: "image/png" }),
70
+ );
71
+
72
+ try {
73
+ const source = probeRegion ?? {
74
+ height: bitmap.height,
75
+ width: bitmap.width,
76
+ x: 0,
77
+ y: 0,
78
+ };
79
+ if (
80
+ source.width > maxDimension ||
81
+ source.height > maxDimension ||
82
+ source.width * source.height > maxPixelArea
83
+ ) {
84
+ throw new Error(
85
+ `Raster probe "${selector}" exceeds the bounded visual proof limit (${source.width}x${source.height}).`,
86
+ );
87
+ }
88
+
89
+ const canvas = document.createElement("canvas");
90
+ canvas.width = Math.ceil(source.width);
91
+ canvas.height = Math.ceil(source.height);
92
+ const context = canvas.getContext("2d", { willReadFrequently: true });
93
+ if (!context) {
94
+ throw new Error(
95
+ `Raster probe "${selector}" could not decode its visual pixels.`,
96
+ );
97
+ }
98
+ context.drawImage(
99
+ bitmap,
100
+ source.x,
101
+ source.y,
102
+ source.width,
103
+ source.height,
104
+ 0,
105
+ 0,
106
+ source.width,
107
+ source.height,
108
+ );
109
+ const pixels = context.getImageData(
110
+ 0,
111
+ 0,
112
+ canvas.width,
113
+ canvas.height,
114
+ ).data;
115
+ const digest = await crypto.subtle.digest(
116
+ "SHA-256",
117
+ new Uint8Array(
118
+ pixels.buffer,
119
+ pixels.byteOffset,
120
+ pixels.byteLength,
121
+ ),
122
+ );
123
+ return {
124
+ height: canvas.height,
125
+ rasterHash: [...new Uint8Array(digest)]
126
+ .map((byte) => byte.toString(16).padStart(2, "0"))
127
+ .join(""),
128
+ width: canvas.width,
129
+ };
130
+ } finally {
131
+ bitmap.close();
132
+ }
133
+ },
134
+ {
135
+ encoded: raster.toString("base64"),
136
+ maxDimension: maxRasterDimension,
137
+ maxPixelArea: maxRasterPixelArea,
138
+ probeRegion: region,
139
+ selector,
140
+ },
141
+ );
142
+
143
+ return JSON.stringify(snapshot);
144
+ }
145
+
146
+ export async function resolveToolcraftProductRasterProbe(
147
+ page: Page,
148
+ probe: ToolcraftProductRasterProbe,
149
+ timeoutMs = 5000,
150
+ ): Promise<ToolcraftResolvedProductRasterProbe> {
151
+ if (!probe.selector.trim()) {
152
+ throw new Error("A raster probe requires a non-empty selector.");
153
+ }
154
+
155
+ const locator = page.locator(probe.selector);
156
+ await expect(
157
+ locator,
158
+ `Raster probe "${probe.selector}" must resolve exactly once.`,
159
+ ).toHaveCount(1);
160
+ await expect(locator).toBeVisible({ timeout: timeoutMs });
161
+ const ownerBounds = await locator.boundingBox();
162
+ if (
163
+ ownerBounds === null ||
164
+ !Number.isFinite(ownerBounds.width) ||
165
+ !Number.isFinite(ownerBounds.height) ||
166
+ ownerBounds.width <= 0 ||
167
+ ownerBounds.height <= 0
168
+ ) {
169
+ throw new Error(
170
+ `Raster probe "${probe.selector}" must have finite positive visible bounds.`,
171
+ );
172
+ }
173
+
174
+ if (probe.region) {
175
+ validateRegion(
176
+ probe.region,
177
+ ownerBounds.width,
178
+ ownerBounds.height,
179
+ probe.selector,
180
+ );
181
+ }
182
+ const localBounds = probe.region ?? {
183
+ height: ownerBounds.height,
184
+ width: ownerBounds.width,
185
+ x: 0,
186
+ y: 0,
187
+ };
188
+ const bounds = {
189
+ height: localBounds.height,
190
+ width: localBounds.width,
191
+ x: ownerBounds.x + localBounds.x,
192
+ y: ownerBounds.y + localBounds.y,
193
+ };
194
+
195
+ return {
196
+ bounds,
197
+ capture: async () => {
198
+ const pageSelectors = warmedSelectors.get(page) ?? new Set<string>();
199
+ const key = `${probe.selector}:${JSON.stringify(probe.region ?? null)}`;
200
+ if (!pageSelectors.has(key)) {
201
+ await locator.screenshot(screenshotOptions);
202
+ await page.evaluate(
203
+ () => new Promise<void>((resolve) => requestAnimationFrame(() => resolve())),
204
+ );
205
+ pageSelectors.add(key);
206
+ warmedSelectors.set(page, pageSelectors);
207
+ }
208
+ const raster = await locator.screenshot(screenshotOptions);
209
+ return decodeRasterSnapshot(page, raster, probe.region, probe.selector);
210
+ },
211
+ locator,
212
+ };
213
+ }
@@ -6,27 +6,27 @@ import {
6
6
  } from "@playwright/test";
7
7
 
8
8
  import { getToolcraftControlFieldByTarget } from "./browser-control-target-helpers";
9
-
9
+ import {
10
+ createToolcraftSurfaceActionRunner,
11
+ normalizeToolcraftSurfaceActionOptions,
12
+ type ToolcraftBrowserActionSurface,
13
+ type ToolcraftBrowserSurfaceActionOptions,
14
+ } from "./browser-proof-surface-action";
15
+ import type {
16
+ ToolcraftBrowserAction,
17
+ ToolcraftBrowserObservation,
18
+ } from "./browser-proof-types";
10
19
  const TOOLCRAFT_APP_ROOT_SELECTOR = '[data-slot="toolcraft-runtime-app"]';
11
20
  const TOOLCRAFT_APP_TITLE_SELECTOR = 'meta[name="toolcraft-app-title"]';
12
21
  const TOOLCRAFT_SERVER_IDENTITY_PATH = "/.toolcraft/server-identity.json";
13
22
 
14
- declare const toolcraftBrowserActionBrand: unique symbol;
15
- declare const toolcraftBrowserObservationBrand: unique symbol;
16
23
  declare const toolcraftBrowserSessionBrand: unique symbol;
17
24
 
18
- export type ToolcraftBrowserAction<
19
- Kind extends string = "interaction",
20
- Result = void,
21
- > = {
22
- readonly [toolcraftBrowserActionBrand]: true;
23
- readonly kind?: Kind;
24
- readonly result?: Result;
25
- };
26
-
27
- export type ToolcraftBrowserObservation<T> = {
28
- readonly [toolcraftBrowserObservationBrand]: T;
29
- };
25
+ export type {
26
+ ToolcraftBrowserAction,
27
+ ToolcraftBrowserObservation,
28
+ } from "./browser-proof-types";
29
+ export type { ToolcraftBrowserActionSurface } from "./browser-proof-surface-action";
30
30
 
31
31
  export type ToolcraftBrowserProofSession = {
32
32
  action<Result = void>(
@@ -36,6 +36,10 @@ export type ToolcraftBrowserProofSession = {
36
36
  target: string,
37
37
  run: (control: Locator, page: Page) => Promise<Result>,
38
38
  ): ToolcraftBrowserAction<"interaction", Result>;
39
+ surfaceAction(
40
+ target: string,
41
+ options: ToolcraftBrowserSurfaceActionOptions,
42
+ ): ToolcraftBrowserAction<"interaction">;
39
43
  targetAction<Result = void>(
40
44
  target: string,
41
45
  run: (page: Page) => Promise<Result>,
@@ -60,6 +64,7 @@ type ActionRecord = {
60
64
  kind: "interaction" | "reload";
61
65
  run: (page: Page) => Promise<unknown>;
62
66
  session: SessionRecord;
67
+ surface?: ToolcraftBrowserActionSurface;
63
68
  target?: string;
64
69
  };
65
70
 
@@ -289,6 +294,23 @@ export async function createToolcraftBrowserProofSession(
289
294
  return run(control, currentPage);
290
295
  },
291
296
  session: record,
297
+ surface: "panel",
298
+ target: normalizedTarget,
299
+ });
300
+ return action;
301
+ },
302
+ surfaceAction(
303
+ target: string,
304
+ rawOptions: ToolcraftBrowserSurfaceActionOptions,
305
+ ): ToolcraftBrowserAction<"interaction"> {
306
+ const normalizedTarget = normalizeActionTarget(target);
307
+ const options = normalizeToolcraftSurfaceActionOptions(rawOptions);
308
+ const action = Object.freeze({}) as ToolcraftBrowserAction<"interaction">;
309
+ actionRecords.set(action, {
310
+ kind: "interaction",
311
+ run: createToolcraftSurfaceActionRunner(options),
312
+ session: record,
313
+ surface: options.surface,
292
314
  target: normalizedTarget,
293
315
  });
294
316
  return action;
@@ -364,6 +386,12 @@ export function getToolcraftBrowserActionTarget(
364
386
  return requireAction(action).target;
365
387
  }
366
388
 
389
+ export function getToolcraftBrowserActionSurface(
390
+ action: ToolcraftBrowserAction,
391
+ ): ToolcraftBrowserActionSurface | undefined {
392
+ return requireAction(action).surface;
393
+ }
394
+
367
395
  export async function readToolcraftBrowserObservation<T>(
368
396
  observation: ToolcraftBrowserObservation<T>,
369
397
  ): Promise<T> {
@@ -0,0 +1,79 @@
1
+ import { expect, type Page } from "@playwright/test";
2
+
3
+ export type ToolcraftBrowserActionSurface = "canvas" | "panel";
4
+
5
+ export type ToolcraftBrowserSurfaceActionOptions = Readonly<{
6
+ position?: Readonly<{ x: number; y: number }>;
7
+ selector: string;
8
+ surface: ToolcraftBrowserActionSurface;
9
+ }>;
10
+
11
+ export function normalizeToolcraftSurfaceActionOptions(
12
+ options: ToolcraftBrowserSurfaceActionOptions,
13
+ ): ToolcraftBrowserSurfaceActionOptions {
14
+ if (!options.selector.trim()) {
15
+ throw new Error("A surface action requires a non-empty selector.");
16
+ }
17
+ if (options.surface !== "canvas" && options.surface !== "panel") {
18
+ throw new Error("A surface action requires canvas or panel ownership.");
19
+ }
20
+ if (
21
+ options.position &&
22
+ (!Number.isFinite(options.position.x) ||
23
+ !Number.isFinite(options.position.y) ||
24
+ options.position.x < 0 ||
25
+ options.position.y < 0)
26
+ ) {
27
+ throw new Error(
28
+ "A surface action position requires finite nonnegative coordinates.",
29
+ );
30
+ }
31
+ return options;
32
+ }
33
+
34
+ async function getToolcraftActionSurface(
35
+ page: Page,
36
+ options: ToolcraftBrowserSurfaceActionOptions,
37
+ ): Promise<ToolcraftBrowserActionSurface | null> {
38
+ return page.locator(options.selector).evaluate((element) => {
39
+ if (element.closest('[data-slot="toolcraft-runtime-canvas"]')) {
40
+ return "canvas";
41
+ }
42
+ if (
43
+ element.closest(
44
+ "[data-toolcraft-controls-panel-shell], [data-toolcraft-layers-panel]",
45
+ )
46
+ ) {
47
+ return "panel";
48
+ }
49
+ return null;
50
+ });
51
+ }
52
+
53
+ export function createToolcraftSurfaceActionRunner(
54
+ options: ToolcraftBrowserSurfaceActionOptions,
55
+ ): (page: Page) => Promise<void> {
56
+ return async (page) => {
57
+ const locator = page.locator(options.selector);
58
+ await expect(
59
+ locator,
60
+ `Surface action locator "${options.selector}" must resolve exactly once.`,
61
+ ).toHaveCount(1);
62
+ await expect(locator).toBeVisible();
63
+ expect(
64
+ await getToolcraftActionSurface(page, options),
65
+ `Surface action locator "${options.selector}" must live inside the declared ${options.surface} runtime surface.`,
66
+ ).toBe(options.surface);
67
+
68
+ if (options.position) {
69
+ const bounds = await locator.boundingBox();
70
+ expect(bounds).not.toBeNull();
71
+ expect(options.position.x).toBeLessThanOrEqual(bounds!.width);
72
+ expect(options.position.y).toBeLessThanOrEqual(bounds!.height);
73
+ }
74
+
75
+ await locator.click(
76
+ options.position ? { position: options.position } : undefined,
77
+ );
78
+ };
79
+ }
@@ -0,0 +1,15 @@
1
+ declare const toolcraftBrowserActionBrand: unique symbol;
2
+ declare const toolcraftBrowserObservationBrand: unique symbol;
3
+
4
+ export type ToolcraftBrowserAction<
5
+ Kind extends string = "interaction",
6
+ Result = void,
7
+ > = {
8
+ readonly [toolcraftBrowserActionBrand]: true;
9
+ readonly kind?: Kind;
10
+ readonly result?: Result;
11
+ };
12
+
13
+ export type ToolcraftBrowserObservation<T> = {
14
+ readonly [toolcraftBrowserObservationBrand]: T;
15
+ };