@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
package/package.json
CHANGED
|
@@ -99,7 +99,7 @@ test("generated standalone app preserves authority-bound performance iteration l
|
|
|
99
99
|
}
|
|
100
100
|
const output = `${stdout}\n${stderr}`;
|
|
101
101
|
assert.doesNotMatch(output, /ERR_MODULE_NOT_FOUND/u);
|
|
102
|
-
assert.match(output, /^# tests
|
|
103
|
-
assert.match(output, /^# pass
|
|
102
|
+
assert.match(output, /^# tests 11$/mu);
|
|
103
|
+
assert.match(output, /^# pass 11$/mu);
|
|
104
104
|
assert.match(output, /^# fail 0$/mu);
|
|
105
105
|
});
|
|
@@ -31,10 +31,20 @@ const materialBrowserTestNames = Object.freeze([
|
|
|
31
31
|
"browser: frosting color changes material output",
|
|
32
32
|
"browser: gloss changes material output",
|
|
33
33
|
"browser: layer mode changes material output",
|
|
34
|
-
"browser: material appearance reaches exported pixels",
|
|
34
|
+
"browser: material appearance reaches decoded exported pixels",
|
|
35
35
|
"browser: sprinkle color changes material output",
|
|
36
36
|
"browser: sprinkles visibility changes material output",
|
|
37
37
|
]);
|
|
38
|
+
const materialDeliveryBrowserTestNames = Object.freeze([
|
|
39
|
+
"browser: ambient speed changes product output",
|
|
40
|
+
...materialBrowserTestNames,
|
|
41
|
+
"browser: timeline playback drives product output",
|
|
42
|
+
]);
|
|
43
|
+
const materialDeliveryAcceptanceIds = Object.freeze([
|
|
44
|
+
"animation.speed",
|
|
45
|
+
...materialAcceptanceIds,
|
|
46
|
+
"runtime.timeline",
|
|
47
|
+
]);
|
|
38
48
|
const materialProductTestFiles = Object.freeze([
|
|
39
49
|
"src/app/acceptance/validation-pipeline.test.ts",
|
|
40
50
|
"src/app/app-acceptance.base-coverage.test.ts",
|
|
@@ -44,6 +54,7 @@ const materialProductTestFiles = Object.freeze([
|
|
|
44
54
|
"src/app/app-automated-runtime-evidence.test.ts",
|
|
45
55
|
"src/app/app-performance.fixture-helper.test.ts",
|
|
46
56
|
"src/app/app-performance.gates.test.ts",
|
|
57
|
+
"src/app/app-performance.lifecycle.test.ts",
|
|
47
58
|
"src/app/app-schema.test.ts",
|
|
48
59
|
"src/app/material-output.test.tsx",
|
|
49
60
|
]);
|
|
@@ -294,8 +305,8 @@ export async function assertGeneratedFreshDemandOnlyLifecycle({
|
|
|
294
305
|
browserEnv,
|
|
295
306
|
checkpointPath,
|
|
296
307
|
execFileAsync,
|
|
297
|
-
expectedAcceptanceIds:
|
|
298
|
-
expectedBrowserTestNames:
|
|
308
|
+
expectedAcceptanceIds: materialDeliveryAcceptanceIds,
|
|
309
|
+
expectedBrowserTestNames: materialDeliveryBrowserTestNames,
|
|
299
310
|
expectedChangedFiles: generatedProductMaterialIterationFixturePaths,
|
|
300
311
|
expectedProductTestFiles: materialProductTestFiles,
|
|
301
312
|
targetDir,
|
|
@@ -115,15 +115,13 @@ function createGeneratedCommandEnvironment(packageManager, overrides = {}) {
|
|
|
115
115
|
return childEnv;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
|
|
118
|
+
async function executeGeneratedPackageManager(
|
|
119
119
|
execFileAsync,
|
|
120
120
|
targetDir,
|
|
121
|
-
|
|
121
|
+
packageManager,
|
|
122
|
+
packageManagerArgs,
|
|
122
123
|
{ env = {} } = {},
|
|
123
124
|
) {
|
|
124
|
-
const { packageManager } = await readGeneratedPackageManager(targetDir);
|
|
125
|
-
const packageManagerArgs =
|
|
126
|
-
packageManager === "npm" ? ["run", ...args] : args;
|
|
127
125
|
try {
|
|
128
126
|
return await execFileAsync(packageManager, packageManagerArgs, {
|
|
129
127
|
cwd: targetDir,
|
|
@@ -143,6 +141,45 @@ export async function runGeneratedCommand(
|
|
|
143
141
|
}
|
|
144
142
|
}
|
|
145
143
|
|
|
144
|
+
export async function runGeneratedCommand(
|
|
145
|
+
execFileAsync,
|
|
146
|
+
targetDir,
|
|
147
|
+
args,
|
|
148
|
+
options,
|
|
149
|
+
) {
|
|
150
|
+
const { packageManager } = await readGeneratedPackageManager(targetDir);
|
|
151
|
+
const packageManagerArgs =
|
|
152
|
+
packageManager === "npm" ? ["run", ...args] : args;
|
|
153
|
+
return executeGeneratedPackageManager(
|
|
154
|
+
execFileAsync,
|
|
155
|
+
targetDir,
|
|
156
|
+
packageManager,
|
|
157
|
+
packageManagerArgs,
|
|
158
|
+
options,
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export async function runGeneratedExecutable(
|
|
163
|
+
execFileAsync,
|
|
164
|
+
targetDir,
|
|
165
|
+
executableName,
|
|
166
|
+
args,
|
|
167
|
+
options,
|
|
168
|
+
) {
|
|
169
|
+
const { packageManager } = await readGeneratedPackageManager(targetDir);
|
|
170
|
+
const packageManagerArgs =
|
|
171
|
+
packageManager === "npm"
|
|
172
|
+
? ["exec", "--", executableName, ...args]
|
|
173
|
+
: ["exec", executableName, ...args];
|
|
174
|
+
return executeGeneratedPackageManager(
|
|
175
|
+
execFileAsync,
|
|
176
|
+
targetDir,
|
|
177
|
+
packageManager,
|
|
178
|
+
packageManagerArgs,
|
|
179
|
+
options,
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
146
183
|
export function runGeneratedScript(
|
|
147
184
|
execFileAsync,
|
|
148
185
|
targetDir,
|
|
@@ -2,6 +2,21 @@ import assert from "node:assert/strict";
|
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
|
|
5
|
+
import {
|
|
6
|
+
assertGeneratedExportIntentDocsDoNotInferVideo,
|
|
7
|
+
collectGeneratedAgentFacingDocs,
|
|
8
|
+
getMissingGeneratedPerformanceLifecycleMarkers,
|
|
9
|
+
getStaleAgentPerformanceWorkflowFailures,
|
|
10
|
+
} from "./generate-test-doc-policy-assertions.mjs";
|
|
11
|
+
|
|
12
|
+
export {
|
|
13
|
+
assertGeneratedExportIntentDocsDoNotInferVideo,
|
|
14
|
+
collectGeneratedAgentFacingDocs,
|
|
15
|
+
getMissingGeneratedPerformanceLifecycleMarkers,
|
|
16
|
+
getStaleAgentPerformanceWorkflowFailures,
|
|
17
|
+
staleAnimationDerivedVideoPattern,
|
|
18
|
+
} from "./generate-test-doc-policy-assertions.mjs";
|
|
19
|
+
|
|
5
20
|
const generatedDocPaths = [
|
|
6
21
|
"README.md",
|
|
7
22
|
"workflow.md",
|
|
@@ -23,53 +38,6 @@ const generatedDocPaths = [
|
|
|
23
38
|
"core/reference-study.md",
|
|
24
39
|
];
|
|
25
40
|
|
|
26
|
-
const staleAgentPerformanceWorkflowPattern =
|
|
27
|
-
/app-performance-impact|explicit-performance-work|test:browser:perf|verify:(?:final|quick|ui)|verify:perf:(?:playwright|record-iteration|refresh)|--reason=performance-iteration|--performance-test/iu;
|
|
28
|
-
|
|
29
|
-
async function collectMarkdownPaths(rootDir, relativeDir = "") {
|
|
30
|
-
const currentDir = path.join(rootDir, relativeDir);
|
|
31
|
-
const entries = await fs.readdir(currentDir, { withFileTypes: true });
|
|
32
|
-
const markdownPaths = [];
|
|
33
|
-
|
|
34
|
-
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
35
|
-
const relativePath = path.join(relativeDir, entry.name);
|
|
36
|
-
if (entry.isDirectory()) {
|
|
37
|
-
markdownPaths.push(...(await collectMarkdownPaths(rootDir, relativePath)));
|
|
38
|
-
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
39
|
-
markdownPaths.push(relativePath);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return markdownPaths;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export async function collectGeneratedAgentFacingDocs(targetDir) {
|
|
47
|
-
const docsRoot = path.join(targetDir, "docs/toolcraft");
|
|
48
|
-
const docPaths = await collectMarkdownPaths(docsRoot);
|
|
49
|
-
const docs = await Promise.all(
|
|
50
|
-
docPaths.map(async (docPath) => ({
|
|
51
|
-
docPath: path.posix.join("docs/toolcraft", docPath.split(path.sep).join("/")),
|
|
52
|
-
source: await fs.readFile(path.join(docsRoot, docPath), "utf8"),
|
|
53
|
-
})),
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
return [
|
|
57
|
-
{
|
|
58
|
-
docPath: "AGENTS.md",
|
|
59
|
-
source: await fs.readFile(path.join(targetDir, "AGENTS.md"), "utf8"),
|
|
60
|
-
},
|
|
61
|
-
...docs,
|
|
62
|
-
];
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function getStaleAgentPerformanceWorkflowFailures(sources) {
|
|
66
|
-
return sources.flatMap(({ docPath, source }) =>
|
|
67
|
-
staleAgentPerformanceWorkflowPattern.test(source)
|
|
68
|
-
? [`${docPath} contains removed performance workflow guidance`]
|
|
69
|
-
: [],
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
41
|
export async function assertGeneratedDocs(targetDir) {
|
|
74
42
|
await Promise.all(
|
|
75
43
|
generatedDocPaths.map((docPath) => fs.stat(path.join(targetDir, "docs/toolcraft", docPath))),
|
|
@@ -79,15 +47,21 @@ export async function assertGeneratedDocs(targetDir) {
|
|
|
79
47
|
const licenseSource = await fs.readFile(path.join(targetDir, "LICENSE.md"), "utf8");
|
|
80
48
|
const noticeSource = await fs.readFile(path.join(targetDir, "NOTICE.md"), "utf8");
|
|
81
49
|
const localDocPaths = generatedDocPaths.filter((docPath) => docPath !== "README.md");
|
|
50
|
+
const generatedAgentFacingDocs = await collectGeneratedAgentFacingDocs(targetDir);
|
|
82
51
|
const staleWorkflowFailures = getStaleAgentPerformanceWorkflowFailures(
|
|
83
|
-
|
|
52
|
+
generatedAgentFacingDocs,
|
|
84
53
|
);
|
|
85
54
|
|
|
55
|
+
assert.match(noticeSource, /Mediabunny/u);
|
|
56
|
+
assert.match(noticeSource, /MPL-2\.0/u);
|
|
57
|
+
assert.match(noticeSource, /https:\/\/github\.com\/Vanilagy\/mediabunny/u);
|
|
58
|
+
|
|
86
59
|
assert.deepEqual(
|
|
87
60
|
staleWorkflowFailures,
|
|
88
61
|
[],
|
|
89
62
|
`Generated agent-facing docs contain stale performance workflow guidance:\n${staleWorkflowFailures.join("\n")}`,
|
|
90
63
|
);
|
|
64
|
+
assertGeneratedExportIntentDocsDoNotInferVideo(generatedAgentFacingDocs);
|
|
91
65
|
|
|
92
66
|
assert.match(agentsSource, /Quick Entry Contract/);
|
|
93
67
|
assert.match(agentsSource, /Local Reference Docs/);
|
|
@@ -139,6 +113,7 @@ export async function assertGeneratedDocs(targetDir) {
|
|
|
139
113
|
assert.match(agentsSource, /defineToolcraft/);
|
|
140
114
|
assert.match(agentsSource, /ToolcraftApp/);
|
|
141
115
|
assert.match(agentsSource, /canvasContent/);
|
|
116
|
+
assert.match(agentsSource, /exportRenderer/);
|
|
142
117
|
assert.match(agentsSource, /renderDefaultCanvasMedia=\{false\}/);
|
|
143
118
|
assert.match(agentsSource, /onPanelAction/);
|
|
144
119
|
assert.match(agentsSource, /MIT License/);
|
|
@@ -213,18 +188,63 @@ export async function assertGeneratedDocs(targetDir) {
|
|
|
213
188
|
assert.match(coreRuntimeBoundarySource, /immutable signed copy of the shared runtime/);
|
|
214
189
|
assert.match(coreRuntimeBoundarySource, /copied runtime tree or its signed integrity manifest is missing/);
|
|
215
190
|
assert.match(coreRuntimeBoundarySource, /modelPresentation/);
|
|
191
|
+
assert.match(coreRuntimeBoundarySource, /exportRenderer/);
|
|
192
|
+
assert.match(coreRuntimeBoundarySource, /runtime owns typed image\/video actions end to end/i);
|
|
216
193
|
assert.match(coreRuntimeBoundarySource, /does not suppress runtime model layers/);
|
|
217
194
|
assert.match(componentRulesSource, /Do not show Layers for a single-layer app/);
|
|
218
195
|
assert.match(coreTimelineSource, /Any app with `Export Video` must enable the top Toolcraft timeline/);
|
|
219
|
-
assert.match(coreSetupExportSource, /
|
|
196
|
+
assert.match(coreSetupExportSource, /productReadiness\.exportIntent/);
|
|
197
|
+
assert.match(
|
|
198
|
+
coreSetupExportSource,
|
|
199
|
+
/image[^\n]*`toolcraft-default`[^\n]*`user-requested`[^\n]*`user-removed`/i,
|
|
200
|
+
);
|
|
201
|
+
assert.match(
|
|
202
|
+
coreSetupExportSource,
|
|
203
|
+
/video[^\n]*`not-requested`[^\n]*`user-requested`/i,
|
|
204
|
+
);
|
|
205
|
+
assert.match(
|
|
206
|
+
coreSetupExportSource,
|
|
207
|
+
/image[^\n]*`user-requested`[^\n]*non-empty[^\n]*evidence/i,
|
|
208
|
+
);
|
|
209
|
+
assert.match(
|
|
210
|
+
coreSetupExportSource,
|
|
211
|
+
/image[^\n]*`user-removed`[^\n]*non-empty[^\n]*evidence/i,
|
|
212
|
+
);
|
|
213
|
+
assert.match(
|
|
214
|
+
coreSetupExportSource,
|
|
215
|
+
/video[^\n]*`user-requested`[^\n]*non-empty[^\n]*evidence/i,
|
|
216
|
+
);
|
|
217
|
+
for (const decisionStep of [
|
|
218
|
+
"Start every product with image export.",
|
|
219
|
+
"Add video export only when the user explicitly requests video delivery.",
|
|
220
|
+
"Do not infer video from animation, playback, keyframes, or timeline.",
|
|
221
|
+
"Keep image with video unless the user explicitly requests removal.",
|
|
222
|
+
"Record in `productReadiness.exportIntent`.",
|
|
223
|
+
]) {
|
|
224
|
+
assert.equal(
|
|
225
|
+
coreSetupExportSource.split(decisionStep).length - 1,
|
|
226
|
+
1,
|
|
227
|
+
`Canonical export-intent step must appear exactly once: ${decisionStep}`,
|
|
228
|
+
);
|
|
229
|
+
}
|
|
220
230
|
assert.match(
|
|
221
231
|
coreSetupExportSource,
|
|
222
|
-
/
|
|
232
|
+
/Clipboard copy may be an additional product action, but it never changes or substitutes for the recorded artifact intent/,
|
|
223
233
|
);
|
|
224
|
-
assert.match(coreSetupExportSource, /Clipboard copy is optional and never replaces export/);
|
|
225
234
|
assert.match(coreSetupExportSource, /renderScaleCoverage/);
|
|
226
235
|
assert.match(coreSetupExportSource, /selected-backing-pixels/);
|
|
227
236
|
assert.match(coreSetupExportSource, /canvas-render-scale-backing/);
|
|
237
|
+
assert.match(coreSetupExportSource, /Mediabunny/);
|
|
238
|
+
assert.match(coreSetupExportSource, /fixed 30 FPS offline schedule/);
|
|
239
|
+
assert.match(coreSetupExportSource, /Product code must not instantiate `MediaRecorder` or `VideoEncoder`/);
|
|
240
|
+
assert.doesNotMatch(
|
|
241
|
+
coreSetupExportSource,
|
|
242
|
+
/createToolcraftPngExportCanvas|renderRuntimeSceneToCanvas|renderModelsToCanvas/,
|
|
243
|
+
);
|
|
244
|
+
assert.doesNotMatch(
|
|
245
|
+
coreMediaUploadSource,
|
|
246
|
+
/createToolcraftPngExportCanvas|renderRuntimeSceneToCanvas|renderModelsToCanvas/,
|
|
247
|
+
);
|
|
228
248
|
assert.match(
|
|
229
249
|
coreSetupExportSource,
|
|
230
250
|
/interaction[\s\S]*steady[\s\S]*playback[\s\S]*timeline/i,
|
|
@@ -236,6 +256,10 @@ export async function assertGeneratedDocs(targetDir) {
|
|
|
236
256
|
);
|
|
237
257
|
assert.match(assemblyDocsSource, /@\/toolcraft\/runtime/);
|
|
238
258
|
assert.match(assemblyDocsSource, /ToolcraftAppComposition/);
|
|
259
|
+
assert.match(
|
|
260
|
+
assemblyDocsSource,
|
|
261
|
+
/Every product declaration requires `productReadiness\.exportIntent`/,
|
|
262
|
+
);
|
|
239
263
|
assert.match(assemblyDocsSource, /protected route/);
|
|
240
264
|
assert.match(assemblyDocsSource, /transferMode: "reference-runtime-clone"/);
|
|
241
265
|
assert.match(assemblyDocsSource, /`canvasContent` must not contain app UI/);
|
|
@@ -249,6 +273,7 @@ export async function assertGeneratedDocs(targetDir) {
|
|
|
249
273
|
assert.match(acceptanceDocsSource, /automatedTestName/);
|
|
250
274
|
assert.match(acceptanceDocsSource, /browserTestName/);
|
|
251
275
|
assert.match(acceptanceDocsSource, /app-acceptance-data\.ts/);
|
|
276
|
+
assert.match(acceptanceDocsSource, /productReadiness\.exportIntent/);
|
|
252
277
|
assert.match(
|
|
253
278
|
acceptanceDocsSource,
|
|
254
279
|
/Contract docs are signed except product-owned `agent-worklog\.md` and optional `workflow-observation\.md`; only the observation stays outside `sourceHash`/,
|
|
@@ -269,6 +294,8 @@ export async function assertGeneratedDocs(targetDir) {
|
|
|
269
294
|
acceptanceDocsSource,
|
|
270
295
|
/export-content proof is distinct from export mechanics/i,
|
|
271
296
|
);
|
|
297
|
+
assert.match(acceptanceDocsSource, /actual encoded packet metadata/i);
|
|
298
|
+
assert.match(acceptanceDocsSource, /distinct decoded frame hashes/i);
|
|
272
299
|
assert.match(
|
|
273
300
|
acceptanceDocsSource,
|
|
274
301
|
/Each browser file owns one acceptance domain/i,
|
|
@@ -312,24 +339,14 @@ export async function assertGeneratedDocs(targetDir) {
|
|
|
312
339
|
path.join(targetDir, "docs/toolcraft/core/performance.md"),
|
|
313
340
|
"utf8",
|
|
314
341
|
);
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
[
|
|
322
|
-
|
|
323
|
-
["core/performance.md", corePerformanceDocsSource],
|
|
324
|
-
]) {
|
|
325
|
-
for (const marker of performanceLifecycleMarkers) {
|
|
326
|
-
assert.equal(
|
|
327
|
-
source.includes(marker),
|
|
328
|
-
true,
|
|
329
|
-
`docs/toolcraft/${docPath} must include canonical marker: ${marker}`,
|
|
330
|
-
);
|
|
331
|
-
}
|
|
332
|
-
}
|
|
342
|
+
assert.deepEqual(
|
|
343
|
+
getMissingGeneratedPerformanceLifecycleMarkers([
|
|
344
|
+
{ docPath: "workflow.md", source: workflowDocsSource },
|
|
345
|
+
{ docPath: "performance.md", source: performanceDocsSource },
|
|
346
|
+
{ docPath: "core/performance.md", source: corePerformanceDocsSource },
|
|
347
|
+
]),
|
|
348
|
+
[],
|
|
349
|
+
);
|
|
333
350
|
assert.match(rendererDocsSource, /rendererTechnique/);
|
|
334
351
|
assert.match(rendererDocsSource, /sourceRepresentation/);
|
|
335
352
|
assert.match(rendererDocsSource, /whyNotAlternativeStrategies/);
|
|
@@ -339,6 +356,7 @@ export async function assertGeneratedDocs(targetDir) {
|
|
|
339
356
|
assert.match(rendererDocsSource, /canonical paths/i);
|
|
340
357
|
assert.match(rendererDocsSource, /combined fixtures/i);
|
|
341
358
|
assert.match(rendererDocsSource, /modelPresentation/);
|
|
359
|
+
assert.match(rendererDocsSource, /ToolcraftAppComposition\.exportRenderer/);
|
|
342
360
|
assert.match(rendererDocsSource, /useToolcraftModelPresentationConsumer/);
|
|
343
361
|
assert.match(rendererDocsSource, /acquirePresentation/);
|
|
344
362
|
assert.match(rendererDocsSource, /lease\.release/);
|
|
@@ -367,12 +385,34 @@ export async function assertGeneratedDocs(targetDir) {
|
|
|
367
385
|
corePerformanceDocsSource,
|
|
368
386
|
/functional failure[\s\S]*without measured performance/i,
|
|
369
387
|
);
|
|
388
|
+
assert.match(corePerformanceDocsSource, /exact 30 FPS packet cadence[\s\S]*functional correctness/i);
|
|
389
|
+
assert.match(performanceDocsSource, /exact 30 FPS packet cadence[\s\S]*functional proof/i);
|
|
370
390
|
assert.match(performanceDocsSource, /coherent (?:user-visible )?delivery batch/i);
|
|
371
391
|
assert.match(performanceDocsSource, /verify:delivery/);
|
|
372
392
|
assert.match(performanceDocsSource, /immediately previous successful delivery/i);
|
|
373
393
|
assert.match(performanceDocsSource, /performance-iteration/);
|
|
374
394
|
assert.match(performanceDocsSource, /renderScaleCoverage/);
|
|
375
395
|
assert.match(performanceDocsSource, /canvas-render-scale-backing/);
|
|
396
|
+
assert.match(
|
|
397
|
+
performanceDocsSource,
|
|
398
|
+
/localized complaint[^\n]*without (?:a |asking the user)/iu,
|
|
399
|
+
);
|
|
400
|
+
assert.match(
|
|
401
|
+
performanceDocsSource,
|
|
402
|
+
/ambiguous complaint[\s\S]*one user-facing/iu,
|
|
403
|
+
);
|
|
404
|
+
assert.match(
|
|
405
|
+
performanceDocsSource,
|
|
406
|
+
/targeted diagnosis[\s\S]*complete (?:performance )?review/iu,
|
|
407
|
+
);
|
|
408
|
+
assert.match(
|
|
409
|
+
performanceDocsSource,
|
|
410
|
+
/every measured path[\s\S]*devicePixelRatio × 2/iu,
|
|
411
|
+
);
|
|
412
|
+
assert.match(
|
|
413
|
+
coreSetupExportSource,
|
|
414
|
+
/product code may customize only the slider step/iu,
|
|
415
|
+
);
|
|
376
416
|
assert.match(performanceDocsSource, /Use bare `npm run verify:delivery` once/i);
|
|
377
417
|
assert.match(
|
|
378
418
|
workflowDocsSource,
|
|
@@ -5,10 +5,54 @@ import path from "node:path";
|
|
|
5
5
|
import test from "node:test";
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
|
+
assertGeneratedExportIntentDocsDoNotInferVideo,
|
|
8
9
|
collectGeneratedAgentFacingDocs,
|
|
10
|
+
getMissingGeneratedPerformanceLifecycleMarkers,
|
|
9
11
|
getStaleAgentPerformanceWorkflowFailures,
|
|
10
12
|
} from "./generate-test-doc-assertions.mjs";
|
|
11
13
|
|
|
14
|
+
test("rejects animation-derived video rules without rejecting explicit authority", () => {
|
|
15
|
+
for (const source of [
|
|
16
|
+
[
|
|
17
|
+
"Products whose requested delivery includes",
|
|
18
|
+
"animation also expose",
|
|
19
|
+
"`Export Video`.",
|
|
20
|
+
].join(" "),
|
|
21
|
+
["Animated apps automatically show", "Export Video."].join(" "),
|
|
22
|
+
["Animation also", "requires", "Export Video."].join(" "),
|
|
23
|
+
"Timeline playback enables Export Video.",
|
|
24
|
+
"Animated apps automatically expose video export.",
|
|
25
|
+
"Timeline playback enables video export.",
|
|
26
|
+
"Animation implies video delivery.",
|
|
27
|
+
]) {
|
|
28
|
+
assert.throws(
|
|
29
|
+
() =>
|
|
30
|
+
assertGeneratedExportIntentDocsDoNotInferVideo([
|
|
31
|
+
{ docPath: "docs/toolcraft/stale.md", source },
|
|
32
|
+
]),
|
|
33
|
+
/docs\/toolcraft\/stale\.md contains animation-derived video export guidance/,
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
assert.doesNotThrow(() =>
|
|
38
|
+
assertGeneratedExportIntentDocsDoNotInferVideo([
|
|
39
|
+
{
|
|
40
|
+
docPath: "docs/toolcraft/allowed.md",
|
|
41
|
+
source: [
|
|
42
|
+
"Do not infer video from animation, playback, keyframes, or timeline.",
|
|
43
|
+
"Animation, playback, keyframes, and timeline presence never add Export Video.",
|
|
44
|
+
"Animated apps do not automatically expose video export.",
|
|
45
|
+
"Timeline playback never enables video export.",
|
|
46
|
+
"Animation does not imply video delivery.",
|
|
47
|
+
"An animated app includes Export Video because the user explicitly requested video delivery.",
|
|
48
|
+
"An animated app exposes video export because the user explicitly requested video delivery.",
|
|
49
|
+
"Any app with Export Video must enable the top Toolcraft timeline.",
|
|
50
|
+
].join("\n"),
|
|
51
|
+
},
|
|
52
|
+
]),
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
|
|
12
56
|
test("scans every generated agent-facing Markdown source independently", async (t) => {
|
|
13
57
|
const targetDir = await fs.mkdtemp(path.join(os.tmpdir(), "toolcraft-doc-scan-"));
|
|
14
58
|
t.after(() => fs.rm(targetDir, { force: true, recursive: true }));
|
|
@@ -41,3 +85,24 @@ test("scans every generated agent-facing Markdown source independently", async (
|
|
|
41
85
|
"docs/toolcraft/core/performance.md contains removed performance workflow guidance",
|
|
42
86
|
]);
|
|
43
87
|
});
|
|
88
|
+
|
|
89
|
+
test("requires adaptive routing in every generated performance lifecycle document", () => {
|
|
90
|
+
const routingMarker =
|
|
91
|
+
"<!-- toolcraft-performance-routing: localized=agent-targeted; ambiguous=one-user-facing-choice; broad=offer-targeted-or-full; full=explicit-only -->";
|
|
92
|
+
const existingMarkers = [
|
|
93
|
+
"<!-- toolcraft-performance-lifecycle: first-delivery=functional; later-delivery=functional-targeted; complaint=one-authority-targeted-performance-iteration; full-audit=explicit-only -->",
|
|
94
|
+
"<!-- toolcraft-performance-iteration: authority=exact-request-evidence+canonical-path-ids; fixture=reachable-development; after-pass=return-app-to-user+stop -->",
|
|
95
|
+
"<!-- toolcraft-performance-full-authority: automatic=forbidden; recommendation=two-compatible-iterations-or-broad-unlocalizable-problem; command=pnpm verify:perf; authority=explicit-user-request-or-accepted-offer -->",
|
|
96
|
+
].join("\n");
|
|
97
|
+
|
|
98
|
+
assert.deepEqual(
|
|
99
|
+
getMissingGeneratedPerformanceLifecycleMarkers([
|
|
100
|
+
{ docPath: "workflow.md", source: `${existingMarkers}\n${routingMarker}` },
|
|
101
|
+
{ docPath: "performance.md", source: existingMarkers },
|
|
102
|
+
{ docPath: "core/performance.md", source: `${existingMarkers}\n${routingMarker}` },
|
|
103
|
+
]),
|
|
104
|
+
[
|
|
105
|
+
`docs/toolcraft/performance.md must include canonical marker: ${routingMarker}`,
|
|
106
|
+
],
|
|
107
|
+
);
|
|
108
|
+
});
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
const staleAgentPerformanceWorkflowPattern =
|
|
6
|
+
/app-performance-impact|explicit-performance-work|test:browser:perf|verify:(?:final|quick|ui)|verify:perf:(?:playwright|record-iteration|refresh)|--reason=performance-iteration|--performance-test/iu;
|
|
7
|
+
|
|
8
|
+
const exportIntentSentencePatternSource = String.raw`[^\n.!?]`;
|
|
9
|
+
const videoArtifactTargetPatternSource = String.raw`(?:Export Video|video\s+(?:export|delivery))`;
|
|
10
|
+
const explicitVideoAuthorityPatternSource = String.raw`(?:explicit(?:ly)?\s+(?:(?:user[- ]?)?request(?:ed|s)?\s+)?${videoArtifactTargetPatternSource}|user\s+explicitly\s+request(?:ed|s)?\s+${videoArtifactTargetPatternSource}|user[- ]request(?:ed|s)?\s+${videoArtifactTargetPatternSource})`;
|
|
11
|
+
const animationInferenceVerbPatternSource = String.raw`(?:exposes?|includes?|shows?|adds?|enables?|implies?|has|needs?|requires?|produces?|proves?)`;
|
|
12
|
+
const staleAnimationInferencePatternSource = [
|
|
13
|
+
String.raw`products?\s+whose\s+requested\s+delivery\s+includes\s+animation`,
|
|
14
|
+
String.raw`animated\s+apps?\b(?!${exportIntentSentencePatternSource}{0,100}\b(?:do(?:es)?\s+not|never)\b)${exportIntentSentencePatternSource}{0,100}\b${animationInferenceVerbPatternSource}\b${exportIntentSentencePatternSource}{0,60}\b${videoArtifactTargetPatternSource}\b`,
|
|
15
|
+
String.raw`(?:animation|playback|keyframes?|timeline(?:\s+playback)?)\b\s+(?:also\s+)?${animationInferenceVerbPatternSource}\b${exportIntentSentencePatternSource}{0,60}\b${videoArtifactTargetPatternSource}\b`,
|
|
16
|
+
].join("|");
|
|
17
|
+
|
|
18
|
+
export const staleAnimationDerivedVideoPattern = new RegExp(
|
|
19
|
+
String.raw`(?:^|[\n.!?]\s*)(?!${exportIntentSentencePatternSource}{0,240}\b${explicitVideoAuthorityPatternSource}\b)${exportIntentSentencePatternSource}{0,240}(?:${staleAnimationInferencePatternSource})`,
|
|
20
|
+
"iu",
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const generatedPerformanceLifecycleMarkers = [
|
|
24
|
+
"<!-- toolcraft-performance-lifecycle: first-delivery=functional; later-delivery=functional-targeted; complaint=one-authority-targeted-performance-iteration; full-audit=explicit-only -->",
|
|
25
|
+
"<!-- toolcraft-performance-iteration: authority=exact-request-evidence+canonical-path-ids; fixture=reachable-development; after-pass=return-app-to-user+stop -->",
|
|
26
|
+
"<!-- toolcraft-performance-full-authority: automatic=forbidden; recommendation=two-compatible-iterations-or-broad-unlocalizable-problem; command=pnpm verify:perf; authority=explicit-user-request-or-accepted-offer -->",
|
|
27
|
+
"<!-- toolcraft-performance-routing: localized=agent-targeted; ambiguous=one-user-facing-choice; broad=offer-targeted-or-full; full=explicit-only -->",
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
export function getMissingGeneratedPerformanceLifecycleMarkers(sources) {
|
|
31
|
+
return sources.flatMap(({ docPath, source }) =>
|
|
32
|
+
generatedPerformanceLifecycleMarkers.flatMap((marker) =>
|
|
33
|
+
source.includes(marker)
|
|
34
|
+
? []
|
|
35
|
+
: [`docs/toolcraft/${docPath} must include canonical marker: ${marker}`],
|
|
36
|
+
),
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function collectMarkdownPaths(rootDir, relativeDir = "") {
|
|
41
|
+
const currentDir = path.join(rootDir, relativeDir);
|
|
42
|
+
const entries = await fs.readdir(currentDir, { withFileTypes: true });
|
|
43
|
+
const markdownPaths = [];
|
|
44
|
+
|
|
45
|
+
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
46
|
+
const relativePath = path.join(relativeDir, entry.name);
|
|
47
|
+
if (entry.isDirectory()) {
|
|
48
|
+
markdownPaths.push(...(await collectMarkdownPaths(rootDir, relativePath)));
|
|
49
|
+
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
50
|
+
markdownPaths.push(relativePath);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return markdownPaths;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function collectGeneratedAgentFacingDocs(targetDir) {
|
|
58
|
+
const docsRoot = path.join(targetDir, "docs/toolcraft");
|
|
59
|
+
const docPaths = await collectMarkdownPaths(docsRoot);
|
|
60
|
+
const docs = await Promise.all(
|
|
61
|
+
docPaths.map(async (docPath) => ({
|
|
62
|
+
docPath: path.posix.join("docs/toolcraft", docPath.split(path.sep).join("/")),
|
|
63
|
+
source: await fs.readFile(path.join(docsRoot, docPath), "utf8"),
|
|
64
|
+
})),
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
return [
|
|
68
|
+
{
|
|
69
|
+
docPath: "AGENTS.md",
|
|
70
|
+
source: await fs.readFile(path.join(targetDir, "AGENTS.md"), "utf8"),
|
|
71
|
+
},
|
|
72
|
+
...docs,
|
|
73
|
+
];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function getStaleAgentPerformanceWorkflowFailures(sources) {
|
|
77
|
+
return sources.flatMap(({ docPath, source }) =>
|
|
78
|
+
staleAgentPerformanceWorkflowPattern.test(source)
|
|
79
|
+
? [`${docPath} contains removed performance workflow guidance`]
|
|
80
|
+
: [],
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function assertGeneratedExportIntentDocsDoNotInferVideo(sources) {
|
|
85
|
+
for (const { docPath, source } of sources) {
|
|
86
|
+
assert.doesNotMatch(
|
|
87
|
+
source,
|
|
88
|
+
staleAnimationDerivedVideoPattern,
|
|
89
|
+
`${docPath} contains animation-derived video export guidance`,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
}
|