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

66 lines
3.4 KiB
Markdown

# PR #278: reject impossible mandatory moves before copying
Measured on 2026-10-16 against `433a8b0`, which includes the
[immutable date-count optimization](pr-278-immutable-date-counts.md).
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.
```sh
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](issue-78.md#reproduction).