@ztothez/design-engineering 2.0.0
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/LICENSE +15 -0
- package/README.md +448 -0
- package/ROADMAP.md +127 -0
- package/SKILL.md +698 -0
- package/V2-ROADMAP.md +431 -0
- package/V3-ROADMAP.md +605 -0
- package/V4-ROADMAP.md +283 -0
- package/clean-room-ux-design-spec.md +1431 -0
- package/dist/cli/aggregate-gates.d.ts +2 -0
- package/dist/cli/aggregate-gates.js +86 -0
- package/dist/cli/aggregate-gates.js.map +1 -0
- package/dist/cli/assess-maintainer-review.d.ts +2 -0
- package/dist/cli/assess-maintainer-review.js +72 -0
- package/dist/cli/assess-maintainer-review.js.map +1 -0
- package/dist/cli/audit.d.ts +2 -0
- package/dist/cli/audit.js +71 -0
- package/dist/cli/audit.js.map +1 -0
- package/dist/cli/compile-comparison-review.d.ts +2 -0
- package/dist/cli/compile-comparison-review.js +154 -0
- package/dist/cli/compile-comparison-review.js.map +1 -0
- package/dist/cli/compile-plan.d.ts +2 -0
- package/dist/cli/compile-plan.js +66 -0
- package/dist/cli/compile-plan.js.map +1 -0
- package/dist/cli/evaluate-corpus.d.ts +2 -0
- package/dist/cli/evaluate-corpus.js +65 -0
- package/dist/cli/evaluate-corpus.js.map +1 -0
- package/dist/cli/generate-react.d.ts +2 -0
- package/dist/cli/generate-react.js +83 -0
- package/dist/cli/generate-react.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +58 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/portfolio.d.ts +2 -0
- package/dist/cli/portfolio.js +316 -0
- package/dist/cli/portfolio.js.map +1 -0
- package/dist/cli/quality-gate.d.ts +2 -0
- package/dist/cli/quality-gate.js +131 -0
- package/dist/cli/quality-gate.js.map +1 -0
- package/dist/cli/repair-react.d.ts +2 -0
- package/dist/cli/repair-react.js +163 -0
- package/dist/cli/repair-react.js.map +1 -0
- package/dist/cli/review-heuristics.d.ts +2 -0
- package/dist/cli/review-heuristics.js +68 -0
- package/dist/cli/review-heuristics.js.map +1 -0
- package/dist/cli/validate-brief.d.ts +2 -0
- package/dist/cli/validate-brief.js +58 -0
- package/dist/cli/validate-brief.js.map +1 -0
- package/dist/cli/validate-comparison.d.ts +2 -0
- package/dist/cli/validate-comparison.js +68 -0
- package/dist/cli/validate-comparison.js.map +1 -0
- package/dist/cli/validate-contract.d.ts +2 -0
- package/dist/cli/validate-contract.js +54 -0
- package/dist/cli/validate-contract.js.map +1 -0
- package/dist/cli/validate-design.d.ts +2 -0
- package/dist/cli/validate-design.js +53 -0
- package/dist/cli/validate-design.js.map +1 -0
- package/dist/cli/validate-information.d.ts +2 -0
- package/dist/cli/validate-information.js +53 -0
- package/dist/cli/validate-information.js.map +1 -0
- package/dist/cli/validate-trust.d.ts +2 -0
- package/dist/cli/validate-trust.js +53 -0
- package/dist/cli/validate-trust.js.map +1 -0
- package/dist/cli/verify-ui.d.ts +2 -0
- package/dist/cli/verify-ui.js +181 -0
- package/dist/cli/verify-ui.js.map +1 -0
- package/dist/src/acceptance/evaluator.d.ts +13 -0
- package/dist/src/acceptance/evaluator.js +201 -0
- package/dist/src/acceptance/evaluator.js.map +1 -0
- package/dist/src/acceptance/loader.d.ts +2 -0
- package/dist/src/acceptance/loader.js +18 -0
- package/dist/src/acceptance/loader.js.map +1 -0
- package/dist/src/acceptance/report.d.ts +2 -0
- package/dist/src/acceptance/report.js +18 -0
- package/dist/src/acceptance/report.js.map +1 -0
- package/dist/src/acceptance/schema.d.ts +64 -0
- package/dist/src/acceptance/schema.js +57 -0
- package/dist/src/acceptance/schema.js.map +1 -0
- package/dist/src/acceptance/types.d.ts +47 -0
- package/dist/src/acceptance/types.js +2 -0
- package/dist/src/acceptance/types.js.map +1 -0
- package/dist/src/aggregate/report.d.ts +2 -0
- package/dist/src/aggregate/report.js +33 -0
- package/dist/src/aggregate/report.js.map +1 -0
- package/dist/src/aggregate/runner.d.ts +2 -0
- package/dist/src/aggregate/runner.js +165 -0
- package/dist/src/aggregate/runner.js.map +1 -0
- package/dist/src/aggregate/schema.d.ts +182 -0
- package/dist/src/aggregate/schema.js +54 -0
- package/dist/src/aggregate/schema.js.map +1 -0
- package/dist/src/aggregate/types.d.ts +57 -0
- package/dist/src/aggregate/types.js +2 -0
- package/dist/src/aggregate/types.js.map +1 -0
- package/dist/src/audit/policy.d.ts +3 -0
- package/dist/src/audit/policy.js +45 -0
- package/dist/src/audit/policy.js.map +1 -0
- package/dist/src/audit/report.d.ts +2 -0
- package/dist/src/audit/report.js +32 -0
- package/dist/src/audit/report.js.map +1 -0
- package/dist/src/audit/rules/accessibility-name.d.ts +2 -0
- package/dist/src/audit/rules/accessibility-name.js +64 -0
- package/dist/src/audit/rules/accessibility-name.js.map +1 -0
- package/dist/src/audit/rules/component-size.d.ts +2 -0
- package/dist/src/audit/rules/component-size.js +27 -0
- package/dist/src/audit/rules/component-size.js.map +1 -0
- package/dist/src/audit/rules/credential-placeholder.d.ts +2 -0
- package/dist/src/audit/rules/credential-placeholder.js +83 -0
- package/dist/src/audit/rules/credential-placeholder.js.map +1 -0
- package/dist/src/audit/rules/helpers.d.ts +16 -0
- package/dist/src/audit/rules/helpers.js +64 -0
- package/dist/src/audit/rules/helpers.js.map +1 -0
- package/dist/src/audit/rules/index.d.ts +2 -0
- package/dist/src/audit/rules/index.js +23 -0
- package/dist/src/audit/rules/index.js.map +1 -0
- package/dist/src/audit/rules/interactive-integrity.d.ts +2 -0
- package/dist/src/audit/rules/interactive-integrity.js +111 -0
- package/dist/src/audit/rules/interactive-integrity.js.map +1 -0
- package/dist/src/audit/rules/mixed-responsibilities.d.ts +2 -0
- package/dist/src/audit/rules/mixed-responsibilities.js +39 -0
- package/dist/src/audit/rules/mixed-responsibilities.js.map +1 -0
- package/dist/src/audit/rules/mock-production-path.d.ts +2 -0
- package/dist/src/audit/rules/mock-production-path.js +39 -0
- package/dist/src/audit/rules/mock-production-path.js.map +1 -0
- package/dist/src/audit/rules/network-state.d.ts +2 -0
- package/dist/src/audit/rules/network-state.js +39 -0
- package/dist/src/audit/rules/network-state.js.map +1 -0
- package/dist/src/audit/rules/operational-claim.d.ts +2 -0
- package/dist/src/audit/rules/operational-claim.js +94 -0
- package/dist/src/audit/rules/operational-claim.js.map +1 -0
- package/dist/src/audit/rules/placeholder-interaction.d.ts +2 -0
- package/dist/src/audit/rules/placeholder-interaction.js +46 -0
- package/dist/src/audit/rules/placeholder-interaction.js.map +1 -0
- package/dist/src/audit/rules/raw-design-values.d.ts +2 -0
- package/dist/src/audit/rules/raw-design-values.js +97 -0
- package/dist/src/audit/rules/raw-design-values.js.map +1 -0
- package/dist/src/audit/scanner.d.ts +2 -0
- package/dist/src/audit/scanner.js +215 -0
- package/dist/src/audit/scanner.js.map +1 -0
- package/dist/src/audit/types.d.ts +62 -0
- package/dist/src/audit/types.js +2 -0
- package/dist/src/audit/types.js.map +1 -0
- package/dist/src/comparison/evaluator.d.ts +2 -0
- package/dist/src/comparison/evaluator.js +478 -0
- package/dist/src/comparison/evaluator.js.map +1 -0
- package/dist/src/comparison/loader.d.ts +3 -0
- package/dist/src/comparison/loader.js +26 -0
- package/dist/src/comparison/loader.js.map +1 -0
- package/dist/src/comparison/maintainer.d.ts +47 -0
- package/dist/src/comparison/maintainer.js +218 -0
- package/dist/src/comparison/maintainer.js.map +1 -0
- package/dist/src/comparison/report.d.ts +2 -0
- package/dist/src/comparison/report.js +48 -0
- package/dist/src/comparison/report.js.map +1 -0
- package/dist/src/comparison/schema.d.ts +464 -0
- package/dist/src/comparison/schema.js +502 -0
- package/dist/src/comparison/schema.js.map +1 -0
- package/dist/src/contracts/archetypes.d.ts +21 -0
- package/dist/src/contracts/archetypes.js +102 -0
- package/dist/src/contracts/archetypes.js.map +1 -0
- package/dist/src/contracts/journeys.d.ts +7 -0
- package/dist/src/contracts/journeys.js +32 -0
- package/dist/src/contracts/journeys.js.map +1 -0
- package/dist/src/contracts/report.d.ts +2 -0
- package/dist/src/contracts/report.js +33 -0
- package/dist/src/contracts/report.js.map +1 -0
- package/dist/src/contracts/schema.d.ts +1038 -0
- package/dist/src/contracts/schema.js +385 -0
- package/dist/src/contracts/schema.js.map +1 -0
- package/dist/src/contracts/validator.d.ts +12 -0
- package/dist/src/contracts/validator.js +303 -0
- package/dist/src/contracts/validator.js.map +1 -0
- package/dist/src/corpus/evaluator.d.ts +2 -0
- package/dist/src/corpus/evaluator.js +203 -0
- package/dist/src/corpus/evaluator.js.map +1 -0
- package/dist/src/corpus/loader.d.ts +2 -0
- package/dist/src/corpus/loader.js +20 -0
- package/dist/src/corpus/loader.js.map +1 -0
- package/dist/src/corpus/report.d.ts +2 -0
- package/dist/src/corpus/report.js +33 -0
- package/dist/src/corpus/report.js.map +1 -0
- package/dist/src/corpus/schema.d.ts +316 -0
- package/dist/src/corpus/schema.js +269 -0
- package/dist/src/corpus/schema.js.map +1 -0
- package/dist/src/design-intelligence/loader.d.ts +2 -0
- package/dist/src/design-intelligence/loader.js +21 -0
- package/dist/src/design-intelligence/loader.js.map +1 -0
- package/dist/src/design-intelligence/report.d.ts +2 -0
- package/dist/src/design-intelligence/report.js +36 -0
- package/dist/src/design-intelligence/report.js.map +1 -0
- package/dist/src/design-intelligence/schema.d.ts +838 -0
- package/dist/src/design-intelligence/schema.js +854 -0
- package/dist/src/design-intelligence/schema.js.map +1 -0
- package/dist/src/design-intelligence/validator.d.ts +2 -0
- package/dist/src/design-intelligence/validator.js +1371 -0
- package/dist/src/design-intelligence/validator.js.map +1 -0
- package/dist/src/design-plan/compiler.d.ts +8 -0
- package/dist/src/design-plan/compiler.js +288 -0
- package/dist/src/design-plan/compiler.js.map +1 -0
- package/dist/src/design-plan/report.d.ts +2 -0
- package/dist/src/design-plan/report.js +28 -0
- package/dist/src/design-plan/report.js.map +1 -0
- package/dist/src/design-plan/schema.d.ts +202 -0
- package/dist/src/design-plan/schema.js +76 -0
- package/dist/src/design-plan/schema.js.map +1 -0
- package/dist/src/generation/loader.d.ts +2 -0
- package/dist/src/generation/loader.js +21 -0
- package/dist/src/generation/loader.js.map +1 -0
- package/dist/src/generation/policy.d.ts +12 -0
- package/dist/src/generation/policy.js +62 -0
- package/dist/src/generation/policy.js.map +1 -0
- package/dist/src/generation/react-typescript.d.ts +6 -0
- package/dist/src/generation/react-typescript.js +538 -0
- package/dist/src/generation/react-typescript.js.map +1 -0
- package/dist/src/generation/report.d.ts +2 -0
- package/dist/src/generation/report.js +21 -0
- package/dist/src/generation/report.js.map +1 -0
- package/dist/src/generation/schema.d.ts +44 -0
- package/dist/src/generation/schema.js +50 -0
- package/dist/src/generation/schema.js.map +1 -0
- package/dist/src/generation/templates/tokens.d.ts +1 -0
- package/dist/src/generation/templates/tokens.js +59 -0
- package/dist/src/generation/templates/tokens.js.map +1 -0
- package/dist/src/heuristics/evaluator.d.ts +2 -0
- package/dist/src/heuristics/evaluator.js +65 -0
- package/dist/src/heuristics/evaluator.js.map +1 -0
- package/dist/src/heuristics/loader.d.ts +2 -0
- package/dist/src/heuristics/loader.js +21 -0
- package/dist/src/heuristics/loader.js.map +1 -0
- package/dist/src/heuristics/report.d.ts +3 -0
- package/dist/src/heuristics/report.js +31 -0
- package/dist/src/heuristics/report.js.map +1 -0
- package/dist/src/heuristics/schema.d.ts +198 -0
- package/dist/src/heuristics/schema.js +197 -0
- package/dist/src/heuristics/schema.js.map +1 -0
- package/dist/src/information-design/loader.d.ts +2 -0
- package/dist/src/information-design/loader.js +21 -0
- package/dist/src/information-design/loader.js.map +1 -0
- package/dist/src/information-design/report.d.ts +2 -0
- package/dist/src/information-design/report.js +27 -0
- package/dist/src/information-design/report.js.map +1 -0
- package/dist/src/information-design/schema.d.ts +370 -0
- package/dist/src/information-design/schema.js +329 -0
- package/dist/src/information-design/schema.js.map +1 -0
- package/dist/src/information-design/validator.d.ts +2 -0
- package/dist/src/information-design/validator.js +242 -0
- package/dist/src/information-design/validator.js.map +1 -0
- package/dist/src/interface-trust/loader.d.ts +2 -0
- package/dist/src/interface-trust/loader.js +21 -0
- package/dist/src/interface-trust/loader.js.map +1 -0
- package/dist/src/interface-trust/report.d.ts +2 -0
- package/dist/src/interface-trust/report.js +26 -0
- package/dist/src/interface-trust/report.js.map +1 -0
- package/dist/src/interface-trust/schema.d.ts +299 -0
- package/dist/src/interface-trust/schema.js +238 -0
- package/dist/src/interface-trust/schema.js.map +1 -0
- package/dist/src/interface-trust/validator.d.ts +2 -0
- package/dist/src/interface-trust/validator.js +283 -0
- package/dist/src/interface-trust/validator.js.map +1 -0
- package/dist/src/portfolio/adapter-report.d.ts +3 -0
- package/dist/src/portfolio/adapter-report.js +38 -0
- package/dist/src/portfolio/adapter-report.js.map +1 -0
- package/dist/src/portfolio/adapters.d.ts +37 -0
- package/dist/src/portfolio/adapters.js +325 -0
- package/dist/src/portfolio/adapters.js.map +1 -0
- package/dist/src/portfolio/evidence.d.ts +9 -0
- package/dist/src/portfolio/evidence.js +233 -0
- package/dist/src/portfolio/evidence.js.map +1 -0
- package/dist/src/portfolio/files.d.ts +8 -0
- package/dist/src/portfolio/files.js +77 -0
- package/dist/src/portfolio/files.js.map +1 -0
- package/dist/src/portfolio/fixture-server.d.ts +11 -0
- package/dist/src/portfolio/fixture-server.js +131 -0
- package/dist/src/portfolio/fixture-server.js.map +1 -0
- package/dist/src/portfolio/loader.d.ts +2 -0
- package/dist/src/portfolio/loader.js +21 -0
- package/dist/src/portfolio/loader.js.map +1 -0
- package/dist/src/portfolio/mcp.d.ts +186 -0
- package/dist/src/portfolio/mcp.js +117 -0
- package/dist/src/portfolio/mcp.js.map +1 -0
- package/dist/src/portfolio/promotion-schema.d.ts +220 -0
- package/dist/src/portfolio/promotion-schema.js +148 -0
- package/dist/src/portfolio/promotion-schema.js.map +1 -0
- package/dist/src/portfolio/promotion.d.ts +4 -0
- package/dist/src/portfolio/promotion.js +160 -0
- package/dist/src/portfolio/promotion.js.map +1 -0
- package/dist/src/portfolio/qualification-schema.d.ts +268 -0
- package/dist/src/portfolio/qualification-schema.js +112 -0
- package/dist/src/portfolio/qualification-schema.js.map +1 -0
- package/dist/src/portfolio/qualification.d.ts +4 -0
- package/dist/src/portfolio/qualification.js +157 -0
- package/dist/src/portfolio/qualification.js.map +1 -0
- package/dist/src/portfolio/registry.d.ts +34 -0
- package/dist/src/portfolio/registry.js +240 -0
- package/dist/src/portfolio/registry.js.map +1 -0
- package/dist/src/portfolio/report.d.ts +4 -0
- package/dist/src/portfolio/report.js +47 -0
- package/dist/src/portfolio/report.js.map +1 -0
- package/dist/src/portfolio/run-schema.d.ts +135 -0
- package/dist/src/portfolio/run-schema.js +81 -0
- package/dist/src/portfolio/run-schema.js.map +1 -0
- package/dist/src/portfolio/runner.d.ts +118 -0
- package/dist/src/portfolio/runner.js +423 -0
- package/dist/src/portfolio/runner.js.map +1 -0
- package/dist/src/portfolio/schema.d.ts +251 -0
- package/dist/src/portfolio/schema.js +317 -0
- package/dist/src/portfolio/schema.js.map +1 -0
- package/dist/src/portfolio/snapshot.d.ts +89 -0
- package/dist/src/portfolio/snapshot.js +548 -0
- package/dist/src/portfolio/snapshot.js.map +1 -0
- package/dist/src/portfolio/taxonomy-schema.d.ts +215 -0
- package/dist/src/portfolio/taxonomy-schema.js +74 -0
- package/dist/src/portfolio/taxonomy-schema.js.map +1 -0
- package/dist/src/portfolio/taxonomy.d.ts +5 -0
- package/dist/src/portfolio/taxonomy.js +236 -0
- package/dist/src/portfolio/taxonomy.js.map +1 -0
- package/dist/src/portfolio/vault.d.ts +53 -0
- package/dist/src/portfolio/vault.js +176 -0
- package/dist/src/portfolio/vault.js.map +1 -0
- package/dist/src/product-brief/loader.d.ts +2 -0
- package/dist/src/product-brief/loader.js +21 -0
- package/dist/src/product-brief/loader.js.map +1 -0
- package/dist/src/product-brief/report.d.ts +2 -0
- package/dist/src/product-brief/report.js +22 -0
- package/dist/src/product-brief/report.js.map +1 -0
- package/dist/src/product-brief/schema.d.ts +367 -0
- package/dist/src/product-brief/schema.js +272 -0
- package/dist/src/product-brief/schema.js.map +1 -0
- package/dist/src/product-brief/validator.d.ts +2 -0
- package/dist/src/product-brief/validator.js +251 -0
- package/dist/src/product-brief/validator.js.map +1 -0
- package/dist/src/product.d.ts +7 -0
- package/dist/src/product.js +28 -0
- package/dist/src/product.js.map +1 -0
- package/dist/src/quality-gate/report.d.ts +2 -0
- package/dist/src/quality-gate/report.js +46 -0
- package/dist/src/quality-gate/report.js.map +1 -0
- package/dist/src/quality-gate/runner.d.ts +2 -0
- package/dist/src/quality-gate/runner.js +175 -0
- package/dist/src/quality-gate/runner.js.map +1 -0
- package/dist/src/quality-gate/schema.d.ts +75 -0
- package/dist/src/quality-gate/schema.js +37 -0
- package/dist/src/quality-gate/schema.js.map +1 -0
- package/dist/src/quality-gate/types.d.ts +49 -0
- package/dist/src/quality-gate/types.js +2 -0
- package/dist/src/quality-gate/types.js.map +1 -0
- package/dist/src/repair/loader.d.ts +2 -0
- package/dist/src/repair/loader.js +11 -0
- package/dist/src/repair/loader.js.map +1 -0
- package/dist/src/repair/policy.d.ts +16 -0
- package/dist/src/repair/policy.js +65 -0
- package/dist/src/repair/policy.js.map +1 -0
- package/dist/src/repair/report.d.ts +2 -0
- package/dist/src/repair/report.js +32 -0
- package/dist/src/repair/report.js.map +1 -0
- package/dist/src/repair/runner.d.ts +17 -0
- package/dist/src/repair/runner.js +511 -0
- package/dist/src/repair/runner.js.map +1 -0
- package/dist/src/repair/schema.d.ts +264 -0
- package/dist/src/repair/schema.js +202 -0
- package/dist/src/repair/schema.js.map +1 -0
- package/dist/src/retrieval/report.d.ts +2 -0
- package/dist/src/retrieval/report.js +21 -0
- package/dist/src/retrieval/report.js.map +1 -0
- package/dist/src/retrieval/schema.d.ts +123 -0
- package/dist/src/retrieval/schema.js +77 -0
- package/dist/src/retrieval/schema.js.map +1 -0
- package/dist/src/retrieval/search.d.ts +26 -0
- package/dist/src/retrieval/search.js +415 -0
- package/dist/src/retrieval/search.js.map +1 -0
- package/dist/src/runtime/advanced-checks.d.ts +6 -0
- package/dist/src/runtime/advanced-checks.js +487 -0
- package/dist/src/runtime/advanced-checks.js.map +1 -0
- package/dist/src/runtime/composition-checks.d.ts +5 -0
- package/dist/src/runtime/composition-checks.js +307 -0
- package/dist/src/runtime/composition-checks.js.map +1 -0
- package/dist/src/runtime/interface-checks.d.ts +12 -0
- package/dist/src/runtime/interface-checks.js +224 -0
- package/dist/src/runtime/interface-checks.js.map +1 -0
- package/dist/src/runtime/policy.d.ts +13 -0
- package/dist/src/runtime/policy.js +97 -0
- package/dist/src/runtime/policy.js.map +1 -0
- package/dist/src/runtime/report.d.ts +2 -0
- package/dist/src/runtime/report.js +48 -0
- package/dist/src/runtime/report.js.map +1 -0
- package/dist/src/runtime/schema.d.ts +406 -0
- package/dist/src/runtime/schema.js +308 -0
- package/dist/src/runtime/schema.js.map +1 -0
- package/dist/src/runtime/types.d.ts +177 -0
- package/dist/src/runtime/types.js +2 -0
- package/dist/src/runtime/types.js.map +1 -0
- package/dist/src/runtime/verifier.d.ts +2 -0
- package/dist/src/runtime/verifier.js +1201 -0
- package/dist/src/runtime/verifier.js.map +1 -0
- package/dist/src/server.d.ts +2 -0
- package/dist/src/server.js +1352 -0
- package/dist/src/server.js.map +1 -0
- package/docs/installation.md +337 -0
- package/knowledge-base/INDEX.md +285 -0
- package/knowledge-base/benchmarks/aegisops/CALIBRATION.md +52 -0
- package/knowledge-base/benchmarks/aegisops/MANIFEST.md +56 -0
- package/knowledge-base/benchmarks/aegisops/SOURCE-EVIDENCE.md +45 -0
- package/knowledge-base/benchmarks/aegisops/acceptance-criteria.md +42 -0
- package/knowledge-base/benchmarks/aegisops/anti-patterns.md +19 -0
- package/knowledge-base/benchmarks/aegisops/attestations.template.yaml +3 -0
- package/knowledge-base/benchmarks/aegisops/attestations.yaml +115 -0
- package/knowledge-base/benchmarks/aegisops/journeys.json +91 -0
- package/knowledge-base/benchmarks/aegisops/product-contract.yaml +328 -0
- package/knowledge-base/benchmarks/azure-optimizer/SOURCE-EVIDENCE.md +26 -0
- package/knowledge-base/benchmarks/azure-optimizer/V2-IMPLEMENTATION.md +39 -0
- package/knowledge-base/benchmarks/azure-optimizer/acceptance-criteria.md +23 -0
- package/knowledge-base/benchmarks/azure-optimizer/anti-patterns.md +13 -0
- package/knowledge-base/benchmarks/azure-optimizer/journeys.json +88 -0
- package/knowledge-base/benchmarks/azure-optimizer/product-contract.yaml +216 -0
- package/knowledge-base/benchmarks/azure-optimizer/v2-human-review-methodology.yaml +171 -0
- package/knowledge-base/benchmarks/azure-optimizer/v2-journeys.json +139 -0
- package/knowledge-base/benchmarks/corpus/PROVENANCE.md +21 -0
- package/knowledge-base/benchmarks/corpus/README.md +30 -0
- package/knowledge-base/benchmarks/corpus/cases/anti-slop-negative/package.json +9 -0
- package/knowledge-base/benchmarks/corpus/cases/anti-slop-negative/src/FakeDashboard.tsx +10 -0
- package/knowledge-base/benchmarks/corpus/cases/anti-slop-positive/package.json +9 -0
- package/knowledge-base/benchmarks/corpus/cases/anti-slop-positive/src/Progress.tsx +15 -0
- package/knowledge-base/benchmarks/corpus/cases/architecture-negative/package.json +9 -0
- package/knowledge-base/benchmarks/corpus/cases/architecture-negative/src/OperationsPanel.tsx +40 -0
- package/knowledge-base/benchmarks/corpus/cases/architecture-positive/package.json +9 -0
- package/knowledge-base/benchmarks/corpus/cases/architecture-positive/src/Dashboard.tsx +17 -0
- package/knowledge-base/benchmarks/corpus/cases/architecture-positive/src/theme.css +15 -0
- package/knowledge-base/benchmarks/corpus/cases/task-incomplete/SOURCE-EVIDENCE.md +3 -0
- package/knowledge-base/benchmarks/corpus/cases/task-incomplete/journeys.json +20 -0
- package/knowledge-base/benchmarks/corpus/cases/task-incomplete/product-contract.yaml +78 -0
- package/knowledge-base/benchmarks/corpus/corpus.schema.yaml +159 -0
- package/knowledge-base/benchmarks/corpus/corpus.yaml +209 -0
- package/knowledge-base/benchmarks/interface-quality/README.md +26 -0
- package/knowledge-base/benchmarks/interface-quality/SOLO-MAINTAINER-TRACK.md +35 -0
- package/knowledge-base/benchmarks/interface-quality/comparison-methodology-v1.1.schema.yaml +288 -0
- package/knowledge-base/benchmarks/interface-quality/comparison-methodology.schema.yaml +235 -0
- package/knowledge-base/benchmarks/interface-quality/comparison-methodology.template.yaml +181 -0
- package/knowledge-base/benchmarks/interface-quality/evidence/example-runtime-report.json +11 -0
- package/knowledge-base/benchmarks/interface-quality/review-session.schema.yaml +14 -0
- package/knowledge-base/benchmarks/interface-quality/review.schema.yaml +296 -0
- package/knowledge-base/benchmarks/interface-quality/review.template.yaml +43 -0
- package/knowledge-base/benchmarks/portfolio-corpus/ADAPTERS.md +68 -0
- package/knowledge-base/benchmarks/portfolio-corpus/PORTFOLIO-RUNNER.md +131 -0
- package/knowledge-base/benchmarks/portfolio-corpus/PRODUCT-TASK-CONTRACTS.md +29 -0
- package/knowledge-base/benchmarks/portfolio-corpus/PROMOTED-RULES.md +31 -0
- package/knowledge-base/benchmarks/portfolio-corpus/archetype-profiles.yaml +26 -0
- package/knowledge-base/benchmarks/portfolio-corpus/product-task-profile.schema.yaml +105 -0
- package/knowledge-base/benchmarks/portfolio-corpus/registry.schema.yaml +188 -0
- package/knowledge-base/benchmarks/portfolio-corpus/registry.template.yaml +63 -0
- package/knowledge-base/benchmarks/portfolio-corpus/rule-fixtures/component-size-abstention.json +10 -0
- package/knowledge-base/benchmarks/portfolio-corpus/rule-fixtures/component-size-negative.json +10 -0
- package/knowledge-base/benchmarks/portfolio-corpus/rule-fixtures/component-size-positive.json +10 -0
- package/knowledge-base/benchmarks/portfolio-corpus/rule-fixtures/interactive-integrity-abstention.json +10 -0
- package/knowledge-base/benchmarks/portfolio-corpus/rule-fixtures/interactive-integrity-negative.json +10 -0
- package/knowledge-base/benchmarks/portfolio-corpus/rule-fixtures/interactive-integrity-positive.json +10 -0
- package/knowledge-base/benchmarks/portfolio-corpus/rule-fixtures/raw-design-values-abstention.json +10 -0
- package/knowledge-base/benchmarks/portfolio-corpus/rule-fixtures/raw-design-values-negative.json +10 -0
- package/knowledge-base/benchmarks/portfolio-corpus/rule-fixtures/raw-design-values-positive.json +10 -0
- package/knowledge-base/benchmarks/portfolio-corpus/rule-holdout-evaluation.template.json +14 -0
- package/knowledge-base/benchmarks/portfolio-corpus/rule-promotion-evidence.template.json +24 -0
- package/knowledge-base/benchmarks/portfolio-corpus/v3-command-evidence.template.json +17 -0
- package/knowledge-base/benchmarks/portfolio-corpus/v3-qualification-evidence.template.json +29 -0
- package/knowledge-base/benchmarks/scenestart/CALIBRATION.md +95 -0
- package/knowledge-base/benchmarks/scenestart/MANIFEST.md +53 -0
- package/knowledge-base/benchmarks/scenestart/SOURCE-EVIDENCE.md +43 -0
- package/knowledge-base/benchmarks/scenestart/acceptance-criteria.md +59 -0
- package/knowledge-base/benchmarks/scenestart/anti-patterns.md +26 -0
- package/knowledge-base/benchmarks/scenestart/attestations.template.yaml +3 -0
- package/knowledge-base/benchmarks/scenestart/attestations.yaml +21 -0
- package/knowledge-base/benchmarks/scenestart/human-review.md +99 -0
- package/knowledge-base/benchmarks/scenestart/human-review.template.md +105 -0
- package/knowledge-base/benchmarks/scenestart/journeys.json +141 -0
- package/knowledge-base/benchmarks/scenestart/product-contract.yaml +427 -0
- package/knowledge-base/dependencies.yaml +69 -0
- package/knowledge-base/design-intelligence/MASTER.md +87 -0
- package/knowledge-base/design-intelligence/asset-generation.md +66 -0
- package/knowledge-base/design-intelligence/brand-systems.md +69 -0
- package/knowledge-base/design-intelligence/closed-loop-repair.md +95 -0
- package/knowledge-base/design-intelligence/design-deliverable.schema.yaml +1194 -0
- package/knowledge-base/design-intelligence/design-deliverable.template.yaml +591 -0
- package/knowledge-base/design-intelligence/design-plan.md +78 -0
- package/knowledge-base/design-intelligence/design-plan.schema.yaml +621 -0
- package/knowledge-base/design-intelligence/figma-production.md +63 -0
- package/knowledge-base/design-intelligence/generation-adapter.md +72 -0
- package/knowledge-base/design-intelligence/generation-adapter.schema.yaml +47 -0
- package/knowledge-base/design-intelligence/iconography.md +46 -0
- package/knowledge-base/design-intelligence/information-design.md +104 -0
- package/knowledge-base/design-intelligence/information-design.schema.yaml +390 -0
- package/knowledge-base/design-intelligence/information-design.template.yaml +281 -0
- package/knowledge-base/design-intelligence/interaction-recovery-verification.md +72 -0
- package/knowledge-base/design-intelligence/interface-trust.md +103 -0
- package/knowledge-base/design-intelligence/interface-trust.schema.yaml +263 -0
- package/knowledge-base/design-intelligence/interface-trust.template.yaml +173 -0
- package/knowledge-base/design-intelligence/licensing-and-provenance.md +59 -0
- package/knowledge-base/design-intelligence/presentation-design.md +56 -0
- package/knowledge-base/design-intelligence/product-design-brief.md +67 -0
- package/knowledge-base/design-intelligence/product-design-brief.schema.yaml +279 -0
- package/knowledge-base/design-intelligence/product-design-brief.template.yaml +225 -0
- package/knowledge-base/design-intelligence/repair-request.schema.yaml +95 -0
- package/knowledge-base/design-intelligence/repair-request.template.yaml +39 -0
- package/knowledge-base/design-intelligence/visual-accessibility.md +56 -0
- package/knowledge-base/design-intelligence/visual-polish.md +172 -0
- package/knowledge-base/maintained/architecture/MASTER.md +22 -0
- package/knowledge-base/maintained/architecture/component-boundaries.md +30 -0
- package/knowledge-base/maintained/architecture/product-platforms.md +25 -0
- package/knowledge-base/maintained/architecture/quality-attributes-and-evaluation.md +35 -0
- package/knowledge-base/maintained/product-patterns/MASTER.md +10 -0
- package/knowledge-base/maintained/product-patterns/ai-workspaces.md +26 -0
- package/knowledge-base/maintained/product-patterns/operational-dashboards.md +22 -0
- package/knowledge-base/provenance.yaml +196 -0
- package/knowledge-base/retrieval-scope.yaml +43 -0
- package/knowledge-base/usability-evaluation/HEURISTIC_EVALUATION.md +115 -0
- package/knowledge-base/usability-evaluation/heuristic-review.schema.yaml +210 -0
- package/knowledge-base/usability-evaluation/heuristic-review.template.yaml +37 -0
- package/package.json +133 -0
|
@@ -0,0 +1,1371 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
const REPORT_VERSION = "1.0.0";
|
|
3
|
+
const REQUIRED_GENERATION_STAGES = [
|
|
4
|
+
"product-task",
|
|
5
|
+
"truth-data-source-contract",
|
|
6
|
+
"information-architecture",
|
|
7
|
+
"interaction-state-model",
|
|
8
|
+
"visual-direction",
|
|
9
|
+
"token-architecture",
|
|
10
|
+
"implementation",
|
|
11
|
+
"automated-verification",
|
|
12
|
+
"human-visual-review",
|
|
13
|
+
];
|
|
14
|
+
const REQUIRED_TRUST_SCENARIOS = ["demo", "live", "fallback", "stale", "disconnected"];
|
|
15
|
+
const REQUIRED_INFORMATION_LEVELS = [
|
|
16
|
+
"context-provenance",
|
|
17
|
+
"primary-outcome-action",
|
|
18
|
+
"critical-exceptions",
|
|
19
|
+
"health-impact-metrics",
|
|
20
|
+
"prioritized-findings",
|
|
21
|
+
"operational-telemetry",
|
|
22
|
+
"evidence-audit-trail",
|
|
23
|
+
"history-exports",
|
|
24
|
+
];
|
|
25
|
+
const REQUIRED_DENSITY_PRIORITY_ROLES = ["context", "primary-outcome", "next-action"];
|
|
26
|
+
const DEFERRED_DENSITY_PRIORITY_ROLES = ["telemetry", "evidence", "history"];
|
|
27
|
+
const DEFERRED_DENSITY_PRIORITY_ROLE_SET = new Set(DEFERRED_DENSITY_PRIORITY_ROLES);
|
|
28
|
+
function duplicateValues(values) {
|
|
29
|
+
const seen = new Set();
|
|
30
|
+
const duplicates = new Set();
|
|
31
|
+
for (const value of values) {
|
|
32
|
+
if (seen.has(value))
|
|
33
|
+
duplicates.add(value);
|
|
34
|
+
seen.add(value);
|
|
35
|
+
}
|
|
36
|
+
return [...duplicates].sort();
|
|
37
|
+
}
|
|
38
|
+
function hexToRgb(value) {
|
|
39
|
+
if (!/^#[0-9a-f]{6}$/i.test(value))
|
|
40
|
+
return undefined;
|
|
41
|
+
return [
|
|
42
|
+
Number.parseInt(value.slice(1, 3), 16),
|
|
43
|
+
Number.parseInt(value.slice(3, 5), 16),
|
|
44
|
+
Number.parseInt(value.slice(5, 7), 16),
|
|
45
|
+
];
|
|
46
|
+
}
|
|
47
|
+
function luminance(value) {
|
|
48
|
+
const rgb = hexToRgb(value);
|
|
49
|
+
if (!rgb)
|
|
50
|
+
return undefined;
|
|
51
|
+
const channels = rgb.map((channel) => {
|
|
52
|
+
const normalized = channel / 255;
|
|
53
|
+
return normalized <= 0.04045
|
|
54
|
+
? normalized / 12.92
|
|
55
|
+
: ((normalized + 0.055) / 1.055) ** 2.4;
|
|
56
|
+
});
|
|
57
|
+
return 0.2126 * channels[0] + 0.7152 * channels[1] + 0.0722 * channels[2];
|
|
58
|
+
}
|
|
59
|
+
function contrastRatio(foreground, background) {
|
|
60
|
+
const first = luminance(foreground);
|
|
61
|
+
const second = luminance(background);
|
|
62
|
+
if (first === undefined || second === undefined)
|
|
63
|
+
return undefined;
|
|
64
|
+
return (Math.max(first, second) + 0.05) / (Math.min(first, second) + 0.05);
|
|
65
|
+
}
|
|
66
|
+
function requiredSection(deliverable, present, path, findings) {
|
|
67
|
+
if (present)
|
|
68
|
+
return;
|
|
69
|
+
findings.push({
|
|
70
|
+
ruleId: "ZTDE-DI-001",
|
|
71
|
+
severity: "error",
|
|
72
|
+
path,
|
|
73
|
+
message: `Declared deliverable ${deliverable} is missing its structured section.`,
|
|
74
|
+
remediation: `Add the ${path} section or remove ${deliverable} from scope.deliverables.`,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
function resolveTokenColor(name, tokens, modeOverrides, visited = new Set()) {
|
|
78
|
+
if (visited.has(name))
|
|
79
|
+
return undefined;
|
|
80
|
+
visited.add(name);
|
|
81
|
+
const override = modeOverrides?.get(name);
|
|
82
|
+
if (typeof override?.value === "string")
|
|
83
|
+
return override.value;
|
|
84
|
+
if (override?.reference) {
|
|
85
|
+
return resolveTokenColor(override.reference, tokens, modeOverrides, visited);
|
|
86
|
+
}
|
|
87
|
+
const token = tokens.get(name);
|
|
88
|
+
if (!token || token.type !== "color")
|
|
89
|
+
return undefined;
|
|
90
|
+
if (typeof token.value === "string")
|
|
91
|
+
return token.value;
|
|
92
|
+
return token.reference ? resolveTokenColor(token.reference, tokens, modeOverrides, visited) : undefined;
|
|
93
|
+
}
|
|
94
|
+
function tokenChainTerminates(name, tokens, visited = new Set()) {
|
|
95
|
+
if (visited.has(name))
|
|
96
|
+
return false;
|
|
97
|
+
visited.add(name);
|
|
98
|
+
const token = tokens.get(name);
|
|
99
|
+
if (!token)
|
|
100
|
+
return false;
|
|
101
|
+
if (token.value !== undefined)
|
|
102
|
+
return true;
|
|
103
|
+
return token.reference ? tokenChainTerminates(token.reference, tokens, visited) : false;
|
|
104
|
+
}
|
|
105
|
+
function resolveTokenValue(name, tokens, visited = new Set()) {
|
|
106
|
+
if (visited.has(name))
|
|
107
|
+
return undefined;
|
|
108
|
+
visited.add(name);
|
|
109
|
+
const token = tokens.get(name);
|
|
110
|
+
if (!token)
|
|
111
|
+
return undefined;
|
|
112
|
+
if (token.value !== undefined)
|
|
113
|
+
return token.value;
|
|
114
|
+
return token.reference ? resolveTokenValue(token.reference, tokens, visited) : undefined;
|
|
115
|
+
}
|
|
116
|
+
function addDuplicates(values, path, label, findings) {
|
|
117
|
+
for (const duplicate of duplicateValues(values)) {
|
|
118
|
+
findings.push({
|
|
119
|
+
ruleId: "ZTDE-DI-002",
|
|
120
|
+
severity: "error",
|
|
121
|
+
path,
|
|
122
|
+
message: `Duplicate ${label}: ${duplicate}.`,
|
|
123
|
+
remediation: `Give every ${label} a stable unique identifier.`,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
export function validateDesignDeliverable(manifest, sourcePath) {
|
|
128
|
+
const findings = [];
|
|
129
|
+
const declared = new Set(manifest.scope.deliverables);
|
|
130
|
+
if (declared.has("interface-system")) {
|
|
131
|
+
if (manifest.version === "1.0") {
|
|
132
|
+
findings.push({
|
|
133
|
+
ruleId: "ZTDE-DI-701",
|
|
134
|
+
severity: "error",
|
|
135
|
+
path: "version",
|
|
136
|
+
message: "Interface-system deliverables require design-deliverable contract version 2.0 or 2.1.",
|
|
137
|
+
remediation: "Migrate the manifest to version 2.1 and declare every required visual-polish section.",
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
for (const [path, present] of [
|
|
141
|
+
["productTask", manifest.productTask !== undefined],
|
|
142
|
+
["interfaceTrust", manifest.interfaceTrust !== undefined],
|
|
143
|
+
["informationHierarchy", manifest.informationHierarchy !== undefined],
|
|
144
|
+
["metricContracts", manifest.metricContracts !== undefined],
|
|
145
|
+
["generationWorkflow", manifest.generationWorkflow !== undefined],
|
|
146
|
+
["visualDirection", manifest.visualDirection !== undefined],
|
|
147
|
+
["typography", manifest.typography !== undefined],
|
|
148
|
+
["composition", manifest.composition !== undefined],
|
|
149
|
+
["densityProfile", manifest.densityProfile !== undefined],
|
|
150
|
+
["interactionStates", manifest.interactionStates !== undefined],
|
|
151
|
+
["motion", manifest.motion !== undefined],
|
|
152
|
+
["chartContracts", manifest.chartContracts !== undefined],
|
|
153
|
+
["renderedEvidence", manifest.renderedEvidence !== undefined],
|
|
154
|
+
["humanVisualReview", manifest.humanVisualReview !== undefined],
|
|
155
|
+
]) {
|
|
156
|
+
requiredSection("interface-system", present, path, findings);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (declared.has("brand-system")) {
|
|
160
|
+
requiredSection("brand-system", manifest.brand !== undefined, "brand", findings);
|
|
161
|
+
}
|
|
162
|
+
if (declared.has("figma-library")) {
|
|
163
|
+
requiredSection("figma-library", manifest.figma !== undefined, "figma", findings);
|
|
164
|
+
}
|
|
165
|
+
if (declared.has("asset-set")) {
|
|
166
|
+
requiredSection("asset-set", manifest.assets.length > 0, "assets", findings);
|
|
167
|
+
}
|
|
168
|
+
if (declared.has("icon-system")) {
|
|
169
|
+
requiredSection("icon-system", manifest.iconSystem !== undefined, "iconSystem", findings);
|
|
170
|
+
}
|
|
171
|
+
if (declared.has("presentation")) {
|
|
172
|
+
requiredSection("presentation", manifest.presentations.length > 0, "presentations", findings);
|
|
173
|
+
}
|
|
174
|
+
addDuplicates(manifest.scope.deliverables, "scope.deliverables", "deliverable", findings);
|
|
175
|
+
addDuplicates(manifest.tokenSystem.tokens.map((token) => token.name), "tokenSystem.tokens", "token name", findings);
|
|
176
|
+
addDuplicates(manifest.tokenSystem.modes.map((mode) => mode.name), "tokenSystem.modes", "mode name", findings);
|
|
177
|
+
addDuplicates(manifest.assets.map((asset) => asset.id), "assets", "asset identifier", findings);
|
|
178
|
+
addDuplicates(manifest.evidence.map((evidence) => evidence.id), "evidence", "evidence identifier", findings);
|
|
179
|
+
const tokens = new Map(manifest.tokenSystem.tokens.map((token) => [token.name, token]));
|
|
180
|
+
for (const [index, token] of manifest.tokenSystem.tokens.entries()) {
|
|
181
|
+
if (!token.reference)
|
|
182
|
+
continue;
|
|
183
|
+
const referenced = tokens.get(token.reference);
|
|
184
|
+
if (!referenced) {
|
|
185
|
+
findings.push({
|
|
186
|
+
ruleId: "ZTDE-DI-101",
|
|
187
|
+
severity: "error",
|
|
188
|
+
path: `tokenSystem.tokens[${index}].reference`,
|
|
189
|
+
message: `Token ${token.name} references missing token ${token.reference}.`,
|
|
190
|
+
remediation: "Add the referenced token or correct the reference.",
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
else if (referenced.type !== token.type) {
|
|
194
|
+
findings.push({
|
|
195
|
+
ruleId: "ZTDE-DI-102",
|
|
196
|
+
severity: "error",
|
|
197
|
+
path: `tokenSystem.tokens[${index}].reference`,
|
|
198
|
+
message: `Token ${token.name} and ${token.reference} have different types.`,
|
|
199
|
+
remediation: "Reference a token of the same type.",
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
else if (!tokenChainTerminates(token.name, tokens)) {
|
|
203
|
+
findings.push({
|
|
204
|
+
ruleId: "ZTDE-DI-103",
|
|
205
|
+
severity: "error",
|
|
206
|
+
path: `tokenSystem.tokens[${index}]`,
|
|
207
|
+
message: `Token ${token.name} has a cyclic or unresolved reference chain.`,
|
|
208
|
+
remediation: "Terminate every token chain at one compatible primitive token.",
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
const evidenceRecords = new Map(manifest.evidence.map((entry) => [entry.id, entry]));
|
|
213
|
+
const checkVisualTokenRefs = (refs, path, ruleId, expectedType) => {
|
|
214
|
+
for (const [index, reference] of refs.entries()) {
|
|
215
|
+
const token = tokens.get(reference);
|
|
216
|
+
if (!token) {
|
|
217
|
+
findings.push({
|
|
218
|
+
ruleId,
|
|
219
|
+
severity: "error",
|
|
220
|
+
path: `${path}[${index}]`,
|
|
221
|
+
message: `Visual contract references missing token ${reference}.`,
|
|
222
|
+
remediation: "Add the canonical token or correct the visual-contract reference.",
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
else if (token.level === "primitive") {
|
|
226
|
+
findings.push({
|
|
227
|
+
ruleId,
|
|
228
|
+
severity: "error",
|
|
229
|
+
path: `${path}[${index}]`,
|
|
230
|
+
message: `Visual usage references primitive token ${reference} directly.`,
|
|
231
|
+
remediation: "Bind component and composition usage to a semantic or component token that resolves to the primitive.",
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
else if (expectedType && token.type !== expectedType) {
|
|
235
|
+
findings.push({
|
|
236
|
+
ruleId,
|
|
237
|
+
severity: "error",
|
|
238
|
+
path: `${path}[${index}]`,
|
|
239
|
+
message: `Visual token ${reference} has type ${token.type}; expected ${expectedType}.`,
|
|
240
|
+
remediation: `Reference a semantic or component ${expectedType} token.`,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
if (manifest.interfaceTrust) {
|
|
246
|
+
addDuplicates(manifest.interfaceTrust.requiredScenarios, "interfaceTrust.requiredScenarios", "trust scenario", findings);
|
|
247
|
+
for (const scenario of REQUIRED_TRUST_SCENARIOS) {
|
|
248
|
+
if (!manifest.interfaceTrust.requiredScenarios.includes(scenario)) {
|
|
249
|
+
findings.push({
|
|
250
|
+
ruleId: "ZTDE-DI-912",
|
|
251
|
+
severity: "error",
|
|
252
|
+
path: "interfaceTrust.requiredScenarios",
|
|
253
|
+
message: `Interface-trust link omits required scenario ${scenario}.`,
|
|
254
|
+
remediation: `Include ${scenario} and bind the interface-system manifest to the complete trust contract.`,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
const validated = manifest.interfaceTrust.status === "validated";
|
|
259
|
+
if (validated && (!manifest.interfaceTrust.reportPath || !manifest.interfaceTrust.evidenceRef)) {
|
|
260
|
+
findings.push({
|
|
261
|
+
ruleId: "ZTDE-DI-912",
|
|
262
|
+
severity: "error",
|
|
263
|
+
path: "interfaceTrust",
|
|
264
|
+
message: "Interface-trust link is marked validated without a report path and evidence reference.",
|
|
265
|
+
remediation: "Set status to declared or attach the actual validator report and an evidence record.",
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
if (!validated && (manifest.interfaceTrust.reportPath || manifest.interfaceTrust.evidenceRef)) {
|
|
269
|
+
findings.push({
|
|
270
|
+
ruleId: "ZTDE-DI-912",
|
|
271
|
+
severity: "error",
|
|
272
|
+
path: "interfaceTrust",
|
|
273
|
+
message: "Declared interface-trust link carries validation evidence without validated status.",
|
|
274
|
+
remediation: "Remove premature validation evidence or set validated only after the recorded report passes.",
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
if (manifest.interfaceTrust.evidenceRef && !evidenceRecords.has(manifest.interfaceTrust.evidenceRef)) {
|
|
278
|
+
findings.push({
|
|
279
|
+
ruleId: "ZTDE-DI-912",
|
|
280
|
+
severity: "error",
|
|
281
|
+
path: "interfaceTrust.evidenceRef",
|
|
282
|
+
message: `Interface-trust link references missing evidence ${manifest.interfaceTrust.evidenceRef}.`,
|
|
283
|
+
remediation: "Add the validator-report evidence record or correct the reference.",
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
if (manifest.informationHierarchy) {
|
|
288
|
+
addDuplicates(manifest.informationHierarchy.levels, "informationHierarchy.levels", "information hierarchy level", findings);
|
|
289
|
+
for (const [index, level] of REQUIRED_INFORMATION_LEVELS.entries()) {
|
|
290
|
+
if (manifest.informationHierarchy.levels[index] !== level) {
|
|
291
|
+
findings.push({
|
|
292
|
+
ruleId: "ZTDE-DI-913",
|
|
293
|
+
severity: "error",
|
|
294
|
+
path: `informationHierarchy.levels[${index}]`,
|
|
295
|
+
message: `Information hierarchy position ${index + 1} must be ${level}.`,
|
|
296
|
+
remediation: "Restore the required context-to-history operational answer order.",
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
const validated = manifest.informationHierarchy.status === "validated";
|
|
301
|
+
if (validated && (!manifest.informationHierarchy.reportPath || !manifest.informationHierarchy.evidenceRef)) {
|
|
302
|
+
findings.push({
|
|
303
|
+
ruleId: "ZTDE-DI-913",
|
|
304
|
+
severity: "error",
|
|
305
|
+
path: "informationHierarchy",
|
|
306
|
+
message: "Information hierarchy is marked validated without a report path and evidence reference.",
|
|
307
|
+
remediation: "Set status to declared or attach the actual information validator report and evidence record.",
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
if (!validated && (manifest.informationHierarchy.reportPath || manifest.informationHierarchy.evidenceRef)) {
|
|
311
|
+
findings.push({
|
|
312
|
+
ruleId: "ZTDE-DI-913",
|
|
313
|
+
severity: "error",
|
|
314
|
+
path: "informationHierarchy",
|
|
315
|
+
message: "Declared information hierarchy carries validation evidence without validated status.",
|
|
316
|
+
remediation: "Remove premature evidence or set validated only after the recorded report passes.",
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
if (manifest.informationHierarchy.evidenceRef && !evidenceRecords.has(manifest.informationHierarchy.evidenceRef)) {
|
|
320
|
+
findings.push({
|
|
321
|
+
ruleId: "ZTDE-DI-913",
|
|
322
|
+
severity: "error",
|
|
323
|
+
path: "informationHierarchy.evidenceRef",
|
|
324
|
+
message: `Information hierarchy references missing evidence ${manifest.informationHierarchy.evidenceRef}.`,
|
|
325
|
+
remediation: "Add the validator-report evidence record or correct the reference.",
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
if (manifest.metricContracts) {
|
|
330
|
+
addDuplicates(manifest.metricContracts.metrics.map((entry) => entry.metricId), "metricContracts.metrics", "metric contract", findings);
|
|
331
|
+
if (manifest.informationHierarchy &&
|
|
332
|
+
manifest.metricContracts.informationContractId !== manifest.informationHierarchy.contractId) {
|
|
333
|
+
findings.push({
|
|
334
|
+
ruleId: "ZTDE-DI-914",
|
|
335
|
+
severity: "error",
|
|
336
|
+
path: "metricContracts.informationContractId",
|
|
337
|
+
message: "Metric contracts do not reference the declared information hierarchy contract.",
|
|
338
|
+
remediation: "Use the same information-contract identifier for hierarchy, metrics, and charts.",
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
const chartIds = new Set(manifest.chartContracts?.map((entry) => entry.id) ?? []);
|
|
342
|
+
for (const [metricIndex, metric] of manifest.metricContracts.metrics.entries()) {
|
|
343
|
+
for (const [chartIndex, chartRef] of metric.chartRefs.entries()) {
|
|
344
|
+
if (!chartIds.has(chartRef)) {
|
|
345
|
+
findings.push({
|
|
346
|
+
ruleId: "ZTDE-DI-914",
|
|
347
|
+
severity: "error",
|
|
348
|
+
path: `metricContracts.metrics[${metricIndex}].chartRefs[${chartIndex}]`,
|
|
349
|
+
message: `Metric ${metric.metricId} references missing chart ${chartRef}.`,
|
|
350
|
+
remediation: "Add the visual chart contract or remove the unsupported chart reference.",
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
const metricIds = new Set(manifest.metricContracts.metrics.map((entry) => entry.metricId));
|
|
356
|
+
for (const [chartIndex, chart] of manifest.chartContracts?.entries() ?? []) {
|
|
357
|
+
for (const [metricIndex, metricRef] of chart.metricRefs.entries()) {
|
|
358
|
+
if (!metricIds.has(metricRef)) {
|
|
359
|
+
findings.push({
|
|
360
|
+
ruleId: "ZTDE-DI-914",
|
|
361
|
+
severity: "error",
|
|
362
|
+
path: `chartContracts[${chartIndex}].metricRefs[${metricIndex}]`,
|
|
363
|
+
message: `Chart ${chart.id} references metric ${metricRef} outside metricContracts.`,
|
|
364
|
+
remediation: "Add the metric decision contract or correct the chart metric reference.",
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
if (manifest.generationWorkflow) {
|
|
371
|
+
addDuplicates(manifest.generationWorkflow.steps.map((entry) => entry.stage), "generationWorkflow.steps", "generation stage", findings);
|
|
372
|
+
const allowedStatuses = {
|
|
373
|
+
"product-task": new Set(["declared"]),
|
|
374
|
+
"truth-data-source-contract": new Set(["declared"]),
|
|
375
|
+
"information-architecture": new Set(["declared"]),
|
|
376
|
+
"interaction-state-model": new Set(["declared"]),
|
|
377
|
+
"visual-direction": new Set(["declared"]),
|
|
378
|
+
"token-architecture": new Set(["declared"]),
|
|
379
|
+
implementation: new Set(["required", "implemented"]),
|
|
380
|
+
"automated-verification": new Set(["required", "verified"]),
|
|
381
|
+
"human-visual-review": new Set(["review-required", "review-completed"]),
|
|
382
|
+
};
|
|
383
|
+
const allowedArtifactRefs = new Set([
|
|
384
|
+
manifest.id,
|
|
385
|
+
manifest.productTask?.productContractId,
|
|
386
|
+
manifest.interfaceTrust?.contractId,
|
|
387
|
+
manifest.informationHierarchy?.contractId,
|
|
388
|
+
...(manifest.metricContracts?.metrics.map((entry) => entry.metricId) ?? []),
|
|
389
|
+
...evidenceRecords.keys(),
|
|
390
|
+
].filter((value) => Boolean(value)));
|
|
391
|
+
for (const [index, stage] of REQUIRED_GENERATION_STAGES.entries()) {
|
|
392
|
+
const entry = manifest.generationWorkflow.steps[index];
|
|
393
|
+
if (!entry || entry.stage !== stage) {
|
|
394
|
+
findings.push({
|
|
395
|
+
ruleId: "ZTDE-DI-915",
|
|
396
|
+
severity: "error",
|
|
397
|
+
path: `generationWorkflow.steps[${index}]`,
|
|
398
|
+
message: `Generation workflow position ${index + 1} must be ${stage}.`,
|
|
399
|
+
remediation: "Restore the required product-task through human-review generation order.",
|
|
400
|
+
});
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
if (!allowedStatuses[stage].has(entry.status)) {
|
|
404
|
+
findings.push({
|
|
405
|
+
ruleId: "ZTDE-DI-915",
|
|
406
|
+
severity: "error",
|
|
407
|
+
path: `generationWorkflow.steps[${index}].status`,
|
|
408
|
+
message: `Stage ${stage} cannot use status ${entry.status}.`,
|
|
409
|
+
remediation: `Use one of: ${[...allowedStatuses[stage]].join(", ")}.`,
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
for (const [referenceIndex, reference] of entry.artifactRefs.entries()) {
|
|
413
|
+
if (!allowedArtifactRefs.has(reference)) {
|
|
414
|
+
findings.push({
|
|
415
|
+
ruleId: "ZTDE-DI-915",
|
|
416
|
+
severity: "error",
|
|
417
|
+
path: `generationWorkflow.steps[${index}].artifactRefs[${referenceIndex}]`,
|
|
418
|
+
message: `Generation stage ${stage} references unknown artifact ${reference}.`,
|
|
419
|
+
remediation: "Reference the manifest, linked contracts, metric contracts, or declared evidence records.",
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
if (["verified", "review-completed"].includes(entry.status) && entry.artifactRefs.length === 0) {
|
|
424
|
+
findings.push({
|
|
425
|
+
ruleId: "ZTDE-DI-915",
|
|
426
|
+
severity: "error",
|
|
427
|
+
path: `generationWorkflow.steps[${index}].artifactRefs`,
|
|
428
|
+
message: `Completed stage ${stage} has no evidence reference.`,
|
|
429
|
+
remediation: "Attach the actual verification or reviewer-supplied evidence record.",
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
const implementation = manifest.generationWorkflow.steps.find((entry) => entry.stage === "implementation");
|
|
434
|
+
const automated = manifest.generationWorkflow.steps.find((entry) => entry.stage === "automated-verification");
|
|
435
|
+
const human = manifest.generationWorkflow.steps.find((entry) => entry.stage === "human-visual-review");
|
|
436
|
+
if (automated?.status === "verified" && implementation?.status !== "implemented") {
|
|
437
|
+
findings.push({
|
|
438
|
+
ruleId: "ZTDE-DI-915",
|
|
439
|
+
severity: "error",
|
|
440
|
+
path: "generationWorkflow.steps",
|
|
441
|
+
message: "Automated verification is marked complete before implementation.",
|
|
442
|
+
remediation: "Keep verification required until an implemented artifact has produced the referenced evidence.",
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
if (human?.status === "review-completed") {
|
|
446
|
+
if (automated?.status !== "verified" || manifest.humanVisualReview?.status !== "completed") {
|
|
447
|
+
findings.push({
|
|
448
|
+
ruleId: "ZTDE-DI-915",
|
|
449
|
+
severity: "error",
|
|
450
|
+
path: "generationWorkflow.steps",
|
|
451
|
+
message: "Human visual review is marked complete before automated evidence and attributable review are complete.",
|
|
452
|
+
remediation: "Keep review-required until automated verification passes and reviewer-supplied evidence is recorded.",
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
if (manifest.visualDirection) {
|
|
458
|
+
checkVisualTokenRefs(manifest.visualDirection.tokenRefs, "visualDirection.tokenRefs", "ZTDE-DI-701");
|
|
459
|
+
for (const [index, reference] of manifest.visualDirection.referenceEvidenceRefs.entries()) {
|
|
460
|
+
if (!evidenceRecords.has(reference)) {
|
|
461
|
+
findings.push({
|
|
462
|
+
ruleId: "ZTDE-DI-701",
|
|
463
|
+
severity: "error",
|
|
464
|
+
path: `visualDirection.referenceEvidenceRefs[${index}]`,
|
|
465
|
+
message: `Visual direction references missing evidence ${reference}.`,
|
|
466
|
+
remediation: "Add the evidence record or remove the unsupported visual reference.",
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
const ornament = manifest.visualDirection.ornamentPolicy;
|
|
471
|
+
for (const [name, allowed] of Object.entries(ornament)) {
|
|
472
|
+
if (allowed) {
|
|
473
|
+
findings.push({
|
|
474
|
+
ruleId: "ZTDE-DI-707",
|
|
475
|
+
severity: "error",
|
|
476
|
+
path: `visualDirection.ornamentPolicy.${name}`,
|
|
477
|
+
message: `Visual direction allows prohibited ornament category ${name}.`,
|
|
478
|
+
remediation: "Remove ornamental treatment or bind the visual element to a concrete product meaning and task.",
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
if (manifest.typography) {
|
|
484
|
+
addDuplicates(manifest.typography.roles.map((entry) => entry.role), "typography.roles", "typography role", findings);
|
|
485
|
+
const requiredRoles = ["body", "label", "heading", "metadata", "metric", "evidence", "log", "code"];
|
|
486
|
+
for (const role of requiredRoles) {
|
|
487
|
+
if (!manifest.typography.roles.some((entry) => entry.role === role)) {
|
|
488
|
+
findings.push({
|
|
489
|
+
ruleId: "ZTDE-DI-702",
|
|
490
|
+
severity: "error",
|
|
491
|
+
path: "typography.roles",
|
|
492
|
+
message: `Typography role ${role} is missing.`,
|
|
493
|
+
remediation: `Add the ${role} role with semantic family, size, weight, line-height, and color tokens.`,
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
for (const [index, role] of manifest.typography.roles.entries()) {
|
|
498
|
+
checkVisualTokenRefs([role.familyToken], `typography.roles[${index}].familyToken`, "ZTDE-DI-702", "font-family");
|
|
499
|
+
checkVisualTokenRefs([role.sizeToken], `typography.roles[${index}].sizeToken`, "ZTDE-DI-702", "dimension");
|
|
500
|
+
checkVisualTokenRefs([role.weightToken], `typography.roles[${index}].weightToken`, "ZTDE-DI-702", "font-weight");
|
|
501
|
+
checkVisualTokenRefs([role.lineHeightToken], `typography.roles[${index}].lineHeightToken`, "ZTDE-DI-702", "number");
|
|
502
|
+
checkVisualTokenRefs([role.colorToken], `typography.roles[${index}].colorToken`, "ZTDE-DI-702", "color");
|
|
503
|
+
}
|
|
504
|
+
if (manifest.typography.numericAlignment !== "tabular") {
|
|
505
|
+
findings.push({
|
|
506
|
+
ruleId: "ZTDE-DI-702",
|
|
507
|
+
severity: "warning",
|
|
508
|
+
path: "typography.numericAlignment",
|
|
509
|
+
message: "Operational metrics use proportional numeric alignment.",
|
|
510
|
+
remediation: "Use tabular numerals for changing metrics and aligned comparisons unless the typeface lacks support.",
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
if (manifest.composition) {
|
|
515
|
+
addDuplicates(manifest.composition.grids.map((entry) => String(entry.viewport)), "composition.grids", "responsive viewport", findings);
|
|
516
|
+
const requiredViewports = [375, 768, 1024, 1440];
|
|
517
|
+
for (const viewport of requiredViewports) {
|
|
518
|
+
if (!manifest.composition.grids.some((entry) => entry.viewport === viewport)) {
|
|
519
|
+
findings.push({
|
|
520
|
+
ruleId: "ZTDE-DI-703",
|
|
521
|
+
severity: "error",
|
|
522
|
+
path: "composition.grids",
|
|
523
|
+
message: `Composition grid for ${viewport} CSS pixels is missing.`,
|
|
524
|
+
remediation: `Declare columns, gutter, margin, and composition behavior at ${viewport} CSS pixels.`,
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
for (const [index, grid] of manifest.composition.grids.entries()) {
|
|
529
|
+
checkVisualTokenRefs([grid.gutterToken, grid.marginToken], `composition.grids[${index}].tokens`, "ZTDE-DI-703", "dimension");
|
|
530
|
+
}
|
|
531
|
+
checkVisualTokenRefs([manifest.composition.spacingRhythm.baseToken, ...manifest.composition.spacingRhythm.allowedStepTokens], "composition.spacingRhythm", "ZTDE-DI-703", "dimension");
|
|
532
|
+
for (const [index, component] of manifest.composition.stableDimensions.entries()) {
|
|
533
|
+
checkVisualTokenRefs(component.tokenRefs, `composition.stableDimensions[${index}].tokenRefs`, "ZTDE-DI-703", "dimension");
|
|
534
|
+
}
|
|
535
|
+
for (const [path, entries, required] of [
|
|
536
|
+
["surfaces", manifest.composition.surfaces, ["canvas", "subtle", "raised"]],
|
|
537
|
+
["borders", manifest.composition.borders, ["default", "strong", "focus", "selected"]],
|
|
538
|
+
["elevations", manifest.composition.elevations, ["base", "raised", "overlay"]],
|
|
539
|
+
["emphasis", manifest.composition.emphasis, ["primary", "secondary", "tertiary", "muted"]],
|
|
540
|
+
]) {
|
|
541
|
+
const values = entries.map((entry) => entry.role ?? entry.level ?? "");
|
|
542
|
+
addDuplicates(values, `composition.${path}`, `${path} role`, findings);
|
|
543
|
+
for (const role of required) {
|
|
544
|
+
if (!values.includes(role)) {
|
|
545
|
+
findings.push({
|
|
546
|
+
ruleId: "ZTDE-DI-704",
|
|
547
|
+
severity: "error",
|
|
548
|
+
path: `composition.${path}`,
|
|
549
|
+
message: `Composition ${path} hierarchy is missing ${role}.`,
|
|
550
|
+
remediation: `Declare the ${role} role with semantic token bindings.`,
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
for (const [index, entry] of manifest.composition.surfaces.entries()) {
|
|
556
|
+
checkVisualTokenRefs([entry.tokenRef], `composition.surfaces[${index}].tokenRef`, "ZTDE-DI-704", "color");
|
|
557
|
+
}
|
|
558
|
+
for (const [index, entry] of manifest.composition.borders.entries()) {
|
|
559
|
+
checkVisualTokenRefs([entry.tokenRef], `composition.borders[${index}].tokenRef`, "ZTDE-DI-704", "color");
|
|
560
|
+
}
|
|
561
|
+
for (const [index, entry] of manifest.composition.elevations.entries()) {
|
|
562
|
+
checkVisualTokenRefs([entry.tokenRef], `composition.elevations[${index}].tokenRef`, "ZTDE-DI-704", "shadow");
|
|
563
|
+
}
|
|
564
|
+
for (const [index, entry] of manifest.composition.emphasis.entries()) {
|
|
565
|
+
checkVisualTokenRefs([entry.textToken, entry.surfaceToken], `composition.emphasis[${index}].tokens`, "ZTDE-DI-704", "color");
|
|
566
|
+
}
|
|
567
|
+
checkVisualTokenRefs([manifest.composition.selectedState.backgroundToken, manifest.composition.selectedState.borderToken], "composition.selectedState", "ZTDE-DI-704", "color");
|
|
568
|
+
}
|
|
569
|
+
if (manifest.densityProfile) {
|
|
570
|
+
checkVisualTokenRefs([
|
|
571
|
+
manifest.densityProfile.controlHeightToken,
|
|
572
|
+
manifest.densityProfile.rowHeightToken,
|
|
573
|
+
manifest.densityProfile.compactRowHeightToken,
|
|
574
|
+
...manifest.densityProfile.spacingTokenRefs,
|
|
575
|
+
], "densityProfile", "ZTDE-DI-705", "dimension");
|
|
576
|
+
addDuplicates(manifest.densityProfile.viewportBehavior.map((entry) => String(entry.viewport)), "densityProfile.viewportBehavior", "density viewport", findings);
|
|
577
|
+
for (const viewport of [375, 768, 1024, 1440]) {
|
|
578
|
+
if (!manifest.densityProfile.viewportBehavior.some((entry) => entry.viewport === viewport)) {
|
|
579
|
+
findings.push({
|
|
580
|
+
ruleId: "ZTDE-DI-705",
|
|
581
|
+
severity: "error",
|
|
582
|
+
path: "densityProfile.viewportBehavior",
|
|
583
|
+
message: `Density behavior for ${viewport} CSS pixels is missing.`,
|
|
584
|
+
remediation: `Declare density mode and visible priorities at ${viewport} CSS pixels.`,
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
if (manifest.version === "2.1") {
|
|
589
|
+
for (const [index, entry] of manifest.densityProfile.viewportBehavior.entries()) {
|
|
590
|
+
const path = `densityProfile.viewportBehavior[${index}]`;
|
|
591
|
+
if (!entry.priorityRoles) {
|
|
592
|
+
findings.push({
|
|
593
|
+
ruleId: "ZTDE-DI-709",
|
|
594
|
+
severity: "error",
|
|
595
|
+
path: `${path}.priorityRoles`,
|
|
596
|
+
message: `Density behavior for ${entry.viewport} CSS pixels has no machine-readable decision order.`,
|
|
597
|
+
remediation: "Map each visible priority to a canonical priority role in the same order.",
|
|
598
|
+
});
|
|
599
|
+
continue;
|
|
600
|
+
}
|
|
601
|
+
addDuplicates(entry.priorityRoles, `${path}.priorityRoles`, "density priority role", findings);
|
|
602
|
+
if (entry.priorityRoles.length !== entry.visiblePriorities.length) {
|
|
603
|
+
findings.push({
|
|
604
|
+
ruleId: "ZTDE-DI-709",
|
|
605
|
+
severity: "error",
|
|
606
|
+
path,
|
|
607
|
+
message: `Density behavior for ${entry.viewport} CSS pixels declares ${entry.visiblePriorities.length} visible priorities but ${entry.priorityRoles.length} priority roles.`,
|
|
608
|
+
remediation: "Provide one canonical priority role for each visible priority.",
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
for (const role of REQUIRED_DENSITY_PRIORITY_ROLES) {
|
|
612
|
+
if (!entry.priorityRoles.includes(role)) {
|
|
613
|
+
findings.push({
|
|
614
|
+
ruleId: "ZTDE-DI-709",
|
|
615
|
+
severity: "error",
|
|
616
|
+
path: `${path}.priorityRoles`,
|
|
617
|
+
message: `Density behavior for ${entry.viewport} CSS pixels omits required ${role} content.`,
|
|
618
|
+
remediation: "Keep context, the primary outcome, and the next action visible before optional detail.",
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
const actionIndex = entry.priorityRoles.indexOf("next-action");
|
|
623
|
+
for (const role of DEFERRED_DENSITY_PRIORITY_ROLES) {
|
|
624
|
+
const detailIndex = entry.priorityRoles.indexOf(role);
|
|
625
|
+
if (detailIndex !== -1 && (actionIndex === -1 || detailIndex < actionIndex)) {
|
|
626
|
+
findings.push({
|
|
627
|
+
ruleId: "ZTDE-DI-709",
|
|
628
|
+
severity: "error",
|
|
629
|
+
path: `${path}.priorityRoles`,
|
|
630
|
+
message: `Density behavior for ${entry.viewport} CSS pixels places ${role} before the next action.`,
|
|
631
|
+
remediation: "Place decision-critical context, outcome, exceptions, and action before telemetry, evidence detail, or history.",
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
if (entry.viewport === 375 &&
|
|
636
|
+
(entry.mode !== "comfortable" ||
|
|
637
|
+
entry.priorityRoles.length > 4 ||
|
|
638
|
+
entry.priorityRoles.some((role) => DEFERRED_DENSITY_PRIORITY_ROLE_SET.has(role)))) {
|
|
639
|
+
findings.push({
|
|
640
|
+
ruleId: "ZTDE-DI-709",
|
|
641
|
+
severity: "error",
|
|
642
|
+
path,
|
|
643
|
+
message: "The 375 CSS-pixel composition does not preserve a restrained decision-first view.",
|
|
644
|
+
remediation: "Use comfortable density and expose at most context, outcome, critical exceptions, and next action before expandable detail.",
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
if (entry.viewport === 768 && entry.mode === "dense") {
|
|
648
|
+
findings.push({
|
|
649
|
+
ruleId: "ZTDE-DI-709",
|
|
650
|
+
severity: "error",
|
|
651
|
+
path: `${path}.mode`,
|
|
652
|
+
message: "The 768 CSS-pixel composition uses dense mode before sufficient horizontal space is available.",
|
|
653
|
+
remediation: "Use comfortable or compact density and verify text resize and touch operation before selecting dense mode.",
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
if (manifest.interactionStates) {
|
|
660
|
+
addDuplicates(manifest.interactionStates.states.map((entry) => entry.state), "interactionStates.states", "interaction state", findings);
|
|
661
|
+
const requiredStates = ["loading", "empty", "success", "warning", "error", "partial", "disabled", "selected", "focus"];
|
|
662
|
+
for (const state of requiredStates) {
|
|
663
|
+
if (!manifest.interactionStates.states.some((entry) => entry.state === state)) {
|
|
664
|
+
findings.push({
|
|
665
|
+
ruleId: "ZTDE-DI-706",
|
|
666
|
+
severity: "error",
|
|
667
|
+
path: "interactionStates.states",
|
|
668
|
+
message: `Interaction state ${state} is missing from the visual language.`,
|
|
669
|
+
remediation: `Declare ${state} behavior, semantic tokens, and visible cues.`,
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
for (const [index, state] of manifest.interactionStates.states.entries()) {
|
|
674
|
+
checkVisualTokenRefs(state.tokenRefs, `interactionStates.states[${index}].tokenRefs`, "ZTDE-DI-706");
|
|
675
|
+
if (["warning", "error", "partial", "selected"].includes(state.state) && !state.textCue && !state.iconCue) {
|
|
676
|
+
findings.push({
|
|
677
|
+
ruleId: "ZTDE-DI-706",
|
|
678
|
+
severity: "error",
|
|
679
|
+
path: `interactionStates.states[${index}]`,
|
|
680
|
+
message: `State ${state.state} has no text or icon cue independent of color.`,
|
|
681
|
+
remediation: "Add visible text or a semantic icon in addition to color and position.",
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
if (manifest.motion) {
|
|
687
|
+
const durationRanges = {
|
|
688
|
+
instant: [0, 100],
|
|
689
|
+
feedback: [100, 220],
|
|
690
|
+
transition: [150, 350],
|
|
691
|
+
emphasis: [200, 500],
|
|
692
|
+
};
|
|
693
|
+
for (const [category, reference] of Object.entries(manifest.motion.durationTokens)) {
|
|
694
|
+
checkVisualTokenRefs([reference], `motion.durationTokens.${category}`, "ZTDE-DI-708", "duration");
|
|
695
|
+
const value = resolveTokenValue(reference, tokens);
|
|
696
|
+
const [minimum, maximum] = durationRanges[category];
|
|
697
|
+
if (typeof value !== "number" || value < minimum || value > maximum) {
|
|
698
|
+
findings.push({
|
|
699
|
+
ruleId: "ZTDE-DI-708",
|
|
700
|
+
severity: "error",
|
|
701
|
+
path: `motion.durationTokens.${category}`,
|
|
702
|
+
message: `Motion category ${category} does not resolve to ${minimum}-${maximum} milliseconds.`,
|
|
703
|
+
remediation: "Reference a semantic duration token whose primitive numeric value fits the category.",
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
addDuplicates(manifest.motion.motions.map((entry) => entry.id), "motion.motions", "motion identifier", findings);
|
|
708
|
+
const motions = new Set(manifest.motion.motions.map((entry) => entry.id));
|
|
709
|
+
const equivalents = new Set(manifest.motion.reducedMotion.equivalents.map((entry) => entry.motionRef));
|
|
710
|
+
for (const [index, equivalent] of manifest.motion.reducedMotion.equivalents.entries()) {
|
|
711
|
+
if (!motions.has(equivalent.motionRef)) {
|
|
712
|
+
findings.push({
|
|
713
|
+
ruleId: "ZTDE-DI-708",
|
|
714
|
+
severity: "error",
|
|
715
|
+
path: `motion.reducedMotion.equivalents[${index}].motionRef`,
|
|
716
|
+
message: `Reduced-motion equivalent references missing motion ${equivalent.motionRef}.`,
|
|
717
|
+
remediation: "Reference a declared motion or remove the unrelated equivalent.",
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
for (const motion of manifest.motion.motions) {
|
|
722
|
+
if (!equivalents.has(motion.id)) {
|
|
723
|
+
findings.push({
|
|
724
|
+
ruleId: "ZTDE-DI-708",
|
|
725
|
+
severity: "error",
|
|
726
|
+
path: "motion.reducedMotion.equivalents",
|
|
727
|
+
message: `Motion ${motion.id} has no reduced-motion equivalent.`,
|
|
728
|
+
remediation: "Declare how the motion is removed, replaced, or shortened without losing state meaning.",
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
if (manifest.chartContracts) {
|
|
734
|
+
addDuplicates(manifest.chartContracts.map((entry) => entry.id), "chartContracts", "chart contract", findings);
|
|
735
|
+
for (const [index, chart] of manifest.chartContracts.entries()) {
|
|
736
|
+
checkVisualTokenRefs(chart.tokenRefs, `chartContracts[${index}].tokenRefs`, "ZTDE-DI-801");
|
|
737
|
+
if (chart.backgroundToken) {
|
|
738
|
+
checkVisualTokenRefs([chart.backgroundToken], `chartContracts[${index}].backgroundToken`, "ZTDE-DI-801", "color");
|
|
739
|
+
}
|
|
740
|
+
if (!chart.titleVisible || !chart.valuesVisible) {
|
|
741
|
+
findings.push({
|
|
742
|
+
ruleId: "ZTDE-DI-801",
|
|
743
|
+
severity: "error",
|
|
744
|
+
path: `chartContracts[${index}]`,
|
|
745
|
+
message: `Chart ${chart.id} hides its title or readable values.`,
|
|
746
|
+
remediation: "Show a visible title and values; do not depend on hover, shape, or color alone.",
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
if (!chart.legend.visible && !chart.legend.reason) {
|
|
750
|
+
findings.push({
|
|
751
|
+
ruleId: "ZTDE-DI-801",
|
|
752
|
+
severity: "error",
|
|
753
|
+
path: `chartContracts[${index}].legend.reason`,
|
|
754
|
+
message: `Chart ${chart.id} omits its legend without documenting direct labeling.`,
|
|
755
|
+
remediation: "Show a legend or state why direct labels make every series unambiguous.",
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
const cues = new Set(chart.nonColorCues);
|
|
759
|
+
if (cues.size !== chart.nonColorCues.length || [...cues].every((cue) => cue === "color")) {
|
|
760
|
+
findings.push({
|
|
761
|
+
ruleId: "ZTDE-DI-801",
|
|
762
|
+
severity: "error",
|
|
763
|
+
path: `chartContracts[${index}].nonColorCues`,
|
|
764
|
+
message: `Chart ${chart.id} lacks distinct color-independent cues.`,
|
|
765
|
+
remediation: "Combine color with direct text, values, shape, pattern, position, or line style.",
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
if (chart.decorative) {
|
|
769
|
+
findings.push({
|
|
770
|
+
ruleId: "ZTDE-DI-801",
|
|
771
|
+
severity: "error",
|
|
772
|
+
path: `chartContracts[${index}].decorative`,
|
|
773
|
+
message: `Chart ${chart.id} is decorative.`,
|
|
774
|
+
remediation: "Remove the chart or bind it to a metric decision, comparison, accessible alternative, and explicit states.",
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
if (manifest.renderedEvidence) {
|
|
780
|
+
addDuplicates(manifest.renderedEvidence.captures.map((entry) => String(entry.viewport)), "renderedEvidence.captures", "rendered viewport", findings);
|
|
781
|
+
for (const viewport of [375, 768, 1024, 1440]) {
|
|
782
|
+
if (!manifest.renderedEvidence.captures.some((entry) => entry.viewport === viewport)) {
|
|
783
|
+
findings.push({
|
|
784
|
+
ruleId: "ZTDE-DI-901",
|
|
785
|
+
severity: "error",
|
|
786
|
+
path: "renderedEvidence.captures",
|
|
787
|
+
message: `Rendered-evidence declaration for ${viewport} CSS pixels is missing.`,
|
|
788
|
+
remediation: `Add a planned, captured, or verified record for ${viewport} CSS pixels.`,
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
if (manifest.humanVisualReview) {
|
|
794
|
+
addDuplicates(manifest.humanVisualReview.dimensions, "humanVisualReview.dimensions", "human-review dimension", findings);
|
|
795
|
+
for (const dimension of ["hierarchy", "balance", "scanability", "density", "domain-fit"]) {
|
|
796
|
+
if (!manifest.humanVisualReview.dimensions.includes(dimension)) {
|
|
797
|
+
findings.push({
|
|
798
|
+
ruleId: "ZTDE-DI-902",
|
|
799
|
+
severity: "error",
|
|
800
|
+
path: "humanVisualReview.dimensions",
|
|
801
|
+
message: `Human visual review omits ${dimension}.`,
|
|
802
|
+
remediation: `Include ${dimension} in the attributable rendered-output review.`,
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
if (manifest.humanVisualReview.status === "completed" && manifest.humanVisualReview.reviewers.length === 0) {
|
|
807
|
+
findings.push({
|
|
808
|
+
ruleId: "ZTDE-DI-902",
|
|
809
|
+
severity: "error",
|
|
810
|
+
path: "humanVisualReview.reviewers",
|
|
811
|
+
message: "Human visual review is marked completed without an attributable reviewer.",
|
|
812
|
+
remediation: "Set status to required or record reviewer-supplied name, role, timestamp, and review evidence. Agents must not invent this record.",
|
|
813
|
+
});
|
|
814
|
+
}
|
|
815
|
+
for (const [index, reviewer] of manifest.humanVisualReview.reviewers.entries()) {
|
|
816
|
+
const record = evidenceRecords.get(reviewer.evidenceRef);
|
|
817
|
+
if (!record || record.kind !== "review") {
|
|
818
|
+
findings.push({
|
|
819
|
+
ruleId: "ZTDE-DI-902",
|
|
820
|
+
severity: "error",
|
|
821
|
+
path: `humanVisualReview.reviewers[${index}].evidenceRef`,
|
|
822
|
+
message: `Human reviewer ${reviewer.name} does not reference review evidence.`,
|
|
823
|
+
remediation: "Add an evidence record with kind review that contains the reviewer-supplied assessment.",
|
|
824
|
+
});
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
for (const [modeIndex, mode] of manifest.tokenSystem.modes.entries()) {
|
|
829
|
+
addDuplicates(mode.overrides.map((override) => override.token), `tokenSystem.modes[${modeIndex}].overrides`, "mode override", findings);
|
|
830
|
+
for (const [overrideIndex, override] of mode.overrides.entries()) {
|
|
831
|
+
const token = tokens.get(override.token);
|
|
832
|
+
if (!token) {
|
|
833
|
+
findings.push({
|
|
834
|
+
ruleId: "ZTDE-DI-104",
|
|
835
|
+
severity: "error",
|
|
836
|
+
path: `tokenSystem.modes[${modeIndex}].overrides[${overrideIndex}].token`,
|
|
837
|
+
message: `Mode ${mode.name} overrides missing token ${override.token}.`,
|
|
838
|
+
remediation: "Correct the token name or add the token before declaring the override.",
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
if (override.reference && !tokens.has(override.reference)) {
|
|
842
|
+
findings.push({
|
|
843
|
+
ruleId: "ZTDE-DI-104",
|
|
844
|
+
severity: "error",
|
|
845
|
+
path: `tokenSystem.modes[${modeIndex}].overrides[${overrideIndex}].reference`,
|
|
846
|
+
message: `Mode ${mode.name} references missing token ${override.reference}.`,
|
|
847
|
+
remediation: "Correct the mode reference or add the referenced token.",
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
if (token &&
|
|
851
|
+
override.reference &&
|
|
852
|
+
tokens.get(override.reference)?.type !== token.type) {
|
|
853
|
+
findings.push({
|
|
854
|
+
ruleId: "ZTDE-DI-105",
|
|
855
|
+
severity: "error",
|
|
856
|
+
path: `tokenSystem.modes[${modeIndex}].overrides[${overrideIndex}].reference`,
|
|
857
|
+
message: `Mode ${mode.name} changes ${override.token} to an incompatible token type.`,
|
|
858
|
+
remediation: "Reference a token with the same type as the overridden token.",
|
|
859
|
+
});
|
|
860
|
+
}
|
|
861
|
+
if (token?.type === "color" && override.value !== undefined && (typeof override.value !== "string" || !hexToRgb(override.value))) {
|
|
862
|
+
findings.push({
|
|
863
|
+
ruleId: "ZTDE-DI-105",
|
|
864
|
+
severity: "error",
|
|
865
|
+
path: `tokenSystem.modes[${modeIndex}].overrides[${overrideIndex}].value`,
|
|
866
|
+
message: `Color override for ${override.token} is not an opaque six-digit hexadecimal color.`,
|
|
867
|
+
remediation: "Use an opaque #RRGGBB value or a compatible token reference.",
|
|
868
|
+
});
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
const assets = new Map(manifest.assets.map((asset) => [asset.id, asset]));
|
|
873
|
+
if (manifest.brand) {
|
|
874
|
+
addDuplicates(manifest.brand.marks.map((mark) => mark.id), "brand.marks", "brand mark", findings);
|
|
875
|
+
for (const [index, mark] of manifest.brand.marks.entries()) {
|
|
876
|
+
if (!assets.has(mark.asset)) {
|
|
877
|
+
findings.push({
|
|
878
|
+
ruleId: "ZTDE-DI-201",
|
|
879
|
+
severity: "error",
|
|
880
|
+
path: `brand.marks[${index}].asset`,
|
|
881
|
+
message: `Brand mark ${mark.id} references missing asset ${mark.asset}.`,
|
|
882
|
+
remediation: "Add the logo asset with approved provenance or correct the asset identifier.",
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
if (manifest.figma) {
|
|
888
|
+
addDuplicates(manifest.figma.pages.map((page) => page.name), "figma.pages", "Figma page name", findings);
|
|
889
|
+
const pageRoles = new Set(manifest.figma.pages.map((page) => page.role));
|
|
890
|
+
for (const requiredRole of ["foundations", "components"]) {
|
|
891
|
+
if (!pageRoles.has(requiredRole)) {
|
|
892
|
+
findings.push({
|
|
893
|
+
ruleId: "ZTDE-DI-202",
|
|
894
|
+
severity: "error",
|
|
895
|
+
path: "figma.pages",
|
|
896
|
+
message: `Figma library lacks a ${requiredRole} page.`,
|
|
897
|
+
remediation: `Add a maintained ${requiredRole} page with a stated purpose.`,
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
addDuplicates(manifest.figma.collections.map((collection) => collection.name), "figma.collections", "Figma collection", findings);
|
|
902
|
+
for (const [collectionIndex, collection] of manifest.figma.collections.entries()) {
|
|
903
|
+
addDuplicates(collection.modes, `figma.collections[${collectionIndex}].modes`, "Figma mode", findings);
|
|
904
|
+
for (const [tokenIndex, tokenName] of collection.tokens.entries()) {
|
|
905
|
+
if (!tokens.has(tokenName)) {
|
|
906
|
+
findings.push({
|
|
907
|
+
ruleId: "ZTDE-DI-203",
|
|
908
|
+
severity: "error",
|
|
909
|
+
path: `figma.collections[${collectionIndex}].tokens[${tokenIndex}]`,
|
|
910
|
+
message: `Figma collection ${collection.name} references missing token ${tokenName}.`,
|
|
911
|
+
remediation: "Bind the collection only to canonical manifest tokens.",
|
|
912
|
+
});
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
addDuplicates(manifest.figma.components.map((component) => component.name), "figma.components", "component name", findings);
|
|
917
|
+
for (const [componentIndex, component] of manifest.figma.components.entries()) {
|
|
918
|
+
addDuplicates(component.properties.map((property) => property.name), `figma.components[${componentIndex}].properties`, "component property", findings);
|
|
919
|
+
const states = new Set(component.states);
|
|
920
|
+
if (!states.has("default") || (component.interactive && !states.has("focus"))) {
|
|
921
|
+
findings.push({
|
|
922
|
+
ruleId: "ZTDE-DI-204",
|
|
923
|
+
severity: "error",
|
|
924
|
+
path: `figma.components[${componentIndex}].states`,
|
|
925
|
+
message: `Component ${component.name} does not declare required default and interactive focus states.`,
|
|
926
|
+
remediation: "Add default and, for interactive components, focus states to the component contract.",
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
if (component.interactive && !states.has("disabled")) {
|
|
930
|
+
findings.push({
|
|
931
|
+
ruleId: "ZTDE-DI-205",
|
|
932
|
+
severity: "warning",
|
|
933
|
+
path: `figma.components[${componentIndex}].states`,
|
|
934
|
+
message: `Interactive component ${component.name} has no disabled state.`,
|
|
935
|
+
remediation: "Add a disabled state or document why disabling is invalid for this component.",
|
|
936
|
+
});
|
|
937
|
+
}
|
|
938
|
+
if (!component.documented) {
|
|
939
|
+
findings.push({
|
|
940
|
+
ruleId: "ZTDE-DI-206",
|
|
941
|
+
severity: "warning",
|
|
942
|
+
path: `figma.components[${componentIndex}].documented`,
|
|
943
|
+
message: `Component ${component.name} lacks usage documentation.`,
|
|
944
|
+
remediation: "Document purpose, property semantics, state use, and accessibility constraints.",
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
for (const [index, asset] of manifest.assets.entries()) {
|
|
950
|
+
if (manifest.version === "2.1" && (!asset.purpose || !asset.failureBehavior)) {
|
|
951
|
+
findings.push({
|
|
952
|
+
ruleId: "ZTDE-DI-310",
|
|
953
|
+
severity: "error",
|
|
954
|
+
path: `assets[${index}]`,
|
|
955
|
+
message: `Version 2.1 asset ${asset.id} lacks a purpose or explicit failure behavior.`,
|
|
956
|
+
remediation: "Declare why the asset supports the product task and what users receive when it cannot render.",
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
if (asset.failureBehavior?.strategy === "hide-decorative" &&
|
|
960
|
+
asset.alternative.kind !== "decorative") {
|
|
961
|
+
findings.push({
|
|
962
|
+
ruleId: "ZTDE-DI-310",
|
|
963
|
+
severity: "error",
|
|
964
|
+
path: `assets[${index}].failureBehavior.strategy`,
|
|
965
|
+
message: `Informative asset ${asset.id} cannot disappear as decorative failure behavior.`,
|
|
966
|
+
remediation: "Provide a text alternative, placeholder, retry, or blocking state that preserves the asset's meaning.",
|
|
967
|
+
});
|
|
968
|
+
}
|
|
969
|
+
if (asset.alternative.kind === "decorative" &&
|
|
970
|
+
asset.failureBehavior &&
|
|
971
|
+
asset.failureBehavior.strategy !== "hide-decorative") {
|
|
972
|
+
findings.push({
|
|
973
|
+
ruleId: "ZTDE-DI-310",
|
|
974
|
+
severity: "error",
|
|
975
|
+
path: `assets[${index}].failureBehavior.strategy`,
|
|
976
|
+
message: `Decorative asset ${asset.id} declares a failure treatment that adds unsupported meaning.`,
|
|
977
|
+
remediation: "Hide failed decorative assets without introducing a placeholder, retry, or blocking state.",
|
|
978
|
+
});
|
|
979
|
+
}
|
|
980
|
+
if (asset.rights.status !== "approved") {
|
|
981
|
+
findings.push({
|
|
982
|
+
ruleId: "ZTDE-DI-301",
|
|
983
|
+
severity: "error",
|
|
984
|
+
path: `assets[${index}].rights.status`,
|
|
985
|
+
message: `Asset ${asset.id} has unresolved rights status ${asset.rights.status}.`,
|
|
986
|
+
remediation: "Do not ship the asset until rights are reviewed and recorded as approved, or replace it.",
|
|
987
|
+
});
|
|
988
|
+
}
|
|
989
|
+
if (asset.rights.status === "approved" && !asset.rights.evidence && !asset.source.sourceUrl) {
|
|
990
|
+
findings.push({
|
|
991
|
+
ruleId: "ZTDE-DI-302",
|
|
992
|
+
severity: "error",
|
|
993
|
+
path: `assets[${index}].rights`,
|
|
994
|
+
message: `Asset ${asset.id} is marked approved without a source URL or evidence path.`,
|
|
995
|
+
remediation: "Record verifiable rights evidence; an approval label alone is insufficient.",
|
|
996
|
+
});
|
|
997
|
+
}
|
|
998
|
+
if (asset.rights.status === "approved" &&
|
|
999
|
+
asset.source.origin !== "original" &&
|
|
1000
|
+
(!asset.rights.reviewedBy || !asset.rights.reviewedAt)) {
|
|
1001
|
+
findings.push({
|
|
1002
|
+
ruleId: "ZTDE-DI-309",
|
|
1003
|
+
severity: "error",
|
|
1004
|
+
path: `assets[${index}].rights`,
|
|
1005
|
+
message: `Non-original asset ${asset.id} is approved without attributable review metadata.`,
|
|
1006
|
+
remediation: "Record the reviewer-provided name and review timestamp. An agent must not invent this approval.",
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
1009
|
+
if (asset.rights.basis === "spdx-license" && !asset.rights.spdxExpression) {
|
|
1010
|
+
findings.push({
|
|
1011
|
+
ruleId: "ZTDE-DI-303",
|
|
1012
|
+
severity: "error",
|
|
1013
|
+
path: `assets[${index}].rights.spdxExpression`,
|
|
1014
|
+
message: `Asset ${asset.id} uses an SPDX basis without an SPDX expression.`,
|
|
1015
|
+
remediation: "Record the applicable SPDX identifier or expression and retain source evidence.",
|
|
1016
|
+
});
|
|
1017
|
+
}
|
|
1018
|
+
if (asset.source.origin === "generated" && !asset.generation) {
|
|
1019
|
+
findings.push({
|
|
1020
|
+
ruleId: "ZTDE-DI-304",
|
|
1021
|
+
severity: "error",
|
|
1022
|
+
path: `assets[${index}].generation`,
|
|
1023
|
+
message: `Generated asset ${asset.id} lacks generation provenance.`,
|
|
1024
|
+
remediation: "Record provider, model, prompt record, human contributions, and reference-asset rights.",
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
if (asset.source.origin !== "generated" && asset.generation) {
|
|
1028
|
+
findings.push({
|
|
1029
|
+
ruleId: "ZTDE-DI-305",
|
|
1030
|
+
severity: "warning",
|
|
1031
|
+
path: `assets[${index}].generation`,
|
|
1032
|
+
message: `Asset ${asset.id} has generation metadata but origin ${asset.source.origin}.`,
|
|
1033
|
+
remediation: "Correct the origin or remove unrelated generation metadata.",
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
for (const [referenceIndex, reference] of asset.generation?.references.entries() ?? []) {
|
|
1037
|
+
if (reference.rightsStatus !== "approved") {
|
|
1038
|
+
findings.push({
|
|
1039
|
+
ruleId: "ZTDE-DI-306",
|
|
1040
|
+
severity: "error",
|
|
1041
|
+
path: `assets[${index}].generation.references[${referenceIndex}].rightsStatus`,
|
|
1042
|
+
message: `Generated asset ${asset.id} depends on a reference with unresolved rights.`,
|
|
1043
|
+
remediation: "Approve and document the reference rights or remove the reference from the generation workflow.",
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
if (asset.alternative.kind === "decorative" && asset.alternative.content) {
|
|
1048
|
+
findings.push({
|
|
1049
|
+
ruleId: "ZTDE-DI-307",
|
|
1050
|
+
severity: "warning",
|
|
1051
|
+
path: `assets[${index}].alternative`,
|
|
1052
|
+
message: `Decorative asset ${asset.id} contains alternative text.`,
|
|
1053
|
+
remediation: "Use an empty alternative in implementation, or reclassify the asset if it communicates information.",
|
|
1054
|
+
});
|
|
1055
|
+
}
|
|
1056
|
+
if (asset.alternative.kind !== "decorative" && !asset.alternative.content) {
|
|
1057
|
+
findings.push({
|
|
1058
|
+
ruleId: "ZTDE-DI-308",
|
|
1059
|
+
severity: "error",
|
|
1060
|
+
path: `assets[${index}].alternative.content`,
|
|
1061
|
+
message: `Informative asset ${asset.id} lacks alternative content.`,
|
|
1062
|
+
remediation: "Add concise text, a long description, data table, caption, or transcript appropriate to the asset.",
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
if (manifest.iconSystem) {
|
|
1067
|
+
addDuplicates(manifest.iconSystem.icons.map((icon) => icon.id), "iconSystem.icons", "icon identifier", findings);
|
|
1068
|
+
addDuplicates(manifest.iconSystem.icons.map((icon) => icon.name), "iconSystem.icons", "icon name", findings);
|
|
1069
|
+
for (const [index, icon] of manifest.iconSystem.icons.entries()) {
|
|
1070
|
+
const asset = assets.get(icon.asset);
|
|
1071
|
+
if (!asset || asset.kind !== "icon") {
|
|
1072
|
+
findings.push({
|
|
1073
|
+
ruleId: "ZTDE-DI-401",
|
|
1074
|
+
severity: "error",
|
|
1075
|
+
path: `iconSystem.icons[${index}].asset`,
|
|
1076
|
+
message: `Icon ${icon.id} does not reference an icon asset.`,
|
|
1077
|
+
remediation: "Add or reference an approved asset whose kind is icon.",
|
|
1078
|
+
});
|
|
1079
|
+
}
|
|
1080
|
+
if (!icon.decorative && !icon.accessibleName) {
|
|
1081
|
+
findings.push({
|
|
1082
|
+
ruleId: "ZTDE-DI-402",
|
|
1083
|
+
severity: "error",
|
|
1084
|
+
path: `iconSystem.icons[${index}].accessibleName`,
|
|
1085
|
+
message: `Semantic icon ${icon.id} lacks an accessible name.`,
|
|
1086
|
+
remediation: "Provide an outcome-oriented accessible name or pair the icon with equivalent visible text.",
|
|
1087
|
+
});
|
|
1088
|
+
}
|
|
1089
|
+
if (icon.decorative && icon.accessibleName) {
|
|
1090
|
+
findings.push({
|
|
1091
|
+
ruleId: "ZTDE-DI-403",
|
|
1092
|
+
severity: "warning",
|
|
1093
|
+
path: `iconSystem.icons[${index}].accessibleName`,
|
|
1094
|
+
message: `Decorative icon ${icon.id} declares an accessible name.`,
|
|
1095
|
+
remediation: "Hide decorative icons from assistive technology or mark the icon as semantic.",
|
|
1096
|
+
});
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
for (const [presentationIndex, presentation] of manifest.presentations.entries()) {
|
|
1101
|
+
addDuplicates(presentation.masterLayouts, `presentations[${presentationIndex}].masterLayouts`, "master layout", findings);
|
|
1102
|
+
addDuplicates(presentation.slides.map((slide) => slide.id), `presentations[${presentationIndex}].slides`, "slide identifier", findings);
|
|
1103
|
+
const layouts = new Set(presentation.masterLayouts);
|
|
1104
|
+
for (const [slideIndex, slide] of presentation.slides.entries()) {
|
|
1105
|
+
if (!layouts.has(slide.layout)) {
|
|
1106
|
+
findings.push({
|
|
1107
|
+
ruleId: "ZTDE-DI-501",
|
|
1108
|
+
severity: "error",
|
|
1109
|
+
path: `presentations[${presentationIndex}].slides[${slideIndex}].layout`,
|
|
1110
|
+
message: `Slide ${slide.id} references missing master layout ${slide.layout}.`,
|
|
1111
|
+
remediation: "Use a declared master layout or add the missing layout to the presentation system.",
|
|
1112
|
+
});
|
|
1113
|
+
}
|
|
1114
|
+
for (const [assetIndex, assetId] of slide.assets.entries()) {
|
|
1115
|
+
if (!assets.has(assetId)) {
|
|
1116
|
+
findings.push({
|
|
1117
|
+
ruleId: "ZTDE-DI-502",
|
|
1118
|
+
severity: "error",
|
|
1119
|
+
path: `presentations[${presentationIndex}].slides[${slideIndex}].assets[${assetIndex}]`,
|
|
1120
|
+
message: `Slide ${slide.id} references missing asset ${assetId}.`,
|
|
1121
|
+
remediation: "Add the approved asset record or remove the reference.",
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
const contrastResults = [];
|
|
1128
|
+
const tokenModes = new Map(manifest.tokenSystem.modes.map((mode) => [mode.name, mode]));
|
|
1129
|
+
addDuplicates(manifest.accessibility.contrastPairs.map((pair) => pair.id), "accessibility.contrastPairs", "contrast pair", findings);
|
|
1130
|
+
for (const [index, pair] of manifest.accessibility.contrastPairs.entries()) {
|
|
1131
|
+
const mode = pair.mode ? tokenModes.get(pair.mode) : undefined;
|
|
1132
|
+
if (pair.mode && !mode) {
|
|
1133
|
+
findings.push({
|
|
1134
|
+
ruleId: "ZTDE-DI-601",
|
|
1135
|
+
severity: "error",
|
|
1136
|
+
path: `accessibility.contrastPairs[${index}].mode`,
|
|
1137
|
+
message: `Contrast pair ${pair.id} references missing token mode ${pair.mode}.`,
|
|
1138
|
+
remediation: "Declare the token mode or correct the contrast-pair mode.",
|
|
1139
|
+
});
|
|
1140
|
+
continue;
|
|
1141
|
+
}
|
|
1142
|
+
const modeOverrides = mode
|
|
1143
|
+
? new Map(mode.overrides.map((override) => [override.token, override]))
|
|
1144
|
+
: undefined;
|
|
1145
|
+
const foreground = resolveTokenColor(pair.foreground, tokens, modeOverrides);
|
|
1146
|
+
const background = resolveTokenColor(pair.background, tokens, modeOverrides);
|
|
1147
|
+
if (!foreground || !background) {
|
|
1148
|
+
findings.push({
|
|
1149
|
+
ruleId: "ZTDE-DI-601",
|
|
1150
|
+
severity: "error",
|
|
1151
|
+
path: `accessibility.contrastPairs[${index}]`,
|
|
1152
|
+
message: `Contrast pair ${pair.id} cannot resolve both colors to primitive values.`,
|
|
1153
|
+
remediation: "Reference color tokens with valid, acyclic primitive color values.",
|
|
1154
|
+
});
|
|
1155
|
+
continue;
|
|
1156
|
+
}
|
|
1157
|
+
if (pair.usage === "large-text" &&
|
|
1158
|
+
(pair.fontSizePx === undefined ||
|
|
1159
|
+
pair.fontWeight === undefined ||
|
|
1160
|
+
(pair.fontSizePx < 24 && !(pair.fontSizePx >= 18.66 && pair.fontWeight >= 700)))) {
|
|
1161
|
+
findings.push({
|
|
1162
|
+
ruleId: "ZTDE-DI-602",
|
|
1163
|
+
severity: "error",
|
|
1164
|
+
path: `accessibility.contrastPairs[${index}]`,
|
|
1165
|
+
message: `Contrast pair ${pair.id} is classified as large text without qualifying size and weight.`,
|
|
1166
|
+
remediation: "Record at least 24px regular text or 18.66px text at weight 700 or greater, otherwise classify it as normal text.",
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1169
|
+
const ratio = contrastRatio(foreground, background);
|
|
1170
|
+
const required = pair.usage === "normal-text" ? 4.5 : 3;
|
|
1171
|
+
const passed = ratio + Number.EPSILON >= required;
|
|
1172
|
+
contrastResults.push({ id: pair.id, ratio: Number(ratio.toFixed(2)), required, passed });
|
|
1173
|
+
if (!passed) {
|
|
1174
|
+
findings.push({
|
|
1175
|
+
ruleId: "ZTDE-DI-603",
|
|
1176
|
+
severity: "error",
|
|
1177
|
+
path: `accessibility.contrastPairs[${index}]`,
|
|
1178
|
+
message: `Contrast pair ${pair.id} has ratio ${ratio.toFixed(2)}:1 and requires ${required}:1.`,
|
|
1179
|
+
remediation: "Change semantic token references or primitive values, then verify the rendered result.",
|
|
1180
|
+
});
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
if (manifest.version === "2.1" && declared.has("interface-system")) {
|
|
1184
|
+
const canvasToken = manifest.composition?.surfaces.find((surface) => surface.role === "canvas")?.tokenRef;
|
|
1185
|
+
const focusToken = manifest.composition?.borders.find((border) => border.role === "focus")?.tokenRef;
|
|
1186
|
+
const textTokens = new Set(manifest.typography?.roles.map((role) => role.colorToken) ?? []);
|
|
1187
|
+
const requiredModes = [
|
|
1188
|
+
undefined,
|
|
1189
|
+
...manifest.tokenSystem.modes.map((mode) => mode.name),
|
|
1190
|
+
];
|
|
1191
|
+
if (canvasToken) {
|
|
1192
|
+
for (const mode of requiredModes) {
|
|
1193
|
+
for (const foreground of textTokens) {
|
|
1194
|
+
const covered = manifest.accessibility.contrastPairs.some((pair) => pair.foreground === foreground &&
|
|
1195
|
+
pair.background === canvasToken &&
|
|
1196
|
+
pair.usage === "normal-text" &&
|
|
1197
|
+
pair.mode === mode);
|
|
1198
|
+
if (!covered) {
|
|
1199
|
+
findings.push({
|
|
1200
|
+
ruleId: "ZTDE-DI-605",
|
|
1201
|
+
severity: "error",
|
|
1202
|
+
path: "accessibility.contrastPairs",
|
|
1203
|
+
message: `Typography token ${foreground} has no normal-text contrast declaration on ${canvasToken}${mode ? ` in ${mode} mode` : " in the default mode"}.`,
|
|
1204
|
+
remediation: "Add and pass an explicit contrast pair for every typography foreground on the canvas in every declared mode.",
|
|
1205
|
+
});
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
if (focusToken) {
|
|
1209
|
+
const focusCovered = manifest.accessibility.contrastPairs.some((pair) => pair.foreground === focusToken &&
|
|
1210
|
+
pair.background === canvasToken &&
|
|
1211
|
+
pair.usage === "non-text" &&
|
|
1212
|
+
pair.mode === mode);
|
|
1213
|
+
if (!focusCovered) {
|
|
1214
|
+
findings.push({
|
|
1215
|
+
ruleId: "ZTDE-DI-605",
|
|
1216
|
+
severity: "error",
|
|
1217
|
+
path: "accessibility.contrastPairs",
|
|
1218
|
+
message: `Focus token ${focusToken} has no non-text contrast declaration on ${canvasToken}${mode ? ` in ${mode} mode` : " in the default mode"}.`,
|
|
1219
|
+
remediation: "Add and pass an explicit focus contrast pair for every declared interface mode.",
|
|
1220
|
+
});
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
const colorTokenNames = new Set(manifest.tokenSystem.tokens.filter((token) => token.type === "color").map((token) => token.name));
|
|
1226
|
+
const hasContrastPair = (foreground, background, mode) => manifest.accessibility.contrastPairs.some((pair) => pair.foreground === foreground &&
|
|
1227
|
+
pair.background === background &&
|
|
1228
|
+
pair.usage === "non-text" &&
|
|
1229
|
+
pair.mode === mode);
|
|
1230
|
+
for (const [stateIndex, state] of manifest.interactionStates?.states.entries() ?? []) {
|
|
1231
|
+
const colors = state.tokenRefs.filter((reference) => colorTokenNames.has(reference));
|
|
1232
|
+
const foreground = colors[0];
|
|
1233
|
+
const background = colors[1];
|
|
1234
|
+
if (!foreground || !background)
|
|
1235
|
+
continue;
|
|
1236
|
+
for (const mode of requiredModes) {
|
|
1237
|
+
if (!hasContrastPair(foreground, background, mode)) {
|
|
1238
|
+
findings.push({
|
|
1239
|
+
ruleId: "ZTDE-DI-606",
|
|
1240
|
+
severity: "error",
|
|
1241
|
+
path: `interactionStates.states[${stateIndex}].tokenRefs`,
|
|
1242
|
+
message: `State ${state.state} lacks declared non-text contrast for ${foreground} on ${background}${mode ? ` in ${mode} mode` : " in the default mode"}.`,
|
|
1243
|
+
remediation: "Add and pass a non-text contrast pair for the state foreground and adjacent surface in every declared mode.",
|
|
1244
|
+
});
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
for (const [chartIndex, chart] of manifest.chartContracts?.entries() ?? []) {
|
|
1249
|
+
const foreground = chart.tokenRefs.find((reference) => colorTokenNames.has(reference));
|
|
1250
|
+
const background = chart.backgroundToken;
|
|
1251
|
+
if (!foreground || !background) {
|
|
1252
|
+
findings.push({
|
|
1253
|
+
ruleId: "ZTDE-DI-606",
|
|
1254
|
+
severity: "error",
|
|
1255
|
+
path: `chartContracts[${chartIndex}]`,
|
|
1256
|
+
message: `Chart ${chart.id} lacks a series color or background token for contrast verification.`,
|
|
1257
|
+
remediation: "Declare the chart background token and at least one semantic series color token.",
|
|
1258
|
+
});
|
|
1259
|
+
continue;
|
|
1260
|
+
}
|
|
1261
|
+
for (const mode of requiredModes) {
|
|
1262
|
+
if (!hasContrastPair(foreground, background, mode)) {
|
|
1263
|
+
findings.push({
|
|
1264
|
+
ruleId: "ZTDE-DI-606",
|
|
1265
|
+
severity: "error",
|
|
1266
|
+
path: `chartContracts[${chartIndex}].tokenRefs`,
|
|
1267
|
+
message: `Chart ${chart.id} lacks declared series contrast on ${background}${mode ? ` in ${mode} mode` : " in the default mode"}.`,
|
|
1268
|
+
remediation: "Add and pass a non-text contrast pair for the chart series and its rendered surface in every declared mode.",
|
|
1269
|
+
});
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
for (const [index, cue] of manifest.accessibility.nonColorCues.entries()) {
|
|
1275
|
+
const uniqueCues = new Set(cue.cues);
|
|
1276
|
+
if (uniqueCues.size !== cue.cues.length || [...uniqueCues].every((value) => value === "color")) {
|
|
1277
|
+
findings.push({
|
|
1278
|
+
ruleId: "ZTDE-DI-604",
|
|
1279
|
+
severity: "error",
|
|
1280
|
+
path: `accessibility.nonColorCues[${index}].cues`,
|
|
1281
|
+
message: `Meaning ${cue.meaning} does not declare distinct color-independent cues.`,
|
|
1282
|
+
remediation: "Combine color with text, icon, shape, pattern, position, value, or underline.",
|
|
1283
|
+
});
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
const summary = {
|
|
1287
|
+
errors: findings.filter((finding) => finding.severity === "error").length,
|
|
1288
|
+
warnings: findings.filter((finding) => finding.severity === "warning").length,
|
|
1289
|
+
info: findings.filter((finding) => finding.severity === "info").length,
|
|
1290
|
+
};
|
|
1291
|
+
const requiredViewports = Object.fromEntries([375, 768, 1024, 1440].map((viewport) => {
|
|
1292
|
+
const capture = manifest.renderedEvidence?.captures.find((entry) => entry.viewport === viewport);
|
|
1293
|
+
return [String(viewport), capture?.status ?? "missing"];
|
|
1294
|
+
}));
|
|
1295
|
+
const visualPolishDeclared = declared.has("interface-system");
|
|
1296
|
+
const renderedEvidenceReady = visualPolishDeclared && Object.values(requiredViewports).every((status) => status === "verified");
|
|
1297
|
+
const humanReviewReady = visualPolishDeclared &&
|
|
1298
|
+
manifest.humanVisualReview?.status === "completed" &&
|
|
1299
|
+
manifest.humanVisualReview.reviewers.length > 0;
|
|
1300
|
+
const stages = Object.fromEntries(REQUIRED_GENERATION_STAGES.map((stage) => [
|
|
1301
|
+
stage,
|
|
1302
|
+
manifest.generationWorkflow?.steps.find((entry) => entry.stage === stage)?.status ?? "missing",
|
|
1303
|
+
]));
|
|
1304
|
+
const generationReady = visualPolishDeclared &&
|
|
1305
|
+
REQUIRED_GENERATION_STAGES.slice(0, 6).every((stage) => stages[stage] === "declared") &&
|
|
1306
|
+
stages.implementation !== "missing" &&
|
|
1307
|
+
stages["automated-verification"] !== "missing" &&
|
|
1308
|
+
stages["human-visual-review"] !== "missing";
|
|
1309
|
+
const trustStatus = manifest.interfaceTrust?.status ?? "missing";
|
|
1310
|
+
const informationStatus = manifest.informationHierarchy?.status ?? "missing";
|
|
1311
|
+
const contractsValidated = trustStatus === "validated" && informationStatus === "validated";
|
|
1312
|
+
const automatedVerificationReady = stages["automated-verification"] === "verified";
|
|
1313
|
+
const integratedReleaseReady = summary.errors === 0 &&
|
|
1314
|
+
generationReady &&
|
|
1315
|
+
contractsValidated &&
|
|
1316
|
+
automatedVerificationReady &&
|
|
1317
|
+
renderedEvidenceReady &&
|
|
1318
|
+
humanReviewReady;
|
|
1319
|
+
return {
|
|
1320
|
+
version: REPORT_VERSION,
|
|
1321
|
+
generatedAt: new Date().toISOString(),
|
|
1322
|
+
sourcePath: resolve(sourcePath),
|
|
1323
|
+
manifestId: manifest.id,
|
|
1324
|
+
product: manifest.product,
|
|
1325
|
+
deliverables: manifest.scope.deliverables,
|
|
1326
|
+
findings,
|
|
1327
|
+
contrastResults,
|
|
1328
|
+
coverage: {
|
|
1329
|
+
tokens: manifest.tokenSystem.tokens.length,
|
|
1330
|
+
assets: manifest.assets.length,
|
|
1331
|
+
icons: manifest.iconSystem?.icons.length ?? 0,
|
|
1332
|
+
presentations: manifest.presentations.length,
|
|
1333
|
+
slides: manifest.presentations.reduce((total, presentation) => total + presentation.slides.length, 0),
|
|
1334
|
+
contrastPairs: manifest.accessibility.contrastPairs.length,
|
|
1335
|
+
typographyRoles: manifest.typography?.roles.length ?? 0,
|
|
1336
|
+
interactionStates: manifest.interactionStates?.states.length ?? 0,
|
|
1337
|
+
chartContracts: manifest.chartContracts?.length ?? 0,
|
|
1338
|
+
renderedViewports: manifest.renderedEvidence?.captures.length ?? 0,
|
|
1339
|
+
metricContracts: manifest.metricContracts?.metrics.length ?? 0,
|
|
1340
|
+
generationStages: manifest.generationWorkflow?.steps.length ?? 0,
|
|
1341
|
+
},
|
|
1342
|
+
integration: {
|
|
1343
|
+
generationReady,
|
|
1344
|
+
trustStatus,
|
|
1345
|
+
informationStatus,
|
|
1346
|
+
contractsValidated,
|
|
1347
|
+
automatedVerificationReady,
|
|
1348
|
+
humanReviewReady,
|
|
1349
|
+
releaseReady: integratedReleaseReady,
|
|
1350
|
+
stages,
|
|
1351
|
+
},
|
|
1352
|
+
visualPolish: {
|
|
1353
|
+
declared: visualPolishDeclared,
|
|
1354
|
+
requiredViewports,
|
|
1355
|
+
renderedEvidenceReady,
|
|
1356
|
+
humanReviewReady,
|
|
1357
|
+
releaseReady: summary.errors === 0 && renderedEvidenceReady && humanReviewReady,
|
|
1358
|
+
},
|
|
1359
|
+
summary,
|
|
1360
|
+
passed: summary.errors === 0,
|
|
1361
|
+
limitations: [
|
|
1362
|
+
"Manifest validation verifies declared structure, token math, references, and provenance records; it does not inspect Figma files or rendered pixels.",
|
|
1363
|
+
"Planned or captured viewport records are not verified rendered evidence. Visual release readiness requires verified screenshots and runtime reports at 375, 768, 1024, and 1440 CSS pixels.",
|
|
1364
|
+
"Human visual review is incomplete until a reviewer supplies attributable evidence for hierarchy, balance, scanability, density, and domain fit. An agent must not create that record.",
|
|
1365
|
+
"Linked trust and information contracts count as validated only when the manifest records their actual passing reports and evidence references.",
|
|
1366
|
+
"Rights records support review but are not legal advice or a determination that an asset is cleared in every jurisdiction and channel.",
|
|
1367
|
+
"Run browser verification and human review against final exported or implemented artifacts.",
|
|
1368
|
+
],
|
|
1369
|
+
};
|
|
1370
|
+
}
|
|
1371
|
+
//# sourceMappingURL=validator.js.map
|