@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,149 @@
1
+ import { expect, test } from "@playwright/test";
2
+ import type { FullConfig, FullResult, Suite } from "@playwright/test/reporter";
3
+
4
+ import ToolcraftFeatureVerificationReporter, {
5
+ parseToolcraftFeatureVerificationRequest,
6
+ } from "./toolcraft-feature-verification-reporter";
7
+
8
+ const selectedPlan = Object.freeze({
9
+ acceptanceIds: Object.freeze(["material.layer"]),
10
+ testNames: Object.freeze(["browser: material.layer"]),
11
+ version: 1 as const,
12
+ });
13
+
14
+ function createSuite(testNames: readonly string[]): Suite {
15
+ return {
16
+ allTests: () => testNames.map((title) => ({ title })),
17
+ } as unknown as Suite;
18
+ }
19
+
20
+ const config = {} as FullConfig;
21
+ const result = { status: "passed" } as FullResult;
22
+
23
+ test("feature reporter parses only the exact versioned request shapes", () => {
24
+ expect(
25
+ parseToolcraftFeatureVerificationRequest(
26
+ '{"acceptanceIds":["material.layer"],"mode":"ids","version":1}',
27
+ ),
28
+ ).toEqual({ acceptanceIds: ["material.layer"], mode: "ids", version: 1 });
29
+ expect(
30
+ parseToolcraftFeatureVerificationRequest('{"mode":"all","version":1}'),
31
+ ).toEqual({ mode: "all", version: 1 });
32
+
33
+ for (const value of [
34
+ undefined,
35
+ "not-json",
36
+ '{"mode":"all","version":2}',
37
+ '{"mode":"all","version":1,"acceptanceIds":[]}',
38
+ '{"acceptanceIds":[],"mode":"ids","version":1}',
39
+ '{"acceptanceIds":["material.layer","material.layer"],"mode":"ids","version":1}',
40
+ '{"acceptanceIds":[" material.layer"],"mode":"ids","version":1}',
41
+ '{"acceptanceIds":["material.layer"],"mode":"ids","version":1,"extra":true}',
42
+ ]) {
43
+ expect(() => parseToolcraftFeatureVerificationRequest(value)).toThrow();
44
+ }
45
+ });
46
+
47
+ test("feature reporter selects current app semantics and emits exactly one plan line", async () => {
48
+ const output: string[] = [];
49
+ const selectionInputs: unknown[] = [];
50
+ const reporter = new ToolcraftFeatureVerificationReporter({
51
+ createSelection: (input) => {
52
+ selectionInputs.push(input);
53
+ return selectedPlan;
54
+ },
55
+ requestSource:
56
+ '{"acceptanceIds":["material.layer"],"mode":"ids","version":1}',
57
+ writeError: (source) => {
58
+ throw new Error(`Unexpected reporter error: ${source}`);
59
+ },
60
+ writeOutput: (source) => output.push(source),
61
+ });
62
+
63
+ reporter.onBegin(config, createSuite(selectedPlan.testNames));
64
+ await expect(reporter.onEnd(result)).resolves.toBeUndefined();
65
+ expect(selectionInputs).toHaveLength(1);
66
+ expect(selectionInputs[0]).toMatchObject({
67
+ acceptanceIds: ["material.layer"],
68
+ all: false,
69
+ });
70
+ expect(output).toEqual([`${JSON.stringify(selectedPlan)}\n`]);
71
+ });
72
+
73
+ test("feature reporter maps all mode without internal acceptance ids", async () => {
74
+ const inputs: unknown[] = [];
75
+ const reporter = new ToolcraftFeatureVerificationReporter({
76
+ createSelection: (input) => {
77
+ inputs.push(input);
78
+ return selectedPlan;
79
+ },
80
+ requestSource: '{"mode":"all","version":1}',
81
+ writeError: () => {},
82
+ writeOutput: () => {},
83
+ });
84
+
85
+ reporter.onBegin(config, createSuite(selectedPlan.testNames));
86
+ await expect(reporter.onEnd(result)).resolves.toBeUndefined();
87
+ expect(inputs[0]).toMatchObject({ all: true });
88
+ expect(inputs[0]).not.toHaveProperty("acceptanceIds");
89
+ });
90
+
91
+ test("feature reporter fails closed for absent and ambiguous selected tests", async () => {
92
+ for (const titles of [[], [...selectedPlan.testNames, ...selectedPlan.testNames]]) {
93
+ const errors: string[] = [];
94
+ const output: string[] = [];
95
+ const reporter = new ToolcraftFeatureVerificationReporter({
96
+ createSelection: () => selectedPlan,
97
+ requestSource: '{"mode":"all","version":1}',
98
+ writeError: (source) => errors.push(source),
99
+ writeOutput: (source) => output.push(source),
100
+ });
101
+
102
+ reporter.onBegin(config, createSuite(titles));
103
+ await expect(reporter.onEnd(result)).resolves.toEqual({ status: "failed" });
104
+ expect(output).toEqual([]);
105
+ expect(errors.join("\n")).toMatch(/exactly once/iu);
106
+ }
107
+ });
108
+
109
+ test("feature reporter suppresses output after malformed input or preparation failure", async () => {
110
+ for (const fixture of [
111
+ {
112
+ createSelection: () => selectedPlan,
113
+ requestSource: "not-json",
114
+ suite: createSuite(selectedPlan.testNames),
115
+ },
116
+ {
117
+ createSelection: () => {
118
+ throw new Error("unknown acceptance id");
119
+ },
120
+ requestSource: '{"mode":"all","version":1}',
121
+ suite: createSuite(selectedPlan.testNames),
122
+ },
123
+ ]) {
124
+ const errors: string[] = [];
125
+ const output: string[] = [];
126
+ const reporter = new ToolcraftFeatureVerificationReporter({
127
+ ...fixture,
128
+ writeError: (source) => errors.push(source),
129
+ writeOutput: (source) => output.push(source),
130
+ });
131
+
132
+ reporter.onBegin(config, fixture.suite);
133
+ await expect(reporter.onEnd(result)).resolves.toEqual({ status: "failed" });
134
+ expect(output).toEqual([]);
135
+ expect(errors).toHaveLength(1);
136
+ }
137
+ });
138
+
139
+ test("feature reporter fails when onEnd runs without onBegin", async () => {
140
+ const errors: string[] = [];
141
+ const reporter = new ToolcraftFeatureVerificationReporter({
142
+ requestSource: '{"mode":"all","version":1}',
143
+ writeError: (source) => errors.push(source),
144
+ writeOutput: () => {},
145
+ });
146
+
147
+ await expect(reporter.onEnd(result)).resolves.toEqual({ status: "failed" });
148
+ expect(errors.join("\n")).toMatch(/complete onBegin lifecycle/iu);
149
+ });
@@ -0,0 +1,223 @@
1
+ import type {
2
+ FullConfig,
3
+ FullResult,
4
+ Reporter,
5
+ Suite,
6
+ } from "@playwright/test/reporter";
7
+
8
+ import {
9
+ createToolcraftFeatureVerificationSelection,
10
+ starterAcceptance,
11
+ starterControlSectionInventory,
12
+ } from "../src/app/starter-acceptance";
13
+ import { starterSchema } from "../src/app/starter-schema";
14
+
15
+ export const TOOLCRAFT_FEATURE_VERIFICATION_REQUEST_ENV =
16
+ "TOOLCRAFT_FEATURE_VERIFICATION_REQUEST";
17
+
18
+ type ToolcraftFeatureVerificationRequest =
19
+ | Readonly<{
20
+ acceptanceIds: readonly string[];
21
+ mode: "ids";
22
+ version: 1;
23
+ }>
24
+ | Readonly<{
25
+ mode: "all";
26
+ version: 1;
27
+ }>;
28
+
29
+ type ToolcraftFeatureVerificationReporterState =
30
+ | Readonly<{ kind: "idle" }>
31
+ | Readonly<{ error: unknown; kind: "preparation-failed" }>
32
+ | Readonly<{
33
+ kind: "ready";
34
+ plan: ReturnType<typeof createToolcraftFeatureVerificationSelection>;
35
+ }>;
36
+
37
+ type ToolcraftFeatureVerificationReporterOptions = Readonly<{
38
+ createSelection?: typeof createToolcraftFeatureVerificationSelection;
39
+ requestSource?: string;
40
+ writeError?: (source: string) => void;
41
+ writeOutput?: (source: string) => void;
42
+ }>;
43
+
44
+ const compareCodeUnits = (left: string, right: string): number =>
45
+ left < right ? -1 : left > right ? 1 : 0;
46
+
47
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
48
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
49
+ return false;
50
+ }
51
+ const prototype = Object.getPrototypeOf(value);
52
+ return prototype === Object.prototype || prototype === null;
53
+ }
54
+
55
+ function requireExactKeys(
56
+ value: Record<string, unknown>,
57
+ expected: readonly string[],
58
+ ): void {
59
+ const expectedSet = new Set(expected);
60
+ const unknown = Reflect.ownKeys(value)
61
+ .filter((key) => typeof key !== "string" || !expectedSet.has(key))
62
+ .map(String)
63
+ .sort(compareCodeUnits);
64
+ const missing = expected.filter(
65
+ (key) => !Object.prototype.hasOwnProperty.call(value, key),
66
+ );
67
+ if (unknown.length > 0 || missing.length > 0) {
68
+ throw new Error(
69
+ [
70
+ ...(unknown.length > 0
71
+ ? [`unknown fields: ${unknown.join(", ")}`]
72
+ : []),
73
+ ...(missing.length > 0
74
+ ? [`missing fields: ${missing.join(", ")}`]
75
+ : []),
76
+ ].join("; "),
77
+ );
78
+ }
79
+ }
80
+
81
+ export function parseToolcraftFeatureVerificationRequest(
82
+ source: string | undefined,
83
+ ): ToolcraftFeatureVerificationRequest {
84
+ if (!source) {
85
+ throw new Error(
86
+ `${TOOLCRAFT_FEATURE_VERIFICATION_REQUEST_ENV} must contain one versioned JSON request.`,
87
+ );
88
+ }
89
+ let value: unknown;
90
+ try {
91
+ value = JSON.parse(source);
92
+ } catch (error) {
93
+ throw new Error(
94
+ `${TOOLCRAFT_FEATURE_VERIFICATION_REQUEST_ENV} must contain valid JSON.`,
95
+ { cause: error },
96
+ );
97
+ }
98
+ if (!isPlainObject(value)) {
99
+ throw new Error(
100
+ `${TOOLCRAFT_FEATURE_VERIFICATION_REQUEST_ENV} must contain a plain object.`,
101
+ );
102
+ }
103
+ if (value.mode === "all") {
104
+ requireExactKeys(value, ["mode", "version"]);
105
+ if (value.version !== 1) {
106
+ throw new Error("Toolcraft feature verification request.version must be 1.");
107
+ }
108
+ return Object.freeze({ mode: "all", version: 1 });
109
+ }
110
+ if (value.mode !== "ids") {
111
+ throw new Error(
112
+ "Toolcraft feature verification request.mode must be ids or all.",
113
+ );
114
+ }
115
+ requireExactKeys(value, ["acceptanceIds", "mode", "version"]);
116
+ if (value.version !== 1) {
117
+ throw new Error("Toolcraft feature verification request.version must be 1.");
118
+ }
119
+ if (
120
+ !Array.isArray(value.acceptanceIds) ||
121
+ value.acceptanceIds.length === 0 ||
122
+ !value.acceptanceIds.every(
123
+ (id) => typeof id === "string" && id.length > 0 && id.trim() === id,
124
+ )
125
+ ) {
126
+ throw new Error(
127
+ "Toolcraft feature verification request.acceptanceIds must be a non-empty array of trimmed strings.",
128
+ );
129
+ }
130
+ if (new Set(value.acceptanceIds).size !== value.acceptanceIds.length) {
131
+ throw new Error(
132
+ "Toolcraft feature verification request.acceptanceIds must be unique.",
133
+ );
134
+ }
135
+ return Object.freeze({
136
+ acceptanceIds: Object.freeze([...value.acceptanceIds]),
137
+ mode: "ids",
138
+ version: 1,
139
+ });
140
+ }
141
+
142
+ function describeError(error: unknown): string {
143
+ if (!(error instanceof Error)) return String(error);
144
+ const cause = error.cause === undefined ? "" : `\nCaused by: ${describeError(error.cause)}`;
145
+ return `${error.stack ?? `${error.name}: ${error.message}`}${cause}`;
146
+ }
147
+
148
+ function assertSelectedTitlesExistExactlyOnce(
149
+ selectedTitles: readonly string[],
150
+ suite: Suite,
151
+ ): void {
152
+ const availableTitles = suite.allTests().map(({ title }) => title);
153
+ for (const selectedTitle of selectedTitles) {
154
+ const count = availableTitles.filter((title) => title === selectedTitle).length;
155
+ if (count !== 1) {
156
+ throw new Error(
157
+ `Selected browser test "${selectedTitle}" must occur exactly once in the Playwright suite; found ${count}.`,
158
+ );
159
+ }
160
+ }
161
+ }
162
+
163
+ export default class ToolcraftFeatureVerificationReporter implements Reporter {
164
+ private readonly createSelection: typeof createToolcraftFeatureVerificationSelection;
165
+ private readonly requestSource: string | undefined;
166
+ private state: ToolcraftFeatureVerificationReporterState = { kind: "idle" };
167
+ private readonly writeError: (source: string) => void;
168
+ private readonly writeOutput: (source: string) => void;
169
+
170
+ constructor(options: ToolcraftFeatureVerificationReporterOptions = {}) {
171
+ this.createSelection =
172
+ options.createSelection ?? createToolcraftFeatureVerificationSelection;
173
+ this.requestSource =
174
+ options.requestSource ?? process.env[TOOLCRAFT_FEATURE_VERIFICATION_REQUEST_ENV];
175
+ this.writeError = options.writeError ?? ((source) => process.stderr.write(source));
176
+ this.writeOutput = options.writeOutput ?? ((source) => process.stdout.write(source));
177
+ }
178
+
179
+ onBegin(_config: FullConfig, suite: Suite): void {
180
+ try {
181
+ const request = parseToolcraftFeatureVerificationRequest(this.requestSource);
182
+ const plan = this.createSelection({
183
+ acceptance: starterAcceptance,
184
+ ...(request.mode === "all"
185
+ ? { all: true }
186
+ : { acceptanceIds: request.acceptanceIds, all: false }),
187
+ schema: starterSchema,
188
+ sectionInventory: starterControlSectionInventory,
189
+ });
190
+ assertSelectedTitlesExistExactlyOnce(plan.testNames, suite);
191
+ this.state = { kind: "ready", plan };
192
+ } catch (error) {
193
+ this.state = { error, kind: "preparation-failed" };
194
+ }
195
+ }
196
+
197
+ async onEnd(_result: FullResult): Promise<{ status: "failed" } | void> {
198
+ switch (this.state.kind) {
199
+ case "idle":
200
+ return this.reportFailure(
201
+ new Error(
202
+ "Toolcraft feature verification reporter did not receive a complete onBegin lifecycle.",
203
+ ),
204
+ );
205
+ case "preparation-failed":
206
+ return this.reportFailure(this.state.error);
207
+ case "ready":
208
+ this.writeOutput(`${JSON.stringify(this.state.plan)}\n`);
209
+ return;
210
+ }
211
+ }
212
+
213
+ private reportFailure(error: unknown): { status: "failed" } {
214
+ this.writeError(
215
+ `Toolcraft feature verification collection failed:\n${describeError(error)}\n`,
216
+ );
217
+ return { status: "failed" };
218
+ }
219
+
220
+ printsToStdio(): boolean {
221
+ return true;
222
+ }
223
+ }
@@ -10,10 +10,12 @@
10
10
  "build": "tsc -p tsconfig.json --noEmit && vite build",
