Runs / kyc-form Batch Runs from different design-system versions should not be compared.
The page A screenshot in each theme, as the benchmark took it.
page.tsx As the agent left it; marked lines broke a rule.
Violations 49 counted, under 11 rules. “Not counted” marks a compiler error that restates a design-system violation, “Ignored” one the agent silenced with a comment.
Steps One row per model call, with the tools it asked for. An agent that reads the guidelines before writing shows it here; what a checker or submit_view answered is under its call.
Step Tools Tokens in Tokens out Cost 0 read_file, list_files 1,091 114 $0.0002 1 write_file 1,587 5,557 $0.0029 2 stop 7,165 68 $0.0008
Output cap The provider's default 3 import { useState, type FormEvent } from "react";
4 import { css } from "styled-system/css";
5 import data from "./fixture.json";
6
7 type FormValues = {
8 dateOfBirth: string;
9 nationality: string;
10 countryOfResidence: string;
11 taxId: string;
12 documentType: string;
13 documentNumber: string;
14 pep: string;
15 };
16
17 type FieldKey = keyof FormValues;
18
19 const initialValues: FormValues = {
20 dateOfBirth: "",
21 nationality: "",
22 countryOfResidence: "",
23 taxId: "",
24 documentType: "",
25 documentNumber: "",
26 pep: "",
27 };
28
29 const REQUIRED_MESSAGE = "This field is required.";
30
31 const pageStyle = css({
32 maxWidth: "640px",
33 margin: "0 auto",
34 padding: "32px 24px",
35 fontFamily: "inherit",
36 color: "neutral.900",
37 });
38
39 const headingStyle = css({
40 fontSize: "2xl",
41 fontWeight: "semibold",
42 marginBottom: "8px",
43 });
44
45 const introStyle = css({
46 color: "neutral.600",
47 marginBottom: "24px",
48 });
49
50 const summaryStyle = css({
51 display: "grid",
52 gridTemplateColumns: "1fr 1fr",
53 gap: "12px",
54 padding: "16px",
55 borderRadius: "8px",
56 backgroundColor: "neutral.100",
57 marginBottom: "24px",
58 });
59
60 const summaryLabelStyle = css({
61 fontSize: "sm",
62 color: "neutral.600",
63 });
64
65 const summaryValueStyle = css({
66 fontWeight: "medium",
67 wordBreak: "break-all",
68 });
69
70 const formStyle = css({
71 display: "flex",
72 flexDirection: "column",
73 gap: "20px",
74 });
75
76 const fieldStyle = css({
77 display: "flex",
78 flexDirection: "column",
79 gap: "6px",
80 });
81
82 const labelStyle = css({
83 fontSize: "sm",
84 fontWeight: "medium",
85 });
86
87 const inputStyle = css({
88 padding: "10px 12px",
89 borderRadius: "6px",
90 border: "1px solid",
91 borderColor: "neutral.400",
92 fontSize: "md",
93 backgroundColor: "white",
94 _invalid: { borderColor: "red.600" },
95 });
96
97 const inputErrorStyle = css({
98 borderColor: "red.600",
99 });
100
101 const errorTextStyle = css({
102 fontSize: "sm",
103 color: "red.600",
104 });
105
106 const radioGroupStyle = css({
107 display: "flex",
108 gap: "16px",
109 });
110
111 const radioLabelStyle = css({
112 display: "flex",
113 alignItems: "center",
114 gap: "6px",
115 fontSize: "md",
116 });
117
118 const buttonStyle = css({
119 alignSelf: "flex-start",
120 padding: "12px 24px",
121 borderRadius: "6px",
122 border: "none",
123 backgroundColor: "neutral.900",
124 color: "white",
125 fontWeight: "medium",
126 cursor: "pointer",
127 });
128
129 const reviewStyle = css({
130 padding: "24px",
131 borderRadius: "8px",
132 backgroundColor: "neutral.100",
133 });
134
135 const countryOptions = data.countries.map((c) => ({
136 value: c.code,
137 label: c.name,
138 }));
139
140 export default function IdentityVerificationPage() {
141 const [values, setValues] = useState<FormValues>(initialValues);
142 const [errors, setErrors] = useState<Partial<Record<FieldKey, string>>>({});
143 const [submitted, setSubmitted] = useState(false);
144
145 const { firstName, lastName, email } = data.customer;
146
147 function updateField(key: FieldKey, value: string) {
148 setValues((prev) => ({ ...prev, [key]: value }));
149 setErrors((prev) => {
150 if (!prev[key]) return prev;
151 const next = { ...prev };
152 delete next[key];
153 return next;
154 });
155 }
156
157 function handleSubmit(event: FormEvent<HTMLFormElement>) {
158 event.preventDefault();
159
160 const nextErrors: Partial<Record<FieldKey, string>> = {};
161 (Object.keys(values) as FieldKey[]).forEach((key) => {
162 if (values[key].trim() === "") {
163 nextErrors[key] = REQUIRED_MESSAGE;
164 }
165 });
166
167 setErrors(nextErrors);
168 if (Object.keys(nextErrors).length === 0) {
169 setSubmitted(true);
170 }
171 }
172
173 if (submitted) {
174 return (
175 <main className={pageStyle}>
176 <h1 className={headingStyle}>Identity verification</h1>
177 <div className={reviewStyle} role="status">
178 <p>
179 Thank you, {firstName}. Your identity details are being reviewed.
180 We will let you know once the review is complete.
181 </p>
182 </div>
183 </main>
184 );
185 }
186
187 const errorId = (key: FieldKey) => `${key}-error`;
188
189 return (
190 <main className={pageStyle}>
191 <h1 className={headingStyle}>Identity verification</h1>
192 <p className={introStyle}>
193 Please provide the following details to complete your account opening.
194 All fields are required.
195 </p>
196
197 <section className={summaryStyle} aria-label="Customer details">
198 <div>
199 <div className={summaryLabelStyle}>First name</div>
200 <div className={summaryValueStyle}>{firstName}</div>
201 </div>
202 <div>
203 <div className={summaryLabelStyle}>Last name</div>
204 <div className={summaryValueStyle}>{lastName}</div>
205 </div>
206 <div style={{ gridColumn: "1 / -1" }}>
207 <div className={summaryLabelStyle}>Email</div>
208 <div className={summaryValueStyle}>{email}</div>
209 </div>
210 </section>
211
212 <form className={formStyle} onSubmit={handleSubmit} noValidate>
213 <div className={fieldStyle}>
214 <label htmlFor="dateOfBirth" className={labelStyle}>
215 Date of birth
216 </label>
217 <input
218 id="dateOfBirth"
219 name="dateOfBirth"
220 type="date"
221 value={values.dateOfBirth}
222 onChange={(e) => updateField("dateOfBirth", e.target.value)}
223 aria-invalid={!!errors.dateOfBirth}
224 aria-describedby={errors.dateOfBirth ? errorId("dateOfBirth") : undefined}
225 className={`${inputStyle} ${errors.dateOfBirth ? inputErrorStyle : ""}`}
226 />
227 {errors.dateOfBirth && (
228 <span id={errorId("dateOfBirth")} className={errorTextStyle}>
229 {errors.dateOfBirth}
230 </span>
231 )}
232 </div>
233
234 <div className={fieldStyle}>
235 <label htmlFor="nationality" className={labelStyle}>
236 Nationality
237 </label>
238 <select
239 id="nationality"
240 name="nationality"
241 value={values.nationality}
242 onChange={(e) => updateField("nationality", e.target.value)}
243 aria-invalid={!!errors.nationality}
244 aria-describedby={errors.nationality ? errorId("nationality") : undefined}
245 className={`${inputStyle} ${errors.nationality ? inputErrorStyle : ""}`}
246 >
247 <option value="">Select a country</option>
248 {countryOptions.map((c) => (
249 <option key={c.value} value={c.value}>
250 {c.label}
251 </option>
252 ))}
253 </select>
254 {errors.nationality && (
255 <span id={errorId("nationality")} className={errorTextStyle}>
256 {errors.nationality}
257 </span>
258 )}
259 </div>
260
261 <div className={fieldStyle}>
262 <label htmlFor="countryOfResidence" className={labelStyle}>
263 Country of residence
264 </label>
265 <select
266 id="countryOfResidence"
267 name="countryOfResidence"
268 value={values.countryOfResidence}
269 onChange={(e) => updateField("countryOfResidence", e.target.value)}
270 aria-invalid={!!errors.countryOfResidence}
271 aria-describedby={
272 errors.countryOfResidence ? errorId("countryOfResidence") : undefined
273 }
274 className={`${inputStyle} ${errors.countryOfResidence ? inputErrorStyle : ""}`}
275 >
276 <option value="">Select a country</option>
277 {countryOptions.map((c) => (
278 <option key={c.value} value={c.value}>
279 {c.label}
280 </option>
281 ))}
282 </select>
283 {errors.countryOfResidence && (
284 <span id={errorId("countryOfResidence")} className={errorTextStyle}>
285 {errors.countryOfResidence}
286 </span>
287 )}
288 </div>
289
290 <div className={fieldStyle}>
291 <label htmlFor="taxId" className={labelStyle}>
292 Tax identification number
293 </label>
294 <input
295 id="taxId"
296 name="taxId"
297 type="text"
298 autoComplete="off"
299 value={values.taxId}
300 onChange={(e) => updateField("taxId", e.target.value)}
301 aria-invalid={!!errors.taxId}
302 aria-describedby={errors.taxId ? errorId("taxId") : undefined}
303 className={`${inputStyle} ${errors.taxId ? inputErrorStyle : ""}`}
304 />
305 {errors.taxId && (
306 <span id={errorId("taxId")} className={errorTextStyle}>
307 {errors.taxId}
308 </span>
309 )}
310 </div>
311
312 <div className={fieldStyle}>
313 <label htmlFor="documentType" className={labelStyle}>
314 Type of identity document
315 </label>
316 <select
317 id="documentType"
318 name="documentType"
319 value={values.documentType}
320 onChange={(e) => updateField("documentType", e.target.value)}
321 aria-invalid={!!errors.documentType}
322 aria-describedby={errors.documentType ? errorId("documentType") : undefined}
323 className={`${inputStyle} ${errors.documentType ? inputErrorStyle : ""}`}
324 >
325 <option value="">Select a document type</option>
326 {data.documentTypes.map((d) => (
327 <option key={d.value} value={d.value}>
328 {d.label}
329 </option>
330 ))}
331 </select>
332 {errors.documentType && (
333 <span id={errorId("documentType")} className={errorTextStyle}>
334 {errors.documentType}
335 </span>
336 )}
337 </div>
338
339 <div className={fieldStyle}>
340 <label htmlFor="documentNumber" className={labelStyle}>
341 Document number
342 </label>
343 <input
344 id="documentNumber"
345 name="documentNumber"
346 type="text"
347 autoComplete="off"
348 value={values.documentNumber}
349 onChange={(e) => updateField("documentNumber", e.target.value)}
350 aria-invalid={!!errors.documentNumber}
351 aria-describedby={errors.documentNumber ? errorId("documentNumber") : undefined}
352 className={`${inputStyle} ${errors.documentNumber ? inputErrorStyle : ""}`}
353 />
354 {errors.documentNumber && (
355 <span id={errorId("documentNumber")} className={errorTextStyle}>
356 {errors.documentNumber}
357 </span>
358 )}
359 </div>
360
361 <fieldset className={fieldStyle} style={{ border: "none", padding: 0, margin: 0 }}>
362 <legend className={labelStyle}>Are you a politically exposed person?</legend>
363 <div className={radioGroupStyle}>
364 <label className={radioLabelStyle}>
365 <input
366 type="radio"
367 name="pep"
368 value="yes"
369 checked={values.pep === "yes"}
370 onChange={() => updateField("pep", "yes")}
371 aria-invalid={!!errors.pep}
372 aria-describedby={errors.pep ? errorId("pep") : undefined}
373 />
374 Yes
375 </label>
376 <label className={radioLabelStyle}>
377 <input
378 type="radio"
379 name="pep"
380 value="no"
381 checked={values.pep === "no"}
382 onChange={() => updateField("pep", "no")}
383 aria-invalid={!!errors.pep}
384 aria-describedby={errors.pep ? errorId("pep") : undefined}
385 />
386 No
387 </label>
388 </div>
389 {errors.pep && (
390 <span id={errorId("pep")} className={errorTextStyle}>
391 {errors.pep}
392 </span>
393 )}
394 </fieldset>
395
396 <button type="submit" className={buttonStyle}>
397 Submit
398 </button>
399 </form>
400 </main>
401 );
402 }
403
`24px` is a raw length. Use a token.
token-roles/palette 10 design-system page.tsx:36:10 · neutral.900 `neutral.900` is a palette shade: it ignores the theme. Use a semantic color token. page.tsx:46:10 · neutral.600 `neutral.600` is a palette shade: it ignores the theme. Use a semantic color token. page.tsx:56:20 · neutral.100 `neutral.100` is a palette shade: it ignores the theme. Use a semantic color token. page.tsx:62:10 · neutral.600 `neutral.600` is a palette shade: it ignores the theme. Use a semantic color token. page.tsx:91:16 · neutral.400 `neutral.400` is a palette shade: it ignores the theme. Use a semantic color token. page.tsx:94:28 · red.600 `red.600` is a palette shade: it ignores the theme. Use a semantic color token. page.tsx:98:16 · red.600 `red.600` is a palette shade: it ignores the theme. Use a semantic color token. page.tsx:103:10 · red.600 `red.600` is a palette shade: it ignores the theme. Use a semantic color token. page.tsx:123:20 · neutral.900 `neutral.900` is a palette shade: it ignores the theme. Use a semantic color token. page.tsx:132:20 · neutral.100 `neutral.100` is a palette shade: it ignores the theme. Use a semantic color token. Every run that broke token-roles/palette components/native-element 9 design-system page.tsx:217:11 · <input> `<input>` has a design-system equivalent: use `Input` from `@vektos/ds`. page.tsx:238:11 · <select> `<select>` has a design-system equivalent: use `Select` from `@vektos/ds`. page.tsx:265:11 · <select> `<select>` has a design-system equivalent: use `Select` from `@vektos/ds`. page.tsx:294:11 · <input> `<input>` has a design-system equivalent: use `Input` from `@vektos/ds`. page.tsx:316:11 · <select> `<select>` has a design-system equivalent: use `Select` from `@vektos/ds`. page.tsx:343:11 · <input> `<input>` has a design-system equivalent: use `Input` from `@vektos/ds`. page.tsx:365:15 · <input> `<input>` has a design-system equivalent: use `Input` from `@vektos/ds`. page.tsx:377:15 · <input> `<input>` has a design-system equivalent: use `Input` from `@vektos/ds`. page.tsx:396:9 · <button> `<button>` has a design-system equivalent: use `Button` from `@vektos/ds`. Every run that broke components/native-element lint/jsx-a11y(prefer-tag-over-role) 1 quality typecheck/TS2769 0 quality