Runs / loan-contract 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 10 counted, under 2 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 get_guidelines 1,092 93 $0.0031 1 list_files, list_components, list_tokens, read_file 2,114 109 $0.0054 2 get_component, get_component, get_component 2,594 417 $0.0098
Output cap The provider's default 4 CardBody,
5 CardDescription,
6 CardHeader,
7 CardTitle,
8 Table,
9 TableBody,
10 TableCell,
11 TableHead,
12 TableHeader,
13 TableRow,
14 } from "@vektos/ds";
15 import { css } from "styled-system/css";
16 import data from "./fixture.json";
17
18 const currencyFormatter = new Intl.NumberFormat("en-IE", {
19 style: "currency",
20 currency: data.contract.currency,
21 minimumFractionDigits: 2,
22 maximumFractionDigits: 2,
23 });
24
25 const dateFormatter = new Intl.DateTimeFormat("en-GB", {
26 day: "2-digit",
27 month: "short",
28 year: "numeric",
29 timeZone: "UTC",
30 });
31
32 const statusDetails: Record<
33 string,
34 { label: string; tone: "neutral" | "success" | "warning" | "danger" }
35 > = {
36 paid: { label: "Paid", tone: "success" },
37 due: { label: "Due", tone: "warning" },
38 upcoming: { label: "Upcoming", tone: "neutral" },
39 };
40
41 function formatCurrency(value: number) {
42 return currencyFormatter.format(value);
43 }
44
45 function formatDate(value: string) {
46 return dateFormatter.format(new Date(`${value}T00:00:00Z`));
47 }
48
49 function DocumentIcon() {
50 return (
51 <svg
52 aria-hidden="true"
53 viewBox="0 0 24 24"
54 fill="none"
55 stroke="currentColor"
56 strokeWidth="1.8"
57 strokeLinecap="round"
58 strokeLinejoin="round"
59 className={css({
60 width: "6",
61 height: "6",
62 flexShrink: "0",
63 color: "accent.default",
64 })}
65 >
66 <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z" />
67 <path d="M14 2v6h6M8 13h8M8 17h5" />
68 </svg>
69 );
70 }
71
72 function CheckIcon() {
73 return (
74 <svg
75 aria-hidden="true"
76 viewBox="0 0 24 24"
77 fill="none"
78 stroke="currentColor"
79 strokeWidth="2"
80 strokeLinecap="round"
81 strokeLinejoin="round"
82 className={css({
83 width: "4",
84 height: "4",
85 flexShrink: "0",
86 marginInlineStart: "auto",
87 color: "success.text",
88 })}
89 >
90 <path d="m5 12 4 4L19 6" />
91 </svg>
92 );
93 }
94
95 export default function PersonalLoanContractPage() {
96 const { contract } = data;
97 const repaidAmount = contract.principal - contract.outstanding;
98 const repaidPercentage = (repaidAmount / contract.principal) * 100;
99 const nextInstalment =
100 data.schedule.find((instalment) => instalment.status === "due") ??
101 data.schedule.find((instalment) => instalment.status === "upcoming");
102 const contractStatus =
103 contract.status.charAt(0).toUpperCase() + contract.status.slice(1);
104
105 return (
106 <div
107 className={`vektos ${css({
108 width: "full",
109 bg: "bg.canvas",
110 color: "fg.default",
111 })}`}
112 >
113 <main
114 className={css({
115 width: "full",
116 maxWidth: "full",
117 px: { base: "4", md: "8" },
118 py: { base: "6", md: "8" },
119 display: "flex",
120 flexDirection: "column",
121 gap: "8",
122 })}
123 >
124 <header
125 className={css({
126 display: "flex",
127 flexDirection: "column",
128 gap: "3",
129 })}
130 >
131 <p
132 className={css({
133 margin: "0",
134 color: "accent.default",
135 fontSize: "xs",
136 fontWeight: "semibold",
137 })}
138 >
139 LOAN CONTRACT
140 </p>
141 <div
142 className={css({
143 display: "flex",
144 alignItems: "center",
145 flexWrap: "wrap",
146 gap: "3",
147 })}
148 >
149 <h1
150 className={css({
151 margin: "0",
152 fontSize: "lg",
153 fontWeight: "semibold",
154 lineHeight: "tight",
155 })}
156 >
157 {contract.product}
158 </h1>
159 <Badge tone={contract.status === "active" ? "success" : "neutral"}>
160 {contractStatus}
161 </Badge>
162 </div>
163 <p className={css({ margin: "0", color: "fg.muted", fontSize: "sm" })}>
164 Contract {contract.number}
165 <span aria-hidden="true"> · </span>
166 Borrower {contract.borrower}
167 </p>
168 </header>
169
170 <section
171 aria-label="Loan summary"
172 className={css({
173 display: "grid",
174 gridTemplateColumns: { base: "1fr", lg: "2fr 1fr" },
175 alignItems: "stretch",
176 gap: "6",
177 })}
178 >
179 <Card className={css({ height: "full" })}>
180 <CardHeader>
181 <CardTitle asChild>
182 <h2>Key terms</h2>
183 </CardTitle>
184 <CardDescription>
185 The original terms of this personal loan. Rates are annual.
186 </CardDescription>
187 </CardHeader>
188 <CardBody>
189 <dl
190 className={css({
191 margin: "0",
192 display: "grid",
193 gridTemplateColumns: {
194 base: "1fr",
195 sm: "repeat(2, 1fr)",
196 },
197 gap: "6",
198 })}
199 >
200 <div
201 className={css({
202 display: "flex",
203 flexDirection: "column",
204 gap: "1",
205 })}
206 >
207 <dt className={css({ color: "fg.muted", fontSize: "sm" })}>
208 Amount borrowed
209 </dt>
210 <dd className={css({ margin: "0", fontWeight: "semibold" })}>
211 {formatCurrency(contract.principal)}
212 </dd>
213 </div>
214 <div
215 className={css({
216 display: "flex",
217 flexDirection: "column",
218 gap: "1",
219 })}
220 >
221 <dt className={css({ color: "fg.muted", fontSize: "sm" })}>
222 Monthly payment
223 </dt>
224 <dd className={css({ margin: "0", fontWeight: "semibold" })}>
225 {formatCurrency(contract.monthlyPayment)}
226 </dd>
227 </div>
228 <div
229 className={css({
230 display: "flex",
231 flexDirection: "column",
232 gap: "1",
233 })}
234 >
235 <dt className={css({ color: "fg.muted", fontSize: "sm" })}>
236 Nominal interest rate
237 </dt>
238 <dd className={css({ margin: "0", fontWeight: "semibold" })}>
239 {(contract.nominalRate * 100).toFixed(2)}%
240 </dd>
241 </div>
242 <div
243 className={css({
244 display: "flex",
245 flexDirection: "column",
246 gap: "1",
247 })}
248 >
249 <dt className={css({ color: "fg.muted", fontSize: "sm" })}>
250 APR
251 </dt>
252 <dd className={css({ margin: "0", fontWeight: "semibold" })}>
253 {(contract.apr * 100).toFixed(2)}%
254 </dd>
255 </div>
256 <div
257 className={css({
258 display: "flex",
259 flexDirection: "column",
260 gap: "1",
261 })}
262 >
263 <dt className={css({ color: "fg.muted", fontSize: "sm" })}>
264 Term
265 </dt>
266 <dd className={css({ margin: "0", fontWeight: "semibold" })}>
267 {contract.termMonths} months
268 </dd>
269 </div>
270 <div
271 className={css({
272 display: "flex",
273 flexDirection: "column",
274 gap: "1",
275 })}
276 >
277 <dt className={css({ color: "fg.muted", fontSize: "sm" })}>
278 Start date
279 </dt>
280 <dd className={css({ margin: "0", fontWeight: "semibold" })}>
281 <time dateTime={contract.startDate}>
282 {formatDate(contract.startDate)}
283 </time>
284 </dd>
285 </div>
286 </dl>
287 </CardBody>
288 </Card>
289
290 <Card className={css({ height: "full" })}>
291 <CardHeader>
292 <CardTitle asChild>
293 <h2>Outstanding balance</h2>
294 </CardTitle>
295 <CardDescription>
296 The amount still owed on this contract.
297 </CardDescription>
298 </CardHeader>
299 <CardBody>
300 <div
301 className={css({
302 display: "flex",
303 flexDirection: "column",
304 gap: "6",
305 })}
306 >
307 <data
308 value={contract.outstanding}
309 className={css({
310 fontSize: "lg",
311 lineHeight: "tight",
312 fontWeight: "semibold",
313 })}
314 >
315 {formatCurrency(contract.outstanding)}
316 </data>
317
318 <div
319 className={css({
320 display: "flex",
321 flexDirection: "column",
322 gap: "2",
323 })}
324 >
325 <div
326 className={css({
327 display: "flex",
328 justifyContent: "space-between",
329 gap: "3",
330 fontSize: "sm",
331 })}
332 >
333 <span className={css({ color: "fg.muted" })}>
334 Principal repaid
335 </span>
336 <span className={css({ fontWeight: "medium" })}>
337 {formatCurrency(repaidAmount)}
338 </span>
339 </div>
340 <progress
341 aria-label={`${repaidPercentage.toFixed(1)}% of principal repaid`}
342 max={contract.principal}
343 value={repaidAmount}
344 className={css({
345 display: "block",
346 width: "full",
347 height: "2",
348 accentColor: "accent.default",
349 })}
350 >
351 {repaidPercentage.toFixed(1)}%
352 </progress>
353 <span className={css({ color: "fg.muted", fontSize: "xs" })}>
354 {repaidPercentage.toFixed(1)}% of the amount borrowed
355 </span>
356 </div>
357
358 {nextInstalment ? (
359 <div
360 className={css({
361 borderTopWidth: "thin",
362 borderColor: "border.default",
363 paddingTop: "4",
364 display: "flex",
365 flexDirection: "column",
366 gap: "3",
367 })}
368 >
369 <div
370 className={css({
371 display: "flex",
372 alignItems: "center",
373 justifyContent: "space-between",
374 gap: "3",
375 })}
376 >
377 <span
378 className={css({ color: "fg.muted", fontSize: "sm" })}
379 >
380 Next instalment
381 </span>
382 <Badge tone="warning">Due</Badge>
383 </div>
384 <div
385 className={css({
386 display: "flex",
387 alignItems: "center",
388 justifyContent: "space-between",
389 gap: "3",
390 })}
391 >
392 <time
393 dateTime={nextInstalment.dueDate}
394 className={css({ fontSize: "sm" })}
395 >
396 {formatDate(nextInstalment.dueDate)}
397 </time>
398 <span className={css({ fontWeight: "semibold" })}>
399 {formatCurrency(nextInstalment.payment)}
400 </span>
401 </div>
402 </div>
403 ) : null}
404 </div>
405 </CardBody>
406 </Card>
407 </section>
408
409 <Card>
410 <CardHeader>
411 <CardTitle asChild>
412 <h2>Repayment schedule</h2>
413 </CardTitle>
414 <CardDescription>
415 Showing {data.schedule.length} of {contract.termMonths} scheduled
416 instalments. All amounts are in {contract.currency}.
417 </CardDescription>
418 </CardHeader>
419 <div
420 className={css({
421 width: "full",
422 overflowX: "auto",
423 marginBlockStart: "4",
424 })}
425 >
426 <Table
427 aria-label={`Repayment schedule for contract ${contract.number}`}
428 className={css({ width: "full", whiteSpace: "nowrap" })}
429 >
430 <TableHead>
431 <TableRow>
432 <TableHeader numeric>Instalment</TableHeader>
433 <TableHeader>Due date</TableHeader>
434 <TableHeader numeric>Payment</TableHeader>
435 <TableHeader numeric>Principal</TableHeader>
436 <TableHeader numeric>Interest</TableHeader>
437 <TableHeader numeric>Balance after payment</TableHeader>
438 <TableHeader>Status</TableHeader>
439 </TableRow>
440 </TableHead>
441 <TableBody>
442 {data.schedule.map((instalment) => {
443 const status = statusDetails[instalment.status] ?? {
444 label: instalment.status,
445 tone: "neutral" as const,
446 };
447
448 return (
449 <TableRow key={instalment.number}>
450 <TableCell numeric>{instalment.number}</TableCell>
451 <TableCell>
452 <time dateTime={instalment.dueDate}>
453 {formatDate(instalment.dueDate)}
454 </time>
455 </TableCell>
456 <TableCell
457 numeric
458 className={css({ fontWeight: "medium" })}
459 >
460 {formatCurrency(instalment.payment)}
461 </TableCell>
462 <TableCell numeric>
463 {formatCurrency(instalment.principal)}
464 </TableCell>
465 <TableCell numeric>
466 {formatCurrency(instalment.interest)}
467 </TableCell>
468 <TableCell
469 numeric
470 className={css({ fontWeight: "medium" })}
471 >
472 {formatCurrency(instalment.remaining)}
473 </TableCell>
474 <TableCell>
475 <Badge tone={status.tone}>{status.label}</Badge>
476 </TableCell>
477 </TableRow>
478 );
479 })}
480 </TableBody>
481 </Table>
482 </div>
483 </Card>
484
485 <Card>
486 <CardHeader>
487 <CardTitle asChild>
488 <h2>Signed documents</h2>
489 </CardTitle>
490 <CardDescription>
491 {data.documents.length} documents signed for this contract.
492 </CardDescription>
493 </CardHeader>
494 <CardBody>
495 <ul
496 className={css({
497 listStyle: "none",
498 margin: "0",
499 padding: "0",
500 display: "grid",
501 gridTemplateColumns: {
502 base: "1fr",
503 md: "repeat(3, 1fr)",
504 },
505 gap: "3",
506 })}
507 >
508 {data.documents.map((document) => (
509 <li
510 key={document.name}
511 className={css({
512 display: "flex",
513 alignItems: "center",
514 gap: "3",
515 padding: "4",
516 rounded: "md",
517 bg: "bg.subtle",
518 })}
519 >
520 <DocumentIcon />
521 <div
522 className={css({
523 display: "flex",
524 flexDirection: "column",
525 gap: "1",
526 })}
527 >
528 <span className={css({ fontWeight: "medium" })}>
529 {document.name}
530 </span>
531 <span
532 className={css({ color: "fg.muted", fontSize: "sm" })}
533 >
534 Signed{" "}
535 <time dateTime={document.signedAt}>
536 {formatDate(document.signedAt)}
537 </time>
538 </span>
539 </div>
540 <CheckIcon />
541 </li>
542 ))}
543 </ul>
544 </CardBody>
545 </Card>
546 </main>
547 </div>
548 );
549 }
550
lint/@pandacss(no-physical-properties)
2 quality
4 check_code 9,957 3,694 $0.0584
5 write_file 3,813 4,115 $0.0523