V1/V2/V3 duplicated the empty-result shape, the paid-shares/bonus math
and the Friday-priority deduction loop. Pull them into ineligibleResult,
payResult and deductInOrder; each variant keeps only its distinct
threshold, eligibility test and deduction slots.
paidShares is now computed uniformly as max(0, classified - deduction);
never-deducted slots carry deduction 0, so the result is byte-identical
(verified against a 13122-case golden master over the full input grid).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Each variant emitted isWinner:false and the calculator set winner.isWinner
=true, but the UI marks the winner via variantId===winnerId, never the
flag. Only one test read it. Removed from the 6 variant returns, the empty
result, and the calculator.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Remove broken webpack.yml (no package.json/webpack config exists)
- Drop dead RATE_NORMAL/RATE_WEEKEND fields on BonusCalculator; share the
real rate constants across all three variants in variants.js
- Simplify getEmptyResult() to build allResults via .map instead of
three manual spreads
- Replace 5 duplicated German month-name arrays and 2 weekday-name
arrays in app.js with a shared monthName()/WEEKDAY_NAMES helper;
drop the now-redundant getMonthName() method
- Reuse existing .modal/.modal-backdrop/.modal-content CSS classes in
generateEmailReport() instead of hand-rolled inline styles
- Delegate ImageImporter.classify() to the shared classify() in
variants.js instead of a duplicated copy
- Unify ad hoc YYYY-MM-DD formatting in app.js to use the existing
HolidayProvider.formatDate() helper
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>