/**
 * # protocol/oversight-wire — the SNAKE_CASE wire mirror of the oversight contract (kestrel-telx.5).
 *
 * The oversight stream (contract §4) is served over the SAME platform HTTP/SSE dialect the
 * Operation stream is: **snake_case bodies**, an **opaque STRING cursor**, a **closed `event:`
 * enum**. `src/protocol/oversight.ts` is the camelCase DOMAIN contract both Renderings consume;
 * this leaf is its wire face, decoded to the domain types AT THE BOUNDARY (contract §4.4). It is
 * re-exported by {@link ./wire.ts} — the one import path the CLI transport
 * ({@link ../cli/backend/wire.ts}) already re-exports — so there is exactly ONE definition of the
 * oversight wire shapes and exactly ONE definition of the SSE vocabulary (the enum itself stays in
 * `oversight.ts`; nothing here re-declares it). It lives in its own file only because it is long;
 * every consumer reaches it through `wire.ts`, per the bead.
 *
 * ## FAIL CLOSED — a decoder is a GATE, not a cast
 * Every decoder below reads `unknown` and CHECKS each required field, throwing
 * {@link OversightWireError} naming the exact path. A missing / mistyped field is a loud protocol
 * violation, never `undefined` smuggled into a domain type and never a silent default. Nullable
 * contract fields (`fair`, `plan`, `note`, …) are decoded as EXPLICIT `null` — absent-not-hidden —
 * and a `null` where the contract requires a value still reds.
 *
 * ## ZERO runtime dependencies (OSS-ADR-0046 + tests/protocol.boundary.test.ts)
 * The only imports are intra-protocol. In particular this leaf holds NO CLI error type: it throws
 * its own dependency-free {@link OversightWireError}, which the CLI client
 * ({@link ../cli/backend/oversight-remote.ts}) wraps into a `CliError` with code
 * `OVERSIGHT_PROTOCOL_VIOLATION` (contract §4.3 rule 1/2). Same discipline as
 * {@link ../client/sse-transport.ts}: the transport/decoder layer is error-agnostic, the caller owns
 * the error TAXONOMY.
 *
 * ## NOT in the shipped JSON Schema (slice-1 posture)
 * `scripts/gen-wire-schema.ts` reflects an explicit root list (`WIRE_COMPOSITES`, the ten slice-1
 * RESPONSE composites). The oversight shapes are deliberately NOT added to it: the platform route
 * (§4.1) does not exist yet, and shipping a schema for a route nobody serves would be a gate whose
 * stated coverage exceeds its actual coverage. Adding them is a one-line follow-up when the route
 * lands.
 */

import type {
  AgentTier,
  AgentTierStatus,
  Attribution,
  AuthorTier,
  Authorship,
  BookView,
  Caller,
  CallerDetection,
  CallerKind,
  EngineActionKind,
  EscalationReason,
  KernelBrief,
  KernelBudget,
  KernelClaim,
  KernelEngineAction,
  KernelField,
  KernelFill,
  KernelLeg,
  KernelMandate,
  KernelOwnerAct,
  KernelPlanState,
  KernelPosition,
  KernelRestingOrder,
  KernelVehicleHealth,
  KernelWake,
  MessageAuthor,
  Mode,
  OrgNode,
  OversightAct,
  OversightActRecord,
  OversightDelivery,
  OversightEscalation,
  OversightEvent,
  OversightEventType,
  OversightFrame,
  OversightIdentity,
  OversightKernel,
  OversightMessage,
  OversightTurn,
  PlanLifecycle,
  PlanOutcome,
  PodView,
  RiskEnvelope,
  SpectatorFrame,
  SpectatorPane,
  TurnDisposition,
  WakeSeverity,
} from "./oversight.ts";
import {
  AGENT_TIERS,
  ATTRIBUTIONS,
  AUTHOR_TIERS,
  CALLER_DETECTIONS,
  CALLER_KINDS,
  ENGINE_ACTION_KINDS,
  ESCALATION_REASONS,
  MESSAGE_AUTHORS,
  MODES,
  OVERSIGHT_ACT_KINDS,
  PLAN_LIFECYCLES,
  PLAN_OUTCOMES,
  TURN_DISPOSITIONS,
  WAKE_SEVERITIES,
} from "./oversight.ts";
import type { Scope } from "./index.ts";
import type { FailureClass, OperationId, SessionDiagnostic, SessionId, TurnBody, TurnEntry } from "./session.ts";
import { FAILURE_CLASSES, SESSION_DIAGNOSTICS } from "./session.ts";

