/**
 * HttpParitySource.ts — the live Phase-1/3 ParitySource adapter.
 *
 * Portal exposes `GET /api/instar/read` (Dawn, committed at d65136b3b6) as the
 * read-only seam — the architectural pivot from raw Postgres after Prisma Data
 * Platform refused to mint a database role (it forbids CREATE ROLE / GRANT). API
 * level is actually a cleaner seam than direct DB access: the dry-run tests
 * against the same contract Phase 2 (write/update APIs) will use, with no
 * Prisma-admin dependency, and the architectural levels line up (Portal's HTTP
 * surface ↔ Instar's {@link ParitySource} interface).
 *
 * This adapter implements ParitySource via that endpoint. The runner's seam,
 * comparator, invariants, and JSONL audit trail are unchanged — only the read
 * adapter swaps. Reads are PRE-FETCHED in {@link prepare}: the dry-run captures
 * one snapshot of Portal's clusters at a moment in time, then compares against
 * that frozen view. This makes the sync `readPortalClusters()` contract trivially
 * satisfiable and stabilises the comparison against in-flight Portal writes
 * (Portal remains the sole writer; we just look at one consistent slice).
 *
 * The endpoint is paginated (server-side cap: 1000 rows per request). The
 * pagination is keyed off the feedback table — clusters/dispatches accompany each
 * page and may repeat — so cluster collection deduplicates by clusterId across
 * pages and stops when a page returns fewer feedback rows than the requested
 * limit (the documented "no more pages" signal) OR after a hard safety cap.
 *
 * Field naming is intentionally tolerant: cluster rows may arrive as camelCase
 * (Prisma default) or snake_case (raw SQL projection). The mapper accepts both.
 */
import type { ParitySource } from './dryRunCompare.js';
import type { PortalCluster } from '../processor/parity.js';
/** Minimal fetch shape the adapter needs (lets tests pass a stub). */
export type FetchLike = (input: string, init?: {
    headers?: Record<string, string>;
    signal?: AbortSignal;
}) => Promise<{
    ok: boolean;
    status: number;
    statusText: string;
    json(): Promise<unknown>;
    text(): Promise<string>;
}>;
export interface HttpParitySourceConfig {
    /** Portal base URL, e.g. `https://portal.bot-me.ai`. */
    baseUrl: string;
    /** Bearer token with `instar:read` scope. */
    token: string;
    /** Page size sent as `?limit=`. Default 1000 (server max per Dawn's contract). */
    pageSize?: number;
    /** Safety cap on pagination loops. Default 200 pages (= 200k feedback rows). */
    maxPages?: number;
    /** Optional `?status=` filter passed through to the endpoint. */
    status?: string;
    /** Injectable fetch (for tests). Defaults to global `fetch`. */
    fetchImpl?: FetchLike;
    /** Optional path override (defaults to `/api/instar/read`). */
    readPath?: string;
    /**
     * Per-page fetch timeout in ms. Default 90 000 (a healthy full snapshot ran
     * ~15s/page, so 90s is ~6× headroom). Enforced via AbortSignal so one stalled
     * Portal page request cannot hang `prepare()` forever — the 2026-06-05 live
     * incident: a silent page stall left a triggered parity pass unresolved for
     * 10+ minutes with no logged outcome and nothing recorded.
     */
    pageTimeoutMs?: number;
    /**
     * Total budget for the whole snapshot fetch in ms. Default 600 000 (10 min).
     * Checked between pages AND bounds each page's abort signal, so `prepare()`
     * has a hard upper duration even at the 200-page safety cap.
     */
    totalTimeoutMs?: number;
    /**
     * When true, `prepare()` ALSO captures the raw cluster + feedback rows verbatim
     * (every field as the wire delivered it, no coercion) for the AS-IS import
     * runner. Off by default — parity mode only needs the typed cluster projection.
     */
    captureRaw?: boolean;
    /**
     * When true, `prepare()` fetches ONLY the cluster snapshot and stops after the
     * first page — Portal returns the COMPLETE cluster set in `data.clusters` on
     * every page (verified: offset 0/70k/143k and even `limit=1` all return the
     * full 1,370 clusters), so paginating the entire 145K-row feedback table just
     * to collect clusters is pure waste. The parity-pass only needs the clusters
     * (invariant-1 fingerprint), so this fast path lets it complete in ~1s instead
     * of grinding 146 pages and blowing the single-flight max-hold budget (#948 —
     * the server's contended event loop turns the full fetch into a >12min wall).
     * Mutually exclusive with `captureRaw` (the import rehearsal genuinely needs
     * every feedback row); if both are set, `captureRaw` wins and this is ignored.
     */
    clustersOnly?: boolean;
}
/** Error thrown when Portal returns non-OK. The status code is preserved for callers. */
export declare class HttpParitySourceError extends Error {
    readonly status: number;
    constructor(status: number, message: string);
}
/**
 * Live ParitySource backed by Portal's `/api/instar/read` endpoint. Construct
 * with the base URL + read-scope token, then `await source.prepare()` once
 * before passing to {@link runDryRunCompare}. The pre-fetch captures a single
 * consistent snapshot of Portal's clusters; the runner reads it synchronously.
 */
export declare class HttpParitySource implements ParitySource {
    private readonly config;
    private snapshot;
    /** Raw rows verbatim (only populated when `captureRaw` is set). */
    private rawClusters;
    private rawFeedback;
    private rawFeedbackUnkeyed;
    private readonly pageSize;
    private readonly maxPages;
    private readonly fetch;
    private readonly readPath;
    private readonly pageTimeoutMs;
    private readonly totalTimeoutMs;
    constructor(config: HttpParitySourceConfig);
    /** Pre-fetch and cache the cluster snapshot. Idempotent: re-calling re-fetches. */
    prepare(): Promise<void>;
    /** Sync ParitySource read — returns the snapshot captured by {@link prepare}. */
    readPortalClusters(): PortalCluster[];
    /** Raw cluster rows verbatim (requires `captureRaw` + a completed prepare()). */
    readRawClusters(): Record<string, unknown>[];
    /** Raw feedback rows verbatim (requires `captureRaw` + a completed prepare()). */
    readRawFeedback(): Record<string, unknown>[];
}
//# sourceMappingURL=HttpParitySource.d.ts.map