feat(planning): explain and trace planning decisions
This commit is contained in:
1 parent
609b3dece9
commit
d7a13b0b1e
24 files changed
+6073
-342
No files matched your search
@@ -1,41 +1,92 @@
|
||||
/// <reference lib="webworker" />
|
||||
|
||||
import type { PlanningOutcome, PlanOutcome } from './leave-planner.service';
|
||||
import { calculatePlanningInternal } from './leave-planner.core';
|
||||
import type {
|
||||
CounterfactualAnalysis,
|
||||
LeavePlacement,
|
||||
PlanOutcome,
|
||||
PlanningOutcome,
|
||||
PlanningSnapshot,
|
||||
PlanningTraceState,
|
||||
} from './leave-planner.service';
|
||||
import {
|
||||
analyzeCounterfactualInternal,
|
||||
calculatePlanningInternal,
|
||||
type CounterfactualBaselineOptions,
|
||||
type PlanningArtifacts,
|
||||
} from './leave-planner.core';
|
||||
|
||||
type WorkerPlanningRequest = {
|
||||
horizon?: { start?: unknown; end?: unknown };
|
||||
balances?: unknown;
|
||||
rules?: unknown;
|
||||
identities?: unknown;
|
||||
labels?: unknown;
|
||||
deadlineMs?: unknown;
|
||||
progress?: unknown;
|
||||
};
|
||||
|
||||
type WorkerRequest = {
|
||||
type: 'plan';
|
||||
request: WorkerPlanningRequest;
|
||||
};
|
||||
type WorkerRequest =
|
||||
| {
|
||||
type: 'plan';
|
||||
request: WorkerPlanningRequest;
|
||||
}
|
||||
| {
|
||||
type: 'counterfactual';
|
||||
request: PlanningSnapshot;
|
||||
plan: PlanOutcome;
|
||||
placement: LeavePlacement;
|
||||
state?: PlanningTraceState;
|
||||
options?: CounterfactualBaselineOptions;
|
||||
};
|
||||
|
||||
type WorkerResponse =
|
||||
| { type: 'progress'; stage: string }
|
||||
| { type: 'trace-overhead'; totalMs: number }
|
||||
| { type: 'checkpoint'; plan: PlanOutcome }
|
||||
| { type: 'result'; outcome: PlanningOutcome }
|
||||
| { type: 'artifacts'; artifacts: PlanningArtifacts }
|
||||
| { type: 'counterfactual-result'; analysis: CounterfactualAnalysis }
|
||||
| { type: 'error'; message: string };
|
||||
|
||||
const worker = self as DedicatedWorkerGlobalScope;
|
||||
|
||||
worker.onmessage = (event: MessageEvent<WorkerRequest>) => {
|
||||
if (event.data?.type !== 'plan') return;
|
||||
try {
|
||||
const outcome = calculatePlanningInternal(
|
||||
{
|
||||
...event.data.request,
|
||||
progress: (stage: string) =>
|
||||
worker.postMessage({ type: 'progress', stage } satisfies WorkerResponse),
|
||||
},
|
||||
(plan) => worker.postMessage({ type: 'checkpoint', plan } satisfies WorkerResponse),
|
||||
if (event.data?.type === 'plan') {
|
||||
let artifacts: PlanningArtifacts = {};
|
||||
let outcomePosted = false;
|
||||
const outcome = calculatePlanningInternal(
|
||||
{
|
||||
...event.data.request,
|
||||
progress: (stage: string) =>
|
||||
worker.postMessage({ type: 'progress', stage } satisfies WorkerResponse),
|
||||
traceProgress: (totalMs: number) =>
|
||||
worker.postMessage({
|
||||
type: 'trace-overhead',
|
||||
totalMs,
|
||||
} satisfies WorkerResponse),
|
||||
},
|
||||
(plan) => worker.postMessage({ type: 'checkpoint', plan } satisfies WorkerResponse),
|
||||
(value) => (artifacts = value),
|
||||
(value) => {
|
||||
outcomePosted = true;
|
||||
worker.postMessage({ type: 'result', outcome: value } satisfies WorkerResponse);
|
||||
},
|
||||
);
|
||||
if (!outcomePosted)
|
||||
worker.postMessage({ type: 'result', outcome } satisfies WorkerResponse);
|
||||
worker.postMessage({ type: 'artifacts', artifacts } satisfies WorkerResponse);
|
||||
return;
|
||||
}
|
||||
if (event.data?.type !== 'counterfactual') return;
|
||||
const analysis = analyzeCounterfactualInternal(
|
||||
event.data.request,
|
||||
event.data.plan,
|
||||
event.data.placement,
|
||||
event.data.state,
|
||||
event.data.options,
|
||||
);
|
||||
worker.postMessage({ type: 'result', outcome } satisfies WorkerResponse);
|
||||
worker.postMessage({ type: 'counterfactual-result', analysis } satisfies WorkerResponse);
|
||||
} catch (error) {
|
||||
worker.postMessage({
|
||||
type: 'error',
|
||||
|
||||
Reference in new issue
Block a user