/**
 * CMP.2 — satisfaction probe (async, task-group-gated).
 *
 * Authoritative spec: `docs/tasks/T-compression.md` CMP.2 + the
 * pre-research D1 (`docs/research/T-compression-pre-research-2026-05-27.md`).
 *
 * The locked design ([[project_memory_architecture_dual_surface_sync]]):
 * long-term memory compression is GATED by a user-satisfaction probe.
 * After a GROUP OF TASKS completes (a track/feature group), we want to
 * ask the user "satisfied with <group>?" — and their answer gates
 * whether the compression orchestrator (CMP.4) is allowed to consolidate
 * + delete that group's predecessor memories.
 *
 * D1 — LOCKED: the probe is ASYNC. It is NEVER a synchronous, blocking
 * user prompt mid-flow (that would be the d9-guard false-stop class +
 * would interrupt automation). Instead we APPEND a probe row to a
 * per-session JSONL buffer; the user answers at a natural boundary, and
 * `recordAnswer` writes the answer back. `readSatisfaction` exposes the
 * ANSWERED probes to the orchestrator. Same automation-buffer pattern as
 * `store_lesson.ts` / the wedge capture buffer.
 *
 * Dedup: at most ONE open (unanswered) probe per group at a time — a
 * second `emitProbe` for a group that already has an open probe is a
 * no-op, so a re-firing trigger doesn't pile up duplicate questions.
 *
 * Null-safety: an absent or malformed buffer yields `[]` (never throws)
 * — the orchestrator treats "no answered probe" as "not satisfied →
 * compress nothing", which is the fail-closed default.
 *
 * Storage: `~/.opensquid/sessions/<sessionId>/satisfaction-probe.jsonl`
 * (OPENSQUID_HOME-overridable so tests isolate to a mkdtemp).
 *
 * Imports from: node:fs/promises, node:path, ./paths.js.
 * Imported by: src/runtime/hooks/session-end.ts (emit trigger);
 *   src/runtime/compression_orchestrator.ts (read path, CMP.4).
 */
/**
 * One probe row. `emitted_at` set on emit; the answer fields
 * (`satisfied` + optional `confidence` + `answered_at`) are absent until
 * the user responds. The buffer is append-only — an answer is a NEW row
 * for the same group (the latest answered row wins per group), so we
 * never rewrite history (the locked anti-drift discipline).
 */
export interface SatisfactionProbe {
    group: string;
    emitted_at: string;
    satisfied?: boolean;
    confidence?: number;
    answered_at?: string;
}
/** Buffer path. OPENSQUID_HOME-aware so tests isolate to mkdtemp. */
export declare function probeBufferPath(sessionId: string): string;
/**
 * Derive the feature "group" key from an active task. A track-style
 * task id (`"CMP.4"`) groups by its track prefix (`"CMP"`) so all tasks
 * in a track share ONE probe — the locked design's "after a group of
 * features completes". Falls back to the bare task id, then the subject.
 * Returns `null` when nothing usable is present.
 */
export declare function groupFromTask(task: {
    taskId?: string;
    id?: string;
    subject?: string;
} | null | undefined): string | null;
/**
 * Emit a probe for `group` — appends an unanswered row UNLESS one is
 * already open for the group (dedup). Async + append-only; never blocks.
 */
export declare function emitProbe(sessionId: string, group: string, nowIso?: () => string): Promise<void>;
/**
 * Record the user's answer for `group` — appends an answered row.
 * No-op if there is no open probe for the group (nothing to answer).
 */
export declare function recordAnswer(sessionId: string, group: string, satisfied: boolean, confidence?: number, nowIso?: () => string): Promise<void>;
/**
 * Answered probes only, latest answer per group — what the orchestrator
 * (CMP.4) reads. `[]` on absent/malformed buffer (fail-closed).
 */
export declare function readSatisfaction(sessionId: string): Promise<SatisfactionProbe[]>;
//# sourceMappingURL=satisfaction_probe.d.ts.map