@ryuenn3123/agentic-senior-core 3.0.36 → 3.0.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/.agent-context/prompts/bootstrap-design.md +109 -113
  2. package/.agent-context/rules/frontend-architecture.md +92 -104
  3. package/.agent-context/state/README.md +26 -0
  4. package/.cursor/mcp.json +10 -0
  5. package/.cursor/rules/agentic-senior-core.mdc +48 -0
  6. package/.cursorrules +22 -88
  7. package/.gemini/instructions.md +25 -16
  8. package/.github/copilot-instructions.md +25 -16
  9. package/.github/instructions/agentic-senior-core.instructions.md +47 -0
  10. package/.instructions.md +98 -207
  11. package/.windsurf/rules/agentic-senior-core.md +43 -0
  12. package/.windsurfrules +22 -88
  13. package/AGENTS.md +23 -26
  14. package/CLAUDE.md +43 -0
  15. package/CONTRIBUTING.md +5 -2
  16. package/GEMINI.md +43 -0
  17. package/README.md +24 -7
  18. package/lib/cli/backup.mjs +4 -4
  19. package/lib/cli/commands/init/project-context.mjs +101 -0
  20. package/lib/cli/commands/init/runtime-environment.mjs +59 -0
  21. package/lib/cli/commands/init/setup-decisions.mjs +83 -0
  22. package/lib/cli/commands/init.mjs +33 -250
  23. package/lib/cli/commands/optimize.mjs +1 -1
  24. package/lib/cli/commands/upgrade.mjs +32 -7
  25. package/lib/cli/compiler.mjs +59 -17
  26. package/lib/cli/constants.mjs +5 -0
  27. package/lib/cli/detector.mjs +4 -0
  28. package/lib/cli/preflight.mjs +3 -3
  29. package/lib/cli/project-scaffolder/design-contract/validation.mjs +789 -0
  30. package/lib/cli/project-scaffolder/design-contract.mjs +137 -861
  31. package/lib/cli/project-scaffolder/prompt-builders.mjs +73 -81
  32. package/lib/cli/utils/filesystem.mjs +79 -0
  33. package/lib/cli/utils/managed-surface.mjs +237 -0
  34. package/lib/cli/utils/prompting.mjs +44 -0
  35. package/lib/cli/utils.mjs +33 -335
  36. package/package.json +21 -2
  37. package/scripts/clean-local-artifacts.mjs +76 -0
  38. package/scripts/docs-quality-drift-report.mjs +5 -0
  39. package/scripts/frontend-usability-audit.mjs +23 -19
  40. package/scripts/governance-weekly-report.mjs +37 -15
  41. package/scripts/single-source-lazy-loading-audit.mjs +24 -0
  42. package/scripts/sync-thin-adapters.mjs +99 -129
  43. package/scripts/v3-purge-audit.mjs +5 -0
  44. package/scripts/validate/config.mjs +21 -0
  45. package/scripts/validate/coverage-checks.mjs +55 -0
  46. package/.agent-context/marketplace/trust-tiers.json +0 -114
  47. package/.agent-context/state/benchmark-analysis.json +0 -431
  48. package/.agent-context/state/benchmark-evidence-bundle.json +0 -1040
  49. package/.agent-context/state/benchmark-history.json +0 -75
  50. package/.agent-context/state/benchmark-trend-report.csv +0 -5
  51. package/.agent-context/state/benchmark-trend-report.json +0 -140
  52. package/.agent-context/state/benchmark-writer-judge-matrix.json +0 -462
  53. package/.agent-context/state/memory-continuity-benchmark.json +0 -132
  54. package/.agent-context/state/onboarding-report.json +0 -102
  55. package/.agent-context/state/quality-trend-report.json +0 -89
  56. package/.agent-context/state/token-optimization-benchmark.json +0 -130
  57. package/.agent-context/state/weekly-governance-report.json +0 -329
  58. package/lib/cli/compatibility.mjs +0 -124
@@ -1,5 +1,45 @@
1
1
  import { toTitleCase } from '../utils.mjs';
2
2
  import { DESIGN_REQUIRED_SECTIONS } from './constants.mjs';
3
+ import { validateDesignIntentContract } from './design-contract/validation.mjs';
4
+
5
+ const GENERICITY_DRIFT_SIGNALS = [
6
+ 'offline-prescribed-style-used-as-final-direction',
7
+ 'unresearched-library-or-framework-choice',
8
+ 'missing-conceptual-anchor-without-external-research',
9
+ 'visual-decisions-not-derived-from-conceptual-anchor',
10
+ 'ai-safe-ui-template-look',
11
+ 'ai-color-default-palette-without-product-role-behavior',
12
+ 'brandless-clean-template-look',
13
+ 'interchangeable-product-renaming-test-fails',
14
+ 'decorative-grid-or-glow-wallpaper-without-product-function',
15
+ 'safe-cream-slate-or-monochrome-palette-used-as-readability-excuse',
16
+ 'generic-abstract-logo-or-iconography',
17
+ 'timid-anchor-that-renames-dashboard-or-admin-shell',
18
+ 'motion-suppressed-without-accessibility-or-performance-reason',
19
+ 'motion-or-3d-omitted-from-fear-without-fit-analysis',
20
+ 'scale-only-responsive-layout',
21
+ 'zero-based-redesign-kept-prior-visual-dna',
22
+ 'restyle-instead-of-recomposition',
23
+ ];
24
+
25
+ const FORBIDDEN_PATTERN_SIGNALS = [
26
+ ...GENERICITY_DRIFT_SIGNALS.filter((signal) => signal !== 'unresearched-library-or-framework-choice'),
27
+ 'single-safe-typographic-family-without-role-contrast-or-rationale',
28
+ ];
29
+
30
+ const VALID_BOLD_SIGNALS = [
31
+ 'single-cohesive-conceptual-anchor',
32
+ 'high-variance-candidate-selection',
33
+ 'context-derived-visual-direction',
34
+ 'three-at-a-glance-product-specific-signals',
35
+ 'visually-exploratory-accessible-palette-derived-from-product',
36
+ 'audacious-accessible-palette-with-product-role-behavior',
37
+ 'background-or-geometry-serves-product-function',
38
+ 'motion-or-spatial-experience-derived-from-anchor',
39
+ 'explicit-3d-canvas-fit-or-nonfit-decision',
40
+ 'responsive-recomposition-by-task-priority',
41
+ 'purposeful-motion-with-reduced-motion-path',
42
+ ];
3
43
 
