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 35 counted, under 5 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-storybook-story-instructions 3 18 $0.0001 1 docs-list 3 20 $0.0002 2 list_files, read_file, docs-show, docs-show, docs-show 3 114 $0.0002
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 formatMoney = (amount: number) =>
19 new Intl.NumberFormat("en-IE", {
20 style: "currency",
21 currency: data.contract.currency,
22 }).format(amount);
23
24 const formatDate = (date: string) =>
25 new Intl.DateTimeFormat("en-GB", {
26 day: "numeric",
27 month: "short",
28 year: "numeric",
29 }).format(new Date(`${date}T00:00:00`));
30
31 const terms = [
32 { label: "Amount borrowed", value: formatMoney(data.contract.principal) },
33 { label: "Nominal interest rate", value: `${(data.contract.nominalRate * 100).toFixed(2)}%` },
34 { label: "APR", value: `${(data.contract.apr * 100).toFixed(2)}%` },
35 { label: "Term", value: `${data.contract.termMonths} months` },
36 { label: "Monthly payment", value: formatMoney(data.contract.monthlyPayment) },
37 { label: "Start date", value: formatDate(data.contract.startDate) },
38 ];
39
40 const scheduleStatus = {
41 paid: { label: "Paid", tone: "success" as const },
42 due: { label: "Due", tone: "warning" as const },
43 upcoming: { label: "Upcoming", tone: "neutral" as const },
44 };
45
46 export default function Page() {
47 return (
48 <main className={css({ minHeight: "100vh", bg: "gray.50", color: "gray.900", py: { base: "8", md: "12" }, px: { base: "4", md: "8" } })}>
49 <div className={css({ maxW: "1120px", mx: "auto" })}>
50 <nav aria-label="Breadcrumb" className={css({ mb: "6", fontSize: "sm", color: "gray.500" })}>
51 <span>Loans</span>
52 <span aria-hidden="true" className={css({ mx: "2" })}>/</span>
53 <span className={css({ color: "gray.700" })}>Contract details</span>
54 </nav>
55
56 <header className={css({ display: "flex", flexWrap: "wrap", alignItems: "flex-start", justifyContent: "space-between", gap: "4", mb: "8" })}>
57 <div>
58 <p className={css({ mb: "2", fontSize: "sm", fontWeight: "medium", color: "gray.500" })}>PERSONAL LOAN</p>
59 <h1 className={css({ fontSize: { base: "2xl", md: "3xl" }, lineHeight: "1.2", fontWeight: "bold", letterSpacing: "-0.02em" })}>
60 {data.contract.product}
61 </h1>
62 <p className={css({ mt: "2", fontSize: "sm", color: "gray.600" })}>
63 Contract <span className={css({ fontWeight: "semibold", color: "gray.800" })}>{data.contract.number}</span>
64 <span aria-hidden="true" className={css({ mx: "2" })}>·</span>
65 {data.contract.borrower}
66 </p>
67 </div>
68 <div className={css({ pt: { base: "0", md: "2" } })}>
69 <Badge tone={data.contract.status === "active" ? "success" : "neutral"}>
70 {data.contract.status.charAt(0).toUpperCase() + data.contract.status.slice(1)}
71 </Badge>
72 </div>
73 </header>
74
75 <section aria-labelledby="overview-heading" className={css({ mb: "8" })}>
76 <h2 id="overview-heading" className={css({ mb: "4", fontSize: "lg", fontWeight: "semibold" })}>Loan overview</h2>
77 <div className={css({ display: "grid", gridTemplateColumns: { base: "1fr", sm: "repeat(2, minmax(0, 1fr))", lg: "repeat(4, minmax(0, 1fr))" }, gap: "4" })}>
78 {terms.map((term) => (
79 <Card key={term.label}>
80 <CardBody>
81 <p className={css({ fontSize: "sm", color: "gray.500" })}>{term.label}</p>
82 <p className={css({ mt: "2", fontSize: "lg", fontWeight: "semibold", color: "gray.900", fontVariantNumeric: "tabular-nums" })}>{term.value}</p>
83 </CardBody>
84 </Card>
85 ))}
86 <Card>
87 <CardBody>
88 <p className={css({ fontSize: "sm", color: "gray.500" })}>Still owed</p>
89 <p className={css({ mt: "2", fontSize: "lg", fontWeight: "bold", color: "blue.700", fontVariantNumeric: "tabular-nums" })}>{formatMoney(data.contract.outstanding)}</p>
90 </CardBody>
91 </Card>
92 </div>
93 </section>
94
95 <section aria-labelledby="schedule-heading" className={css({ mb: "8" })}>
96 <Card>
97 <CardHeader>
98 <CardTitle asChild><h2 id="schedule-heading">Repayment schedule</h2></CardTitle>
99 <CardDescription>Instalment breakdown and remaining balance.</CardDescription>
100 </CardHeader>
101 <div className={css({ overflowX: "auto" })}>
102 <Table aria-label="Repayment schedule">
103 <TableHead>
104 <TableRow>
105 <TableHeader>Instalment</TableHeader>
106 <TableHeader>Due date</TableHeader>
107 <TableHeader numeric>Payment</TableHeader>
108 <TableHeader numeric>Principal</TableHeader>
109 <TableHeader numeric>Interest</TableHeader>
110 <TableHeader numeric>Balance left</TableHeader>
111 <TableHeader>Status</TableHeader>
112 </TableRow>
113 </TableHead>
114 <TableBody>
115 {data.schedule.map((instalment) => {
116 const status = scheduleStatus[instalment.status as keyof typeof scheduleStatus];
117 return (
118 <TableRow key={instalment.number}>
119 <TableCell>#{instalment.number}</TableCell>
120 <TableCell>{formatDate(instalment.dueDate)}</TableCell>
121 <TableCell numeric>{formatMoney(instalment.payment)}</TableCell>
122 <TableCell numeric>{formatMoney(instalment.principal)}</TableCell>
123 <TableCell numeric>{formatMoney(instalment.interest)}</TableCell>
124 <TableCell numeric>{formatMoney(instalment.remaining)}</TableCell>
125 <TableCell><Badge tone={status.tone}>{status.label}</Badge></TableCell>
126 </TableRow>
127 );
128 })}
129 </TableBody>
130 </Table>
131 </div>
132 </Card>
133 </section>
134
135 <section aria-labelledby="documents-heading">
136 <Card>
137 <CardHeader>
138 <CardTitle asChild><h2 id="documents-heading">Signed documents</h2></CardTitle>
139 <CardDescription>Documents signed for this contract.</CardDescription>
140 </CardHeader>
141 <CardBody>
142 <ul className={css({ display: "grid", gap: "0" })}>
143 {data.documents.map((document) => (
144 <li key={document.name} className={css({ display: "flex", flexWrap: "wrap", justifyContent: "space-between", alignItems: "center", gap: "2", py: "4", borderTopWidth: "1px", borderColor: "gray.200", _first: { borderTopWidth: "0", pt: "0" }, _last: { pb: "0" } })}>
145 <span className={css({ fontWeight: "medium", color: "gray.800" })}>{document.name}</span>
146 <time dateTime={document.signedAt} className={css({ fontSize: "sm", color: "gray.500" })}>{formatDate(document.signedAt)}</time>
147 </li>
148 ))}
149 </ul>
150 </CardBody>
151 </Card>
152 </section>
153 </div>
154 </main>
155 );
156 }
157
Use the logical property "marginBlockStart" instead of the physical "marginTop".
page.tsx:89:37 Use the logical property "marginBlockStart" instead of the physical "marginTop". page.tsx:95:70 Use the logical property "marginBlockEnd" instead of the physical "marginBottom". page.tsx:144:169 Use the logical property "borderBlockStartWidth" instead of the physical "borderTopWidth". page.tsx:144:227 Use the logical property "borderBlockStartWidth" instead of the physical "borderTopWidth". page.tsx:144:248 Use the logical property "paddingBlockStart" instead of the physical "paddingTop". page.tsx:144:268 Use the logical property "paddingBlockEnd" instead of the physical "paddingBottom". token-roles/palette 14 design-system page.tsx:48:52 · gray.50 `gray.50` is a palette shade: it ignores the theme. Use a semantic color token. page.tsx:48:70 · gray.900 `gray.900` is a palette shade: it ignores the theme. Use a semantic color token. page.tsx:50:87 · gray.500 `gray.500` is a palette shade: it ignores the theme. Use a semantic color token. page.tsx:53:41 · gray.700 `gray.700` is a palette shade: it ignores the theme. Use a semantic color token. page.tsx:58:87 · gray.500 `gray.500` is a palette shade: it ignores the theme. Use a semantic color token. page.tsx:62:65 · gray.600 `gray.600` is a palette shade: it ignores the theme. Use a semantic color token. page.tsx:63:78 · gray.800 `gray.800` is a palette shade: it ignores the theme. Use a semantic color token. page.tsx:81:62 · gray.500 `gray.500` is a palette shade: it ignores the theme. Use a semantic color token. page.tsx:82:95 · gray.900 `gray.900` is a palette shade: it ignores the theme. Use a semantic color token. page.tsx:88:60 · gray.500 `gray.500` is a palette shade: it ignores the theme. Use a semantic color token. page.tsx:89:89 · blue.700 `blue.700` is a palette shade: it ignores the theme. Use a semantic color token. page.tsx:144:205 · gray.200 `gray.200` is a palette shade: it ignores the theme. Use a semantic color token. page.tsx:145:73 · gray.800 `gray.800` is a palette shade: it ignores the theme. Use a semantic color token. page.tsx:146:96 · gray.500 `gray.500` is a palette shade: it ignores the theme. Use a semantic color token. Every run that broke token-roles/palette raw-values/raw-length 4 design-system typecheck/TS2769 2 quality 4 stories-changed 3 59 $0.0005
5 stories-find-by-component 3 78 $0.0002
7 stories-find-by-component 3 247 $0.0002