refactor(planning): remove the original decision trace
CI / policy (push) Successful in 7s
CI / validate (push) Successful in 1m15s
CI / test (push) Successful in 3m18s
CI / benchmark (push) Failing after 5m53s
CI / build (push) Successful in 1m23s
CI / security (push) Successful in 7m6s
CI / policy (pull_request) Successful in 7s
CI / validate (pull_request) Successful in 1m9s
CI / build (pull_request) Successful in 43s
CI / test (pull_request) Successful in 3m19s
CI / images (push) Successful in 3m7s
CI / required (push) Successful in 2s
CI / benchmark (pull_request) Failing after 5m28s
CI / security (pull_request) Successful in 6m37s
CI / images (pull_request) Successful in 3m18s
CI / required (pull_request) Successful in 1s
CI / policy (push) Successful in 7s
CI / validate (push) Successful in 1m15s
CI / test (push) Successful in 3m18s
CI / benchmark (push) Failing after 5m53s
CI / build (push) Successful in 1m23s
CI / security (push) Successful in 7m6s
CI / policy (pull_request) Successful in 7s
CI / validate (pull_request) Successful in 1m9s
CI / build (pull_request) Successful in 43s
CI / test (pull_request) Successful in 3m19s
CI / images (push) Successful in 3m7s
CI / required (push) Successful in 2s
CI / benchmark (pull_request) Failing after 5m28s
CI / security (pull_request) Successful in 6m37s
CI / images (pull_request) Successful in 3m18s
CI / required (pull_request) Successful in 1s
This commit is contained in:
1 parent
ea4256107f
commit
d9d9befa12
43 files changed
+729
-8880
No files matched your search
@@ -6,10 +6,9 @@ import {
|
||||
type PlanOutcome,
|
||||
type PlanningArtifacts,
|
||||
type PlanningRequest,
|
||||
type PlanningTraceUpdate,
|
||||
} from './leave-planner.core';
|
||||
import { OPTIMIZATION_PRESETS } from './planning-objectives';
|
||||
import { applyReplayDeltas, createPlanningCalculation } from './leave-planner.service';
|
||||
import { createPlanningCalculation } from './leave-planner.service';
|
||||
|
||||
const economy: OptimizationPlanningRule = {
|
||||
id: 'economy',
|
||||
@@ -415,25 +414,20 @@ describe('supporting placement economy and provenance', () => {
|
||||
});
|
||||
|
||||
it('reclassifies a deferred support addition when an eligible earlier-expiring balance replaces it', () => {
|
||||
let artifacts: PlanningArtifacts | undefined;
|
||||
const outcome = calculatePlanningInternal(
|
||||
{
|
||||
horizon: { start: '2024-05-06', end: '2024-05-11' },
|
||||
balances: [
|
||||
{ id: 'deferred', type: 'cp', quantity: 3, expiryDate: '2025-01-01' },
|
||||
{
|
||||
id: 'at-risk',
|
||||
type: 'rtt',
|
||||
quantity: 1,
|
||||
availableFrom: '2024-05-07',
|
||||
expiryDate: '2024-05-07',
|
||||
},
|
||||
],
|
||||
rules: [bundles[0].rule, economy],
|
||||
},
|
||||
undefined,
|
||||
(value) => (artifacts = value),
|
||||
);
|
||||
const outcome = calculatePlanningInternal({
|
||||
horizon: { start: '2024-05-06', end: '2024-05-11' },
|
||||
balances: [
|
||||
{ id: 'deferred', type: 'cp', quantity: 3, expiryDate: '2025-01-01' },
|
||||
{
|
||||
id: 'at-risk',
|
||||
type: 'rtt',
|
||||
quantity: 1,
|
||||
availableFrom: '2024-05-07',
|
||||
expiryDate: '2024-05-07',
|
||||
},
|
||||
],
|
||||
rules: [bundles[0].rule, economy],
|
||||
});
|
||||
if (outcome.kind !== 'Plan') throw new Error('Expected a plan');
|
||||
expect(
|
||||
outcome.placements.map(({ date, balanceId, supporting }) => ({
|
||||
@@ -448,20 +442,6 @@ describe('supporting placement economy and provenance', () => {
|
||||
]);
|
||||
expect(outcome.metrics.supportingPlacements).toBe(2);
|
||||
expect(outcome.remainingBalances[0]).toMatchObject({ id: 'deferred', quantity: 1 });
|
||||
expect(
|
||||
artifacts?.trace?.phases.flatMap(({ decisions }) =>
|
||||
decisions.flatMap(({ deltas }) => deltas),
|
||||
),
|
||||
).toContainEqual(
|
||||
expect.objectContaining({
|
||||
kind: 'placement-updated',
|
||||
previousPlacement: expect.objectContaining({
|
||||
balanceId: 'deferred',
|
||||
supporting: true,
|
||||
}),
|
||||
placement: expect.objectContaining({ balanceId: 'at-risk', supporting: false }),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('compares new deferred support when at-risk holiday placements relocate into an explicit window', async () => {
|
||||
@@ -491,13 +471,10 @@ describe('supporting placement economy and provenance', () => {
|
||||
};
|
||||
const economyFirst = plan({ ...request, rules: [holiday, economy, early] });
|
||||
let artifacts: PlanningArtifacts | undefined;
|
||||
const updates: { update: PlanningTraceUpdate; snapshot: string }[] = [];
|
||||
const windowFirst = calculatePlanningInternal(
|
||||
{
|
||||
...request,
|
||||
rules: [holiday, early, economy],
|
||||
traceProgress: (_time: number, update: PlanningTraceUpdate) =>
|
||||
updates.push({ update, snapshot: JSON.stringify(update) }),
|
||||
},
|
||||
(checkpoint, state) => expect(state?.placements).toEqual(checkpoint.placements),
|
||||
(value) => (artifacts = value),
|
||||
@@ -547,12 +524,8 @@ describe('supporting placement economy and provenance', () => {
|
||||
expect(windowFirst.metrics.supportingPlacements).toBe(2);
|
||||
expect(windowFirst.preferences[0].satisfied).toBe(2);
|
||||
expect(windowFirst.metrics.holidayWeekValue).toBe(3);
|
||||
if (
|
||||
artifacts?.explanation?.kind !== 'PlanExplanation' ||
|
||||
!artifacts.finalState ||
|
||||
!artifacts.trace
|
||||
)
|
||||
throw new Error('Expected matching explanation and trace artifacts');
|
||||
if (artifacts?.explanation?.kind !== 'PlanExplanation' || !artifacts.finalState)
|
||||
throw new Error('Expected matching explanation and state snapshots');
|
||||
expect(artifacts.finalState.placements).toEqual(windowFirst.placements);
|
||||
expect(artifacts.explanation.placements.map(({ placement }) => placement)).toEqual(
|
||||
windowFirst.placements,
|
||||
@@ -568,33 +541,6 @@ describe('supporting placement economy and provenance', () => {
|
||||
expect(placement.contributions).not.toContainEqual(contribution);
|
||||
}
|
||||
}
|
||||
const replay = {
|
||||
balances: artifacts.trace.initialState.balances.map((balance) => ({ ...balance })),
|
||||
placements: new Map(
|
||||
artifacts.trace.initialState.placements.map((placement) => [
|
||||
placement.date,
|
||||
placement,
|
||||
]),
|
||||
),
|
||||
earnedActivations: [...artifacts.trace.initialState.earnedActivations],
|
||||
};
|
||||
for (const decision of artifacts.trace.phases.flatMap(({ decisions }) => decisions))
|
||||
applyReplayDeltas(replay, decision.deltas, artifacts.finalState);
|
||||
expect(
|
||||
[...replay.placements.values()].sort((a, b) => a.date.localeCompare(b.date)),
|
||||
).toEqual(windowFirst.placements);
|
||||
expect(
|
||||
artifacts.trace.phases
|
||||
.filter(({ name }) => name === 'preference:early')
|
||||
.flatMap(({ decisions }) => decisions.flatMap(({ candidates }) => candidates)),
|
||||
).toContainEqual(
|
||||
expect.objectContaining({
|
||||
status: 'chosen',
|
||||
placement: expect.objectContaining({ date: '2026-11-03', ruleIds: ['early'] }),
|
||||
}),
|
||||
);
|
||||
expect(updates.length).toBeGreaterThan(0);
|
||||
for (const { update, snapshot } of updates) expect(JSON.stringify(update)).toBe(snapshot);
|
||||
let cancelled = false;
|
||||
let cancelledArtifacts: PlanningArtifacts | undefined;
|
||||
let published: PlanOutcome | undefined;
|
||||
@@ -605,8 +551,6 @@ describe('supporting placement economy and provenance', () => {
|
||||
progress: (stage: string) => {
|
||||
if (stage === 'optimization:economy') cancelled = true;
|
||||
},
|
||||
traceProgress: (_time: number, update: PlanningTraceUpdate) =>
|
||||
updates.push({ update, snapshot: JSON.stringify(update) }),
|
||||
},
|
||||
(checkpoint, state) => {
|
||||
expect(state?.placements).toEqual(checkpoint.placements);
|
||||
@@ -637,7 +581,6 @@ describe('supporting placement economy and provenance', () => {
|
||||
expect.objectContaining({ kind: 'rule', ruleId: 'early' }),
|
||||
);
|
||||
}
|
||||
for (const { update, snapshot } of updates) expect(JSON.stringify(update)).toBe(snapshot);
|
||||
});
|
||||
|
||||
it('keeps established maximum credit when a later earned period masks its local contribution', () => {
|
||||
@@ -708,28 +651,6 @@ describe('supporting placement economy and provenance', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('records the calendar credit and classification change in the original calendar-rule phase', () => {
|
||||
let artifacts: PlanningArtifacts | undefined;
|
||||
calculatePlanningInternal(
|
||||
{ ...weekend, rules: [gain, economy, requested] },
|
||||
undefined,
|
||||
(value) => (artifacts = value),
|
||||
);
|
||||
const changes = artifacts?.trace?.phases
|
||||
.find(({ name }) => name === 'preference:requested')
|
||||
?.decisions.flatMap(({ deltas }) => deltas);
|
||||
expect(changes).toContainEqual(
|
||||
expect.objectContaining({
|
||||
kind: 'placement-updated',
|
||||
previousPlacement: expect.objectContaining({ supporting: true }),
|
||||
placement: expect.objectContaining({
|
||||
ruleIds: ['gain', 'requested'],
|
||||
supporting: false,
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('keeps earned support chronological and preserves the captured economy rule in explanations and counterfactuals', async () => {
|
||||
vi.stubGlobal('window', undefined);
|
||||
try {
|
||||
@@ -792,15 +713,6 @@ describe('supporting placement economy and provenance', () => {
|
||||
expect(supporting.contributions).toContainEqual(
|
||||
expect.objectContaining({ kind: 'supporting' }),
|
||||
);
|
||||
const trace = await calculation.trace;
|
||||
expect(trace?.phases.map(({ name }) => name)).toEqual([
|
||||
'validation',
|
||||
'obligations',
|
||||
'optimization:gain',
|
||||
'optimization:economy',
|
||||
'expiry',
|
||||
'dates',
|
||||
]);
|
||||
const analysis = await calculation.analyzeCounterfactual(outcome.placements[1]);
|
||||
if (analysis.kind !== 'Counterfactual') throw new Error('Expected a counterfactual');
|
||||
expect(analysis.results.find(({ date }) => date === '2024-05-03')).toMatchObject({
|
||||
|
||||
Reference in new issue
Block a user