@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,459 @@
1
+ import assert from "node:assert/strict";
2
+ import fs from "node:fs/promises";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import test from "node:test";
6
+
7
+ import {
8
+ createToolcraftMotionReferenceExecutor,
9
+ createToolcraftMotionReferenceStudy,
10
+ main,
11
+ } from "./create-toolcraft-motion-reference-study.mjs";
12
+ import {
13
+ createToolcraftSha256,
14
+ getToolcraftMotionReferenceArtifactErrors,
15
+ } from "./toolcraft-motion-reference-artifacts.mjs";
16
+ import {
17
+ publishToolcraftMotionReferenceStudies,
18
+ } from "./toolcraft-motion-reference-publication.mjs";
19
+ import {
20
+ recoverToolcraftMotionReferencePublication,
21
+ } from "./toolcraft-motion-reference-publication-journal.mjs";
22
+ import {
23
+ ToolcraftMotionReferenceStageError,
24
+ } from "./toolcraft-motion-reference-stage.mjs";
25
+ import {
26
+ TOOLCRAFT_MOTION_REFERENCE_STAGES,
27
+ } from "./toolcraft-motion-reference-stage-registry.mjs";
28
+
29
+ const hex = (character) => character.repeat(64);
30
+
31
+ async function harness(context, {
32
+ frameCount = 30,
33
+ loopSeamScore = 0,
34
+ sourceKind = "video",
35
+ } = {}) {
36
+ const rootDir = await fs.mkdtemp(path.join(os.tmpdir(), "motion-command-"));
37
+ context.after(() => fs.rm(rootDir, { force: true, recursive: true }));
38
+ const source = path.join(rootDir, sourceKind === "frame-sequence" ? "frames" :
39
+ sourceKind === "contact-sheet" ? "sheet.png" : "reference.mkv");
40
+ if (sourceKind === "frame-sequence") await fs.mkdir(source);
41
+ else await fs.writeFile(source, "source");
42
+ const calls = { contact: 0, execute: [], hash: 0, inspect: [], materialize: [],
43
+ publish: 0, scan: [] };
44
+ const frameTimes = Array.from({ length: frameCount }, (_, index) => index / 30);
45
+ const owner = {
46
+ inspect: async (input) => {
47
+ calls.inspect.push(input);
48
+ return {
49
+ decodedFrameCount: frameCount,
50
+ ffmpegVersion: "ffmpeg 8.0",
51
+ ffprobeVersion: "ffprobe 8.0",
52
+ hasAlpha: false,
53
+ height: 180,
54
+ inputPath: source,
55
+ pixelFormat: "yuv444p",
56
+ sourceBasename: path.basename(source),
57
+ sourceKind,
58
+ sourceSha256: sourceKind === "video" ? undefined : hex("a"),
59
+ timingMode: sourceKind === "video" ? "seconds" : "ordinal",
60
+ width: 320,
61
+ ...(sourceKind === "video" ? {
62
+ durationSeconds: frameCount / 30,
63
+ frameTimes,
64
+ nominalFrameRate: 30,
65
+ } : {}),
66
+ ...(sourceKind === "contact-sheet" ? {
67
+ sourceGrid: { columns: 5, rows: Math.ceil(frameCount / 5) },
68
+ } : {}),
69
+ };
70
+ },
71
+ materializeReviewedFrames: async ({ inspection, outputDirectory,
72
+ sourceFrameIndices }) => {
73
+ calls.materialize.push([...sourceFrameIndices]);
74
+ await fs.mkdir(outputDirectory, { recursive: true });
75
+ return Promise.all(sourceFrameIndices.map(async (sourceFrameIndex, ordinal) => {
76
+ const framePath = path.join(outputDirectory,
77
+ `review-${String(ordinal).padStart(6, "0")}.png`);
78
+ await fs.writeFile(framePath, `frame:${sourceFrameIndex}`);
79
+ return {
80
+ path: framePath,
81
+ sourceFrameIndex,
82
+ sourceLocator: `${source}#frame=${sourceFrameIndex}`,
83
+ ...(inspection.timingMode === "seconds" ? {
84
+ timeSeconds: inspection.frameTimes[sourceFrameIndex],
85
+ } : {}),
86
+ };
87
+ }));
88
+ },
89
+ scan: async () => {
90
+ calls.scan.push(sourceKind);
91
+ const changeScores = Array(frameCount).fill(0);
92
+ if (frameCount > 92) changeScores[91] = 1;
93
+ return {
94
+ changeMetric: "max-yuva-diff-v1",
95
+ changeScores,
96
+ componentDifferences: [],
97
+ loopSeamScore,
98
+ scannedFrameCount: frameCount,
99
+ };
100
+ },
101
+ };
102
+ const execute = async (request) => {
103
+ calls.execute.push(request);
104
+ return { stdout: `${request.binary} version 8.0` };
105
+ };
106
+ const createContactSheet = async ({ frames, outputPath, sourceHeight, sourceWidth }) => {
107
+ calls.contact += 1;
108
+ const columns = Math.ceil(Math.sqrt(frames.length * sourceWidth / sourceHeight));
109
+ const rows = Math.ceil(frames.length / columns);
110
+ await fs.writeFile(outputPath,
111
+ `sheet:${frames.map(({ sourceFrameIndex }) => sourceFrameIndex).join(",")}`);
112
+ return {
113
+ cells: frames.map(({ sourceFrameIndex }, index) => ({
114
+ column: index % columns,
115
+ frameId: `source-frame:${sourceFrameIndex}`,
116
+ height: sourceHeight,
117
+ row: Math.floor(index / columns),
118
+ sourceFrameIndex,
119
+ width: sourceWidth,
120
+ x: (index % columns) * sourceWidth,
121
+ y: Math.floor(index / columns) * sourceHeight,
122
+ })),
123
+ columns,
124
+ height: rows * sourceHeight,
125
+ outputPath,
126
+ rows,
127
+ width: columns * sourceWidth,
128
+ };
129
+ };
130
+ const dependencies = {
131
+ createContactSheet,
132
+ execute,
133
+ fileSystem: fs,
134
+ hashSource: async () => { calls.hash += 1; return hex("a"); },
135
+ imageSource: owner,
136
+ mediaSource: owner,
137
+ publishStudies: async (pairs, settings) => {
138
+ calls.publish += 1;
139
+ return publishToolcraftMotionReferenceStudies(pairs, {
140
+ ...settings, lockLeaseMilliseconds: 500, now: () => 1_000,
141
+ });
142
+ },
143
+ rootDir,
144
+ };
145
+ const options = {
146
+ kind: sourceKind,
147
+ source,
148
+ ...(sourceKind === "contact-sheet" ? { grid: { columns: 5, rows: 6 } } : {}),
149
+ };
150
+ return { calls, dependencies, options, owner, rootDir, source };
151
+ }
152
+
153
+ function referenceInput(result) {
154
+ return [{
155
+ behaviors: [],
156
+ kind: "motion-reference",
157
+ referenceId: result.referenceId,
158
+ studies: result.studies.map(({ evidence, evidencePath, studyId }) => ({
159
+ evidence, evidencePath, events: [], phases: [], studyId,
160
+ })),
161
+ }];
162
+ }
163
+
164
+ test("fails at binary detection before creating temporary state", async (context) => {
165
+ const value = await harness(context);
166
+ value.dependencies.execute = async ({ binary }) => ({
167
+ error: Object.assign(new Error(`${binary} unavailable`), { code: "ENOENT" }),
168
+ exitCode: 1,
169
+ });
170
+ await assert.rejects(() => createToolcraftMotionReferenceStudy(
171
+ value.options, value.dependencies,
172
+ ), (error) => error.stage === "binary-detection");
173
+ assert.equal(await fs.stat(path.join(value.rootDir, ".toolcraft"))
174
+ .then(() => true, () => false), false);
175
+ });
176
+
177
+ test("selects media and image owners in one exhaustive source boundary", async (context) => {
178
+ for (const sourceKind of ["video", "gif", "screen-recording", "frame-sequence",
179
+ "contact-sheet"]) {
180
+ const value = await harness(context, { frameCount: 3, sourceKind });
181
+ const selected = [];
182
+ value.dependencies.mediaSource = { ...value.owner,
183
+ inspect: async (input) => { selected.push("media"); return value.owner.inspect(input); } };
184
+ value.dependencies.imageSource = { ...value.owner,
185
+ inspect: async (input) => { selected.push("image"); return value.owner.inspect(input); } };
186
+ await createToolcraftMotionReferenceStudy(value.options, value.dependencies);
187
+ assert.deepEqual(selected, [["video", "gif", "screen-recording"].includes(sourceKind) ?
188
+ "media" : "image"]);
189
+ assert.equal(value.calls.hash,
190
+ ["video", "gif", "screen-recording"].includes(sourceKind) ? 1 : 0);
191
+ }
192
+ });
193
+
194
+ test("publishes a verifier-valid single study with exactly two final files", async (context) => {
195
+ const value = await harness(context, { frameCount: 30 });
196
+ const result = await createToolcraftMotionReferenceStudy(value.options, value.dependencies);
197
+ assert.equal(value.calls.scan.length, 1);
198
+ assert.equal(value.calls.materialize.length, 1);
199
+ assert.equal(value.calls.publish, 1);
200
+ assert.equal(result.studies.length, 1);
201
+ assert.deepEqual(await fs.readdir(path.join(value.rootDir,
202
+ path.dirname(result.studies[0].evidencePath))), ["contact-sheet.png", "evidence.json"]);
203
+ assert.deepEqual(await getToolcraftMotionReferenceArtifactErrors({
204
+ referenceInputs: referenceInput(result), rootDir: value.rootDir,
205
+ }), []);
206
+ });
207
+
208
+ test("normalizes declared image timing before selection without omitting source frames",
209
+ async (context) => {
210
+ const value = await harness(context, { frameCount: 2, sourceKind: "frame-sequence" });
211
+ const timestampsFile = path.join(value.rootDir, "timestamps.json");
212
+ await fs.writeFile(timestampsFile, "[10,11]\n");
213
+ value.options = {
214
+ ...value.options,
215
+ focus: [{ endSeconds: 1, startSeconds: 0 }],
216
+ segment: { endSeconds: 2, startSeconds: 0 },
217
+ timestampsFile,
218
+ };
219
+ const result = await createToolcraftMotionReferenceStudy(
220
+ value.options, value.dependencies,
221
+ );
222
+ assert.deepEqual(result.studies[0].evidence.reviewedFrames.map((frame) =>
223
+ ({ sourceFrameIndex: frame.sourceFrameIndex, timeSeconds: frame.timeSeconds })), [
224
+ { sourceFrameIndex: 0, timeSeconds: 0 },
225
+ { sourceFrameIndex: 1, timeSeconds: 1 },
226
+ ]);
227
+ assert.equal(result.studies[0].evidence.timing.timestampsSha256,
228
+ createToolcraftSha256(Buffer.from("[10,11]\n")));
229
+ assert.deepEqual(await getToolcraftMotionReferenceArtifactErrors({
230
+ referenceInputs: referenceInput(result), rootDir: value.rootDir,
231
+ }), []);
232
+ });
233
+
234
+ test("rejects one-frame declared timestamps before scan or publication", async (context) => {
235
+ const value = await harness(context, { frameCount: 1, sourceKind: "frame-sequence" });
236
+ const timestampsFile = path.join(value.rootDir, "timestamps.json");
237
+ await fs.writeFile(timestampsFile, "[10]\n");
238
+ value.options = { ...value.options, timestampsFile };
239
+
240
+ await assert.rejects(() => createToolcraftMotionReferenceStudy(
241
+ value.options, value.dependencies,
242
+ ), /at least two.*timestamps.*duration|timestamps.*at least two.*duration/iu);
243
+ assert.equal(value.calls.scan.length, 0);
244
+ assert.equal(value.calls.publish, 0);
245
+ });
246
+
247
+ test("partitions dense review once, extracts one union, and publishes one atomic group", async (context) => {
248
+ const value = await harness(context, { frameCount: 330, loopSeamScore: 1 });
249
+ const result = await createToolcraftMotionReferenceStudy(value.options, value.dependencies);
250
+ assert.ok(result.studies.length > 1);
251
+ assert.equal(value.calls.scan.length, 1);
252
+ assert.equal(value.calls.materialize.length, 1);
253
+ assert.equal(value.calls.publish, 1);
254
+ assert.equal(new Set(value.calls.materialize[0]).size,
255
+ value.calls.materialize[0].length);
256
+ assert.deepEqual(result.studies.map(({ evidence }) =>
257
+ evidence.detectedEvents.some(({ kind }) => kind === "loop-seam")), [true, false]);
258
+ assert.deepEqual(await getToolcraftMotionReferenceArtifactErrors({
259
+ referenceInputs: referenceInput(result), rootDir: value.rootDir,
260
+ }), []);
261
+ });
262
+
263
+ test("a focus refinement replaces the complete previous partition group", async (context) => {
264
+ const value = await harness(context, { frameCount: 330, loopSeamScore: 1 });
265
+ const initial = await createToolcraftMotionReferenceStudy(
266
+ value.options, value.dependencies,
267
+ );
268
+ const refined = await createToolcraftMotionReferenceStudy({
269
+ ...value.options,
270
+ focus: [{ endSeconds: 5.4, startSeconds: 4.1 }],
271
+ }, value.dependencies);
272
+ const initialIds = initial.studies.map(({ studyId }) => studyId).sort();
273
+ const refinedIds = refined.studies.map(({ studyId }) => studyId).sort();
274
+
275
+ assert.equal(initialIds.length, 2);
276
+ assert.equal(refinedIds.length, 2);
277
+ assert.deepEqual(initialIds.filter((studyId) => refinedIds.includes(studyId)), []);
278
+ assert.deepEqual(await fs.readdir(path.join(
279
+ value.rootDir, "src", "app", "reference-studies",
280
+ )), refinedIds);
281
+ });
282
+
283
+ test("group replacement retains another canonical source and replaces equal ids", async (context) => {
284
+ const value = await harness(context, { frameCount: 330, loopSeamScore: 1 });
285
+ const initial = await createToolcraftMotionReferenceStudy(value.options, value.dependencies);
286
+ const equalReplacement = await createToolcraftMotionReferenceStudy(
287
+ value.options, value.dependencies,
288
+ );
289
+ assert.deepEqual(equalReplacement.studies.map(({ studyId }) => studyId),
290
+ initial.studies.map(({ studyId }) => studyId));
291
+
292
+ value.dependencies.hashSource = async () => hex("b");
293
+ const unrelated = await createToolcraftMotionReferenceStudy(
294
+ value.options, value.dependencies,
295
+ );
296
+ value.dependencies.hashSource = async () => hex("a");
297
+ const refined = await createToolcraftMotionReferenceStudy({
298
+ ...value.options, focus: [{ endSeconds: 5.4, startSeconds: 4.1 }],
299
+ }, value.dependencies);
300
+ const expectedIds = [...unrelated.studies, ...refined.studies]
301
+ .map(({ studyId }) => studyId).sort();
302
+ assert.deepEqual(await fs.readdir(path.join(
303
+ value.rootDir, "src", "app", "reference-studies",
304
+ )), expectedIds);
305
+ });
306
+
307
+ test("group inventory fails closed on an unexplained previous directory", async (context) => {
308
+ const value = await harness(context, { frameCount: 330, loopSeamScore: 1 });
309
+ const initial = await createToolcraftMotionReferenceStudy(value.options, value.dependencies);
310
+ const root = path.join(value.rootDir, "src", "app", "reference-studies");
311
+ await fs.mkdir(path.join(root, "unexplained"));
312
+ await assert.rejects(() => createToolcraftMotionReferenceStudy({
313
+ ...value.options, focus: [{ endSeconds: 5.4, startSeconds: 4.1 }],
314
+ }, value.dependencies), /inventory.*exactly|unexplained/iu);
315
+ assert.deepEqual((await fs.readdir(root)).sort(), [
316
+ ...initial.studies.map(({ studyId }) => studyId), "unexplained",
317
+ ].sort());
318
+ await fs.rm(path.join(root, "unexplained"), { recursive: true });
319
+ await fs.symlink(path.join(root, initial.studies[0].studyId),
320
+ path.join(root, "linked-study"), "dir");
321
+ await assert.rejects(() => createToolcraftMotionReferenceStudy({
322
+ ...value.options, focus: [{ endSeconds: 5.4, startSeconds: 4.1 }],
323
+ }, value.dependencies), /inventory.*link|unexplained/iu);
324
+ });
325
+
326
+ test("a precommit failure restores only the complete obsolete-id group", async (context) => {
327
+ const value = await harness(context, { frameCount: 330, loopSeamScore: 1 });
328
+ const initial = await createToolcraftMotionReferenceStudy(value.options, value.dependencies);
329
+ const root = path.join(value.rootDir, "src", "app", "reference-studies");
330
+ let publications = 0;
331
+ const fileSystem = {
332
+ ...fs,
333
+ rename: async (from, to) => {
334
+ if (from.includes(`.staging${path.sep}`) &&
335
+ path.dirname(to) === root && ++publications === 2) {
336
+ throw new Error("controlled precommit failure");
337
+ }
338
+ return fs.rename(from, to);
339
+ },
340
+ };
341
+ value.dependencies.fileSystem = fileSystem;
342
+ value.dependencies.publishStudies = async (pairs, settings) =>
343
+ publishToolcraftMotionReferenceStudies(pairs, {
344
+ ...settings, fileSystem, lockLeaseMilliseconds: 500, now: () => 1_000,
345
+ });
346
+ await assert.rejects(() => createToolcraftMotionReferenceStudy({
347
+ ...value.options, focus: [{ endSeconds: 5.4, startSeconds: 4.1 }],
348
+ }, value.dependencies), /controlled precommit failure/iu);
349
+ assert.deepEqual(await fs.readdir(root),
350
+ initial.studies.map(({ studyId }) => studyId).sort());
351
+ });
352
+
353
+ test("crash recovery restores the complete old group at each retire and publish rename",
354
+ async (context) => {
355
+ for (let crashAt = 1; crashAt <= 4; crashAt += 1) {
356
+ const value = await harness(context, { frameCount: 330, loopSeamScore: 1 });
357
+ const initial = await createToolcraftMotionReferenceStudy(
358
+ value.options, value.dependencies,
359
+ );
360
+ const root = path.join(value.rootDir, "src", "app", "reference-studies");
361
+ const temporaryRoot = path.join(value.rootDir, ".toolcraft", "tmp");
362
+ const transactionRoot = path.join(
363
+ temporaryRoot, `${initial.referenceId}.transaction`,
364
+ );
365
+ let mutation = 0;
366
+ let crashed = false;
367
+ value.dependencies.fileSystem = {
368
+ ...fs,
369
+ rename: async (from, to) => {
370
+ const dataMutation = path.dirname(to) === transactionRoot ||
371
+ (from.includes(`.staging${path.sep}`) && path.dirname(to) === root) ||
372
+ path.dirname(from) === transactionRoot;
373
+ if (crashed && dataMutation) throw new Error("simulated process crash");
374
+ if (dataMutation && ++mutation === crashAt) {
375
+ await fs.rename(from, to);
376
+ crashed = true;
377
+ throw new Error("simulated process crash");
378
+ }
379
+ return fs.rename(from, to);
380
+ },
381
+ };
382
+ value.dependencies.publishStudies = async (pairs, settings) =>
383
+ publishToolcraftMotionReferenceStudies(pairs, {
384
+ ...settings,
385
+ fileSystem: value.dependencies.fileSystem,
386
+ lockLeaseMilliseconds: 500,
387
+ now: () => 1_000,
388
+ });
389
+ await assert.rejects(() => createToolcraftMotionReferenceStudy({
390
+ ...value.options, focus: [{ endSeconds: 5.4, startSeconds: 4.1 }],
391
+ }, value.dependencies), /simulated process crash/iu, `crash mutation ${crashAt}`);
392
+ const journalPath = path.join(temporaryRoot,
393
+ `${initial.referenceId}.lock.publication.json`);
394
+ await recoverToolcraftMotionReferencePublication({
395
+ artifactRoot: root,
396
+ fileSystem: fs,
397
+ heartbeat: async () => {},
398
+ journalPath,
399
+ sourceIdentity: initial.referenceId,
400
+ temporaryRoot,
401
+ token: `recovery-${crashAt}`,
402
+ transactionRoot,
403
+ });
404
+ assert.deepEqual(await fs.readdir(root),
405
+ initial.studies.map(({ studyId }) => studyId).sort());
406
+ assert.equal(await fs.stat(journalPath).then(() => true, () => false), false);
407
+ }
408
+ });
409
+
410
+ test("cleans temporary output and preserves a checked scan stage", async (context) => {
411
+ const value = await harness(context);
412
+ value.dependencies.mediaSource = {
413
+ ...value.dependencies.mediaSource,
414
+ scan: async () => { throw new ToolcraftMotionReferenceStageError(
415
+ TOOLCRAFT_MOTION_REFERENCE_STAGES.mediaScan, "controlled failure",
416
+ ); },
417
+ };
418
+ await assert.rejects(() => createToolcraftMotionReferenceStudy(
419
+ value.options, value.dependencies,
420
+ ), (error) => error.stage === "media-scan");
421
+ const temporaryRoot = path.join(value.rootDir, ".toolcraft", "tmp");
422
+ assert.deepEqual(await fs.readdir(temporaryRoot), []);
423
+ });
424
+
425
+ test("normalizes a concurrent source hash failure without exposing its path", async (context) => {
426
+ const value = await harness(context);
427
+ value.dependencies.hashSource = async () => {
428
+ throw new Error(`unreadable ${value.source}`);
429
+ };
430
+ await assert.rejects(() => createToolcraftMotionReferenceStudy(
431
+ value.options, value.dependencies,
432
+ ), (error) => error.stage === "source-hash");
433
+ const errors = [];
434
+ assert.equal(await main([
435
+ "--source", value.source, "--kind", "video",
436
+ ], value.dependencies, { error: (message) => errors.push(message), log: () => {} }), 1);
437
+ assert.equal(errors.length, 1);
438
+ assert.equal(errors[0].includes(value.source), false);
439
+ });
440
+
441
+ test("returns an actionable bounded error for ordinal review above 120", async (context) => {
442
+ const value = await harness(context, { frameCount: 121, sourceKind: "frame-sequence" });
443
+ await assert.rejects(() => createToolcraftMotionReferenceStudy(
444
+ value.options, value.dependencies,
445
+ ), /ordinal.*120|120.*ordinal/iu);
446
+ assert.equal(value.calls.materialize.length, 0);
447
+ assert.equal(value.calls.publish, 0);
448
+ });
449
+
450
+ test("the production executor adapts captured stdout without parsing stderr", async () => {
451
+ const calls = [];
452
+ const execute = createToolcraftMotionReferenceExecutor({
453
+ captureProcess: async (...args) => { calls.push(args); return "captured stdout"; },
454
+ cwd: "/project",
455
+ });
456
+ assert.deepEqual(await execute({ args: ["-version"], binary: "ffmpeg",
457
+ stage: "binary-detection" }), { stdout: "captured stdout" });
458
+ assert.deepEqual(calls, [["ffmpeg", ["-version"], { cwd: "/project" }]]);
459
+ });
@@ -0,0 +1,45 @@
1
+ export type ToolcraftDeliveryCatalogAcceptance = Readonly<{
2
+ acceptanceId: string;
3
+ contractHash: string;
4
+ domainId: string;
5
+ file: string;
6
+ testName: string;
7
+ }>;
8
+
9
+ export type ToolcraftDeliveryCatalogPerformance = Readonly<{
10
+ passIds: readonly string[];
11
+ pathId: string;
12
+ testName: string;
13
+ }>;
14
+
15
+ export type ToolcraftDeliveryCatalog = Readonly<{
16
+ acceptance: readonly ToolcraftDeliveryCatalogAcceptance[];
17
+ performance: readonly ToolcraftDeliveryCatalogPerformance[];
18
+ version: 2;
19
+ }>;
20
+
21
+ export type ToolcraftDeliveryCatalogValidation = Readonly<{
22
+ catalog?: ToolcraftDeliveryCatalog;
23
+ errors: readonly string[];
24
+ }>;
25
+
26
+ export function validateToolcraftDeliveryCatalog(
27
+ value: unknown,
28
+ ): ToolcraftDeliveryCatalogValidation;
29
+
30
+ export function createToolcraftDeliveryCatalog(
31
+ input: Readonly<Record<string, unknown>>,
32
+ ): ToolcraftDeliveryCatalog;
33
+
34
+ export function collectToolcraftPlaywrightTestTitles(
35
+ report: unknown,
36
+ ): readonly Readonly<{ file: string; testName: string }>[];
37
+
38
+ export function resolveToolcraftPlaywrightTestTitles(
39
+ availableTitles: readonly unknown[],
40
+ requestedTitles: readonly string[],
41
+ ): readonly unknown[];
42
+
43
+ export function getToolcraftPlaywrightExactGrepPattern(
44
+ selections: readonly unknown[],
45
+ ): string;
@@ -120,19 +120,6 @@ export function createVerificationFixture(prefix) {
120
120
  );
