export interface ApprenticeshipCycleStoreOptions {
    /** SQLite DB path. Use `:memory:` for tests. */
    dbPath: string;
    /** Override clock for deterministic tests. */
    now?: () => Date;
}
export interface ApprenticeshipCycleRecordInput {
    id?: string;
    instanceId: string;
    cycleNumber: number;
    createdAt?: string;
    task: string;
    menteeOutput: string;
    mentorFlagged?: string[];
    overseerDifferential?: string[];
    coaching?: string;
    infraItems?: string[];
    kind?: string;
    status?: string;
    /** The channel this cycle's mentor↔mentee interaction ACTUALLY ran through
     *  (the dogfooded-channel standard, APPRENTICESHIP-PROGRAM-PROJECT-DESIGN §4a). */
    channel?: string;
    /** REQUIRED operator-seat UX verdict (2026-06-05 UX-blindspot directive).
     *  Typed loose here so the runtime gate — not the compiler — produces the
     *  self-describing refusal callers actually see over HTTP. */
    operatorSeatUx?: unknown;
    /** REQUIRED for telegram-playwright cycles: the objective post-drive
     *  transcript-audit artifact (PR #864's report, distilled). Typed loose for
     *  the same runtime-gate reason as operatorSeatUx. */
    transcriptAudit?: unknown;
}
/**
 * The objective half of the cycle's observation record — proof that the
 * post-drive transcript auditor (`instar dev:post-drive-transcript-audit`,
 * PR #864) actually RAN over this drive's window.
 *
 * WHY THIS IS REQUIRED (Observation Needs Structure, PR #861): #856 gated the
 * mentor's SUBJECTIVE seat-counts, but the judgment-free auditor shipped as a
 * manual CLI — nothing structurally guaranteed it ran after a drive. An
 * observation tool nobody is forced to run is the same wish the article bans,
 * one level up. This block makes the audit an unskippable artifact on the
 * channel whose entire point is UX-under-test.
 *
 * `ledger` is an honesty declaration of where findings were filed:
 *  - 'local'   — filed into THIS agent's framework ledger (cross-checkable;
 *                the route verifies the dedup keys actually resolve).
 *  - 'remote'  — filed into another agent's ledger (e.g. the mentee's server
 *                holds the transcript AND took the observations).
 *  - 'dry-run' — auditor ran with --dry-run; findings counted, none filed.
 *  - 'failed'  — auditor ran but filing failed; reason belongs in `notes`.
 */
export interface TranscriptAuditAttachment {
    /** Topic ids the auditor read (the drive's actual transcript locations). */
    topicIds: number[];
    /** The audited drive window (ISO timestamps). */
    window: {
        start: string;
        end: string;
    };
    /** The report's per-category counts (e.g. { 'asks-of-user': 1, total: 3 }). */
    summary: Record<string, number>;
    /** Stable dedup keys of every finding (empty array = clean drive). */
    findingDedupKeys: string[];
    /** Report generation timestamp (ISO). */
    generatedAt: string;
    /** Where the findings were filed — see interface doc. */
    ledger: 'local' | 'remote' | 'dry-run' | 'failed';
    /** Free-form context (e.g. the remote base-url, or why filing failed). */
    notes?: string;
}
/**
 * The operator-seat UX verdict — what a HUMAN sitting in the user's chair
 * would have experienced during this cycle's drive.
 *
 * WHY THIS IS REQUIRED (the 2026-06-05 UX-blindspot incident): the mentor
 * prompt had instructed "observe the Telegram UX" for weeks as prose; 35
 * ledger findings later, not one was experience-framed — the operator found
 * the resend-asks / duplicate notices / photo failures himself. A standing
 * responsibility to NOTICE something is a wish unless an unskippable artifact
 * proves the looking happened. record() refuses cycles without this block.
 *
 * The counts are the agent's antidote to its own pain-threshold asymmetry:
 * an agent compensates for friction at zero felt cost (resends, ignores
 * duplicates), so the block forces it to COUNT what it compensated for.
 */
