@pixel-point/toolcraft 0.0.17 → 0.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/generate-demand-only-lifecycle.test.mjs +9 -1
- package/src/generate-performance-iteration-execution.test.mjs +3 -3
- package/src/generate-test-delivery-architecture-assertions.mjs +11 -73
- package/src/generate-test-demand-only-lifecycle.mjs +34 -36
- package/src/generate-test-dependency-sandbox.mjs +4 -1
- package/src/generate-test-doc-assertions.mjs +81 -89
- package/src/generate-test-doc-assertions.test.mjs +44 -1
- package/src/generate-test-doc-policy-assertions.mjs +92 -0
- package/src/generate-test-export-doc-assertions.mjs +53 -0
- package/src/generate-test-file-assertions.mjs +77 -83
- package/src/generate-test-integrity-assertions.mjs +5 -2
- package/src/generate-test-integrity-manifest-assertions.mjs +16 -5
- package/src/generate-test-integrity-ownership-assertions.mjs +36 -4
- package/src/generate-test-package-assertions.mjs +4 -0
- package/src/generate-test-product-fixture.mjs +1 -1
- package/src/generate-test-product-fixture.test.mjs +35 -38
- package/src/generate-test-product-iteration.mjs +0 -1
- package/src/generate-test-product-iteration.test.mjs +17 -1
- package/src/generate-test-runtime-boundary-assertions.mjs +178 -0
- package/src/generate-test-standalone-assertions.mjs +7 -13
- package/src/generate-test-standalone-delivery-stages.mjs +2 -86
- package/src/generate.test.mjs +4 -0
- package/src/generated-integrity-manifest.test.mjs +5 -2
- package/src/generated-source-policy.test.mjs +0 -4
- package/src/package-json.mjs +5 -0
- package/src/package-json.test.mjs +21 -0
- package/src/package-manager.mjs +2 -0
- package/src/package-manager.test.mjs +8 -0
- package/src/packaged-template-fallback-helpers.mjs +254 -0
- package/src/packaged-template-fallback.test.mjs +121 -46
- package/src/packaged-template-runtime-assertions.mjs +150 -0
- package/templates/runtime/contracts/component-contracts.choices.test.ts +64 -5
- package/templates/runtime/contracts/component-contracts.choices.ts +55 -5
- package/templates/runtime/contracts/component-contracts.inputs.test.ts +6 -6
- package/templates/runtime/contracts/component-contracts.inputs.ts +8 -7
- 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 +22 -8
- package/templates/runtime/contracts/component-contracts.runtime-labels.test.ts +7 -1
- package/templates/runtime/contracts/component-contracts.runtime-panels.test.ts +3 -0
- package/templates/runtime/contracts/component-contracts.runtime-shell.test.ts +4 -1
- package/templates/runtime/contracts/component-contracts.runtime.ts +19 -12
- package/templates/runtime/contracts/component-contracts.test.ts +2 -0
- package/templates/runtime/contracts/component-contracts.visual.test.ts +20 -0
- package/templates/runtime/contracts/component-contracts.visual.ts +4 -0
- package/templates/runtime/contracts/decision-contracts.test.ts +35 -11
- package/templates/runtime/contracts/decision-contracts.ts +12 -12
- package/templates/runtime/contracts/performance-verification-policy.test.ts +12 -12
- package/templates/runtime/contracts/performance-verification-policy.ts +8 -8
- package/templates/runtime/export/artifact-download.ts +1 -0
- package/templates/runtime/export/artifact-frame-renderer.ts +2 -15
- package/templates/runtime/export/artifact-frame-state.ts +16 -0
- package/templates/runtime/export/artifact-scene-frame.test.ts +3 -3
- package/templates/runtime/export/artifact-scene-frame.ts +3 -3
- package/templates/runtime/export/export-background.ts +0 -19
- package/templates/runtime/export/export-error.ts +5 -0
- package/templates/runtime/export/export-renderer-coverage.ts +54 -0
- package/templates/runtime/export/export.test.ts +45 -42
- package/templates/runtime/export/image-artifact-export.ts +2 -2
- package/templates/runtime/export/index.ts +57 -16
- package/templates/runtime/export/product-export-renderer.test.ts +38 -4
- package/templates/runtime/export/product-export-renderer.ts +0 -41
- package/templates/runtime/export/product-svg-export-renderer.ts +21 -0
- package/templates/runtime/export/svg-artifact-export.test.ts +98 -0
- package/templates/runtime/export/svg-artifact-export.ts +120 -0
- package/templates/runtime/export/svg-document.test.ts +221 -0
- package/templates/runtime/export/svg-document.ts +400 -0
- package/templates/runtime/export/svg-policy.ts +47 -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.test.tsx +21 -1
- package/templates/runtime/react/app-shell/settings-transfer.test.ts +21 -0
- package/templates/runtime/react/app-shell/toolcraft-app.scene-export.test.tsx +75 -1
- package/templates/runtime/react/app-shell/toolcraft-app.tsx +24 -9
- package/templates/runtime/react/canvas/canvas-shell-interactions.test.tsx +30 -0
- package/templates/runtime/react/canvas/canvas-shell-pinch-interactions.test.tsx +155 -0
- package/templates/runtime/react/canvas/canvas-shell-rendering.test.tsx +77 -1
- package/templates/runtime/react/canvas/canvas-shell-test-utils.tsx +13 -1
- package/templates/runtime/react/canvas/canvas-shell.tsx +32 -6
- package/templates/runtime/react/canvas/canvas-viewport-geometry.ts +133 -0
- 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/canvas/use-canvas-viewport-interactions.ts +285 -36
- 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.color-applicability-layout.test.tsx +134 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.color-layout.test.tsx +16 -1
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.control-visibility.test.tsx +40 -19
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.render-isolation.test.tsx +2 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.scene-export-actions.test.tsx +40 -1
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.setup-controls.test.tsx +3 -3
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-collection.test.tsx +59 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-color-bank.test.tsx +67 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.vector-interaction.test.tsx +6 -6
- package/templates/runtime/react/controls-panel/actions/controls-panel-actions.ts +4 -6
- package/templates/runtime/react/controls-panel/actions/export-action-runner.ts +41 -6
- 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 +41 -10
- package/templates/runtime/react/controls-panel/layout/controls-panel-section.tsx +7 -4
- package/templates/runtime/react/controls-panel/renderers/controls-panel-action-renderer.tsx +2 -1
- package/templates/runtime/react/controls-panel/renderers/controls-panel-basic-renderers.tsx +2 -52
- 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-color-values.ts +1 -9
- package/templates/runtime/react/controls-panel/values/controls-panel-spatial-values.ts +7 -2
- 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-math.ts +9 -69
- 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/scene/scene-bounds.test.ts +23 -0
- package/templates/runtime/scene/scene-bounds.ts +31 -17
- package/templates/runtime/schema/app-capabilities.test.ts +4 -0
- package/templates/runtime/schema/artifact-export-actions.test.ts +47 -0
- package/templates/runtime/schema/artifact-export-actions.ts +49 -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-layout.ts +14 -9
- package/templates/runtime/schema/controls-panel-section-roundtrip.test.ts +59 -0
- 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-canvas.test.ts +16 -3
- package/templates/runtime/schema/define-toolcraft.source-collection.test.ts +79 -0
- package/templates/runtime/schema/runtime-setup-section.ts +24 -5
- package/templates/runtime/schema/types.ts +69 -13
- package/templates/runtime/state/canvas-background-state.ts +1 -16
- package/templates/runtime/state/canvas-state.ts +32 -20
- package/templates/runtime/state/control-value-codecs.test.ts +98 -0
- package/templates/runtime/state/control-value-codecs.ts +700 -0
- package/templates/runtime/state/control-value-normalization.test.ts +1 -1
- package/templates/runtime/state/control-value-normalization.ts +127 -135
- package/templates/runtime/state/controls-reducer.ts +26 -3
- package/templates/runtime/state/create-template-state.test.ts +30 -0
- package/templates/runtime/state/create-template-state.ts +52 -31
- package/templates/runtime/state/orientation-pose.ts +80 -0
- package/templates/runtime/state/persistence-control-values.test.ts +59 -0
- package/templates/runtime/state/reducer-controls.test.ts +45 -0
- package/templates/runtime/state/reducer-media-reset.test.ts +1 -1
- package/templates/runtime/state/reducer-timeline.test.ts +70 -0
- package/templates/runtime/state/timeline-reducer.ts +40 -2
- package/templates/runtime/testing/performance-schema-queries.ts +2 -2
- package/templates/starter/AGENTS.md +29 -28
- package/templates/starter/docs/toolcraft/README.md +6 -6
- package/templates/starter/docs/toolcraft/acceptance-testing.md +34 -48
- package/templates/starter/docs/toolcraft/agent-worklog.md +103 -1
- package/templates/starter/docs/toolcraft/assembly-workflow.md +16 -8
- package/templates/starter/docs/toolcraft/component-rules.md +9 -7
- package/templates/starter/docs/toolcraft/core/control-selection.md +9 -3
- package/templates/starter/docs/toolcraft/core/layout.md +13 -8
- package/templates/starter/docs/toolcraft/core/media-upload.md +3 -1
- package/templates/starter/docs/toolcraft/core/performance.md +8 -10
- package/templates/starter/docs/toolcraft/core/reference-study.md +80 -19
- package/templates/starter/docs/toolcraft/core/runtime-boundary.md +15 -3
- package/templates/starter/docs/toolcraft/core/setup-export.md +67 -11
- package/templates/starter/docs/toolcraft/custom-controls.md +6 -4
- package/templates/starter/docs/toolcraft/decision-contract.md +4 -2
- package/templates/starter/docs/toolcraft/performance.md +8 -10
- package/templates/starter/docs/toolcraft/renderer-technique.md +6 -2
- package/templates/starter/docs/toolcraft/schema-reference.md +24 -22
- package/templates/starter/docs/toolcraft/workflow.md +14 -14
- package/templates/starter/e2e/app-browser-control-applicability-requirements.spec.ts +163 -0
- package/templates/starter/e2e/app-browser-infinity-canvas-evidence.spec.ts +45 -2
- package/templates/starter/e2e/app-browser-motion-reference-requirements.spec.ts +411 -0
- package/templates/starter/e2e/app-browser-orientation-evidence.spec.ts +174 -21
- package/templates/starter/e2e/app-browser-proof-session.spec.ts +85 -0
- package/templates/starter/e2e/app-browser-runtime-requirements.spec.ts +63 -33
- package/templates/starter/e2e/app-browser-selection-scope-evidence.spec.ts +137 -0
- package/templates/starter/e2e/app-browser-semantic-evidence.spec.ts +61 -15
- 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 +20 -11
- package/templates/starter/e2e/browser-infinity-canvas-svg-evidence.ts +42 -0
- package/templates/starter/e2e/browser-layer-evidence-helpers.ts +15 -36
- 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-product-raster-snapshot.ts +213 -0
- package/templates/starter/e2e/browser-proof-session.ts +43 -15
- package/templates/starter/e2e/browser-proof-surface-action.ts +79 -0
- package/templates/starter/e2e/browser-proof-types.ts +15 -0
- package/templates/starter/e2e/browser-runtime-applicability-requirements.ts +84 -0
- package/templates/starter/e2e/browser-runtime-evidence-reporter.ts +9 -2
- package/templates/starter/e2e/browser-runtime-evidence-requirements.ts +51 -32
- package/templates/starter/e2e/browser-selection-scope-evidence.ts +269 -0
- package/templates/starter/e2e/browser-semantic-evidence-test-helpers.ts +122 -0
- package/templates/starter/e2e/browser-svg-export-evidence.spec.ts +79 -0
- package/templates/starter/e2e/browser-svg-export-evidence.ts +152 -0
- package/templates/starter/e2e/export-artifact-helpers.ts +70 -0
- package/templates/starter/e2e/product-observable-helpers.ts +8 -129
- package/templates/starter/e2e/svg-artifact-inspection.spec.ts +136 -0
- package/templates/starter/e2e/svg-artifact-inspection.ts +331 -0
- package/templates/starter/e2e/svg-download-test-fixtures.ts +34 -0
- package/templates/starter/e2e/toolcraft-delivery-catalog-reporter.ts +198 -15
- package/templates/starter/e2e/toolcraft-feature-verification-reporter.spec.ts +149 -0
- package/templates/starter/e2e/toolcraft-feature-verification-reporter.ts +223 -0
- package/templates/starter/package.json +2 -0
- package/templates/starter/scripts/check-toolcraft-docs.mjs +1 -0
- package/templates/starter/scripts/create-toolcraft-motion-reference-study.mjs +233 -0
- package/templates/starter/scripts/create-toolcraft-motion-reference-study.test.mjs +459 -0
- package/templates/starter/scripts/playwright-test-title-selection.d.mts +45 -0
- package/templates/starter/scripts/run-browser-performance-test-helpers.mjs +0 -27
- package/templates/starter/scripts/run-browser-performance.mjs +0 -6
- package/templates/starter/scripts/run-browser-performance.test.mjs +5 -13
- package/templates/starter/scripts/run-delivery-verification-test-helpers.mjs +0 -34
- package/templates/starter/scripts/run-delivery-verification.test.mjs +135 -31
- package/templates/starter/scripts/run-feature-verification.mjs +212 -0
- package/templates/starter/scripts/run-feature-verification.test.mjs +226 -0
- package/templates/starter/scripts/toolcraft-checkpoint-delivery-state.mjs +21 -8
- package/templates/starter/scripts/toolcraft-checkpoint-delivery-state.test.mjs +32 -92
- package/templates/starter/scripts/toolcraft-checkpoint-transaction.mjs +28 -6
- package/templates/starter/scripts/toolcraft-checkpoint-transaction.test.mjs +8 -63
- package/templates/starter/scripts/toolcraft-contract-manifest.json +1 -0
- package/templates/starter/scripts/toolcraft-delivery-anchor.mjs +28 -8
- package/templates/starter/scripts/toolcraft-delivery-anchor.test.mjs +50 -61
- package/templates/starter/scripts/toolcraft-delivery-architecture-inventory.mjs +0 -4
- package/templates/starter/scripts/toolcraft-delivery-architecture-policy.mjs +0 -1
- package/templates/starter/scripts/toolcraft-delivery-evidence.test.mjs +2 -3
- package/templates/starter/scripts/toolcraft-delivery-executor.mjs +5 -1
- package/templates/starter/scripts/toolcraft-delivery-executor.test.mjs +5 -12
- package/templates/starter/scripts/toolcraft-delivery-functional-context.d.mts +1 -48
- package/templates/starter/scripts/toolcraft-delivery-functional-context.mjs +2 -30
- package/templates/starter/scripts/toolcraft-delivery-functional-context.test.mjs +4 -166
- package/templates/starter/scripts/toolcraft-delivery-functional-initial.test.mjs +4 -20
- package/templates/starter/scripts/toolcraft-delivery-lifecycle.mjs +43 -192
- package/templates/starter/scripts/toolcraft-delivery-performance-iteration-lifecycle.test.mjs +79 -440
- package/templates/starter/scripts/toolcraft-delivery-plan-authority.test.mjs +102 -297
- package/templates/starter/scripts/toolcraft-delivery-plan-construction.mjs +46 -97
- package/templates/starter/scripts/toolcraft-delivery-plan-test-helpers.mjs +125 -0
- package/templates/starter/scripts/toolcraft-delivery-plan-validation.test.mjs +58 -0
- package/templates/starter/scripts/toolcraft-delivery-plan.d.mts +19 -31
- package/templates/starter/scripts/toolcraft-delivery-plan.mjs +254 -252
- package/templates/starter/scripts/toolcraft-delivery-plan.test.mjs +29 -457
- package/templates/starter/scripts/toolcraft-delivery-receipt-performance.test.mjs +1 -1
- package/templates/starter/scripts/toolcraft-delivery-receipt-strictness.test.mjs +3 -72
- package/templates/starter/scripts/toolcraft-delivery-receipt-test-helpers.mjs +7 -36
- package/templates/starter/scripts/toolcraft-delivery-receipt.d.mts +3 -5
- package/templates/starter/scripts/toolcraft-delivery-receipt.mjs +15 -31
- package/templates/starter/scripts/toolcraft-delivery-receipt.test.mjs +28 -20
- package/templates/starter/scripts/toolcraft-delivery-receipt.types.test.mts +22 -30
- package/templates/starter/scripts/toolcraft-feature-verification-plan.d.mts +20 -0
- package/templates/starter/scripts/toolcraft-feature-verification-plan.mjs +146 -0
- package/templates/starter/scripts/toolcraft-feature-verification-plan.test.mjs +96 -0
- package/templates/starter/scripts/toolcraft-functional-proof-model.d.mts +3 -18
- package/templates/starter/scripts/toolcraft-functional-proof-model.mjs +39 -127
- package/templates/starter/scripts/toolcraft-functional-proof-model.test.mjs +25 -362
- package/templates/starter/scripts/toolcraft-functional-proof-model.types.test.mts +6 -83
- package/templates/starter/scripts/toolcraft-functional-proof-primitives.d.mts +11 -0
- package/templates/starter/scripts/toolcraft-functional-proof-primitives.mjs +61 -0
- package/templates/starter/scripts/toolcraft-functional-proof-primitives.test.mjs +43 -0
- package/templates/starter/scripts/toolcraft-integrity-policy.mjs +13 -0
- package/templates/starter/scripts/toolcraft-integrity-test-utils.mjs +1 -1
- package/templates/starter/scripts/toolcraft-layer-evidence-facade.test.mjs +58 -22
- package/templates/starter/scripts/toolcraft-motion-reference-analysis-protocol.mjs +111 -0
- package/templates/starter/scripts/toolcraft-motion-reference-analysis-protocol.test.mjs +116 -0
- package/templates/starter/scripts/toolcraft-motion-reference-artifacts.d.mts +37 -0
- package/templates/starter/scripts/toolcraft-motion-reference-artifacts.mjs +308 -0
- package/templates/starter/scripts/toolcraft-motion-reference-artifacts.test.mjs +420 -0
- package/templates/starter/scripts/toolcraft-motion-reference-artifacts.types.test.mts +50 -0
- package/templates/starter/scripts/toolcraft-motion-reference-command-options.mjs +195 -0
- package/templates/starter/scripts/toolcraft-motion-reference-command-options.test.mjs +224 -0
- package/templates/starter/scripts/toolcraft-motion-reference-contact-sheet.mjs +122 -0
- package/templates/starter/scripts/toolcraft-motion-reference-contact-sheet.test.mjs +153 -0
- package/templates/starter/scripts/toolcraft-motion-reference-evidence-assembly.mjs +270 -0
- package/templates/starter/scripts/toolcraft-motion-reference-evidence.test.mjs +432 -0
- package/templates/starter/scripts/toolcraft-motion-reference-ffmpeg-output.mjs +275 -0
- package/templates/starter/scripts/toolcraft-motion-reference-ffmpeg-output.test.mjs +294 -0
- package/templates/starter/scripts/toolcraft-motion-reference-group-inventory.mjs +148 -0
- package/templates/starter/scripts/toolcraft-motion-reference-image-filter-graph.mjs +101 -0
- package/templates/starter/scripts/toolcraft-motion-reference-image-filter-graph.test.mjs +124 -0
- package/templates/starter/scripts/toolcraft-motion-reference-image-source.mjs +259 -0
- package/templates/starter/scripts/toolcraft-motion-reference-image-source.test.mjs +338 -0
- package/templates/starter/scripts/toolcraft-motion-reference-image-timing.mjs +96 -0
- package/templates/starter/scripts/toolcraft-motion-reference-image-timing.test.mjs +81 -0
- package/templates/starter/scripts/toolcraft-motion-reference-lock-recovery.test.mjs +144 -0
- package/templates/starter/scripts/toolcraft-motion-reference-media-source.mjs +165 -0
- package/templates/starter/scripts/toolcraft-motion-reference-media-source.test.mjs +299 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication-discovery.test.mjs +142 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication-isolation.test.mjs +234 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication-journal-schema.mjs +122 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication-journal-store.mjs +89 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication-journal-store.test.mjs +74 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication-journal.mjs +264 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication-journal.test.mjs +377 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication-lease.mjs +254 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication-lease.test.mjs +130 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication-staging.mjs +128 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication-staging.test.mjs +209 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication.fixtures.mjs +88 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication.mjs +249 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication.test.mjs +433 -0
- package/templates/starter/scripts/toolcraft-motion-reference-review-output.mjs +38 -0
- package/templates/starter/scripts/toolcraft-motion-reference-review-output.test.mjs +29 -0
- package/templates/starter/scripts/toolcraft-motion-reference-root-safety.test.mjs +84 -0
- package/templates/starter/scripts/toolcraft-motion-reference-roots.mjs +83 -0
- package/templates/starter/scripts/toolcraft-motion-reference-sampling.mjs +283 -0
- package/templates/starter/scripts/toolcraft-motion-reference-sampling.test.mjs +480 -0
- package/templates/starter/scripts/toolcraft-motion-reference-stage-registry.mjs +39 -0
- package/templates/starter/scripts/toolcraft-motion-reference-stage-registry.test.mjs +59 -0
- package/templates/starter/scripts/toolcraft-motion-reference-stage.mjs +71 -0
- package/templates/starter/scripts/toolcraft-motion-reference-stage.test.mjs +61 -0
- package/templates/starter/scripts/toolcraft-motion-review-numeric.mjs +74 -0
- package/templates/starter/scripts/toolcraft-motion-review-numeric.test.mjs +65 -0
- package/templates/starter/scripts/toolcraft-motion-review-partitioning.mjs +268 -0
- package/templates/starter/scripts/toolcraft-motion-review-partitioning.test.mjs +329 -0
- package/templates/starter/scripts/toolcraft-motion-review-protected-units.mjs +120 -0
- package/templates/starter/scripts/toolcraft-motion-review-protected-units.test.mjs +111 -0
- package/templates/starter/scripts/toolcraft-performance-escalation-policy.test.mjs +77 -345
- package/templates/starter/scripts/toolcraft-performance-receipt-validation.test.mjs +19 -21
- package/templates/starter/scripts/toolcraft-product-boundary-ast.mjs +85 -115
- package/templates/starter/scripts/toolcraft-product-boundary-module-policy.mjs +101 -0
- package/templates/starter/scripts/toolcraft-product-boundary.test.mjs +0 -72
- 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-export-boundary.mjs +16 -18
- package/templates/starter/scripts/toolcraft-product-export-boundary.test.mjs +200 -0
- package/templates/starter/scripts/toolcraft-product-observable-facade.test.mjs +46 -1
- package/templates/starter/scripts/toolcraft-receipt-boundary.test.mjs +0 -1
- package/templates/starter/scripts/toolcraft-source-inventory.d.mts +5 -0
- package/templates/starter/scripts/toolcraft-source-inventory.mjs +25 -14
- package/templates/starter/scripts/toolcraft-source-inventory.test.mjs +48 -0
- package/templates/starter/scripts/toolcraft-source-ownership.mjs +0 -1
- package/templates/starter/scripts/toolcraft-source-ownership.test.mjs +30 -5
- 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.mjs +2 -0
- package/templates/starter/scripts/toolcraft-verification-receipt-test-helpers.mjs +5 -26
- package/templates/starter/scripts/toolcraft-verification-receipt.d.mts +0 -7
- package/templates/starter/scripts/toolcraft-verification-receipt.mjs +3 -47
- package/templates/starter/scripts/toolcraft-verification-receipt.test.mjs +6 -87
- package/templates/starter/scripts/toolcraft-vitest-runtime-contract.d.mts +19 -0
- package/templates/starter/scripts/toolcraft-vitest-runtime-contract.mjs +107 -0
- package/templates/starter/scripts/toolcraft-vitest-runtime-contract.test.mjs +114 -0
- package/templates/starter/scripts/toolcraft-vitest-runtime-evidence-reporter.mjs +13 -2
- package/templates/starter/scripts/toolcraft-vitest-runtime-evidence-reporter.test.mjs +110 -0
- package/templates/starter/src/app/acceptance/artifact-export-intent.ts +161 -0
- package/templates/starter/src/app/acceptance/canvas-coverage.ts +1 -0
- package/templates/starter/src/app/acceptance/color-bank-labels.ts +11 -15
- package/templates/starter/src/app/acceptance/color-row-grouping.ts +33 -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 -31
- package/templates/starter/src/app/acceptance/control-acceptance-kind-rules.ts +24 -5
- package/templates/starter/src/app/acceptance/control-acceptance-policy.ts +4 -16
- 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-component-rules.ts +0 -10
- package/templates/starter/src/app/acceptance/control-labels.ts +30 -1
- 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 +21 -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 +25 -17
- package/templates/starter/src/app/acceptance/feature-verification-selection.test.ts +295 -0
- package/templates/starter/src/app/acceptance/feature-verification-selection.ts +161 -0
- package/templates/starter/src/app/acceptance/infinity-canvas.ts +10 -0
- package/templates/starter/src/app/acceptance/inline-layout.ts +64 -9
- package/templates/starter/src/app/acceptance/interaction-ownership-intent.ts +19 -1
- package/templates/starter/src/app/acceptance/interaction-ownership.ts +18 -2
- package/templates/starter/src/app/acceptance/media-upload.ts +5 -1
- package/templates/starter/src/app/acceptance/motion-reference-evidence-validation.mjs +65 -0
- package/templates/starter/src/app/acceptance/motion-reference-evidence-windows.mjs +301 -0
- package/templates/starter/src/app/acceptance/motion-reference-evidence.d.mts +11 -0
- package/templates/starter/src/app/acceptance/motion-reference-evidence.mjs +145 -0
- package/templates/starter/src/app/acceptance/motion-reference-study-behaviors.ts +162 -0
- package/templates/starter/src/app/acceptance/motion-reference-study-coverage.ts +206 -0
- package/templates/starter/src/app/acceptance/motion-reference-study-identity.ts +129 -0
- package/templates/starter/src/app/acceptance/motion-reference-study-partitions.ts +186 -0
- package/templates/starter/src/app/acceptance/motion-reference-study.ts +90 -0
- 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-actions.test.ts +9 -1
- package/templates/starter/src/app/acceptance/output-export-actions.ts +14 -22
- package/templates/starter/src/app/acceptance/output-export-layout-rules.ts +22 -10
- package/templates/starter/src/app/acceptance/output-export-model.ts +58 -11
- package/templates/starter/src/app/acceptance/output-export.ts +25 -10
- package/templates/starter/src/app/acceptance/output-video-export-rules.ts +99 -0
- package/templates/starter/src/app/acceptance/reference-study-types.ts +167 -17
- package/templates/starter/src/app/acceptance/runtime-coverage.ts +6 -1
- package/templates/starter/src/app/acceptance/selection-scope.test.ts +200 -0
- package/templates/starter/src/app/acceptance/selection-scope.ts +151 -0
- package/templates/starter/src/app/acceptance/transfer-mode-types.ts +114 -0
- package/templates/starter/src/app/acceptance/types.ts +65 -125
- package/templates/starter/src/app/acceptance/validate-coverage.ts +33 -5
- package/templates/starter/src/app/starter-acceptance-data.ts +1 -0
- package/templates/starter/src/app/starter-acceptance.animation-intent.test.ts +3 -0
- package/templates/starter/src/app/starter-acceptance.artifact-export-intent.test.ts +312 -0
- package/templates/starter/src/app/starter-acceptance.background-export.test.ts +35 -0
- package/templates/starter/src/app/starter-acceptance.canvas-sizing.test.ts +18 -1
- package/templates/starter/src/app/starter-acceptance.color-row-grouping.test.ts +118 -0
- package/templates/starter/src/app/starter-acceptance.compound-part-coverage.test.ts +66 -1
- package/templates/starter/src/app/starter-acceptance.contract-fixtures.test.ts +41 -0
- package/templates/starter/src/app/starter-acceptance.contract-fixtures.ts +113 -16
- package/templates/starter/src/app/starter-acceptance.control-applicability.test.ts +225 -0
- package/templates/starter/src/app/starter-acceptance.control-label-context.test.ts +1 -0
- package/templates/starter/src/app/starter-acceptance.control-labels.test.ts +78 -3
- package/templates/starter/src/app/starter-acceptance.control-naming-rules.test.ts +77 -1
- 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-fit-check.test.ts +1 -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 +74 -3
- package/templates/starter/src/app/starter-acceptance.export-test-utils.ts +26 -0
- package/templates/starter/src/app/{starter-acceptance.image-video-export-settings.test.ts → starter-acceptance.image-export-settings.test.ts} +39 -9
- package/templates/starter/src/app/starter-acceptance.interaction-ownership.test.ts +31 -3
- package/templates/starter/src/app/starter-acceptance.layers.test.ts +2 -1
- package/templates/starter/src/app/starter-acceptance.media-upload.fixtures.ts +11 -1
- package/templates/starter/src/app/starter-acceptance.media-upload.test.ts +56 -0
- package/templates/starter/src/app/starter-acceptance.motion-reference-evidence.test.ts +17 -0
- package/templates/starter/src/app/starter-acceptance.motion-reference-identity.test.ts +163 -0
- package/templates/starter/src/app/starter-acceptance.motion-reference-mapping.test.ts +133 -0
- package/templates/starter/src/app/starter-acceptance.motion-reference-ownership.test.ts +121 -0
- package/templates/starter/src/app/starter-acceptance.motion-reference-partitions.test.ts +210 -0
- package/templates/starter/src/app/starter-acceptance.motion-reference-test-utils.ts +313 -0
- package/templates/starter/src/app/starter-acceptance.output-export-intent.test.ts +458 -0
- package/templates/starter/src/app/starter-acceptance.output-export-rules.test.ts +4 -0
- package/templates/starter/src/app/starter-acceptance.product-output-export.test.ts +116 -104
- package/templates/starter/src/app/starter-acceptance.product-readiness.test.ts +29 -0
- package/templates/starter/src/app/starter-acceptance.product-worklog.test.ts +123 -2
- package/templates/starter/src/app/starter-acceptance.reference-custom-timeline.test.ts +2 -0
- package/templates/starter/src/app/starter-acceptance.reference-foundation.test.ts +8 -0
- package/templates/starter/src/app/starter-acceptance.reference-timeline.test.ts +7 -0
- package/templates/starter/src/app/starter-acceptance.section-cohesion.test.ts +3 -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.timeline-playback.test.ts +5 -0
- package/templates/starter/src/app/starter-acceptance.ts +45 -10
- package/templates/starter/src/app/starter-acceptance.video-export-settings.test.ts +338 -0
- package/templates/starter/src/app/starter-acceptance.video-reference-study.test.ts +34 -236
- package/templates/starter/src/app/starter-acceptance.view-interaction.test.ts +12 -0
- package/templates/starter/src/app/starter-acceptance.worklog-test-utils.ts +122 -6
- package/templates/starter/src/app/starter-acceptance.worklog.test.ts +152 -16
- package/templates/starter/src/app/starter-performance.gates.test.ts +20 -18
- package/templates/starter/src/app/starter-performance.lifecycle.test.ts +22 -6
- package/templates/starter/src/app/test-evidence/browser-runtime-contract.ts +5 -2
- package/templates/starter/src/routes/index.tsx +1 -0
- package/templates/starter/tsconfig.json +1 -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/starter/scripts/toolcraft-browser-impact-selection.mjs +0 -26
- package/templates/starter/scripts/toolcraft-delivery-framework-refresh.test.mjs +0 -141
- package/templates/starter/scripts/toolcraft-delivery-functional-changed.test.mjs +0 -468
- package/templates/starter/scripts/toolcraft-delivery-functional-model-lifecycle.test.mjs +0 -254
- package/templates/starter/scripts/toolcraft-delivery-functional-semantic-regression.test.mjs +0 -135
- package/templates/starter/scripts/toolcraft-delivery-performance-iteration-durability.test.mjs +0 -329
- package/templates/starter/scripts/toolcraft-delivery-plan-errors.test.mjs +0 -430
- package/templates/starter/scripts/toolcraft-delivery-plan-functional-model.test.mjs +0 -358
- package/templates/starter/scripts/toolcraft-functional-proof-regression-fixtures.mjs +0 -298
- package/templates/starter/scripts/toolcraft-verification-impact-inventory.d.mts +0 -62
- package/templates/starter/scripts/toolcraft-verification-impact-inventory.mjs +0 -344
- package/templates/starter/scripts/toolcraft-verification-impact-inventory.test.mjs +0 -204
- package/templates/starter/scripts/toolcraft-verification-impact-performance-candidates.test.mjs +0 -210
- package/templates/starter/scripts/toolcraft-verification-impact-resolution.mjs +0 -344
- package/templates/starter/scripts/toolcraft-verification-impact-resolution.test.mjs +0 -270
- package/templates/starter/scripts/toolcraft-verification-impact-semantic-resolution.test.mjs +0 -449
- package/templates/starter/scripts/toolcraft-verification-impact-support-resolution.test.mjs +0 -195
- package/templates/starter/scripts/toolcraft-verification-impact.d.mts +0 -132
- package/templates/starter/scripts/toolcraft-verification-impact.mjs +0 -169
- package/templates/starter/scripts/toolcraft-verification-impact.test.mjs +0 -300
- package/templates/starter/scripts/toolcraft-verification-input-roles.mjs +0 -197
- package/templates/starter/scripts/toolcraft-verification-input-roles.test.mjs +0 -225
- package/templates/starter/src/app/acceptance/condition-exclusivity.test.ts +0 -60
- package/templates/starter/src/app/acceptance/condition-exclusivity.ts +0 -221
- package/templates/starter/src/app/acceptance/video-reference-study.ts +0 -217
- package/templates/starter/src/app/starter-verification-impact.json +0 -15
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ToolcraftControlConditionSchema,
|
|
3
|
-
|
|
3
|
+
ResolvedToolcraftControlSchema,
|
|
4
|
+
} from "@repo/toolcraft-runtime";
|
|
5
|
+
import {
|
|
6
|
+
getToolcraftApplicabilityPredicates,
|
|
4
7
|
} from "@repo/toolcraft-runtime";
|
|
5
8
|
|
|
6
9
|
import type { ToolcraftControlLayoutFacts } from "./control-layout-model";
|
|
@@ -17,7 +20,7 @@ function normalizeToolcraftConditionValue(value: unknown): string | null {
|
|
|
17
20
|
|
|
18
21
|
function getToolcraftConditionBranchTexts(
|
|
19
22
|
condition: ToolcraftControlConditionSchema,
|
|
20
|
-
gateControl:
|
|
23
|
+
gateControl: ResolvedToolcraftControlSchema,
|
|
21
24
|
): string[] {
|
|
22
25
|
const rawValues =
|
|
23
26
|
"equals" in condition
|
|
@@ -44,7 +47,7 @@ function sectionTitleLooksLikeDependencyBranch({
|
|
|
44
47
|
sectionTitle,
|
|
45
48
|
}: {
|
|
46
49
|
condition: ToolcraftControlConditionSchema;
|
|
47
|
-
gateControl:
|
|
50
|
+
gateControl: ResolvedToolcraftControlSchema;
|
|
48
51
|
sectionTitle: string | undefined;
|
|
49
52
|
}): boolean {
|
|
50
53
|
const sectionText = normalizeToolcraftSemanticText(sectionTitle);
|
|
@@ -68,10 +71,18 @@ export function getToolcraftControlDependencyGroupingErrors(
|
|
|
68
71
|
const errors: string[] = [];
|
|
69
72
|
|
|
70
73
|
for (const item of facts.visibleControls) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
const conditions = [
|
|
75
|
+
...getToolcraftApplicabilityPredicates(
|
|
76
|
+
item.control.applicability,
|
|
77
|
+
).map(
|
|
78
|
+
(condition) => ["applicability", condition] as const,
|
|
79
|
+
),
|
|
80
|
+
...(item.control.disabledWhen
|
|
81
|
+
? [["disabledWhen", item.control.disabledWhen] as const]
|
|
82
|
+
: []),
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
for (const [conditionName, condition] of conditions) {
|
|
75
86
|
if (!condition || !item.loosePrefix) {
|
|
76
87
|
continue;
|
|
77
88
|
}
|
|
@@ -86,7 +97,7 @@ export function getToolcraftControlDependencyGroupingErrors(
|
|
|
86
97
|
gateControl.loosePrefix !== null &&
|
|
87
98
|
gateControl.loosePrefix === item.loosePrefix;
|
|
88
99
|
const looksLikeBranchSection =
|
|
89
|
-
conditionName === "
|
|
100
|
+
conditionName === "applicability" &&
|
|
90
101
|
sectionTitleLooksLikeDependencyBranch({
|
|
91
102
|
condition,
|
|
92
103
|
gateControl: gateControl.control,
|
|
@@ -98,7 +109,7 @@ export function getToolcraftControlDependencyGroupingErrors(
|
|
|
98
109
|
}
|
|
99
110
|
|
|
100
111
|
errors.push(
|
|
101
|
-
`${item.sectionLabel} / ${item.controlId} is gated by ${conditionName} target "${condition.target}" in ${gateControl.sectionLabel}, but it belongs to the same dependency group. Keep selectors and their dependent controls in one semantic section when they describe one product entity or branch; use
|
|
112
|
+
`${item.sectionLabel} / ${item.controlId} is gated by ${conditionName} target "${condition.target}" in ${gateControl.sectionLabel}, but it belongs to the same dependency group. Keep selectors and their dependent controls in one semantic section when they describe one product entity or branch; use conditional applicability for branch-specific controls inside that section instead of splitting branch controls into their own section. Do not use disabledWhen for product controls.`,
|
|
102
113
|
);
|
|
103
114
|
}
|
|
104
115
|
}
|
|
@@ -2,10 +2,8 @@ import {
|
|
|
2
2
|
getToolcraftFontPickerOwnedTypographyPart,
|
|
3
3
|
} from "./control-labels";
|
|
4
4
|
import type { ToolcraftControlLayoutFacts } from "./control-layout-model";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
hasToolcraftInventorySplitEvidence,
|
|
8
|
-
} from "./control-section-inventory";
|
|
5
|
+
import { hasToolcraftInventoryEntityAgreement } from "./control-section-entity-cohesion";
|
|
6
|
+
import { getToolcraftSectionInventoryById } from "./control-section-inventory";
|
|
9
7
|
import { getControlLabelText } from "./controls";
|
|
10
8
|
import type { ToolcraftControlSectionInventoryEntry } from "./types";
|
|
11
9
|
|
|
@@ -60,13 +58,13 @@ function getToolcraftProductEntitySplitErrors({
|
|
|
60
58
|
for (const [prefix, sections] of facts.strictPrefixSections) {
|
|
61
59
|
if (
|
|
62
60
|
sections.size > 1 &&
|
|
63
|
-
!
|
|
61
|
+
!hasToolcraftInventoryEntityAgreement({ sectionInventoryById, sections })
|
|
64
62
|
) {
|
|
65
63
|
const sectionLabels = [...sections].map(
|
|
66
64
|
(sectionId) => facts.sectionLabelsById.get(sectionId) ?? sectionId,
|
|
67
65
|
);
|
|
68
66
|
errors.push(
|
|
69
|
-
`Controls for
|
|
67
|
+
`Controls for target family "${prefix}" are split across sections: ${sectionLabels.join(", ")}. Assign one shared entityId when the sections edit one logical entity; the entity cohesion validator decides whether that split is allowed.`,
|
|
70
68
|
);
|
|
71
69
|
}
|
|
72
70
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ResolvedToolcraftAppSchema,
|
|
3
|
-
|
|
3
|
+
ResolvedToolcraftControlSchema,
|
|
4
4
|
} from "@repo/toolcraft-runtime";
|
|
5
5
|
|
|
6
6
|
import { isToolcraftProductSectionControl } from "./controls";
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from "./semantic";
|
|
13
13
|
|
|
14
14
|
export type ToolcraftControlLayoutControlEntry = {
|
|
15
|
-
control:
|
|
15
|
+
control: ResolvedToolcraftControlSchema;
|
|
16
16
|
controlId: string;
|
|
17
17
|
loosePrefix: string | null;
|
|
18
18
|
sectionLabel: string;
|
|
@@ -21,7 +21,7 @@ export type ToolcraftControlLayoutControlEntry = {
|
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
export type ToolcraftControlLayoutSectionFact = {
|
|
24
|
-
controls: readonly [string,
|
|
24
|
+
controls: readonly [string, ResolvedToolcraftControlSchema][];
|
|
25
25
|
sectionLabel: string;
|
|
26
26
|
sectionId: string;
|
|
27
27
|
sectionLoosePrefixes: ReadonlySet<string>;
|
|
@@ -41,7 +41,7 @@ export type ToolcraftControlLayoutFacts = {
|
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
function getToolcraftControlSemanticCluster(
|
|
44
|
-
control:
|
|
44
|
+
control: ResolvedToolcraftControlSchema,
|
|
45
45
|
): string {
|
|
46
46
|
return (
|
|
47
47
|
control.semanticGroup?.trim() ||
|
|
@@ -2,11 +2,14 @@ import {
|
|
|
2
2
|
getToolcraftColorBankDescriptionError,
|
|
3
3
|
getToolcraftColorBankLabelErrors,
|
|
4
4
|
} from "./color-bank-labels";
|
|
5
|
+
import { getToolcraftColorRowGroupingErrors } from "./color-row-grouping";
|
|
5
6
|
import {
|
|
6
7
|
getToolcraftControlDescriptionError,
|
|
8
|
+
getToolcraftDuplicateSectionTitleLabelError,
|
|
7
9
|
getToolcraftGenericControlLabelError,
|
|
8
10
|
} from "./control-labels";
|
|
9
11
|
import type { ToolcraftControlLayoutFacts } from "./control-layout-model";
|
|
12
|
+
import { TOOLCRAFT_DENSE_SECTION_MIN_CONTROLS } from "./control-section-entity-cohesion";
|
|
10
13
|
import {
|
|
11
14
|
controlTypeSectionTitlePattern,
|
|
12
15
|
genericControlSectionTitlePattern,
|
|
@@ -15,9 +18,6 @@ import {
|
|
|
15
18
|
const broadControlSectionTitlePattern =
|
|
16
19
|
/^(animation|export|flow|icon|logo|motion|output|scene|shape|shapes|text|typography|visual|visuals)$/i;
|
|
17
20
|
|
|
18
|
-
const maxPreferredControlsPerSection = 7;
|
|
19
|
-
const maxHardControlsPerSection = 10;
|
|
20
|
-
|
|
21
21
|
export function getToolcraftControlLayoutSectionInvariantErrors(
|
|
22
22
|
facts: ToolcraftControlLayoutFacts,
|
|
23
23
|
): string[] {
|
|
@@ -55,7 +55,7 @@ export function getToolcraftControlLayoutSectionInvariantErrors(
|
|
|
55
55
|
.map(([controlId]) => controlId);
|
|
56
56
|
|
|
57
57
|
if (
|
|
58
|
-
controls.length
|
|
58
|
+
controls.length >= TOOLCRAFT_DENSE_SECTION_MIN_CONTROLS &&
|
|
59
59
|
missingSemanticGroups.length > 0
|
|
60
60
|
) {
|
|
61
61
|
errors.push(
|
|
@@ -63,6 +63,10 @@ export function getToolcraftControlLayoutSectionInvariantErrors(
|
|
|
63
63
|
);
|
|
64
64
|
}
|
|
65
65
|
errors.push(
|
|
66
|
+
...getToolcraftColorRowGroupingErrors({
|
|
67
|
+
controls,
|
|
68
|
+
sectionLabel,
|
|
69
|
+
}),
|
|
66
70
|
...getToolcraftColorBankLabelErrors({
|
|
67
71
|
controls,
|
|
68
72
|
sectionLabel,
|
|
@@ -71,6 +75,18 @@ export function getToolcraftControlLayoutSectionInvariantErrors(
|
|
|
71
75
|
);
|
|
72
76
|
|
|
73
77
|
for (const [controlId, control] of controls) {
|
|
78
|
+
const duplicateSectionTitleLabelError =
|
|
79
|
+
getToolcraftDuplicateSectionTitleLabelError({
|
|
80
|
+
control,
|
|
81
|
+
controlId,
|
|
82
|
+
sectionLabel,
|
|
83
|
+
sectionTitle,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
if (duplicateSectionTitleLabelError) {
|
|
87
|
+
errors.push(duplicateSectionTitleLabelError);
|
|
88
|
+
}
|
|
89
|
+
|
|
74
90
|
const genericLabelError = getToolcraftGenericControlLabelError({
|
|
75
91
|
control,
|
|
76
92
|
controlId,
|
|
@@ -135,7 +151,7 @@ export function getToolcraftControlLayoutSectionHeuristicErrors(
|
|
|
135
151
|
sectionTitle !== undefined && broadControlSectionTitlePattern.test(sectionTitle);
|
|
136
152
|
|
|
137
153
|
if (
|
|
138
|
-
controls.length
|
|
154
|
+
controls.length >= TOOLCRAFT_DENSE_SECTION_MIN_CONTROLS &&
|
|
139
155
|
hasBroadSectionTitle &&
|
|
140
156
|
semanticClusters.size >= 3
|
|
141
157
|
) {
|
|
@@ -144,11 +160,6 @@ export function getToolcraftControlLayoutSectionHeuristicErrors(
|
|
|
144
160
|
);
|
|
145
161
|
}
|
|
146
162
|
|
|
147
|
-
if (controls.length > maxHardControlsPerSection && semanticClusters.size > 1) {
|
|
148
|
-
errors.push(
|
|
149
|
-
`${sectionLabel} has ${controls.length} controls across ${semanticClusters.size} semantic clusters (${clusterList}). Controls-panel sections should stay discrete; split sections that grow past ${maxHardControlsPerSection} controls unless every control edits one tightly scoped entity.`,
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
163
|
}
|
|
153
164
|
|
|
154
165
|
return errors;
|
|
@@ -10,6 +10,12 @@ export function getRequiredToolcraftControlPartCoverage(
|
|
|
10
10
|
return ["anchorGrid.position"];
|
|
11
11
|
case "channelMixer":
|
|
12
12
|
return ["channelMixer.activeChannel", "channelMixer.values"];
|
|
13
|
+
case "collectionActions":
|
|
14
|
+
return [
|
|
15
|
+
"collectionActions.add",
|
|
16
|
+
"collectionActions.remove",
|
|
17
|
+
"collectionActions.items",
|
|
18
|
+
];
|
|
13
19
|
case "curves":
|
|
14
20
|
return control.variant === "single"
|
|
15
21
|
? ["curves.points"]
|
|
@@ -39,6 +45,8 @@ export function getRequiredToolcraftControlPartCoverage(
|
|
|
39
45
|
return ["rangeInput.start", "rangeInput.end"];
|
|
40
46
|
case "rangeSlider":
|
|
41
47
|
return ["rangeSlider.lower", "rangeSlider.upper"];
|
|
48
|
+
case "sourceCollection":
|
|
49
|
+
return ["sourceCollection.items"];
|
|
42
50
|
case "vector":
|
|
43
51
|
return ["vector.x", "vector.y"];
|
|
44
52
|
default:
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
getToolcraftControlSectionEntityCohesionErrors,
|
|
5
|
+
hasToolcraftInventoryEntityAgreement,
|
|
6
|
+
} from "./control-section-entity-cohesion";
|
|
7
|
+
import type { ToolcraftControlSectionInventoryEntry } from "./types";
|
|
8
|
+
|
|
9
|
+
function makeSection({
|
|
10
|
+
count,
|
|
11
|
+
entity = "Renderable object",
|
|
12
|
+
entityId = "renderable-object",
|
|
13
|
+
id = "object",
|
|
14
|
+
splitReason,
|
|
15
|
+
workflowStage,
|
|
16
|
+
}: {
|
|
17
|
+
count: number;
|
|
18
|
+
entity?: string;
|
|
19
|
+
entityId?: string;
|
|
20
|
+
id?: string;
|
|
21
|
+
splitReason?: string;
|
|
22
|
+
workflowStage?: string;
|
|
23
|
+
}): ToolcraftControlSectionInventoryEntry {
|
|
24
|
+
return {
|
|
25
|
+
entity,
|
|
26
|
+
entityId,
|
|
27
|
+
groupingReason: `The ${id} controls edit one coherent part of the entity.`,
|
|
28
|
+
id,
|
|
29
|
+
splitReason,
|
|
30
|
+
targets: Array.from(
|
|
31
|
+
{ length: count },
|
|
32
|
+
(_, index) => `${id}.value${index + 1}`,
|
|
33
|
+
),
|
|
34
|
+
title: id,
|
|
35
|
+
workflowStage,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
describe("Toolcraft control section entity cohesion", () => {
|
|
40
|
+
it.each([1, 7, 8, 10])(
|
|
41
|
+
"accepts one entity in one section with %s controls",
|
|
42
|
+
(count) => {
|
|
43
|
+
expect(
|
|
44
|
+
getToolcraftControlSectionEntityCohesionErrors([
|
|
45
|
+
makeSection({ count }),
|
|
46
|
+
]),
|
|
47
|
+
).toEqual([]);
|
|
48
|
+
},
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
it("rejects splitting an entity that fits in one section", () => {
|
|
52
|
+
const errors = getToolcraftControlSectionEntityCohesionErrors([
|
|
53
|
+
makeSection({ count: 3, id: "object-source" }),
|
|
54
|
+
makeSection({ count: 4, id: "object-style" }),
|
|
55
|
+
]);
|
|
56
|
+
|
|
57
|
+
expect(errors).toContain(
|
|
58
|
+
'Control Section Inventory entity "renderable-object" owns 7 controls across 2 sections (object-source, object-style). Entities with 10 or fewer controls must stay in one section.',
|
|
59
|
+
);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("rejects an entity above the hard maximum left in one section", () => {
|
|
63
|
+
expect(
|
|
64
|
+
getToolcraftControlSectionEntityCohesionErrors([
|
|
65
|
+
makeSection({ count: 11 }),
|
|
66
|
+
]),
|
|
67
|
+
).toContain(
|
|
68
|
+
'Control Section Inventory entity "renderable-object" owns 11 controls in section object. Split entities above 10 controls into explicit workflow stages.',
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("accepts a balanced large-entity workflow split", () => {
|
|
73
|
+
expect(
|
|
74
|
+
getToolcraftControlSectionEntityCohesionErrors([
|
|
75
|
+
makeSection({
|
|
76
|
+
count: 5,
|
|
77
|
+
id: "object-structure",
|
|
78
|
+
splitReason: "Structure is authored before the finishing workflow.",
|
|
79
|
+
workflowStage: "structure",
|
|
80
|
+
}),
|
|
81
|
+
makeSection({
|
|
82
|
+
count: 6,
|
|
83
|
+
id: "object-finish",
|
|
84
|
+
splitReason: "Finish is authored after the structural workflow.",
|
|
85
|
+
workflowStage: "finish",
|
|
86
|
+
}),
|
|
87
|
+
]),
|
|
88
|
+
).toEqual([]);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("rejects a one-control tail in a split entity", () => {
|
|
92
|
+
expect(
|
|
93
|
+
getToolcraftControlSectionEntityCohesionErrors([
|
|
94
|
+
makeSection({
|
|
95
|
+
count: 10,
|
|
96
|
+
id: "object-primary",
|
|
97
|
+
splitReason: "Primary editing precedes the final workflow stage.",
|
|
98
|
+
workflowStage: "primary",
|
|
99
|
+
}),
|
|
100
|
+
makeSection({
|
|
101
|
+
count: 1,
|
|
102
|
+
id: "object-final",
|
|
103
|
+
splitReason: "The final workflow follows primary editing.",
|
|
104
|
+
workflowStage: "final",
|
|
105
|
+
}),
|
|
106
|
+
]),
|
|
107
|
+
).toContain(
|
|
108
|
+
'Control Section Inventory entity "renderable-object" section object-final owns 1 control. Every section in a split entity must own between 2 and 10 controls.',
|
|
109
|
+
);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("rejects a split section above the per-section maximum", () => {
|
|
113
|
+
expect(
|
|
114
|
+
getToolcraftControlSectionEntityCohesionErrors([
|
|
115
|
+
makeSection({
|
|
116
|
+
count: 11,
|
|
117
|
+
id: "object-primary",
|
|
118
|
+
splitReason: "Primary editing precedes the final workflow stage.",
|
|
119
|
+
workflowStage: "primary",
|
|
120
|
+
}),
|
|
121
|
+
makeSection({
|
|
122
|
+
count: 2,
|
|
123
|
+
id: "object-final",
|
|
124
|
+
splitReason: "The final workflow follows primary editing.",
|
|
125
|
+
workflowStage: "final",
|
|
126
|
+
}),
|
|
127
|
+
]),
|
|
128
|
+
).toContain(
|
|
129
|
+
'Control Section Inventory entity "renderable-object" section object-primary owns 11 controls. Every section in a split entity must own between 2 and 10 controls.',
|
|
130
|
+
);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("requires a workflow stage on every section of a split entity", () => {
|
|
134
|
+
expect(
|
|
135
|
+
getToolcraftControlSectionEntityCohesionErrors([
|
|
136
|
+
makeSection({
|
|
137
|
+
count: 6,
|
|
138
|
+
id: "object-primary",
|
|
139
|
+
splitReason: "Primary editing precedes the final workflow stage.",
|
|
140
|
+
}),
|
|
141
|
+
makeSection({
|
|
142
|
+
count: 6,
|
|
143
|
+
id: "object-final",
|
|
144
|
+
splitReason: "The final workflow follows primary editing.",
|
|
145
|
+
workflowStage: "final",
|
|
146
|
+
}),
|
|
147
|
+
]),
|
|
148
|
+
).toContain(
|
|
149
|
+
'Control Section Inventory entity "renderable-object" section object-primary must declare workflowStage because the entity is split across sections.',
|
|
150
|
+
);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("requires complete, unique split evidence and a consistent entity name", () => {
|
|
154
|
+
const errors = getToolcraftControlSectionEntityCohesionErrors([
|
|
155
|
+
makeSection({ count: 6, id: "object-a", workflowStage: "edit" }),
|
|
156
|
+
makeSection({
|
|
157
|
+
count: 6,
|
|
158
|
+
entity: "Different label",
|
|
159
|
+
id: "object-b",
|
|
160
|
+
splitReason: "This section follows the first editing stage.",
|
|
161
|
+
workflowStage: "edit",
|
|
162
|
+
}),
|
|
163
|
+
]);
|
|
164
|
+
|
|
165
|
+
expect(errors).toEqual(
|
|
166
|
+
expect.arrayContaining([
|
|
167
|
+
expect.stringContaining("uses inconsistent entity names"),
|
|
168
|
+
expect.stringContaining("object-a must declare splitReason"),
|
|
169
|
+
expect.stringContaining('repeats workflowStage "edit"'),
|
|
170
|
+
]),
|
|
171
|
+
);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it("keeps independent entities independent", () => {
|
|
175
|
+
expect(
|
|
176
|
+
getToolcraftControlSectionEntityCohesionErrors([
|
|
177
|
+
makeSection({ count: 4, entityId: "entity-a", id: "entity-a" }),
|
|
178
|
+
makeSection({ count: 4, entityId: "entity-b", id: "entity-b" }),
|
|
179
|
+
]),
|
|
180
|
+
).toEqual([]);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it("requires one shared entityId for target-prefix corroboration", () => {
|
|
184
|
+
const first = makeSection({ count: 6, id: "first" });
|
|
185
|
+
const second = makeSection({
|
|
186
|
+
count: 6,
|
|
187
|
+
entityId: "different-entity",
|
|
188
|
+
id: "second",
|
|
189
|
+
});
|
|
190
|
+
const sectionInventoryById = new Map([
|
|
191
|
+
[first.id, first],
|
|
192
|
+
[second.id, second],
|
|
193
|
+
]);
|
|
194
|
+
const sections = new Set([first.id, second.id]);
|
|
195
|
+
|
|
196
|
+
expect(
|
|
197
|
+
hasToolcraftInventoryEntityAgreement({
|
|
198
|
+
sectionInventoryById,
|
|
199
|
+
sections,
|
|
200
|
+
}),
|
|
201
|
+
).toBe(false);
|
|
202
|
+
|
|
203
|
+
sectionInventoryById.set(second.id, {
|
|
204
|
+
...second,
|
|
205
|
+
entityId: first.entityId,
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
expect(
|
|
209
|
+
hasToolcraftInventoryEntityAgreement({
|
|
210
|
+
sectionInventoryById,
|
|
211
|
+
sections,
|
|
212
|
+
}),
|
|
213
|
+
).toBe(true);
|
|
214
|
+
});
|
|
215
|
+
});
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { ToolcraftControlSectionInventoryEntry } from "./types";
|
|
2
|
+
|
|
3
|
+
export const TOOLCRAFT_DENSE_SECTION_MIN_CONTROLS = 8;
|
|
4
|
+
|
|
5
|
+
const TOOLCRAFT_MAX_CONTROLS_PER_SECTION = 10;
|
|
6
|
+
const TOOLCRAFT_MIN_CONTROLS_PER_SPLIT_SECTION = 2;
|
|
7
|
+
const TOOLCRAFT_MIN_SPLIT_REASON_LENGTH = 12;
|
|
8
|
+
|
|
9
|
+
export function hasToolcraftInventoryEntityAgreement({
|
|
10
|
+
sectionInventoryById,
|
|
11
|
+
sections,
|
|
12
|
+
}: {
|
|
13
|
+
sectionInventoryById: ReadonlyMap<
|
|
14
|
+
string,
|
|
15
|
+
ToolcraftControlSectionInventoryEntry
|
|
16
|
+
>;
|
|
17
|
+
sections: ReadonlySet<string>;
|
|
18
|
+
}): boolean {
|
|
19
|
+
const entries = [...sections].map((sectionId) =>
|
|
20
|
+
sectionInventoryById.get(sectionId),
|
|
21
|
+
);
|
|
22
|
+
const entityIds = entries.map((entry) => entry?.entityId?.trim() ?? "");
|
|
23
|
+
|
|
24
|
+
return entityIds.every(Boolean) && new Set(entityIds).size === 1;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function getToolcraftControlSectionEntityCohesionErrors(
|
|
28
|
+
sectionInventory: readonly ToolcraftControlSectionInventoryEntry[],
|
|
29
|
+
): string[] {
|
|
30
|
+
const errors: string[] = [];
|
|
31
|
+
const entriesByEntityId = new Map<
|
|
32
|
+
string,
|
|
33
|
+
ToolcraftControlSectionInventoryEntry[]
|
|
34
|
+
>();
|
|
35
|
+
|
|
36
|
+
for (const entry of sectionInventory) {
|
|
37
|
+
const entityId = entry.entityId?.trim() ?? "";
|
|
38
|
+
const entity = entry.entity?.trim() ?? "";
|
|
39
|
+
|
|
40
|
+
if (
|
|
41
|
+
!entityId ||
|
|
42
|
+
!entity ||
|
|
43
|
+
(entry.id?.trim().length ?? 0) === 0 ||
|
|
44
|
+
!Array.isArray(entry.targets) ||
|
|
45
|
+
entry.targets.length === 0
|
|
46
|
+
) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const entries = entriesByEntityId.get(entityId) ?? [];
|
|
51
|
+
entries.push(entry);
|
|
52
|
+
entriesByEntityId.set(entityId, entries);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
for (const [entityId, entries] of entriesByEntityId) {
|
|
56
|
+
const controlCount = entries.reduce(
|
|
57
|
+
(total, entry) => total + entry.targets.length,
|
|
58
|
+
0,
|
|
59
|
+
);
|
|
60
|
+
const sectionNames = entries.map((entry) => entry.title.trim() || entry.id);
|
|
61
|
+
const entityNames = new Set(entries.map((entry) => entry.entity.trim()));
|
|
62
|
+
|
|
63
|
+
if (entityNames.size > 1) {
|
|
64
|
+
errors.push(
|
|
65
|
+
`Control Section Inventory entity "${entityId}" uses inconsistent entity names: ${[
|
|
66
|
+
...entityNames,
|
|
67
|
+
].join(", ")}. Reuse one human-readable entity name for every section in the entity.`,
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (controlCount <= TOOLCRAFT_MAX_CONTROLS_PER_SECTION) {
|
|
72
|
+
if (entries.length > 1) {
|
|
73
|
+
errors.push(
|
|
74
|
+
`Control Section Inventory entity "${entityId}" owns ${controlCount} controls across ${entries.length} sections (${sectionNames.join(", ")}). Entities with ${TOOLCRAFT_MAX_CONTROLS_PER_SECTION} or fewer controls must stay in one section.`,
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (entries.length === 1) {
|
|
81
|
+
errors.push(
|
|
82
|
+
`Control Section Inventory entity "${entityId}" owns ${controlCount} controls in section ${sectionNames[0]}. Split entities above ${TOOLCRAFT_MAX_CONTROLS_PER_SECTION} controls into explicit workflow stages.`,
|
|
83
|
+
);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const sectionsByStage = new Map<string, string[]>();
|
|
88
|
+
|
|
89
|
+
for (const entry of entries) {
|
|
90
|
+
const sectionName = entry.title.trim() || entry.id;
|
|
91
|
+
const sectionControlCount = entry.targets.length;
|
|
92
|
+
const workflowStage = entry.workflowStage?.trim() ?? "";
|
|
93
|
+
const splitReason = entry.splitReason?.trim() ?? "";
|
|
94
|
+
|
|
95
|
+
if (
|
|
96
|
+
sectionControlCount < TOOLCRAFT_MIN_CONTROLS_PER_SPLIT_SECTION ||
|
|
97
|
+
sectionControlCount > TOOLCRAFT_MAX_CONTROLS_PER_SECTION
|
|
98
|
+
) {
|
|
99
|
+
errors.push(
|
|
100
|
+
`Control Section Inventory entity "${entityId}" section ${sectionName} owns ${sectionControlCount} ${sectionControlCount === 1 ? "control" : "controls"}. Every section in a split entity must own between ${TOOLCRAFT_MIN_CONTROLS_PER_SPLIT_SECTION} and ${TOOLCRAFT_MAX_CONTROLS_PER_SECTION} controls.`,
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (!workflowStage) {
|
|
105
|
+
errors.push(
|
|
106
|
+
`Control Section Inventory entity "${entityId}" section ${sectionName} must declare workflowStage because the entity is split across sections.`,
|
|
107
|
+
);
|
|
108
|
+
} else {
|
|
109
|
+
const normalizedStage = workflowStage.toLowerCase();
|
|
110
|
+
const stageSections = sectionsByStage.get(normalizedStage) ?? [];
|
|
111
|
+
stageSections.push(sectionName);
|
|
112
|
+
sectionsByStage.set(normalizedStage, stageSections);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (splitReason.length < TOOLCRAFT_MIN_SPLIT_REASON_LENGTH) {
|
|
116
|
+
errors.push(
|
|
117
|
+
`Control Section Inventory entity "${entityId}" section ${sectionName} must declare splitReason of at least ${TOOLCRAFT_MIN_SPLIT_REASON_LENGTH} characters because the entity is split across sections.`,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
for (const [stage, stageSections] of sectionsByStage) {
|
|
123
|
+
if (stageSections.length > 1) {
|
|
124
|
+
errors.push(
|
|
125
|
+
`Control Section Inventory entity "${entityId}" repeats workflowStage "${stage}" across sections ${stageSections.join(", ")}. Workflow stages must be unique within one entity.`,
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return errors;
|
|
132
|
+
}
|
|
@@ -40,6 +40,7 @@ function createSchema({
|
|
|
40
40
|
|
|
41
41
|
const inventoryEntry = {
|
|
42
42
|
entity: "Appearance",
|
|
43
|
+
entityId: "appearance",
|
|
43
44
|
groupingReason: "These controls define the visible appearance of the output.",
|
|
44
45
|
id: "appearance",
|
|
45
46
|
targets: ["appearance.opacity"],
|
|
@@ -56,6 +57,53 @@ describe("Toolcraft Control Section Inventory identity", () => {
|
|
|
56
57
|
).toEqual([]);
|
|
57
58
|
});
|
|
58
59
|
|
|
60
|
+
it("preserves inventory ownership when runtime Setup relocates product background controls", () => {
|
|
61
|
+
const schema = defineToolcraft({
|
|
62
|
+
canvas: { enabled: true },
|
|
63
|
+
panels: {
|
|
64
|
+
controls: {
|
|
65
|
+
sections: [
|
|
66
|
+
{
|
|
67
|
+
controls: {
|
|
68
|
+
background: {
|
|
69
|
+
applicability: { mode: "always" },
|
|
70
|
+
defaultValue: "#101010",
|
|
71
|
+
target: "appearance.background",
|
|
72
|
+
type: "color",
|
|
73
|
+
},
|
|
74
|
+
includeBackground: {
|
|
75
|
+
applicability: { mode: "always" },
|
|
76
|
+
defaultValue: true,
|
|
77
|
+
target: "export.includeBackground",
|
|
78
|
+
type: "switch",
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
id: "background",
|
|
82
|
+
title: "Background",
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
title: "Controls",
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
const backgroundInventory = {
|
|
90
|
+
entity: "Output background",
|
|
91
|
+
entityId: "output-background",
|
|
92
|
+
groupingReason:
|
|
93
|
+
"Inclusion and color jointly define the exported background.",
|
|
94
|
+
id: "background",
|
|
95
|
+
targets: ["export.includeBackground", "appearance.background"],
|
|
96
|
+
title: "Background",
|
|
97
|
+
} as const;
|
|
98
|
+
|
|
99
|
+
expect(schema.panels.controls?.sections[0]?.id).toBe("runtime.setup");
|
|
100
|
+
expect(
|
|
101
|
+
getToolcraftControlSectionInventoryErrors(schema, [
|
|
102
|
+
backgroundInventory,
|
|
103
|
+
]),
|
|
104
|
+
).toEqual([]);
|
|
105
|
+
});
|
|
106
|
+
|
|
59
107
|
it("rejects an inventory id that does not match the schema section", () => {
|
|
60
108
|
const errors = getToolcraftControlSectionInventoryErrors(createSchema(), [
|
|
61
109
|
{ ...inventoryEntry, id: "different-section" },
|
|
@@ -80,6 +128,45 @@ describe("Toolcraft Control Section Inventory identity", () => {
|
|
|
80
128
|
);
|
|
81
129
|
});
|
|
82
130
|
|
|
131
|
+
it.each([
|
|
132
|
+
[
|
|
133
|
+
"blank entityId",
|
|
134
|
+
{ ...inventoryEntry, entityId: "" },
|
|
135
|
+
'Control Section Inventory entry "Original title" must declare a non-empty stable entityId.',
|
|
136
|
+
],
|
|
137
|
+
[
|
|
138
|
+
"blank entity",
|
|
139
|
+
{ ...inventoryEntry, entity: "" },
|
|
140
|
+
'Control Section Inventory entry "Original title" must declare a human-readable entity name.',
|
|
141
|
+
],
|
|
142
|
+
])("rejects %s", (_label, entry, expectedMessage) => {
|
|
143
|
+
expect(
|
|
144
|
+
getToolcraftControlSectionInventoryErrors(createSchema(), [entry]),
|
|
145
|
+
).toContain(expectedMessage);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("rejects a missing entityId without throwing", () => {
|
|
149
|
+
const { entityId: _entityId, ...entryWithoutEntityId } = inventoryEntry;
|
|
150
|
+
const malformedInventory = [
|
|
151
|
+
entryWithoutEntityId,
|
|
152
|
+
] as unknown as readonly ToolcraftControlSectionInventoryEntry[];
|
|
153
|
+
|
|
154
|
+
expect(() =>
|
|
155
|
+
getToolcraftControlSectionInventoryErrors(
|
|
156
|
+
createSchema(),
|
|
157
|
+
malformedInventory,
|
|
158
|
+
),
|
|
159
|
+
).not.toThrow();
|
|
160
|
+
expect(
|
|
161
|
+
getToolcraftControlSectionInventoryErrors(
|
|
162
|
+
createSchema(),
|
|
163
|
+
malformedInventory,
|
|
164
|
+
),
|
|
165
|
+
).toContain(
|
|
166
|
+
'Control Section Inventory entry "Original title" must declare a non-empty stable entityId.',
|
|
167
|
+
);
|
|
168
|
+
});
|
|
169
|
+
|
|
83
170
|
it.each([
|
|
84
171
|
["missing", undefined],
|
|
85
172
|
["non-string", 42],
|