11
11
  "preview": "node scripts/run-vite-on-free-port.mjs preview",
12
12
  "preview:restart": "node scripts/run-vite-on-free-port.mjs preview --toolcraft-restart",
13
+ "reference:study": "node scripts/create-toolcraft-motion-reference-study.mjs",
13
14
  "docs:check": "node scripts/check-toolcraft-docs.mjs",
14
15
  "test": "node scripts/check-toolcraft-docs.mjs && node --test scripts/*.test.mjs && vitest run src --passWithNoTests --reporter=default --reporter=./scripts/toolcraft-vitest-runtime-evidence-reporter.mjs",
15
16
  "test:generated": "node scripts/check-toolcraft-docs.mjs && node scripts/check-toolcraft-integrity.mjs && node --test scripts/*.test.mjs && vitest run src --passWithNoTests --reporter=default --reporter=./scripts/toolcraft-vitest-runtime-evidence-reporter.mjs",
16
17
  "test:browser": "playwright install chromium && playwright test --grep-invert \"browser perf:|toolcraft kernel:\"",
18
+ "test:feature": "node scripts/run-feature-verification.mjs",
17
19
  "typecheck": "tsc -p tsconfig.json --noEmit",
18
20
  "verify:delivery": "node scripts/run-delivery-verification.mjs",
