@pixel-point/toolcraft 0.0.16 → 0.0.17

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 (170) hide show
  1. package/package.json +1 -1
  2. package/src/generate-performance-iteration-execution.test.mjs +2 -2
  3. package/src/generate-test-demand-only-lifecycle.mjs +14 -3
  4. package/src/generate-test-dependency-sandbox.mjs +42 -5
  5. package/src/generate-test-doc-assertions.mjs +68 -18
  6. package/src/generate-test-doc-assertions.test.mjs +22 -0
  7. package/src/generate-test-file-assertions.mjs +43 -76
  8. package/src/generate-test-output-assertions.mjs +95 -0
  9. package/src/generate-test-package-assertions.mjs +6 -0
  10. package/src/generate-test-performance-boundary-assertions.mjs +45 -0
  11. package/src/generate-test-product-fixture.mjs +1 -0
  12. package/src/generate-test-product-fixture.test.mjs +18 -0
  13. package/src/generate-test-product-iteration.mjs +1 -0
  14. package/src/generate-test-product-iteration.test.mjs +1 -0
  15. package/src/generate-test-standalone-delivery-stages.mjs +14 -6
  16. package/src/generate.test.mjs +14 -0
  17. package/templates/runtime/contracts/component-contracts.choices.test.ts +12 -9
  18. package/templates/runtime/contracts/component-contracts.choices.ts +10 -9
  19. package/templates/runtime/contracts/component-contracts.runtime-acceptance.test.ts +17 -2
  20. package/templates/runtime/contracts/component-contracts.runtime-panels.test.ts +1 -1
  21. package/templates/runtime/contracts/component-contracts.runtime-shell.test.ts +1 -1
  22. package/templates/runtime/contracts/component-contracts.runtime.ts +3 -2
  23. package/templates/runtime/contracts/decision-contracts.test.ts +25 -4
  24. package/templates/runtime/contracts/decision-contracts.ts +3 -3
  25. package/templates/runtime/contracts/performance-verification-policy.test.ts +59 -6
  26. package/templates/runtime/contracts/performance-verification-policy.ts +5 -2
  27. package/templates/runtime/export/artifact-download.test.ts +71 -0
  28. package/templates/runtime/export/artifact-download.ts +80 -0
  29. package/templates/runtime/export/artifact-export-request.ts +23 -0
  30. package/templates/runtime/export/artifact-export-settings.test.ts +75 -0
  31. package/templates/runtime/export/artifact-export-settings.ts +96 -0
  32. package/templates/runtime/export/artifact-frame-renderer.test.ts +107 -0
  33. package/templates/runtime/export/artifact-frame-renderer.ts +96 -0
  34. package/templates/runtime/export/artifact-frame-state.test.ts +54 -0
  35. package/templates/runtime/export/artifact-frame-state.ts +44 -0
  36. package/templates/runtime/export/artifact-scene-frame.test.ts +84 -0
  37. package/templates/runtime/export/artifact-scene-frame.ts +118 -0
  38. package/templates/runtime/export/export-background.ts +65 -0
  39. package/templates/runtime/export/export-error.ts +43 -0
  40. package/templates/runtime/export/export.test.ts +6 -186
  41. package/templates/runtime/export/image-artifact-export.test.ts +111 -0
  42. package/templates/runtime/export/image-artifact-export.ts +145 -0
  43. package/templates/runtime/export/index.ts +14 -1
  44. package/templates/runtime/export/product-export-renderer.test.ts +77 -0
  45. package/templates/runtime/export/product-export-renderer.ts +63 -0
  46. package/templates/runtime/export/video-artifact-export.test.ts +166 -0
  47. package/templates/runtime/export/video-artifact-export.ts +164 -0
  48. package/templates/runtime/export/video-encoding-backend.ts +124 -0
  49. package/templates/runtime/export/video-encoding-policy.test.ts +68 -0
  50. package/templates/runtime/export/video-encoding-policy.ts +86 -0
  51. package/templates/runtime/export/video-frame-schedule.test.ts +58 -0
  52. package/templates/runtime/export/video-frame-schedule.ts +42 -0
  53. package/templates/runtime/index.ts +1 -0
  54. package/templates/runtime/react/app-shell/runtime-public-api-runtime.test.tsx +291 -0
  55. package/templates/runtime/react/app-shell/runtime-public-api-test-support.ts +21 -0
  56. package/templates/runtime/react/app-shell/runtime-public-api.test.tsx +4 -303
  57. package/templates/runtime/react/app-shell/toolcraft-app.scene-export.test.tsx +12 -27
  58. package/templates/runtime/react/app-shell/toolcraft-app.tsx +22 -4
  59. package/templates/runtime/react/app-shell/toolcraft-source-asset-context.test.tsx +16 -57
  60. package/templates/runtime/react/app-shell/toolcraft-source-asset-context.tsx +75 -434
  61. package/templates/runtime/react/app-shell/toolcraft-source-asset-owner.test.ts +194 -0
  62. package/templates/runtime/react/app-shell/toolcraft-source-asset-owner.ts +227 -0
  63. package/templates/runtime/react/app-shell/toolcraft-source-asset-provider-ownership.test.tsx +243 -0
  64. package/templates/runtime/react/app-shell/toolcraft-source-asset-test-support.ts +51 -0
  65. package/templates/runtime/react/app-shell/toolcraft-unavailable-resource-proof.test.ts +138 -0
  66. package/templates/runtime/react/app-shell/toolcraft-unavailable-resource-proof.ts +378 -0
  67. package/templates/runtime/react/controls-panel/__tests__/controls-panel.footer-actions.test.tsx +7 -12
  68. package/templates/runtime/react/controls-panel/__tests__/controls-panel.scene-export-actions.test.tsx +17 -83
  69. package/templates/runtime/react/controls-panel/actions/controls-panel-actions.ts +42 -84
  70. package/templates/runtime/react/controls-panel/actions/export-action-runner.ts +62 -0
  71. package/templates/runtime/react/panel-host/panel-host-runtime-placement.test.tsx +30 -0
  72. package/templates/runtime/react/panel-host/panel-host.tsx +4 -0
  73. package/templates/runtime/scene/scene-bounds.ts +1 -2
  74. package/templates/runtime/schema/canvas-render-scale.ts +62 -0
  75. package/templates/runtime/schema/controls-panel-section-id.test.ts +1 -1
  76. package/templates/runtime/schema/controls-panel-section-roundtrip.test.ts +3 -3
  77. package/templates/runtime/schema/define-toolcraft.setup-background.test.ts +1 -1
  78. package/templates/runtime/schema/define-toolcraft.setup-render-scale-timeline.test.ts +71 -3
  79. package/templates/runtime/schema/define-toolcraft.ts +1 -1
  80. package/templates/runtime/schema/schema-resolvers.ts +0 -56
  81. package/templates/runtime/schema/types.ts +4 -4
  82. package/templates/runtime/state/canvas-background-state.ts +6 -0
  83. package/templates/runtime/testing/performance-render-plan-integration.test.ts +64 -0
  84. package/templates/runtime/testing/performance-renderer-pipeline-validation.ts +18 -1
  85. package/templates/starter/AGENTS.md +8 -7
  86. package/templates/starter/NOTICE.md +6 -0
  87. package/templates/starter/docs/toolcraft/README.md +2 -1
  88. package/templates/starter/docs/toolcraft/acceptance-testing.md +8 -6
  89. package/templates/starter/docs/toolcraft/agent-worklog.md +3 -3
  90. package/templates/starter/docs/toolcraft/assembly-workflow.md +4 -3
  91. package/templates/starter/docs/toolcraft/core/media-upload.md +2 -2
  92. package/templates/starter/docs/toolcraft/core/performance.md +14 -3
  93. package/templates/starter/docs/toolcraft/core/runtime-boundary.md +3 -1
  94. package/templates/starter/docs/toolcraft/core/setup-export.md +16 -12
  95. package/templates/starter/docs/toolcraft/core/timeline-animation.md +4 -4
  96. package/templates/starter/docs/toolcraft/performance.md +20 -6
  97. package/templates/starter/docs/toolcraft/renderer-technique.md +1 -1
  98. package/templates/starter/docs/toolcraft/schema-reference.md +2 -6
  99. package/templates/starter/docs/toolcraft/workflow.md +7 -2
  100. package/templates/starter/e2e/app-browser-control-coverage.spec.ts +33 -0
  101. package/templates/starter/e2e/app-browser-infinity-canvas-evidence.spec.ts +43 -1
  102. package/templates/starter/e2e/app-browser-render-scale-evidence.spec.ts +60 -6
  103. package/templates/starter/e2e/app-browser-render-scale-requirements.spec.ts +77 -1
  104. package/templates/starter/e2e/app-browser-runtime-provenance.spec.ts +8 -0
  105. package/templates/starter/e2e/app-browser-runtime-reporter.spec.ts +35 -0
  106. package/templates/starter/e2e/app-browser-runtime-requirements.spec.ts +4 -1
  107. package/templates/starter/e2e/app-browser-semantic-evidence.spec.ts +0 -1
  108. package/templates/starter/e2e/app-browser-shell.spec.ts +13 -5
  109. package/templates/starter/e2e/app-performance-path-adapters.ts +8 -1
  110. package/templates/starter/e2e/app-performance.spec.ts +16 -9
  111. package/templates/starter/e2e/browser-infinity-canvas-evidence.ts +9 -330
  112. package/templates/starter/e2e/browser-infinity-canvas-unavailable-image-evidence.ts +370 -0
  113. package/templates/starter/e2e/browser-media-export-evidence.spec.ts +77 -0
  114. package/templates/starter/e2e/browser-media-export-evidence.ts +208 -0
  115. package/templates/starter/e2e/browser-render-scale-evidence.ts +37 -29
  116. package/templates/starter/e2e/browser-runtime-evidence-reporter.ts +4 -1
  117. package/templates/starter/e2e/browser-runtime-evidence-requirements.ts +43 -9
  118. package/templates/starter/e2e/browser-standard-timeline-evidence.ts +106 -0
  119. package/templates/starter/e2e/decoded-pixel-observation.spec.ts +74 -0
  120. package/templates/starter/e2e/decoded-pixel-observation.ts +227 -0
  121. package/templates/starter/e2e/export-artifact-helpers.ts +206 -25
  122. package/templates/starter/e2e/image-artifact-inspection.spec.ts +41 -0
  123. package/templates/starter/e2e/image-artifact-inspection.ts +99 -0
  124. package/templates/starter/e2e/performance-canvas-helpers.ts +22 -21
  125. package/templates/starter/e2e/performance-canvas-quality-guard.spec.ts +312 -0
  126. package/templates/starter/e2e/performance-canvas-quality-guard.ts +196 -0
  127. package/templates/starter/e2e/performance-canvas-quality-observer.ts +351 -0
  128. package/templates/starter/e2e/performance-control-layout-helpers.ts +2 -2
  129. package/templates/starter/e2e/performance-path-adapter-contract.ts +4 -4
  130. package/templates/starter/e2e/performance-path-helpers.spec.ts +203 -70
  131. package/templates/starter/e2e/performance-path-helpers.ts +210 -91
  132. package/templates/starter/e2e/performance-pipeline-evidence-continuity.spec.ts +76 -0
  133. package/templates/starter/e2e/performance-pipeline-evidence-test-fixtures.ts +11 -2
  134. package/templates/starter/e2e/performance-pipeline-invariants.ts +47 -4
  135. package/templates/starter/e2e/performance-render-scale-runner.spec.ts +140 -38
  136. package/templates/starter/e2e/video-artifact-inspection.spec.ts +64 -0
  137. package/templates/starter/e2e/video-artifact-inspection.ts +281 -0
  138. package/templates/starter/gitignore +1 -0
  139. package/templates/starter/package.json +1 -0
  140. package/templates/starter/scripts/check-toolcraft-docs.mjs +17 -0
  141. package/templates/starter/scripts/toolcraft-delivery-plan-authority.test.mjs +60 -0
  142. package/templates/starter/scripts/toolcraft-delivery-plan-errors.test.mjs +7 -2
  143. package/templates/starter/scripts/toolcraft-delivery-plan.mjs +7 -3
  144. package/templates/starter/scripts/toolcraft-product-boundary-ast.mjs +24 -2
  145. package/templates/starter/scripts/toolcraft-product-boundary.mjs +12 -0
  146. package/templates/starter/scripts/toolcraft-product-boundary.test.mjs +46 -0
  147. package/templates/starter/scripts/toolcraft-product-evidence-boundary.test.mjs +85 -20
  148. package/templates/starter/scripts/toolcraft-product-evidence-import-policy.mjs +43 -0
  149. package/templates/starter/scripts/toolcraft-product-export-boundary.mjs +168 -0
  150. package/templates/starter/scripts/toolcraft-typescript-analysis.d.mts +73 -0
  151. package/templates/starter/scripts/toolcraft-unavailable-resource-evidence-facade-test-helpers.mjs +318 -0
  152. package/templates/starter/scripts/toolcraft-unavailable-resource-evidence-facade.test.mjs +155 -206
  153. package/templates/starter/scripts/toolcraft-verification-inventory.mjs +1 -0
  154. package/templates/starter/scripts/toolcraft-verification-receipt.test.mjs +51 -0
  155. package/templates/starter/scripts/toolcraft-vite-env-activation.test.mjs +128 -59
  156. package/templates/starter/src/app/acceptance/export-artifact-coverage.ts +113 -0
  157. package/templates/starter/src/app/acceptance/output-background-rules.ts +1 -1
  158. package/templates/starter/src/app/acceptance/output-export.ts +13 -2
  159. package/templates/starter/src/app/acceptance/types.ts +7 -0
  160. package/templates/starter/src/app/acceptance/validate-coverage.ts +2 -1
  161. package/templates/starter/src/app/starter-acceptance.export-artifact.test.ts +131 -0
  162. package/templates/starter/src/app/starter-acceptance.keyframes.test.ts +14 -4
  163. package/templates/starter/src/app/starter-acceptance.output-export-rules.test.ts +42 -1
  164. package/templates/starter/src/app/starter-acceptance.ts +2 -0
  165. package/templates/starter/src/app/starter-performance-test-utils.ts +103 -0
  166. package/templates/starter/src/app/starter-performance.gates.test.ts +231 -278
  167. package/templates/starter/src/app/starter-performance.lifecycle.test.ts +261 -0
  168. package/templates/starter/src/app/test-evidence/browser-runtime-contract.ts +2 -0
  169. package/templates/starter/src/routes/index.tsx +1 -0
  170. package/templates/runtime/export/export.ts +0 -166
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixel-point/toolcraft",
3
- "version": "0.0.16",
3
+ "version": "0.0.17",
4
4
  "license": "SEE LICENSE IN LICENSE.md",
