@ryuenn3123/agentic-senior-core 3.0.17 → 3.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent-context/prompts/bootstrap-design.md +16 -7
- package/.agent-context/rules/frontend-architecture.md +5 -5
- package/.agent-context/state/memory-continuity-benchmark.json +1 -1
- package/.cursorrules +1 -1
- package/.gemini/instructions.md +1 -1
- package/.github/copilot-instructions.md +1 -1
- package/.instructions.md +1 -1
- package/.windsurfrules +1 -1
- package/AGENTS.md +1 -1
- package/lib/cli/project-scaffolder/design-contract.mjs +363 -314
- package/lib/cli/project-scaffolder/prompt-builders.mjs +28 -22
- package/lib/cli/project-scaffolder/storage.mjs +0 -2
- package/package.json +2 -2
- package/scripts/frontend-usability-audit.mjs +19 -8
- package/scripts/mcp-server/constants.mjs +60 -0
- package/scripts/mcp-server/tool-registry.mjs +149 -0
- package/scripts/mcp-server/tools.mjs +446 -0
- package/scripts/mcp-server.mjs +23 -661
- package/scripts/release-gate/audit-checks.mjs +426 -0
- package/scripts/release-gate/constants.mjs +53 -0
- package/scripts/release-gate/runtime.mjs +63 -0
- package/scripts/release-gate/static-checks.mjs +182 -0
- package/scripts/release-gate.mjs +12 -793
- package/scripts/ui-design-judge/constants.mjs +24 -0
- package/scripts/ui-design-judge/design-execution-summary.mjs +233 -0
- package/scripts/ui-design-judge/git-input.mjs +131 -0
- package/scripts/ui-design-judge/prompting.mjs +73 -0
- package/scripts/ui-design-judge/providers.mjs +102 -0
- package/scripts/ui-design-judge/reporting.mjs +181 -0
- package/scripts/ui-design-judge/rubric-calibration.mjs +211 -0
- package/scripts/ui-design-judge/rubric-goldset.json +188 -0
- package/scripts/ui-design-judge.mjs +105 -774
- package/scripts/ui-rubric-calibration.mjs +35 -0
- package/scripts/validate/config.mjs +69 -16
|
@@ -29,174 +29,58 @@ export function shouldBootstrapDesignDocument(discoveryAnswers, initContext) {
|
|
|
29
29
|
return false;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
function
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
],
|
|
54
|
-
motionPurpose: 'Use motion to reinforce buying confidence, product continuity, and premium delight. It may be theatrical at key moments if it stays fast, legible, and supportive of decision-making.',
|
|
55
|
-
motionChoreography: 'Favor fast hover and focus feedback, confident sheet choreography, product-media continuity, and one or two signature reveal moments. Avoid autoplay spectacle that distracts from purchase decisions.',
|
|
56
|
-
motionDurations: {
|
|
57
|
-
desktop: 180,
|
|
58
|
-
mobile: 240,
|
|
59
|
-
},
|
|
60
|
-
componentMorphology: {
|
|
61
|
-
mobile: 'Product cards should compress supporting metadata, pin purchase actions closer to the thumb zone, and move comparison into progressive disclosure or bottom sheets.',
|
|
62
|
-
tablet: 'Cards and merch modules should preserve comparison affordances while reducing tertiary chrome and keeping visual hierarchy stable.',
|
|
63
|
-
desktop: 'Cards can expand media, comparison, and reassurance copy while keeping buying cues dominant and visually disciplined.',
|
|
64
|
-
},
|
|
65
|
-
mutationRules: {
|
|
66
|
-
mobile: 'Convert browsing into vertically stacked product cards, move cart and filter actions into sticky or bottom-sheet patterns, and keep thumb-reach actions persistent.',
|
|
67
|
-
tablet: 'Preserve browsing flow with a two-column rhythm, collapse tertiary filters, and keep comparison moments visible without forcing desktop density.',
|
|
68
|
-
desktop: 'Expose multi-column merchandising, comparison views, and richer product context while keeping the purchase path visually dominant.',
|
|
69
|
-
},
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (aggregateText.includes('dashboard') || aggregateText.includes('operations') || aggregateText.includes('report')) {
|
|
74
|
-
return {
|
|
75
|
-
designPhilosophy: 'Operational calm under high information density.',
|
|
76
|
-
brandAdjectives: ['calm', 'precise', 'trustworthy'],
|
|
77
|
-
antiAdjectives: ['chaotic', 'gimmicky', 'visually exhausting'],
|
|
78
|
-
typographyScaleRatio: '1.125',
|
|
79
|
-
baseGridUnit: 4,
|
|
80
|
-
densityMode: 'high-density-scanning',
|
|
81
|
-
colorIntent: 'Use neutrals for structure and reserve accent saturation for status shifts, risky actions, and alerts.',
|
|
82
|
-
distinctiveMoves: [
|
|
83
|
-
'Prioritize scanning clarity and status recognition over decorative density.',
|
|
84
|
-
'Use visual weight to separate signal from operational noise.',
|
|
85
|
-
'Reserve strong accents for alerts, decisions, and state transitions only.',
|
|
86
|
-
],
|
|
87
|
-
motionPurpose: 'Use motion as operational feedback and state continuity, while still allowing decisive state transitions that make dense workflows feel alive and controlled.',
|
|
88
|
-
motionChoreography: 'Prefer fast transitions for filters, drawers, status reveals, and row expansion, but allow strong confirmation moments when they improve confidence and scan clarity.',
|
|
89
|
-
motionDurations: {
|
|
90
|
-
desktop: 160,
|
|
91
|
-
mobile: 220,
|
|
92
|
-
},
|
|
93
|
-
componentMorphology: {
|
|
94
|
-
mobile: 'Data rows should become prioritized cards or grouped summaries, with filters and secondary tools moving into sheets or drawers.',
|
|
95
|
-
tablet: 'Operational panels should retain split-view logic where possible, while tertiary panels collapse behind explicit toggles.',
|
|
96
|
-
desktop: 'Dense tables, side panels, and comparison surfaces can remain visible simultaneously, with state treatments optimized for rapid scanning.',
|
|
97
|
-
},
|
|
98
|
-
mutationRules: {
|
|
99
|
-
mobile: 'Collapse dense tables into prioritized cards or row groups, move filters into drawers or sheets, and pin the most critical actions to the bottom reach zone.',
|
|
100
|
-
tablet: 'Keep two-column or split-pane workflows, collapse tertiary panels, and maintain fast scan paths for operators using touch or keyboard.',
|
|
101
|
-
desktop: 'Expose the highest-density views with visible navigation, comparison surfaces, and simultaneous context panels for power users.',
|
|
102
|
-
},
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (aggregateText.includes('developer') || aggregateText.includes('api') || aggregateText.includes('platform')) {
|
|
107
|
-
return {
|
|
108
|
-
designPhilosophy: 'Technical precision with explicit structure and honest feedback.',
|
|
109
|
-
brandAdjectives: ['precise', 'technical', 'transparent'],
|
|
110
|
-
antiAdjectives: ['vague', 'marketing-heavy', 'template-polished'],
|
|
111
|
-
typographyScaleRatio: '1.125',
|
|
112
|
-
baseGridUnit: 4,
|
|
113
|
-
densityMode: 'technical-utility',
|
|
114
|
-
colorIntent: 'Anchor the interface in disciplined neutrals and use accent color only where state, feedback, or code-adjacent interaction needs emphasis.',
|
|
115
|
-
distinctiveMoves: [
|
|
116
|
-
'Make structure and feedback feel exact without becoming sterile.',
|
|
117
|
-
'Use code-adjacent rhythm and hierarchy to build trust with technical users.',
|
|
118
|
-
'Keep complexity legible through spacing, grouping, and explicit interaction states.',
|
|
119
|
-
],
|
|
120
|
-
motionPurpose: 'Use motion to clarify causality, reveal system state, preserve context, and give technical workflows a sense of precision instead of dead stillness.',
|
|
121
|
-
motionChoreography: 'Prefer sharp panel transitions, command feedback, disclosure motion, and occasional signature transitions that feel exact rather than ornamental.',
|
|
122
|
-
motionDurations: {
|
|
123
|
-
desktop: 170,
|
|
124
|
-
mobile: 230,
|
|
125
|
-
},
|
|
126
|
-
componentMorphology: {
|
|
127
|
-
mobile: 'Technical panes should flatten into sequential sections, with commands and diagnostics colocated near the content they affect.',
|
|
128
|
-
tablet: 'Split views should survive where useful, with explicit panel toggles and condensed chrome for code-adjacent tasks.',
|
|
129
|
-
desktop: 'Navigation, documentation, diagnostics, and active work surfaces can remain concurrently visible when it improves expert comprehension.',
|
|
130
|
-
},
|
|
131
|
-
mutationRules: {
|
|
132
|
-
mobile: 'Switch multi-pane technical layouts into stacked sections, turn secondary navigation into segmented or sheet-based controls, and keep commands near the content they affect.',
|
|
133
|
-
tablet: 'Retain split-view comprehension where possible, compress chrome, and keep documentation or diagnostics adjacent to the active task.',
|
|
134
|
-
desktop: 'Expose full navigation, dense comparison surfaces, and multi-pane workflows for expert scanning and debugging.',
|
|
135
|
-
},
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (aggregateText.includes('content') || aggregateText.includes('community') || aggregateText.includes('publish')) {
|
|
140
|
-
return {
|
|
141
|
-
designPhilosophy: 'Editorial flow with warm but controlled expression.',
|
|
142
|
-
brandAdjectives: ['editorial', 'warm', 'expressive'],
|
|
143
|
-
antiAdjectives: ['flat', 'anonymous', 'feed-generic'],
|
|
144
|
-
typographyScaleRatio: '1.200',
|
|
145
|
-
baseGridUnit: 8,
|
|
146
|
-
densityMode: 'reading-first',
|
|
147
|
-
colorIntent: 'Let typography and surface contrast lead while chroma supports hierarchy and key participation actions.',
|
|
148
|
-
distinctiveMoves: [
|
|
149
|
-
'Build a strong reading rhythm so content feels curated rather than dumped into cards.',
|
|
150
|
-
'Use contrast and spacing to guide attention between creation, moderation, and discovery.',
|
|
151
|
-
'Give key interaction moments personality without sacrificing clarity.',
|
|
152
|
-
],
|
|
153
|
-
motionPurpose: 'Use motion to support reading rhythm, reveal structure, and reward contribution moments with visible craft, not generic restraint.',
|
|
154
|
-
motionChoreography: 'Favor reveal choreography for section transitions, expressive but measured feedback on participation, and media behavior that feels alive without becoming noisy.',
|
|
155
|
-
motionDurations: {
|
|
156
|
-
desktop: 190,
|
|
157
|
-
mobile: 250,
|
|
158
|
-
},
|
|
159
|
-
componentMorphology: {
|
|
160
|
-
mobile: 'Reading surfaces should dominate while secondary discovery and community tools collapse behind sheets, tabs, or segmented controls.',
|
|
161
|
-
tablet: 'Editorial modules can balance reading and discovery, provided the primary narrative flow remains obvious.',
|
|
162
|
-
desktop: 'Long-form content, secondary navigation, and related discovery modules can coexist without fragmenting the reading rhythm.',
|
|
163
|
-
},
|
|
164
|
-
mutationRules: {
|
|
165
|
-
mobile: 'Prioritize reading and contribution flows in a single-column narrative stack, tuck secondary discovery tools behind sheets, and keep primary creation actions within reach.',
|
|
166
|
-
tablet: 'Balance narrative reading with supporting discovery modules, using two-column compositions only where hierarchy stays obvious.',
|
|
167
|
-
desktop: 'Use wider editorial compositions, visible secondary navigation, and modular discovery surfaces without breaking reading rhythm.',
|
|
168
|
-
},
|
|
169
|
-
};
|
|
170
|
-
}
|
|
32
|
+
function buildStructureFirstSeedSignals({
|
|
33
|
+
projectName,
|
|
34
|
+
projectDescription,
|
|
35
|
+
primaryDomain,
|
|
36
|
+
supplementalFields = {},
|
|
37
|
+
}) {
|
|
38
|
+
const normalizedDescription = String(projectDescription || '').trim();
|
|
39
|
+
const normalizedDomain = String(primaryDomain || '').trim().toLowerCase();
|
|
40
|
+
const repoEvidenceSummary = supplementalFields?.repoEvidence?.designEvidenceSummary || null;
|
|
41
|
+
const hasRepoEvidence = Boolean(
|
|
42
|
+
repoEvidenceSummary
|
|
43
|
+
|| (Array.isArray(supplementalFields?.repoEvidence?.workspaceUiEntries)
|
|
44
|
+
&& supplementalFields.repoEvidence.workspaceUiEntries.length > 0)
|
|
45
|
+
);
|
|
46
|
+
const evidenceSourceLabel = hasRepoEvidence
|
|
47
|
+
? 'current repo evidence, existing UI code, and the active brief'
|
|
48
|
+
: 'the active brief and any repo evidence available at synthesis time';
|
|
49
|
+
const projectContextLabel = normalizedDescription
|
|
50
|
+
? `the product context "${normalizedDescription}"`
|
|
51
|
+
: 'the current product context';
|
|
52
|
+
const isMobileLikeSurface = normalizedDomain.includes('mobile');
|
|
171
53
|
|
|
172
54
|
return {
|
|
173
|
-
designPhilosophy:
|
|
174
|
-
brandAdjectives: ['
|
|
175
|
-
antiAdjectives: ['
|
|
55
|
+
designPhilosophy: `Use ${evidenceSourceLabel} to synthesize a project-specific design system for ${projectName || 'this project'}. Treat this seed as structural scaffolding that must be refined before UI implementation, not as final art direction.`,
|
|
56
|
+
brandAdjectives: ['project-specific', 'intentional', 'evidence-led'],
|
|
57
|
+
antiAdjectives: ['template-neutral', 'copycat', 'unjustified-defaults'],
|
|
176
58
|
typographyScaleRatio: '1.200',
|
|
177
59
|
baseGridUnit: 8,
|
|
178
|
-
|
|
179
|
-
|
|
60
|
+
spacingPattern: isMobileLikeSurface ? 'mobile-first-single-axis' : 'adaptive-task-priority',
|
|
61
|
+
densityMode: isMobileLikeSurface ? 'touch-priority' : 'adaptive-task-priority',
|
|
62
|
+
colorIntent: `Define palette roles from ${projectContextLabel} and refine them with repo evidence. Treat the listed palette roles as minimum semantic categories, not final visual choices.`,
|
|
63
|
+
paletteRoles: ['base', 'surface', 'text', 'muted', 'accent', 'border', 'focus', 'success', 'warning', 'danger'],
|
|
180
64
|
distinctiveMoves: [
|
|
181
|
-
'
|
|
182
|
-
'Use
|
|
183
|
-
'
|
|
65
|
+
'Derive one memorable signature move from the product task, current repo evidence, and the active brief before locking the layout language.',
|
|
66
|
+
'Use task priority, hierarchy, and surface relationships to replace template-neutral hero or card-grid defaults.',
|
|
67
|
+
'Document why the final visual move belongs to this project and what generic fallback it intentionally avoids.',
|
|
184
68
|
],
|
|
185
|
-
motionPurpose: '
|
|
186
|
-
motionChoreography: '
|
|
69
|
+
motionPurpose: 'Use motion to clarify causality, hierarchy, state feedback, and perceived product quality. The final motion tone must be refined from repo evidence and the active brief, not inherited from this seed alone.',
|
|
70
|
+
motionChoreography: 'Keep motion purposeful, reduced-motion-safe, and tied to state or surface changes. Any signature choreography must be justified in docs/DESIGN.md before it becomes part of the system.',
|
|
187
71
|
motionDurations: {
|
|
188
72
|
desktop: 180,
|
|
189
73
|
mobile: 240,
|
|
190
74
|
},
|
|
191
75
|
componentMorphology: {
|
|
192
|
-
mobile: '
|
|
193
|
-
tablet: '
|
|
194
|
-
desktop: '
|
|
76
|
+
mobile: 'Simplify the primary task surface, keep decisive actions in easy reach, and move supporting context behind explicit disclosure when space gets tight.',
|
|
77
|
+
tablet: 'Preserve task continuity while compressing tertiary chrome and keeping priority boundaries obvious across shared surfaces.',
|
|
78
|
+
desktop: 'Expose the richest version of the task flow and supporting context without defaulting to symmetrical template composition.',
|
|
195
79
|
},
|
|
196
80
|
mutationRules: {
|
|
197
|
-
mobile: '
|
|
198
|
-
tablet: 'Preserve
|
|
199
|
-
desktop: 'Expose the
|
|
81
|
+
mobile: 'Recompose the flow around the first decisive action, collapse secondary navigation into explicit overlays or sheets, and re-rank supporting context below the primary task.',
|
|
82
|
+
tablet: 'Preserve task continuity with fewer simultaneous surfaces, condensed chrome, and explicit boundaries between primary, supporting, and deferred content.',
|
|
83
|
+
desktop: 'Expose the fullest version of the task flow, supporting context, and navigation system without falling back to interchangeable dashboard or hero defaults.',
|
|
200
84
|
},
|
|
201
85
|
};
|
|
202
86
|
}
|
|
@@ -207,27 +91,26 @@ function buildDesignIntentContractObject({
|
|
|
207
91
|
primaryDomain,
|
|
208
92
|
features = [],
|
|
209
93
|
initContext,
|
|
210
|
-
architectureRecommendation = null,
|
|
211
94
|
status = 'seed-needs-design-synthesis',
|
|
212
95
|
supplementalFields = {},
|
|
213
96
|
}) {
|
|
214
|
-
const inferredKeywords =
|
|
97
|
+
const inferredKeywords = buildStructureFirstSeedSignals({
|
|
98
|
+
projectName,
|
|
215
99
|
projectDescription,
|
|
216
100
|
primaryDomain,
|
|
217
101
|
features,
|
|
102
|
+
supplementalFields,
|
|
218
103
|
});
|
|
219
|
-
const normalizedPrimaryDomain = String(primaryDomain || '').trim().toLowerCase();
|
|
220
|
-
const resolvedSpacingPattern = inferredKeywords.densityMode === 'dense'
|
|
221
|
-
? 'compact-grid'
|
|
222
|
-
: normalizedPrimaryDomain.includes('mobile')
|
|
223
|
-
? 'mobile-first-single-axis'
|
|
224
|
-
: inferredKeywords.densityMode === 'focused'
|
|
225
|
-
? 'high-contrast-rhythm'
|
|
226
|
-
: 'balanced-grid';
|
|
227
104
|
|
|
228
105
|
return {
|
|
229
106
|
mode: 'dynamic',
|
|
230
107
|
status,
|
|
108
|
+
seedPolicy: {
|
|
109
|
+
mode: 'structure-first-scaffold',
|
|
110
|
+
requiresProjectSpecificRefinement: true,
|
|
111
|
+
forbidLiteralCarryoverAsFinalArtDirection: true,
|
|
112
|
+
repoEvidenceShouldOverrideSeedTaste: true,
|
|
113
|
+
},
|
|
231
114
|
project: {
|
|
232
115
|
name: projectName,
|
|
233
116
|
context: projectDescription,
|
|
@@ -239,6 +122,8 @@ function buildDesignIntentContractObject({
|
|
|
239
122
|
brandAdjectives: inferredKeywords.brandAdjectives,
|
|
240
123
|
antiAdjectives: inferredKeywords.antiAdjectives,
|
|
241
124
|
visualDirection: {
|
|
125
|
+
seedMode: 'scaffold-only',
|
|
126
|
+
requiresProjectSpecificSynthesis: true,
|
|
242
127
|
trendStance: 'trend-aware-not-trend-chasing',
|
|
243
128
|
distinctiveMoves: inferredKeywords.distinctiveMoves,
|
|
244
129
|
copiedReferenceAllowed: false,
|
|
@@ -246,8 +131,9 @@ function buildDesignIntentContractObject({
|
|
|
246
131
|
mathSystems: {
|
|
247
132
|
typographyScaleRatio: inferredKeywords.typographyScaleRatio,
|
|
248
133
|
baseGridUnit: inferredKeywords.baseGridUnit,
|
|
249
|
-
spacingPattern:
|
|
134
|
+
spacingPattern: inferredKeywords.spacingPattern,
|
|
250
135
|
densityMode: inferredKeywords.densityMode,
|
|
136
|
+
seedValuesRequireCalibration: true,
|
|
251
137
|
},
|
|
252
138
|
tokenSystem: {
|
|
253
139
|
sourceOfTruth: 'docs/design-intent.json',
|
|
@@ -280,7 +166,9 @@ function buildDesignIntentContractObject({
|
|
|
280
166
|
format: 'OKLCH',
|
|
281
167
|
allowHexDerivatives: true,
|
|
282
168
|
requirePerceptualLightnessCurve: true,
|
|
283
|
-
paletteRoles:
|
|
169
|
+
paletteRoles: inferredKeywords.paletteRoles,
|
|
170
|
+
rolePolicy: 'minimum-semantic-scaffold',
|
|
171
|
+
rolesAreMinimumScaffold: true,
|
|
284
172
|
intent: inferredKeywords.colorIntent,
|
|
285
173
|
},
|
|
286
174
|
crossViewportAdaptation: {
|
|
@@ -294,6 +182,7 @@ function buildDesignIntentContractObject({
|
|
|
294
182
|
choreography: inferredKeywords.motionChoreography,
|
|
295
183
|
desktopDurationMs: inferredKeywords.motionDurations.desktop,
|
|
296
184
|
mobileDurationMs: inferredKeywords.motionDurations.mobile,
|
|
185
|
+
seedToneLocked: false,
|
|
297
186
|
respectReducedMotion: true,
|
|
298
187
|
preferTransformAndOpacity: true,
|
|
299
188
|
avoidDecorativeMotionForItsOwnSake: true,
|
|
@@ -301,6 +190,7 @@ function buildDesignIntentContractObject({
|
|
|
301
190
|
componentMorphology: {
|
|
302
191
|
requireStateBehaviorMatrix: true,
|
|
303
192
|
preserveIdentityAcrossViewports: true,
|
|
193
|
+
seedBehaviorsRequireRefinement: true,
|
|
304
194
|
stateKeys: ['default', 'hover', 'focus', 'active', 'disabled', 'loading', 'error'],
|
|
305
195
|
viewportBehavior: inferredKeywords.componentMorphology,
|
|
306
196
|
},
|
|
@@ -327,51 +217,177 @@ function buildDesignIntentContractObject({
|
|
|
327
217
|
typographyReadabilityTuning: true,
|
|
328
218
|
},
|
|
329
219
|
},
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
220
|
+
designExecutionPolicy: {
|
|
221
|
+
representationStrategy: 'surface-plan-v1',
|
|
222
|
+
seedRefinementRequiredBeforeUiImplementation: true,
|
|
223
|
+
requireSurfacePlan: true,
|
|
224
|
+
requireComponentGraph: true,
|
|
225
|
+
requireViewportMutationPlan: true,
|
|
226
|
+
requireInteractionStateMatrix: true,
|
|
227
|
+
requireContentPriorityMap: true,
|
|
228
|
+
requireTaskFlowNarrative: true,
|
|
229
|
+
requireSignatureMoveRationale: true,
|
|
230
|
+
requireStructuredHandoff: true,
|
|
231
|
+
requireRepoEvidenceAlignment: true,
|
|
232
|
+
forbidScreenshotDependency: true,
|
|
233
|
+
handoffFormatVersion: 'ui-handoff-v1',
|
|
234
|
+
semanticReviewFocus: [
|
|
235
|
+
'distinctiveness-vs-genericity',
|
|
236
|
+
'contract-fidelity',
|
|
237
|
+
'hierarchy-and-task-priority',
|
|
238
|
+
'component-state-behavior',
|
|
239
|
+
'cross-viewport-mutation',
|
|
240
|
+
],
|
|
241
|
+
},
|
|
242
|
+
designExecutionHandoff: {
|
|
243
|
+
version: 'ui-handoff-v1',
|
|
244
|
+
location: 'inline-design-intent',
|
|
245
|
+
status: 'seed-needs-refinement',
|
|
246
|
+
seedMode: 'structure-first-scaffold',
|
|
247
|
+
requiresTaskSpecificRefinement: true,
|
|
248
|
+
primaryExperienceGoal: `Refine the main ${String(primaryDomain || 'product').toLowerCase()} journey in ${projectName} so the first decisive action, supporting context, and signature move come from repo evidence and the active brief rather than scaffold defaults.`,
|
|
249
|
+
surfacePlan: [
|
|
250
|
+
{
|
|
251
|
+
surfaceId: 'primary-entry-surface',
|
|
252
|
+
role: 'primary-task-entry',
|
|
253
|
+
goal: `Map the first meaningful task in ${projectName} and replace generic hero filler with task-first hierarchy justified by repo evidence and the active brief.`,
|
|
254
|
+
primaryAction: 'Define the first decisive action or decision point explicitly during refinement instead of inheriting placeholder CTA language.',
|
|
255
|
+
supportingModules: ['context', 'proof', 'navigation'],
|
|
256
|
+
signatureMoveHint: 'Document one project-specific signature move for the primary surface and explain which generic fallback it intentionally rejects.',
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
surfaceId: 'supporting-proof-surface',
|
|
260
|
+
role: 'trust-and-context',
|
|
261
|
+
goal: 'Define how proof, explanation, or operational context supports the main task without turning the layout into a template-neutral secondary rail.',
|
|
262
|
+
primaryAction: 'Clarify what supporting proof or status belongs near the main task once the product-specific flow is confirmed.',
|
|
263
|
+
supportingModules: ['status', 'metadata', 'secondary-actions'],
|
|
264
|
+
signatureMoveHint: 'Explain how this supporting surface reinforces the primary task without competing for dominance or collapsing into generic chrome.',
|
|
265
|
+
},
|
|
266
|
+
],
|
|
267
|
+
componentGraph: {
|
|
268
|
+
nodes: [
|
|
269
|
+
{
|
|
270
|
+
id: 'primary-action-surface',
|
|
271
|
+
role: 'task-driver',
|
|
272
|
+
priority: 'high',
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
id: 'supporting-context-rail',
|
|
276
|
+
role: 'context-support',
|
|
277
|
+
priority: 'medium',
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
id: 'feedback-status-module',
|
|
281
|
+
role: 'feedback-and-proof',
|
|
282
|
+
priority: 'medium',
|
|
283
|
+
},
|
|
284
|
+
],
|
|
285
|
+
edges: [
|
|
286
|
+
{
|
|
287
|
+
from: 'primary-action-surface',
|
|
288
|
+
to: 'supporting-context-rail',
|
|
289
|
+
relationship: 'context-support',
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
from: 'primary-action-surface',
|
|
293
|
+
to: 'feedback-status-module',
|
|
294
|
+
relationship: 'state-feedback',
|
|
295
|
+
},
|
|
347
296
|
],
|
|
348
297
|
},
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
'
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
'
|
|
357
|
-
'
|
|
298
|
+
contentPriorityMap: {
|
|
299
|
+
primary: [
|
|
300
|
+
'core-task-entry',
|
|
301
|
+
'primary-status-or-value-message',
|
|
302
|
+
'decisive-action-labeling',
|
|
303
|
+
],
|
|
304
|
+
secondary: [
|
|
305
|
+
'supporting-proof',
|
|
306
|
+
'navigation-context',
|
|
307
|
+
'secondary-actions',
|
|
308
|
+
],
|
|
309
|
+
deferred: [
|
|
310
|
+
'deep-explanation',
|
|
311
|
+
'tertiary-metadata',
|
|
312
|
+
'low-priority-decoration',
|
|
358
313
|
],
|
|
359
314
|
},
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
315
|
+
viewportMutationPlan: {
|
|
316
|
+
mobile: inferredKeywords.mutationRules.mobile,
|
|
317
|
+
tablet: inferredKeywords.mutationRules.tablet,
|
|
318
|
+
desktop: inferredKeywords.mutationRules.desktop,
|
|
364
319
|
},
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
320
|
+
interactionStateMatrix: [
|
|
321
|
+
{
|
|
322
|
+
componentId: 'primary-action-control',
|
|
323
|
+
states: ['default', 'hover', 'focus', 'loading', 'success', 'error'],
|
|
324
|
+
notes: 'Refine these states with project-specific feedback language and visual treatment, but keep them legible, decisive, and consistent across all supported viewports.',
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
componentId: 'primary-content-module',
|
|
328
|
+
states: ['default', 'focus', 'expanded', 'loading', 'error'],
|
|
329
|
+
notes: 'Refine this module so it preserves hierarchy and progressive disclosure without collapsing into anonymous cards or safe default dashboard panels.',
|
|
330
|
+
},
|
|
331
|
+
],
|
|
332
|
+
taskFlowNarrative: [
|
|
333
|
+
`Entry: refine how ${projectName} establishes the first meaningful action using current task evidence instead of generic product-marketing framing.`,
|
|
334
|
+
'Decision: define the hierarchy, proof, and state language that help the user choose the next step without defaulting to generic card-grid or hero habits.',
|
|
335
|
+
'Resolution: specify the feedback, recovery path, and next useful action so progress remains visible without hiding behind decorative confirmation states.',
|
|
336
|
+
],
|
|
337
|
+
signatureMoveRationale: 'Explain which project-specific surface, motion, typographic, or compositional move anchors the system and why a generic fallback would weaken the product.',
|
|
338
|
+
implementationGuardrails: {
|
|
339
|
+
requireBuildFromHandoff: true,
|
|
340
|
+
requireGapNotesBeforeFallback: true,
|
|
341
|
+
forbidGenericLayoutFallbackWithoutReason: true,
|
|
370
342
|
},
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
343
|
+
},
|
|
344
|
+
reviewRubric: {
|
|
345
|
+
version: 'ui-rubric-v1',
|
|
346
|
+
dimensions: [
|
|
347
|
+
{
|
|
348
|
+
key: 'distinctiveness',
|
|
349
|
+
blockingByDefault: false,
|
|
350
|
+
question: 'Does the UI feel authored and project-specific rather than like a default framework or template kit?',
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
key: 'contractFidelity',
|
|
354
|
+
blockingByDefault: true,
|
|
355
|
+
question: 'Does the changed UI still follow the explicit design contract, interaction priorities, and accessibility boundaries?',
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
key: 'visualConsistency',
|
|
359
|
+
blockingByDefault: false,
|
|
360
|
+
question: 'Do typography, spacing, color usage, and component behaviors still feel like one system?',
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
key: 'heuristicUxQuality',
|
|
364
|
+
blockingByDefault: false,
|
|
365
|
+
question: 'Does the UI preserve task clarity, feedback quality, and user confidence in the touched flows?',
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
key: 'motionDiscipline',
|
|
369
|
+
blockingByDefault: false,
|
|
370
|
+
question: 'If motion is present, does it stay purposeful, performant, reduced-motion-safe, and consistent with the product tone?',
|
|
371
|
+
},
|
|
372
|
+
],
|
|
373
|
+
genericitySignals: [
|
|
374
|
+
'safe-centered-hero-without-product-rationale',
|
|
375
|
+
'balanced-card-grid-without-priority-shift',
|
|
376
|
+
'default-framework-button-and-input-treatment',
|
|
377
|
+
'trend-gradient-without-structural-role',
|
|
378
|
+
'interchangeable-dashboard-chrome',
|
|
379
|
+
],
|
|
380
|
+
validBoldSignals: [
|
|
381
|
+
'one-clear-signature-move',
|
|
382
|
+
'project-specific-layout-tension',
|
|
383
|
+
'purposeful-motion-as-identity',
|
|
384
|
+
'distinct-typographic-hierarchy',
|
|
385
|
+
'non-template-task-priority',
|
|
386
|
+
],
|
|
387
|
+
reportingRules: {
|
|
388
|
+
mustExplainGenericity: true,
|
|
389
|
+
mustSeparateTasteFromFailure: true,
|
|
390
|
+
contractFidelityOverridesPersonalTaste: true,
|
|
375
391
|
},
|
|
376
392
|
},
|
|
377
393
|
contextHygiene: {
|
|
@@ -424,7 +440,10 @@ function buildDesignIntentContractObject({
|
|
|
424
440
|
requireStateMorphology: true,
|
|
425
441
|
requireAccessibilitySplit: true,
|
|
426
442
|
requireWcagHardFloor: true,
|
|
427
|
-
|
|
443
|
+
requireStructuredDesignExecutionPolicy: true,
|
|
444
|
+
requireStructuredDesignHandoff: true,
|
|
445
|
+
requireReviewRubric: true,
|
|
446
|
+
requireGenericityExplanation: true,
|
|
428
447
|
requireSignatureMove: true,
|
|
429
448
|
rejectTemplateNeutralLayout: true,
|
|
430
449
|
},
|
|
@@ -540,6 +559,19 @@ export function validateDesignIntentContract(designIntentContract) {
|
|
|
540
559
|
if (designIntentContract.colorTruth.allowHexDerivatives !== true) {
|
|
541
560
|
validationErrors.push('designIntent.colorTruth.allowHexDerivatives must equal true.');
|
|
542
561
|
}
|
|
562
|
+
if (!String(designIntentContract.colorTruth.intent || '').trim()) {
|
|
563
|
+
validationErrors.push('designIntent.colorTruth.intent must be a non-empty string.');
|
|
564
|
+
}
|
|
565
|
+
const paletteRoles = designIntentContract.colorTruth.paletteRoles;
|
|
566
|
+
if (!Array.isArray(paletteRoles) || paletteRoles.length < 4) {
|
|
567
|
+
validationErrors.push('designIntent.colorTruth.paletteRoles must define the minimum semantic palette roles.');
|
|
568
|
+
} else {
|
|
569
|
+
for (const requiredPaletteRole of ['base', 'surface', 'text', 'accent']) {
|
|
570
|
+
if (!paletteRoles.includes(requiredPaletteRole)) {
|
|
571
|
+
validationErrors.push(`designIntent.colorTruth.paletteRoles is missing "${requiredPaletteRole}".`);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
543
575
|
}
|
|
544
576
|
|
|
545
577
|
if (!designIntentContract.crossViewportAdaptation || typeof designIntentContract.crossViewportAdaptation !== 'object') {
|
|
@@ -670,130 +702,151 @@ export function validateDesignIntentContract(designIntentContract) {
|
|
|
670
702
|
}
|
|
671
703
|
}
|
|
672
704
|
|
|
673
|
-
if (!designIntentContract.
|
|
674
|
-
validationErrors.push('designIntent.
|
|
705
|
+
if (!designIntentContract.designExecutionPolicy || typeof designIntentContract.designExecutionPolicy !== 'object') {
|
|
706
|
+
validationErrors.push('designIntent.designExecutionPolicy must exist.');
|
|
675
707
|
} else {
|
|
676
|
-
if (designIntentContract.
|
|
677
|
-
validationErrors.push('designIntent.
|
|
708
|
+
if (designIntentContract.designExecutionPolicy.representationStrategy !== 'surface-plan-v1') {
|
|
709
|
+
validationErrors.push('designIntent.designExecutionPolicy.representationStrategy must equal "surface-plan-v1".');
|
|
710
|
+
}
|
|
711
|
+
for (const requiredFlagName of [
|
|
712
|
+
'requireSurfacePlan',
|
|
713
|
+
'requireComponentGraph',
|
|
714
|
+
'requireViewportMutationPlan',
|
|
715
|
+
'requireInteractionStateMatrix',
|
|
716
|
+
'requireContentPriorityMap',
|
|
717
|
+
'requireTaskFlowNarrative',
|
|
718
|
+
'requireSignatureMoveRationale',
|
|
719
|
+
'requireStructuredHandoff',
|
|
720
|
+
'requireRepoEvidenceAlignment',
|
|
721
|
+
'forbidScreenshotDependency',
|
|
722
|
+
]) {
|
|
723
|
+
if (designIntentContract.designExecutionPolicy[requiredFlagName] !== true) {
|
|
724
|
+
validationErrors.push(`designIntent.designExecutionPolicy.${requiredFlagName} must equal true.`);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
if (designIntentContract.designExecutionPolicy.handoffFormatVersion !== 'ui-handoff-v1') {
|
|
728
|
+
validationErrors.push('designIntent.designExecutionPolicy.handoffFormatVersion must equal "ui-handoff-v1".');
|
|
729
|
+
}
|
|
730
|
+
if (
|
|
731
|
+
!Array.isArray(designIntentContract.designExecutionPolicy.semanticReviewFocus)
|
|
732
|
+
|| designIntentContract.designExecutionPolicy.semanticReviewFocus.length < 4
|
|
733
|
+
) {
|
|
734
|
+
validationErrors.push('designIntent.designExecutionPolicy.semanticReviewFocus must list the required review dimensions.');
|
|
678
735
|
}
|
|
679
|
-
|
|
680
|
-
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
if (!designIntentContract.designExecutionHandoff || typeof designIntentContract.designExecutionHandoff !== 'object') {
|
|
739
|
+
validationErrors.push('designIntent.designExecutionHandoff must exist.');
|
|
740
|
+
} else {
|
|
741
|
+
if (designIntentContract.designExecutionHandoff.version !== 'ui-handoff-v1') {
|
|
742
|
+
validationErrors.push('designIntent.designExecutionHandoff.version must equal "ui-handoff-v1".');
|
|
681
743
|
}
|
|
682
|
-
if (designIntentContract.
|
|
683
|
-
validationErrors.push('designIntent.
|
|
744
|
+
if (designIntentContract.designExecutionHandoff.seedMode !== 'structure-first-scaffold') {
|
|
745
|
+
validationErrors.push('designIntent.designExecutionHandoff.seedMode must equal "structure-first-scaffold".');
|
|
684
746
|
}
|
|
685
|
-
if (
|
|
686
|
-
validationErrors.push('designIntent.
|
|
747
|
+
if (designIntentContract.designExecutionHandoff.requiresTaskSpecificRefinement !== true) {
|
|
748
|
+
validationErrors.push('designIntent.designExecutionHandoff.requiresTaskSpecificRefinement must equal true.');
|
|
687
749
|
}
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
750
|
+
if (!String(designIntentContract.designExecutionHandoff.primaryExperienceGoal || '').trim()) {
|
|
751
|
+
validationErrors.push('designIntent.designExecutionHandoff.primaryExperienceGoal must be a non-empty string.');
|
|
752
|
+
}
|
|
753
|
+
if (!Array.isArray(designIntentContract.designExecutionHandoff.surfacePlan) || designIntentContract.designExecutionHandoff.surfacePlan.length < 1) {
|
|
754
|
+
validationErrors.push('designIntent.designExecutionHandoff.surfacePlan must define at least one planned surface.');
|
|
755
|
+
}
|
|
756
|
+
const componentGraph = designIntentContract.designExecutionHandoff.componentGraph;
|
|
757
|
+
if (!componentGraph || typeof componentGraph !== 'object') {
|
|
758
|
+
validationErrors.push('designIntent.designExecutionHandoff.componentGraph must exist.');
|
|
692
759
|
} else {
|
|
693
|
-
if (
|
|
694
|
-
validationErrors.push('designIntent.
|
|
695
|
-
}
|
|
696
|
-
if (capturePlan.requireFullPageCapture !== true) {
|
|
697
|
-
validationErrors.push('designIntent.visualQaPolicy.capturePlan.requireFullPageCapture must equal true.');
|
|
698
|
-
}
|
|
699
|
-
if (capturePlan.requireSectionCapturesForLongPages !== true) {
|
|
700
|
-
validationErrors.push('designIntent.visualQaPolicy.capturePlan.requireSectionCapturesForLongPages must equal true.');
|
|
701
|
-
}
|
|
702
|
-
if (capturePlan.longPageStrategy !== 'anchor-plus-tiles') {
|
|
703
|
-
validationErrors.push('designIntent.visualQaPolicy.capturePlan.longPageStrategy must equal "anchor-plus-tiles".');
|
|
704
|
-
}
|
|
705
|
-
if (
|
|
706
|
-
typeof capturePlan.minimumSectionCaptureCount !== 'number'
|
|
707
|
-
|| capturePlan.minimumSectionCaptureCount < 3
|
|
708
|
-
) {
|
|
709
|
-
validationErrors.push('designIntent.visualQaPolicy.capturePlan.minimumSectionCaptureCount must be a number greater than or equal to 3.');
|
|
760
|
+
if (!Array.isArray(componentGraph.nodes) || componentGraph.nodes.length < 2) {
|
|
761
|
+
validationErrors.push('designIntent.designExecutionHandoff.componentGraph.nodes must list the primary execution nodes.');
|
|
710
762
|
}
|
|
711
|
-
if (
|
|
712
|
-
|
|
713
|
-
|| capturePlan.maxViewportHeightsPerTile < 2
|
|
714
|
-
|| capturePlan.maxViewportHeightsPerTile > 6
|
|
715
|
-
) {
|
|
716
|
-
validationErrors.push('designIntent.visualQaPolicy.capturePlan.maxViewportHeightsPerTile must be a number between 2 and 6.');
|
|
717
|
-
}
|
|
718
|
-
if (
|
|
719
|
-
typeof capturePlan.tileOverlapRatio !== 'number'
|
|
720
|
-
|| capturePlan.tileOverlapRatio <= 0
|
|
721
|
-
|| capturePlan.tileOverlapRatio >= 0.5
|
|
722
|
-
) {
|
|
723
|
-
validationErrors.push('designIntent.visualQaPolicy.capturePlan.tileOverlapRatio must be a number between 0 and 0.5.');
|
|
724
|
-
}
|
|
725
|
-
if (!Array.isArray(capturePlan.requiredSectionTypes) || capturePlan.requiredSectionTypes.length < 3) {
|
|
726
|
-
validationErrors.push('designIntent.visualQaPolicy.capturePlan.requiredSectionTypes must list the required section capture types.');
|
|
763
|
+
if (!Array.isArray(componentGraph.edges) || componentGraph.edges.length < 1) {
|
|
764
|
+
validationErrors.push('designIntent.designExecutionHandoff.componentGraph.edges must define relationships between UI nodes.');
|
|
727
765
|
}
|
|
728
766
|
}
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
validationErrors.push('designIntent.visualQaPolicy.masking must exist.');
|
|
767
|
+
const contentPriorityMap = designIntentContract.designExecutionHandoff.contentPriorityMap;
|
|
768
|
+
if (!contentPriorityMap || typeof contentPriorityMap !== 'object') {
|
|
769
|
+
validationErrors.push('designIntent.designExecutionHandoff.contentPriorityMap must exist.');
|
|
733
770
|
} else {
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
validationErrors.push('designIntent.visualQaPolicy.masking.requireMaskReasonAnnotations must equal true.');
|
|
739
|
-
}
|
|
740
|
-
if (!Array.isArray(maskingPolicy.allowedDynamicMaskCategories) || maskingPolicy.allowedDynamicMaskCategories.length < 4) {
|
|
741
|
-
validationErrors.push('designIntent.visualQaPolicy.masking.allowedDynamicMaskCategories must list the approved masking categories.');
|
|
771
|
+
for (const priorityBucket of ['primary', 'secondary', 'deferred']) {
|
|
772
|
+
if (!Array.isArray(contentPriorityMap[priorityBucket]) || contentPriorityMap[priorityBucket].length < 1) {
|
|
773
|
+
validationErrors.push(`designIntent.designExecutionHandoff.contentPriorityMap.${priorityBucket} must contain at least one item.`);
|
|
774
|
+
}
|
|
742
775
|
}
|
|
743
776
|
}
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
validationErrors.push('designIntent.visualQaPolicy.stability must exist.');
|
|
777
|
+
const viewportMutationPlan = designIntentContract.designExecutionHandoff.viewportMutationPlan;
|
|
778
|
+
if (!viewportMutationPlan || typeof viewportMutationPlan !== 'object') {
|
|
779
|
+
validationErrors.push('designIntent.designExecutionHandoff.viewportMutationPlan must exist.');
|
|
748
780
|
} else {
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
validationErrors.push('designIntent.visualQaPolicy.stability.maxMaskedDiffRatio must be a number between 0 and 0.1.');
|
|
754
|
-
}
|
|
755
|
-
if (stabilityPolicy.maxMaskedDiffRatio < stabilityPolicy.maxUnmaskedDiffRatio) {
|
|
756
|
-
validationErrors.push('designIntent.visualQaPolicy.stability.maxMaskedDiffRatio must be greater than or equal to maxUnmaskedDiffRatio.');
|
|
757
|
-
}
|
|
758
|
-
if (stabilityPolicy.requireConsistentRenderingEnvironment !== true) {
|
|
759
|
-
validationErrors.push('designIntent.visualQaPolicy.stability.requireConsistentRenderingEnvironment must equal true.');
|
|
781
|
+
for (const viewportKey of ['mobile', 'tablet', 'desktop']) {
|
|
782
|
+
if (!String(viewportMutationPlan[viewportKey] || '').trim()) {
|
|
783
|
+
validationErrors.push(`designIntent.designExecutionHandoff.viewportMutationPlan.${viewportKey} must be a non-empty string.`);
|
|
784
|
+
}
|
|
760
785
|
}
|
|
761
786
|
}
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
787
|
+
if (!Array.isArray(designIntentContract.designExecutionHandoff.interactionStateMatrix) || designIntentContract.designExecutionHandoff.interactionStateMatrix.length < 1) {
|
|
788
|
+
validationErrors.push('designIntent.designExecutionHandoff.interactionStateMatrix must list key component state expectations.');
|
|
789
|
+
}
|
|
790
|
+
if (!Array.isArray(designIntentContract.designExecutionHandoff.taskFlowNarrative) || designIntentContract.designExecutionHandoff.taskFlowNarrative.length < 2) {
|
|
791
|
+
validationErrors.push('designIntent.designExecutionHandoff.taskFlowNarrative must describe the key UI task flow in sequence.');
|
|
792
|
+
}
|
|
793
|
+
if (!String(designIntentContract.designExecutionHandoff.signatureMoveRationale || '').trim()) {
|
|
794
|
+
validationErrors.push('designIntent.designExecutionHandoff.signatureMoveRationale must explain the chosen authored move.');
|
|
795
|
+
}
|
|
796
|
+
const implementationGuardrails = designIntentContract.designExecutionHandoff.implementationGuardrails;
|
|
797
|
+
if (!implementationGuardrails || typeof implementationGuardrails !== 'object') {
|
|
798
|
+
validationErrors.push('designIntent.designExecutionHandoff.implementationGuardrails must exist.');
|
|
766
799
|
} else {
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
}
|
|
776
|
-
if (
|
|
777
|
-
typeof semanticEscalationPolicy.meaningfulDiffRatioThreshold !== 'number'
|
|
778
|
-
|| semanticEscalationPolicy.meaningfulDiffRatioThreshold <= 0
|
|
779
|
-
|| semanticEscalationPolicy.meaningfulDiffRatioThreshold >= 0.2
|
|
780
|
-
) {
|
|
781
|
-
validationErrors.push('designIntent.visualQaPolicy.semanticEscalation.meaningfulDiffRatioThreshold must be a number between 0 and 0.2.');
|
|
800
|
+
for (const requiredFlagName of [
|
|
801
|
+
'requireBuildFromHandoff',
|
|
802
|
+
'requireGapNotesBeforeFallback',
|
|
803
|
+
'forbidGenericLayoutFallbackWithoutReason',
|
|
804
|
+
]) {
|
|
805
|
+
if (implementationGuardrails[requiredFlagName] !== true) {
|
|
806
|
+
validationErrors.push(`designIntent.designExecutionHandoff.implementationGuardrails.${requiredFlagName} must equal true.`);
|
|
807
|
+
}
|
|
782
808
|
}
|
|
783
809
|
}
|
|
810
|
+
}
|
|
784
811
|
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
812
|
+
if (!designIntentContract.reviewRubric || typeof designIntentContract.reviewRubric !== 'object') {
|
|
813
|
+
validationErrors.push('designIntent.reviewRubric must exist.');
|
|
814
|
+
} else {
|
|
815
|
+
if (designIntentContract.reviewRubric.version !== 'ui-rubric-v1') {
|
|
816
|
+
validationErrors.push('designIntent.reviewRubric.version must equal "ui-rubric-v1".');
|
|
817
|
+
}
|
|
818
|
+
if (!Array.isArray(designIntentContract.reviewRubric.dimensions) || designIntentContract.reviewRubric.dimensions.length < 5) {
|
|
819
|
+
validationErrors.push('designIntent.reviewRubric.dimensions must define the required rubric dimensions.');
|
|
788
820
|
} else {
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
821
|
+
for (const requiredRubricKey of [
|
|
822
|
+
'distinctiveness',
|
|
823
|
+
'contractFidelity',
|
|
824
|
+
'visualConsistency',
|
|
825
|
+
'heuristicUxQuality',
|
|
826
|
+
'motionDiscipline',
|
|
827
|
+
]) {
|
|
828
|
+
if (!designIntentContract.reviewRubric.dimensions.some((dimension) => dimension?.key === requiredRubricKey)) {
|
|
829
|
+
validationErrors.push(`designIntent.reviewRubric.dimensions is missing "${requiredRubricKey}".`);
|
|
830
|
+
}
|
|
794
831
|
}
|
|
795
|
-
|
|
796
|
-
|
|
832
|
+
}
|
|
833
|
+
if (!Array.isArray(designIntentContract.reviewRubric.genericitySignals) || designIntentContract.reviewRubric.genericitySignals.length < 3) {
|
|
834
|
+
validationErrors.push('designIntent.reviewRubric.genericitySignals must list common genericity drift signals.');
|
|
835
|
+
}
|
|
836
|
+
if (!Array.isArray(designIntentContract.reviewRubric.validBoldSignals) || designIntentContract.reviewRubric.validBoldSignals.length < 3) {
|
|
837
|
+
validationErrors.push('designIntent.reviewRubric.validBoldSignals must list legitimate authored signals.');
|
|
838
|
+
}
|
|
839
|
+
if (!designIntentContract.reviewRubric.reportingRules || typeof designIntentContract.reviewRubric.reportingRules !== 'object') {
|
|
840
|
+
validationErrors.push('designIntent.reviewRubric.reportingRules must exist.');
|
|
841
|
+
} else {
|
|
842
|
+
for (const requiredFlagName of [
|
|
843
|
+
'mustExplainGenericity',
|
|
844
|
+
'mustSeparateTasteFromFailure',
|
|
845
|
+
'contractFidelityOverridesPersonalTaste',
|
|
846
|
+
]) {
|
|
847
|
+
if (designIntentContract.reviewRubric.reportingRules[requiredFlagName] !== true) {
|
|
848
|
+
validationErrors.push(`designIntent.reviewRubric.reportingRules.${requiredFlagName} must equal true.`);
|
|
849
|
+
}
|
|
797
850
|
}
|
|
798
851
|
}
|
|
799
852
|
}
|
|
@@ -817,7 +870,6 @@ export function buildDesignIntentSeedFromSignals({
|
|
|
817
870
|
primaryDomain,
|
|
818
871
|
features = [],
|
|
819
872
|
initContext,
|
|
820
|
-
architectureRecommendation = null,
|
|
821
873
|
status = 'seed-needs-design-synthesis',
|
|
822
874
|
supplementalFields = {},
|
|
823
875
|
}) {
|
|
@@ -827,7 +879,6 @@ export function buildDesignIntentSeedFromSignals({
|
|
|
827
879
|
primaryDomain,
|
|
828
880
|
features,
|
|
829
881
|
initContext,
|
|
830
|
-
architectureRecommendation,
|
|
831
882
|
status,
|
|
832
883
|
supplementalFields,
|
|
833
884
|
});
|
|
@@ -843,7 +894,6 @@ export function buildDesignIntentSeedFromSignals({
|
|
|
843
894
|
export function buildDesignIntentSeed({
|
|
844
895
|
discoveryAnswers,
|
|
845
896
|
initContext,
|
|
846
|
-
architectureRecommendation,
|
|
847
897
|
}) {
|
|
848
898
|
return buildDesignIntentSeedFromSignals({
|
|
849
899
|
projectName: discoveryAnswers.projectName,
|
|
@@ -851,7 +901,6 @@ export function buildDesignIntentSeed({
|
|
|
851
901
|
primaryDomain: discoveryAnswers.primaryDomain,
|
|
852
902
|
features: discoveryAnswers.features,
|
|
853
903
|
initContext,
|
|
854
|
-
architectureRecommendation,
|
|
855
904
|
status: 'seed-needs-design-synthesis',
|
|
856
905
|
});
|
|
857
906
|
}
|