export interface OperatorSeatUx {
    /** Duplicate deliveries/notices observed in the drive window ("actively working" x2, replayed messages). */
    dupNotices: number;
    /** Infra-noise messages a human user shouldn't have to see (restart/queue chatter, internal status leaks). */
    infraNoiseMsgs: number;
    /** Times the mentee asked the USER to do machine work (resend, retry, re-paste). Each one is a finding. */
    asksOfUser: number;
    /** Updates carrying no information a user could act on ("still working, nothing to report" filler). */
    contentFreeUpdates: number;
    /** Modalities actually exercised this drive (e.g. 'text', 'photo', 'file'). Coverage = what's listed here, nothing more. */
    modalitiesExercised: string[];
    /** Whether the drive overlapped restart churn / degraded infra — bad-weather coverage is part of the job. */
    duringRestartChurn: boolean;
    /** Free-form observations from the user's chair. */
    notes?: string;
}
export declare const APPRENTICESHIP_CYCLE_AXES: readonly ["mentor-mentee-differential", "overseer-apprentice-devreview", "overseer-mentee-direct"];
export type ApprenticeshipCycleAxis = typeof APPRENTICESHIP_CYCLE_AXES[number];
export type ApprenticeshipCycleKind = ApprenticeshipCycleAxis | 'unknown';
/**
 * How a cycle's mentor↔mentee interaction actually ran (§4a "dogfooded channel").
 *  - `telegram-playwright` — THE channel: the mentor drove the mentee through the
 *    real Telegram UX via the dedicated Playwright profile (experiences the UX).
 *  - `threadline-backup`   — the backup transport (only when Playwright can't reach
 *    Telegram); still counts toward the keystone.
 *  - `direct-shortcut`     — a CLI/API shortcut that bypassed the UX-under-test;
 *    recorded for honesty but does NOT count toward the keystone axis.
 *  - `unknown`             — unset / grandfathered (pre-field cycles); counts, so the
 *    enforcement never retroactively un-fires an already-earned keystone.
 */
export declare const APPRENTICESHIP_CYCLE_CHANNELS: readonly ["telegram-playwright", "threadline-backup", "direct-shortcut", "unknown"];
export type ApprenticeshipCycleChannel = typeof APPRENTICESHIP_CYCLE_CHANNELS[number];
export interface ApprenticeshipRoleAxisCoverage {
    fired: boolean;
    cycleCount: number;
    lastAt: string | null;
}
/**
 * The keystone axis — the ONE that proves the recursion actually ran at its
 * deepest layer (the mentor actually drove the mentee, vs merely reviewing or
 * overseeing). Surfacing its health is what makes the 2026-06-06 imbalance
 * (mentor-heavy / mentee-light: the mentor layer ran 13 cycles while the
 * mentee layer ran 3) a VISIBLE tracked fact instead of something only a human
 * notices weeks later. "Observation Needs Structure" applied to layer balance.
 */
export declare const APPRENTICESHIP_KEYSTONE_AXIS: ApprenticeshipCycleAxis;
/** Oversight axes — review/direct activity that is NOT the keystone drive. A
 *  program busy on these while the keystone goes stale is drifting away from
 *  actually exercising its mentee. */
export declare const APPRENTICESHIP_OVERSIGHT_AXES: ApprenticeshipCycleAxis[];
/** Default: this many oversight cycles AFTER the last keystone cycle marks the
 *  deepest layer as starved (the program kept reviewing/overseeing without
 *  driving the mentee). Observe-only threshold; tune via roleCoverage opts. */
export declare const DEFAULT_KEYSTONE_STARVATION_OVERSIGHT = 3;
/** Default: the keystone (deepest) layer is DORMANT once its last drive is this
 *  old, regardless of oversight activity. Distinct from `starved` (which needs
 *  oversight to pile up): dormancy is the wall-clock silence that masks as
 *  "healthy" when the whole layer simply goes quiet — the exact blind spot the
 *  bare oversight-since-keystone count can't see. 6h: long enough not to fire on
 *  a normal gap between mentee drives, short enough to catch a real stall.
 *  Observe-only; tune via roleCoverage opts. */
export declare const DEFAULT_KEYSTONE_DORMANCY_MS: number;
/**
 * Observe-only health of the keystone (deepest) layer for one instance. Never
 * gates or blocks — it makes "is the mentee layer actually running?" a
 * queryable fact. `starved=true` means the program is active but its deepest
 * layer is under-firing: either the keystone never ran while oversight did, or
 * enough oversight has piled up since the last keystone drive that the layer
 * has clearly drifted. The generalization of the older narrow `driftWarning`.
 */