/* ─────────────────────────── the fail-closed reader ─────────────────────────── */

/** A wire body that does not match the contract. Dependency-free on purpose: the CLI wraps it as a
 *  `CliError{code:"OVERSIGHT_PROTOCOL_VIOLATION"}`, the SDK could wrap it as its own. */
export class OversightWireError extends Error {
  constructor(
    readonly path: string,
    detail: string,
  ) {
    super(`oversight wire: ${path} — ${detail}`);
    this.name = "OversightWireError";
  }
}

type Rec = Record<string, unknown>;

function kindOf(v: unknown): string {
  if (v === null) return "null";
  if (Array.isArray(v)) return "array";
  return typeof v;
}

/** Narrow `v` to a plain object or fail closed. */
function obj(v: unknown, path: string): Rec {
  if (typeof v !== "object" || v === null || Array.isArray(v)) {
    throw new OversightWireError(path, `expected an object, got ${kindOf(v)}`);
  }
  return v as Rec;
}

function str(o: Rec, k: string, path: string): string {
  const v = o[k];
  if (typeof v !== "string") throw new OversightWireError(`${path}.${k}`, `expected string, got ${kindOf(v)}`);
  return v;
}

function num(o: Rec, k: string, path: string): number {
  const v = o[k];
  if (typeof v !== "number" || !Number.isFinite(v)) {
    throw new OversightWireError(`${path}.${k}`, `expected a finite number, got ${kindOf(v)}`);
  }
  return v;
}

function bool(o: Rec, k: string, path: string): boolean {
  const v = o[k];
  if (typeof v !== "boolean") throw new OversightWireError(`${path}.${k}`, `expected boolean, got ${kindOf(v)}`);
  return v;
}

/** A REQUIRED nullable field: present and either the value or an explicit `null` (absent-not-hidden
 *  — a DROPPED key still reds; only an explicit `null` reads as UNKNOWN). */
function nullable<T>(read: (o: Rec, k: string, path: string) => T) {
  return (o: Rec, k: string, path: string): T | null => {
    if (!(k in o)) throw new OversightWireError(`${path}.${k}`, "required (nullable) field is absent — absent-not-hidden");
    return o[k] === null ? null : read(o, k, path);
  };
}
const nullStr = nullable(str);
const nullNum = nullable(num);

/** An OPTIONAL field: absent ⇒ `undefined`; present ⇒ type-checked. */
function optional<T>(read: (o: Rec, k: string, path: string) => T) {
  return (o: Rec, k: string, path: string): T | undefined =>
    o[k] === undefined ? undefined : read(o, k, path);
}

/** A closed vocabulary member, checked against its runtime tuple — the wire can never smuggle an
 *  off-enum member in as a bare string. */
function member<T extends string>(tuple: readonly T[]) {
  return (o: Rec, k: string, path: string): T => {
    const v = str(o, k, path);
    if (!(tuple as readonly string[]).includes(v)) {
      throw new OversightWireError(`${path}.${k}`, `${JSON.stringify(v)} is outside the closed vocabulary [${tuple.join(", ")}]`);
    }
    return v as T;
  };
}

function list<T>(o: Rec, k: string, path: string, each: (v: unknown, path: string) => T): readonly T[] {
  const v = o[k];
  if (!Array.isArray(v)) throw new OversightWireError(`${path}.${k}`, `expected array, got ${kindOf(v)}`);
  return v.map((item, i) => each(item, `${path}.${k}[${i}]`));
}

function strList(o: Rec, k: string, path: string): readonly string[] {
  return list(o, k, path, (v, p) => {
    if (typeof v !== "string") throw new OversightWireError(p, `expected string, got ${kindOf(v)}`);
    return v;
  });
}

