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 18 counted, under 3 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 docs-list 3,396 152 $0.0083 1 list_files, docs-show, docs-show, docs-show, docs-show, docs-show 798 208 $0.0044 2 read_file 3,993 64 $0.0095
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
17 import data from "./fixture.json";
18
19 const currencyFormatter = new Intl.NumberFormat("en-IE", {
20 style: "currency",
21 currency: data.contract.currency,
22 minimumFractionDigits: 2,
23 maximumFractionDigits: 2,
24 });
25
26 const dateFormatter = new Intl.DateTimeFormat("en-GB", {
27 day: "2-digit",
28 month: "short",
29 year: "numeric",
30 timeZone: "UTC",
31 });
32
33 const statusLabels: Record<string, string> = {
34 active: "Active",
35 paid: "Paid",
36 due: "Due",
37 upcoming: "Upcoming",
38 };
39
40 function formatCurrency(value: number) {
41 return currencyFormatter.format(value);
42 }
43
44 function formatDate(value: string) {
45 return dateFormatter.format(new Date(`${value}T00:00:00Z`));
46 }
47
48 function formatRate(value: number) {
49 return `${(value * 100).toFixed(2)}%`;
50 }
51
52 function statusTone(status: string): "success" | "warning" | "neutral" {
53 if (status === "paid" || status === "active") return "success";
54 if (status === "due") return "warning";
55 return "neutral";
56 }
57
58 function statusLabel(status: string) {
59 return statusLabels[status] ?? status.charAt(0).toUpperCase() + status.slice(1);
60 }
61
62 const pageStyles = css({
63 bg: "bg.canvas",
64 color: "fg.default",
65 minHeight: "100vh",
66 });
67
68 const contentStyles = css({
69 width: "full",
70 maxWidth: "7xl",
71 mx: "auto",
72 px: { base: "4", md: "6", lg: "8" },
73 py: { base: "6", md: "10" },
74 });
75
76 const eyebrowStyles = css({
77 color: "fg.muted",
78 fontSize: "sm",
79 fontWeight: "medium",
80 });
81
82 const titleStyles = css({
83 fontSize: { base: "2xl", md: "3xl" },
84 fontWeight: "semibold",
85 lineHeight: "tight",
86 });
87
88 const metaStyles = css({
89 color: "fg.muted",
90 fontSize: "sm",
91 });
92
93 const sectionTitleStyles = css({
94 fontSize: "lg",
95 fontWeight: "semibold",
96 });
97
98 const termLabelStyles = css({
99 color: "fg.muted",
100 fontSize: "sm",
101 });
102
103 const termValueStyles = css({
104 color: "fg.default",
105 fontSize: "lg",
106 fontWeight: "semibold",
107 lineHeight: "tight",
108 });
109
110 const outstandingStyles = css({
111 color: "fg.default",
112 fontSize: { base: "3xl", md: "4xl" },
113 fontWeight: "semibold",
114 lineHeight: "tight",
115 fontVariantNumeric: "tabular-nums",
116 });
117
118 const documentIconStyles = css({
119 display: "flex",
120 alignItems: "center",
121 justifyContent: "center",
122 flexShrink: "0",
123 width: "10",
124 height: "10",
125 rounded: "md",
126 bg: "accent.subtle",
127 color: "fg.default",
128 });
129
130 function DocumentIcon() {
131 return (
132 <svg
133 aria-hidden="true"
134 className={css({ width: "5", height: "5" })}
135 fill="none"
136 viewBox="0 0 24 24"
137 stroke="currentColor"
138 strokeWidth="1.8"
139 strokeLinecap="round"
140 strokeLinejoin="round"
141 >
142 <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z" />
143 <path d="M14 2v6h6M8 13h8M8 17h5" />
144 </svg>
145 );
146 }
147
148 export default function PersonalLoanContractPage() {
149 const { contract } = data;
150 const dueCount = data.schedule.filter((instalment) => instalment.status === "due").length;
151 const terms = [
152 { label: "Amount borrowed", value: formatCurrency(contract.principal) },
153 { label: "Nominal interest rate", value: formatRate(contract.nominalRate) },
154 { label: "APR", value: formatRate(contract.apr) },
155 { label: "Term", value: `${contract.termMonths} months` },
156 { label: "Monthly payment", value: formatCurrency(contract.monthlyPayment) },
157 { label: "Start date", value: formatDate(contract.startDate), date: contract.startDate },
158 ];
159
160 return (
161 <div className={`vektos ${pageStyles}`}>
162 <main className={contentStyles}>
163 <header
164 className={css({
165 display: "flex",
166 flexDirection: "column",
167 gap: "3",
168 marginBottom: { base: "6", md: "8" },
169 })}
170 >
171 <p className={eyebrowStyles}>Loan contract</p>
172 <div className={css({ display: "flex", alignItems: "center", flexWrap: "wrap", gap: "3" })}>
173 <h1 className={titleStyles}>{contract.product}</h1>
174 <Badge tone={statusTone(contract.status)}>{statusLabel(contract.status)}</Badge>
175 </div>
176 <p className={metaStyles}>
177 Contract <span className={css({ fontFamily: "mono", color: "fg.default" })}>{contract.number}</span>
178 <span aria-hidden="true"> · </span>
179 {contract.borrower}
180 </p>
181 </header>
182
183 <div className={css({ display: "flex", flexDirection: "column", gap: { base: "6", md: "8" } })}>
184 <section
185 aria-label="Loan terms and outstanding balance"
186 className={css({
187 display: "grid",
188 gridTemplateColumns: { base: "1fr", lg: "minmax(0, 2fr) minmax(0, 1fr)" },
189 gap: { base: "4", md: "6" },
190 alignItems: "stretch",
191 })}
192 >
193 <Card>
194 <CardHeader>
195 <CardTitle asChild>
196 <h2 className={sectionTitleStyles}>Key terms</h2>
197 </CardTitle>
198 <CardDescription>The agreed terms for this personal loan.</CardDescription>
199 </CardHeader>
200 <CardBody>
201 <dl
202 className={css({
203 display: "grid",
204 gridTemplateColumns: {
205 base: "1fr",
206 sm: "repeat(2, minmax(0, 1fr))",
207 md: "repeat(3, minmax(0, 1fr))",
208 },
209 gap: { base: "5", md: "6" },
210 })}
211 >
212 {terms.map((term) => (
213 <div key={term.label} className={css({ display: "flex", flexDirection: "column", gap: "2" })}>
214 <dt className={termLabelStyles}>{term.label}</dt>
215 <dd className={termValueStyles}>
216 {term.date ? <time dateTime={term.date}>{term.value}</time> : term.value}
217 </dd>
218 </div>
219 ))}
220 </dl>
221 </CardBody>
222 </Card>
223
224 <Card>
225 <CardHeader>
226 <CardTitle asChild>
227 <h2 className={sectionTitleStyles}>Outstanding balance</h2>
228 </CardTitle>
229 <CardDescription>The amount still owed on this contract.</CardDescription>
230 </CardHeader>
231 <CardBody className={css({ display: "flex", flexDirection: "column", gap: "3" })}>
232 <p className={outstandingStyles}>{formatCurrency(contract.outstanding)}</p>
233 <p className={metaStyles}>Outstanding principal in {contract.currency}</p>
234 </CardBody>
235 </Card>
236 </section>
237
238 <section aria-labelledby="repayment-schedule-title">
239 <Card>
240 <CardHeader>
241 <CardTitle asChild>
242 <h2 id="repayment-schedule-title" className={sectionTitleStyles}>
243 Repayment schedule
244 </h2>
245 </CardTitle>
246 <CardDescription>
247 {data.schedule.length} of {contract.termMonths} instalments shown
248 {dueCount > 0 ? ` · ${dueCount} ${dueCount === 1 ? "payment" : "payments"} due` : ""}
249 </CardDescription>
250 </CardHeader>
251 <div className={css({ overflowX: "auto" })}>
252 <Table
253 aria-label="Personal loan repayment schedule"
254 className={css({ minWidth: "5xl", marginBlockStart: "4" })}
255 >
256 <TableHead>
257 <TableRow>
258 <TableHeader numeric>No.</TableHeader>
259 <TableHeader>Due date</TableHeader>
260 <TableHeader numeric>Payment</TableHeader>
261 <TableHeader numeric>Principal</TableHeader>
262 <TableHeader numeric>Interest</TableHeader>
263 <TableHeader numeric>Remaining balance</TableHeader>
264 <TableHeader>Status</TableHeader>
265 </TableRow>
266 </TableHead>
267 <TableBody>
268 {data.schedule.map((instalment) => (
269 <TableRow key={instalment.number}>
270 <TableCell numeric>{instalment.number}</TableCell>
271 <TableCell>
272 <time dateTime={instalment.dueDate}>{formatDate(instalment.dueDate)}</time>
273 </TableCell>
274 <TableCell numeric>{formatCurrency(instalment.payment)}</TableCell>
275 <TableCell numeric>{formatCurrency(instalment.principal)}</TableCell>
276 <TableCell numeric>{formatCurrency(instalment.interest)}</TableCell>
277 <TableCell numeric>{formatCurrency(instalment.remaining)}</TableCell>
278 <TableCell>
279 <Badge tone={statusTone(instalment.status)}>{statusLabel(instalment.status)}</Badge>
280 </TableCell>
281 </TableRow>
282 ))}
283 </TableBody>
284 </Table>
285 </div>
286 </Card>
287 </section>
288
289 <section aria-labelledby="signed-documents-title">
290 <Card>
291 <CardHeader>
292 <CardTitle asChild>
293 <h2 id="signed-documents-title" className={sectionTitleStyles}>
294 Signed documents
295 </h2>
296 </CardTitle>
297 <CardDescription>
298 {data.documents.length} documents signed for this contract.
299 </CardDescription>
300 </CardHeader>
301 <CardBody>
302 <ul className={css({ display: "flex", flexDirection: "column", gap: "4" })}>
303 {data.documents.map((document) => (
304 <li
305 key={document.name}
306 className={css({ display: "flex", alignItems: "center", gap: "3" })}
307 >
308 <span aria-hidden="true" className={documentIconStyles}>
309 <DocumentIcon />
310 </span>
311 <div className={css({ flex: "1", minWidth: "0" })}>
312 <p className={css({ fontWeight: "medium" })}>{document.name}</p>
313 <p className={metaStyles}>
314 Signed <time dateTime={document.signedAt}>{formatDate(document.signedAt)}</time>
315 </p>
316 </div>
317 <Badge tone="success">Signed</Badge>
318 </li>
319 ))}
320 </ul>
321 </CardBody>
322 </Card>
323 </section>
324 </div>
325 </main>
326 </div>
327 );
328 }
329
No overload matches this call.
raw-values/raw-length 1 design-system get-storybook-story-instructions
4 write_file 2,242 8,801 $0.0943
5 stories-changed 8,842 77 $0.0207
6 stories-find-by-component 137 156 $0.0058