export interface ApprenticeshipKeystoneBalance {
    keystoneAxis: ApprenticeshipCycleAxis;
    keystoneCycleCount: number;
    lastKeystoneAt: string | null;
    /** Combined cycle count across the oversight axes. */
    oversightCycleCount: number;
    /** Oversight cycles recorded strictly AFTER the last keystone cycle (or all
     *  of them, if the keystone never fired). */
    oversightSinceKeystone: number;
    /** The deepest layer is under-firing relative to ongoing program activity. */
    starved: boolean;
    /** The threshold actually applied (so callers can show "3 of 3"). */
    starvationThreshold: number;
    /** Milliseconds since the last keystone drive (null if it never fired). The
     *  wall-clock staleness `oversightSinceKeystone` is blind to. */
    lastKeystoneAgeMs: number | null;
    /** The keystone fired before, but its last drive is older than the dormancy
     *  threshold — the deepest layer has gone quiet. Orthogonal to `starved`: a
     *  layer can be dormant without any oversight piling up (total silence reads
     *  "healthy" to the starvation check, which is the gap this closes). */
    dormant: boolean;
    /** The dormancy threshold actually applied, in milliseconds. */
    dormancyThresholdMs: number;
    /** Plain-English why, for surfacing to a human. */
    reason: string;
}
export interface ApprenticeshipRoleCoverage {
    instanceId: string;
    axes: Record<ApprenticeshipCycleAxis, ApprenticeshipRoleAxisCoverage>;
    unknown: ApprenticeshipRoleAxisCoverage;
    dormantAxes: ApprenticeshipCycleAxis[];
    driftWarning: boolean;
    /** mentor-mentee-differential cycles that ran via a `direct-shortcut` (so they
     *  did NOT count toward the keystone axis). Surfaced for honesty — a shortcut is
     *  recorded but can never make the keystone look healthy (§4a enforcement). */
    shortcutDifferentialCount: number;
    /** Observe-only deepest-layer health (the 2026-06-06 mentor/mentee balance
     *  signal). Never gates; surfaces the imbalance so it can't silently drift. */
    keystoneBalance: ApprenticeshipKeystoneBalance;
}
export interface RoleCoverageOptions {
    /** Oversight-since-keystone count that marks the deepest layer starved.
     *  Defaults to DEFAULT_KEYSTONE_STARVATION_OVERSIGHT. */
    oversightStarvationThreshold?: number;
    /** Age (ms) past which the keystone layer is reported DORMANT regardless of
     *  oversight. Defaults to DEFAULT_KEYSTONE_DORMANCY_MS. */
    keystoneDormancyMs?: number;
}
export interface ApprenticeshipCycleRecord {
    id: string;
    instanceId: string;
    cycleNumber: number;
    createdAt: string;
    task: string;
    menteeOutput: string;
    mentorFlagged: string[];
    overseerDifferential: string[];
    coaching: string;
    infraItems: string[];
    kind: ApprenticeshipCycleKind;
    status: string;
    channel: ApprenticeshipCycleChannel;
    /** null only on legacy rows recorded before the gate (grandfathered, like channel='unknown'). */
    operatorSeatUx: OperatorSeatUx | null;
    /** null on legacy rows and on channels where the audit is optional and was not supplied. */
    transcriptAudit: TranscriptAuditAttachment | null;
}
export declare class ApprenticeshipCycleStore {
    private db;
    private unregisterSqliteHandle;
    private now;
    private stmts;
    constructor(opts: ApprenticeshipCycleStoreOptions);
    private prepareStatements;
    record(input: ApprenticeshipCycleRecordInput): ApprenticeshipCycleRecord;
    list(opts?: {
        instanceId?: string;
        limit?: number | string;
    }): ApprenticeshipCycleRecord[];
    get(id: string): ApprenticeshipCycleRecord | null;
    roleCoverage(instanceId: string, opts?: RoleCoverageOptions): ApprenticeshipRoleCoverage;
    /**
     * Observe-only keystone (deepest-layer) health. NEVER gates — it only makes
     * the mentor/mentee balance a queryable fact (the 2026-06-06 imbalance fix:
     * "Observation Needs Structure" applied to layer balance). Starved when the
     * program is active but its keystone drive is under-firing: keystone never
     * ran while oversight did, OR enough oversight has accrued since the last
     * keystone cycle that the layer has clearly drifted.
     */
    private computeKeystoneBalance;
    closeCycle(id: string): ApprenticeshipCycleRecord | null;
    close(): void;
    private rowToRecord;
}
//# sourceMappingURL=ApprenticeshipCycleStore.d.ts.map