/** A REQUIRED nullable SUB-OBJECT decoded by `dec`. */
function nullObj<T>(o: Rec, k: string, path: string, dec: (v: unknown, path: string) => T): T | null {
  if (!(k in o)) throw new OversightWireError(`${path}.${k}`, "required (nullable) section is absent — absent-not-hidden");
  return o[k] === null ? null : dec(o[k], `${path}.${k}`);
}

const callerKind = member<CallerKind>(CALLER_KINDS);
const callerDetection = member<CallerDetection>(CALLER_DETECTIONS);
const mode = member<Mode>(MODES);
const attribution = member<Attribution>(ATTRIBUTIONS);
const planLifecycle = member<PlanLifecycle>(PLAN_LIFECYCLES);
const planOutcome = member<PlanOutcome>(PLAN_OUTCOMES);
const wakeSeverity = member<WakeSeverity>(WAKE_SEVERITIES);
const engineActionKind = member<EngineActionKind>(ENGINE_ACTION_KINDS);
const agentTier = member<AgentTier>(AGENT_TIERS);
const authorTier = member<AuthorTier>(AUTHOR_TIERS);
const escalationReason = member<EscalationReason>(ESCALATION_REASONS);
const messageAuthor = member<MessageAuthor>(MESSAGE_AUTHORS);
const turnDisposition = member<TurnDisposition>(TURN_DISPOSITIONS);
const actKind = member(OVERSIGHT_ACT_KINDS);
const failureClass = member<FailureClass>(FAILURE_CLASSES);
const sessionDiagnostic = member<SessionDiagnostic>(SESSION_DIAGNOSTICS);
const side = member<"buy" | "sell">(["buy", "sell"]);

/* ────────────────────────────── identity (§3.1) ────────────────────────────── */

export function decodeCaller(v: unknown, path = "caller"): Caller {
  const o = obj(v, path);
  return {
    kind: callerKind(o, "kind", path),
    harness: nullStr(o, "harness", path),
    detectedBy: callerDetection(o, "detected_by", path),
    interactive: bool(o, "interactive", path),
  };
}

export function decodeOversightIdentity(v: unknown, path = "identity"): OversightIdentity {
  const o = obj(v, path);
  const operation = optional(str)(o, "operation", path);
  return {
    caller: decodeCaller(o["caller"], `${path}.caller`),
    sessionId: str(o, "session_id", path) as SessionId,
    ...(operation !== undefined ? { operation: operation as OperationId } : {}),
    mode: mode(o, "mode", path),
    // `Scope` is the platform's capability vocabulary, already pinned by the Operation dialect;
    // it rides through as its string members (no oversight-local re-declaration).
    scopes: strList(o, "scopes", path) as readonly Scope[],
  };
}

/* ────────────────────────────── the kernel (§3.2) ──────────────────────────── */

export function decodeKernelField(v: unknown, path: string): KernelField {
  const o = obj(v, path);
  const source = optional(str)(o, "source", path);
  const modelVer = optional(str)(o, "model_ver", path);
  const confidence = optional(num)(o, "confidence", path);
  const asOfSeq = optional(num)(o, "as_of_seq", path);
  return {
    value: num(o, "value", path),
    attribution: attribution(o, "attribution", path),
    ...(source !== undefined ? { source } : {}),
    ...(modelVer !== undefined ? { modelVer } : {}),
    ...(confidence !== undefined ? { confidence } : {}),
    ...(asOfSeq !== undefined ? { asOfSeq } : {}),
  };
}

export function decodeKernelLeg(v: unknown, path: string): KernelLeg {
  const o = obj(v, path);
  const strike = optional(num)(o, "strike", path);
  const right = optional(member<"C" | "P">(["C", "P"]))(o, "right", path);
  // ADR-0017: strike and right are BOTH present (an option) or BOTH absent (spot). A half-populated
  // leg would render a fictional strike — refuse it.
  if ((strike === undefined) !== (right === undefined)) {
    throw new OversightWireError(path, "strike and right must be BOTH present (option) or BOTH absent (spot) — ADR-0017");
  }
  return {
    symbol: str(o, "symbol", path),
    ...(strike !== undefined ? { strike } : {}),
    ...(right !== undefined ? { right } : {}),
  };
}

