/**
 * # src/pm/oracle — THE PINNED ORACLE DEFINITION (design blocker B5, formal)
 *
 * (bd kestrel-markets-n7jx.2 / PM-persona-benchmark design §11 B5.) The separability factorial
 * (PM-8) freezes the strategist+watcher downstream as an ORACLE so that what varies is only the PM
 * seat's allocation. An undefined oracle ⇒ no separability isolation. This module PINS it, and
 * pins the doctrine that governs how it may and may not be used.
 *
 * ## The interim oracle
 *
 * The interim oracle is the **per-pole best-known book + play-EV table** — exactly the PM-1 / PM-3
 * pattern already shipped in `tests/bench/pm-item-bank.ts` and `tests/bench/pm3-bank.ts`:
 *
 *   - for each pole of each matched pair, a frozen `ev: Record<play, realizedEV>` table giving each
 *     candidate play's realized play-EV under THAT pole's known outcome, and
 *   - an `oracleBook` = the best-known allocation for the pole (the α normalizer).
 *
 * The oracle DATA lives with the banks (closed holdback + public split); this module owns only the
 * TYPE and the DOCTRINE, so the OSS spine carries no repertoire.
 *
 * ## THE ORACLE DOCTRINE (verbatim — this text is load-bearing; do not paraphrase in derived docs)
 *
 *   The oracle is a **grading yardstick, never a supervision target, never an expected-achievable
 *   bar.** Floors are **re-derivable with a latency parameter L** when the clock-honest track lands
 *   (`floors(L)`, regime declared per row). Teacher-corpus admissibility is **gated on the teacher
 *   clearing the comprehension gate on the corpus's render regime.**
 *
 * Unpacked (each clause is a rail, cross-referenced to where it is enforced):
 *
 *  - **Grading yardstick, never a supervision target.** The oracle normalizes α (`bookα/oracleα`);
 *    it is NEVER shown to a graded seat and NEVER used as a training/imitation label. A seat that
 *    is handed the oracle is measuring nothing. (Mirrors the OSS grading firewall; the frozen table
 *    is read only by the grader, never by the PM.)
 *  - **Never an expected-achievable bar.** `oracleα` is best-known, not a floor a good seat "should"
 *    reach; scores are reported relative to it AND to the sham/chance floors, never as "% of a bar a
 *    competent PM must clear." Creative-α (design §12b) can legitimately exceed the oracle on
 *    open-menu items — where the oracle would misgrade a genuinely-better book as error, the oracle
 *    does not apply.
 *  - **`floors(L)` — re-derivable with a latency parameter.** The current oracle is latency-blind.
 *    When the clock-honest track lands, every floor becomes a FUNCTION of an execution-latency
 *    parameter `L`, and each graded row DECLARES the regime `L` it was derived under (a latency-blind
 *    row and a clock-honest row are not comparable and must never be pooled). See {@link Floors}.
 *  - **Teacher-seat comprehension gate** (the TEACHER-SEAT GATE, percept-session corollary to
 *    distill-the-judge). If a reference seat's output becomes a distillation corpus, the ADR-0044
 *    comprehension gate applies to the TEACHER too: a teacher that misreads the render frame teaches
 *    frame-unconditioned noise with perfect confidence. Before any scrimmage/roster raw JSONL is used
 *    as teacher corpus: (1) the teacher seat MUST clear the comprehension gate on the EXACT render
 *    regime the corpus was generated under (regime id stamped — see {@link TeacherCorpusAdmission});
 *    (2) the render is the student's ENTIRE observable universe, so corpus admissibility inherits the
 *    percept-gap question — if the frame-probe ≫ render-probe control (OSS wa0j.60) shows canonical
 *    drops decision-relevant state, corpora generated on that render are bounded by it. The
 *    information-parity gate guarantees the arm carries ≥ canonical CONTENT; wa0j.60's frame-probe is
 *    the deeper question of whether canonical itself is lossy where it matters — owned by the percept
 *    epic, but admissibility here fails closed on it.
 */

/** A candidate play's realized EV under a pole's known outcome — the frozen oracle downstream. */
export type PlayEvTable = Readonly<Record<string, number>>;

/** One entry of an oracle allocation (structurally the bank's `BookEntry`). */
export interface OracleBookEntry {
  readonly play: string;
  readonly size: number;
}

/**
 * The interim oracle for one pole: the frozen play-EV table plus the best-known allocation. This is
 * the exact shape the banks already carry (`Pole.ev` + `Pole.oracleBook`) — pinned here as the
 * canonical type so PM-7/PM-8 consume a named contract, not an ad-hoc record.
 */
export interface PoleOracle {
  /** Realized play-EV per candidate under this pole's known outcome. */
  readonly ev: PlayEvTable;
  /** The best-known allocation for this pole — the α normalizer (`Σ size·EV`). */
  readonly oracleBook: readonly OracleBookEntry[];
}

/**
 * The latency regime a floor/oracle row was derived under. `latency-blind` is the CURRENT interim
 * regime (no execution clock); `clock-honest` rows carry the execution-latency parameter `L` (ms)
 * they were derived at. Rows of different regimes are NOT comparable and must never be pooled.
 */
export type FloorRegime = { readonly kind: "latency-blind" } | { readonly kind: "clock-honest"; readonly L: number };

/**
 * `floors(L)` — the doctrine's promise made a signature. A floor is re-derivable as a function of the
 * latency parameter `L` once the clock-honest track lands; every derived floor stamps the
 * {@link FloorRegime} it was computed under so the grader can refuse to pool across regimes. Until
 * the clock-honest track lands this evaluates the latency-blind regime only.
 */
export interface Floors {
  /** The floor value under the given regime (interim: latency-blind returns the latency-blind floor). */
  readonly value: number;
  /** The regime this floor was derived under — DECLARED per row, never elided. */
  readonly regime: FloorRegime;
}

/**
 * Teacher-corpus admissibility record (the TEACHER-SEAT GATE made checkable). A raw JSONL corpus is
 * admissible as teacher/distillation input ONLY if the teacher seat that generated it cleared the
 * comprehension gate on the corpus's own render regime. Both fields must be present and true, and the
 * `renderRegimeId` must match the corpus's stamped regime, or the corpus is inadmissible (fail closed).
 */
export interface TeacherCorpusAdmission {
  /** The render regime id the corpus was generated under (stamped on the corpus). */
  readonly renderRegimeId: string;
  /** True iff the teacher seat cleared the ADR-0044 comprehension gate on THIS render regime. */
  readonly teacherClearedComprehensionGate: boolean;
  /** True iff the frame-probe ≫ render-probe percept-gap control (OSS wa0j.60) did NOT fire on this render. */
  readonly perceptGapClear: boolean;
}

/**
 * Fail-closed admissibility check for a teacher corpus. A corpus is admissible only when the teacher
 * cleared the comprehension gate on the corpus's own render regime AND the percept-gap control is
 * clear for that render. Returns the reason it is inadmissible, or `null` if admissible.
 */
export function teacherCorpusInadmissibleReason(a: TeacherCorpusAdmission): string | null {
  if (!a.teacherClearedComprehensionGate) {
    return `teacher did not clear the comprehension gate on render regime ${JSON.stringify(a.renderRegimeId)} — ` +
      `a teacher that misreads the frame teaches frame-unconditioned noise with perfect confidence`;
  }
  if (!a.perceptGapClear) {
    return `percept-gap control (frame-probe ≫ render-probe, wa0j.60) fired on render regime ` +
      `${JSON.stringify(a.renderRegimeId)} — canonical drops decision-relevant state; corpus is bounded by the render`;
  }
  return null;
}
