import type { FeatureFlag, FlagState } from './types.js'; /** * The graduation lane a flag sits in. * - `graduated` , the flag's default flipped ON (it graduated). * - `dark` , default OFF, no graduation evidence gathered. * - `soaking` , default OFF, an owner has it accumulating evidence. * - `graduate-candidate`: judged ready to flip, awaiting a release decision. * THIS is the only release-blocking state: it must resolve to `graduated` * (flip it) or `blocked` (record a dated reason) every release. * - `blocked` , held OFF on purpose, with a dated recorded reason. */ export type GraduationState = 'dark' | 'soaking' | 'graduate-candidate' | 'graduated' | 'blocked'; /** The validation instrumentation a flag actually has wired (a static fact). */ export type GraduationInstrumentation = 'divergence-simulation' | 'none'; /** A dated reason a ready flag is being held OFF rather than flipped. */ export interface GraduationBlocker { readonly reason: string; /** ISO date (YYYY-MM-DD) the blocker was recorded. */ readonly date: string; } /** * An owner-set annotation that overrides a flag's DERIVED graduation state. * A flag with no annotation derives to `graduated` (default ON) or `dark` * (default OFF). Only the soaking / candidate / blocked lanes are owner-set. */ export interface FlagGraduationAnnotation { readonly flagId: string; readonly state: 'soaking' | 'graduate-candidate' | 'blocked'; /** Required when state === 'blocked'; forbidden otherwise. */ readonly blocker?: GraduationBlocker; /** Free-form owner note (evidence pointer, rationale). */ readonly note?: string; } /** Real shadow/divergence readings for a flag, when a live provider supplies them. */ export interface FlagDivergenceEvidence { readonly divergenceRate: number; readonly totalEvaluations: number; readonly gateStatus: 'allowed' | 'blocked' | 'no_data'; } /** The evidence bundle for one flag, real data, or an explicit absence of it. */ export interface FlagGraduationEvidence { readonly instrumentation: GraduationInstrumentation; /** Divergence readings when a live provider supplied them; null otherwise. */ readonly divergence: FlagDivergenceEvidence | null; /** Human-readable summary; says "no evidence collected" when nothing real exists. */ readonly note: string; } /** A resolved graduation row for one flag. */ export interface FlagGraduationEntry { readonly flagId: string; readonly name: string; readonly tier: number; readonly currentDefault: FlagState; readonly runtimeToggleable: boolean; readonly state: GraduationState; readonly evidence: FlagGraduationEvidence; readonly blocker: GraduationBlocker | null; readonly note: string | null; } export interface FlagGraduationSummary { readonly total: number; readonly dark: number; readonly soaking: number; readonly graduateCandidate: number; readonly graduated: number; readonly blocked: number; } export interface FlagGraduationReport { readonly generatedAt: number; readonly entries: readonly FlagGraduationEntry[]; readonly summary: FlagGraduationSummary; /** * Flag ids that block a release: every flag in `graduate-candidate` (ready, * but neither flipped nor blocked). Empty means the release policy passes. */ readonly releaseBlockers: readonly string[]; } /** Provides real shadow/divergence readings for a flag, or null when none exist. */ export interface GraduationEvidenceProvider { divergenceFor(flagId: string): FlagDivergenceEvidence | null; } /** * Owner-set graduation annotations. HONEST DEFAULT: empty, no flag is asserted * ready without recorded evidence. Owners add soaking/candidate/blocked entries * here as real evidence arrives; the release gate then forces each candidate to * flip or record a dated blocker. */ export declare const FLAG_GRADUATION_ANNOTATIONS: readonly FlagGraduationAnnotation[]; export interface BuildFlagGraduationReportOptions { readonly flags?: readonly FeatureFlag[]; readonly annotations?: readonly FlagGraduationAnnotation[]; readonly evidence?: GraduationEvidenceProvider | null; readonly now?: () => number; } /** * Build the graduation report from the flag registry, owner annotations, and * whatever real evidence a provider supplies. Pure and deterministic given its * inputs; supplies live defaults so the operator verb and CLI can call it bare. */ export declare function buildFlagGraduationReport(options?: BuildFlagGraduationReportOptions): FlagGraduationReport; export interface GraduationReleaseGateResult { readonly ok: boolean; readonly blockers: readonly string[]; readonly message: string; } /** * The release policy: a report passes only when nothing sits in * `graduate-candidate`. Each candidate must flip (become `graduated`) or record * a dated blocker (become `blocked`) before the release proceeds. */ export declare function evaluateGraduationReleaseGate(report: FlagGraduationReport): GraduationReleaseGateResult; //# sourceMappingURL=graduation.d.ts.map