export function decodeKernelPosition(v: unknown, path: string): KernelPosition {
  const o = obj(v, path);
  return {
    leg: decodeKernelLeg(o["leg"], `${path}.leg`),
    qty: num(o, "qty", path),
    basis: num(o, "basis", path),
    fair: nullNum(o, "fair", path),
    unrealUsd: nullNum(o, "unreal_usd", path),
    plan: nullStr(o, "plan", path),
    claimOwner: nullStr(o, "claim_owner", path),
    structure: nullStr(o, "structure", path),
  };
}

export function decodeKernelRestingOrder(v: unknown, path: string): KernelRestingOrder {
  const o = obj(v, path);
  return {
    ref: str(o, "ref", path),
    leg: decodeKernelLeg(o["leg"], `${path}.leg`),
    side: side(o, "side", path),
    qty: num(o, "qty", path),
    px: num(o, "px", path),
    live: bool(o, "live", path),
    clamped: bool(o, "clamped", path),
    note: nullStr(o, "note", path),
    plan: nullStr(o, "plan", path),
  };
}

export function decodeKernelFill(v: unknown, path: string): KernelFill {
  const o = obj(v, path);
  return {
    leg: decodeKernelLeg(o["leg"], `${path}.leg`),
    side: side(o, "side", path),
    qty: num(o, "qty", path),
    px: num(o, "px", path),
    plan: nullStr(o, "plan", path),
  };
}

export function decodeKernelPlanState(v: unknown, path: string): KernelPlanState {
  const o = obj(v, path);
  return {
    name: str(o, "name", path),
    state: planLifecycle(o, "state", path),
    outcome: "outcome" in o && o["outcome"] === null ? null : planOutcome(o, "outcome", path),
    note: nullStr(o, "note", path),
    blockedReason: nullStr(o, "blocked_reason", path),
  };
}

export function decodeRiskEnvelope(v: unknown, path: string): RiskEnvelope {
  const o = obj(v, path);
  return {
    remainingR: num(o, "remaining_r", path),
    planEnvelope: num(o, "plan_envelope", path),
    bookEnvelope: num(o, "book_envelope", path),
    ownerEnvelope: num(o, "owner_envelope", path),
  };
}

export function decodeKernelBudget(v: unknown, path: string): KernelBudget {
  const o = obj(v, path);
  return {
    used: nullNum(o, "used", path),
    remaining: nullNum(o, "remaining", path),
    total: nullNum(o, "total", path),
    maxConcurrentR: nullNum(o, "max_concurrent_r", path),
  };
}

export function decodeKernelWake(v: unknown, path: string): KernelWake {
  const o = obj(v, path);
  return {
    reason: str(o, "reason", path),
    severity: wakeSeverity(o, "severity", path),
    deadlineMin: nullNum(o, "deadline_min", path),
  };
}

export function decodeKernelVehicleHealth(v: unknown, path: string): KernelVehicleHealth {
  const o = obj(v, path);
  return {
    symbol: str(o, "symbol", path),
    bidPresentRate: num(o, "bid_present_rate", path),
    twoSided: bool(o, "two_sided", path),
    staleS: num(o, "stale_s", path),
    dark: bool(o, "dark", path),
  };
}

export function decodeKernelEngineAction(v: unknown, path: string): KernelEngineAction {
  const o = obj(v, path);
  return {
    id: str(o, "id", path),
    kind: engineActionKind(o, "kind", path),
    asofSeq: num(o, "asof_seq", path),
    reason: nullStr(o, "reason", path),
  };
}

export function decodeKernelOwnerAct(v: unknown, path: string): KernelOwnerAct {
  const o = obj(v, path);
  return { id: str(o, "id", path), kind: str(o, "kind", path), asofSeq: num(o, "asof_seq", path) };
}

export function decodeKernelClaim(v: unknown, path: string): KernelClaim {
  const o = obj(v, path);
  return {
    field: decodeKernelField(o["field"], `${path}.field`),
    claimType: member<"predictor" | "regime">(["predictor", "regime"])(o, "claim_type", path),
  };
}

