import { createHmac } from "node:crypto"; import type { PrivacyClass } from "../types.js"; export function experimentAssignment(secret: Buffer | string, taskFingerprint: string, experimentId: string, allocation = 0.1): "champion" | "challenger" { if (!Number.isFinite(allocation) || allocation < 0 || allocation > 1) throw new Error("Experiment allocation must be between 0 and 1"); const value = createHmac("sha256", secret).update(`${taskFingerprint}:${experimentId}`).digest().readUInt32BE(0) / 0x1_0000_0000; return value < allocation ? "challenger" : "champion"; } export interface ExperimentSafetyInput { privacyClass: PrivacyClass; risk: string; policy: string; securitySensitive?: boolean; migration?: boolean; destructive?: boolean; productionIncident?: boolean; } export type ExperimentExclusionReason = "secret" | "policy-max" | "security-sensitive" | "migration" | "destructive" | "high-risk-production-incident" | "high-risk"; export function experimentExclusionReason(input: ExperimentSafetyInput): ExperimentExclusionReason | undefined { if (input.privacyClass === "secret") return "secret"; if (input.policy === "max") return "policy-max"; if (input.securitySensitive) return "security-sensitive"; if (input.migration) return "migration"; if (input.destructive) return "destructive"; if (input.risk === "high" && input.productionIncident) return "high-risk-production-incident"; if (input.risk === "high") return "high-risk"; return undefined; } export function excludedFromExperiment(input: ExperimentSafetyInput): boolean { return experimentExclusionReason(input) !== undefined; }