Files
vac-optimizer/docs/benchmark/pr-278-mandatory-moves.md
T

3.4 KiB

PR #278: reject impossible mandatory moves before copying

Measured on 2026-10-16 against 433a8b0, which includes the immutable date-count optimization.

A loaded-year CPU profile attributed 5.09 seconds to candidate assignment and 6.53 seconds to final validation out of 58.24 seconds. Generic moves and swaps copied the candidate state before discovering that a mandatory placement's new date or leave type could never satisfy its rule.

The shared assignment function now calls the existing mandatoryRelocationDate check before copying. It checks only necessary date and type conditions. Complete multi-day patterns and earned-entitlement chronology are still validated after the candidate is assembled. Preferences remain movable, and valid alternatives, objective order and deterministic tie breaks remain unchanged.

Before and after

Both protocol runs use Node 24.18.0, Bun 1.3.14 and Vitest 5.0.3 on the same local machine. This comparison uses a fresh baseline from this session. No other test, build or profiling workload runs alongside either protocol measurement.

NODE_OPTIONS=--max-old-space-size=2048 timeout 300s bunx vitest run src/app/benchmark/leave-planner-benchmark.spec.ts --maxWorkers=1

All seven warm-ups, fourteen measured calculations, the typed-obligation precheck, fixtures, assertions and resource limits remain unchanged.

Measurement Before After
Vitest duration 232.630 s 228.130 s
Benchmark test 231.483 s 227.011 s
Loaded year, mean of two measured calculations 59.255 s 57.850 s
Typed obligations, mean of two measured calculations 4.552 s 4.368 s
Headroom before timeout (Vitest duration) 67.370 s 71.870 s

The Vitest duration was 1.9% shorter in this pair. External wall time was not recorded for these runs. Both runs completed successfully, and every repeated scenario remained deterministic. The baseline is faster than the one recorded for the preceding optimization, so only same-session pairs are comparable. Live CI performance still needs confirmation.

Correctness checks

Complete outcomes, stable explanations and final-state snapshots match the baseline for all seven scenarios. Baseline snapshots come from the preceding optimization's saved run, whose bundle matches a fresh build of 433a8b0 byte for byte; the loaded-year snapshot was also regenerated in this session. Diagnostic comparisons ran alongside functional checks, so their timings are not used for the protocol comparison.

The functional coverage suite passes all 640 tests across 33 files. Two additional regression cases cover obligations and lower-priority preferences when a calendar objective competes for the same leave balance. Both cases pass before and after the optimization. Existing tests also exercise typed reassignments, complete multi-day patterns, earned entitlements and counterfactual explanations. Application and spec type checks, lint, source formatting and git diff --check pass.

No browser timing run or live CI rerun was performed for this change.

Diagnostic sources, profiles, bundles and full logs are retained in /tmp/vac-opt278-step3. The original core diagnostic runner is documented in issue-78.md.