5
5
  "type": "module",
6
6
  "bin": {
@@ -99,7 +99,7 @@ test("generated standalone app preserves authority-bound performance iteration l
99
99
  }
100
100
  const output = `${stdout}\n${stderr}`;
101
101
  assert.doesNotMatch(output, /ERR_MODULE_NOT_FOUND/u);
102
- assert.match(output, /^# tests 9$/mu);
103
- assert.match(output, /^# pass 9$/mu);
102
+ assert.match(output, /^# tests 11$/mu);
103
+ assert.match(output, /^# pass 11$/mu);
104
104
  assert.match(output, /^# fail 0$/mu);
105
105
  });
@@ -31,10 +31,20 @@ const materialBrowserTestNames = Object.freeze([
31
31
  "browser: frosting color changes material output",
32
32
  "browser: gloss changes material output",
33
33
  "browser: layer mode changes material output",
34
- "browser: material appearance reaches exported pixels",
34
+ "browser: material appearance reaches decoded exported pixels",
35
35
  "browser: sprinkle color changes material output",
36
36
  "browser: sprinkles visibility changes material output",
37
37
  ]);
38
+ const materialDeliveryBrowserTestNames = Object.freeze([
39
+ "browser: ambient speed changes product output",
40
+ ...materialBrowserTestNames,
41
+ "browser: timeline playback drives product output",
42
+ ]);
43
+ const materialDeliveryAcceptanceIds = Object.freeze([
44
+ "animation.speed",
45
+ ...materialAcceptanceIds,
46
+ "runtime.timeline",
47
+ ]);
38
48
  const materialProductTestFiles = Object.freeze([
39
49
  "src/app/acceptance/validation-pipeline.test.ts",
40
50
  "src/app/app-acceptance.base-coverage.test.ts",
@@ -44,6 +54,7 @@ const materialProductTestFiles = Object.freeze([
44
54
  "src/app/app-automated-runtime-evidence.test.ts",
45
55
  "src/app/app-performance.fixture-helper.test.ts",
46
56
  "src/app/app-performance.gates.test.ts",
57
+ "src/app/app-performance.lifecycle.test.ts",
47
58
  "src/app/app-schema.test.ts",
48
59
  "src/app/material-output.test.tsx",
49
60
  ]);
@@ -294,8 +305,8 @@ export async function assertGeneratedFreshDemandOnlyLifecycle({
294
305
  browserEnv,
295
306
  checkpointPath,
296
307
  execFileAsync,
297
- expectedAcceptanceIds: materialAcceptanceIds,
298
- expectedBrowserTestNames: materialBrowserTestNames,
308
+ expectedAcceptanceIds: materialDeliveryAcceptanceIds,
309
+ expectedBrowserTestNames: materialDeliveryBrowserTestNames,
299
310
  expectedChangedFiles: generatedProductMaterialIterationFixturePaths,
300
311
  expectedProductTestFiles: materialProductTestFiles,
301
312
  targetDir,
@@ -115,15 +115,13 @@ function createGeneratedCommandEnvironment(packageManager, overrides = {}) {
115
115
  return childEnv;
116
116
  }
117
117
 
118
- export async function runGeneratedCommand(
118
+ async function executeGeneratedPackageManager(
119
119
  execFileAsync,
120
120
  targetDir,
121
- args,
121
+ packageManager,
122
+ packageManagerArgs,
122
123
  { env = {} } = {},
123
124
  ) {
124
- const { packageManager } = await readGeneratedPackageManager(targetDir);
125
- const packageManagerArgs =
126
- packageManager === "npm" ? ["run", ...args] : args;
127
125
  try {
128
126
  return await execFileAsync(packageManager, packageManagerArgs, {
129
127
  cwd: targetDir,
@@ -143,6 +141,45 @@ export async function runGeneratedCommand(
143
141
  }
144
142
  }
145
143
 
144
+ export async function runGeneratedCommand(
145
+ execFileAsync,
146
+ targetDir,
147
+ args,
148
+ options,
149
+ ) {
150
+ const { packageManager } = await readGeneratedPackageManager(targetDir);
151
+ const packageManagerArgs =
152
+ packageManager === "npm" ? ["run", ...args] : args;
153
+ return executeGeneratedPackageManager(
154
+ execFileAsync,
155
+ targetDir,
156
+ packageManager,
157
+ packageManagerArgs,
158
+ options,
159
+ );
160
+ }
161
+
162
+ export async function runGeneratedExecutable(
163
+ execFileAsync,
164
+ targetDir,
165
+ executableName,
166
+ args,
167
+ options,
168
+ ) {
169
+ const { packageManager } = await readGeneratedPackageManager(targetDir);
170
+ const packageManagerArgs =
171
+ packageManager === "npm"
172
+ ? ["exec", "--", executableName, ...args]
173
+ : ["exec", executableName, ...args];
174
+ return executeGeneratedPackageManager(
175
+ execFileAsync,
176
+ targetDir,
177
+ packageManager,
178
+ packageManagerArgs,
179
+ options,
180
+ );
181
+ }
182
+
146
183
  export function runGeneratedScript(
147
184
  execFileAsync,
148
185
  targetDir,
@@ -26,6 +26,23 @@ const generatedDocPaths = [
26
26
  const staleAgentPerformanceWorkflowPattern =
27
27
  /app-performance-impact|explicit-performance-work|test:browser:perf|verify:(?:final|quick|ui)|verify:perf:(?:playwright|record-iteration|refresh)|--reason=performance-iteration|--performance-test/iu;
28
28
 
29
+ const generatedPerformanceLifecycleMarkers = [
30
+ "<!-- toolcraft-performance-lifecycle: first-delivery=functional; later-delivery=functional-targeted; complaint=one-authority-targeted-performance-iteration; full-audit=explicit-only -->",
31
+ "<!-- toolcraft-performance-iteration: authority=exact-request-evidence+canonical-path-ids; fixture=reachable-development; after-pass=return-app-to-user+stop -->",
32
+ "<!-- toolcraft-performance-full-authority: automatic=forbidden; recommendation=two-compatible-iterations-or-broad-unlocalizable-problem; command=pnpm verify:perf; authority=explicit-user-request-or-accepted-offer -->",
33
+ "<!-- toolcraft-performance-routing: localized=agent-targeted; ambiguous=one-user-facing-choice; broad=offer-targeted-or-full; full=explicit-only -->",
34
+ ];
35
+
36
+ export function getMissingGeneratedPerformanceLifecycleMarkers(sources) {
37
+ return sources.flatMap(({ docPath, source }) =>
38
+ generatedPerformanceLifecycleMarkers.flatMap((marker) =>
39
+ source.includes(marker)
40
+ ? []
41
+ : [`docs/toolcraft/${docPath} must include canonical marker: ${marker}`],
42
+ ),
43
+ );
44
+ }
45
+
29
46
  async function collectMarkdownPaths(rootDir, relativeDir = "") {
30
47
  const currentDir = path.join(rootDir, relativeDir);
31
48
  const entries = await fs.readdir(currentDir, { withFileTypes: true });
@@ -83,6 +100,10 @@ export async function assertGeneratedDocs(targetDir) {
83
100
  await collectGeneratedAgentFacingDocs(targetDir),
84
101
  );
85
102
 
103
+ assert.match(noticeSource, /Mediabunny/u);
104
+ assert.match(noticeSource, /MPL-2\.0/u);
105
+ assert.match(noticeSource, /https:\/\/github\.com\/Vanilagy\/mediabunny/u);
106
+
86
107
  assert.deepEqual(
87
108
  staleWorkflowFailures,
88
109
  [],
@@ -139,6 +160,7 @@ export async function assertGeneratedDocs(targetDir) {
139
160
  assert.match(agentsSource, /defineToolcraft/);
140
161
  assert.match(agentsSource, /ToolcraftApp/);
141
162
  assert.match(agentsSource, /canvasContent/);
163
+ assert.match(agentsSource, /exportRenderer/);
142
164
  assert.match(agentsSource, /renderDefaultCanvasMedia=\{false\}/);
143
165
  assert.match(agentsSource, /onPanelAction/);
144
166
  assert.match(agentsSource, /MIT License/);
@@ -213,6 +235,8 @@ export async function assertGeneratedDocs(targetDir) {
213
235
  assert.match(coreRuntimeBoundarySource, /immutable signed copy of the shared runtime/);
214
236
  assert.match(coreRuntimeBoundarySource, /copied runtime tree or its signed integrity manifest is missing/);
215
237
  assert.match(coreRuntimeBoundarySource, /modelPresentation/);
238
+ assert.match(coreRuntimeBoundarySource, /exportRenderer/);
239
+ assert.match(coreRuntimeBoundarySource, /runtime owns typed image\/video actions end to end/i);
216
240
  assert.match(coreRuntimeBoundarySource, /does not suppress runtime model layers/);
217
241
  assert.match(componentRulesSource, /Do not show Layers for a single-layer app/);
218
242
  assert.match(coreTimelineSource, /Any app with `Export Video` must enable the top Toolcraft timeline/);
@@ -225,6 +249,17 @@ export async function assertGeneratedDocs(targetDir) {
225
249
  assert.match(coreSetupExportSource, /renderScaleCoverage/);
226
250
  assert.match(coreSetupExportSource, /selected-backing-pixels/);
227
251
  assert.match(coreSetupExportSource, /canvas-render-scale-backing/);
252
+ assert.match(coreSetupExportSource, /Mediabunny/);
253
+ assert.match(coreSetupExportSource, /fixed 30 FPS offline schedule/);
254
+ assert.match(coreSetupExportSource, /Product code must not instantiate `MediaRecorder` or `VideoEncoder`/);
255
+ assert.doesNotMatch(
256
+ coreSetupExportSource,
257
+ /createToolcraftPngExportCanvas|renderRuntimeSceneToCanvas|renderModelsToCanvas/,
258
+ );
259
+ assert.doesNotMatch(
260
+ coreMediaUploadSource,
261
+ /createToolcraftPngExportCanvas|renderRuntimeSceneToCanvas|renderModelsToCanvas/,
262
+ );
228
263
  assert.match(
229
264
  coreSetupExportSource,
230
265
  /interaction[\s\S]*steady[\s\S]*playback[\s\S]*timeline/i,
@@ -269,6 +304,8 @@ export async function assertGeneratedDocs(targetDir) {
269
304
  acceptanceDocsSource,
270
305
  /export-content proof is distinct from export mechanics/i,
271
306
  );
307
+ assert.match(acceptanceDocsSource, /actual encoded packet metadata/i);
308
+ assert.match(acceptanceDocsSource, /distinct decoded frame hashes/i);
272
309
  assert.match(
273
310
  acceptanceDocsSource,
274
311
  /Each browser file owns one acceptance domain/i,
@@ -312,24 +349,14 @@ export async function assertGeneratedDocs(targetDir) {
312
349
  path.join(targetDir, "docs/toolcraft/core/performance.md"),
313
350
  "utf8",
314
351
  );
315
- const performanceLifecycleMarkers = [
316
- "<!-- toolcraft-performance-lifecycle: first-delivery=functional; later-delivery=functional-targeted; complaint=one-authority-targeted-performance-iteration; full-audit=explicit-only -->",
317
- "<!-- toolcraft-performance-iteration: authority=exact-request-evidence+canonical-path-ids; fixture=reachable-development; after-pass=return-app-to-user+stop -->",
318
- "<!-- toolcraft-performance-full-authority: automatic=forbidden; recommendation=two-compatible-iterations-or-broad-unlocalizable-problem; command=pnpm verify:perf; authority=explicit-user-request-or-accepted-offer -->",
319
- ];
320
- for (const [docPath, source] of [
321
- ["workflow.md", workflowDocsSource],
322
- ["performance.md", performanceDocsSource],
323
- ["core/performance.md", corePerformanceDocsSource],
324
- ]) {
325
- for (const marker of performanceLifecycleMarkers) {
326
- assert.equal(
327
- source.includes(marker),
328
- true,
329
- `docs/toolcraft/${docPath} must include canonical marker: ${marker}`,
330
- );
331
- }
332
- }
352
+ assert.deepEqual(
353
+ getMissingGeneratedPerformanceLifecycleMarkers([
354
+ { docPath: "workflow.md", source: workflowDocsSource },
355
+ { docPath: "performance.md", source: performanceDocsSource },
356
+ { docPath: "core/performance.md", source: corePerformanceDocsSource },
357
+ ]),
358
+ [],
359
+ );
333
360
  assert.match(rendererDocsSource, /rendererTechnique/);
334
361
  assert.match(rendererDocsSource, /sourceRepresentation/);
335
362
  assert.match(rendererDocsSource, /whyNotAlternativeStrategies/);
@@ -339,6 +366,7 @@ export async function assertGeneratedDocs(targetDir) {
339
366
  assert.match(rendererDocsSource, /canonical paths/i);
340
367
  assert.match(rendererDocsSource, /combined fixtures/i);
341
368
  assert.match(rendererDocsSource, /modelPresentation/);
369
+ assert.match(rendererDocsSource, /ToolcraftAppComposition\.exportRenderer/);
342
370
  assert.match(rendererDocsSource, /useToolcraftModelPresentationConsumer/);
343
371
  assert.match(rendererDocsSource, /acquirePresentation/);
344
372
  assert.match(rendererDocsSource, /lease\.release/);
@@ -367,12 +395,34 @@ export async function assertGeneratedDocs(targetDir) {
367
395
  corePerformanceDocsSource,
368
396
  /functional failure[\s\S]*without measured performance/i,
369
397
  );
398
+ assert.match(corePerformanceDocsSource, /exact 30 FPS packet cadence[\s\S]*functional correctness/i);
399
+ assert.match(performanceDocsSource, /exact 30 FPS packet cadence[\s\S]*functional proof/i);
370
400
  assert.match(performanceDocsSource, /coherent (?:user-visible )?delivery batch/i);
371
401
  assert.match(performanceDocsSource, /verify:delivery/);
372
402
  assert.match(performanceDocsSource, /immediately previous successful delivery/i);
373
403
  assert.match(performanceDocsSource, /performance-iteration/);
374
404
  assert.match(performanceDocsSource, /renderScaleCoverage/);
375
405
  assert.match(performanceDocsSource, /canvas-render-scale-backing/);
406
+ assert.match(
407
+ performanceDocsSource,
408
+ /localized complaint[^\n]*without (?:a |asking the user)/iu,
409
+ );
410
+ assert.match(
411
+ performanceDocsSource,
412
+ /ambiguous complaint[\s\S]*one user-facing/iu,
413
+ );
414
+ assert.match(
415
+ performanceDocsSource,
416
+ /targeted diagnosis[\s\S]*complete (?:performance )?review/iu,
417
+ );
418
+ assert.match(
419
+ performanceDocsSource,
420
+ /every measured path[\s\S]*devicePixelRatio × 2/iu,
421
+ );
422
+ assert.match(
423
+ coreSetupExportSource,
424
+ /product code may customize only the slider step/iu,
425
+ );
376
426
  assert.match(performanceDocsSource, /Use bare `npm run verify:delivery` once/i);
377
427
  assert.match(
378
428
  workflowDocsSource,
@@ -6,6 +6,7 @@ import test from "node:test";
6
6
 
7
7
  import {
8
8
  collectGeneratedAgentFacingDocs,
9
+ getMissingGeneratedPerformanceLifecycleMarkers,
9
10
  getStaleAgentPerformanceWorkflowFailures,
10
11
  } from "./generate-test-doc-assertions.mjs";
11
12
 
@@ -41,3 +42,24 @@ test("scans every generated agent-facing Markdown source independently", async (
41
42
  "docs/toolcraft/core/performance.md contains removed performance workflow guidance",
42
43
  ]);
43
44
  });
45
+
46
+ test("requires adaptive routing in every generated performance lifecycle document", () => {
47
+ const routingMarker =
48
+ "<!-- toolcraft-performance-routing: localized=agent-targeted; ambiguous=one-user-facing-choice; broad=offer-targeted-or-full; full=explicit-only -->";
49
+ const existingMarkers = [
50
+ "<!-- toolcraft-performance-lifecycle: first-delivery=functional; later-delivery=functional-targeted; complaint=one-authority-targeted-performance-iteration; full-audit=explicit-only -->",
51
+ "<!-- toolcraft-performance-iteration: authority=exact-request-evidence+canonical-path-ids; fixture=reachable-development; after-pass=return-app-to-user+stop -->",
52
+ "<!-- toolcraft-performance-full-authority: automatic=forbidden; recommendation=two-compatible-iterations-or-broad-unlocalizable-problem; command=pnpm verify:perf; authority=explicit-user-request-or-accepted-offer -->",
53
+ ].join("\n");
54
+
55
+ assert.deepEqual(
56
+ getMissingGeneratedPerformanceLifecycleMarkers([
57
+ { docPath: "workflow.md", source: `${existingMarkers}\n${routingMarker}` },
58
+ { docPath: "performance.md", source: existingMarkers },
59
+ { docPath: "core/performance.md", source: `${existingMarkers}\n${routingMarker}` },
60
+ ]),
61
+ [
62
+ `docs/toolcraft/performance.md must include canonical marker: ${routingMarker}`,
63
+ ],
64
+ );
65
+ });
@@ -6,9 +6,15 @@ import {
6
6
  assertGeneratedDeliveryArchitecture,
7
7
  deliveryArchitecturePaths,
8
8
  } from "./generate-test-delivery-architecture-assertions.mjs";
9
- import { listRelativeFiles, readTextFiles, repoRoot } from "./generate-test-fs-utils.mjs";
9
+ import { listRelativeFiles, repoRoot } from "./generate-test-fs-utils.mjs";
10
+ import { assertGeneratedPerformanceCanvasBoundary } from "./generate-test-performance-boundary-assertions.mjs";
10
11
  import { isGeneratedTestSupportPath } from "./generated-source-policy.mjs";
11
12
 
13
+ export {
14
+ assertGeneratedRoutesAndStyles,
15
+ assertGeneratedTextIsStandalone,
16
+ } from "./generate-test-output-assertions.mjs";
17
+
12
18
  function assertSignedProtectedFiles(manifest, relativePaths, responsibility) {
13
19
  for (const relativePath of relativePaths) {
14
20
  assert.ok(
@@ -68,6 +74,39 @@ export async function assertGeneratedFiles(targetDir) {
68
74
  expectedRuntimeFiles,
69
75
  "Generated standalone runtime must contain every production runtime module.",
70
76
  );
77
+ for (const relativePath of [
78
+ "runtime/export/artifact-export-settings.ts",
79
+ "runtime/export/artifact-export-request.ts",
80
+ "runtime/export/artifact-frame-renderer.ts",
81
+ "runtime/export/artifact-frame-state.ts",
82
+ "runtime/export/artifact-scene-frame.ts",
83
+ "runtime/export/image-artifact-export.ts",
84
+ "runtime/export/product-export-renderer.ts",
85
+ "runtime/export/video-artifact-export.ts",
86
+ "runtime/export/video-encoding-backend.ts",
87
+ "runtime/export/video-frame-schedule.ts",
88
+ ]) {
89
+ assert.ok(
90
+ generatedToolcraftFiles.includes(relativePath),
91
+ `Generated runtime must contain ${relativePath}.`,
92
+ );
93
+ }
94
+ assert.equal(
95
+ generatedToolcraftFiles.includes("runtime/export/export.ts"),
96
+ false,
97
+ "Generated runtime must not copy the removed legacy export helper.",
98
+ );
99
+ for (const relativePath of [
100
+ "e2e/browser-media-export-evidence.ts",
101
+ "e2e/decoded-pixel-observation.ts",
102
+ "e2e/image-artifact-inspection.ts",
103
+ "e2e/video-artifact-inspection.ts",
104
+ ]) {
105
+ assert.ok(
106
+ await fs.stat(path.join(targetDir, relativePath)),
107
+ `Generated output must contain ${relativePath}.`,
108
+ );
109
+ }
71
110
  for (const relativePath of generatedToolcraftFiles) {
72
111
  assert.equal(
73
112
  isGeneratedTestSupportPath(relativePath),
@@ -96,9 +135,7 @@ export async function assertGeneratedFiles(targetDir) {
96
135
  await listRelativeFiles(path.join(repoRoot, "starter/e2e")),
97
136
  );
98
137
  assert.ok(await fs.stat(path.join(targetDir, "e2e/app-controls.spec.ts")));
99
- assert.ok(
100
- await fs.stat(path.join(targetDir, "e2e/app-performance-path-adapters.ts")),
101
- );
138
+ await assertGeneratedPerformanceCanvasBoundary(targetDir);
102
139
 
103
140
  const generatedAppSourceFiles = await listRelativeFiles(path.join(targetDir, "src/app"));
104
141
  assert.ok(await fs.stat(path.join(targetDir, "src/app/app-schema.ts")));
@@ -350,6 +387,8 @@ export async function assertGeneratedFiles(targetDir) {
350
387
  "e2e/performance-measurement-evidence.ts",
351
388
  "e2e/performance-path-adapter-contract.ts",
352
389
  "e2e/performance-path-helpers.ts",
390
+ "e2e/performance-canvas-quality-observer.ts",
391
+ "e2e/performance-canvas-quality-guard.ts",
353
392
  "e2e/performance-slider-helpers.ts",
354
393
  "scripts/toolcraft-performance-report.mjs",
355
394
  "scripts/toolcraft-kernel-benchmark-receipt.mjs",
@@ -415,75 +454,3 @@ export async function assertGeneratedFiles(targetDir) {
415
454
  undefined,
416
455
  );
417
456
  }
418
-
419
- export async function assertGeneratedRoutesAndStyles(targetDir) {
420
- await assert.rejects(
421
- () => fs.stat(path.join(targetDir, "src/toolcraft/runtime/react/canvas-shell.test.tsx")),
422
- /ENOENT/,
423
- );
424
-
425
- const routeSource = await fs.readFile(path.join(targetDir, "src/routes/index.tsx"), "utf8");
426
- assert.match(routeSource, /@\/toolcraft\/runtime\/react/);
427
- assert.match(routeSource, /\.\.\/app\/app-composition/);
428
- assert.match(routeSource, /canvasContent=\{appComposition\.canvasContent\}/);
429
- assert.match(routeSource, /controlRenderers=\{appComposition\.controlRenderers\}/);
430
- assert.match(routeSource, /modelPresentation=\{appComposition\.modelPresentation\}/);
431
- assert.match(routeSource, /onPanelAction=\{appComposition\.onPanelAction\}/);
432
- assert.match(
433
- routeSource,
434
- /renderDefaultCanvasMedia=\{appComposition\.renderDefaultCanvasMedia\}/,
435
- );
436
- assert.match(
437
- routeSource,
438
- /rendererPipelineRegistration=\{appComposition\.rendererPipelineRegistration\}/,
439
- );
440
- assert.match(
441
- routeSource,
442
- /sceneBoundsProvider=\{appComposition\.sceneBoundsProvider\}/,
443
- );
444
- assert.match(routeSource, /schema=\{appComposition\.schema\}/);
445
- assert.match(routeSource, /className="h-dvh min-h-dvh"/);
446
- assert.doesNotMatch(routeSource, /\{\.\.\.appComposition\}/);
447
- assert.doesNotMatch(routeSource, /appSchema|ProductCanvas/);
448
-
449
- const compositionSource = await fs.readFile(
450
- path.join(targetDir, "src/app/app-composition.tsx"),
451
- "utf8",
452
- );
453
- assert.match(
454
- compositionSource,
455
- /import type \{ ToolcraftAppComposition \} from "@\/toolcraft\/runtime\/react"/,
456
- );
457
- assert.match(compositionSource, /export const appComposition/);
458
- assert.match(compositionSource, /appComposition\s*:\s*ToolcraftAppComposition\s*=/);
459
- assert.match(compositionSource, /modelPresentation:\s*\{\s*mode:\s*"runtime"\s*\}/);
460
-
461
- const stylesSource = await fs.readFile(path.join(targetDir, "src/styles.css"), "utf8");
462
- assert.match(stylesSource, /@source "\.\/toolcraft\/ui";/);
463
- assert.match(stylesSource, /@import "@\/toolcraft\/ui\/styles\.css";/);
464
- }
465
-
466
- export async function assertGeneratedTextIsStandalone(targetDir) {
467
- const allText = await readTextFiles(targetDir);
468
- assert.doesNotMatch(allText, /BEGIN PRIVATE KEY/);
469
- assert.doesNotMatch(allText, /@repo\/ui|@repo\/toolcraft-runtime|workspace:/);
470
- assert.doesNotMatch(allText, new RegExp("template" + "-runtime"));
471
- assert.doesNotMatch(allText, /packages\/typescript-config/);
472
- assert.doesNotMatch(
473
- allText,
474
- /prototype-smoke|browser-functional-smoke|performance-smoke|app-performance-smoke|toolcraft-performance-smoke-runner/,
475
- );
476
- assert.doesNotMatch(
477
- allText,
478
- /starterComposition|starter-composition|starterSchema|starter-schema|starterAcceptance|starterControlSectionInventory|starter-acceptance|starterProductReadiness|starterTransferMode|starterPerformance|starter-performance|StarterHome|Toolcraft Starter/,
479
- );
480
-
481
- const kernelReceiptDeclaration = await fs.readFile(
482
- path.join(targetDir, "scripts/toolcraft-kernel-benchmark-receipt.d.mts"),
483
- "utf8",
484
- );
485
- assert.match(
486
- kernelReceiptDeclaration,
487
- /from "@\/toolcraft\/runtime"/,
488
- );
489
- }
@@ -0,0 +1,95 @@
1
+ import assert from "node:assert/strict";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+
5
+ import { readTextFiles } from "./generate-test-fs-utils.mjs";
6
+
7
+ export async function assertGeneratedRoutesAndStyles(targetDir) {
8
+ await assert.rejects(
9
+ () =>
10
+ fs.stat(
11
+ path.join(
12
+ targetDir,
13
+ "src/toolcraft/runtime/react/canvas-shell.test.tsx",
14
+ ),
15
+ ),
16
+ /ENOENT/,
17
+ );
18
+
19
+ const routeSource = await fs.readFile(
20
+ path.join(targetDir, "src/routes/index.tsx"),
21
+ "utf8",
22
+ );
23
+ assert.match(routeSource, /@\/toolcraft\/runtime\/react/);
24
+ assert.match(routeSource, /\.\.\/app\/app-composition/);
25
+ assert.match(routeSource, /canvasContent=\{appComposition\.canvasContent\}/);
26
+ assert.match(routeSource, /controlRenderers=\{appComposition\.controlRenderers\}/);
27
+ assert.match(routeSource, /modelPresentation=\{appComposition\.modelPresentation\}/);
28
+ assert.match(routeSource, /onPanelAction=\{appComposition\.onPanelAction\}/);
29
+ assert.match(
30
+ routeSource,
31
+ /renderDefaultCanvasMedia=\{appComposition\.renderDefaultCanvasMedia\}/,
32
+ );
33
+ assert.match(
34
+ routeSource,
35
+ /rendererPipelineRegistration=\{appComposition\.rendererPipelineRegistration\}/,
36
+ );
37
+ assert.match(
38
+ routeSource,
39
+ /sceneBoundsProvider=\{appComposition\.sceneBoundsProvider\}/,
40
+ );
41
+ assert.match(routeSource, /schema=\{appComposition\.schema\}/);
42
+ assert.match(routeSource, /className="h-dvh min-h-dvh"/);
43
+ assert.doesNotMatch(routeSource, /\{\.\.\.appComposition\}/);
44
+ assert.doesNotMatch(routeSource, /appSchema|ProductCanvas/);
45
+
46
+ const compositionSource = await fs.readFile(
47
+ path.join(targetDir, "src/app/app-composition.tsx"),
48
+ "utf8",
49
+ );
50
+ assert.match(
51
+ compositionSource,
52
+ /import type \{ ToolcraftAppComposition \} from "@\/toolcraft\/runtime\/react"/,
53
+ );
54
+ assert.match(compositionSource, /export const appComposition/);
55
+ assert.match(
56
+ compositionSource,
57
+ /appComposition\s*:\s*ToolcraftAppComposition\s*=/,
58
+ );
59
+ assert.match(
60
+ compositionSource,
61
+ /modelPresentation:\s*\{\s*mode:\s*"runtime"\s*\}/,
62
+ );
63
+
64
+ const stylesSource = await fs.readFile(
65
+ path.join(targetDir, "src/styles.css"),
66
+ "utf8",
67
+ );
68
+ assert.match(stylesSource, /@source "\.\/toolcraft\/ui";/);
69
+ assert.match(stylesSource, /@import "@\/toolcraft\/ui\/styles\.css";/);
70
+ }
71
+
72
+ export async function assertGeneratedTextIsStandalone(targetDir) {
73
+ const allText = await readTextFiles(targetDir);
74
+ assert.doesNotMatch(allText, /BEGIN PRIVATE KEY/);
75
+ assert.doesNotMatch(allText, /@repo\/ui|@repo\/toolcraft-runtime|workspace:/);
76
+ assert.doesNotMatch(allText, new RegExp("template" + "-runtime"));
77
+ assert.doesNotMatch(allText, /packages\/typescript-config/);
78
+ assert.doesNotMatch(
79
+ allText,
80
+ /prototype-smoke|browser-functional-smoke|performance-smoke|app-performance-smoke|toolcraft-performance-smoke-runner/,
81
+ );
82
+ assert.doesNotMatch(
83
+ allText,
84
+ /starterComposition|starter-composition|starterSchema|starter-schema|starterAcceptance|starterControlSectionInventory|starter-acceptance|starterProductReadiness|starterTransferMode|starterPerformance|starter-performance|StarterHome|Toolcraft Starter/,
85
+ );
86
+
87
+ const kernelReceiptDeclaration = await fs.readFile(
88
+ path.join(
89
+ targetDir,
90
+ "scripts/toolcraft-kernel-benchmark-receipt.d.mts",
91
+ ),
92
+ "utf8",
93
+ );
94
+ assert.match(kernelReceiptDeclaration, /from "@\/toolcraft\/runtime"/);
95
+ }
@@ -16,6 +16,11 @@ export async function assertGeneratedPackageJson(targetDir) {
16
16
  assert.equal(packageJson.dependencies.fflate, "0.8.3");
17
17
  assert.equal(packageJson.dependencies.draco3dgltf, undefined);
18
18
  assert.equal(packageJson.dependencies.meshoptimizer, "1.2.0");
19
+ assert.equal(
20
+ packageJson.dependencies.mediabunny,
21
+ "1.52.2",
22
+ "Generated apps must pin the runtime-owned timestamped video encoder.",
23
+ );
19
24
  assert.equal(packageJson.dependencies["react-resizable-panels"], "^4.10.0");
20
25
  assert.equal(packageJson.dependencies.sonner, "^2.0.7");
21
26
  assert.equal(packageJson.dependencies.three, "0.185.1");
@@ -76,6 +81,7 @@ export async function assertGeneratedGitignore(targetDir) {
76
81
  assert.match(gitignoreSource, /node_modules/);
77
82
  assert.match(gitignoreSource, /dist/);
78
83
  assert.match(gitignoreSource, /playwright-report/);
84
+ assert.match(gitignoreSource, /^\.playwright-mcp$/mu);
79
85
  assert.match(gitignoreSource, /\.env\.\*/);
80
86
  assert.match(gitignoreSource, /\.toolcraft/);
81
87
  await assert.rejects(() => fs.stat(path.join(targetDir, "gitignore")), /ENOENT/);
@@ -0,0 +1,45 @@
1
+ import assert from "node:assert/strict";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+
5
+ export async function assertGeneratedPerformanceCanvasBoundary(targetDir) {
6
+ const [
7
+ adaptersSource,
8
+ adapterContractSource,
9
+ guardSource,
10
+ helpersSource,
11
+ ] = await Promise.all([
12
+ fs.readFile(
13
+ path.join(targetDir, "e2e/app-performance-path-adapters.ts"),
14
+ "utf8",
15
+ ),
16
+ fs.readFile(
17
+ path.join(targetDir, "e2e/performance-path-adapter-contract.ts"),
18
+ "utf8",
19
+ ),
20
+ fs.readFile(
21
+ path.join(targetDir, "e2e/performance-canvas-quality-guard.ts"),
22
+ "utf8",
23
+ ),
24
+ fs.readFile(
25
+ path.join(targetDir, "e2e/performance-path-helpers.ts"),
26
+ "utf8",
27
+ ),
28
+ fs.stat(path.join(targetDir, "e2e/performance-canvas-quality-observer.ts")),
29
+ fs.stat(
30
+ path.join(targetDir, "e2e/performance-canvas-quality-guard.spec.ts"),
31
+ ),
32
+ ]);
33
+
34
+ assert.match(adaptersSource, /appPerformanceCanvasBacking/u);
35
+ assert.doesNotMatch(adapterContractSource, /renderScaleBacking\?:/u);
36
+ assert.match(helpersSource, /schema\.canvas\.renderScale\.enabled/u);
37
+ assert.match(
38
+ guardSource,
39
+ /from "\.\/performance-canvas-quality-observer"/u,
40
+ );
41
+ assert.match(
42
+ helpersSource,
43
+ /from "\.\/performance-canvas-quality-guard"/u,
44
+ );
45
+ }
@@ -38,6 +38,7 @@ export const generatedProductFixturePaths = Object.freeze([
38
38
  "e2e/product-canvas.spec.ts",
39
39
  "e2e/product-export.spec.ts",
40
40
  "e2e/product-material.spec.ts",
41
+ "e2e/product-media-export-fixture.ts",
41
42
  "e2e/product-runtime.spec.ts",
42
43
  "e2e/product-test-utils.ts",
43
44
  generatedProductPresentationResourcePath,
@@ -15,6 +15,11 @@ import {
15
15
  writeGeneratedProductFixture,
16
16
  } from "./generate-test-product-fixture.mjs";
17
17
 
18
+ const generatedProductFixtureRoot = new URL(
19
+ "../fixtures/generated-product/",
20
+ import.meta.url,
21
+ );
22
+
18
23
  it("rejects unknown and missing product fixture paths", () => {
19
24
  assert.deepEqual(generatedProductAuthorityFixturePaths, [
20
25
  "docs/toolcraft/agent-worklog.md",
@@ -106,6 +111,19 @@ it("rejects unknown and missing product fixture paths", () => {
106
111
  );
107
112
  });
108
113
 
114
+ it("keeps the vector product overlay explicit about canvas backing", async () => {
115
+ const adaptersSource = await fs.readFile(
116
+ new URL("e2e/app-performance-path-adapters.ts", generatedProductFixtureRoot),
117
+ "utf8",
118
+ );
119
+
120
+ assert.match(adaptersSource, /ToolcraftPerformanceCanvasBacking/u);
121
+ assert.match(
122
+ adaptersSource,
123
+ /appPerformanceCanvasBacking[\s\S]*undefined\s*=\s*undefined/u,
124
+ );
125
+ });
126
+
109
127
  it("reads only an exact supported command from generated authority policy", async () => {
110
128
  const targetDir = await fs.mkdtemp(
111
129
  path.join(os.tmpdir(), "toolcraft-product-manager-"),