4
44
  export function shouldBootstrapDesignDocument(discoveryAnswers, initContext) {
5
45
  const normalizedDomain = String(discoveryAnswers.primaryDomain || '').trim().toLowerCase();
@@ -51,26 +91,26 @@ function buildStructureFirstSeedSignals({
51
91
  : 'the current product context';
52
92
 
53
93
  return {
54
- designPhilosophy: `Use ${evidenceSourceLabel} to synthesize the design system for ${projectName || 'this project'}. This seed is only a decision scaffold: the LLM must choose the visual language, libraries, color system, typography, spacing, and interaction model from ${projectContextLabel}, current repo evidence, and live official documentation when a technology claim is needed.`,
94
+ designPhilosophy: `Synthesize design for ${projectName || 'this project'} from ${evidenceSourceLabel}. Choose visual language, libraries, color, type, spacing, and interaction from ${projectContextLabel}; verify technology claims with official docs.`,
55
95
  typographyScaleRatio: 'agent-calibrated-from-content-platform-and-readability',
56
96
  baseGridUnit: 'agent-calibrated-from-platform-density-and-implementation-stack',
57
97
  spacingPattern: 'agent-defined-from-task-flow-and-viewport-needs',
58
98
  densityMode: 'agent-defined-from-user-task-device-and-content-pressure',
59
- colorIntent: `Choose semantic palette roles from ${projectContextLabel}, current repo evidence, and accessibility needs. Do not inherit fixed palettes or generic SaaS color defaults from this scaffold.`,
99
+ colorIntent: `Choose semantic palette roles from ${projectContextLabel}, repo evidence, and accessibility. Reject scaffold or SaaS palette defaults.`,
60
100
  paletteRoles: ['agent-defined-semantic-roles'],
61
101
  distinctiveMoves: [
62
- 'Choose one recognizable design move from product task, audience, content, repo evidence, and current docs; do not inherit a scaffold preset.',
102
+ 'Choose one product-specific move from task, audience, content, repo evidence, and docs.',
63
103
  ],
64
- motionPurpose: 'Default to a modern motion plan for UI work: use expressive transitions, spatial choreography, micro-interactions, and motion libraries when they strengthen hierarchy, continuity, feedback, memorability, or perceived product quality. If implementation needs a motion library, the LLM must choose a current compatible option from official docs instead of relying on an offline default.',
104
+ motionPurpose: 'Use expressive motion when it improves hierarchy, continuity, feedback, memorability, or confidence. Verify new motion libraries with official docs.',
65
105
  componentMorphology: {
66
- mobile: 'Recompose the experience for touch, task priority, and constrained attention. Mobile should be a deliberate mobile design, not a shrunken desktop.',
67
- tablet: 'Regroup surfaces for medium-width use, preserving task clarity without cloning either desktop or mobile blindly.',
68
- desktop: 'Use the available space to improve hierarchy, scanability, and interaction quality without defaulting to template grids or generic dashboard chrome.',
106
+ mobile: 'Recompose for touch, task priority, and constrained attention.',
107
+ tablet: 'Regroup surfaces for medium width without cloning desktop or mobile.',
108
+ desktop: 'Use space for hierarchy and scanability; avoid template grids.',
69
109
  },
70
110
  mutationRules: {
71
- mobile: 'Define a mobile-specific composition with reordered, merged, or disclosed content where appropriate. Scale-only shrink behavior is failure.',
72
- tablet: 'Define a tablet-specific regrouping strategy rather than a width-only reduction of desktop.',
73
- desktop: 'Define a desktop composition that uses space intentionally and avoids generic equal-weight modules unless the project evidence justifies them.',
111
+ mobile: 'Reorder, merge, or disclose content for mobile. Reject scale-only shrink.',
112
+ tablet: 'Regroup for tablet instead of width-only desktop reduction.',
113
+ desktop: 'Use space intentionally; avoid equal-weight modules without evidence.',
74
114
  },
75
115
  };
76
116
  }
@@ -132,7 +172,7 @@ function buildDesignIntentContractObject({
132
172
  'ui-primitives-or-rich-media',
133
173
  'typography-and-interaction',
134
174
  ],
135
- finalDecisionAuthority: 'agent-llm-from-project-fit-accessibility-performance-maintainability-and-current-official-docs',
175
+ finalDecisionAuthority: 'project-fit-accessibility-performance-maintainability-official-docs',
136
176
  },
137
177
  conceptualAnchor: {
138
178
  mode: 'required-when-no-external-research',
@@ -163,7 +203,7 @@ function buildDesignIntentContractObject({
163
203
  'typographicDecision',
164
204
  ],
165
205
  rejectGenericQualityWordsOnly: true,
166
- specificityFloor: 'name-a-real-material-instrument-artifact-architecture-editorial-genre-cinematic-behavior-exhibition-system-scientific-apparatus-or-industrial-mechanism',
206
+ specificityFloor: 'name-real-material-instrument-artifact-architecture-editorial-genre-cinematic-behavior-exhibition-system-scientific-apparatus-or-industrial-mechanism',
167
207
  },
168
208
  forbiddenFinalAnchorTerms: [
169
209
  'dashboard',
@@ -219,42 +259,64 @@ function buildDesignIntentContractObject({
219
259
  },
220
260
  derivedTokenLogic: {
221
261
  anchorReference: 'agent-defined-anchor-reference',
222
- colorDerivationSource: 'Agent must explain how semantic color roles derive from the chosen anchorReference; default blue or generic SaaS palettes are invalid without anchor evidence.',
223
- spacingDerivationSource: 'Agent must explain how base grid, rhythm, density, and spacing exceptions derive from the chosen anchorReference.',
224
- typographyDerivationSource: 'Agent must explain how display, body, metadata, and data typography roles derive from the chosen anchorReference.',
225
- motionDerivationSource: 'Agent must explain how duration, easing, choreography, and reduced-motion alternatives derive from the chosen anchorReference.',
226
- validationRule: 'Every primitive, semantic, component, typography, spacing, and motion token must trace back to anchorReference; if a token cannot be explained from the anchor, revise the token.',
262
+ colorDerivationSource: 'Explain semantic color roles from anchorReference; reject generic palettes without anchor evidence.',
263
+ spacingDerivationSource: 'Explain grid, rhythm, density, and exceptions from anchorReference.',
264
+ typographyDerivationSource: 'Explain display, body, metadata, and data roles from anchorReference.',
265
+ motionDerivationSource: 'Explain duration, easing, choreography, and reduced-motion from anchorReference.',
266
+ validationRule: 'Every token must trace to anchorReference; revise tokens that cannot.',
227
267
  },
228
268
  motionPaletteDecision: {
229
269
  productCategorySignal: 'agent-inferred-starting-heuristic',
230
- densityDecisionSource: 'Agent must choose motion density from task, content density, brand intent, device/performance, and accessibility evidence; product categories are heuristics, not style presets.',
270
+ densityDecisionSource: 'Choose motion density from task, content, brand, device, performance, and accessibility. Categories are heuristics.',
231
271
  requiredInteractionStates: ['default', 'hover', 'focus-visible', 'active', 'disabled', 'loading', 'empty', 'error', 'success', 'transition'],
232
- paletteAutopilotRisks: ['dark-slate-default', 'cream-beige-default', 'purple-blue-gradient-default', 'monochrome-template-default', 'uniform-card-surface-default', 'generic-grid-wallpaper-default', 'soft-glow-ai-template-default'],
233
- spatialDecision: 'Agent must state whether 3D/canvas/WebGL is useful or unnecessary for product understanding, exploration, or storytelling.',
272
+ paletteAutopilotRisks: ['dark-slate-default', 'cream-beige-default', 'purple-blue-gradient-default', 'monochrome-template-default', 'uniform-card-surface-default', 'generic-grid-wallpaper-default', 'soft-glow-ai-template-default', 'cyber-neon-terminal-default'],
273
+ spatialDecision: 'State 3D/canvas/WebGL fit. If omitted, name product-fit reason and replacement interaction quality.',
234
274
  },
235
275
  aiSafeUiAudit: {
236
276
  status: 'agent-must-complete-before-ui-implementation',
237
- failureDefinition: 'UI is AI-safe when it relies on predictable card stacks, rounded template panels, generic abstract logos, decorative grid wallpaper, beige or slate safety palettes, soft glow backgrounds, or first-output composition with only local copy swapped in.',
238
- interchangeabilityTest: `If this UI can be renamed from ${projectName} to another product category without changing composition, palette, iconography, and motion language, the design is genericity drift and must be revised.`,
277
+ failureDefinition: 'AI-safe UI uses template cards, generic marks, decorative grid wallpaper, safe palettes, glow backgrounds, or copied scaffold composition.',
278
+ interchangeabilityTest: `If this UI can be renamed from ${projectName} to another product category without changing composition, palette, iconography, and motion, revise it.`,
239
279
  requiredProductSpecificSignals: [
240
280
  'agent-defined-product-specific-data-treatment',
241
281
  'agent-defined-product-specific-motion-or-state-behavior',
242
282
  'agent-defined-product-specific-morphology-iconography-or-spatial-structure',
243
283
  ],
244
- paletteExplorationRule: 'Use a visually exploratory product-derived palette while preserving WCAG contrast and status clarity; do not use readability as an excuse for cream, slate, monochrome, or gradient defaults.',
245
- backgroundPatternRule: 'Lines, grids, scanlines, noise, glows, blobs, logos, and geometric decoration must serve a named product function such as alignment, measurement, navigation, crop guidance, timeline reading, status, or motion continuity.',
246
- reviewQuestion: 'What at-a-glance visual evidence proves this screen belongs to this product and not a generic AI-generated template?',
284
+ paletteExplorationRule: 'Use a visually exploratory product-derived palette with WCAG contrast and status clarity.',
285
+ backgroundPatternRule: 'Lines, grids, scanlines, noise, glows, blobs, logos, and geometry must serve a named product function.',
286
+ aiColorAudit: {
287
+ status: 'agent-must-complete-before-ui-implementation',
288
+ failureDefinition: 'AI color drift uses safe defaults before deriving roles from the product anchor.',
289
+ autopilotRisks: ['cream-editorial-default', 'dark-slate-dashboard-default', 'purple-blue-gradient-default', 'monochrome-minimal-default', 'cyber-neon-terminal-default', 'soft-glow-atmosphere-default'],
290
+ requiredEvidence: [
291
+ 'anchor-derived-color-logic',
292
+ 'semantic-role-contrast-beyond-surface-decoration',
293
+ 'product-specific-color-behavior-that-would-not-transfer',
294
+ ],
295
+ reviewQuestion: 'Why does this palette belong to this product?',
296
+ },
297
+ motionSpatialCourageAudit: {
298
+ status: 'agent-must-complete-before-ui-implementation',
299
+ defaultStance: 'Treat motion, scroll choreography, canvas, WebGL, and 3D as first-class options.',
300
+ requiredDecisionFields: [
301
+ 'signature-motion-or-interaction',
302
+ 'spatial-or-3d-fit',
303
+ 'performance-and-reduced-motion-fallback',
304
+ ],
305
+ rejectionRule: 'State a product reason and replacement interaction quality before omitting 3D/canvas.',
306
+ reviewQuestion: 'Is the interaction as expressive as the product can responsibly support?',
307
+ },
308
+ reviewQuestion: 'What visible evidence proves this is product-specific?',
247
309
  blockingByDefault: true,
248
310
  },
249
311
  libraryResearchStatus: 'pending-verification',
250
312
  libraryDecisions: [
251
313
  {
252
314
  library: 'agent-defined-or-none',
253
- purpose: 'Agent must verify any UI, animation, scroll, 3D, canvas, chart, icon, or styling library against current official docs before implementation.',
315
+ purpose: 'Verify UI-related libraries against current official docs before imports.',
254
316
  verifiedAt: null,
255
317
  sourceUrl: null,
256
318
  stableVersion: null,
257
- fallbackIfUnavailable: 'Use native CSS, browser APIs, or existing project dependencies until live verification is available.',
319
+ fallbackIfUnavailable: 'Use native CSS, browser APIs, or existing dependencies.',
258
320
  },
259
321
  ],
260
322
  mathSystems: {
@@ -369,12 +431,12 @@ function buildDesignIntentContractObject({
369
431
  status: 'seed-needs-refinement',
370
432
  seedMode: 'structure-first-scaffold',
371
433
  requiresTaskSpecificRefinement: true,
372
- primaryExperienceGoal: `Define the main ${String(primaryDomain || 'product').toLowerCase()} journey for ${projectName} from repo evidence, the brief, and current docs. The seed must not prescribe final layout.`,
434
+ primaryExperienceGoal: `Define the main ${String(primaryDomain || 'product').toLowerCase()} journey for ${projectName} from repo evidence, brief, and docs.`,
373
435
  surfacePlan: [
374
436
  {
375
437
  surfaceId: 'agent-defined-primary-experience',
376
438
  role: 'primary-context-synthesized-by-agent',
377
- goal: 'Choose the first task or reading path from product evidence and reject template shells.',
439
+ goal: 'Choose the first task path from product evidence; reject template shells.',
378
440
  antiPatterns: ['dashboard-default', 'scale-only-responsive-layout'],
379
441
  },
380
442
  ],
@@ -449,12 +511,12 @@ function buildDesignIntentContractObject({
449
511
  {
450
512
  componentId: 'primary-interaction',
451
513
  states: ['default', 'hover', 'focus', 'loading', 'error'],
452
- notes: 'Refine states from project language and the conceptual anchor; do not use anonymous default panels.',
514
+ notes: 'Refine states from project language and anchor; reject anonymous panels.',
453
515
  },
454
516
  ],
455
517
  taskFlowNarrative: [
456
- `Entry: define how ${projectName} starts the journey from real evidence, not a generic opener.`,
457
- 'Resolution: define proof, feedback, recovery, and next action without leftover template chrome.',
518
+ `Entry: start ${projectName} from real evidence, not a generic opener.`,
519
+ 'Resolution: define proof, feedback, recovery, and next action.',
458
520
  ],
459
521
  visualResetStrategy: {
460
522
  activatesWhenUserRequests: [
@@ -465,7 +527,7 @@ function buildDesignIntentContractObject({
465
527
  existingUiForbiddenAs: ['palette-source', 'layout-source', 'motion-source'],
466
528
  requiredResetAxes: ['composition', 'hierarchy', 'motion-or-interaction', 'responsive-information-architecture'],
467
529
  },
468
- signatureMoveRationale: 'Agent must choose one project-specific visual, motion, typographic, or interaction move and explain why generic fallback weakens it.',
530
+ signatureMoveRationale: 'Choose one project-specific visual, motion, type, or interaction move.',
469
531
  creativeCommitment: {
470
532
  status: 'agent-must-complete-before-ui-implementation',
471
533
  requiredFields: [
@@ -473,7 +535,7 @@ function buildDesignIntentContractObject({
473
535
  'signatureMotion',
474
536
  'typographicDecision',
475
537
  ],
476
- failureMode: 'generic quality words without a named real-world reference are not enough',
538
+ failureMode: 'generic quality words without a real-world reference fail',
477
539
  },
478
540
  implementationGuardrails: {
479
541
  requireBuildFromHandoff: true,
@@ -488,55 +550,31 @@ function buildDesignIntentContractObject({
488
550
  {
489
551
  key: 'distinctiveness',
490
552
  blockingByDefault: true,
491
- question: 'Does the UI feel authored and project-specific rather than like a default framework or template kit?',
553
+ question: 'Is the UI authored and product-specific?',
492
554
  },
493
555
  {
494
556
  key: 'contractFidelity',
495
557
  blockingByDefault: true,
496
- question: 'Does the changed UI still follow the explicit design contract, interaction priorities, and accessibility boundaries?',
558
+ question: 'Does the UI follow contract, priorities, and accessibility?',
497
559
  },
498
560
  {
499
561
  key: 'visualConsistency',
500
562
  blockingByDefault: false,
501
- question: 'Do typography, spacing, color usage, and component behaviors still feel like one system?',
563
+ question: 'Do type, spacing, color, and states form one system?',
502
564
  },
503
565
  {
504
566
  key: 'heuristicUxQuality',
505
567
  blockingByDefault: false,
506
- question: 'Does the UI preserve task clarity, feedback quality, and user confidence in the touched flows?',
568
+ question: 'Does the UI preserve clarity, feedback, and confidence?',
507
569
  },
508
570
  {
509
571
  key: 'motionDiscipline',
510
572
  blockingByDefault: false,
511
- question: 'Does motion act as part of the design language while staying purposeful, performant, reduced-motion-safe, and consistent with the product tone?',
573
+ question: 'Is motion purposeful, performant, reduced-motion-safe, and on-tone?',
512
574
  },
513
575
  ],
514
- genericitySignals: [
515
- 'offline-prescribed-style-used-as-final-direction',
516
- 'unresearched-library-or-framework-choice',
517
- 'missing-conceptual-anchor-without-external-research',
518
- 'visual-decisions-not-derived-from-conceptual-anchor',
519
- 'ai-safe-ui-template-look',
520
- 'interchangeable-product-renaming-test-fails',
521
- 'decorative-grid-or-glow-wallpaper-without-product-function',
522
- 'safe-cream-slate-or-monochrome-palette-used-as-readability-excuse',
523
- 'generic-abstract-logo-or-iconography',
524
- 'timid-anchor-that-renames-dashboard-or-admin-shell',
525
- 'motion-suppressed-without-accessibility-or-performance-reason',
526
- 'scale-only-responsive-layout',
527
- 'zero-based-redesign-kept-prior-visual-dna',
528
- 'restyle-instead-of-recomposition',
529
- ],
530
- validBoldSignals: [
531
- 'single-cohesive-conceptual-anchor',
532
- 'high-variance-candidate-selection',
533
- 'context-derived-visual-direction',
534
- 'three-at-a-glance-product-specific-signals',
535
- 'visually-exploratory-accessible-palette-derived-from-product',
536
- 'background-or-geometry-serves-product-function',
537
- 'responsive-recomposition-by-task-priority',
538
- 'purposeful-motion-with-reduced-motion-path',
539
- ],
576
+ genericitySignals: [...GENERICITY_DRIFT_SIGNALS],
577
+ validBoldSignals: [...VALID_BOLD_SIGNALS],
540
578
  reportingRules: {
541
579
  mustExplainGenericity: true,
542
580
  mustSeparateTasteFromFailure: true,
@@ -560,65 +598,45 @@ function buildDesignIntentContractObject({
560
598
  repoEvidenceOverridesMemory: true,
561
599
  requireExplicitContinuityApproval: true,
562
600
  forbidCarryoverWhenUnapproved: true,
563
- approvedExternalConstraintUsage: 'Convert explicit user-supplied external constraints into current-project rules without comparing against or imitating the source surface.',
601
+ approvedExternalConstraintUsage: 'Convert approved external constraints into current-project rules; do not imitate source surfaces.',
564
602
  driftSignals: [
565
603
  'palette-reused-without-brief-support',
566
604
  'prior-ui-visual-dna-carried-into-reset-request',
567
605
  ],
568
606
  },
569
- experiencePrinciples: [
570
- 'Design must feel project-specific, not interchangeable with generic SaaS templates.',
571
- 'Readable UI must still avoid AI-safe template look; safety is not a substitute for authored visual direction.',
572
- 'Major interface decisions must be explainable in product and user terms.',
573
- 'Accessibility, responsiveness, and implementation realism are non-negotiable.',
574
- 'Cross-viewport behavior must reorganize tasks and navigation, not just scale the desktop layout down.',
575
- 'A single agent-chosen conceptual anchor must unify typography, spacing, morphology, motion, and responsive composition when user research is absent.',
576
- 'Expressive motion and spatial interaction are expected for modern UI work when they support the anchor; keep them accessible and performant instead of suppressing them by default.',
577
- 'When the user asks for a zero-based redesign, existing UI becomes content and behavior evidence only; prior visual DNA must be discarded unless explicitly approved.',
607
+ forbiddenPatterns: [...FORBIDDEN_PATTERN_SIGNALS],
608
+ validationHints: [
609
+ 'rejectArbitraryHexOnlyPalette',
610
+ 'requireViewportMutationRules',
611
+ 'requirePerceptualColorRationale',
612
+ 'requireTokenLayering',
613
+ 'requireTokenAliasingPlan',
614
+ 'allowHexDerivatives',
615
+ 'requireMotionRationale',
616
+ 'requireStateMorphology',
617
+ 'requireAccessibilitySplit',
618
+ 'requireWcagHardFloor',
619
+ 'requireStructuredDesignExecutionPolicy',
620
+ 'requireStructuredDesignHandoff',
621
+ 'requireVisualResetStrategyWhenZeroBasedRedesignRequested',
622
+ 'requireConceptualAnchorWhenNoExternalResearch',
623
+ 'requireAgentLedAnchorResearchWhenUserResearchMissing',
624
+ 'rejectTimidDashboardAnchor',
625
+ 'requireReviewRubric',
626
+ 'requireGenericityExplanation',
627
+ 'genericityAutoFail',
628
+ 'requireSignatureMove',
629
+ 'rejectTemplateNeutralLayout',
630
+ 'requireAiSafeUiAudit',
631
+ 'requireAiColorAudit',
632
+ 'rejectAiColorDefaults',
633
+ 'requireMotionSpatialCourageAudit',
634
+ 'requireExplicit3dCanvasFitDecision',
635
+ 'rejectSafetyAsCreativitySubstitute',
636
+ 'rejectAiSafeUiTemplateLook',
637
+ 'requireThreeProductSpecificSignals',
638
+ 'rejectDecorativeBackgroundPatternsWithoutProductFunction',
578
639
  ],
579
- forbiddenPatterns: [
580
- 'offline-prescribed-style-used-as-final-direction',
581
- 'missing-conceptual-anchor-without-external-research',
582
- 'visual-decisions-not-derived-from-conceptual-anchor',
583
- 'ai-safe-ui-template-look',
584
- 'interchangeable-product-renaming-test-fails',
585
- 'decorative-grid-or-glow-wallpaper-without-product-function',
586
- 'safe-cream-slate-or-monochrome-palette-used-as-readability-excuse',
587
- 'generic-abstract-logo-or-iconography',
588
- 'timid-anchor-that-renames-dashboard-or-admin-shell',
589
- 'motion-suppressed-without-accessibility-or-performance-reason',
590
- 'scale-only-responsive-layout',
591
- 'zero-based-redesign-kept-prior-visual-dna',
592
- 'restyle-instead-of-recomposition',
593
- 'single-safe-typographic-family-without-role-contrast-or-rationale',
594
- ],
595
- validationHints: {
596
- rejectArbitraryHexOnlyPalette: true,
597
- requireViewportMutationRules: true,
598
- requirePerceptualColorRationale: true,
599
- requireTokenLayering: true,
600
- requireTokenAliasingPlan: true,
601
- allowHexDerivatives: true,
602
- requireMotionRationale: true,
603
- requireStateMorphology: true,
604
- requireAccessibilitySplit: true,
605
- requireWcagHardFloor: true,
606
- requireStructuredDesignExecutionPolicy: true,
607
- requireStructuredDesignHandoff: true,
608
- requireVisualResetStrategyWhenZeroBasedRedesignRequested: true,
609
- requireConceptualAnchorWhenNoExternalResearch: true,
610
- requireAgentLedAnchorResearchWhenUserResearchMissing: true,
611
- rejectTimidDashboardAnchor: true,
612
- requireReviewRubric: true,
613
- requireGenericityExplanation: true,
614
- genericityAutoFail: true,
615
- requireSignatureMove: true,
616
- rejectTemplateNeutralLayout: true,
617
- requireAiSafeUiAudit: true,
618
- rejectAiSafeUiTemplateLook: true,
619
- requireThreeProductSpecificSignals: true,
620
- rejectDecorativeBackgroundPatternsWithoutProductFunction: true,
621
- },
622
640
  requiredDesignSections: DESIGN_REQUIRED_SECTIONS,
623
641
  implementation: {
624
642
  requiredDeliverables: ['docs/DESIGN.md', 'docs/design-intent.json'],
@@ -644,749 +662,7 @@ function buildDesignIntentContractObject({
644
662
  };
645
663
  }
646
664
 
647
- function hasNonEmptyString(value) {
648
- return typeof value === 'string' && value.trim().length > 0;
649
- }
650
-
651
- export function validateDesignContractCompleteness(designIntentContract) {
652
- const validationIssues = [];
653
- const conceptualAnchor = designIntentContract?.conceptualAnchor;
654
- const derivedTokenLogic = designIntentContract?.derivedTokenLogic;
655
- const libraryDecisions = designIntentContract?.libraryDecisions;
656
-
657
- const anchorReference = conceptualAnchor?.anchorReference || derivedTokenLogic?.anchorReference;
658
- if (!hasNonEmptyString(anchorReference)) {
659
- validationIssues.push('designIntent.conceptualAnchor.anchorReference must be a stable non-empty ID for deterministic validation.');
660
- }
661
-
662
- if (!derivedTokenLogic || typeof derivedTokenLogic !== 'object') {
663
- validationIssues.push('designIntent.derivedTokenLogic must exist.');
664
- } else {
665
- if (derivedTokenLogic.anchorReference !== anchorReference) {
666
- validationIssues.push('designIntent.derivedTokenLogic.anchorReference must exactly match designIntent.conceptualAnchor.anchorReference.');
667
- }
668
-
669
- for (const requiredFieldName of [
670
- 'colorDerivationSource',
671
- 'spacingDerivationSource',
672
- 'typographyDerivationSource',
673
- 'motionDerivationSource',
674
- 'validationRule',
675
- ]) {
676
- if (!hasNonEmptyString(derivedTokenLogic[requiredFieldName])) {
677
- validationIssues.push(`designIntent.derivedTokenLogic.${requiredFieldName} must be a non-empty string.`);
678
- }
679
- }
680
-
681
- if (
682
- hasNonEmptyString(derivedTokenLogic.validationRule)
683
- && !derivedTokenLogic.validationRule.includes('anchorReference')
684
- ) {
685
- validationIssues.push('designIntent.derivedTokenLogic.validationRule must require traceability to anchorReference.');
686
- }
687
- }
688
-
689
- if (!['verified', 'pending-verification', 'no-external-library-needed'].includes(designIntentContract?.libraryResearchStatus)) {
690
- validationIssues.push('designIntent.libraryResearchStatus must be verified, pending-verification, or no-external-library-needed.');
691
- }
692
-
693
- if (!Array.isArray(libraryDecisions)) {
694
- validationIssues.push('designIntent.libraryDecisions must be an array.');
695
- } else {
696
- for (const [libraryIndex, libraryDecision] of libraryDecisions.entries()) {
697
- if (!libraryDecision || typeof libraryDecision !== 'object') {
698
- validationIssues.push(`designIntent.libraryDecisions[${libraryIndex}] must be an object.`);
699
- continue;
700
- }
701
-
702
- if (!hasNonEmptyString(libraryDecision.library)) {
703
- validationIssues.push(`designIntent.libraryDecisions[${libraryIndex}].library must be a non-empty string.`);
704
- }
705
- if (!hasNonEmptyString(libraryDecision.purpose)) {
706
- validationIssues.push(`designIntent.libraryDecisions[${libraryIndex}].purpose must be a non-empty string.`);
707
- }
708
-
709
- const hasVerification = hasNonEmptyString(libraryDecision.verifiedAt)
710
- && hasNonEmptyString(libraryDecision.sourceUrl);
711
- const hasFallback = hasNonEmptyString(libraryDecision.fallbackIfUnavailable);
712
-
713
- if (!hasVerification && !hasFallback) {
714
- validationIssues.push(`designIntent.libraryDecisions[${libraryIndex}] must either record verification source or provide fallbackIfUnavailable.`);
715
- }
716
- }
717
- }
718
-
719
- return validationIssues;
720
- }
721
-
722
- export function validateDesignIntentContract(designIntentContract) {
723
- const validationErrors = [];
724
-
725
- if (!designIntentContract || typeof designIntentContract !== 'object') {
726
- return ['Design intent contract must be an object.'];
727
- }
728
-
729
- validationErrors.push(...validateDesignContractCompleteness(designIntentContract));
730
-
731
- if (designIntentContract.mode !== 'dynamic') {
732
- validationErrors.push('designIntent.mode must equal "dynamic".');
733
- }
734
-
735
- if (!designIntentContract.project || typeof designIntentContract.project !== 'object') {
736
- validationErrors.push('designIntent.project must exist.');
737
- }
738
-
739
- if (!designIntentContract.designPhilosophy || typeof designIntentContract.designPhilosophy !== 'string') {
740
- validationErrors.push('designIntent.designPhilosophy must be a non-empty string.');
741
- }
742
-
743
- if (!designIntentContract.externalResearchIntake || typeof designIntentContract.externalResearchIntake !== 'object') {
744
- validationErrors.push('designIntent.externalResearchIntake must exist.');
745
- } else {
746
- if (designIntentContract.externalResearchIntake.userSuppliedResearchPolicy !== 'read-as-candidate-evidence-not-final-prescription') {
747
- validationErrors.push('designIntent.externalResearchIntake.userSuppliedResearchPolicy must preserve user research as candidate evidence.');
748
- }
749
- if (designIntentContract.externalResearchIntake.requireOfficialDocsVerificationForTechnologyClaims !== true) {
750
- validationErrors.push('designIntent.externalResearchIntake.requireOfficialDocsVerificationForTechnologyClaims must equal true.');
751
- }
752
- if (
753
- !Array.isArray(designIntentContract.externalResearchIntake.candidateDomains)
754
- || !designIntentContract.externalResearchIntake.candidateDomains.includes('motion-and-scroll')
755
- ) {
756
- validationErrors.push('designIntent.externalResearchIntake.candidateDomains must include motion-and-scroll.');
757
- }
758
- }
759
-
760
- if (!designIntentContract.conceptualAnchor || typeof designIntentContract.conceptualAnchor !== 'object') {
761
- validationErrors.push('designIntent.conceptualAnchor must exist.');
762
- } else {
763
- const conceptualAnchor = designIntentContract.conceptualAnchor;
764
- if (conceptualAnchor.mode !== 'required-when-no-external-research') {
765
- validationErrors.push('designIntent.conceptualAnchor.mode must equal "required-when-no-external-research".');
766
- }
767
- if (conceptualAnchor.seedMode !== 'selection-policy-only') {
768
- validationErrors.push('designIntent.conceptualAnchor.seedMode must equal "selection-policy-only".');
769
- }
770
- if (conceptualAnchor.requiresAgentSelectionBeforeUiImplementation !== true) {
771
- validationErrors.push('designIntent.conceptualAnchor.requiresAgentSelectionBeforeUiImplementation must equal true.');
772
- }
773
- if (!hasNonEmptyString(conceptualAnchor.anchorReference)) {
774
- validationErrors.push('designIntent.conceptualAnchor.anchorReference must be a stable non-empty ID.');
775
- }
776
- const userResearchAbsencePolicy = conceptualAnchor.userResearchAbsencePolicy;
777
- if (!userResearchAbsencePolicy || typeof userResearchAbsencePolicy !== 'object') {
778
- validationErrors.push('designIntent.conceptualAnchor.userResearchAbsencePolicy must exist.');
779
- } else {
780
- if (userResearchAbsencePolicy.userSuppliedResearchOnly !== true) {
781
- validationErrors.push('designIntent.conceptualAnchor.userResearchAbsencePolicy.userSuppliedResearchOnly must equal true.');
782
- }
783
- if (userResearchAbsencePolicy.scaffoldSeedDoesNotCountAsResearch !== true) {
784
- validationErrors.push('designIntent.conceptualAnchor.userResearchAbsencePolicy.scaffoldSeedDoesNotCountAsResearch must equal true.');
785
- }
786
- if (userResearchAbsencePolicy.priorUiDoesNotCountAsResearch !== true) {
787
- validationErrors.push('designIntent.conceptualAnchor.userResearchAbsencePolicy.priorUiDoesNotCountAsResearch must equal true.');
788
- }
789
- if (userResearchAbsencePolicy.requireAgentLedResearchWhenAvailable !== true) {
790
- validationErrors.push('designIntent.conceptualAnchor.userResearchAbsencePolicy.requireAgentLedResearchWhenAvailable must equal true.');
791
- }
792
- }
793
- const candidateSelectionPolicy = conceptualAnchor.candidateSelectionPolicy;
794
- if (!candidateSelectionPolicy || typeof candidateSelectionPolicy !== 'object') {
795
- validationErrors.push('designIntent.conceptualAnchor.candidateSelectionPolicy must exist.');
796
- } else {
797
- if (candidateSelectionPolicy.considerAtLeast < 3) {
798
- validationErrors.push('designIntent.conceptualAnchor.candidateSelectionPolicy.considerAtLeast must be at least 3.');
799
- }
800
- if (candidateSelectionPolicy.discardObviousCandidateCount < 2) {
801
- validationErrors.push('designIntent.conceptualAnchor.candidateSelectionPolicy.discardObviousCandidateCount must be at least 2.');
802
- }
803
- if (candidateSelectionPolicy.minimumCandidateDistance !== 'high') {
804
- validationErrors.push('designIntent.conceptualAnchor.candidateSelectionPolicy.minimumCandidateDistance must equal "high".');
805
- }
806
- if (candidateSelectionPolicy.discardPredictableCandidates !== true) {
807
- validationErrors.push('designIntent.conceptualAnchor.candidateSelectionPolicy.discardPredictableCandidates must equal true.');
808
- }
809
- if (candidateSelectionPolicy.preferDistinctiveOverSafe !== true) {
810
- validationErrors.push('designIntent.conceptualAnchor.candidateSelectionPolicy.preferDistinctiveOverSafe must equal true.');
811
- }
812
- if (candidateSelectionPolicy.doNotRevealHiddenCandidateList !== true) {
813
- validationErrors.push('designIntent.conceptualAnchor.candidateSelectionPolicy.doNotRevealHiddenCandidateList must equal true.');
814
- }
815
- if (candidateSelectionPolicy.outputOnlyChosenAnchor !== true) {
816
- validationErrors.push('designIntent.conceptualAnchor.candidateSelectionPolicy.outputOnlyChosenAnchor must equal true.');
817
- }
818
- }
819
- const creativeCommitmentPolicy = conceptualAnchor.creativeCommitmentPolicy;
820
- if (!creativeCommitmentPolicy || typeof creativeCommitmentPolicy !== 'object') {
821
- validationErrors.push('designIntent.conceptualAnchor.creativeCommitmentPolicy must exist.');
822
- } else {
823
- if (creativeCommitmentPolicy.requiredBeforeComplianceReview !== true) {
824
- validationErrors.push('designIntent.conceptualAnchor.creativeCommitmentPolicy.requiredBeforeComplianceReview must equal true.');
825
- }
826
- if (creativeCommitmentPolicy.recordInDesignDocs !== true) {
827
- validationErrors.push('designIntent.conceptualAnchor.creativeCommitmentPolicy.recordInDesignDocs must equal true.');
828
- }
829
- if (
830
- !Array.isArray(creativeCommitmentPolicy.requiredCommitmentFields)
831
- || !creativeCommitmentPolicy.requiredCommitmentFields.includes('specificReferencePoint')
832
- || !creativeCommitmentPolicy.requiredCommitmentFields.includes('signatureMotion')
833
- || !creativeCommitmentPolicy.requiredCommitmentFields.includes('typographicDecision')
834
- ) {
835
- validationErrors.push('designIntent.conceptualAnchor.creativeCommitmentPolicy.requiredCommitmentFields must include specificReferencePoint, signatureMotion, and typographicDecision.');
836
- }
837
- if (creativeCommitmentPolicy.rejectGenericQualityWordsOnly !== true) {
838
- validationErrors.push('designIntent.conceptualAnchor.creativeCommitmentPolicy.rejectGenericQualityWordsOnly must equal true.');
839
- }
840
- }
841
- if (
842
- !Array.isArray(conceptualAnchor.forbiddenFinalAnchorTerms)
843
- || !conceptualAnchor.forbiddenFinalAnchorTerms.includes('dashboard')
844
- || !conceptualAnchor.forbiddenFinalAnchorTerms.includes('cards')
845
- || !conceptualAnchor.forbiddenFinalAnchorTerms.includes('safe-admin-layout')
846
- ) {
847
- validationErrors.push('designIntent.conceptualAnchor.forbiddenFinalAnchorTerms must reject basic UI labels.');
848
- }
849
- if (
850
- !Array.isArray(conceptualAnchor.sourceDomains)
851
- || conceptualAnchor.sourceDomains.length < 4
852
- || !conceptualAnchor.sourceDomains.includes('complex-physical-engineering')
853
- || !conceptualAnchor.sourceDomains.includes('cinematic-spatial-interface')
854
- || !conceptualAnchor.sourceDomains.includes('premium-interactive-web-experiences')
855
- ) {
856
- validationErrors.push('designIntent.conceptualAnchor.sourceDomains must list broad non-template anchor domains.');
857
- }
858
- const visualRiskBudget = conceptualAnchor.visualRiskBudget;
859
- if (!visualRiskBudget || typeof visualRiskBudget !== 'object') {
860
- validationErrors.push('designIntent.conceptualAnchor.visualRiskBudget must exist.');
861
- } else {
862
- if (visualRiskBudget.mode !== 'high-distinctiveness-with-accessibility-and-performance-guardrails') {
863
- validationErrors.push('designIntent.conceptualAnchor.visualRiskBudget.mode must preserve high-distinctiveness guardrails.');
864
- }
865
- if (visualRiskBudget.allowRichMotionAndMicroInteraction !== true) {
866
- validationErrors.push('designIntent.conceptualAnchor.visualRiskBudget.allowRichMotionAndMicroInteraction must equal true.');
867
- }
868
- if (visualRiskBudget.rejectTimidDefaultWhenAnchorSupportsExpressiveUi !== true) {
869
- validationErrors.push('designIntent.conceptualAnchor.visualRiskBudget.rejectTimidDefaultWhenAnchorSupportsExpressiveUi must equal true.');
870
- }
871
- if (visualRiskBudget.requireReducedMotionFallback !== true) {
872
- validationErrors.push('designIntent.conceptualAnchor.visualRiskBudget.requireReducedMotionFallback must equal true.');
873
- }
874
- }
875
- if (
876
- !Array.isArray(conceptualAnchor.requiredDerivedAxes)
877
- || !conceptualAnchor.requiredDerivedAxes.includes('typography')
878
- || !conceptualAnchor.requiredDerivedAxes.includes('responsive-composition')
879
- ) {
880
- validationErrors.push('designIntent.conceptualAnchor.requiredDerivedAxes must include typography and responsive-composition.');
881
- }
882
- const finalAnchorContract = conceptualAnchor.finalAnchorContract;
883
- if (!finalAnchorContract || typeof finalAnchorContract !== 'object') {
884
- validationErrors.push('designIntent.conceptualAnchor.finalAnchorContract must exist.');
885
- } else {
886
- if (
887
- !Array.isArray(finalAnchorContract.requiredFields)
888
- || !finalAnchorContract.requiredFields.includes('anchorReference')
889
- || !finalAnchorContract.requiredFields.includes('agentResearchMode')
890
- || !finalAnchorContract.requiredFields.includes('specificReferencePoint')
891
- || !finalAnchorContract.requiredFields.includes('signatureMotion')
892
- || !finalAnchorContract.requiredFields.includes('typographicDecision')
893
- || !finalAnchorContract.requiredFields.includes('derivedTokenLogic')
894
- || !finalAnchorContract.requiredFields.includes('visualRiskBudget')
895
- || !finalAnchorContract.requiredFields.includes('motionRiskBudget')
896
- || !finalAnchorContract.requiredFields.includes('cohesionChecks')
897
- ) {
898
- validationErrors.push('designIntent.conceptualAnchor.finalAnchorContract.requiredFields must require anchorReference, agentResearchMode, specificReferencePoint, signatureMotion, typographicDecision, derivedTokenLogic, visualRiskBudget, motionRiskBudget, and cohesionChecks.');
899
- }
900
- if (
901
- !Array.isArray(finalAnchorContract.derivedTokenLogicAxes)
902
- || !finalAnchorContract.derivedTokenLogicAxes.includes('motion')
903
- || !finalAnchorContract.derivedTokenLogicAxes.includes('morphology')
904
- ) {
905
- validationErrors.push('designIntent.conceptualAnchor.finalAnchorContract.derivedTokenLogicAxes must include motion and morphology.');
906
- }
907
- if (
908
- !Array.isArray(finalAnchorContract.cohesionChecks)
909
- || !finalAnchorContract.cohesionChecks.includes('no-dashboard-mental-model')
910
- || !finalAnchorContract.cohesionChecks.includes('motion-derived-from-anchor')
911
- ) {
912
- validationErrors.push('designIntent.conceptualAnchor.finalAnchorContract.cohesionChecks must reject dashboard mental models and require motion derivation.');
913
- }
914
- }
915
- }
916
-
917
- if (!designIntentContract.mathSystems || typeof designIntentContract.mathSystems !== 'object') {
918
- validationErrors.push('designIntent.mathSystems must exist.');
919
- } else {
920
- if (!String(designIntentContract.mathSystems.typographyScaleRatio || '').trim()) {
921
- validationErrors.push('designIntent.mathSystems.typographyScaleRatio must describe the chosen or pending type scale decision.');
922
- }
923
- if (!String(designIntentContract.mathSystems.baseGridUnit || '').trim()) {
924
- validationErrors.push('designIntent.mathSystems.baseGridUnit must describe the chosen or pending spacing grid decision.');
925
- }
926
- }
927
-
928
- if (!designIntentContract.aiSafeUiAudit || typeof designIntentContract.aiSafeUiAudit !== 'object') {
929
- validationErrors.push('designIntent.aiSafeUiAudit must exist.');
930
- } else {
931
- const aiSafeUiAudit = designIntentContract.aiSafeUiAudit;
932
- if (aiSafeUiAudit.status !== 'agent-must-complete-before-ui-implementation') {
933
- validationErrors.push('designIntent.aiSafeUiAudit.status must require completion before UI implementation.');
934
- }
935
- if (!String(aiSafeUiAudit.failureDefinition || '').includes('AI-safe')) {
936
- validationErrors.push('designIntent.aiSafeUiAudit.failureDefinition must define AI-safe UI drift.');
937
- }
938
- if (!String(aiSafeUiAudit.interchangeabilityTest || '').includes('renamed')) {
939
- validationErrors.push('designIntent.aiSafeUiAudit.interchangeabilityTest must include the rename/interchangeability test.');
940
- }
941
- if (!Array.isArray(aiSafeUiAudit.requiredProductSpecificSignals) || aiSafeUiAudit.requiredProductSpecificSignals.length < 3) {
942
- validationErrors.push('designIntent.aiSafeUiAudit.requiredProductSpecificSignals must list at least three product-specific signals.');
943
- }
944
- if (!String(aiSafeUiAudit.paletteExplorationRule || '').trim()) {
945
- validationErrors.push('designIntent.aiSafeUiAudit.paletteExplorationRule must be a non-empty string.');
946
- }
947
- if (!String(aiSafeUiAudit.backgroundPatternRule || '').trim()) {
948
- validationErrors.push('designIntent.aiSafeUiAudit.backgroundPatternRule must be a non-empty string.');
949
- }
950
- if (!String(aiSafeUiAudit.reviewQuestion || '').trim()) {
951
- validationErrors.push('designIntent.aiSafeUiAudit.reviewQuestion must be a non-empty string.');
952
- }
953
- if (aiSafeUiAudit.blockingByDefault !== true) {
954
- validationErrors.push('designIntent.aiSafeUiAudit.blockingByDefault must equal true.');
955
- }
956
- }
957
-
958
- if (!designIntentContract.tokenSystem || typeof designIntentContract.tokenSystem !== 'object') {
959
- validationErrors.push('designIntent.tokenSystem must exist.');
960
- } else {
961
- const taxonomyOrder = designIntentContract.tokenSystem.taxonomyOrder;
962
- if (!Array.isArray(taxonomyOrder) || taxonomyOrder.join('|') !== 'primitive|semantic|component') {
963
- validationErrors.push('designIntent.tokenSystem.taxonomyOrder must equal ["primitive","semantic","component"].');
964
- }
965
- if (designIntentContract.tokenSystem.primitiveColorSpace !== 'OKLCH') {
966
- validationErrors.push('designIntent.tokenSystem.primitiveColorSpace must equal "OKLCH".');
967
- }
968
- if (designIntentContract.tokenSystem.requireSemanticAliases !== true) {
969
- validationErrors.push('designIntent.tokenSystem.requireSemanticAliases must equal true.');
970
- }
971
- if (designIntentContract.tokenSystem.semanticAliasesMutableWithoutComponentRewrite !== true) {
972
- validationErrors.push('designIntent.tokenSystem.semanticAliasesMutableWithoutComponentRewrite must equal true.');
973
- }
974
- if (designIntentContract.tokenSystem.componentTokensConsumeSemantic !== true) {
975
- validationErrors.push('designIntent.tokenSystem.componentTokensConsumeSemantic must equal true.');
976
- }
977
- const fallbackPolicy = designIntentContract.tokenSystem.fallbackPolicy;
978
- if (!fallbackPolicy || typeof fallbackPolicy !== 'object') {
979
- validationErrors.push('designIntent.tokenSystem.fallbackPolicy must exist.');
980
- } else {
981
- if (fallbackPolicy.forbidRawHexOutsidePrimitives !== true) {
982
- validationErrors.push('designIntent.tokenSystem.fallbackPolicy.forbidRawHexOutsidePrimitives must equal true.');
983
- }
984
- if (fallbackPolicy.forbidRawSpacingOutsidePrimitives !== true) {
985
- validationErrors.push('designIntent.tokenSystem.fallbackPolicy.forbidRawSpacingOutsidePrimitives must equal true.');
986
- }
987
- if (fallbackPolicy.requireDocumentedExceptionForLegacyBypass !== true) {
988
- validationErrors.push('designIntent.tokenSystem.fallbackPolicy.requireDocumentedExceptionForLegacyBypass must equal true.');
989
- }
990
- }
991
- const namingConstraints = designIntentContract.tokenSystem.namingConstraints;
992
- if (!namingConstraints || typeof namingConstraints !== 'object') {
993
- validationErrors.push('designIntent.tokenSystem.namingConstraints must exist.');
994
- } else {
995
- if (namingConstraints.forbidCurlyBracesInNames !== true) {
996
- validationErrors.push('designIntent.tokenSystem.namingConstraints.forbidCurlyBracesInNames must equal true.');
997
- }
998
- if (namingConstraints.forbidDotsInNames !== true) {
999
- validationErrors.push('designIntent.tokenSystem.namingConstraints.forbidDotsInNames must equal true.');
1000
- }
1001
- if (namingConstraints.forbidSquareBracketsInNames !== true) {
1002
- validationErrors.push('designIntent.tokenSystem.namingConstraints.forbidSquareBracketsInNames must equal true.');
1003
- }
1004
- }
1005
- }
1006
-
1007
- if (!designIntentContract.colorTruth || typeof designIntentContract.colorTruth !== 'object') {
1008
- validationErrors.push('designIntent.colorTruth must exist.');
1009
- } else {
1010
- if (designIntentContract.colorTruth.format !== 'OKLCH') {
1011
- validationErrors.push('designIntent.colorTruth.format must equal "OKLCH".');
1012
- }
1013
- if (designIntentContract.colorTruth.allowHexDerivatives !== true) {
1014
- validationErrors.push('designIntent.colorTruth.allowHexDerivatives must equal true.');
1015
- }
1016
- if (!String(designIntentContract.colorTruth.intent || '').trim()) {
1017
- validationErrors.push('designIntent.colorTruth.intent must be a non-empty string.');
1018
- }
1019
- const paletteRoles = designIntentContract.colorTruth.paletteRoles;
1020
- if (!Array.isArray(paletteRoles) || paletteRoles.length < 1) {
1021
- validationErrors.push('designIntent.colorTruth.paletteRoles must define or request agent-defined semantic palette roles.');
1022
- }
1023
- if (designIntentContract.colorTruth.rolesMustBeAgentDefined !== true) {
1024
- validationErrors.push('designIntent.colorTruth.rolesMustBeAgentDefined must equal true.');
1025
- }
1026
- }
1027
-
1028
- if (!designIntentContract.crossViewportAdaptation || typeof designIntentContract.crossViewportAdaptation !== 'object') {
1029
- validationErrors.push('designIntent.crossViewportAdaptation must exist.');
1030
- } else {
1031
- const mutationRules = designIntentContract.crossViewportAdaptation.mutationRules;
1032
- if (!mutationRules || typeof mutationRules !== 'object') {
1033
- validationErrors.push('designIntent.crossViewportAdaptation.mutationRules must exist.');
1034
- } else {
1035
- for (const viewportKey of ['mobile', 'tablet', 'desktop']) {
1036
- if (!String(mutationRules[viewportKey] || '').trim()) {
1037
- validationErrors.push(`designIntent.crossViewportAdaptation.mutationRules.${viewportKey} must be a non-empty string.`);
1038
- }
1039
- }
1040
- }
1041
- }
1042
-
1043
- if (!designIntentContract.motionSystem || typeof designIntentContract.motionSystem !== 'object') {
1044
- validationErrors.push('designIntent.motionSystem must exist.');
1045
- } else {
1046
- if (designIntentContract.motionSystem.allowMeaningfulMotion !== true) {
1047
- validationErrors.push('designIntent.motionSystem.allowMeaningfulMotion must equal true.');
1048
- }
1049
- if (!String(designIntentContract.motionSystem.purpose || '').trim()) {
1050
- validationErrors.push('designIntent.motionSystem.purpose must be a non-empty string.');
1051
- }
1052
- if (designIntentContract.motionSystem.respectReducedMotion !== true) {
1053
- validationErrors.push('designIntent.motionSystem.respectReducedMotion must equal true.');
1054
- }
1055
- }
1056
-
1057
- if (!designIntentContract.componentMorphology || typeof designIntentContract.componentMorphology !== 'object') {
1058
- validationErrors.push('designIntent.componentMorphology must exist.');
1059
- } else {
1060
- if (designIntentContract.componentMorphology.requireStateBehaviorMatrix !== true) {
1061
- validationErrors.push('designIntent.componentMorphology.requireStateBehaviorMatrix must equal true.');
1062
- }
1063
- if (!Array.isArray(designIntentContract.componentMorphology.stateKeys) || designIntentContract.componentMorphology.stateKeys.length < 4) {
1064
- validationErrors.push('designIntent.componentMorphology.stateKeys must contain multiple interaction states.');
1065
- }
1066
- const viewportBehavior = designIntentContract.componentMorphology.viewportBehavior;
1067
- if (!viewportBehavior || typeof viewportBehavior !== 'object') {
1068
- validationErrors.push('designIntent.componentMorphology.viewportBehavior must exist.');
1069
- } else {
1070
- for (const viewportKey of ['mobile', 'tablet', 'desktop']) {
1071
- if (!String(viewportBehavior[viewportKey] || '').trim()) {
1072
- validationErrors.push(`designIntent.componentMorphology.viewportBehavior.${viewportKey} must be a non-empty string.`);
1073
- }
1074
- }
1075
- }
1076
- }
1077
-
1078
- if (!designIntentContract.accessibilityPolicy || typeof designIntentContract.accessibilityPolicy !== 'object') {
1079
- validationErrors.push('designIntent.accessibilityPolicy must exist.');
1080
- } else {
1081
- if (designIntentContract.accessibilityPolicy.hardComplianceFloor !== 'WCAG-2.2-AA') {
1082
- validationErrors.push('designIntent.accessibilityPolicy.hardComplianceFloor must equal "WCAG-2.2-AA".');
1083
- }
1084
- if (designIntentContract.accessibilityPolicy.advisoryContrastModel !== 'APCA') {
1085
- validationErrors.push('designIntent.accessibilityPolicy.advisoryContrastModel must equal "APCA".');
1086
- }
1087
- if (designIntentContract.accessibilityPolicy.failOnHardViolations !== true) {
1088
- validationErrors.push('designIntent.accessibilityPolicy.failOnHardViolations must equal true.');
1089
- }
1090
- if (designIntentContract.accessibilityPolicy.advisoryFindingsDoNotBlockByDefault !== true) {
1091
- validationErrors.push('designIntent.accessibilityPolicy.advisoryFindingsDoNotBlockByDefault must equal true.');
1092
- }
1093
- const hardRequirements = designIntentContract.accessibilityPolicy.hardRequirements;
1094
- if (!hardRequirements || typeof hardRequirements !== 'object') {
1095
- validationErrors.push('designIntent.accessibilityPolicy.hardRequirements must exist.');
1096
- } else {
1097
- for (const requirementKey of [
1098
- 'textContrastMinimum',
1099
- 'nonTextContrast',
1100
- 'useOfColorOnlyProhibited',
1101
- 'focusVisible',
1102
- 'focusAppearance',
1103
- 'targetSizeMinimum',
1104
- 'keyboardAccess',
1105
- 'reflowRequired',
1106
- 'accessibleAuthenticationMinimum',
1107
- 'statusMessagesAndDynamicStateAccess',
1108
- ]) {
1109
- if (hardRequirements[requirementKey] !== true) {
1110
- validationErrors.push(`designIntent.accessibilityPolicy.hardRequirements.${requirementKey} must equal true.`);
1111
- }
1112
- }
1113
- }
1114
- const advisoryChecks = designIntentContract.accessibilityPolicy.advisoryChecks;
1115
- if (!advisoryChecks || typeof advisoryChecks !== 'object') {
1116
- validationErrors.push('designIntent.accessibilityPolicy.advisoryChecks must exist.');
1117
- } else {
1118
- for (const advisoryKey of [
1119
- 'perceptualContrastReview',
1120
- 'darkModeContrastTuning',
1121
- 'typographyReadabilityTuning',
1122
- ]) {
1123
- if (advisoryChecks[advisoryKey] !== true) {
1124
- validationErrors.push(`designIntent.accessibilityPolicy.advisoryChecks.${advisoryKey} must equal true.`);
1125
- }
1126
- }
1127
- }
1128
- }
1129
-
1130
- if (!designIntentContract.contextHygiene || typeof designIntentContract.contextHygiene !== 'object') {
1131
- validationErrors.push('designIntent.contextHygiene must exist.');
1132
- } else {
1133
- if (designIntentContract.contextHygiene.continuityMode !== 'opt-in-only') {
1134
- validationErrors.push('designIntent.contextHygiene.continuityMode must equal "opt-in-only".');
1135
- }
1136
- if (designIntentContract.contextHygiene.repoEvidenceOverridesMemory !== true) {
1137
- validationErrors.push('designIntent.contextHygiene.repoEvidenceOverridesMemory must equal true.');
1138
- }
1139
- if (designIntentContract.contextHygiene.requireExplicitContinuityApproval !== true) {
1140
- validationErrors.push('designIntent.contextHygiene.requireExplicitContinuityApproval must equal true.');
1141
- }
1142
- if (designIntentContract.contextHygiene.forbidCarryoverWhenUnapproved !== true) {
1143
- validationErrors.push('designIntent.contextHygiene.forbidCarryoverWhenUnapproved must equal true.');
1144
- }
1145
- if (!Array.isArray(designIntentContract.contextHygiene.allowedSources) || designIntentContract.contextHygiene.allowedSources.length < 4) {
1146
- validationErrors.push('designIntent.contextHygiene.allowedSources must list the approved design evidence sources.');
1147
- }
1148
- if (!Array.isArray(designIntentContract.contextHygiene.taintedSources) || designIntentContract.contextHygiene.taintedSources.length < 3) {
1149
- validationErrors.push('designIntent.contextHygiene.taintedSources must list tainted carryover sources.');
1150
- }
1151
- if (!String(designIntentContract.contextHygiene.approvedExternalConstraintUsage || '').trim()) {
1152
- validationErrors.push('designIntent.contextHygiene.approvedExternalConstraintUsage must be a non-empty string.');
1153
- }
1154
- }
1155
-
1156
- if (!designIntentContract.designExecutionPolicy || typeof designIntentContract.designExecutionPolicy !== 'object') {
1157
- validationErrors.push('designIntent.designExecutionPolicy must exist.');
1158
- } else {
1159
- if (designIntentContract.designExecutionPolicy.representationStrategy !== 'surface-plan-v1') {
1160
- validationErrors.push('designIntent.designExecutionPolicy.representationStrategy must equal "surface-plan-v1".');
1161
- }
1162
- for (const requiredFlagName of [
1163
- 'requireSurfacePlan',
1164
- 'requireComponentGraph',
1165
- 'requireViewportMutationPlan',
1166
- 'requireInteractionStateMatrix',
1167
- 'requireContentPriorityMap',
1168
- 'requireTaskFlowNarrative',
1169
- 'requireSignatureMoveRationale',
1170
- 'requireCreativeCommitmentGate',
1171
- 'requireStructuredHandoff',
1172
- 'requireRepoEvidenceAlignment',
1173
- 'forbidScreenshotDependency',
1174
- 'requirePerSurfaceMutationOps',
1175
- 'forbidUniformSiblingSurfaceTreatment',
1176
- 'zeroBasedRedesignResetsPriorVisualsWhenRequested',
1177
- ]) {
1178
- if (designIntentContract.designExecutionPolicy[requiredFlagName] !== true) {
1179
- validationErrors.push(`designIntent.designExecutionPolicy.${requiredFlagName} must equal true.`);
1180
- }
1181
- }
1182
- if (designIntentContract.designExecutionPolicy.handoffFormatVersion !== 'ui-handoff-v1') {
1183
- validationErrors.push('designIntent.designExecutionPolicy.handoffFormatVersion must equal "ui-handoff-v1".');
1184
- }
1185
- if (
1186
- !Array.isArray(designIntentContract.designExecutionPolicy.semanticReviewFocus)
1187
- || designIntentContract.designExecutionPolicy.semanticReviewFocus.length < 4
1188
- ) {
1189
- validationErrors.push('designIntent.designExecutionPolicy.semanticReviewFocus must list the required review dimensions.');
1190
- }
1191
- }
1192
-
1193
- if (!designIntentContract.designExecutionHandoff || typeof designIntentContract.designExecutionHandoff !== 'object') {
1194
- validationErrors.push('designIntent.designExecutionHandoff must exist.');
1195
- } else {
1196
- if (designIntentContract.designExecutionHandoff.version !== 'ui-handoff-v1') {
1197
- validationErrors.push('designIntent.designExecutionHandoff.version must equal "ui-handoff-v1".');
1198
- }
1199
- if (designIntentContract.designExecutionHandoff.seedMode !== 'structure-first-scaffold') {
1200
- validationErrors.push('designIntent.designExecutionHandoff.seedMode must equal "structure-first-scaffold".');
1201
- }
1202
- if (designIntentContract.designExecutionHandoff.requiresTaskSpecificRefinement !== true) {
1203
- validationErrors.push('designIntent.designExecutionHandoff.requiresTaskSpecificRefinement must equal true.');
1204
- }
1205
- if (!String(designIntentContract.designExecutionHandoff.primaryExperienceGoal || '').trim()) {
1206
- validationErrors.push('designIntent.designExecutionHandoff.primaryExperienceGoal must be a non-empty string.');
1207
- }
1208
- if (!Array.isArray(designIntentContract.designExecutionHandoff.surfacePlan) || designIntentContract.designExecutionHandoff.surfacePlan.length < 1) {
1209
- validationErrors.push('designIntent.designExecutionHandoff.surfacePlan must define at least one planned surface.');
1210
- }
1211
- const componentGraph = designIntentContract.designExecutionHandoff.componentGraph;
1212
- if (!componentGraph || typeof componentGraph !== 'object') {
1213
- validationErrors.push('designIntent.designExecutionHandoff.componentGraph must exist.');
1214
- } else {
1215
- if (!Array.isArray(componentGraph.nodes) || componentGraph.nodes.length < 2) {
1216
- validationErrors.push('designIntent.designExecutionHandoff.componentGraph.nodes must list the primary execution nodes.');
1217
- }
1218
- if (!Array.isArray(componentGraph.edges) || componentGraph.edges.length < 1) {
1219
- validationErrors.push('designIntent.designExecutionHandoff.componentGraph.edges must define relationships between UI nodes.');
1220
- }
1221
- }
1222
- const contentPriorityMap = designIntentContract.designExecutionHandoff.contentPriorityMap;
1223
- if (!contentPriorityMap || typeof contentPriorityMap !== 'object') {
1224
- validationErrors.push('designIntent.designExecutionHandoff.contentPriorityMap must exist.');
1225
- } else {
1226
- for (const priorityBucket of ['primary', 'secondary', 'deferred']) {
1227
- if (!Array.isArray(contentPriorityMap[priorityBucket]) || contentPriorityMap[priorityBucket].length < 1) {
1228
- validationErrors.push(`designIntent.designExecutionHandoff.contentPriorityMap.${priorityBucket} must contain at least one item.`);
1229
- }
1230
- }
1231
- }
1232
- const viewportMutationPlan = designIntentContract.designExecutionHandoff.viewportMutationPlan;
1233
- if (!viewportMutationPlan || typeof viewportMutationPlan !== 'object') {
1234
- validationErrors.push('designIntent.designExecutionHandoff.viewportMutationPlan must exist.');
1235
- } else {
1236
- for (const viewportKey of ['mobile', 'tablet', 'desktop']) {
1237
- const viewportPlan = viewportMutationPlan[viewportKey];
1238
- if (!viewportPlan || typeof viewportPlan !== 'object') {
1239
- validationErrors.push(`designIntent.designExecutionHandoff.viewportMutationPlan.${viewportKey} must be an object.`);
1240
- continue;
1241
- }
1242
- if (!String(viewportPlan.primaryOperation || '').trim()) {
1243
- validationErrors.push(`designIntent.designExecutionHandoff.viewportMutationPlan.${viewportKey}.primaryOperation must be a non-empty string.`);
1244
- }
1245
- if (!Array.isArray(viewportPlan.requiredSurfaceActions) || viewportPlan.requiredSurfaceActions.length < 2) {
1246
- validationErrors.push(`designIntent.designExecutionHandoff.viewportMutationPlan.${viewportKey}.requiredSurfaceActions must contain at least two actions.`);
1247
- }
1248
- if (!Array.isArray(viewportPlan.forbiddenPatterns) || viewportPlan.forbiddenPatterns.length < 1) {
1249
- validationErrors.push(`designIntent.designExecutionHandoff.viewportMutationPlan.${viewportKey}.forbiddenPatterns must contain at least one anti-pattern.`);
1250
- }
1251
- if (!String(viewportPlan.rationale || '').trim()) {
1252
- validationErrors.push(`designIntent.designExecutionHandoff.viewportMutationPlan.${viewportKey}.rationale must be a non-empty string.`);
1253
- }
1254
- }
1255
- }
1256
- if (!Array.isArray(designIntentContract.designExecutionHandoff.interactionStateMatrix) || designIntentContract.designExecutionHandoff.interactionStateMatrix.length < 1) {
1257
- validationErrors.push('designIntent.designExecutionHandoff.interactionStateMatrix must list key component state expectations.');
1258
- }
1259
- if (!Array.isArray(designIntentContract.designExecutionHandoff.taskFlowNarrative) || designIntentContract.designExecutionHandoff.taskFlowNarrative.length < 2) {
1260
- validationErrors.push('designIntent.designExecutionHandoff.taskFlowNarrative must describe the key UI task flow in sequence.');
1261
- }
1262
- if (!String(designIntentContract.designExecutionHandoff.signatureMoveRationale || '').trim()) {
1263
- validationErrors.push('designIntent.designExecutionHandoff.signatureMoveRationale must explain the chosen authored move.');
1264
- }
1265
- const creativeCommitment = designIntentContract.designExecutionHandoff.creativeCommitment;
1266
- if (!creativeCommitment || typeof creativeCommitment !== 'object') {
1267
- validationErrors.push('designIntent.designExecutionHandoff.creativeCommitment must exist.');
1268
- } else {
1269
- if (creativeCommitment.status !== 'agent-must-complete-before-ui-implementation') {
1270
- validationErrors.push('designIntent.designExecutionHandoff.creativeCommitment.status must equal "agent-must-complete-before-ui-implementation".');
1271
- }
1272
- if (
1273
- !Array.isArray(creativeCommitment.requiredFields)
1274
- || !creativeCommitment.requiredFields.includes('specificReferencePoint')
1275
- || !creativeCommitment.requiredFields.includes('signatureMotion')
1276
- || !creativeCommitment.requiredFields.includes('typographicDecision')
1277
- ) {
1278
- validationErrors.push('designIntent.designExecutionHandoff.creativeCommitment.requiredFields must include specificReferencePoint, signatureMotion, and typographicDecision.');
1279
- }
1280
- if (!hasNonEmptyString(creativeCommitment.failureMode)) {
1281
- validationErrors.push('designIntent.designExecutionHandoff.creativeCommitment.failureMode must be a non-empty string.');
1282
- }
1283
- }
1284
- const implementationGuardrails = designIntentContract.designExecutionHandoff.implementationGuardrails;
1285
- if (!implementationGuardrails || typeof implementationGuardrails !== 'object') {
1286
- validationErrors.push('designIntent.designExecutionHandoff.implementationGuardrails must exist.');
1287
- } else {
1288
- for (const requiredFlagName of [
1289
- 'requireBuildFromHandoff',
1290
- 'requireGapNotesBeforeFallback',
1291
- 'forbidGenericLayoutFallbackWithoutReason',
1292
- ]) {
1293
- if (implementationGuardrails[requiredFlagName] !== true) {
1294
- validationErrors.push(`designIntent.designExecutionHandoff.implementationGuardrails.${requiredFlagName} must equal true.`);
1295
- }
1296
- }
1297
- }
1298
- }
1299
-
1300
- if (!designIntentContract.reviewRubric || typeof designIntentContract.reviewRubric !== 'object') {
1301
- validationErrors.push('designIntent.reviewRubric must exist.');
1302
- } else {
1303
- if (designIntentContract.reviewRubric.version !== 'ui-rubric-v1') {
1304
- validationErrors.push('designIntent.reviewRubric.version must equal "ui-rubric-v1".');
1305
- }
1306
- if (designIntentContract.reviewRubric.genericityAutoFail !== true) {
1307
- validationErrors.push('designIntent.reviewRubric.genericityAutoFail must equal true.');
1308
- }
1309
- if (!Array.isArray(designIntentContract.reviewRubric.dimensions) || designIntentContract.reviewRubric.dimensions.length < 5) {
1310
- validationErrors.push('designIntent.reviewRubric.dimensions must define the required rubric dimensions.');
1311
- } else {
1312
- for (const requiredRubricKey of [
1313
- 'distinctiveness',
1314
- 'contractFidelity',
1315
- 'visualConsistency',
1316
- 'heuristicUxQuality',
1317
- 'motionDiscipline',
1318
- ]) {
1319
- if (!designIntentContract.reviewRubric.dimensions.some((dimension) => dimension?.key === requiredRubricKey)) {
1320
- validationErrors.push(`designIntent.reviewRubric.dimensions is missing "${requiredRubricKey}".`);
1321
- }
1322
- }
1323
- }
1324
- if (!Array.isArray(designIntentContract.reviewRubric.genericitySignals) || designIntentContract.reviewRubric.genericitySignals.length < 3) {
1325
- validationErrors.push('designIntent.reviewRubric.genericitySignals must list common genericity drift signals.');
1326
- } else {
1327
- for (const requiredSignal of [
1328
- 'ai-safe-ui-template-look',
1329
- 'interchangeable-product-renaming-test-fails',
1330
- 'decorative-grid-or-glow-wallpaper-without-product-function',
1331
- ]) {
1332
- if (!designIntentContract.reviewRubric.genericitySignals.includes(requiredSignal)) {
1333
- validationErrors.push(`designIntent.reviewRubric.genericitySignals must include "${requiredSignal}".`);
1334
- }
1335
- }
1336
- }
1337
- if (!Array.isArray(designIntentContract.reviewRubric.validBoldSignals) || designIntentContract.reviewRubric.validBoldSignals.length < 3) {
1338
- validationErrors.push('designIntent.reviewRubric.validBoldSignals must list legitimate authored signals.');
1339
- } else {
1340
- for (const requiredSignal of [
1341
- 'three-at-a-glance-product-specific-signals',
1342
- 'visually-exploratory-accessible-palette-derived-from-product',
1343
- ]) {
1344
- if (!designIntentContract.reviewRubric.validBoldSignals.includes(requiredSignal)) {
1345
- validationErrors.push(`designIntent.reviewRubric.validBoldSignals must include "${requiredSignal}".`);
1346
- }
1347
- }
1348
- }
1349
- if (!designIntentContract.reviewRubric.reportingRules || typeof designIntentContract.reviewRubric.reportingRules !== 'object') {
1350
- validationErrors.push('designIntent.reviewRubric.reportingRules must exist.');
1351
- } else {
1352
- for (const requiredFlagName of [
1353
- 'mustExplainGenericity',
1354
- 'mustSeparateTasteFromFailure',
1355
- 'contractFidelityOverridesPersonalTaste',
1356
- ]) {
1357
- if (designIntentContract.reviewRubric.reportingRules[requiredFlagName] !== true) {
1358
- validationErrors.push(`designIntent.reviewRubric.reportingRules.${requiredFlagName} must equal true.`);
1359
- }
1360
- }
1361
- }
1362
- }
1363
-
1364
- if (!Array.isArray(designIntentContract.requiredDesignSections) || designIntentContract.requiredDesignSections.length !== DESIGN_REQUIRED_SECTIONS.length) {
1365
- validationErrors.push('designIntent.requiredDesignSections must match the required design contract sections.');
1366
- } else {
1367
- for (const requiredSectionName of DESIGN_REQUIRED_SECTIONS) {
1368
- if (!designIntentContract.requiredDesignSections.includes(requiredSectionName)) {
1369
- validationErrors.push(`designIntent.requiredDesignSections is missing "${requiredSectionName}".`);
1370
- }
1371
- }
1372
- }
1373
-
1374
- if (!Array.isArray(designIntentContract.forbiddenPatterns) || designIntentContract.forbiddenPatterns.length < 4) {
1375
- validationErrors.push('designIntent.forbiddenPatterns must list concrete anti-generic patterns.');
1376
- } else {
1377
- for (const requiredPattern of [
1378
- 'ai-safe-ui-template-look',
1379
- 'interchangeable-product-renaming-test-fails',
1380
- 'decorative-grid-or-glow-wallpaper-without-product-function',
1381
- ]) {
1382
- if (!designIntentContract.forbiddenPatterns.includes(requiredPattern)) {
1383
- validationErrors.push(`designIntent.forbiddenPatterns must include "${requiredPattern}".`);
1384
- }
1385
- }
1386
- }
1387
-
1388
- return validationErrors;
1389
- }
665
+ export { validateDesignContractCompleteness, validateDesignIntentContract } from './design-contract/validation.mjs';
1390
666
 
1391
667
  export function buildDesignIntentSeedFromSignals({
1392
668
  projectName,