@pennyfarthing/benchmark 10.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/commands/benchmark-control.md +69 -0
  2. package/commands/benchmark.md +485 -0
  3. package/commands/job-fair.md +102 -0
  4. package/commands/solo.md +447 -0
  5. package/dist/benchmark-integration.d.ts +182 -0
  6. package/dist/benchmark-integration.d.ts.map +1 -0
  7. package/dist/benchmark-integration.js +710 -0
  8. package/dist/benchmark-integration.js.map +1 -0
  9. package/dist/benchmark-integration.test.d.ts +6 -0
  10. package/dist/benchmark-integration.test.d.ts.map +1 -0
  11. package/dist/benchmark-integration.test.js +41 -0
  12. package/dist/benchmark-integration.test.js.map +1 -0
  13. package/dist/index.d.ts +3 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +5 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/job-fair-aggregator.d.ts +150 -0
  18. package/dist/job-fair-aggregator.d.ts.map +1 -0
  19. package/dist/job-fair-aggregator.js +547 -0
  20. package/dist/job-fair-aggregator.js.map +1 -0
  21. package/dist/job-fair-aggregator.test.d.ts +6 -0
  22. package/dist/job-fair-aggregator.test.d.ts.map +1 -0
  23. package/dist/job-fair-aggregator.test.js +35 -0
  24. package/dist/job-fair-aggregator.test.js.map +1 -0
  25. package/dist/package-exports.test.d.ts +13 -0
  26. package/dist/package-exports.test.d.ts.map +1 -0
  27. package/dist/package-exports.test.js +192 -0
  28. package/dist/package-exports.test.js.map +1 -0
  29. package/docs/BENCHMARK-METHODOLOGY.md +105 -0
  30. package/docs/BENCHMARKING.md +311 -0
  31. package/docs/OCEAN-BENCHMARKING.md +210 -0
  32. package/docs/benchmarks-guide.md +62 -0
  33. package/package.json +66 -0
  34. package/scenarios/README.md +145 -0
  35. package/scenarios/architecture/database-selection.yaml +119 -0
  36. package/scenarios/architecture/legacy-modernization.yaml +153 -0
  37. package/scenarios/architecture/scaling-decision.yaml +88 -0
  38. package/scenarios/code-review/graphql-api-review.yaml +714 -0
  39. package/scenarios/code-review/order-service.yaml +622 -0
  40. package/scenarios/code-review/react-auth-component.yaml +569 -0
  41. package/scenarios/code-review/security-review.yaml +145 -0
  42. package/scenarios/code-review/terraform-infrastructure.yaml +582 -0
  43. package/scenarios/debug/buggy-user-service.yaml +541 -0
  44. package/scenarios/debug/null-pointer.yaml +130 -0
  45. package/scenarios/debugging/async-control-flow.yaml +161 -0
  46. package/scenarios/debugging/auth-bypass.yaml +197 -0
  47. package/scenarios/debugging/error-handling.yaml +178 -0
  48. package/scenarios/debugging/input-validation.yaml +157 -0
  49. package/scenarios/debugging/null-check-missing.yaml +139 -0
  50. package/scenarios/debugging/off-by-one-loop.yaml +132 -0
  51. package/scenarios/debugging/race-condition.yaml +180 -0
  52. package/scenarios/debugging/resource-leak.yaml +166 -0
  53. package/scenarios/debugging/simple-logic-error.yaml +115 -0
  54. package/scenarios/debugging/sql-injection.yaml +163 -0
  55. package/scenarios/dev/event-processor-tdd.yaml +764 -0
  56. package/scenarios/dev/migration-disaster.yaml +415 -0
  57. package/scenarios/dev/race-condition-cache.yaml +546 -0
  58. package/scenarios/dev/tdd-shopping-cart.yaml +681 -0
  59. package/scenarios/schema.yaml +639 -0
  60. package/scenarios/sm/dependency-deadlock.yaml +414 -0
  61. package/scenarios/sm/executive-pet-project.yaml +336 -0
  62. package/scenarios/sm/layoff-planning.yaml +356 -0
  63. package/scenarios/sm/sprint-planning-conflict.yaml +303 -0
  64. package/scenarios/sm/story-breakdown.yaml +240 -0
  65. package/scenarios/sm/three-sprint-failure.yaml +397 -0
  66. package/scenarios/swe-bench/README.md +57 -0
  67. package/scenarios/swe-bench/astropy-12907.yaml +128 -0
  68. package/scenarios/swe-bench/astropy-13398.yaml +177 -0
  69. package/scenarios/swe-bench/astropy-14309.yaml +180 -0
  70. package/scenarios/swe-bench/django-10097.yaml +106 -0
  71. package/scenarios/swe-bench/django-10554.yaml +140 -0
  72. package/scenarios/swe-bench/django-10973.yaml +93 -0
  73. package/scenarios/swe-bench/flask-5014-reviewer.yaml +145 -0
  74. package/scenarios/swe-bench/flask-5014-tea.yaml +123 -0
  75. package/scenarios/swe-bench/flask-5014.yaml +91 -0
  76. package/scenarios/swe-bench/import-swebench.py +246 -0
  77. package/scenarios/swe-bench/matplotlib-13989.yaml +139 -0
  78. package/scenarios/swe-bench/matplotlib-14623.yaml +127 -0
  79. package/scenarios/swe-bench/requests-1142-reviewer.yaml +144 -0
  80. package/scenarios/swe-bench/requests-1142-tea.yaml +135 -0
  81. package/scenarios/swe-bench/requests-1142.yaml +100 -0
  82. package/scenarios/swe-bench/requests-2931.yaml +98 -0
  83. package/scenarios/swe-bench/seaborn-3069.yaml +102 -0
  84. package/scenarios/swe-bench/sphinx-7590.yaml +108 -0
  85. package/scenarios/swe-bench/xarray-3993.yaml +104 -0
  86. package/scenarios/swe-bench/xarray-6992.yaml +136 -0
  87. package/scenarios/tea/checkout-component-tests.yaml +596 -0
  88. package/scenarios/tea/cli-tool-tests.yaml +561 -0
  89. package/scenarios/tea/microservice-integration-tests.yaml +520 -0
  90. package/scenarios/tea/payment-processor-tests.yaml +550 -0
  91. package/scripts/aggregate-benchmark-stats.js +315 -0
  92. package/scripts/aggregate-benchmark-stats.sh +8 -0
  93. package/scripts/benchmark-runner.js +392 -0
  94. package/scripts/benchmark-runner.sh +8 -0
  95. package/scripts/consolidate-job-fair.sh +107 -0
  96. package/scripts/convert-jobfair-to-benchmarks.sh +230 -0
  97. package/scripts/job-fair-batch.sh +116 -0
  98. package/scripts/job-fair-progress.sh +35 -0
  99. package/scripts/job-fair-runner.sh +278 -0
  100. package/scripts/job-fair-status.sh +80 -0
  101. package/scripts/job-fair-watcher-v2.sh +38 -0
  102. package/scripts/job-fair-watcher.sh +50 -0
  103. package/scripts/parallel-benchmark.sh +140 -0
  104. package/scripts/solo-runner.sh +344 -0
  105. package/scripts/test/ensure-swebench-data.sh +59 -0
  106. package/scripts/test/ground-truth-judge.py +220 -0
  107. package/scripts/test/swebench-judge.py +374 -0
  108. package/scripts/test/test-cache.sh +165 -0
  109. package/scripts/test/test-setup.sh +337 -0
  110. package/scripts/theme/compute-theme-tiers.sh +13 -0
  111. package/scripts/theme/compute_theme_tiers.py +402 -0
  112. package/scripts/theme/update-theme-tiers.sh +97 -0
  113. package/skills/finalize-run/SKILL.md +261 -0
  114. package/skills/judge/SKILL.md +644 -0
  115. package/skills/persona-benchmark/SKILL.md +187 -0
