@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
@@ -21,6 +21,7 @@ export const generatedProductMaterialIterationFixturePaths = Object.freeze([
21
21
  "public/material-sprinkles.svg",
22
22
  "src/app/app-acceptance-data.ts",
23
23
  "src/app/app-verification-impact.json",
24
+ "src/app/material-acceptance-data.ts",
24
25
  "src/app/material-output.test.tsx",
25
26
  "src/app/material-output.tsx",
26
27
  "src/app/material-schema.ts",
@@ -18,6 +18,7 @@ const expectedPaths = [
18
18
  "public/material-sprinkles.svg",
19
19
  "src/app/app-acceptance-data.ts",
20
20
  "src/app/app-verification-impact.json",
21
+ "src/app/material-acceptance-data.ts",
21
22
  "src/app/material-output.test.tsx",
22
23
  "src/app/material-output.tsx",
23
24
  "src/app/material-schema.ts",
@@ -6,7 +6,7 @@ import {
6
6
  assertGeneratedExecutionLedger,
7
7
  runGeneratedDeliveryWithLedger,
8
8
  } from "./generate-test-browser-execution-ledger.mjs";
9
- import { runGeneratedScript } from "./generate-test-dependency-sandbox.mjs";
9
+ import { runGeneratedExecutable } from "./generate-test-dependency-sandbox.mjs";
10
10
 
11
11
  export async function assertGeneratedRuntimeProbe({
12
12
  execFileAsync,
@@ -15,8 +15,11 @@ export async function assertGeneratedRuntimeProbe({
15
15
  const productTestPath = path.join(targetDir, "src/app/app-schema.test.ts");
16
16
  const productTestSource = await fs.readFile(productTestPath, "utf8");
17
17
  const failingSource = productTestSource.replace(
18
- 'it("ambient speed changes product output"',
19
- 'it.fails("ambient speed changes product output"',
18
+ 'it("ambient speed changes product output", () => {',
19
+ [
20
+ 'it.fails("ambient speed changes product output", () => {',
21
+ ' throw new Error("runtime evidence probe failure");',
22
+ ].join("\n"),
20
23
  );
21
24
  assert.notEqual(
22
25
  failingSource,
@@ -26,14 +29,19 @@ export async function assertGeneratedRuntimeProbe({
26
29
  await fs.writeFile(productTestPath, failingSource);
27
30
  try {
28
31
  await assert.rejects(
29
- runGeneratedScript(execFileAsync, targetDir, "test"),
32
+ runGeneratedExecutable(execFileAsync, targetDir, "vitest", [
33
+ "run",
34
+ "src",
35
+ "--passWithNoTests",
36
+ "--reporter=default",
37
+ "--reporter=./scripts/toolcraft-vitest-runtime-evidence-reporter.mjs",
38
+ ]),
30
39
  (error) => {
31
40
  const output = `${String(error.stdout)}\n${String(error.stderr)}`;
32
41
  assert.match(
33
- output.slice(-12_000),
42
+ output,
34
43
  /Toolcraft automated runtime coverage failed:[\s\S]*must not use expected-failure mode/u,
35
44
  );
36
- assert.match(output, /TOOLCRAFT_GENERATED_SCRIPT_TEST_EXECUTED/u);
37
45
  return true;
38
46
  },
39
47
  );
@@ -64,6 +64,20 @@ describe("generateToolcraft", () => {
64
64
  );
65
65
  assert.match(performanceSource, /workloadEnvelope:\s*\{\s*dimensions:\s*\[\]\s*\}/u);
66
66
  assert.doesNotMatch(performanceSource, /\bworkloadTargets\s*:/u);
67
+
68
+ assert.ok(
69
+ await fs.stat(
70
+ path.join(
71
+ targetDir,
72
+ "src/toolcraft/runtime/schema/canvas-render-scale.ts",
73
+ ),
74
+ ),
75
+ );
76
+ const gitignoreSource = await fs.readFile(
77
+ path.join(targetDir, ".gitignore"),
78
+ "utf8",
79
+ );
80
+ assert.match(gitignoreSource, /^\.playwright-mcp$/mu);
67
81
  });
68
82
 
69
83
  it("tests, typechecks, and builds a non-neutral generated product in isolation", async () => {
@@ -216,10 +216,10 @@ describe("Toolcraft template component contracts: choices and actions", () => {
216
216
  "Do not use panelActions for resetting controls; the controls panel header owns Reset controls.",
217
217
  );
218
218
  expect(contract.aiUsageRules).toContain(
219
- "Handle product-specific panelActions through ToolcraftApp onPanelAction.",
219
+ "Handle product-specific non-export panelActions through ToolcraftApp onPanelAction. Typed export-image and export-video actions are runtime-owned and consume ToolcraftAppComposition.exportRenderer.",
220
220
  );
221
221
  expect(contract.aiUsageRules).toContain(
222
- "Async product actions such as Export, Download, Copy, Generate, or Apply must return the real Promise from onPanelAction and report progress through the onPanelAction reportProgress callback.",
222
+ "Async non-export product actions such as Download, Copy, Generate, or Apply must return the real Promise from onPanelAction and report progress through the onPanelAction reportProgress callback.",
223
223
  );
224
224
  expect(contract.aiUsageRules).toContain(
225
225
  "The sticky footer top accent indicator is determinate when reportProgress receives 0..1 values and falls back to pending state only when progress is unavailable.",
@@ -249,7 +249,7 @@ describe("Toolcraft template component contracts: choices and actions", () => {
249
249
  "Image Export format and resolution render as one compact two-column inline Select pair, matching the Video Export settings structure.",
250
250
  );
251
251
  expect(contract.aiUsageRules).toContain(
252
- "Image Export resolution controls the actual exported image long edge: 2K = 2048px, 4K = 4096px, 8K = 8192px. Pass the selected runtime value to createToolcraftPngExportCanvas resolution and prove decoded image width/height in browser acceptance.",
252
+ "Image Export resolution controls the actual exported image long edge: 2K = 2048px, 4K = 4096px, 8K = 8192px. Runtime resolves the selected value and protected browser acceptance proves decoded image width and height.",
253
253
  );
254
254
  expect(contract.aiUsageRules).toContain(
255
255
  "Apps that deliver animation include Export Video as the primary footer action and Export PNG as a secondary footer action; timeline playback alone does not invent video delivery.",
@@ -285,16 +285,16 @@ describe("Toolcraft template component contracts: choices and actions", () => {
285
285
  'Baseline browser video formats are "mp4" and "webm"; MOV or ProRes require an explicit custom encoder/transcoder and dedicated acceptance plus performance coverage.',
286
286
  );
287
287
  expect(contract.aiUsageRules).toContain(
288
- "Video export code must choose the actual MIME/container through MediaRecorder.isTypeSupported or an equivalent encoder capability check, then fall back safely.",
288
+ "Runtime video export chooses the actual MIME, container, and codec through the timestamped Mediabunny encoder capability check, then returns the real supported format or a typed visible failure.",
289
289
  );
290
290
  expect(contract.aiUsageRules).toContain(
291
291
  "Video export must use getToolcraftVideoExportSize for current and 4K dimensions. Current video export uses the current canvas/output size with even encoder-safe rounding; 4K video fits inside an encoder-safe 3840x2160 box, preserves canvas aspect ratio, and uses even pixel dimensions. Do not hand-roll 4096px long-edge video sizing.",
292
292
  );
293
293
  expect(contract.aiUsageRules).toContain(
294
- "Video export must set recording canvas dimensions before captureStream, MediaRecorder, VideoEncoder, or equivalent encoder setup, and must reject recorder/encoder errors instead of returning corrupt blobs.",
294
+ "Runtime video export allocates the selected recording canvas dimensions before timestamped encoder setup and rejects renderer, encoder, muxer, and output-limit errors instead of returning corrupt blobs.",
295
295
  );
296
296
  expect(contract.aiUsageRules).toContain(
297
- "Offline video export duration must be encoded from runtime timeline timestamps. Do not rely on canvas.captureStream plus MediaRecorder wall-clock recording time as the only duration mechanism for rendered-frame export.",
297
+ "Offline video export duration is encoded from the fixed runtime 30 FPS timeline schedule. Product code must not use canvas.captureStream, MediaRecorder, or wall-clock time as a fallback.",
298
298
  );
299
299
  expect(contract.aiUsageRules).toContain(
300
300
  'Video resolution must control exported dimensions. Use "current" output size by default; "4K" is an export resolution target, not a hardcoded 3840x2160 canvas lock.',
@@ -309,13 +309,16 @@ describe("Toolcraft template component contracts: choices and actions", () => {
309
309
  'Product-output apps declare the standard background pair in an authored "Background" source section. Runtime removes that visible section and places Background plus Infinity canvas, then Background color, in Setup; Timeline is the final Setup control.',
310
310
  );
311
311
  expect(contract.aiUsageRules).toContain(
312
- "Product-output apps pass the includeBackground runtime value to createToolcraftPngExportCanvas for PNG alpha and call shouldIncludeToolcraftPreviewBackground(state) for bounded live preview background. In Infinity mode CanvasShell owns the selected full-viewport background color, and Background off restores finite mode and disables Infinity.",
312
+ "Product-output apps call shouldIncludeToolcraftPreviewBackground(state) for bounded live preview background. Runtime artifact export owns Background semantics: PNG may be transparent, JPEG and video remain opaque, Infinity uses the full-viewport color, and Background off restores finite mode and disables Infinity.",
313
313
  );
314
314
  expect(contract.aiUsageRules).toContain(
315
- "PNG export must use createToolcraftPngExportCanvas so background transparency and selected image dimensions or retina fallback are applied consistently; turning Background off makes preview product background and PNG alpha transparent without hiding the Toolcraft canvas backing or video background.",
315
+ "ToolcraftAppComposition.exportRenderer draws one deterministic product frame in scene coordinates for both image and video. Runtime owns canvas allocation, background, runtime media/model compositing, selected dimensions, encoding, download, progress, and typed failures.",
316
316
  );
317
317
  expect(contract.aiUsageRules).toContain(
318
- "Video export must keep product background and use getToolcraftVideoExportSize for current/4K output dimensions.",
318
+ "Product modules must not encode or download export canvases directly and must not instantiate MediaRecorder or VideoEncoder; the generated-source boundary rejects those duplicate export paths.",
319
+ );
320
+ expect(contract.aiUsageRules).toContain(
321
+ "Runtime video export keeps the selected background and uses getToolcraftVideoExportSize for current/4K output dimensions.",
319
322
  );
320
323
  expect(contract.aiUsageRules).toContain(
321
324
  "Copy PNG can be a secondary action when clipboard output is useful, but copy does not replace export.",
@@ -319,8 +319,8 @@ export const TOOLCRAFT_CHOICE_COMPONENT_CONTRACTS = {
319
319
  aiUsageRules: [
320
320
  "Use panelActions only for sticky footer product actions such as Generate, Export, Copy, or Download.",
321
321
  "Do not use panelActions for resetting controls; the controls panel header owns Reset controls.",
322
- "Handle product-specific panelActions through ToolcraftApp onPanelAction.",
323
- "Async product actions such as Export, Download, Copy, Generate, or Apply must return the real Promise from onPanelAction and report progress through the onPanelAction reportProgress callback.",
322
+ "Handle product-specific non-export panelActions through ToolcraftApp onPanelAction. Typed export-image and export-video actions are runtime-owned and consume ToolcraftAppComposition.exportRenderer.",
323
+ "Async non-export product actions such as Download, Copy, Generate, or Apply must return the real Promise from onPanelAction and report progress through the onPanelAction reportProgress callback.",
324
324
  "The sticky footer top accent indicator is determinate when reportProgress receives 0..1 values and falls back to pending state only when progress is unavailable.",
325
325
  "defineToolcraft hoists panelActions into the controls panel sticky footer automatically.",
326
326
  "Product-output apps must always include export in panelActions.",
@@ -330,7 +330,7 @@ export const TOOLCRAFT_CHOICE_COMPONENT_CONTRACTS = {
330
330
  'The Image Export section must include "export.image.format" as a Select control with PNG and JPG choices, defaulting to "png".',
331
331
  'The Image Export section must include "export.image.resolution" as a Select control with 2K, 4K, and 8K choices, defaulting to "4k".',
332
332
  "Image Export format and resolution render as one compact two-column inline Select pair, matching the Video Export settings structure.",
333
- "Image Export resolution controls the actual exported image long edge: 2K = 2048px, 4K = 4096px, 8K = 8192px. Pass the selected runtime value to createToolcraftPngExportCanvas resolution and prove decoded image width/height in browser acceptance.",
333
+ "Image Export resolution controls the actual exported image long edge: 2K = 2048px, 4K = 4096px, 8K = 8192px. Runtime resolves the selected value and protected browser acceptance proves decoded image width and height.",
334
334
  "Apps that deliver animation include Export Video as the primary footer action and Export PNG as a secondary footer action; timeline playback alone does not invent video delivery.",
335
335
  "Any app with Export Video must enable the top Toolcraft timeline; video duration, loop, and rendered timestamps come from runtime timeline state.",
336
336
  'Apps with Export Video must expose a separate "Video Export" controls section.',
@@ -342,17 +342,18 @@ export const TOOLCRAFT_CHOICE_COMPONENT_CONTRACTS = {
342
342
  'Video Export resolution defaults to "current"; keep "4k" available as the high-resolution alternate.',
343
343
  "Video Export format and resolution are a compact semantic pair and should use a two-column inline layout by default; use stacked rows only when labels or selected values do not fit without clipping.",
344
344
  'Baseline browser video formats are "mp4" and "webm"; MOV or ProRes require an explicit custom encoder/transcoder and dedicated acceptance plus performance coverage.',
345
- "Video export code must choose the actual MIME/container through MediaRecorder.isTypeSupported or an equivalent encoder capability check, then fall back safely.",
345
+ "Runtime video export chooses the actual MIME, container, and codec through the timestamped Mediabunny encoder capability check, then returns the real supported format or a typed visible failure.",
346
346
  "Video export must use getToolcraftVideoExportSize for current and 4K dimensions. Current video export uses the current canvas/output size with even encoder-safe rounding; 4K video fits inside an encoder-safe 3840x2160 box, preserves canvas aspect ratio, and uses even pixel dimensions. Do not hand-roll 4096px long-edge video sizing.",
347
- "Video export must set recording canvas dimensions before captureStream, MediaRecorder, VideoEncoder, or equivalent encoder setup, and must reject recorder/encoder errors instead of returning corrupt blobs.",
348
- "Offline video export duration must be encoded from runtime timeline timestamps. Do not rely on canvas.captureStream plus MediaRecorder wall-clock recording time as the only duration mechanism for rendered-frame export.",
347
+ "Runtime video export allocates the selected recording canvas dimensions before timestamped encoder setup and rejects renderer, encoder, muxer, and output-limit errors instead of returning corrupt blobs.",
348
+ "Offline video export duration is encoded from the fixed runtime 30 FPS timeline schedule. Product code must not use canvas.captureStream, MediaRecorder, or wall-clock time as a fallback.",
349
349
  'Video resolution must control exported dimensions. Use "current" output size by default; "4K" is an export resolution target, not a hardcoded 3840x2160 canvas lock.',
350
350
  "Video export browser coverage must load the exported blob metadata and prove video.duration matches the edited runtime timeline duration; blobSize/blobType checks alone are not enough.",
351
351
  "Video export must report frame-based progress through reportProgress during render/encode steps. PNG export should report phase progress for render, blob, and handoff when those phases are asynchronous.",
352
352
  'Product-output apps declare the standard background pair in an authored "Background" source section. Runtime removes that visible section and places Background plus Infinity canvas, then Background color, in Setup; Timeline is the final Setup control.',
353
- "Product-output apps pass the includeBackground runtime value to createToolcraftPngExportCanvas for PNG alpha and call shouldIncludeToolcraftPreviewBackground(state) for bounded live preview background. In Infinity mode CanvasShell owns the selected full-viewport background color, and Background off restores finite mode and disables Infinity.",
354
- "PNG export must use createToolcraftPngExportCanvas so background transparency and selected image dimensions or retina fallback are applied consistently; turning Background off makes preview product background and PNG alpha transparent without hiding the Toolcraft canvas backing or video background.",
355
- "Video export must keep product background and use getToolcraftVideoExportSize for current/4K output dimensions.",
353
+ "Product-output apps call shouldIncludeToolcraftPreviewBackground(state) for bounded live preview background. Runtime artifact export owns Background semantics: PNG may be transparent, JPEG and video remain opaque, Infinity uses the full-viewport color, and Background off restores finite mode and disables Infinity.",
354
+ "ToolcraftAppComposition.exportRenderer draws one deterministic product frame in scene coordinates for both image and video. Runtime owns canvas allocation, background, runtime media/model compositing, selected dimensions, encoding, download, progress, and typed failures.",
355
+ "Product modules must not encode or download export canvases directly and must not instantiate MediaRecorder or VideoEncoder; the generated-source boundary rejects those duplicate export paths.",
356
+ "Runtime video export keeps the selected background and uses getToolcraftVideoExportSize for current/4K output dimensions.",
356
357
  "Copy PNG can be a secondary action when clipboard output is useful, but copy does not replace export.",
357
358
  "Add Copy PNG as a secondary action only when the prompt/reference includes clipboard output or the product clearly benefits from paste/share workflows.",
358
359
  "Footer actions must be one compact horizontal group; do not split them into stacked full-width sections.",
@@ -82,10 +82,22 @@ describe("Toolcraft template component contracts: runtime and composition", () =
82
82
  );
83
83
  expect(rules).toContain("performance-iteration");
84
84
  expect(rules).toContain(
85
- "one exact authority-selected targeted performance iteration",
85
+ "Only a localized complaint or a post-clarification targeted choice creates performance-iteration intent",
86
86
  );
87
87
  expect(rules).toContain(
88
- "Complaint wording and repetition never select the complete performance matrix",
88
+ "Classifier output establishes complaint authority only and never path localization",
89
+ );
90
+ expect(rules).toContain(
91
+ "Regardless of whether the classifier returned high-confidence performance-iteration or needs-agent-judgment, unresolved localization creates neither performance-iteration intent nor canonical path authority",
92
+ );
93
+ expect(rules).toContain(
94
+ "repetition alone never expands scope or selects the complete performance matrix",
95
+ );
96
+ expect(rules).not.toContain(
97
+ "One complaint maps to one exact authority-selected targeted performance iteration",
98
+ );
99
+ expect(rules).not.toContain(
100
+ "Direct and repeated performance complaints each start one bounded targeted iteration",
89
101
  );
90
102
  expect(rules).toContain(
91
103
  "After two consecutive compatible protected performance iterations, the agent must offer a slower complete audit",
@@ -135,6 +147,9 @@ describe("Toolcraft template component contracts: runtime and composition", () =
135
147
  expect(rules).toContain(
136
148
  TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY.renderScaleFidelity,
137
149
  );
150
+ expect(rules).toContain(
151
+ TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY.complaintRouting,
152
+ );
138
153
  expect(contract.aiUsageRules).toContain(
139
154
  "Every export performance scenario must declare the exact panelActions actionValue, visible controlLabel, and completionEvidence it exercises; selectors, unrelated export actions, and injectable completion callbacks are not output evidence. The named browser scenario must resolve to test or it imported from @playwright/test, be statically registered at module scope or inside an executable test.describe, test.describe.serial, or test.describe.parallel suite, and directly await the matching unshadowed protected output-action helper in its root callback block without focus, skip, condition, or nesting; local test runners, uncalled or conditional test declarations, skipped/fixme suites, and runtime skip/fixme/fail annotations are invalid, and generated integrity protects the focused-test Playwright config.",
140
155
  );
@@ -62,7 +62,7 @@ describe("Toolcraft template component contracts: runtime and composition", () =
62
62
  'Any product app with Export Video must enable the top Toolcraft timeline: use panels.timeline mode "playback" for product animation transport, or mode "keyframes" when exported animation is driven by keyframes.',
63
63
  );
64
64
  expect(TOOLCRAFT_COMPONENT_CONTRACTS.timelinePanel.aiUsageRules).toContain(
65
- "Video export renderers must render deterministic frames from runtime timeline timestamps and duration; do not treat autonomous wall-clock time or captureStream recording time as the source of product duration.",
65
+ "Video export frames are rendered deterministically from the runtime-owned 30 FPS timeline schedule; product code must not use autonomous wall-clock time, captureStream, or MediaRecorder as the source or fallback for product duration.",
66
66
  );
67
67
  expect(TOOLCRAFT_COMPONENT_CONTRACTS.timelinePanel.aiUsageRules).toContain(
68
68
  "Playback renderers must consume runtime timeline state; pause freezes output, scrubbing renders a deterministic frame, and the full animation cycle maps to state.timeline.durationSeconds instead of a local fixed duration.",
@@ -58,7 +58,7 @@ describe("Toolcraft template component contracts: runtime and composition", () =
58
58
  "When the standard Background pair exists, disabling Background atomically restores finite mode and disables Infinity canvas; re-enabling Background restores switch availability without enabling Infinity automatically.",
59
59
  );
60
60
  expect(contract.aiUsageRules).toContain(
61
- "Infinite exports use canonical world-space scene frames: ToolcraftAppComposition.sceneBoundsProvider contributes product bounds, runtime image and model bounds are unioned once, hidden or suppressed content is excluded, PNG crops tightly, and video uses one time-range envelope.",
61
+ "Infinite exports use canonical world-space scene frames: ToolcraftAppComposition.sceneBoundsProvider contributes exact-state product bounds, runtime image and model bounds are unioned, hidden or suppressed content is excluded, PNG crops tightly, and runtime video unions every scheduled frame state into one envelope.",
62
62
  );
63
63
  expect(contract.aiUsageRules).toContain(
64
64
  "Do not let canvas.upload choose intrinsic-media by default. Upload without explicit sizing resolves to editable-output so source/background images do not own product output size.",
@@ -26,7 +26,7 @@ export const TOOLCRAFT_RUNTIME_COMPONENT_CONTRACTS = {
26
26
  "Infinity canvas removes finite artboard bounds and clipping, hides Aspect ratio, Canvas width, and Canvas height, and preserves the dormant finite canvas size for exact restoration when disabled.",
27
27
  "Infinity canvas suppresses the bounded product-rendered preview background so the dormant finite output does not appear as a second canvas; when the standard Background pair is enabled, CanvasShell fills the complete infinite viewport with the selected Background color.",
28
28
  "When the standard Background pair exists, disabling Background atomically restores finite mode and disables Infinity canvas; re-enabling Background restores switch availability without enabling Infinity automatically.",
29
- "Infinite exports use canonical world-space scene frames: ToolcraftAppComposition.sceneBoundsProvider contributes product bounds, runtime image and model bounds are unioned once, hidden or suppressed content is excluded, PNG crops tightly, and video uses one time-range envelope.",
29
+ "Infinite exports use canonical world-space scene frames: ToolcraftAppComposition.sceneBoundsProvider contributes exact-state product bounds, runtime image and model bounds are unioned, hidden or suppressed content is excluded, PNG crops tightly, and runtime video unions every scheduled frame state into one envelope.",
30
30
  "Do not let canvas.upload choose intrinsic-media by default. Upload without explicit sizing resolves to editable-output so source/background images do not own product output size.",
31
31
  "Use intrinsic-media only for true media-viewer or source-native apps where the natural uploaded/generated media size is the product output; record the reason and prove it with intrinsic-media-size acceptance.",
32
32
  "Use editable-output for generated, exportable, shader, poster, badge, wall, banner, thumbnail, procedural, reference-clone, and product-output apps so users always see Aspect ratio, Canvas width, and Canvas height.",
@@ -104,6 +104,7 @@ export const TOOLCRAFT_RUNTIME_COMPONENT_CONTRACTS = {
104
104
  runtimeSetupModeRowRule,
105
105
  runtimeSetupModeHelpRule,
106
106
  "Keep sticky footer panelActions for product delivery actions only, such as Export PNG, Export Video, Copy, Generate, Apply, or Download.",
107
+ "Typed Export PNG and Export Video actions are runtime-owned and consume one ToolcraftAppComposition.exportRenderer; use onPanelAction only for non-export product actions.",
107
108
  ],
108
109
  capabilities: ["settings-import-export"],
109
110
  commands: ["controls.setValue", "timeline.setCurrentTime", "timeline.setDuration"],
@@ -324,7 +325,7 @@ export const TOOLCRAFT_RUNTIME_COMPONENT_CONTRACTS = {
324
325
  "When the product has a known loop duration, declare it as panels.timeline.defaultDurationSeconds; the runtime timeline duration starts from that loop duration instead of an unrelated 8s default.",
325
326
  'Timeline animation intent must declare loopDuration with source "reference", "user-request", or "product-derived", plus seconds and evidence; runtime/template fallback 8s is not a valid source.',
326
327
  "panels.timeline.defaultDurationSeconds must match animationIntent.loopDuration.seconds for playback/keyframe animation, so the initial timeline UI shows the declared product loop instead of a generic default.",
327
- "Video export renderers must render deterministic frames from runtime timeline timestamps and duration; do not treat autonomous wall-clock time or captureStream recording time as the source of product duration.",
328
+ "Video export frames are rendered deterministically from the runtime-owned 30 FPS timeline schedule; product code must not use autonomous wall-clock time, captureStream, or MediaRecorder as the source or fallback for product duration.",
328
329
  "Playback renderers may compute an initial loop duration default during app initialization or reset, but must not watch state.timeline.durationSeconds and dispatch timeline.setDuration back to a computed local duration. User-edited timeline duration becomes the loop duration source of truth after initialization or reset.",
329
330
  "Playback renderers should use getToolcraftTimelineLoopTime or getToolcraftTimelineLoopProgress to derive product loop phase from state.timeline.currentTimeSeconds and state.timeline.durationSeconds; do not hand-roll wall-clock, fixed-duration, mirror, yoyo, ping-pong, or reverse phase math.",
330
331
  "Product animation loop means a seamless forward-only cycle by default: motion advances in one direction, first and last frames stitch without a visible jump, and mirror/yoyo/ping-pong/reverse loops require explicit user request.",
@@ -54,8 +54,8 @@ describe("Toolcraft template decision contract", () => {
54
54
 
55
55
  expect(rule?.level).toBe("invariant");
56
56
  expect(rule?.desiredBehavior).toMatch(/sceneBoundsProvider/i);
57
- expect(rule?.desiredBehavior).toMatch(/visible scene elements/i);
58
- expect(rule?.desiredBehavior).toMatch(/time-range envelope/i);
57
+ expect(rule?.desiredBehavior).toMatch(/one exact state/i);
58
+ expect(rule?.desiredBehavior).toMatch(/runtime-owned timestamp schedule/i);
59
59
  expect(rule?.desiredBehavior).toMatch(/finite canvas size/i);
60
60
  expect(rule?.enforcement).toContain("acceptance-validator");
61
61
  expect(rule?.enforcement).toContain("browser-helper");
@@ -228,10 +228,28 @@ describe("Toolcraft template decision contract", () => {
228
228
  expect(rule?.desiredBehavior).toMatch(/performance-iteration/i);
229
229
  expect(rule?.desiredBehavior).toMatch(/bounded targeted iteration/i);
230
230
  expect(rule?.desiredBehavior).toMatch(
231
- /one complaint maps to one exact authority-selected targeted performance iteration over canonical affected path IDs/i,
231
+ /only a localized complaint or a post-clarification targeted choice creates performance-iteration intent and one bounded iteration over exact canonical affected paths/iu,
232
232
  );
233
233
  expect(rule?.desiredBehavior).toMatch(
234
- /complaint wording and repetition never select the complete performance matrix/i,
234
+ /classifier output establishes complaint authority only and never path localization/iu,
235
+ );
236
+ expect(rule?.desiredBehavior).toMatch(
237
+ /regardless of whether the classifier returned high-confidence performance-iteration or needs-agent-judgment, unresolved localization creates neither performance-iteration intent nor canonical path authority/iu,
238
+ );
239
+ expect(rule?.desiredBehavior).not.toMatch(
240
+ /one complaint maps to one exact authority-selected targeted performance iteration/iu,
241
+ );
242
+ expect(rule?.desiredBehavior).not.toMatch(
243
+ /direct and repeated performance complaints each start one bounded targeted iteration/iu,
244
+ );
245
+ expect(rule?.desiredBehavior).toMatch(
246
+ /localized complaint[\s\S]*without asking the user/iu,
247
+ );
248
+ expect(rule?.desiredBehavior).toMatch(
249
+ /ambiguous or unresolved localization[\s\S]*one user-facing clarification[\s\S]*targeted diagnosis or a complete review/iu,
250
+ );
251
+ expect(rule?.desiredBehavior).toMatch(
252
+ /repetition alone never expands scope or selects the complete performance matrix/i,
235
253
  );
236
254
  expect(rule?.desiredBehavior).toMatch(
237
255
  /explicit natural-language request for the complete audit/i,
@@ -244,6 +262,9 @@ describe("Toolcraft template decision contract", () => {
244
262
  expect(rule?.desiredBehavior).toMatch(
245
263
  /renderScaleCoverage "selected-backing-pixels" for interaction and steady, plus playback when timeline is enabled/i,
246
264
  );
265
+ expect(rule?.desiredBehavior).toMatch(
266
+ /every measured path[\s\S]*devicePixelRatio × 2[\s\S]*each measured phase/iu,
267
+ );
247
268
  expect(rule?.desiredBehavior).toMatch(
248
269
  /never downsample[\s\S]*clamp the selected render scale to pass a performance budget/i,
249
270
  );
@@ -58,7 +58,7 @@ export const TOOLCRAFT_DECISION_CONTRACT = [
58
58
  area: "runtime-shell",
59
59
  currentConstraint: "Apps must assemble through defineToolcraft and ToolcraftApp.",
60
60
  desiredBehavior:
61
- "Generated apps use the Toolcraft runtime shell and keep product-specific rendering inside supported extension points: schema controls, canvasContent product output, controlRenderers for true custom controls, ToolcraftApp onPanelAction, and runtime commands. App-specific code must not import or render low-level runtime surfaces or built-in control components directly.",
61
+ "Generated apps use the Toolcraft runtime shell and keep product-specific rendering inside supported extension points: schema controls, canvasContent product output, controlRenderers for true custom controls, one shared ToolcraftAppComposition.exportRenderer for typed image/video actions, ToolcraftApp onPanelAction for non-export product actions, and runtime commands. App-specific code must not import or render low-level runtime surfaces or built-in control components directly, instantiate encoders, or own artifact download mechanics.",
62
62
  enforcement: [
63
63
  "cli-integrity-check",
64
64
  "acceptance-validator",
@@ -99,7 +99,7 @@ export const TOOLCRAFT_DECISION_CONTRACT = [
99
99
  currentConstraint:
100
100
  "Editable output can switch from a finite artboard to an unbounded workspace, but product renderers and export actions still need one canonical world-space frame contract.",
101
101
  desiredBehavior:
102
- "Editable-output apps expose one runtime-owned Infinity canvas mode. Enabling it removes finite artboard clipping and size controls while preserving the dormant finite canvas size for exact restoration. When the standard Background pair exists, its selected color fills the complete infinite viewport and Background off atomically resolves finite mode and disables Infinity. Runtime image and model assets retain explicit world-space frames. ToolcraftAppComposition.sceneBoundsProvider supplies product-renderer bounds through one direct composition boundary; image export crops to the union of visible scene elements and video export uses one provider time-range envelope for all rendered frames. Hidden layers, suppressed default consumers, and editor-only UI do not expand output bounds. Finite mode continues to export the full finite canvas size, while empty, unavailable, and unsafe oversized infinite exports return typed visible failures.",
102
+ "Editable-output apps expose one runtime-owned Infinity canvas mode. Enabling it removes finite artboard clipping and size controls while preserving the dormant finite canvas size for exact restoration. When the standard Background pair exists, its selected color fills the complete infinite viewport and Background off atomically resolves finite mode and disables Infinity. Runtime image and model assets retain explicit world-space frames. ToolcraftAppComposition.sceneBoundsProvider supplies product-renderer bounds for one exact state through one direct composition boundary; image export resolves the current frame and video export unions every state from the runtime-owned timestamp schedule. Hidden layers, suppressed default consumers, and editor-only UI do not expand output bounds. Finite mode continues to export the full finite canvas size, while empty, unavailable, and unsafe oversized infinite exports return typed visible failures.",
103
103
  enforcement: [
104
104
  "acceptance-validator",
105
105
  "browser-helper",
@@ -217,7 +217,7 @@ export const TOOLCRAFT_DECISION_CONTRACT = [
217
217
  currentConstraint:
218
218
  "Product-output apps expose final output delivery through sticky footer panelActions.",
219
219
  desiredBehavior:
220
- 'Product apps include Export PNG plus an "Image Export" section for format and 2K/4K/8K resolution. Apps whose requested delivery includes animation also include Export Video plus "Video Export" settings; a playback or keyframe timeline may exist for interactive preview without inventing video delivery. Copy can be secondary, but it does not replace export. Product apps declare the standard background pair and runtime places it in Setup: Background beside Infinity canvas, Color below, and Timeline last. Standard helpers own runtime PNG transparency, live preview product-background visibility, infinite viewport color, the Background-to-Infinity finite fallback, and selected image dimensions or retina fallback, while video keeps the background.',
220
+ 'Product apps include Export PNG plus an "Image Export" section for format and 2K/4K/8K resolution. Apps whose requested delivery includes animation also include Export Video plus "Video Export" settings; a playback or keyframe timeline may exist for interactive preview without inventing video delivery. Copy can be secondary, but it does not replace export. Product apps declare the standard background pair and runtime places it in Setup: Background beside Infinity canvas, Color below, and Timeline last. One shared product exportRenderer draws deterministic scene-coordinate frames; runtime owns settings, scene crop, PNG/JPEG/video background semantics, visible runtime media/model composition, exact timestamped encoding, download, progress, and typed failures.',
221
221
  enforcement: ["acceptance-validator", "performance-validator", "browser-helper", "starter-agents"],
222
222
  id: "output-export-required",
223
223
  level: "invariant",
@@ -26,6 +26,8 @@ describe("Toolcraft canonical performance verification policy", () => {
26
26
  expect(TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY).toEqual({
27
27
  agentBrowser:
28
28
  "Agent-controlled browser checks are limited to diagnosis and targeted visual investigation; they do not mint durable performance baselines or receipts.",
29
+ complaintRouting:
30
+ "Performance authority and path localization are separate decisions. Classifier output establishes complaint authority only and never path localization. A localized complaint lets the agent select canonical affected paths and run one targeted iteration without asking the user. An ambiguous or unresolved localization requires one user-facing clarification naming visible operations and offering targeted diagnosis or a complete review; never ask the user for internal path ids. Regardless of whether the classifier returned high-confidence performance-iteration or needs-agent-judgment, unresolved localization creates neither performance-iteration intent nor canonical path authority. A broad or honestly unlocalizable problem may justify recommending the complete review immediately, but only the user's explicit request or acceptance authorizes it. A direct request for a complete review runs the full audit without another clarification.",
29
31
  deliveryBatch:
30
32
  "Classify and verify one coherent user-visible delivery batch instead of treating each internal implementation pass or steering correction as a separate aggregate verification boundary.",
31
33
  deliveryCommand:
@@ -37,13 +39,13 @@ describe("Toolcraft canonical performance verification policy", () => {
37
39
  fullAuditDiscovery:
38
40
  "The complete performance matrix remains outside conversational delivery. Complaints, repetition, tier, filename, and touched subsystem never launch it automatically. After two consecutive compatible protected performance iterations, the agent must offer a slower complete audit if the user remains unsatisfied; a demonstrably broad or unlocalizable cross-system problem may justify the same offer earlier. An explicit natural-language request for the complete audit, or explicit acceptance of the agent's offer, authorizes the agent acting as operator to run pnpm verify:perf; the user does not need to know the command name. After the audit, repair and rerun failed paths with focused checks, then run the complete matrix only once at the requested certification boundary.",
39
41
  performanceIterationDelivery:
40
- "The runtime request classifier is a tri-state guard, not a replacement for AI semantic judgment: high-confidence runtime complaints, responsiveness optimization, or excessive CPU, GPU, memory, or resource use classify as performance-iteration; high-confidence product motion, speed, freeze, terminology, or locally negated complaint commands classify as ordinary-product-work; ambiguous or unrecognized wording classifies as needs-agent-judgment and the AI decides from the actual user request. Ordinary work is rejected only for a high-confidence performance iteration. Every performance-iteration worklog intent quotes a nontrivial exact raw substring of Request; whitespace and Unicode code units must match before normalized tri-state classification. Invented, whitespace-collapsed, NFKC-equivalent, or mismatched evidence is rejected; high-confidence ordinary evidence is rejected; exact high-confidence performance-iteration or needs-agent-judgment evidence is accepted under agent ownership. Each performance iteration requires an exact reachable development fixture and fails with a configuration error instead of falling back to maximum. One complaint maps to one exact authority-selected targeted performance iteration over canonical affected path IDs. Direct and repeated performance complaints each start one bounded targeted iteration over affected paths. Complaint wording and repetition never select the complete performance matrix, create or refresh a durable baseline, or grant full-performance certification authority.",
42
+ "The runtime request classifier is a tri-state guard, not a replacement for AI semantic judgment: high-confidence runtime complaints, responsiveness optimization, or excessive CPU, GPU, memory, or resource use classify as performance-iteration; high-confidence product motion, speed, freeze, terminology, or locally negated complaint commands classify as ordinary-product-work; ambiguous or unrecognized wording classifies as needs-agent-judgment and the AI decides from the actual user request. Ordinary work is rejected only for a high-confidence performance iteration. Every performance-iteration worklog intent quotes a nontrivial exact raw substring of Request; whitespace and Unicode code units must match before normalized tri-state classification. Invented, whitespace-collapsed, NFKC-equivalent, or mismatched evidence is rejected; high-confidence ordinary evidence is rejected; exact high-confidence performance-iteration evidence, or needs-agent-judgment evidence after semantic resolution, is accepted under agent ownership. Classifier output establishes complaint authority only and never path localization. Each performance iteration requires an exact reachable development fixture and fails with a configuration error instead of falling back to maximum. Only a localized complaint or a post-clarification targeted choice creates performance-iteration intent and one bounded iteration over exact canonical affected paths. Regardless of whether the classifier returned high-confidence performance-iteration or needs-agent-judgment, unresolved localization creates neither performance-iteration intent nor canonical path authority. Each repeated localized request may create one new bounded targeted iteration over its affected paths; repetition alone never expands scope or selects the complete performance matrix, creates or refreshes a durable baseline, or grants full-performance certification authority.",
41
43
  functionalInitialDelivery:
42
44
  'A functional delivery plan with basis "initial" runs complete functional proof and no measured performance. It preserves any independent full-performance baseline and cannot claim targeted or full performance evidence.',
43
45
  functionalTargetedDelivery:
44
46
  'A functional delivery plan with basis "changed" runs exact affected ownership-derived functional proof and no measured performance. Functional delivery cannot silently invoke targeted performance, the full performance matrix, or create or refresh a performance baseline.',
45
47
  renderScaleFidelity:
46
- 'canvas.renderScale is visible functional fidelity. Raster products declare typed renderScaleCoverage "selected-backing-pixels" for interaction and steady, plus playback when timeline is enabled, and prove real canvas backing pixels in every declared state. Never downsample, stretch a lower-resolution backing canvas, blur output, or clamp the selected render scale to pass a performance budget.',
48
+ 'canvas.renderScale is visible functional fidelity. Raster products declare typed renderScaleCoverage "selected-backing-pixels" for interaction and steady, plus playback when timeline is enabled, and prove real canvas backing pixels in every declared state. Every measured path in a render-scale-enabled raster product proves actual CSS × devicePixelRatio × 2 backing after each measured phase. Never downsample, stretch a lower-resolution backing canvas, blur output, or clamp the selected render scale to pass a performance budget.',
47
49
  });
48
50
  expect(TOOLCRAFT_PERFORMANCE_VERIFICATION_LIFECYCLE).toEqual({
49
51
  delivery: {
@@ -87,7 +89,7 @@ describe("Toolcraft canonical performance verification policy", () => {
87
89
  /ambiguous or unrecognized wording classifies as needs-agent-judgment/i,
88
90
  );
89
91
  expect(TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY_TEXT).toMatch(
90
- /high-confidence performance-iteration or needs-agent-judgment evidence is accepted under agent ownership/i,
92
+ /exact high-confidence performance-iteration evidence, or needs-agent-judgment evidence after semantic resolution, is accepted under agent ownership/i,
91
93
  );
92
94
  expect(TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY_TEXT).toMatch(
93
95
  /whitespace and Unicode code units must match/i,
@@ -96,13 +98,31 @@ describe("Toolcraft canonical performance verification policy", () => {
96
98
  /performance iteration requires an exact reachable development fixture/i,
97
99
  );
98
100
  expect(TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY_TEXT).toMatch(
99
- /direct and repeated performance complaints each start one bounded targeted iteration/i,
101
+ /only a localized complaint or a post-clarification targeted choice creates performance-iteration intent and one bounded iteration over exact canonical affected paths/iu,
100
102
  );
101
103
  expect(TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY_TEXT).toMatch(
102
- /one complaint maps to one exact authority-selected targeted performance iteration over canonical affected path IDs/i,
104
+ /regardless of whether the classifier returned high-confidence performance-iteration or needs-agent-judgment, unresolved localization creates neither performance-iteration intent nor canonical path authority/iu,
103
105
  );
104
106
  expect(TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY_TEXT).toMatch(
105
- /complaint wording and repetition never select the complete performance matrix/i,
107
+ /each repeated localized request may create one new bounded targeted iteration/iu,
108
+ );
109
+ expect(TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY_TEXT).not.toMatch(
110
+ /one complaint maps to one exact authority-selected targeted performance iteration/iu,
111
+ );
112
+ expect(TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY_TEXT).not.toMatch(
113
+ /direct and repeated performance complaints each start one bounded targeted iteration/iu,
114
+ );
115
+ expect(TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY_TEXT).toMatch(
116
+ /localized complaint[\s\S]*without asking the user/iu,
117
+ );
118
+ expect(TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY_TEXT).toMatch(
119
+ /ambiguous or unresolved localization[\s\S]*one user-facing clarification[\s\S]*targeted diagnosis or a complete review/iu,
120
+ );
121
+ expect(TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY_TEXT).toMatch(
122
+ /direct request for a complete review[\s\S]*without another clarification/iu,
123
+ );
124
+ expect(TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY_TEXT).toMatch(
125
+ /repetition alone never expands scope or selects the complete performance matrix/i,
106
126
  );
107
127
  expect(TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY_TEXT).toMatch(
108
128
  /two consecutive compatible protected performance iterations[\s\S]*must offer/i,
@@ -122,8 +142,41 @@ describe("Toolcraft canonical performance verification policy", () => {
122
142
  expect(TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY_TEXT).toMatch(
123
143
  /typed renderScaleCoverage "selected-backing-pixels" for interaction and steady, plus playback when timeline is enabled/i,
124
144
  );
145
+ expect(TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY_TEXT).toMatch(
146
+ /every measured path[\s\S]*devicePixelRatio × 2[\s\S]*each measured phase/iu,
147
+ );
125
148
  expect(TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY_TEXT).toMatch(
126
149
  /never downsample[\s\S]*clamp the selected render scale to pass a performance budget/i,
127
150
  );
128
151
  });
152
+
153
+ it.each([
154
+ {
155
+ axis: "high-confidence but unlocalized complaint",
156
+ expected:
157
+ /classifier output establishes complaint authority only and never path localization[\s\S]*regardless of whether the classifier returned high-confidence performance-iteration[\s\S]*unresolved localization creates neither performance-iteration intent nor canonical path authority/iu,
158
+ },
159
+ {
160
+ axis: "localized complaint",
161
+ expected:
162
+ /localized complaint[\s\S]*one targeted iteration without asking the user/iu,
163
+ },
164
+ {
165
+ axis: "needs-agent-judgment with unresolved localization",
166
+ expected:
167
+ /regardless of whether the classifier returned[\s\S]*needs-agent-judgment[\s\S]*unresolved localization creates neither performance-iteration intent nor canonical path authority/iu,
168
+ },
169
+ {
170
+ axis: "post-clarification targeted choice",
171
+ expected:
172
+ /post-clarification targeted choice creates performance-iteration intent and one bounded iteration over exact canonical affected paths/iu,
173
+ },
174
+ ])("routes $axis without coupling authority to localization", ({ expected }) => {
175
+ const canonicalRoutingPolicy = [
176
+ TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY.complaintRouting,
177
+ TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY.performanceIterationDelivery,
178
+ ].join(" ");
179
+
180
+ expect(canonicalRoutingPolicy).toMatch(expected);
181
+ });
129
182
  });
@@ -3,6 +3,8 @@ export * from "./performance-request-classifier";
3
3
  export const TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY = {
4
4
  agentBrowser:
5
5
  "Agent-controlled browser checks are limited to diagnosis and targeted visual investigation; they do not mint durable performance baselines or receipts.",
6
+ complaintRouting:
7
+ "Performance authority and path localization are separate decisions. Classifier output establishes complaint authority only and never path localization. A localized complaint lets the agent select canonical affected paths and run one targeted iteration without asking the user. An ambiguous or unresolved localization requires one user-facing clarification naming visible operations and offering targeted diagnosis or a complete review; never ask the user for internal path ids. Regardless of whether the classifier returned high-confidence performance-iteration or needs-agent-judgment, unresolved localization creates neither performance-iteration intent nor canonical path authority. A broad or honestly unlocalizable problem may justify recommending the complete review immediately, but only the user's explicit request or acceptance authorizes it. A direct request for a complete review runs the full audit without another clarification.",
6
8
  deliveryBatch:
7
9
  "Classify and verify one coherent user-visible delivery batch instead of treating each internal implementation pass or steering correction as a separate aggregate verification boundary.",
8
10
  deliveryCommand:
@@ -14,13 +16,13 @@ export const TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY = {
14
16
  fullAuditDiscovery:
15
17
  "The complete performance matrix remains outside conversational delivery. Complaints, repetition, tier, filename, and touched subsystem never launch it automatically. After two consecutive compatible protected performance iterations, the agent must offer a slower complete audit if the user remains unsatisfied; a demonstrably broad or unlocalizable cross-system problem may justify the same offer earlier. An explicit natural-language request for the complete audit, or explicit acceptance of the agent's offer, authorizes the agent acting as operator to run pnpm verify:perf; the user does not need to know the command name. After the audit, repair and rerun failed paths with focused checks, then run the complete matrix only once at the requested certification boundary.",
16
18
  performanceIterationDelivery:
17
- "The runtime request classifier is a tri-state guard, not a replacement for AI semantic judgment: high-confidence runtime complaints, responsiveness optimization, or excessive CPU, GPU, memory, or resource use classify as performance-iteration; high-confidence product motion, speed, freeze, terminology, or locally negated complaint commands classify as ordinary-product-work; ambiguous or unrecognized wording classifies as needs-agent-judgment and the AI decides from the actual user request. Ordinary work is rejected only for a high-confidence performance iteration. Every performance-iteration worklog intent quotes a nontrivial exact raw substring of Request; whitespace and Unicode code units must match before normalized tri-state classification. Invented, whitespace-collapsed, NFKC-equivalent, or mismatched evidence is rejected; high-confidence ordinary evidence is rejected; exact high-confidence performance-iteration or needs-agent-judgment evidence is accepted under agent ownership. Each performance iteration requires an exact reachable development fixture and fails with a configuration error instead of falling back to maximum. One complaint maps to one exact authority-selected targeted performance iteration over canonical affected path IDs. Direct and repeated performance complaints each start one bounded targeted iteration over affected paths. Complaint wording and repetition never select the complete performance matrix, create or refresh a durable baseline, or grant full-performance certification authority.",
19
+ "The runtime request classifier is a tri-state guard, not a replacement for AI semantic judgment: high-confidence runtime complaints, responsiveness optimization, or excessive CPU, GPU, memory, or resource use classify as performance-iteration; high-confidence product motion, speed, freeze, terminology, or locally negated complaint commands classify as ordinary-product-work; ambiguous or unrecognized wording classifies as needs-agent-judgment and the AI decides from the actual user request. Ordinary work is rejected only for a high-confidence performance iteration. Every performance-iteration worklog intent quotes a nontrivial exact raw substring of Request; whitespace and Unicode code units must match before normalized tri-state classification. Invented, whitespace-collapsed, NFKC-equivalent, or mismatched evidence is rejected; high-confidence ordinary evidence is rejected; exact high-confidence performance-iteration evidence, or needs-agent-judgment evidence after semantic resolution, is accepted under agent ownership. Classifier output establishes complaint authority only and never path localization. Each performance iteration requires an exact reachable development fixture and fails with a configuration error instead of falling back to maximum. Only a localized complaint or a post-clarification targeted choice creates performance-iteration intent and one bounded iteration over exact canonical affected paths. Regardless of whether the classifier returned high-confidence performance-iteration or needs-agent-judgment, unresolved localization creates neither performance-iteration intent nor canonical path authority. Each repeated localized request may create one new bounded targeted iteration over its affected paths; repetition alone never expands scope or selects the complete performance matrix, creates or refreshes a durable baseline, or grants full-performance certification authority.",
18
20
  functionalInitialDelivery:
19
21
  'A functional delivery plan with basis "initial" runs complete functional proof and no measured performance. It preserves any independent full-performance baseline and cannot claim targeted or full performance evidence.',
20
22
  functionalTargetedDelivery:
21
23
  'A functional delivery plan with basis "changed" runs exact affected ownership-derived functional proof and no measured performance. Functional delivery cannot silently invoke targeted performance, the full performance matrix, or create or refresh a performance baseline.',
22
24
  renderScaleFidelity:
23
- 'canvas.renderScale is visible functional fidelity. Raster products declare typed renderScaleCoverage "selected-backing-pixels" for interaction and steady, plus playback when timeline is enabled, and prove real canvas backing pixels in every declared state. Never downsample, stretch a lower-resolution backing canvas, blur output, or clamp the selected render scale to pass a performance budget.',
25
+ 'canvas.renderScale is visible functional fidelity. Raster products declare typed renderScaleCoverage "selected-backing-pixels" for interaction and steady, plus playback when timeline is enabled, and prove real canvas backing pixels in every declared state. Every measured path in a render-scale-enabled raster product proves actual CSS × devicePixelRatio × 2 backing after each measured phase. Never downsample, stretch a lower-resolution backing canvas, blur output, or clamp the selected render scale to pass a performance budget.',
24
26
  } as const;
25
27
 
26
28
  export const TOOLCRAFT_PERFORMANCE_VERIFICATION_LIFECYCLE = {
@@ -37,6 +39,7 @@ export const TOOLCRAFT_PERFORMANCE_VERIFICATION_LIFECYCLE = {
37
39
 
38
40
  export const TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY_TEXT = [
39
41
  TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY.agentBrowser,
42
+ TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY.complaintRouting,
40
43
  TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY.deliveryBatch,
41
44
  TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY.deliveryCommand,
42
45
  TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY.demandOnlyPerformance,