19
21
  "verify:perf": "node scripts/run-browser-performance.mjs",
@@ -63,6 +63,7 @@ const requiredWorkflowTerms = [
63
63
  "Open exactly one listed document per terminal or tool read",
64
64
  "coherent user-visible delivery batch",
65
65
  "pnpm verify:delivery",
66
+ "pnpm test:feature",
66
67
  ];
67
68
 
68
69
  const repoScope = "@repo";
@@ -0,0 +1,233 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { fileURLToPath, pathToFileURL } from "node:url";
4
+
5
+ import { captureToolcraftProofProcess } from "./toolcraft-proof-process.mjs";
6
+ import {
7
+ createToolcraftMotionReferenceId,
8
+ createToolcraftSha256,
9
+ } from "./toolcraft-motion-reference-artifacts.mjs";
10
+ import {
11
+ parseToolcraftMotionReferenceArgs,
12
+ resolveToolcraftMotionReferenceOptions,
13
+ resolveToolcraftMotionReferenceSourceKind,
14
+ } from "./toolcraft-motion-reference-command-options.mjs";
15
+ import {
16
+ createToolcraftMotionReferenceContactSheet,
17
+ } from "./toolcraft-motion-reference-contact-sheet.mjs";
18
+ import {
19
+ createToolcraftMotionEvidenceReviewPlan,
20
+ stageToolcraftMotionReferenceEvidences,
21
+ } from "./toolcraft-motion-reference-evidence-assembly.mjs";
22
+ import * as imageSource from "./toolcraft-motion-reference-image-source.mjs";
23
+ import {
24
+ applyToolcraftMotionDeclaredImageTiming,
25
+ } from "./toolcraft-motion-reference-image-timing.mjs";
26
+ import {
27
+ resolveToolcraftMotionReferenceRoots,
28
+ } from "./toolcraft-motion-reference-roots.mjs";
29
+ import * as mediaSource from "./toolcraft-motion-reference-media-source.mjs";
30
+ import {
31
+ publishToolcraftMotionReferenceStudies,
32
+ } from "./toolcraft-motion-reference-publication.mjs";
33
+ import {
34
+ createToolcraftMotionInputError,
35
+ createToolcraftMotionStageError,
36
+ formatToolcraftMotionReferenceError,
37
+ runToolcraftMotionStage,
38
+ } from "./toolcraft-motion-reference-stage.mjs";
39
+ import {
40
+ TOOLCRAFT_MOTION_REFERENCE_STAGES,
41
+ } from "./toolcraft-motion-reference-stage-registry.mjs";
42
+
43
+ const scriptDirectory = path.dirname(fileURLToPath(import.meta.url));
44
+ const defaultRootDir = path.dirname(scriptDirectory);
45
+
46
+ export function createToolcraftMotionReferenceExecutor({
47
+ captureProcess = captureToolcraftProofProcess,
48
+ cwd,
49
+ } = {}) {
50
+ return async ({ args, binary }) => {
51
+ try {
52
+ return { stdout: await captureProcess(binary, args, { cwd }) };
53
+ } catch (error) {
54
+ return { error, exitCode: 1 };
55
+ }
56
+ };
57
+ }
58
+
59
+ async function detectBinaries(execute) {
60
+ await Promise.all(["ffmpeg", "ffprobe"].map((binary) =>
61
+ runToolcraftMotionStage(execute, {
62
+ args: ["-version"], binary,
63
+ stage: TOOLCRAFT_MOTION_REFERENCE_STAGES.binaryDetection,
64
+ })));
65
+ }
66
+
67
+ function selectSource(kind, dependencies) {
68
+ switch (kind) {
69
+ case "video":
70
+ case "gif":
71
+ case "screen-recording":
72
+ return { hashExternally: true, image: false, owner: dependencies.mediaSource };
73
+ case "contact-sheet":
74
+ return { hashExternally: false, image: true, owner: dependencies.imageSource };
75
+ case "frame-sequence":
76
+ return { hashExternally: false, image: true, owner: dependencies.imageSource };
77
+ default:
78
+ throw createToolcraftMotionInputError(
79
+ "Set --kind to video, gif, screen-recording, frame-sequence, or contact-sheet.",
80
+ );
81
+ }
82
+ }
83
+
84
+ async function defaultHashSource(source, fileSystem) {
85
+ return createToolcraftSha256(await fileSystem.readFile(source));
86
+ }
87
+ async function hashSourceAtStage(hashSource, source, fileSystem) {
88
+ try {
89
+ return await hashSource(source, fileSystem);
90
+ } catch (error) {
91
+ throw createToolcraftMotionStageError(
92
+ TOOLCRAFT_MOTION_REFERENCE_STAGES.sourceHash, error,
93
+ );
94
+ }
95
+ }
96
+
97
+ export async function createToolcraftMotionReferenceStudy(rawOptions, injected = {}) {
98
+ const dependencies = {
99
+ createContactSheet: createToolcraftMotionReferenceContactSheet,
100
+ execute: createToolcraftMotionReferenceExecutor({ cwd: injected.rootDir ?? defaultRootDir }),
101
+ fileSystem: fs,
102
+ hashSource: defaultHashSource,
103
+ imageSource,
104
+ mediaSource,
105
+ publishStudies: publishToolcraftMotionReferenceStudies,
106
+ rootDir: defaultRootDir,
107
+ ...injected,
108
+ };
109
+ const { referenceStudiesRoot: finalRoot, temporaryRoot } =
110
+ resolveToolcraftMotionReferenceRoots(
111
+ dependencies.rootDir,
112
+ );
113
+ await detectBinaries(dependencies.execute);
114
+ const kind = await resolveToolcraftMotionReferenceSourceKind(rawOptions, {
115
+ stat: dependencies.fileSystem.stat,
116
+ });
117
+ const selectedSource = selectSource(kind, dependencies);
118
+ await dependencies.fileSystem.mkdir(temporaryRoot, { mode: 0o700, recursive: true });
119
+ const workRoot = await dependencies.fileSystem.mkdtemp(
120
+ path.join(temporaryRoot, "motion-reference-"),
121
+ );
122
+ try {
123
+ const [initialInspection, externalHash] = await Promise.all([
124
+ selectedSource.owner.inspect({
125
+ execute: dependencies.execute,
126
+ fileSystem: dependencies.fileSystem,
127
+ grid: rawOptions.grid,
128
+ inputPath: rawOptions.source,
129
+ sourceKind: kind,
130
+ }),
131
+ selectedSource.hashExternally ?
132
+ hashSourceAtStage(
133
+ dependencies.hashSource, rawOptions.source, dependencies.fileSystem,
134
+ ) :
135
+ Promise.resolve(undefined),
136
+ ]);
137
+ const inspectedForResolution = selectedSource.image ?
138
+ await applyToolcraftMotionDeclaredImageTiming(initialInspection, rawOptions, {
139
+ readFile: dependencies.fileSystem.readFile,
140
+ }) : initialInspection;
141
+ const options = await resolveToolcraftMotionReferenceOptions(
142
+ { ...rawOptions, kind }, inspectedForResolution,
143
+ );
144
+ const inspection = inspectedForResolution;
145
+ const sourceSha256 = externalHash ?? inspection.sourceSha256;
146
+ if (!/^[a-f0-9]{64}$/u.test(sourceSha256 ?? "")) {
147
+ throw new TypeError("Toolcraft motion reference source hash is unavailable.");
148
+ }
149
+ const scan = await selectedSource.owner.scan({
150
+ execute: dependencies.execute, inspection,
151
+ });
152
+ const review = createToolcraftMotionEvidenceReviewPlan(inspection, scan, options);
153
+ const frameDirectory = path.join(workRoot, "frames");
154
+ await dependencies.fileSystem.mkdir(frameDirectory);
155
+ const materialized = await selectedSource.owner.materializeReviewedFrames({
156
+ execute: dependencies.execute, inspection, outputDirectory: frameDirectory,
157
+ sourceFrameIndices: review.unionSourceFrameIndices,
158
+ });
159
+ const materializedByIndex = new Map(materialized.map((frame) =>
160
+ [frame.sourceFrameIndex, frame]));
161
+ const provisionalStagingRoot = path.join(workRoot, "studies");
162
+ await dependencies.fileSystem.mkdir(provisionalStagingRoot);
163
+ let records = await stageToolcraftMotionReferenceEvidences({
164
+ dependencies, inspection, materializedByIndex, options, review, scan,
165
+ sourceSha256, stagingRoot: provisionalStagingRoot,
166
+ });
167
+ const referenceId = createToolcraftMotionReferenceId(records[0].evidence);
168
+ const stagingRoot = path.join(workRoot, `${referenceId}.staging`);
169
+ await dependencies.fileSystem.rename(provisionalStagingRoot, stagingRoot);
170
+ records = records.map((record) => ({
171
+ ...record,
172
+ stagingDirectory: path.join(
173
+ stagingRoot, path.basename(record.stagingDirectory),
174
+ ),
175
+ }));
176
+ await dependencies.fileSystem.mkdir(finalRoot, { recursive: true });
177
+ const studies = [];
178
+ for (const { evidence, stagingDirectory } of records) {
179
+ studies.push({
180
+ contactSheetPath: evidence.contactSheet.path,
181
+ evidence,
182
+ evidencePath: path.posix.join("src/app/reference-studies",
183
+ evidence.studyId, "evidence.json"),
184
+ finalDirectory: path.join(finalRoot, evidence.studyId),
185
+ range: evidence.segment ?? (evidence.timingMode === "seconds" ?
186
+ { endSeconds: evidence.durationSeconds, startSeconds: 0 } : undefined),
187
+ reviewedFrameCount: evidence.reviewedFrames.length,
188
+ stagingDirectory,
189
+ studyId: evidence.studyId,
190
+ });
191
+ }
192
+ const publication = await dependencies.publishStudies(studies.map((study) => ({
193
+ finalDirectory: study.finalDirectory,
194
+ stagingDirectory: study.stagingDirectory,
195
+ })), {
196
+ lockDirectory: path.join(temporaryRoot, `${referenceId}.lock`),
197
+ publicationGroup: {
198
+ evidences: studies.map(({ evidence }) => evidence),
199
+ referenceStudiesRoot: finalRoot,
200
+ rootDir: dependencies.rootDir,
201
+ stagingRoot,
202
+ },
203
+ sourceIdentity: referenceId,
204
+ });
205
+ return { publication, referenceId, studies: studies.map(({ finalDirectory,
206
+ stagingDirectory, ...study }) => study) };
207
+ } finally {
208
+ await dependencies.fileSystem.rm(workRoot, { force: true, recursive: true });
209
+ }
210
+ }
211
+
212
+ export async function main(argv = process.argv.slice(2), injected = {}, io = console) {
213
+ try {
214
+ const result = await createToolcraftMotionReferenceStudy(
215
+ parseToolcraftMotionReferenceArgs(argv), injected,
216
+ );
217
+ io.log(`Reference: ${result.referenceId}`);
218
+ result.studies.forEach((study) => {
219
+ const range = study.range ?
220
+ ` range ${study.range.startSeconds}:${study.range.endSeconds}` : "";
221
+ io.log(`${study.studyId} ${study.evidencePath} ${study.contactSheetPath} ` +
222
+ `${study.reviewedFrameCount} reviewed${range}`);
223
+ });
224
+ return 0;
225
+ } catch (error) {
226
+ io.error(formatToolcraftMotionReferenceError(error));
227
+ return 1;
228
+ }
229
+ }
230
+
231
+ if (process.argv[1] && pathToFileURL(path.resolve(process.argv[1])).href === import.meta.url) {
232
+ process.exitCode = await main();
233
+ }