Runs / transfer-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 26 counted, under 7 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 list_files, read_file 1,069 142 $0.0002 1 write_file 1,512 5,268 $0.0028 2 stop 6,801 69 $0.0007
Output cap The provider's default 3
4 import { css } from "styled-system/css";
5 import data from "./fixture.json";
6
7 const IBAN_PATTERN = /^[A-Z]{2}\d{2}[A-Z0-9]{11,30}$/;
8 const AMOUNT_PATTERN = /^\d+([.,]\d{1,2})?$/;
9
10 const money = new Intl.NumberFormat("en-IE", {
11 style: "currency",
12 currency: data.currency,
13 });
14
15 type Confirmation = { amount: number; beneficiary: string };
16
17 type FieldErrors = {
18 beneficiary?: string;
19 iban?: string;
20 amount?: string;
21 };
22
23 function parseAmountToCents(raw: string): number | null {
24 const trimmed = raw.trim();
25 if (!AMOUNT_PATTERN.test(trimmed)) return null;
26 const cents = Math.round(Number(trimmed.replace(",", ".")) * 100);
27 return cents > 0 ? cents : null;
28 }
29
30 const styles = {
31 form: css({
32 display: "flex",
33 flexDirection: "column",
34 gap: "4",
35 maxWidth: "480px",
36 margin: "0 auto",
37 padding: "6",
38 }),
39 field: css({
40 display: "flex",
41 flexDirection: "column",
42 gap: "1",
43 }),
44 label: css({
45 fontWeight: "semibold",
46 }),
47 input: css({
48 padding: "2",
49 borderWidth: "1px",
50 borderStyle: "solid",
51 borderColor: "#8a8f98",
52 borderRadius: "6px",
53 fontSize: "md",
54 }),
55 inputInvalid: css({
56 borderColor: "#b42318",
57 }),
58 hint: css({
59 fontSize: "sm",
60 color: "#4b5563",
61 }),
62 error: css({
63 fontSize: "sm",
64 color: "#b42318",
65 }),
66 button: css({
67 padding: "3",
68 borderRadius: "6px",
69 borderWidth: "0",
70 backgroundColor: "#1d4ed8",
71 color: "white",
72 fontWeight: "semibold",
73 cursor: "pointer",
74 _disabled: {
75 backgroundColor: "#9ca3af",
76 cursor: "not-allowed",
77 },
78 }),
79 confirmation: css({
80 maxWidth: "480px",
81 margin: "0 auto",
82 padding: "4",
83 borderRadius: "6px",
84 backgroundColor: "#ecfdf3",
85 color: "#067647",
86 }),
87 };
88
89 export default function SepaTransferPage() {
90 const [accountId, setAccountId] = useState<string>(data.defaultAccountId);
91 const [beneficiary, setBeneficiary] = useState("");
92 const [iban, setIban] = useState("");
93 const [amount, setAmount] = useState("");
94 const [reference, setReference] = useState("");
95 const [submitted, setSubmitted] = useState(false);
96 const [confirmation, setConfirmation] = useState<Confirmation | null>(null);
97
98 const account =
99 data.accounts.find((a) => a.id === accountId) ?? data.accounts[0];
100 const availableCents = Math.round(account.available * 100);
101
102 const amountCents = parseAmountToCents(amount);
103 const balanceExceeded =
104 amountCents !== null && amountCents > availableCents;
105
106 const errors: FieldErrors = {};
107 if (beneficiary.trim() === "") {
108 errors.beneficiary = "Enter the beneficiary name.";
109 }
110 if (!IBAN_PATTERN.test(iban.replace(/\s/g, "").toUpperCase())) {
111 errors.iban = "Enter a valid IBAN.";
112 }
113 if (amountCents === null) {
114 errors.amount = "Enter an amount greater than zero.";
115 } else if (balanceExceeded) {
116 errors.amount = `The amount is higher than the available balance of ${money.format(account.available)}.`;
117 }
118 const hasErrors = Object.keys(errors).length > 0;
119
120 // Balance error is shown live; other errors appear after the first submit attempt.
121 const shownAmountError =
122 balanceExceeded || (submitted && errors.amount)
123 ? errors.amount
124 : undefined;
125
126 function handleSubmit(event: FormEvent<HTMLFormElement>) {
127 event.preventDefault();
128 setSubmitted(true);
129 if (hasErrors || amountCents === null) return;
130
131 setConfirmation({
132 amount: amountCents / 100,
133 beneficiary: beneficiary.trim(),
134 });
135 setBeneficiary("");
136 setIban("");
137 setAmount("");
138 setReference("");
139 setSubmitted(false);
140 }
141
142 return (
143 <main>
144 <form className={styles.form} onSubmit={handleSubmit} noValidate>
145 <h1>SEPA transfer</h1>
146
147 <div className={styles.field}>
148 <label className={styles.label} htmlFor="from-account">
149 From account
150 </label>
151 <select
152 id="from-account"
153 className={styles.input}
154 value={accountId}
155 onChange={(e) => setAccountId(e.target.value)}
156 >
157 {data.accounts.map((a) => (
158 <option key={a.id} value={a.id}>
159 {a.name} ({a.iban})
160 </option>
161 ))}
162 </select>
163 <span className={styles.hint} aria-live="polite">
164 Available balance: {money.format(account.available)}
165 </span>
166 </div>
167
168 <div className={styles.field}>
169 <label className={styles.label} htmlFor="beneficiary-name">
170 Beneficiary name
171 </label>
172 <input
173 id="beneficiary-name"
174 type="text"
175 autoComplete="off"
176 className={`${styles.input} ${submitted && errors.beneficiary ? styles.inputInvalid : ""}`}
177 value={beneficiary}
178 onChange={(e) => setBeneficiary(e.target.value)}
179 aria-invalid={submitted && !!errors.beneficiary}
180 aria-describedby={
181 submitted && errors.beneficiary ? "beneficiary-error" : undefined
182 }
183 />
184 {submitted && errors.beneficiary && (
185 <span id="beneficiary-error" className={styles.error}>
186 {errors.beneficiary}
187 </span>
188 )}
189 </div>
190
191 <div className={styles.field}>
192 <label className={styles.label} htmlFor="beneficiary-iban">
193 Beneficiary IBAN
194 </label>
195 <input
196 id="beneficiary-iban"
197 type="text"
198 autoComplete="off"
199 spellCheck={false}
200 className={`${styles.input} ${submitted && errors.iban ? styles.inputInvalid : ""}`}
201 value={iban}
202 onChange={(e) => setIban(e.target.value)}
203 aria-invalid={submitted && !!errors.iban}
204 aria-describedby={submitted && errors.iban ? "iban-error" : undefined}
205 />
206 {submitted && errors.iban && (
207 <span id="iban-error" className={styles.error}>
208 {errors.iban}
209 </span>
210 )}
211 </div>
212
213 <div className={styles.field}>
214 <label className={styles.label} htmlFor="amount">
215 Amount ({data.currency})
216 </label>
217 <input
218 id="amount"
219 type="text"
220 inputMode="decimal"
221 autoComplete="off"
222 className={`${styles.input} ${shownAmountError ? styles.inputInvalid : ""}`}
223 value={amount}
224 onChange={(e) => setAmount(e.target.value)}
225 aria-invalid={!!shownAmountError}
226 aria-describedby={shownAmountError ? "amount-error" : undefined}
227 />
228 {shownAmountError && (
229 <span id="amount-error" className={styles.error}>
230 {shownAmountError}
231 </span>
232 )}
233 </div>
234
235 <div className={styles.field}>
236 <label className={styles.label} htmlFor="reference">
237 Reference (optional)
238 </label>
239 <input
240 id="reference"
241 type="text"
242 autoComplete="off"
243 className={styles.input}
244 value={reference}
245 onChange={(e) => setReference(e.target.value)}
246 />
247 </div>
248
249 <button
250 type="submit"
251 className={styles.button}
252 disabled={balanceExceeded}
253 >
254 Send transfer
255 </button>
256 </form>
257
258 {confirmation && (
259 <div className={styles.confirmation} role="status">
260 Transfer of {money.format(confirmation.amount)} to{" "}
261 {confirmation.beneficiary} has been submitted.
262 </div>
263 )}
264 </main>
265 );
266 }
267
`#9ca3af` is a raw color. Use a semantic color token.
page.tsx:84:22 · #ecfdf3 `#ecfdf3` is a raw color. Use a semantic color token. page.tsx:85:12 · #067647 `#067647` is a raw color. Use a semantic color token. raw-values/raw-length 6 design-system typecheck/TS18048 3 quality lint/jsx-a11y(prefer-tag-over-role) 1 quality typecheck/TS2769 0 quality