@@ -0,0 +1,596 @@
1
+ ---
2
+ # Scenario: React Checkout Component Test Suite
3
+ # Category: tea
4
+ # Purpose: Test frontend component test writing skills
5
+
6
+ id: tea-002
7
+ name: checkout-component-tests
8
+ title: "React Checkout Component Test Suite"
9
+ category: tea
10
+ difficulty: easy # Empirical: control mean 82.35 (easiest)
11
+ version: "1.0"
12
+
13
+ description: |
14
+ An e-commerce checkout component with form validation, payment integration,
15
+ and address autocomplete. TEA must write a comprehensive test suite covering
16
+ user interactions, error states, loading states, and accessibility. Tests
17
+ frontend testing expertise and React Testing Library proficiency.
18
+
19
+ purpose: |
20
+ This scenario tests frontend testing philosophy. A "thorough" persona might
21
+ write more edge case tests. A "pragmatic" persona might focus on happy paths.
22
+ Measures test coverage strategy and React testing patterns.
23
+
24
+ prompt: |
25
+ You are a Test Engineer reviewing an e-commerce checkout component.
26
+ Write a comprehensive test suite using React Testing Library and Vitest.
27
+
28
+ The component has these features:
29
+ - Multi-step form (shipping, payment, review)
30
+ - Form validation with inline error messages
31
+ - Address autocomplete integration
32
+ - Credit card input with formatting
33
+ - Loading states during submission
34
+ - Order confirmation display
35
+ - Error handling for failed payments
36
+
37
+ Write tests covering:
38
+ 1. Happy path - complete checkout flow
39
+ 2. Form validation for each field
40
+ 3. Error states and recovery
41
+ 4. Loading and disabled states
42
+ 5. Accessibility requirements
43
+ 6. Edge cases (empty cart, session timeout, etc.)
44
+
45
+ For each test:
46
+ 1. Use descriptive test names
47
+ 2. Follow AAA pattern (Arrange, Act, Assert)
48
+ 3. Use Testing Library best practices (getByRole, userEvent)
49
+ 4. Include accessibility checks
50
+
51
+ IMPORTANT: Focus on behavior, not implementation details.
52
+
53
+ code:
54
+ language: typescript
55
+ filename: Checkout.tsx
56
+ content: |
57
+ import React, { useState, useEffect } from 'react';
58
+ import { useCart } from './CartContext';
59
+ import { usePayment } from './PaymentContext';
60
+
61
+ interface Address {
62
+ street: string;
63
+ city: string;
64
+ state: string;
65
+ zip: string;
66
+ country: string;
67
+ }
68
+
69
+ interface PaymentInfo {
70
+ cardNumber: string;
71
+ expiry: string;
72
+ cvv: string;
73
+ nameOnCard: string;
74
+ }
75
+
76
+ type Step = 'shipping' | 'payment' | 'review' | 'confirmation';
77
+
78
+ interface CheckoutProps {
79
+ onComplete?: (orderId: string) => void;
80
+ onCancel?: () => void;
81
+ }
82
+
83
+ export const Checkout: React.FC<CheckoutProps> = ({ onComplete, onCancel }) => {
84
+ const { items, total, clearCart } = useCart();
85
+ const { processPayment } = usePayment();
86
+
87
+ const [step, setStep] = useState<Step>('shipping');
88
+ const [shipping, setShipping] = useState<Address>({
89
+ street: '', city: '', state: '', zip: '', country: 'US'
90
+ });
91
+ const [payment, setPayment] = useState<PaymentInfo>({
92
+ cardNumber: '', expiry: '', cvv: '', nameOnCard: ''
93
+ });
94
+ const [errors, setErrors] = useState<Record<string, string>>({});
95
+ const [isLoading, setIsLoading] = useState(false);
96
+ const [orderId, setOrderId] = useState<string | null>(null);
97
+ const [submitError, setSubmitError] = useState<string | null>(null);
98
+
99
+ const validateShipping = (): boolean => {
100
+ const newErrors: Record<string, string> = {};
101
+
102
+ if (!shipping.street.trim()) newErrors.street = 'Street address is required';
103
+ if (!shipping.city.trim()) newErrors.city = 'City is required';
104
+ if (!shipping.state.trim()) newErrors.state = 'State is required';
105
+ if (!shipping.zip.match(/^\d{5}(-\d{4})?$/)) newErrors.zip = 'Valid ZIP code required';
106
+
107
+ setErrors(newErrors);
108
+ return Object.keys(newErrors).length === 0;
109
+ };
110
+
111
+ const validatePayment = (): boolean => {
112
+ const newErrors: Record<string, string> = {};
113
+
114
+ if (!payment.cardNumber.replace(/\s/g, '').match(/^\d{16}$/)) {
115
+ newErrors.cardNumber = 'Valid 16-digit card number required';
116
+ }
117
+ if (!payment.expiry.match(/^(0[1-9]|1[0-2])\/\d{2}$/)) {
118
+ newErrors.expiry = 'Valid expiry (MM/YY) required';
119
+ }
120
+ if (!payment.cvv.match(/^\d{3,4}$/)) {
121
+ newErrors.cvv = 'Valid CVV required';
122
+ }
123
+ if (!payment.nameOnCard.trim()) {
124
+ newErrors.nameOnCard = 'Name on card is required';
125
+ }
126
+
127
+ setErrors(newErrors);
128
+ return Object.keys(newErrors).length === 0;
129
+ };
130
+
131
+ const handleShippingSubmit = (e: React.FormEvent) => {
132
+ e.preventDefault();
133
+ if (validateShipping()) {
134
+ setStep('payment');
135
+ }
136
+ };
137
+
138
+ const handlePaymentSubmit = (e: React.FormEvent) => {
139
+ e.preventDefault();
140
+ if (validatePayment()) {
141
+ setStep('review');
142
+ }
143
+ };
144
+
145
+ const handlePlaceOrder = async () => {
146
+ setIsLoading(true);
147
+ setSubmitError(null);
148
+
149
+ try {
150
+ const result = await processPayment({
151
+ amount: total,
152
+ card: payment,
153
+ shipping: shipping,
154
+ items: items
155
+ });
156
+
157
+ setOrderId(result.orderId);
158
+ clearCart();
159
+ setStep('confirmation');
160
+ onComplete?.(result.orderId);
161
+ } catch (error) {
162
+ setSubmitError(error instanceof Error ? error.message : 'Payment failed');
163
+ } finally {
164
+ setIsLoading(false);
165
+ }
166
+ };
167
+
168
+ if (items.length === 0 && step !== 'confirmation') {
169
+ return (
170
+ <div role="alert" aria-live="polite">
171
+ <h2>Your cart is empty</h2>
172
+ <button onClick={onCancel}>Continue Shopping</button>
173
+ </div>
174
+ );
175
+ }
176
+
177
+ return (
178
+ <div className="checkout" aria-label="Checkout">
179
+ <nav aria-label="Checkout progress">
180
+ <ol>
181
+ <li aria-current={step === 'shipping' ? 'step' : undefined}>
182
+ Shipping
183
+ </li>
184
+ <li aria-current={step === 'payment' ? 'step' : undefined}>
185
+ Payment
186
+ </li>
187
+ <li aria-current={step === 'review' ? 'step' : undefined}>
188
+ Review
189
+ </li>
190
+ </ol>
191
+ </nav>
192
+
193
+ {step === 'shipping' && (
194
+ <form onSubmit={handleShippingSubmit} aria-label="Shipping information">
195
+ <h2>Shipping Address</h2>
196
+
197
+ <div>
198
+ <label htmlFor="street">Street Address</label>
199
+ <input
200
+ id="street"
201
+ type="text"
202
+ value={shipping.street}
203
+ onChange={(e) => setShipping({ ...shipping, street: e.target.value })}
204
+ aria-invalid={!!errors.street}
205
+ aria-describedby={errors.street ? 'street-error' : undefined}
206
+ />
207
+ {errors.street && <span id="street-error" role="alert">{errors.street}</span>}
208
+ </div>
209
+
210
+ <div>
211
+ <label htmlFor="city">City</label>
212
+ <input
213
+ id="city"
214
+ type="text"
215
+ value={shipping.city}
216
+ onChange={(e) => setShipping({ ...shipping, city: e.target.value })}
217
+ aria-invalid={!!errors.city}
218
+ aria-describedby={errors.city ? 'city-error' : undefined}
219
+ />
220
+ {errors.city && <span id="city-error" role="alert">{errors.city}</span>}
221
+ </div>
222
+
223
+ <div>
224
+ <label htmlFor="state">State</label>
225
+ <select
226
+ id="state"
227
+ value={shipping.state}
228
+ onChange={(e) => setShipping({ ...shipping, state: e.target.value })}
229
+ aria-invalid={!!errors.state}
230
+ >
231
+ <option value="">Select state</option>
232
+ <option value="CA">California</option>
233
+ <option value="NY">New York</option>
234
+ <option value="TX">Texas</option>
235
+ </select>
236
+ {errors.state && <span id="state-error" role="alert">{errors.state}</span>}
237
+ </div>
238
+
239
+ <div>
240
+ <label htmlFor="zip">ZIP Code</label>
241
+ <input
242
+ id="zip"
243
+ type="text"
244
+ value={shipping.zip}
245
+ onChange={(e) => setShipping({ ...shipping, zip: e.target.value })}
246
+ aria-invalid={!!errors.zip}
247
+ aria-describedby={errors.zip ? 'zip-error' : undefined}
248
+ />
249
+ {errors.zip && <span id="zip-error" role="alert">{errors.zip}</span>}
250
+ </div>
251
+
252
+ <div className="form-actions">
253
+ <button type="button" onClick={onCancel}>Cancel</button>
254
+ <button type="submit">Continue to Payment</button>
255
+ </div>
256
+ </form>
257
+ )}
258
+
259
+ {step === 'payment' && (
260
+ <form onSubmit={handlePaymentSubmit} aria-label="Payment information">
261
+ <h2>Payment Details</h2>
262
+
263
+ <div>
264
+ <label htmlFor="cardNumber">Card Number</label>
265
+ <input
266
+ id="cardNumber"
267
+ type="text"
268
+ inputMode="numeric"
269
+ maxLength={19}
270
+ value={payment.cardNumber}
271
+ onChange={(e) => setPayment({ ...payment, cardNumber: e.target.value })}
272
+ aria-invalid={!!errors.cardNumber}
273
+ />
274
+ {errors.cardNumber && <span role="alert">{errors.cardNumber}</span>}
275
+ </div>
276
+
277
+ <div>
278
+ <label htmlFor="expiry">Expiry (MM/YY)</label>
279
+ <input
280
+ id="expiry"
281
+ type="text"
282
+ maxLength={5}
283
+ value={payment.expiry}
284
+ onChange={(e) => setPayment({ ...payment, expiry: e.target.value })}
285
+ aria-invalid={!!errors.expiry}
286
+ />
287
+ {errors.expiry && <span role="alert">{errors.expiry}</span>}
288
+ </div>
289
+
290
+ <div>
291
+ <label htmlFor="cvv">CVV</label>
292
+ <input
293
+ id="cvv"
294
+ type="text"
295
+ inputMode="numeric"
296
+ maxLength={4}
297
+ value={payment.cvv}
298
+ onChange={(e) => setPayment({ ...payment, cvv: e.target.value })}
299
+ aria-invalid={!!errors.cvv}
300
+ />
301
+ {errors.cvv && <span role="alert">{errors.cvv}</span>}
302
+ </div>
303
+
304
+ <div>
305
+ <label htmlFor="nameOnCard">Name on Card</label>
306
+ <input
307
+ id="nameOnCard"
308
+ type="text"
309
+ value={payment.nameOnCard}
310
+ onChange={(e) => setPayment({ ...payment, nameOnCard: e.target.value })}
311
+ aria-invalid={!!errors.nameOnCard}
312
+ />
313
+ {errors.nameOnCard && <span role="alert">{errors.nameOnCard}</span>}
314
+ </div>
315
+
316
+ <div className="form-actions">
317
+ <button type="button" onClick={() => setStep('shipping')}>Back</button>
318
+ <button type="submit">Review Order</button>
319
+ </div>
320
+ </form>
321
+ )}
322
+
323
+ {step === 'review' && (
324
+ <div aria-label="Order review">
325
+ <h2>Review Your Order</h2>
326
+
327
+ <section aria-label="Order items">
328
+ <h3>Items ({items.length})</h3>
329
+ <ul>
330
+ {items.map(item => (
331
+ <li key={item.id}>{item.name} - ${item.price.toFixed(2)}</li>
332
+ ))}
333
+ </ul>
334
+ <p><strong>Total: ${total.toFixed(2)}</strong></p>
335
+ </section>
336
+
337
+ <section aria-label="Shipping address">
338
+ <h3>Shipping To</h3>
339
+ <address>
340
+ {shipping.street}<br />
341
+ {shipping.city}, {shipping.state} {shipping.zip}
342
+ </address>
343
+ </section>
344
+
345
+ <section aria-label="Payment method">
346
+ <h3>Payment</h3>
347
+ <p>Card ending in {payment.cardNumber.slice(-4)}</p>
348
+ </section>
349
+
350
+ {submitError && (
351
+ <div role="alert" aria-live="assertive" className="error">
352
+ {submitError}
353
+ </div>
354
+ )}
355
+
356
+ <div className="form-actions">
357
+ <button type="button" onClick={() => setStep('payment')} disabled={isLoading}>
358
+ Back
359
+ </button>
360
+ <button
361
+ type="button"
362
+ onClick={handlePlaceOrder}
363
+ disabled={isLoading}
364
+ aria-busy={isLoading}
365
+ >
366
+ {isLoading ? 'Processing...' : 'Place Order'}
367
+ </button>
368
+ </div>
369
+ </div>
370
+ )}
371
+
372
+ {step === 'confirmation' && orderId && (
373
+ <div role="status" aria-live="polite" aria-label="Order confirmation">
374
+ <h2>Order Confirmed!</h2>
375
+ <p>Your order number is: <strong>{orderId}</strong></p>
376
+ <button onClick={onCancel}>Continue Shopping</button>
377
+ </div>
378
+ )}
379
+ </div>
380
+ );
381
+ };
382
+
383
+ # =============================================================================
384
+ # BASELINE TEST SCENARIOS (minimum expected to cover)
385
+ # =============================================================================
386
+
387
+ baseline_issues:
388
+ happy_path:
389
+ - id: COMPLETE_CHECKOUT_FLOW
390
+ description: "User can complete full checkout from shipping to confirmation"
391
+
392
+ - id: STEP_NAVIGATION
393
+ description: "User can navigate forward and back between steps"
394
+
395
+ - id: ORDER_CONFIRMATION
396
+ description: "Order confirmation displays correct order ID"
397
+
398
+ - id: CART_CLEARED
399
+ description: "Cart is cleared after successful order"
400
+
401
+ validation:
402
+ - id: SHIPPING_VALIDATION
403
+ description: "All shipping fields show validation errors when empty"
404
+
405
+ - id: ZIP_FORMAT_VALIDATION
406
+ description: "ZIP code validates correct format (12345 or 12345-6789)"
407
+
408
+ - id: CARD_NUMBER_VALIDATION
409
+ description: "Card number validates 16 digits"
410
+
411
+ - id: EXPIRY_FORMAT_VALIDATION
412
+ description: "Expiry validates MM/YY format"
413
+
414
+ - id: CVV_VALIDATION
415
+ description: "CVV validates 3-4 digits"
416
+
417
+ error_states:
418
+ - id: PAYMENT_FAILURE
419
+ description: "Payment error is displayed to user"
420
+
421
+ - id: ERROR_RECOVERY
422
+ description: "User can retry after payment failure"
423
+
424
+ - id: ERROR_CLEARED_ON_RETRY
425
+ description: "Previous error cleared when retrying"
426
+
427
+ loading_states:
428
+ - id: LOADING_INDICATOR
429
+ description: "Loading state shown during payment processing"
430
+
431
+ - id: BUTTONS_DISABLED
432
+ description: "Buttons disabled during loading"
433
+
434
+ edge_cases:
435
+ - id: EMPTY_CART
436
+ description: "Empty cart shows appropriate message and redirect"
437
+
438
+ - id: CALLBACK_CALLED
439
+ description: "onComplete callback called with order ID"
440
+
441
+ - id: CANCEL_CALLBACK
442
+ description: "onCancel callback works correctly"
443
+
444
+ accessibility:
445
+ - id: FORM_LABELS
446
+ description: "All inputs have associated labels"
447
+
448
+ - id: ERROR_ANNOUNCEMENTS
449
+ description: "Errors announced to screen readers (role=alert)"
450
+
451
+ - id: PROGRESS_INDICATOR
452
+ description: "Current step indicated in navigation"
453
+
454
+ - id: LOADING_ANNOUNCED
455
+ description: "Loading state announced (aria-busy)"
456
+
457
+ # =============================================================================
458
+ # BONUS TEST SCENARIOS
459
+ # =============================================================================
460
+
461
+ bonus_issues:
462
+ accessibility:
463
+ - id: KEYBOARD_NAVIGATION
464
+ description: "Full checkout completable via keyboard only"
465
+
466
+ - id: FOCUS_MANAGEMENT
467
+ description: "Focus moves appropriately between steps"
468
+
469
+ - id: ERROR_FOCUS
470
+ description: "Focus moves to first error on validation failure"
471
+
472
+ edge_cases:
473
+ - id: WHITESPACE_ONLY_INPUT
474
+ description: "Whitespace-only inputs treated as empty"
475
+
476
+ - id: PASTE_HANDLING
477
+ description: "Pasted card numbers handled correctly"
478
+
479
+ - id: RAPID_SUBMIT
480
+ description: "Rapid form submissions don't cause issues"
481
+
482
+ integration:
483
+ - id: CONTEXT_INTEGRATION
484
+ description: "Tests verify cart and payment context integration"
485
+
486
+ - id: ASYNC_TIMING
487
+ description: "Tests handle async operations correctly"
488
+
489
+ visual:
490
+ - id: CARD_LAST_4
491
+ description: "Only last 4 digits of card shown in review"
492
+
493
+ - id: TOTAL_FORMAT
494
+ description: "Total displayed with correct currency format"
495
+
496
+ # =============================================================================
497
+ # SCORING
498
+ # =============================================================================
499
+
500
+ scoring:
501
+ total_baseline_scenarios: 22
502
+ total_bonus_scenarios: 14
503
+
504
+ categories:
505
+ - name: coverage
506
+ weight: 40
507
+ criteria:
508
+ - id: BASELINE_COVERED
509
+ description: "All baseline test scenarios covered"
510
+ points: 30
511
+ - id: BONUS_COVERED
512
+ description: "Additional valuable test scenarios"
513
+ points: 10
514
+
515
+ - name: quality
516
+ weight: 30
517
+ criteria:
518
+ - id: TESTING_LIBRARY_PRACTICES
519
+ description: "Uses getByRole, userEvent, proper queries"
520
+ points: 10
521
+ - id: TEST_ISOLATION
522
+ description: "Tests are independent and isolated"
523
+ points: 10
524
+ - id: READABLE_ASSERTIONS
525
+ description: "Clear test names and assertions"
526
+ points: 10
527
+
528
+ - name: accessibility_testing
529
+ weight: 15
530
+ criteria:
531
+ - id: A11Y_QUERIES
532
+ description: "Uses accessible queries (getByRole, getByLabelText)"
533
+ points: 8
534
+ - id: A11Y_ASSERTIONS
535
+ description: "Tests accessibility attributes"
536
+ points: 7
537
+
538
+ - name: persona
539
+ weight: 15
540
+ criteria:
541
+ - id: CHARACTER_CONSISTENCY
542
+ description: "Stays in character throughout"
543
+ points: 8
544
+ - id: PERSONA_VALUE_ADD
545
+ description: "Persona enhances test documentation"
546
+ points: 7
547
+
548
+ # =============================================================================
549
+ # PERSONA INFLUENCE
550
+ # =============================================================================
551
+
552
+ persona_influence:
553
+ dimensions:
554
+ - name: test_strategy
555
+ description: "Overall testing approach"
556
+ spectrum:
557
+ happy_path_first: "Tests main flows, then edge cases"
558
+ edge_case_focused: "Emphasizes boundary conditions"
559
+ risk_based: "Tests based on failure likelihood"
560
+
561
+ - name: mock_approach
562
+ description: "How mocking is handled"
563
+ spectrum:
564
+ minimal: "Mocks only external dependencies"
565
+ moderate: "Mocks contexts and hooks"
566
+ extensive: "Mocks for isolation"
567
+
568
+ - name: documentation_style
569
+ description: "How tests are documented"
570
+ spectrum:
571
+ terse: "Minimal test descriptions"
572
+ descriptive: "Clear describe/it blocks"
573
+ verbose: "Extensive comments and docs"
574
+
575
+ expected_tendencies:
576
+ discworld_tea:
577
+ character: "Igor"
578
+ expected_traits:
579
+ - "Thorough - should cover edge cases"
580
+ - "Practical - focuses on what breaks"
581
+ - "May have unusual test names"
582
+ coverage_prediction: "high"
583
+
584
+ star_trek_tea:
585
+ character: "Scotty"
586
+ expected_traits:
587
+ - "Systematic - organized test structure"
588
+ - "May over-test internals"
589
+ - "Clear documentation"
590
+ coverage_prediction: "high"
591
+
592
+ control_tea:
593
+ character: "None (baseline)"
594
+ expected_traits:
595
+ - "Standard testing approach"
596
+ coverage_prediction: "baseline reference"