export function decodeKernelMandate(v: unknown, path: string): KernelMandate {
  const o = obj(v, path);
  return {
    objective: str(o, "objective", path),
    rUsd: num(o, "r_usd", path),
    successCriterion: str(o, "success_criterion", path),
    riskRule: str(o, "risk_rule", path),
  };
}

export function decodeKernelBrief(v: unknown, path: string): KernelBrief {
  const o = obj(v, path);
  return { text: str(o, "text", path), hash: str(o, "hash", path), version: nullStr(o, "version", path) };
}

/** The acting kernel. EVERY section is required on the wire (absent-not-hidden, §3.2): an absent
 *  source section arrives as an explicit `null`/`[]`, never as a dropped key. */
export function decodeOversightKernel(v: unknown, path = "kernel"): OversightKernel {
  const o = obj(v, path);
  return {
    mandate: nullObj(o, "mandate", path, decodeKernelMandate),
    brief: nullObj(o, "brief", path, decodeKernelBrief),
    wake: nullObj(o, "wake", path, decodeKernelWake),
    dataHealth: list(o, "data_health", path, decodeKernelVehicleHealth),
    unavailable: strList(o, "unavailable", path),
    budgetEnvelope: nullObj(o, "budget_envelope", path, decodeRiskEnvelope),
    ownerActs: list(o, "owner_acts", path, decodeKernelOwnerAct),
    engineLog: list(o, "engine_log", path, decodeKernelEngineAction),
    claims: list(o, "claims", path, decodeKernelClaim),
    positions: list(o, "positions", path, decodeKernelPosition),
    resting: list(o, "resting", path, decodeKernelRestingOrder),
    fillsSinceLast: list(o, "fills_since_last", path, decodeKernelFill),
    budget: nullObj(o, "budget", path, decodeKernelBudget),
    plans: list(o, "plans", path, decodeKernelPlanState),
  };
}

/* ─────────────────────────────── the org (§3.3) ────────────────────────────── */

export function decodeAuthorship(v: unknown, path: string): Authorship {
  const o = obj(v, path);
  return {
    tier: authorTier(o, "tier", path),
    model: nullStr(o, "model", path),
    version: nullStr(o, "version", path),
  };
}

export function decodeAgentTierStatus(v: unknown, path: string): AgentTierStatus {
  const o = obj(v, path);
  const s = obj(o["strategist"], `${path}.strategist`);
  const w = obj(o["watcher"], `${path}.watcher`);
  const e = obj(o["escalation"], `${path}.escalation`);
  return {
    strategist: {
      model: nullStr(s, "model", `${path}.strategist`),
      thesis: nullStr(s, "thesis", `${path}.strategist`),
      briefHash: nullStr(s, "brief_hash", `${path}.strategist`),
      lastReframeSeq: nullNum(s, "last_reframe_seq", `${path}.strategist`),
    },
    watcher: {
      model: nullStr(w, "model", `${path}.watcher`),
      lastActionSeq: nullNum(w, "last_action_seq", `${path}.watcher`),
    },
    escalation: {
      pending: bool(e, "pending", `${path}.escalation`),
      reason: "reason" in e && e["reason"] === null ? null : escalationReason(e, "reason", `${path}.escalation`),
      atSeq: nullNum(e, "at_seq", `${path}.escalation`),
    },
    configId: nullStr(o, "config_id", path),
  };
}

export function decodeBookView(v: unknown, path: string): BookView {
  const o = obj(v, path);
  const cov = obj(o["coverage"], `${path}.coverage`);
  const st = obj(o["status"], `${path}.status`);
  return {
    bookId: str(o, "book_id", path),
    coverage: {
      symbols: strList(cov, "symbols", `${path}.coverage`),
      thesis: str(cov, "thesis", `${path}.coverage`),
    },
    kernel: decodeOversightKernel(o["kernel"], `${path}.kernel`),
    tiers: decodeAgentTierStatus(o["tiers"], `${path}.tiers`),
    status: {
      severity: wakeSeverity(st, "severity", `${path}.status`),
      deadlineMin: nullNum(st, "deadline_min", `${path}.status`),
      wakesRemaining: nullNum(st, "wakes_remaining", `${path}.status`),
      coalesced: num(st, "coalesced", `${path}.status`),
    },
  };
}

