@pixel-point/toolcraft 0.0.16 → 0.0.18
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.
- package/package.json +1 -1
- package/src/generate-performance-iteration-execution.test.mjs +2 -2
- package/src/generate-test-demand-only-lifecycle.mjs +14 -3
- package/src/generate-test-dependency-sandbox.mjs +42 -5
- package/src/generate-test-doc-assertions.mjs +109 -69
- package/src/generate-test-doc-assertions.test.mjs +65 -0
- package/src/generate-test-doc-policy-assertions.mjs +92 -0
- package/src/generate-test-file-assertions.mjs +36 -118
- package/src/generate-test-output-assertions.mjs +95 -0
- package/src/generate-test-package-assertions.mjs +6 -0
- package/src/generate-test-performance-boundary-assertions.mjs +45 -0
- package/src/generate-test-product-fixture.mjs +1 -0
- package/src/generate-test-product-fixture.test.mjs +18 -0
- package/src/generate-test-product-iteration.mjs +1 -0
- package/src/generate-test-product-iteration.test.mjs +18 -0
- package/src/generate-test-runtime-boundary-assertions.mjs +158 -0
- package/src/generate-test-standalone-assertions.mjs +10 -0
- package/src/generate-test-standalone-delivery-stages.mjs +14 -6
- package/src/generate.test.mjs +14 -0
- package/templates/runtime/contracts/component-contracts.choices.test.ts +59 -12
- package/templates/runtime/contracts/component-contracts.choices.ts +58 -12
- package/templates/runtime/contracts/component-contracts.inputs.test.ts +6 -6
- package/templates/runtime/contracts/component-contracts.inputs.ts +6 -6
- package/templates/runtime/contracts/component-contracts.media-custom.test.ts +8 -2
- package/templates/runtime/contracts/component-contracts.media-custom.ts +8 -2
- package/templates/runtime/contracts/component-contracts.runtime-acceptance.test.ts +21 -6
- package/templates/runtime/contracts/component-contracts.runtime-labels.test.ts +7 -1
- package/templates/runtime/contracts/component-contracts.runtime-panels.test.ts +4 -1
- package/templates/runtime/contracts/component-contracts.runtime-shell.test.ts +4 -1
- package/templates/runtime/contracts/component-contracts.runtime.ts +15 -10
- package/templates/runtime/contracts/component-contracts.test.ts +2 -0
- package/templates/runtime/contracts/decision-contracts.test.ts +43 -4
- package/templates/runtime/contracts/decision-contracts.ts +10 -10
- package/templates/runtime/contracts/performance-verification-policy.test.ts +59 -6
- package/templates/runtime/contracts/performance-verification-policy.ts +5 -2
- package/templates/runtime/export/artifact-download.test.ts +71 -0
- package/templates/runtime/export/artifact-download.ts +80 -0
- package/templates/runtime/export/artifact-export-request.ts +23 -0
- package/templates/runtime/export/artifact-export-settings.test.ts +75 -0
- package/templates/runtime/export/artifact-export-settings.ts +96 -0
- package/templates/runtime/export/artifact-frame-renderer.test.ts +107 -0
- package/templates/runtime/export/artifact-frame-renderer.ts +96 -0
- package/templates/runtime/export/artifact-frame-state.test.ts +54 -0
- package/templates/runtime/export/artifact-frame-state.ts +44 -0
- package/templates/runtime/export/artifact-scene-frame.test.ts +84 -0
- package/templates/runtime/export/artifact-scene-frame.ts +118 -0
- package/templates/runtime/export/export-background.ts +46 -0
- package/templates/runtime/export/export-error.ts +43 -0
- package/templates/runtime/export/export.test.ts +49 -226
- package/templates/runtime/export/image-artifact-export.test.ts +111 -0
- package/templates/runtime/export/image-artifact-export.ts +145 -0
- package/templates/runtime/export/index.ts +44 -3
- package/templates/runtime/export/product-export-renderer.test.ts +77 -0
- package/templates/runtime/export/product-export-renderer.ts +63 -0
- package/templates/runtime/export/video-artifact-export.test.ts +166 -0
- package/templates/runtime/export/video-artifact-export.ts +164 -0
- package/templates/runtime/export/video-encoding-backend.ts +124 -0
- package/templates/runtime/export/video-encoding-policy.test.ts +68 -0
- package/templates/runtime/export/video-encoding-policy.ts +86 -0
- package/templates/runtime/export/video-frame-schedule.test.ts +58 -0
- package/templates/runtime/export/video-frame-schedule.ts +42 -0
- package/templates/runtime/index.ts +3 -0
- package/templates/runtime/model-import/model-import-limits.ts +15 -4
- package/templates/runtime/react/app-shell/runtime-public-api-runtime.test.tsx +291 -0
- package/templates/runtime/react/app-shell/runtime-public-api-test-support.ts +21 -0
- package/templates/runtime/react/app-shell/runtime-public-api.test.tsx +15 -304
- package/templates/runtime/react/app-shell/toolcraft-app.scene-export.test.tsx +41 -27
- package/templates/runtime/react/app-shell/toolcraft-app.tsx +39 -11
- package/templates/runtime/react/app-shell/toolcraft-source-asset-context.test.tsx +16 -57
- package/templates/runtime/react/app-shell/toolcraft-source-asset-context.tsx +75 -434
- package/templates/runtime/react/app-shell/toolcraft-source-asset-owner.test.ts +194 -0
- package/templates/runtime/react/app-shell/toolcraft-source-asset-owner.ts +227 -0
- package/templates/runtime/react/app-shell/toolcraft-source-asset-provider-ownership.test.tsx +243 -0
- package/templates/runtime/react/app-shell/toolcraft-source-asset-test-support.ts +51 -0
- package/templates/runtime/react/app-shell/toolcraft-unavailable-resource-proof.test.ts +138 -0
- package/templates/runtime/react/app-shell/toolcraft-unavailable-resource-proof.ts +378 -0
- package/templates/runtime/react/canvas/canvas-shell-rendering.test.tsx +76 -0
- package/templates/runtime/react/canvas/canvas-shell-test-utils.tsx +13 -1
- package/templates/runtime/react/canvas/canvas-shell.tsx +16 -1
- package/templates/runtime/react/canvas/product-scene-surface.test.tsx +195 -0
- package/templates/runtime/react/canvas/product-scene-surface.tsx +155 -0
- package/templates/runtime/react/canvas/runtime-scene-export.ts +1 -1
- package/templates/runtime/react/controls-panel/__tests__/control-conditions.test.ts +61 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.collection-actions.test.tsx +89 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.control-visibility.test.tsx +40 -19
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.footer-actions.test.tsx +7 -12
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.scene-export-actions.test.tsx +18 -84
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-collection.test.tsx +62 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-color-bank.test.tsx +67 -0
- package/templates/runtime/react/controls-panel/actions/controls-panel-actions.ts +43 -87
- package/templates/runtime/react/controls-panel/actions/export-action-runner.ts +68 -0
- package/templates/runtime/react/controls-panel/conditions/control-conditions.ts +32 -119
- package/templates/runtime/react/controls-panel/layout/controls-panel-control-group.tsx +5 -2
- package/templates/runtime/react/controls-panel/layout/controls-panel-layout.tsx +10 -8
- package/templates/runtime/react/controls-panel/layout/controls-panel-section.tsx +3 -3
- package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-item-fields.test.tsx +63 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-item-fields.tsx +138 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-items.tsx +104 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-renderer.tsx +115 -236
- package/templates/runtime/react/controls-panel/renderers/controls-panel-file-drop-item-controls.test.tsx +95 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-file-drop-item-controls.tsx +82 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-media-renderer.test.tsx +73 -1
- package/templates/runtime/react/controls-panel/renderers/controls-panel-media-renderer.tsx +50 -1
- package/templates/runtime/react/controls-panel/renderers/controls-panel-renderer-registry.test.ts +1 -1
- package/templates/runtime/react/controls-panel/renderers/controls-panel-renderer-registry.ts +2 -1
- package/templates/runtime/react/controls-panel/values/controls-panel-collection-values.ts +38 -6
- package/templates/runtime/react/controls-panel/values/controls-panel-value-labels.ts +1 -0
- package/templates/runtime/react/index.ts +4 -0
- package/templates/runtime/react/model-rendering/model-export.ts +1 -1
- package/templates/runtime/react/orientation-gizmo/orientation-gizmo-selection.ts +5 -5
- package/templates/runtime/react/orientation-gizmo/use-toolcraft-orientation-control-selection.ts +2 -2
- package/templates/runtime/react/panel-host/panel-host-runtime-placement.test.tsx +30 -0
- package/templates/runtime/react/panel-host/panel-host.tsx +4 -0
- package/templates/runtime/scene/scene-bounds.test.ts +23 -0
- package/templates/runtime/scene/scene-bounds.ts +32 -19
- package/templates/runtime/schema/app-capabilities.test.ts +4 -0
- package/templates/runtime/schema/canvas-render-scale.ts +62 -0
- package/templates/runtime/schema/collection-item-controls.ts +29 -0
- package/templates/runtime/schema/control-applicability.test.ts +127 -0
- package/templates/runtime/schema/control-applicability.ts +433 -0
- package/templates/runtime/schema/control-schema-normalization.ts +177 -11
- package/templates/runtime/schema/controls-panel-actions.ts +2 -2
- package/templates/runtime/schema/controls-panel-section-id.test.ts +1 -1
- package/templates/runtime/schema/controls-panel-section-layout.ts +14 -9
- package/templates/runtime/schema/controls-panel-section-roundtrip.test.ts +62 -3
- package/templates/runtime/schema/define-toolcraft.collection-actions-item-controls.test.ts +127 -0
- package/templates/runtime/schema/define-toolcraft.control-sections.test.ts +10 -4
- package/templates/runtime/schema/define-toolcraft.file-drop-item-controls.test.ts +98 -0
- package/templates/runtime/schema/define-toolcraft.file-drop-normalization.test.ts +27 -0
- package/templates/runtime/schema/define-toolcraft.segmented-control-fit.test.ts +20 -2
- package/templates/runtime/schema/define-toolcraft.setup-background.test.ts +1 -1
- package/templates/runtime/schema/define-toolcraft.setup-canvas.test.ts +16 -3
- package/templates/runtime/schema/define-toolcraft.setup-render-scale-timeline.test.ts +71 -3
- package/templates/runtime/schema/define-toolcraft.source-collection.test.ts +79 -0
- package/templates/runtime/schema/define-toolcraft.ts +1 -1
- package/templates/runtime/schema/runtime-setup-section.ts +24 -5
- package/templates/runtime/schema/schema-resolvers.ts +0 -56
- package/templates/runtime/schema/types.ts +72 -17
- package/templates/runtime/state/canvas-background-state.ts +6 -0
- package/templates/runtime/testing/performance-render-plan-integration.test.ts +64 -0
- package/templates/runtime/testing/performance-renderer-pipeline-validation.ts +18 -1
- package/templates/starter/AGENTS.md +18 -15
- package/templates/starter/NOTICE.md +6 -0
- package/templates/starter/docs/toolcraft/README.md +2 -1
- package/templates/starter/docs/toolcraft/acceptance-testing.md +23 -35
- package/templates/starter/docs/toolcraft/agent-worklog.md +18 -3
- package/templates/starter/docs/toolcraft/assembly-workflow.md +13 -5
- package/templates/starter/docs/toolcraft/component-rules.md +8 -6
- package/templates/starter/docs/toolcraft/core/control-selection.md +9 -3
- package/templates/starter/docs/toolcraft/core/layout.md +7 -7
- package/templates/starter/docs/toolcraft/core/media-upload.md +4 -2
- package/templates/starter/docs/toolcraft/core/performance.md +14 -3
- package/templates/starter/docs/toolcraft/core/runtime-boundary.md +16 -3
- package/templates/starter/docs/toolcraft/core/setup-export.md +49 -19
- package/templates/starter/docs/toolcraft/core/timeline-animation.md +4 -4
- package/templates/starter/docs/toolcraft/custom-controls.md +6 -4
- package/templates/starter/docs/toolcraft/decision-contract.md +3 -1
- package/templates/starter/docs/toolcraft/performance.md +20 -6
- package/templates/starter/docs/toolcraft/renderer-technique.md +5 -1
- package/templates/starter/docs/toolcraft/schema-reference.md +23 -25
- package/templates/starter/docs/toolcraft/workflow.md +7 -2
- package/templates/starter/e2e/app-browser-control-applicability-requirements.spec.ts +163 -0
- package/templates/starter/e2e/app-browser-control-coverage.spec.ts +33 -0
- package/templates/starter/e2e/app-browser-infinity-canvas-evidence.spec.ts +50 -3
- package/templates/starter/e2e/app-browser-orientation-evidence.spec.ts +174 -21
- package/templates/starter/e2e/app-browser-render-scale-evidence.spec.ts +60 -6
- package/templates/starter/e2e/app-browser-render-scale-requirements.spec.ts +77 -1
- package/templates/starter/e2e/app-browser-runtime-provenance.spec.ts +8 -0
- package/templates/starter/e2e/app-browser-runtime-reporter.spec.ts +35 -0
- package/templates/starter/e2e/app-browser-runtime-requirements.spec.ts +5 -34
- package/templates/starter/e2e/app-browser-semantic-evidence.spec.ts +61 -16
- package/templates/starter/e2e/app-browser-shell.spec.ts +13 -5
- package/templates/starter/e2e/app-performance-path-adapters.ts +8 -1
- package/templates/starter/e2e/app-performance.spec.ts +16 -9
- package/templates/starter/e2e/{browser-conditional-output-evidence-helpers.ts → browser-background-output-evidence.ts} +0 -68
- package/templates/starter/e2e/browser-control-applicability-evidence.ts +114 -0
- package/templates/starter/e2e/browser-infinity-canvas-evidence.ts +29 -341
- package/templates/starter/e2e/browser-infinity-canvas-unavailable-image-evidence.ts +370 -0
- package/templates/starter/e2e/browser-media-export-evidence.spec.ts +77 -0
- package/templates/starter/e2e/browser-media-export-evidence.ts +208 -0
- package/templates/starter/e2e/browser-orientation-gizmo-evidence-helpers.ts +4 -0
- package/templates/starter/e2e/browser-orientation-gizmo-live-preconditions.ts +86 -0
- package/templates/starter/e2e/browser-render-scale-evidence.ts +37 -29
- package/templates/starter/e2e/browser-runtime-applicability-requirements.ts +84 -0
- package/templates/starter/e2e/browser-runtime-evidence-reporter.ts +13 -3
- package/templates/starter/e2e/browser-runtime-evidence-requirements.ts +72 -35
- package/templates/starter/e2e/browser-semantic-evidence-test-helpers.ts +25 -0
- package/templates/starter/e2e/browser-standard-timeline-evidence.ts +106 -0
- package/templates/starter/e2e/decoded-pixel-observation.spec.ts +74 -0
- package/templates/starter/e2e/decoded-pixel-observation.ts +227 -0
- package/templates/starter/e2e/export-artifact-helpers.ts +206 -25
- package/templates/starter/e2e/image-artifact-inspection.spec.ts +41 -0
- package/templates/starter/e2e/image-artifact-inspection.ts +99 -0
- package/templates/starter/e2e/performance-canvas-helpers.ts +22 -21
- package/templates/starter/e2e/performance-canvas-quality-guard.spec.ts +312 -0
- package/templates/starter/e2e/performance-canvas-quality-guard.ts +196 -0
- package/templates/starter/e2e/performance-canvas-quality-observer.ts +351 -0
- package/templates/starter/e2e/performance-control-layout-helpers.ts +2 -2
- package/templates/starter/e2e/performance-path-adapter-contract.ts +4 -4
- package/templates/starter/e2e/performance-path-helpers.spec.ts +203 -70
- package/templates/starter/e2e/performance-path-helpers.ts +210 -91
- package/templates/starter/e2e/performance-pipeline-evidence-continuity.spec.ts +76 -0
- package/templates/starter/e2e/performance-pipeline-evidence-test-fixtures.ts +11 -2
- package/templates/starter/e2e/performance-pipeline-invariants.ts +47 -4
- package/templates/starter/e2e/performance-render-scale-runner.spec.ts +140 -38
- package/templates/starter/e2e/video-artifact-inspection.spec.ts +64 -0
- package/templates/starter/e2e/video-artifact-inspection.ts +281 -0
- package/templates/starter/gitignore +1 -0
- package/templates/starter/package.json +1 -0
- package/templates/starter/scripts/check-toolcraft-docs.mjs +17 -0
- package/templates/starter/scripts/toolcraft-contract-manifest.json +1 -0
- package/templates/starter/scripts/toolcraft-delivery-plan-authority.test.mjs +60 -0
- package/templates/starter/scripts/toolcraft-delivery-plan-errors.test.mjs +7 -2
- package/templates/starter/scripts/toolcraft-delivery-plan.mjs +7 -3
- package/templates/starter/scripts/toolcraft-product-boundary-ast.mjs +95 -103
- package/templates/starter/scripts/toolcraft-product-boundary-module-policy.mjs +101 -0
- package/templates/starter/scripts/toolcraft-product-boundary.mjs +12 -0
- package/templates/starter/scripts/toolcraft-product-boundary.test.mjs +0 -26
- package/templates/starter/scripts/toolcraft-product-control-bindings.mjs +182 -0
- package/templates/starter/scripts/toolcraft-product-control-boundary.mjs +146 -0
- package/templates/starter/scripts/toolcraft-product-control-boundary.test.mjs +186 -0
- package/templates/starter/scripts/toolcraft-product-evidence-boundary.test.mjs +85 -20
- package/templates/starter/scripts/toolcraft-product-evidence-import-policy.mjs +43 -0
- package/templates/starter/scripts/toolcraft-product-export-boundary.mjs +157 -0
- package/templates/starter/scripts/toolcraft-product-export-boundary.test.mjs +196 -0
- package/templates/starter/scripts/toolcraft-typescript-analysis.d.mts +73 -0
- package/templates/starter/scripts/toolcraft-typescript-source-evidence-structure.test.mjs +20 -0
- package/templates/starter/scripts/toolcraft-typescript-source-evidence.mjs +1 -0
- package/templates/starter/scripts/toolcraft-unavailable-resource-evidence-facade-test-helpers.mjs +318 -0
- package/templates/starter/scripts/toolcraft-unavailable-resource-evidence-facade.test.mjs +157 -206
- package/templates/starter/scripts/toolcraft-verification-inventory.mjs +1 -0
- package/templates/starter/scripts/toolcraft-verification-receipt.test.mjs +51 -0
- package/templates/starter/scripts/toolcraft-vite-env-activation.test.mjs +128 -59
- package/templates/starter/src/app/acceptance/artifact-export-intent.ts +130 -0
- package/templates/starter/src/app/acceptance/conditions.ts +1 -1
- package/templates/starter/src/app/acceptance/control-acceptance-context.ts +2 -2
- package/templates/starter/src/app/acceptance/control-acceptance-coverage.ts +6 -20
- package/templates/starter/src/app/acceptance/control-acceptance-kind-rules.ts +24 -5
- package/templates/starter/src/app/acceptance/control-acceptance-policy.ts +2 -13
- package/templates/starter/src/app/acceptance/control-applicability-cases.test.ts +321 -0
- package/templates/starter/src/app/acceptance/control-applicability-cases.ts +290 -0
- package/templates/starter/src/app/acceptance/control-applicability.ts +332 -0
- package/templates/starter/src/app/acceptance/control-layout-dependency-rules.ts +20 -9
- package/templates/starter/src/app/acceptance/control-layout-entity-rules.ts +4 -6
- package/templates/starter/src/app/acceptance/control-layout-model.ts +4 -4
- package/templates/starter/src/app/acceptance/control-layout-section-rules.ts +3 -10
- package/templates/starter/src/app/acceptance/control-parts.ts +8 -0
- package/templates/starter/src/app/acceptance/control-section-entity-cohesion.test.ts +215 -0
- package/templates/starter/src/app/acceptance/control-section-entity-cohesion.ts +132 -0
- package/templates/starter/src/app/acceptance/control-section-inventory.test.ts +87 -0
- package/templates/starter/src/app/acceptance/control-section-inventory.ts +74 -44
- package/templates/starter/src/app/acceptance/custom-controls.ts +11 -3
- package/templates/starter/src/app/acceptance/export-artifact-coverage.ts +113 -0
- package/templates/starter/src/app/acceptance/inline-layout.ts +64 -9
- package/templates/starter/src/app/acceptance/media-upload.ts +5 -1
- package/templates/starter/src/app/acceptance/orientation-gizmo.ts +18 -11
- package/templates/starter/src/app/acceptance/output-background-rules.ts +2 -2
- package/templates/starter/src/app/acceptance/output-export-layout-rules.ts +18 -10
- package/templates/starter/src/app/acceptance/output-export-model.ts +54 -11
- package/templates/starter/src/app/acceptance/output-export.ts +35 -12
- package/templates/starter/src/app/acceptance/output-video-export-rules.ts +99 -0
- package/templates/starter/src/app/acceptance/types.ts +30 -8
- package/templates/starter/src/app/acceptance/validate-coverage.ts +20 -2
- package/templates/starter/src/app/starter-acceptance.artifact-export-intent.test.ts +239 -0
- package/templates/starter/src/app/starter-acceptance.background-export.test.ts +33 -0
- package/templates/starter/src/app/starter-acceptance.canvas-sizing.test.ts +16 -1
- package/templates/starter/src/app/starter-acceptance.compound-part-coverage.test.ts +65 -0
- package/templates/starter/src/app/starter-acceptance.contract-fixtures.test.ts +41 -0
- package/templates/starter/src/app/starter-acceptance.contract-fixtures.ts +112 -16
- package/templates/starter/src/app/starter-acceptance.control-applicability.test.ts +224 -0
- package/templates/starter/src/app/starter-acceptance.control-order.test.ts +58 -3
- package/templates/starter/src/app/starter-acceptance.control-state.test.ts +0 -111
- package/templates/starter/src/app/starter-acceptance.custom-control-collections.test.ts +3 -1
- package/templates/starter/src/app/starter-acceptance.custom-control-valid.test.ts +1 -1
- package/templates/starter/src/app/starter-acceptance.export-artifact.test.ts +131 -0
- package/templates/starter/src/app/starter-acceptance.export-test-utils.ts +22 -0
- package/templates/starter/src/app/{starter-acceptance.image-video-export-settings.test.ts → starter-acceptance.image-export-settings.test.ts} +37 -9
- package/templates/starter/src/app/starter-acceptance.interaction-ownership.test.ts +12 -0
- package/templates/starter/src/app/starter-acceptance.keyframes.test.ts +14 -4
- package/templates/starter/src/app/starter-acceptance.media-upload.fixtures.ts +11 -1
- package/templates/starter/src/app/starter-acceptance.media-upload.test.ts +28 -0
- package/templates/starter/src/app/starter-acceptance.output-export-intent.test.ts +384 -0
- package/templates/starter/src/app/starter-acceptance.output-export-rules.test.ts +46 -1
- package/templates/starter/src/app/starter-acceptance.product-output-export.test.ts +112 -105
- package/templates/starter/src/app/starter-acceptance.product-readiness.test.ts +12 -0
- package/templates/starter/src/app/starter-acceptance.section-cohesion.test.ts +1 -1
- package/templates/starter/src/app/starter-acceptance.section-dependencies.test.ts +35 -24
- package/templates/starter/src/app/starter-acceptance.section-size.test.ts +72 -0
- package/templates/starter/src/app/starter-acceptance.ts +13 -2
- package/templates/starter/src/app/starter-acceptance.video-export-settings.test.ts +336 -0
- package/templates/starter/src/app/starter-acceptance.view-interaction.test.ts +8 -0
- package/templates/starter/src/app/starter-performance-test-utils.ts +103 -0
- package/templates/starter/src/app/starter-performance.gates.test.ts +231 -278
- package/templates/starter/src/app/starter-performance.lifecycle.test.ts +261 -0
- package/templates/starter/src/app/test-evidence/browser-runtime-contract.ts +4 -2
- package/templates/starter/src/routes/index.tsx +2 -0
- package/templates/ui/components/composites/tabs.tsx +2 -2
- package/templates/ui/components/controls/collection-actions/collection-item-groups.test.tsx +38 -0
- package/templates/ui/components/controls/collection-actions/collection-item-groups.tsx +36 -0
- package/templates/ui/components/controls/collection-actions/index.ts +2 -0
- package/templates/ui/components/controls/file-drop/file-drop-collection-control.tsx +137 -0
- package/templates/ui/components/controls/file-drop/file-drop-control.test.tsx +189 -0
- package/templates/ui/components/controls/file-drop/file-drop-control.tsx +81 -88
- package/templates/ui/components/controls/file-drop/file-drop-presentation.tsx +131 -9
- package/templates/ui/components/controls/file-drop/file-drop-types.ts +36 -22
- package/templates/ui/components/controls/file-drop/index.ts +1 -0
- package/templates/ui/components/controls/index.ts +3 -0
- package/templates/ui/components/controls/range-slider/range-slider-control.tsx +1 -1
- package/templates/ui/components/controls/range-slider/range-slider-value.test.ts +14 -0
- package/templates/ui/components/controls/range-slider/range-slider-value.ts +3 -2
- package/templates/runtime/export/export.ts +0 -166
- package/templates/starter/src/app/acceptance/condition-exclusivity.test.ts +0 -60
- package/templates/starter/src/app/acceptance/condition-exclusivity.ts +0 -221
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Page } from "@playwright/test";
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
+
TOOLCRAFT_CANVAS_RENDER_SCALE,
|
|
4
5
|
compileToolcraftPerformanceFixturePlan,
|
|
5
6
|
deriveToolcraftPerformancePaths,
|
|
6
7
|
type ResolvedToolcraftAppSchema,
|
|
@@ -9,14 +10,11 @@ import {
|
|
|
9
10
|
} from "@repo/toolcraft-runtime";
|
|
10
11
|
|
|
11
12
|
import {
|
|
12
|
-
|
|
13
|
+
expectToolcraftCanvasBackingPixelsForRenderScale,
|
|
13
14
|
expectToolcraftPerformanceRenderScaleBackingEvidence,
|
|
14
|
-
isToolcraftRenderScalePerformancePath,
|
|
15
15
|
} from "./browser-render-scale-evidence";
|
|
16
16
|
import { attachToolcraftBrowserRuntimeEvidence } from "./browser-runtime-evidence";
|
|
17
|
-
import {
|
|
18
|
-
expectToolcraftPerformanceBudget,
|
|
19
|
-
} from "./performance-budget-helpers";
|
|
17
|
+
import { expectToolcraftPerformanceBudget } from "./performance-budget-helpers";
|
|
20
18
|
import { applyToolcraftPerformancePathCompiledFixture } from "./performance-fixture-helpers";
|
|
21
19
|
import {
|
|
22
20
|
readToolcraftPerformanceFixtureResolutionMode,
|
|
@@ -27,11 +25,15 @@ import {
|
|
|
27
25
|
measureToolcraftClipboardActionByLabel,
|
|
28
26
|
measureToolcraftDownloadActionByLabel,
|
|
29
27
|
} from "./performance-output-action-helpers";
|
|
30
|
-
import type { ToolcraftPerformancePathAdapter } from "./performance-path-adapter-contract";
|
|
31
|
-
import { expectToolcraftPipelineInvariant } from "./performance-pipeline-evidence";
|
|
32
28
|
import {
|
|
33
|
-
|
|
34
|
-
} from "./performance-
|
|
29
|
+
createToolcraftPerformanceCanvasQualityGuard,
|
|
30
|
+
} from "./performance-canvas-quality-guard";
|
|
31
|
+
import type {
|
|
32
|
+
ToolcraftPerformanceCanvasBacking,
|
|
33
|
+
ToolcraftPerformancePathAdapter,
|
|
34
|
+
} from "./performance-path-adapter-contract";
|
|
35
|
+
import { expectToolcraftPipelineInvariant } from "./performance-pipeline-evidence";
|
|
36
|
+
import { getToolcraftPerformancePathBudget } from "./performance-profile-helpers";
|
|
35
37
|
import {
|
|
36
38
|
measureToolcraftAnimationFrames,
|
|
37
39
|
measureToolcraftInteraction,
|
|
@@ -39,10 +41,81 @@ import {
|
|
|
39
41
|
|
|
40
42
|
export type ToolcraftCompiledPerformancePathAdapter = Readonly<{
|
|
41
43
|
adapter: ToolcraftPerformancePathAdapter;
|
|
44
|
+
canvasBacking: ToolcraftPerformanceCanvasBacking | undefined;
|
|
42
45
|
path: ToolcraftPerformancePath;
|
|
43
46
|
testName: string;
|
|
44
47
|
}>;
|
|
45
48
|
|
|
49
|
+
type ToolcraftPerformancePathAdapterMatrixInput = Readonly<{
|
|
50
|
+
adapters: readonly ToolcraftPerformancePathAdapter[];
|
|
51
|
+
canvasBacking: ToolcraftPerformanceCanvasBacking | undefined;
|
|
52
|
+
paths: readonly ToolcraftPerformancePath[];
|
|
53
|
+
schema: ResolvedToolcraftAppSchema;
|
|
54
|
+
}>;
|
|
55
|
+
|
|
56
|
+
function compileToolcraftPerformanceCanvasBackingConfig(
|
|
57
|
+
canvasBacking: unknown,
|
|
58
|
+
): ToolcraftPerformanceCanvasBacking {
|
|
59
|
+
if (
|
|
60
|
+
typeof canvasBacking !== "object" ||
|
|
61
|
+
canvasBacking === null ||
|
|
62
|
+
Array.isArray(canvasBacking)
|
|
63
|
+
) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
"Toolcraft performance canvas backing must be a non-null object.",
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
const keys = Reflect.ownKeys(canvasBacking);
|
|
69
|
+
if (keys.length !== 1 || keys[0] !== "canvasSelector") {
|
|
70
|
+
throw new Error(
|
|
71
|
+
'Toolcraft performance canvas backing must contain exactly one "canvasSelector" field.',
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
const descriptor = Object.getOwnPropertyDescriptor(
|
|
75
|
+
canvasBacking,
|
|
76
|
+
"canvasSelector",
|
|
77
|
+
);
|
|
78
|
+
if (!descriptor || !("value" in descriptor)) {
|
|
79
|
+
throw new Error(
|
|
80
|
+
"Toolcraft performance canvas backing canvasSelector must be a data property.",
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
const canvasSelector = descriptor.value;
|
|
84
|
+
if (
|
|
85
|
+
typeof canvasSelector !== "string" ||
|
|
86
|
+
canvasSelector.length === 0 ||
|
|
87
|
+
canvasSelector.trim() !== canvasSelector
|
|
88
|
+
) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
"Toolcraft performance canvas backing canvasSelector must be a non-empty trimmed string.",
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
return Object.freeze({ canvasSelector });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function compilePerformanceCanvasBackingBoundary({
|
|
97
|
+
canvasBacking,
|
|
98
|
+
schema,
|
|
99
|
+
}: Pick<
|
|
100
|
+
ToolcraftPerformancePathAdapterMatrixInput,
|
|
101
|
+
"canvasBacking" | "schema"
|
|
102
|
+
>): ToolcraftPerformanceCanvasBacking | undefined {
|
|
103
|
+
if (canvasBacking === undefined) {
|
|
104
|
+
if (!schema.canvas.renderScale.enabled) {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
throw new Error(
|
|
108
|
+
"Toolcraft render-scale-enabled performance catalogs require one product canvas selector for 2x backing proof.",
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
if (!schema.canvas.renderScale.enabled) {
|
|
112
|
+
throw new Error(
|
|
113
|
+
"Toolcraft performance canvas backing proof must be omitted when canvas render scale is disabled.",
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
return compileToolcraftPerformanceCanvasBackingConfig(canvasBacking);
|
|
117
|
+
}
|
|
118
|
+
|
|
46
119
|
function compareCodeUnits(left: string, right: string): number {
|
|
47
120
|
return left < right ? -1 : left > right ? 1 : 0;
|
|
48
121
|
}
|
|
@@ -57,13 +130,17 @@ export function getToolcraftPerformancePathSettleFrames(
|
|
|
57
130
|
path: Pick<ToolcraftPerformancePath, "interaction">,
|
|
58
131
|
): number | undefined {
|
|
59
132
|
// A p95 distribution needs at least 20 samples to remain distinct from max.
|
|
60
|
-
return path.interaction === "
|
|
133
|
+
return path.interaction === "animation-frame" ||
|
|
134
|
+
path.interaction === "export"
|
|
135
|
+
? undefined
|
|
136
|
+
: 20;
|
|
61
137
|
}
|
|
62
138
|
|
|
63
139
|
export function compileToolcraftPerformancePathAdapterMatrix(
|
|
64
|
-
|
|
65
|
-
adapters: readonly ToolcraftPerformancePathAdapter[],
|
|
140
|
+
input: ToolcraftPerformancePathAdapterMatrixInput,
|
|
66
141
|
): readonly ToolcraftCompiledPerformancePathAdapter[] {
|
|
142
|
+
const compiledCanvasBacking = compilePerformanceCanvasBackingBoundary(input);
|
|
143
|
+
const { adapters, paths } = input;
|
|
67
144
|
const canonicalPaths = [...paths].sort((left, right) =>
|
|
68
145
|
compareCodeUnits(left.id, right.id),
|
|
69
146
|
);
|
|
@@ -100,17 +177,6 @@ export function compileToolcraftPerformancePathAdapterMatrix(
|
|
|
100
177
|
|
|
101
178
|
for (const path of canonicalPaths) {
|
|
102
179
|
const adapter = adaptersByPathId.get(path.id)!;
|
|
103
|
-
if (
|
|
104
|
-
isToolcraftRenderScalePerformancePath(path) &&
|
|
105
|
-
!adapter.renderScaleBacking
|
|
106
|
-
) {
|
|
107
|
-
throw new Error(
|
|
108
|
-
`Toolcraft render-scale performance path "${path.id}" requires real backing-pixel proof configuration.`,
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
if (adapter.renderScaleBacking) {
|
|
112
|
-
assertToolcraftRenderScaleBackingProofConfig(adapter.renderScaleBacking);
|
|
113
|
-
}
|
|
114
180
|
if (path.interaction === "export" && !adapter.output) {
|
|
115
181
|
throw new Error(
|
|
116
182
|
`Toolcraft export performance path "${path.id}" requires a protected output completion adapter.`,
|
|
@@ -135,6 +201,7 @@ export function compileToolcraftPerformancePathAdapterMatrix(
|
|
|
135
201
|
canonicalPaths.map((path) =>
|
|
136
202
|
Object.freeze({
|
|
137
203
|
adapter: adaptersByPathId.get(path.id)!,
|
|
204
|
+
canvasBacking: compiledCanvasBacking,
|
|
138
205
|
path,
|
|
139
206
|
testName: getToolcraftPerformancePathTestName(path),
|
|
140
207
|
}),
|
|
@@ -179,7 +246,7 @@ export async function runToolcraftPerformancePath(
|
|
|
179
246
|
): Promise<void> {
|
|
180
247
|
const fixtureResolutionMode =
|
|
181
248
|
readToolcraftPerformanceFixtureResolutionMode();
|
|
182
|
-
const { adapter, path } = entry;
|
|
249
|
+
const { adapter, canvasBacking, path } = entry;
|
|
183
250
|
const canonicalPath = deriveToolcraftPerformancePaths(schema, config).find(
|
|
184
251
|
(candidate) => candidate.id === path.id,
|
|
185
252
|
);
|
|
@@ -216,76 +283,128 @@ export async function runToolcraftPerformancePath(
|
|
|
216
283
|
);
|
|
217
284
|
}
|
|
218
285
|
|
|
286
|
+
const renderScaleEnabled = schema.canvas.renderScale.enabled;
|
|
287
|
+
if (renderScaleEnabled !== (canvasBacking !== undefined)) {
|
|
288
|
+
throw new Error(
|
|
289
|
+
"Toolcraft performance canvas backing presence must match the resolved render-scale schema.",
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
const baselineCssSize = renderScaleEnabled
|
|
293
|
+
? await expectToolcraftCanvasBackingPixelsForRenderScale(
|
|
294
|
+
page,
|
|
295
|
+
canvasBacking!.canvasSelector,
|
|
296
|
+
TOOLCRAFT_CANVAS_RENDER_SCALE.defaultValue,
|
|
297
|
+
{ state: "performance-baseline" },
|
|
298
|
+
)
|
|
299
|
+
: undefined;
|
|
300
|
+
const canvasQualityGuard = baselineCssSize
|
|
301
|
+
? await createToolcraftPerformanceCanvasQualityGuard(page, {
|
|
302
|
+
baselineCssSize,
|
|
303
|
+
canvasSelector: canvasBacking!.canvasSelector,
|
|
304
|
+
cssSizePolicy:
|
|
305
|
+
path.interaction === "viewport-zoom" ? "viewport-driven" : "fixed",
|
|
306
|
+
pathId: path.id,
|
|
307
|
+
})
|
|
308
|
+
: undefined;
|
|
309
|
+
|
|
219
310
|
const budget = getToolcraftPerformancePathBudget(path, config.scenarios);
|
|
220
311
|
const target = getPathTarget(path);
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
adapter.output
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
312
|
+
let hasPrimaryFailure = false;
|
|
313
|
+
try {
|
|
314
|
+
await expectToolcraftPipelineInvariant(
|
|
315
|
+
page,
|
|
316
|
+
config,
|
|
317
|
+
path.id,
|
|
318
|
+
async (phase) => {
|
|
319
|
+
const context = Object.freeze({ page, path, phase });
|
|
320
|
+
const measurePhase = async () => {
|
|
321
|
+
if (adapter.output?.kind === "download") {
|
|
322
|
+
const measured = await measureToolcraftDownloadActionByLabel(
|
|
323
|
+
page,
|
|
324
|
+
adapter.output.label,
|
|
325
|
+
{ pathId: path.id, phase, profile: path.profile, target },
|
|
326
|
+
);
|
|
327
|
+
await adapter.output.verify(measured.completion, page);
|
|
328
|
+
return measured.result;
|
|
329
|
+
}
|
|
330
|
+
if (adapter.output?.kind === "clipboard") {
|
|
331
|
+
const measured = await measureToolcraftClipboardActionByLabel(
|
|
332
|
+
page,
|
|
333
|
+
adapter.output.label,
|
|
334
|
+
{ pathId: path.id, phase, profile: path.profile, target },
|
|
335
|
+
);
|
|
336
|
+
await adapter.output.verify(measured.completion, page);
|
|
337
|
+
return measured.result;
|
|
338
|
+
}
|
|
339
|
+
if (path.interaction === "animation-frame") {
|
|
340
|
+
await adapter.action(context);
|
|
341
|
+
const result = await measureToolcraftAnimationFrames(page, 120, {
|
|
342
|
+
pathId: path.id,
|
|
343
|
+
phase,
|
|
344
|
+
profile: path.profile,
|
|
345
|
+
target,
|
|
346
|
+
});
|
|
347
|
+
await adapter.verifyOutcome?.(context);
|
|
348
|
+
return result;
|
|
349
|
+
}
|
|
350
|
+
const result = await measureToolcraftInteraction(
|
|
351
|
+
page,
|
|
352
|
+
() => adapter.action(context),
|
|
353
|
+
{
|
|
354
|
+
...(adapter.observeOutcome
|
|
355
|
+
? { observeOutcome: () => adapter.observeOutcome!(context) }
|
|
356
|
+
: {}),
|
|
357
|
+
pathId: path.id,
|
|
358
|
+
phase,
|
|
359
|
+
profile: path.profile,
|
|
360
|
+
settleFrames: getToolcraftPerformancePathSettleFrames(path),
|
|
361
|
+
target,
|
|
362
|
+
},
|
|
363
|
+
);
|
|
364
|
+
await adapter.verifyOutcome?.(context);
|
|
365
|
+
return result;
|
|
366
|
+
};
|
|
367
|
+
const result = canvasQualityGuard
|
|
368
|
+
? await canvasQualityGuard.runPhase(phase, measurePhase)
|
|
369
|
+
: await measurePhase();
|
|
370
|
+
expectToolcraftPerformanceBudget(result, budget);
|
|
371
|
+
await attachPathEvidence("performance-budget", path);
|
|
372
|
+
|
|
373
|
+
if (
|
|
374
|
+
path.interaction === "control-drag" ||
|
|
375
|
+
path.interaction === "mask-drag"
|
|
376
|
+
) {
|
|
377
|
+
await attachPathEvidence("performance-control-drag", path);
|
|
378
|
+
}
|
|
379
|
+
if (
|
|
380
|
+
path.interaction === "viewport-drag" ||
|
|
381
|
+
path.interaction === "viewport-zoom"
|
|
382
|
+
) {
|
|
383
|
+
await attachPathEvidence("performance-viewport", path);
|
|
384
|
+
}
|
|
385
|
+
if (canvasBacking) {
|
|
386
|
+
await expectToolcraftPerformanceRenderScaleBackingEvidence(page, {
|
|
387
|
+
baselineCssSize: baselineCssSize!,
|
|
388
|
+
canvasSelector: canvasBacking.canvasSelector,
|
|
389
|
+
cssSizePolicy:
|
|
390
|
+
path.interaction === "viewport-zoom"
|
|
391
|
+
? "viewport-driven"
|
|
392
|
+
: "fixed",
|
|
261
393
|
pathId: path.id,
|
|
262
394
|
phase,
|
|
263
|
-
profile: path.profile,
|
|
264
|
-
settleFrames: getToolcraftPerformancePathSettleFrames(path),
|
|
265
395
|
target,
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
await attachPathEvidence("performance-viewport", path);
|
|
281
|
-
}
|
|
282
|
-
if (isToolcraftRenderScalePerformancePath(path)) {
|
|
283
|
-
await expectToolcraftPerformanceRenderScaleBackingEvidence(page, {
|
|
284
|
-
...adapter.renderScaleBacking!,
|
|
285
|
-
pathId: path.id,
|
|
286
|
-
target,
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
},
|
|
290
|
-
);
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
},
|
|
399
|
+
);
|
|
400
|
+
} catch (error) {
|
|
401
|
+
hasPrimaryFailure = true;
|
|
402
|
+
throw error;
|
|
403
|
+
} finally {
|
|
404
|
+
try {
|
|
405
|
+
await canvasQualityGuard?.dispose();
|
|
406
|
+
} catch (error) {
|
|
407
|
+
if (!hasPrimaryFailure) throw error;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
291
410
|
}
|
|
@@ -3,6 +3,7 @@ import { expect, test } from "@playwright/test";
|
|
|
3
3
|
import {
|
|
4
4
|
activePipelineAttachments,
|
|
5
5
|
activePipelinePath,
|
|
6
|
+
animationPipelinePath,
|
|
6
7
|
evaluatePipelineEvidence,
|
|
7
8
|
initialPipelineAttachments,
|
|
8
9
|
initialPipelinePath,
|
|
@@ -76,6 +77,81 @@ test("ordinary paths require exact cross-phase continuity", () => {
|
|
|
76
77
|
);
|
|
77
78
|
});
|
|
78
79
|
|
|
80
|
+
test("autonomous animation permits only its invalidated passes to advance between phases", () => {
|
|
81
|
+
const observation = (
|
|
82
|
+
phase: "cold" | "warm" | "sustained",
|
|
83
|
+
beforeExecutions: number,
|
|
84
|
+
afterExecutions: number,
|
|
85
|
+
) =>
|
|
86
|
+
pipelineEvidenceAttachment(
|
|
87
|
+
pipelineEvidence(
|
|
88
|
+
phase,
|
|
89
|
+
noCacheActivitySnapshot(beforeExecutions),
|
|
90
|
+
noCacheActivitySnapshot(afterExecutions),
|
|
91
|
+
animationPipelinePath,
|
|
92
|
+
),
|
|
93
|
+
);
|
|
94
|
+
const valid = evaluatePipelineEvidence(
|
|
95
|
+
[
|
|
96
|
+
observation("cold", 0, 2),
|
|
97
|
+
observation("warm", 5, 7),
|
|
98
|
+
observation("sustained", 10, 12),
|
|
99
|
+
],
|
|
100
|
+
[animationPipelinePath.id],
|
|
101
|
+
);
|
|
102
|
+
const decodeAdvanced = pipelineSnapshot({
|
|
103
|
+
composite: {
|
|
104
|
+
cacheMisses: 5,
|
|
105
|
+
durationMax: 1,
|
|
106
|
+
durationTotal: 5,
|
|
107
|
+
executions: 5,
|
|
108
|
+
},
|
|
109
|
+
decode: {
|
|
110
|
+
activeResources: 1,
|
|
111
|
+
cacheMisses: 1,
|
|
112
|
+
durationMax: 1,
|
|
113
|
+
durationTotal: 1,
|
|
114
|
+
executions: 1,
|
|
115
|
+
resourceCreations: 1,
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
const invalid = evaluatePipelineEvidence(
|
|
119
|
+
[
|
|
120
|
+
observation("cold", 0, 2),
|
|
121
|
+
pipelineEvidenceAttachment(
|
|
122
|
+
pipelineEvidence(
|
|
123
|
+
"warm",
|
|
124
|
+
decodeAdvanced,
|
|
125
|
+
pipelineSnapshot({
|
|
126
|
+
composite: {
|
|
127
|
+
cacheMisses: 7,
|
|
128
|
+
durationMax: 1,
|
|
129
|
+
durationTotal: 7,
|
|
130
|
+
executions: 7,
|
|
131
|
+
},
|
|
132
|
+
decode: {
|
|
133
|
+
activeResources: 1,
|
|
134
|
+
cacheMisses: 1,
|
|
135
|
+
durationMax: 1,
|
|
136
|
+
durationTotal: 1,
|
|
137
|
+
executions: 1,
|
|
138
|
+
resourceCreations: 1,
|
|
139
|
+
},
|
|
140
|
+
}),
|
|
141
|
+
animationPipelinePath,
|
|
142
|
+
),
|
|
143
|
+
),
|
|
144
|
+
observation("sustained", 10, 12),
|
|
145
|
+
],
|
|
146
|
+
[animationPipelinePath.id],
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
expect(valid.errors).toEqual([]);
|
|
150
|
+
expect(invalid.errors).toContainEqual(
|
|
151
|
+
expect.stringMatching(/cold\.after to warm\.before/i),
|
|
152
|
+
);
|
|
153
|
+
});
|
|
154
|
+
|
|
79
155
|
test("initial-render uses fresh canonical zero lifecycle samples without continuity", () => {
|
|
80
156
|
const valid = evaluatePipelineEvidence(initialPipelineAttachments(), [
|
|
81
157
|
initialPipelinePath.id,
|
|
@@ -67,6 +67,12 @@ export const pipelineEvidenceRegistration =
|
|
|
67
67
|
mustNotInvalidate: ["decode"],
|
|
68
68
|
targets: ["canvas.initial-render"],
|
|
69
69
|
},
|
|
70
|
+
{
|
|
71
|
+
interaction: "animation-frame",
|
|
72
|
+
invalidates: ["composite"],
|
|
73
|
+
mustNotInvalidate: ["decode"],
|
|
74
|
+
targets: ["runtime.animation-frame"],
|
|
75
|
+
},
|
|
70
76
|
{
|
|
71
77
|
interaction: "control-drag",
|
|
72
78
|
invalidates: ["composite"],
|
|
@@ -116,8 +122,8 @@ export const pipelineEvidenceRegistration =
|
|
|
116
122
|
relationship: "constant",
|
|
117
123
|
},
|
|
118
124
|
id: "composite",
|
|
119
|
-
inputs: ["decode", "effect.strength"],
|
|
120
|
-
invalidatedBy: ["effect.strength"],
|
|
125
|
+
inputs: ["decode", "effect.strength", "runtime.animation-frame"],
|
|
126
|
+
invalidatedBy: ["effect.strength", "runtime.animation-frame"],
|
|
121
127
|
kind: "composite",
|
|
122
128
|
output: "preview",
|
|
123
129
|
quality: "full",
|
|
@@ -142,6 +148,9 @@ const performancePaths = deriveToolcraftPerformancePaths(
|
|
|
142
148
|
export const activePipelinePath = performancePaths.find(
|
|
143
149
|
(path) => path.interaction === "control-drag",
|
|
144
150
|
)!;
|
|
151
|
+
export const animationPipelinePath = performancePaths.find(
|
|
152
|
+
(path) => path.interaction === "animation-frame",
|
|
153
|
+
)!;
|
|
145
154
|
export const initialPipelinePath = performancePaths.find(
|
|
146
155
|
(path) => path.interaction === "initial-render",
|
|
147
156
|
)!;
|
|
@@ -151,6 +151,35 @@ function snapshotsMatch(
|
|
|
151
151
|
});
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
+
function snapshotsPreserveContinuousAnimation(
|
|
155
|
+
left: ToolcraftPerformancePipelineSnapshot,
|
|
156
|
+
right: ToolcraftPerformancePipelineSnapshot,
|
|
157
|
+
invalidatedPassIds: ReadonlySet<string>,
|
|
158
|
+
): boolean {
|
|
159
|
+
if (
|
|
160
|
+
left.disposed !== right.disposed ||
|
|
161
|
+
left.runtimeId !== right.runtimeId ||
|
|
162
|
+
left.passes.length !== right.passes.length
|
|
163
|
+
) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
const rightByPass = pipelinePassMap(right);
|
|
167
|
+
return left.passes.every((leftPass) => {
|
|
168
|
+
const rightPass = rightByPass.get(leftPass.passId);
|
|
169
|
+
if (!rightPass) return false;
|
|
170
|
+
if (!invalidatedPassIds.has(leftPass.passId)) {
|
|
171
|
+
return TOOLCRAFT_PERFORMANCE_PIPELINE_METRIC_KEYS.every(
|
|
172
|
+
(key) => leftPass[key] === rightPass[key],
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
return TOOLCRAFT_PERFORMANCE_PIPELINE_METRIC_KEYS.every((key) =>
|
|
176
|
+
key === "activeResources"
|
|
177
|
+
? leftPass[key] === rightPass[key]
|
|
178
|
+
: leftPass[key] <= rightPass[key],
|
|
179
|
+
);
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
154
183
|
export function getPipelinePhaseContinuityErrors({
|
|
155
184
|
cold,
|
|
156
185
|
path,
|
|
@@ -164,15 +193,29 @@ export function getPipelinePhaseContinuityErrors({
|
|
|
164
193
|
}): string[] {
|
|
165
194
|
if (path.interaction === "initial-render") return [];
|
|
166
195
|
|
|
196
|
+
const continuousAnimation = path.interaction === "animation-frame";
|
|
197
|
+
const invalidatedPassIds = new Set(path.invalidates);
|
|
198
|
+
const snapshotsPreservePhaseBoundary =
|
|
199
|
+
continuousAnimation
|
|
200
|
+
? (left: ToolcraftPerformancePipelineSnapshot, right: ToolcraftPerformancePipelineSnapshot) =>
|
|
201
|
+
snapshotsPreserveContinuousAnimation(
|
|
202
|
+
left,
|
|
203
|
+
right,
|
|
204
|
+
invalidatedPassIds,
|
|
205
|
+
)
|
|
206
|
+
: snapshotsMatch;
|
|
207
|
+
const continuityRequirement = continuousAnimation
|
|
208
|
+
? "monotonic invalidated-pass and exact non-invalidated-pass"
|
|
209
|
+
: "exact";
|
|
167
210
|
const errors: string[] = [];
|
|
168
|
-
if (!
|
|
211
|
+
if (!snapshotsPreservePhaseBoundary(cold.after, warm.before)) {
|
|
169
212
|
errors.push(
|
|
170
|
-
`Path "${path.id}" must preserve
|
|
213
|
+
`Path "${path.id}" must preserve ${continuityRequirement} pipeline counters from cold.after to warm.before.`,
|
|
171
214
|
);
|
|
172
215
|
}
|
|
173
|
-
if (!
|
|
216
|
+
if (!snapshotsPreservePhaseBoundary(warm.after, sustained.before)) {
|
|
174
217
|
errors.push(
|
|
175
|
-
`Path "${path.id}" must preserve
|
|
218
|
+
`Path "${path.id}" must preserve ${continuityRequirement} pipeline counters from warm.after to sustained.before.`,
|
|
176
219
|
);
|
|
177
220
|
}
|
|
178
221
|
return errors;
|