feat(FN-4218): complete Step 1 — define experiment session types
Fusion-Task-Id: FN-4218 Fusion-Task-Lineage: 0b50d7f4-5001-4eb6-9633-7b24b00097fd
This commit is contained in:
72
packages/core/src/__tests__/experiment-session-types.test.ts
Normal file
72
packages/core/src/__tests__/experiment-session-types.test.ts
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import {
|
||||||
|
EXPERIMENT_METRIC_DIRECTIONS,
|
||||||
|
EXPERIMENT_RECORD_TYPES,
|
||||||
|
EXPERIMENT_RUN_OUTCOMES,
|
||||||
|
EXPERIMENT_SESSION_STATUSES,
|
||||||
|
isConfigRecord,
|
||||||
|
isFinalizeRecord,
|
||||||
|
isHookRecord,
|
||||||
|
isRunRecord,
|
||||||
|
type ExperimentSessionRecord,
|
||||||
|
} from "../experiment-session-types.js";
|
||||||
|
|
||||||
|
describe("experiment-session-types", () => {
|
||||||
|
it("defines constants with expected members and order", () => {
|
||||||
|
expect(EXPERIMENT_SESSION_STATUSES).toEqual(["active", "finalizing", "finalized", "archived"]);
|
||||||
|
expect(EXPERIMENT_METRIC_DIRECTIONS).toEqual(["maximize", "minimize"]);
|
||||||
|
expect(EXPERIMENT_RECORD_TYPES).toEqual(["config", "run", "hook", "finalize"]);
|
||||||
|
expect(EXPERIMENT_RUN_OUTCOMES).toEqual(["keep", "discard", "checks_failed", "errored", "pending"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("narrowing helpers identify record payload types", () => {
|
||||||
|
const records: ExperimentSessionRecord[] = [
|
||||||
|
{
|
||||||
|
id: "EXPR-1",
|
||||||
|
sessionId: "EXP-1",
|
||||||
|
segment: 1,
|
||||||
|
seq: 1,
|
||||||
|
type: "config",
|
||||||
|
payload: { metric: { name: "throughput", direction: "maximize" } },
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "EXPR-2",
|
||||||
|
sessionId: "EXP-1",
|
||||||
|
segment: 1,
|
||||||
|
seq: 2,
|
||||||
|
type: "run",
|
||||||
|
payload: { primaryMetric: 123, secondaryMetrics: [], status: "keep" },
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "EXPR-3",
|
||||||
|
sessionId: "EXP-1",
|
||||||
|
segment: 1,
|
||||||
|
seq: 3,
|
||||||
|
type: "hook",
|
||||||
|
payload: { hook: "before", exitCode: 0 },
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "EXPR-4",
|
||||||
|
sessionId: "EXP-1",
|
||||||
|
segment: 1,
|
||||||
|
seq: 4,
|
||||||
|
type: "finalize",
|
||||||
|
payload: { keptRunIds: ["EXPR-2"], discardedRunIds: [] },
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const [config, run, hook, finalize] = records;
|
||||||
|
expect(isConfigRecord(config)).toBe(true);
|
||||||
|
expect(isRunRecord(config)).toBe(false);
|
||||||
|
expect(isRunRecord(run)).toBe(true);
|
||||||
|
expect(run.payload.primaryMetric).toBe(123);
|
||||||
|
expect(isHookRecord(hook)).toBe(true);
|
||||||
|
expect(hook.payload.hook).toBe("before");
|
||||||
|
expect(isFinalizeRecord(finalize)).toBe(true);
|
||||||
|
expect(finalize.payload.keptRunIds).toEqual(["EXPR-2"]);
|
||||||
|
});
|
||||||
|
});
|
||||||
189
packages/core/src/experiment-session-types.ts
Normal file
189
packages/core/src/experiment-session-types.ts
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
export const EXPERIMENT_SESSION_STATUSES = ["active", "finalizing", "finalized", "archived"] as const;
|
||||||
|
export type ExperimentSessionStatus = typeof EXPERIMENT_SESSION_STATUSES[number];
|
||||||
|
|
||||||
|
export const EXPERIMENT_METRIC_DIRECTIONS = ["maximize", "minimize"] as const;
|
||||||
|
export type ExperimentMetricDirection = typeof EXPERIMENT_METRIC_DIRECTIONS[number];
|
||||||
|
|
||||||
|
export interface ExperimentMetricDefinition {
|
||||||
|
name: string;
|
||||||
|
unit?: string;
|
||||||
|
direction: ExperimentMetricDirection;
|
||||||
|
description?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const EXPERIMENT_RECORD_TYPES = ["config", "run", "hook", "finalize"] as const;
|
||||||
|
export type ExperimentRecordType = typeof EXPERIMENT_RECORD_TYPES[number];
|
||||||
|
|
||||||
|
export const EXPERIMENT_RUN_OUTCOMES = ["keep", "discard", "checks_failed", "errored", "pending"] as const;
|
||||||
|
export type ExperimentRunOutcome = typeof EXPERIMENT_RUN_OUTCOMES[number];
|
||||||
|
|
||||||
|
export interface ExperimentSecondaryMetric {
|
||||||
|
name: string;
|
||||||
|
value: number;
|
||||||
|
unit?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExperimentRunRecordPayload {
|
||||||
|
commit?: string;
|
||||||
|
primaryMetric: number;
|
||||||
|
secondaryMetrics: ExperimentSecondaryMetric[];
|
||||||
|
status: ExperimentRunOutcome;
|
||||||
|
description?: string;
|
||||||
|
confidence?: number;
|
||||||
|
asi?: Record<string, unknown>;
|
||||||
|
durationMs?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExperimentConfigRecordPayload {
|
||||||
|
metric: ExperimentMetricDefinition;
|
||||||
|
maxIterations?: number;
|
||||||
|
rules?: string;
|
||||||
|
ideas?: string;
|
||||||
|
workingDir?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExperimentHookRecordPayload {
|
||||||
|
hook: "before" | "after";
|
||||||
|
exitCode: number;
|
||||||
|
durationMs?: number;
|
||||||
|
stdout?: string;
|
||||||
|
stderr?: string;
|
||||||
|
steerMessage?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExperimentFinalizeRecordPayload {
|
||||||
|
keptRunIds: string[];
|
||||||
|
discardedRunIds: string[];
|
||||||
|
branches?: Array<{ name: string; baseCommit?: string; tipCommit?: string }>;
|
||||||
|
summary?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExperimentSessionRecordBase {
|
||||||
|
id: string;
|
||||||
|
sessionId: string;
|
||||||
|
segment: number;
|
||||||
|
seq: number;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExperimentConfigRecord extends ExperimentSessionRecordBase {
|
||||||
|
type: "config";
|
||||||
|
payload: ExperimentConfigRecordPayload;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExperimentRunRecord extends ExperimentSessionRecordBase {
|
||||||
|
type: "run";
|
||||||
|
payload: ExperimentRunRecordPayload;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExperimentHookRecord extends ExperimentSessionRecordBase {
|
||||||
|
type: "hook";
|
||||||
|
payload: ExperimentHookRecordPayload;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExperimentFinalizeRecord extends ExperimentSessionRecordBase {
|
||||||
|
type: "finalize";
|
||||||
|
payload: ExperimentFinalizeRecordPayload;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ExperimentSessionRecord =
|
||||||
|
| ExperimentConfigRecord
|
||||||
|
| ExperimentRunRecord
|
||||||
|
| ExperimentHookRecord
|
||||||
|
| ExperimentFinalizeRecord;
|
||||||
|
|
||||||
|
export function isRunRecord(record: ExperimentSessionRecord): record is ExperimentRunRecord {
|
||||||
|
return record.type === "run";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isConfigRecord(record: ExperimentSessionRecord): record is ExperimentConfigRecord {
|
||||||
|
return record.type === "config";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isHookRecord(record: ExperimentSessionRecord): record is ExperimentHookRecord {
|
||||||
|
return record.type === "hook";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isFinalizeRecord(record: ExperimentSessionRecord): record is ExperimentFinalizeRecord {
|
||||||
|
return record.type === "finalize";
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExperimentSession {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
projectId?: string;
|
||||||
|
status: ExperimentSessionStatus;
|
||||||
|
metric: ExperimentMetricDefinition;
|
||||||
|
currentSegment: number;
|
||||||
|
maxIterations?: number;
|
||||||
|
workingDir?: string;
|
||||||
|
baselineRunId?: string;
|
||||||
|
bestRunId?: string;
|
||||||
|
keptRunIds: string[];
|
||||||
|
tags: string[];
|
||||||
|
metadata?: Record<string, unknown>;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
finalizedAt?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExperimentSessionCreateInput {
|
||||||
|
name: string;
|
||||||
|
projectId?: string;
|
||||||
|
status?: ExperimentSessionStatus;
|
||||||
|
metric: ExperimentMetricDefinition;
|
||||||
|
currentSegment?: number;
|
||||||
|
maxIterations?: number;
|
||||||
|
workingDir?: string;
|
||||||
|
baselineRunId?: string;
|
||||||
|
bestRunId?: string;
|
||||||
|
keptRunIds?: string[];
|
||||||
|
tags?: string[];
|
||||||
|
metadata?: Record<string, unknown>;
|
||||||
|
finalizedAt?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExperimentSessionUpdateInput {
|
||||||
|
name?: string;
|
||||||
|
projectId?: string;
|
||||||
|
status?: ExperimentSessionStatus;
|
||||||
|
metric?: ExperimentMetricDefinition;
|
||||||
|
currentSegment?: number;
|
||||||
|
maxIterations?: number;
|
||||||
|
workingDir?: string;
|
||||||
|
baselineRunId?: string;
|
||||||
|
bestRunId?: string;
|
||||||
|
keptRunIds?: string[];
|
||||||
|
tags?: string[];
|
||||||
|
metadata?: Record<string, unknown>;
|
||||||
|
finalizedAt?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExperimentSessionRecordAppendInput {
|
||||||
|
segment?: number;
|
||||||
|
type: ExperimentRecordType;
|
||||||
|
payload:
|
||||||
|
| ExperimentRunRecordPayload
|
||||||
|
| ExperimentConfigRecordPayload
|
||||||
|
| ExperimentHookRecordPayload
|
||||||
|
| ExperimentFinalizeRecordPayload;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExperimentSessionListOptions {
|
||||||
|
status?: ExperimentSessionStatus;
|
||||||
|
projectId?: string;
|
||||||
|
tag?: string;
|
||||||
|
limit?: number;
|
||||||
|
offset?: number;
|
||||||
|
search?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExperimentSessionStoreEvents {
|
||||||
|
"session:created": [ExperimentSession];
|
||||||
|
"session:updated": [ExperimentSession];
|
||||||
|
"session:deleted": [string];
|
||||||
|
"session:status_changed": [ExperimentSession];
|
||||||
|
"session:finalized": [ExperimentSession];
|
||||||
|
"record:appended": [ExperimentSessionRecord];
|
||||||
|
"segment:reset": [{ sessionId: string; segment: number }];
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user