export function decodePodView(v: unknown, path: string): PodView {
  const o = obj(v, path);
  const aggRaw = obj(o["aggregate"], `${path}.aggregate`);
  const aggregate: Record<string, Record<string, number>> = {};
  for (const [childId, facts] of Object.entries(aggRaw)) {
    const f = obj(facts, `${path}.aggregate.${childId}`);
    const inner: Record<string, number> = {};
    for (const key of Object.keys(f)) inner[key] = num(f, key, `${path}.aggregate.${childId}`);
    aggregate[childId] = inner;
  }
  return {
    podId: str(o, "pod_id", path),
    envelope: decodeRiskEnvelope(o["envelope"], `${path}.envelope`),
    aggregate,
    children: list(o, "children", path, decodeOrgNode),
  };
}

export function decodeOrgNode(v: unknown, path: string): OrgNode {
  const o = obj(v, path);
  const node = member<"book" | "pod">(["book", "pod"])(o, "node", path);
  return node === "book"
    ? { node: "book", book: decodeBookView(o["book"], `${path}.book`) }
    : { node: "pod", pod: decodePodView(o["pod"], `${path}.pod`) };
}

/* ──────────────────────────── the Frame (§3.4, §4.2) ───────────────────────── */

export function decodeSpectatorPane(v: unknown, path: string): SpectatorPane {
  const o = obj(v, path);
  return {
    paneId: str(o, "pane_id", path),
    columns: strList(o, "columns", path),
    rows: list(o, "rows", path, (row, rp) => {
      if (!Array.isArray(row)) throw new OversightWireError(rp, `expected a row array, got ${kindOf(row)}`);
      return row.map((cell, i) => {
        if (cell === null || typeof cell === "string" || (typeof cell === "number" && Number.isFinite(cell))) {
          return cell as string | number | null;
        }
        throw new OversightWireError(`${rp}[${i}]`, `expected a scalar cell (string | finite number | null), got ${kindOf(cell)}`);
      });
    }),
  };
}

export function decodeSpectatorFrame(v: unknown, path: string): SpectatorFrame {
  const o = obj(v, path);
  return {
    watchlist: strList(o, "watchlist", path),
    // The ONE permitted wall clock in this contract (§4 invariant 4) — spectator only.
    asof: str(o, "asof", path),
    panes: list(o, "panes", path, decodeSpectatorPane),
  };
}

export function decodeOversightMessage(v: unknown, path: string): OversightMessage {
  const o = obj(v, path);
  return {
    seq: num(o, "seq", path),
    messageId: str(o, "message_id", path),
    author: messageAuthor(o, "author", path),
    to: nullStr(o, "to", path),
    text: str(o, "text", path),
  };
}

export function decodeOversightFrame(v: unknown, path = "frame"): OversightFrame {
  const o = obj(v, path);
  return {
    identity: decodeOversightIdentity(o["identity"], `${path}.identity`),
    asofSeq: num(o, "asof_seq", path),
    pod: nullObj(o, "pod", path, decodePodView),
    spectator: nullObj(o, "spectator", path, decodeSpectatorFrame),
    pending: nullObj(o, "pending", path, decodeOversightDelivery),
    messages: list(o, "messages", path, decodeOversightMessage),
  };
}

/* ─────────────────────────── the turn-stream (§3.5) ────────────────────────── */

export function decodeOversightDelivery(v: unknown, path = "delivery"): OversightDelivery {
  const o = obj(v, path);
  return {
    sessionId: str(o, "session_id", path) as SessionId,
    ordinal: num(o, "ordinal", path),
    parentHash: str(o, "parent_hash", path),
    // The RUNTIME's Frame address, carried verbatim — a Rendering never re-hashes the projection.
    frameRoot: str(o, "frame_root", path),
    bookId: str(o, "book_id", path),
    tier: agentTier(o, "tier", path),
    kernel: decodeOversightKernel(o["kernel"], `${path}.kernel`),
  };
}