121
121
  writeFileSync(path.join(rootDir, "src", "app", "app.test.ts"),
122
122
  "export const appTest = true;\n");
123
- writeFileSync(
124
- path.join(rootDir, "src", "app", "app-verification-impact.json"),
125
- `${JSON.stringify({
126
- owners: [
127
- {
128
- acceptanceIds: ["persistence.reload"],
129
- kind: "functional",
130
- path: "src/app.ts",
131
- },
132
- ],
133
- version: 3,
134
- })}\n`,
135
- );
136
123
  writeFileSync(
137
124
  path.join(rootDir, "src", "toolcraft", ".toolcraft-manifest.json"),
138
125
  '{"protectedFiles":{}}\n',
@@ -241,20 +228,6 @@ export function createProtectedRunnerFixture(
241
228
  deliveryCatalog = fixtureDeliveryCatalog,
242
229
  ) {
243
230
  const rootDir = createVerificationFixture("protected-runner");
244
- writeFileSync(
245
- path.join(rootDir, "src", "app", "app-verification-impact.json"),
246
- `${JSON.stringify({
247
- owners: [
248
- {
249
- acceptanceIds: ["persistence.reload"],
250
- kind: "performance",
251
- passIds: ["composite"],
252
- path: "src/app.ts",
253
- },
254
- ],
255
- version: 3,
256
- })}\n`,
257
- );
258
231
  const fixtureScriptsDir = path.join(rootDir, "scripts");
259
232
  const binDir = path.join(rootDir, "node_modules", ".bin");
260
233
  mkdirSync(fixtureScriptsDir, { recursive: true });
@@ -36,11 +36,6 @@ async function runToolcraftFullPerformanceCertificationCore({ projectDir }) {
36
36
  if (loaded.error) throw new Error(loaded.error);
37
37
  const initialInventory =
38
38
  await collectToolcraftVerificationInputs(projectDir);
39
- if (loaded.anchor.sourceHash !== initialInventory.sourceHash) {
40
- throw new Error(
41
- "Toolcraft full performance requires a current successful delivery for the unchanged source.",
42
- );
43
- }
44
39
  await runToolcraftProofPackageScript(projectDir, "build");
45
40
  const measurement = await measureToolcraftPerformanceCheckpoint({
46
41
  baselineInventory: initialInventory,
@@ -52,7 +47,6 @@ async function runToolcraftFullPerformanceCertificationCore({ projectDir }) {
52
47
  rootDir: projectDir,
53
48
  update: (bundle) => ({
54
49
  ...bundle,
55
- currentPerformance: checkpoint,
56
50
  performanceBaseline: checkpoint,
57
51
  }),
58
52
  });
@@ -24,7 +24,6 @@ import {
24
24
  readProofInvocations,
25
25
  runProtectedRunner,
26
26
  runnerPath,
27
- writePassedCheckpointFixture,
28
27
  } from "./run-browser-performance-test-helpers.mjs";
29
28
  import { getToolcraftCheckpointBundlePath } from "./toolcraft-checkpoint-paths.mjs";
30
29
  import { validateToolcraftPerformanceReceipt } from "./toolcraft-verification-receipt.mjs";
@@ -60,9 +59,9 @@ test("full certification runs only build plus the complete performance matrix an
60
59
  );
61
60
  assert.deepEqual(updated.delivery, existing.delivery);
62
61
  assert.deepEqual(readCheckpointBundle(rootDir), updated);
63
- assert.equal(updated.currentPerformance.sourceHash, existing.delivery.sourceHash);
64
- assert.deepEqual(updated.currentPerformance, updated.performanceBaseline);
65
- assert.deepEqual(Object.keys(updated.currentPerformance).sort(), [
62
+ assert.equal(updated.currentPerformance, null);
63
+ assert.equal(updated.performanceBaseline.sourceHash, existing.delivery.sourceHash);
64
+ assert.deepEqual(Object.keys(updated.performanceBaseline).sort(), [
66
65
  "completedAt",
67
66
  "files",
68
67
  "kind",
@@ -205,7 +204,7 @@ test("operator full certification creates and refreshes the independent checkpoi
205
204
  runProtectedRunner(rootDir);
206
205
  const firstBundle = readCheckpointBundle(rootDir);
207
206
  const firstBaseline = firstBundle.performanceBaseline;
208
- assert.deepEqual(firstBundle.currentPerformance, firstBaseline);
207
+ assert.equal(firstBundle.currentPerformance, null);
209
208
  assert.match(firstBaseline.performanceEvidence.reportHash, /^[a-f0-9]{64}$/u);
210
209
  assert.equal(firstBaseline.performanceEvidence.profileCatalogVersion, 1);
211
210
  assert.equal(firstBaseline.performanceEvidence.measurements.length, 3);
@@ -217,18 +216,11 @@ test("operator full certification creates and refreshes the independent checkpoi
217
216
  );
218
217
 
219
218
  writeFileSync(path.join(rootDir, "src", "app.ts"), "export const value = 2;\n");
220
- const staleResult = invokeRunner(rootDir, "run-browser-performance.mjs");
221
- assert.notEqual(staleResult.status, 0);
222
- assert.match(
223
- `${staleResult.stdout}\n${staleResult.stderr}`,
224
- /requires a current successful delivery for the unchanged source/iu,
225
- );
226
- await writePassedCheckpointFixture(rootDir, { writeBaseline: false });
227
219
  runProtectedRunner(rootDir);
228
220
  const secondBundle = readCheckpointBundle(rootDir);
229
221
  const secondBaseline = secondBundle.performanceBaseline;
230
222
  assert.notEqual(secondBaseline.sourceHash, firstBaseline.sourceHash);
231
- assert.deepEqual(secondBundle.currentPerformance, secondBaseline);
223
+ assert.equal(secondBundle.currentPerformance, null);
232
224
  assert.equal(secondBaseline.kind, "performance-checkpoint");
233
225
  assert.deepEqual(await validateToolcraftPerformanceReceipt({ rootDir }), []);
234
226
  });
@@ -77,40 +77,6 @@ export function createDeliveryFixture(
77
77
  path.join(rootDir, "src", "app", "app-performance.ts"),
78
78
  "export const performance = true;\n",
79
79
  );
80
- writeFileSync(
81
- path.join(rootDir, "src", "app", "app-verification-impact.json"),
82
- `${JSON.stringify({
83
- owners: [
84
- {
85
- acceptanceIds: ["persistence.reload"],
86
- kind: "functional",
87
- path: "src/app/app-composition.tsx",
88
- },
89
- {
90
- acceptanceIds: ["persistence.reload"],
91
- kind: "functional",
92
- path: "src/app/app-schema.ts",
93
- },
94
- {
95
- acceptanceIds: ["persistence.reload"],
96
- kind: "functional",
97
- path: "src/app.ts",
98
- },
99
- {
100
- acceptanceIds: ["persistence.reload"],
101
- kind: "performance",
102
- passIds: ["composite"],
103
- path: "src/app/renderer.ts",
104
- },
105
- {
106
- acceptanceIds: ["persistence.reload"],
107
- kind: "functional",
108
- path: "src/app/schema.ts",
109
- },
110
- ],
111
- version: 3,
112
- })}\n`,
113
- );
114
80
  writeFileSync(
115
81
  path.join(rootDir, "scripts", "record-delivery-event.mjs"),
116
82
  [