diff --git a/apps/web/src/db/schema/uncertainty.ts b/apps/web/src/db/schema/uncertainty.ts new file mode 100644 index 0000000..0e5b1ec --- /dev/null +++ b/apps/web/src/db/schema/uncertainty.ts @@ -0,0 +1,55 @@ +import { index, integer, real, sqliteTable, text } from "drizzle-orm/sqlite-core"; +import { uuidv7 } from "uuidv7"; + +export const uncertaintyPrediction = sqliteTable( + "uncertainty_prediction", + { + id: text("id") + .primaryKey() + .$defaultFn(() => uuidv7()), + surface: text("surface").notNull(), + featureKey: text("feature_key").notNull(), + inputFingerprint: text("input_fingerprint").notNull(), + model: text("model").notNull(), + modelVersion: text("model_version").notNull(), + claimedConfidence: real("claimed_confidence").notNull(), + predictionPayload: text("prediction_payload").notNull(), + state: text("state").notNull(), + outcomeLabel: text("outcome_label"), + outcomePayload: text("outcome_payload"), + outcomeCorrectness: real("outcome_correctness"), + createdAt: integer("created_at", { mode: "timestamp_ms" }) + .notNull() + .$defaultFn(() => new Date()), + witnessedAt: integer("witnessed_at", { mode: "timestamp_ms" }), + orphanAfter: integer("orphan_after", { mode: "timestamp_ms" }).notNull(), + cohortKey: text("cohort_key").notNull(), + }, + (table) => [ + index("idx_uncertainty_prediction_cohort").on(table.cohortKey), + index("idx_uncertainty_prediction_surface").on(table.surface), + index("idx_uncertainty_prediction_state").on(table.state), + index("idx_uncertainty_prediction_orphan_sweep").on(table.state, table.orphanAfter), + ], +); + +export const uncertaintyCalibrationSnapshot = sqliteTable( + "uncertainty_calibration_snapshot", + { + id: text("id") + .primaryKey() + .$defaultFn(() => uuidv7()), + cohortKey: text("cohort_key").notNull(), + bucketLower: real("bucket_lower").notNull(), + bucketUpper: real("bucket_upper").notNull(), + claimedConfidence: real("claimed_confidence").notNull(), + actualCorrectness: real("actual_correctness").notNull(), + predictionCount: integer("prediction_count").notNull(), + orphanCount: integer("orphan_count").notNull(), + brierScore: real("brier_score").notNull(), + computedAt: integer("computed_at", { mode: "timestamp_ms" }) + .notNull() + .$defaultFn(() => new Date()), + }, + (table) => [index("idx_uncertainty_calibration_snapshot_cohort").on(table.cohortKey)], +); diff --git a/apps/web/src/db/schema/uncertainty.zod.ts b/apps/web/src/db/schema/uncertainty.zod.ts new file mode 100644 index 0000000..6eb4ef0 --- /dev/null +++ b/apps/web/src/db/schema/uncertainty.zod.ts @@ -0,0 +1,50 @@ +import { createInsertSchema, createSelectSchema } from "drizzle-zod"; +import { z } from "zod"; +import { uncertaintyCalibrationSnapshot, uncertaintyPrediction } from "./uncertainty"; + +const predictionState = z.enum(["emitted", "witnessed", "orphaned", "retired"]); +const outcomeLabel = z.enum(["accepted", "rejected", "edited", "ignored", "custom"]); +const unitInterval = z.number().min(0).max(1); + +const calibrationSnapshotOverrides = { + bucketLower: unitInterval, + bucketUpper: unitInterval, + claimedConfidence: unitInterval, + actualCorrectness: unitInterval, + predictionCount: z.number().int().nonnegative(), + orphanCount: z.number().int().nonnegative(), + brierScore: unitInterval, +}; + +export const insertUncertaintyPredictionSchema = createInsertSchema(uncertaintyPrediction, { + state: predictionState, + outcomeLabel: outcomeLabel.nullable().optional(), + claimedConfidence: unitInterval, + outcomeCorrectness: unitInterval.nullable().optional(), +}); + +export const selectUncertaintyPredictionSchema = createSelectSchema(uncertaintyPrediction, { + state: predictionState, + outcomeLabel: outcomeLabel.nullable(), + claimedConfidence: unitInterval, + outcomeCorrectness: unitInterval.nullable(), +}); + +export const insertUncertaintyCalibrationSnapshotSchema = createInsertSchema( + uncertaintyCalibrationSnapshot, + calibrationSnapshotOverrides, +); + +export const selectUncertaintyCalibrationSnapshotSchema = createSelectSchema( + uncertaintyCalibrationSnapshot, + calibrationSnapshotOverrides, +); + +export type InsertUncertaintyPrediction = z.infer; +export type SelectUncertaintyPrediction = z.infer; +export type InsertUncertaintyCalibrationSnapshot = z.infer< + typeof insertUncertaintyCalibrationSnapshotSchema +>; +export type SelectUncertaintyCalibrationSnapshot = z.infer< + typeof selectUncertaintyCalibrationSnapshotSchema +>;