export function decodeTurnBody(v: unknown, path: string): TurnBody {
  const o = obj(v, path);
  const kind = member<"authored" | "stand-down" | "failure">(["authored", "stand-down", "failure"])(o, "kind", path);
  switch (kind) {
    case "authored":
      return { kind, bytes: str(o, "bytes", path) };
    case "stand-down":
      return { kind, reason: str(o, "reason", path) };
    case "failure":
      return { kind, failureClass: failureClass(o, "failure_class", path) };
  }
}

export function decodeTurnEntry(v: unknown, path: string): TurnEntry {
  const o = obj(v, path);
  if (o["kind"] !== "turn") throw new OversightWireError(`${path}.kind`, `expected "turn", got ${JSON.stringify(o["kind"])}`);
  return {
    kind: "turn",
    sessionId: str(o, "session_id", path) as SessionId,
    ordinal: num(o, "ordinal", path),
    parentHash: str(o, "parent_hash", path),
    frameRoot: str(o, "frame_root", path),
    authoredSha256: str(o, "authored_sha256", path),
    body: decodeTurnBody(o["body"], `${path}.body`),
    entryHash: str(o, "entry_hash", path),
  };
}

export function decodeOversightTurn(v: unknown, path = "turn"): OversightTurn {
  const o = obj(v, path);
  return {
    entry: decodeTurnEntry(o["entry"], `${path}.entry`),
    disposition: turnDisposition(o, "disposition", path),
    authoredBy: decodeAuthorship(o["authored_by"], `${path}.authored_by`),
    escalated: "escalated" in o && o["escalated"] === null ? null : escalationReason(o, "escalated", path),
  };
}

export function decodeOversightEscalation(v: unknown, path = "escalation"): OversightEscalation {
  const o = obj(v, path);
  return {
    seq: num(o, "seq", path),
    bookId: str(o, "book_id", path),
    // NB: dot-access `o.from`, never the bracket-quoted form — the protocol.boundary import
    // scanner regex reads a quoted key of that name as an ES import specifier and false-positives.
    from: decodeAuthorship(o.from, `${path}.from`),
    to: authorTier(o, "to", path),
    reason: escalationReason(o, "reason", path),
    note: nullStr(o, "note", path),
    answeredBySeq: nullNum(o, "answered_by_seq", path),
  };
}

/* ──────────────────────────────── acts (§3.6) ──────────────────────────────── */

export function decodeOversightAct(v: unknown, path = "act"): OversightAct {
  const o = obj(v, path);
  const act = actKind(o, "act", path);
  switch (act) {
    case "allocate":
      return { act, target: str(o, "target", path), envelopeR: num(o, "envelope_r", path) };
    case "arm":
      return { act, target: str(o, "target", path) };
    case "de-arm":
      return { act, target: str(o, "target", path), reason: str(o, "reason", path) };
    case "coverage":
      return {
        act,
        bookId: str(o, "book_id", path),
        symbols: strList(o, "symbols", path),
        thesis: str(o, "thesis", path), // REQUIRED: instruments alone are not coverage
      };
    case "fund":
      return { act, ownerEnvelope: num(o, "owner_envelope", path), authorizationRef: str(o, "authorization_ref", path) };
    case "de-fund":
      return { act, ownerEnvelope: num(o, "owner_envelope", path) };
    case "pause":
      return { act, target: str(o, "target", path) };
    case "veto":
      return { act, target: str(o, "target", path), reason: str(o, "reason", path) };
  }
}

export function decodeOversightActRecord(v: unknown, path = "record"): OversightActRecord {
  const o = obj(v, path);
  return {
    seq: num(o, "seq", path),
    actId: str(o, "act_id", path),
    act: decodeOversightAct(o["act"], `${path}.act`),
    authoredBy: decodeAuthorship(o["authored_by"], `${path}.authored_by`),
  };
}

/* ───────────────────────────── the SSE envelope (§4) ───────────────────────── */

