harn-stdlib 0.10.41

Embedded Harn standard library source catalog
Documentation
/**
 * std/eval/experiment — portable controlled-experiment contracts.
 *
 * This facade owns experiment validity and decision semantics. Hosts own
 * execution placement, arm-config validation, persistence location, metric
 * projection, and user notification.
 */
pub import {
  AssignmentPlan,
  PlannedAssignment,
  RealizedAssignment,
  plan_assignments,
  realize_assignment,
} from "std/eval/experiment/assignment"
pub import {
  AlarmKind,
  AssignmentPolicy,
  CaseSet,
  ExperimentArm,
  ExperimentBudget,
  ExperimentDecisionPolicy,
  ExperimentGuardrail,
  ExperimentManifest,
  ExperimentMetric,
  ExperimentMetrics,
  ExperimentPhase,
  ExperimentRegistration,
  ExperimentSplitPolicy,
  ExperimentValidationContext,
  GuardrailAlarm,
  MetricBounds,
  MetricDirection,
  PromotionReceipt,
  experiment_manifest_contract,
  experiment_registration_contract,
  experiment_registration_descriptor,
  register_experiment,
  validate_experiment_manifest,
} from "std/eval/experiment/contracts"
pub import {
  CandidateOutcome,
  CandidateStatus,
  ExperimentDecision,
  ExperimentDecisionInput,
  ExperimentVerdict,
  GuardrailOutcome,
  MetricPair,
  PairedObservation,
  decide_experiment,
  experiment_decision_contract,
  experiment_decision_descriptor,
} from "std/eval/experiment/decision"

/**
 * Explicitly promote an iterate winner onto the frozen gate case set.
 *
 * No other verdict can unlock gate data, and gate decisions cannot be promoted
 * again. The returned receipt links both immutable registrations and the source
 * decision.
 *
 * @effects: []
 * @errors: [validation]
 */
pub fn promote_experiment(
  registration: ExperimentRegistration,
  decision: ExperimentDecision,
) -> {registration: ExperimentRegistration, receipt: PromotionReceipt} {
  if registration.phase != "iterate"
    || decision.phase != "iterate"
    || decision.registration_id != registration.registration_id
    || decision.verdict != "ITERATE_WINNER"
    || decision.winner == nil {
    throw "std/eval/experiment: promotion requires this registration's iterate winner"
  }
  let winner: ExperimentArm? = nil
  for arm in registration.candidates {
    if arm.id == decision.winner {
      winner = arm
    }
  }
  if winner == nil {
    throw "std/eval/experiment: decision winner is not registered"
  }
  if decision.spend_usd < registration.prior_spend_usd
    || decision.spend_usd
    > registration.budget
    .max_spend_usd {
    throw "std/eval/experiment: decision spend is outside the frozen budget"
  }
  const identity = {
    source: registration.registration_id,
    decision: decision.decision_id,
    spend_usd: decision.spend_usd,
    arm: winner.id,
    gate: registration.gate_case_set,
  }
  const gate_registration_id = "expreg-" + to_string(hash_value(identity))
  const gate_registration: ExperimentRegistration = {
    schema: "harn.experiment.registration.v1",
    schema_version: 1,
    registration_id: gate_registration_id,
    manifest_digest: registration.manifest_digest,
    phase: "gate",
    experiment_id: registration.experiment_id,
    hypothesis: registration.hypothesis,
    owner: registration.owner,
    baseline: registration.baseline,
    candidates: [winner],
    decision: registration.decision,
    metrics: registration.metrics,
    assignment: registration.assignment,
    case_set: registration.gate_case_set,
    gate_case_set: registration.gate_case_set,
    budget: registration.budget,
    min_trials_per_case: registration.min_trials_per_case,
    prior_spend_usd: decision.spend_usd,
    promoted_from: registration.registration_id,
    promoted_arm: winner.id,
  }
  const receipt: PromotionReceipt = {
    schema: "harn.experiment.promotion.v1",
    promotion_id: "expprom-" + to_string(hash_value(identity)),
    source_registration_id: registration.registration_id,
    source_decision_id: decision.decision_id,
    promoted_arm: winner.id,
    gate_registration_id: gate_registration_id,
  }
  return {registration: gate_registration, receipt: receipt}
}