/**
 * The oversight SSE frame's JSON `data:` payload — the mirror of {@link ./wire.ts WireOperationEvent}.
 * `cursor` echoes the SSE `id:` line (an OPAQUE STRING — §4.3 rule 6: never parsed), `type` is the
 * closed enum from `oversight.ts` (ONE definition — this shape re-declares nothing), and the
 * type-specific body rides in `data` as snake_case.
 */
export interface WireOversightEvent {
  readonly cursor: string;
  readonly type: OversightEventType;
  readonly session_id: string;
  readonly data?: Record<string, unknown>;
}

/**
 * Decode ONE typed oversight event body into the camelCase domain union (contract §4.2 table).
 *
 * `type` MUST already have been admitted against `isOversightEventType` (§4.3 rule 1 — the
 * transport's closed-vocabulary gate); this decoder is TOTAL over the enum, so a member added to
 * the enum without a case here is a compile error (the `never` exhaustiveness arm), not a silent
 * pass-through.
 */
export function decodeOversightEvent(type: OversightEventType, data: unknown): OversightEvent {
  const path = type;
  switch (type) {
    case "oversight.snapshot":
      return { type, frame: decodeOversightFrame(obj(data, path)["frame"], `${path}.frame`) };
    case "oversight.delivery": {
      const o = obj(data, path);
      return { type, seq: num(o, "seq", path), delivery: decodeOversightDelivery(o["delivery"], `${path}.delivery`) };
    }
    case "oversight.turn": {
      const o = obj(data, path);
      return { type, seq: num(o, "seq", path), turn: decodeOversightTurn(o["turn"], `${path}.turn`) };
    }
    case "oversight.act":
      return { type, record: decodeOversightActRecord(obj(data, path)["record"], `${path}.record`) };
    case "oversight.escalation":
      return { type, escalation: decodeOversightEscalation(obj(data, path)["escalation"], `${path}.escalation`) };
    case "oversight.message":
      return { type, message: decodeOversightMessage(obj(data, path)["message"], `${path}.message`) };
    case "oversight.journal": {
      const o = obj(data, path);
      return {
        type,
        seq: num(o, "seq", path),
        bookId: str(o, "book_id", path),
        authoredBy: decodeAuthorship(o["authored_by"], `${path}.authored_by`),
        text: str(o, "text", path),
      };
    }
    case "oversight.diagnostic": {
      const o = obj(data, path);
      return { type, diagnostic: sessionDiagnostic(o, "diagnostic", path), ordinal: num(o, "ordinal", path) };
    }
    case "oversight.finalized": {
      const o = obj(data, path);
      return {
        type,
        seq: num(o, "seq", path),
        sessionId: str(o, "session_id", path) as SessionId,
        tipHash: str(o, "tip_hash", path),
        artifacts: strList(o, "artifacts", path),
      };
    }
    case "oversight.failed":
      return { type, reason: str(obj(data, path), "reason", path) };
    default: {
      // fail closed: an enum member with no decoder is a protocol drift, never a silent default.
      const never: never = type;
      throw new OversightWireError("type", `no decoder for ${JSON.stringify(never)}`);
    }
  }
}

/**
 * The BUS-BACKED `seq` of a decoded event, or `null` for the two members that carry none
 * (`oversight.snapshot` — a projection; `oversight.diagnostic` — nothing landed; `oversight.failed`
 * — the stream is dying). This is the input to §4.3 rule 4 (monotone seq): the rule can only apply
 * where the contract says a `seq` exists, so the extraction lives HERE, beside the shapes, rather
 * than being re-derived by each client.
 */
export function busSeqOf(e: OversightEvent): number | null {
  switch (e.type) {
    case "oversight.delivery":
    case "oversight.turn":
    case "oversight.journal":
    case "oversight.finalized":
      return e.seq;
    case "oversight.act":
      return e.record.seq;
    case "oversight.escalation":
      return e.escalation.seq;
    case "oversight.message":
      return e.message.seq;
    case "oversight.snapshot":
    case "oversight.diagnostic":
    case "oversight.failed":
      return null;
    default: {
      const never: never = e;
      throw new OversightWireError("event", `unhandled event ${JSON.stringify(never)}`);
    }
  }
}
