/**
 * # blotter/project — the pure Blotter projector (kestrel-a57.1 slice 2, ADR-0011)
 *
 * `project(bus)` is the **permanent, deterministic** fold from one canonical GRADED bus into a
 * {@link Blotter}. Its one invariant (ADR-0011): **it is a pure function of the bus** — the same bus
 * projects to a byte-identical Blotter, and no engine-state scrape is ever permitted. Everything the
 * Blotter carries is re-derived from bus bytes:
 *
 *   • META (seq 0)                  → session identity / judge / fidelity / bus receipt
 *   • JOURNAL events                → journals[] (full body inline) + plan reasoning_ref (by seq)
 *   • PLAN events                   → plans[] (lifecycle + final_state)
 *   • ORDER + TELEMETRY events      → orders[] (place ⋈ fill/cancel/reject ⋈ esc/reprice ⋈ settle)
 *   • settle-outcome TELEMETRY      → totals{floor, expected} + headline taint + orders[].support +
 *                                     fill_claim[] (expected-$ partitioned calibrated|extrapolated, a57.4)
 *   • settle_mark TELEMETRY         → totals.settle_mark (the settle spot's provenance + staleness
 *                                     verdict, kestrel-xwf; a stale mark taints the headline)
 *   • META fill_model               → fidelity.self_limitation (what the judge could NOT observe, a57.4)
 *
 * **Fail closed (ADR-0011).** The projector requires a GRADED bus: a bus whose opening META lacks the
 * judge self-description (`fill_model`/`instance`/`fidelity`) is a fill-model-agnostic INPUT tape, not a
 * graded bus — `project` refuses it with a logged reason rather than inventing a judge (the two-bus rule).
 *
 * **Scope.** The aggregated `fill_claim[]` rollup and the fidelity self-limitation stamp land in a57.4
 * (this slice); the paper/live certification legs (a57.3) and all human/legible rendering (a57.13) remain
 * OUT — the projector never renders. The
 * report→Blotter unification (the existing {@link ../session EpisodeReport} still stands beside the
 * Blotter) is a LATER cleanup.
 */

import type {
  BusEvent,
  ExperimentalEnvelope,
  FillModelStamp,
  FillSupport,
  JournalEvent,
  MetaEvent,
  OrderEvent,
  PlanOutcome,
  PlanState,
  RankableReason,
  TelemetryGuardEvent,
  TelemetryOrderEvent,
  TelemetrySettleEvent,
  TelemetrySettleMarkEvent,
  TelemetryThetaBleedEvent,
  TokenAccounting,
} from "../bus/index.ts";
import { CORPUS_TIERS, FACES, groupPlanInstances, serializeBus } from "../bus/index.ts";
// The support partition is OWNED by src/support (kestrel-dpy, ADR-0014): the projector CONSUMES it to
// build the SIGNED fill_claim sub-cells rather than re-deriving a sign split here.
import { partition } from "../support/index.ts";
// The headline policy is OWNED by src/grade/headline.ts (kestrel-9gu.12): the projector assembles the
// gate evidence FROM BUS BYTES and selects through the one shared policy — never a fork of it.
import { readSampledQualificationClaim, sampledQualified, selectHeadline } from "../grade/headline.ts";
// The disarm EVENT discriminant is owned by the one de-arm-rule home (kestrel-z473.5): the projector reads
// the SAME constant the driver's emit sites use, so projection and emission agree by construction.
import { DISARM_CONTROL_TYPE } from "../engine/disarm.ts";

import type {
  Blotter,
  BlotterLifecycleStep,
  BlotterSession,
  Certification,
  DeliberationTraceEntry,
  FidelitySelfLimitation,
  FillClaim,
  HeadlineFlag,
  DisarmRecord,
  JournalEntry,
  OrderFinalState,
  OrderRecord,
  PlanRecord,
  Rankability,
  RankableLeg,
  ReasoningRef,
  SettleMarkRecord,
  Totals,
  WakeTrace,
} from "./types.ts";
import { sha256 } from "../crypto/sha256.ts";
import { roundToGrid } from "../protocol/grade.ts";
// The training_cutoff × MODEL_KNOWLEDGE_CUTOFF cross-check (kestrel-m9i.23): the ONE place the registry
// fence + the pinned month-boundary rule live. A leaf module (no bus barrel import — kestrel-exx). m9i.25's
// post-cutoff rankable leg consumes the SAME `isPostCutoff` boundary rule (never a second copy).
import { checkTrainingCutoff, isPostCutoff, type TrainingCutoffCheck } from "./model-registry.ts";

// ─────────────────────────────────────────────────────────────────────────────
// Determinism helpers (no wall clock, no RNG — RUNTIME §0)
// ─────────────────────────────────────────────────────────────────────────────

// sha256 (the portable, synchronous digest — Bun-native fast path, Worker-portable pure-JS fallback,
// kestrel-alw.17) is imported from ../crypto/sha256.ts so a projected receipt hashes byte-identically
// under `bun test`, the CLI, and a Cloudflare Worker isolate.

/** The exact report/grader $-grid rounding, so a bus-derived sum rounds byte-identically to the report's
 * totals (RUNTIME §0). Re-homed onto the ONE grid the grader owns ({@link ../protocol/grade.ts REPORT_GRID}
 * / `roundToGrid`, kestrel-z473.6) — never a local `1e8` — so recomputation stays byte-stable. */
const round = roundToGrid;

/** The maximum length of a {@link ReasoningRef} excerpt (ADR-0011 recommendation 2, "~120 chars"). */
const EXCERPT_CAP = 120;

/** A mechanical, deterministic excerpt of a JOURNAL body: its first non-empty line, trimmed, capped to
 * {@link EXCERPT_CAP} chars with a single-char ellipsis on truncation. No markdown interpretation. */
function excerptOf(body: string): string {
  let first = "";
  for (const line of body.split("\n")) {
    const t = line.trim();
    if (t.length > 0) {
      first = t;
      break;
    }
  }
  if (first.length <= EXCERPT_CAP) return first;
  return first.slice(0, EXCERPT_CAP - 1) + "…";
}

// ─────────────────────────────────────────────────────────────────────────────
// Fidelity self-limitation — what the judge (fill model) could NOT observe (a57.4)
// ─────────────────────────────────────────────────────────────────────────────

/** The fail-closed self-limitation for a judge that DECLARED none (a legacy graded bus whose META `fill_model`
 * carries no `self_limitation`): rather than invent observability, declare it unstated so a consumer treats
 * the record as maximally limited (never over-claims, never a silent default to unlimited). */
const UNSTATED_LIMITS: readonly { code: string; note: string }[] = [
  { code: "observability-unstated", note: "fill model declared no self-limitation; the judge's observability limits are unstated — treat all fills as maximally limited (fail-closed)" },
];

/**
 * Read the judge's self-limitation off the graded META's `fill_model` stamp (a57.4) — the fill model
 * DECLARES what it structurally could not observe, so this is a verbatim projection, never a downstream
 * guess. Previously this keyed on `fill_model.name`, which silently mislabelled the calibrated
 * `maker-fair-v1+<version>` judge (it matched no key) as maximally limited (kestrel-o32). Now the
 * declaration rides the META. FAIL CLOSED: a legacy stamp carrying no declaration falls back to
 * {@link UNSTATED_LIMITS} — never a silent default to unlimited observability. Pure and deterministic.
 */
function selfLimitationOf(fillModel: FillModelStamp): FidelitySelfLimitation {
  const limits = fillModel.self_limitation ?? UNSTATED_LIMITS;
  return { fill_model: fillModel.name, limits: limits.map((l) => ({ code: l.code, note: l.note })) };
}

// ─────────────────────────────────────────────────────────────────────────────
// Fail-closed META gate — the projector requires a GRADED bus
// ─────────────────────────────────────────────────────────────────────────────

/**
 * The opening META of a graded bus, or a loud refusal. Fail-closed (ADR-0011): a bus with no META, or a
 * META lacking the judge self-description (`fill_model`/`instance`/`fidelity`), is not a graded bus — it
 * is a fill-model-agnostic INPUT tape (the two-bus rule) — so the projector refuses to invent a judge.
 */
function requireGradedMeta(bus: readonly BusEvent[]): MetaEvent {
  const meta = bus.find((e): e is MetaEvent => e.stream === "META");
  if (meta === undefined) {
    throw new Error("blotter: no META header in bus (a well-formed bus opens with exactly one META, ADR-0011)");
  }
  if (meta.fill_model === undefined || meta.instance === undefined || meta.fidelity === undefined) {
    throw new Error(
      "blotter: META lacks judge identity (fill_model/instance/fidelity) — the projector requires a GRADED bus, " +
        "not a fill-model-agnostic input tape (the two-bus rule, ADR-0011; fail-closed)",
    );
  }
  return meta;
}

// ─────────────────────────────────────────────────────────────────────────────
// Experimental envelope (kestrel-a57.14) — project the injected author identity, fail-closed
// ─────────────────────────────────────────────────────────────────────────────

/**
 * The fourteen REQUIRED identity fields of the experimental envelope (kestrel-a57.14; `face` + `adapter`
 * + `adapter_version` joined the original eleven per the m9i.2 owner tweaks — mandatory-for-certified
 * BEFORE the m9i.7 face/harness tournament). A declared envelope missing/empty/malformed on ANY one fails
 * the record closed to a PROVISIONAL verdict with a recorded reason NAMING the field — never a silent
 * default. Iterated in this fixed order so the recorded reasons are byte-stable across re-projection
 * (determinism, RUNTIME §0).
 */
const REQUIRED_ENVELOPE_IDENTITY = [
  "provider",
  "model",
  "version",
  "training_cutoff",
  "prompt_hash",
  "tokenizer",
  "tool_policy",
  "rendering_identity",
  "wake_source",
  "token_accounting",
  "corpus_tier",
  "face",
  "adapter",
  "adapter_version",
] as const satisfies readonly (keyof ExperimentalEnvelope)[];

/** A real, finite magnitude (no NaN/±Infinity) — the token counters must be genuine injected numbers. */
function isFiniteNumber(v: unknown): v is number {
  return typeof v === "number" && Number.isFinite(v);
}

/** The injected token accounting, iff it is a well-formed `{input, output, thinking}` triple of finite
 * numbers; otherwise `undefined` (the caller records a fail-closed reason naming `token_accounting`). */
function readTokenAccounting(v: unknown): TokenAccounting | undefined {
  if (typeof v !== "object" || v === null) return undefined;
  const r = v as Record<string, unknown>;
  const input = r.input;
  const output = r.output;
  const thinking = r.thinking;
  if (!isFiniteNumber(input) || !isFiniteNumber(output) || !isFiniteNumber(thinking)) return undefined;
  return { input, output, thinking };
}

/** The outcome of projecting the experimental envelope: the projected identity (present ONLY when
 * complete) plus any fail-closed reasons (present ONLY when a declared envelope was incomplete). */
interface EnvelopeProjection {
  readonly envelope?: ExperimentalEnvelope;
  readonly reasons: readonly string[];
}

/**
 * Project the experimental envelope (kestrel-a57.14) from the graded META's INJECTED `envelope` — its
 * input half (the seam's `AgentConfig`/`ModelIdentity` descriptor) — fail-closed. PURE: a deterministic function of
 * the injected bytes (no wall clock/RNG), with `token_accounting` taken as the injected accounting (off
 * the deterministic record path — the owner-away conservative default), never re-derived. Three outcomes:
 *
 *   • `raw === undefined` — the bus DECLARES no envelope (a pre-a57.14 / input-derived graded bus, exactly
 *     like the optional v4 judge fields): nothing to project, nothing to fail closed on ⇒ `{ reasons: [] }`
 *     and the verdict is unaffected (backward-compatible).
 *   • a COMPLETE declared envelope (all fourteen identity fields present + well-formed, `face` inside the
 *     closed http|sdk|cli|mcp vocabulary) ⇒ the envelope projected VERBATIM (each value traceable to the
 *     injected input; the prompt HASH passed through, never content; exactly the fourteen fields — any
 *     extra key is dropped, never fabricated).
 *   • an INCOMPLETE declared envelope (any required field missing/empty/malformed) ⇒ NO projected envelope
 *     (a broken identity is never stamped as identity) plus a recorded reason NAMING each absent field —
 *     the caller flips the verdict to PROVISIONAL. No field is EVER silently defaulted to `""`/`"unknown"`.
 */
function projectExperimentalEnvelope(raw: unknown): EnvelopeProjection {
  if (raw === undefined) return { reasons: [] }; // no declared envelope — additive/optional, verdict unchanged
  if (typeof raw !== "object" || raw === null) {
    return {
      reasons: ["envelope: declared but not an object — no required identity field can be resolved (fail-closed, a57.14)"],
    };
  }
  const rec = raw as Record<string, unknown>;
  const reasons: string[] = [];
  const tokenAccounting = readTokenAccounting(rec.token_accounting);
  for (const field of REQUIRED_ENVELOPE_IDENTITY) {
    if (field === "token_accounting") {
      if (tokenAccounting === undefined) {
        reasons.push("envelope: missing required identity field 'token_accounting' (injected accounting absent or malformed) — fail-closed, not defaulted (a57.14)");
      }
      continue;
    }
    const v = rec[field];
    if (typeof v !== "string" || v.length === 0) {
      reasons.push(`envelope: missing required identity field '${field}' — fail-closed, not defaulted (a57.14)`);
      continue;
    }
    // `face` is a CLOSED vocabulary (m9i.2 owner tweak): a declared-but-unknown face is a broken identity,
    // fail-closed exactly like a missing field — never coerced onto a known face, never passed through.
    if (field === "face" && !(FACES as readonly string[]).includes(v)) {
      reasons.push(`envelope: face '${v}' is outside the closed interface vocabulary (http|sdk|cli|mcp) — fail-closed, not coerced (m9i.2)`);
    }
    // `corpus_tier` is a CLOSED vocabulary (kestrel-m9i.26): a declared-but-unknown tier (a typo, or the
    // retired `public-baseline`) is a broken identity, fail-closed exactly like `face` — never coerced onto a
    // known tier, never passed through (the tier gates the practice-vs-holdback wall).
    if (field === "corpus_tier" && !(CORPUS_TIERS as readonly string[]).includes(v)) {
      reasons.push(`envelope: corpus_tier '${v}' is outside the closed corpus vocabulary (public|semi-private|private) — fail-closed, not coerced (m9i.26)`);
    }
  }
  if (reasons.length > 0) return { reasons }; // declared-but-incomplete — record the reasons, project no identity

  // COMPLETE — reconstruct EXACTLY the fourteen identity fields VERBATIM (drop extras; never fabricate).
  const envelope: ExperimentalEnvelope = {
    provider: rec.provider as string,
    model: rec.model as string,
    version: rec.version as string,
    training_cutoff: rec.training_cutoff as string,
    prompt_hash: rec.prompt_hash as string,
    tokenizer: rec.tokenizer as string,
    tool_policy: rec.tool_policy as string,
    rendering_identity: rec.rendering_identity as string,
    wake_source: rec.wake_source as string,
    token_accounting: tokenAccounting!,
    corpus_tier: rec.corpus_tier as string,
    face: rec.face as string,
    adapter: rec.adapter as string,
    adapter_version: rec.adapter_version as string,
  };
  return { envelope, reasons: [] };
}

// ─────────────────────────────────────────────────────────────────────────────
// project
// ─────────────────────────────────────────────────────────────────────────────

/**
 * Project one GRADED bus into its canonical {@link Blotter}. Pure and deterministic (ADR-0011): no wall
 * clock, no RNG, no engine-state scrape — the same bus in ⇒ a byte-identical Blotter out (proven by
 * {@link ./certify.ts}). Refuses a non-graded bus loudly (fail-closed).
 */
export function project(bus: readonly BusEvent[]): Blotter {
  const meta = requireGradedMeta(bus);

  // The author's experimental envelope (a57.14): projected VERBATIM from the graded META's INJECTED
  // `envelope` when complete, else recorded as fail-closed reasons that flip the verdict to PROVISIONAL.
  // A graded bus that declared no envelope yields neither — additive/optional, backward-compatible.
  const envelopeProjection = projectExperimentalEnvelope(meta.envelope);

  // The training_cutoff × model-registry cross-check (kestrel-m9i.23), additive to the a57.14 envelope
  // reasons: ONLY a COMPLETE envelope (its `model` + `training_cutoff` both present + well-formed) is
  // cross-checked against the MODEL_KNOWLEDGE_CUTOFF fence keyed by model id. Fail-closed — an unknown model
  // id or a declared-vs-registry mismatch appends a typed reason (rendered from `reason.detail`) that flips
  // the verdict to PROVISIONAL exactly like a missing identity field, never a silent default and never a
  // rewrite of the declared cutoff. An incomplete/absent envelope already carries its own reasons (or
  // declares no identity to cross-check), so the registry is never consulted for one — the envelope stamp
  // (below) and the goldens stay byte-unchanged for every registered+matching run (NO-CHURN).
  const envelopeReasons: string[] = [...envelopeProjection.reasons];
  // The cross-check result is HOISTED: it feeds BOTH the certification reasons (below) and the m9i.25
  // post-cutoff rankable leg (a complete envelope whose cutoff verifies yields the `cutoffMonth` the
  // boundary rule needs; an absent/incomplete envelope or a failing check leaves the cutoff unverifiable).
  const cutoffCheck: TrainingCutoffCheck | undefined =
    envelopeProjection.envelope === undefined
      ? undefined
      : checkTrainingCutoff({
          model: envelopeProjection.envelope.model,
          declaredCutoff: envelopeProjection.envelope.training_cutoff,
        });
  if (cutoffCheck !== undefined && !cutoffCheck.ok) envelopeReasons.push(cutoffCheck.reason.detail);

  // ── session — identity / judge / fidelity / envelope / bus receipt ───────────
  // The bus receipt pins the recorded truth (ADR-0010). determinism_hash re-pins the engine's OUTPUT —
  // every event after the opening META — a pure read of the bus (mirrors the report's determinism_hash).
  const output = bus.filter((e) => e !== meta);
  const session: BlotterSession = {
    instance: meta.instance!,
    instruments: meta.instruments,
    bus: {
      events: bus.length,
      sha256: sha256(serializeBus(bus)),
      schema: meta.bus_schema,
    },
    determinism_hash: sha256(serializeBus(output)),
    fill_model: meta.fill_model!,
    // Fidelity (a57.4): the level pass-through PLUS the judge's self-limitation, read verbatim from the
    // fill model's DECLARED limits on the graded META — what it structurally could not observe, so a
    // consumer cannot over-claim (fail-closed to UNSTATED when a legacy stamp declared none).
    fidelity: {
      level: meta.fidelity!,
      self_limitation: selfLimitationOf(meta.fill_model!),
    },
    // The projected experimental envelope (a57.14) — the author's identity, present ONLY when complete.
    ...(envelopeProjection.envelope !== undefined ? { envelope: envelopeProjection.envelope } : {}),
    // The FULL ConfigId (m9i.2 owner tweak) — projected VERBATIM from the graded META when stamped, the
    // sampling-axis-complete config identity the grid CellKey keys on. Additive/optional (absent on a
    // config-less or pre-tweak graded bus); never re-derived here (the driver stamped it at open).
    ...(typeof meta.config_id === "string" && meta.config_id.length > 0 ? { config_id: meta.config_id } : {}),
    // The cell config axis (fillSeed stripped — ADR-0016 §3) — projected VERBATIM when the driver stamped it
    // (a seeded run, where it diverges from config_id). The config axis the grid cellOf keys the cell on;
    // seed-only replicates share it. Additive/optional; never re-derived here (the driver stamped it at open).
    ...(typeof meta.cell_config_id === "string" && meta.cell_config_id.length > 0
      ? { cell_config_id: meta.cell_config_id }
      : {}),
  };

  // ── journals — folded straight from the JOURNAL stream (full body inline) ─────
  const journals: JournalEntry[] = [];
  for (const e of bus) {
    if (e.stream !== "JOURNAL") continue;
    const j = e as JournalEvent;
    journals.push({ seq: j.seq, kind: j.kind, ts: j.ts, body: j.body });
  }

  // ── disarms — reason-carrying stand-down / de-arm audit (CONTROL `disarm`, kestrel-2pl) ────────
  // The author's `standDown` reason (and a fail-closed supersede-parse-escape de-arm) becomes an
  // explicit Blotter record, not merely inferable from plans going `expired(superseded)`. A pure bus read.
  const disarms: DisarmRecord[] = [];
  for (const e of bus) {
    if (e.stream !== "CONTROL" || e.type !== DISARM_CONTROL_TYPE) continue;
    disarms.push({ seq: e.seq, ts: e.ts, ...(e.note !== undefined ? { reason: e.note } : {}) });
  }

  // A plan references its pre-hoc author reasoning: the `author` JOURNAL with the greatest seq strictly
  // below the plan's first lifecycle transition (provable pre-hoc by seq, a57.11). Referenced by seq —
  // never copied (ADR-0011 recommendation 2). The JOURNAL-backed authoring FLOW itself is a57.2; this is
  // just the mechanical linkage a Blotter draws over whatever author records already ride the bus.
  const authorJournals = journals.filter((j) => j.kind === "author").sort((a, b) => a.seq - b.seq);
  const reasoningRefFor = (firstPlanSeq: number): ReasoningRef | undefined => {
    let ref: JournalEntry | undefined;
    for (const j of authorJournals) {
      if (j.seq < firstPlanSeq) ref = j; // ascending scan ⇒ last kept is the greatest seq below
      else break;
    }
    return ref === undefined ? undefined : { seq: ref.seq, excerpt: excerptOf(ref.body) };
  };

  // ── plans — lifecycle traces from the PLAN stream, ONE record per exact INSTANCE ──
  // Group BY INSTANCE first (kestrel-22j.15), not by name: a legal same-name replacement is a DISTINCT
  // instance, so it keeps its own lifecycle + terminal outcome instead of collapsing onto its predecessor.
  // Lineage aggregation stays a SEPARATE roll-up a consumer does over `plan` (the name). The grouping is a
  // pure fold shared with EpisodeReport (groupPlanInstances) so the two projections can never drift: it keys
  // on the explicit `plan_instance` (v5) and, for a pre-v5 bus, migrates EXPLICITLY by lifecycle
  // sessionization — never a silent mis-identify (RUNTIME §8).
  const plans: PlanRecord[] = groupPlanInstances(bus).map((g) => {
    const lifecycle: BlotterLifecycleStep[] = g.events.map((pe) => ({
      seq: pe.seq,
      ts: pe.ts,
      state: pe.state,
      ...(pe.outcome !== undefined ? { outcome: pe.outcome } : {}),
      ...(pe.reason !== undefined ? { reason: pe.reason } : {}),
    }));
    const last = lifecycle[lifecycle.length - 1]!;
    const final_state: PlanState | PlanOutcome = last.outcome ?? last.state;
    const ref = reasoningRefFor(lifecycle[0]!.seq);
    return { plan: g.plan, plan_instance: g.instance, lifecycle, final_state, ...(ref !== undefined ? { reasoning_ref: ref } : {}) };
  });

  // ── orders — one record per placed order, ORDER ⋈ TELEMETRY ───────────────────
  // esc rung (last-wins) + reprice tally from TELEMETRY `order`; probabilistic accounting + support from
  // TELEMETRY `settle`. All re-derived from the bus — never scraped from engine state (ADR-0011).
  const escByRef = new Map<string, number>();
  const repriceByRef = new Map<string, number>();
  const settleByRef = new Map<string, TelemetrySettleEvent>();
  // Fill-guard evidence (kestrel-9gu.6): the far-OTM assessment inputs + cap decision, keyed by order.
  const guardByRef = new Map<string, TelemetryGuardEvent>();
  for (const e of bus) {
    if (e.stream !== "TELEMETRY") continue;
    if (e.type === "order") {
      const t = e as TelemetryOrderEvent;
      escByRef.set(t.order_id, t.esc_stage); // last-wins ⇒ final rung
      if (t.reprice) repriceByRef.set(t.order_id, (repriceByRef.get(t.order_id) ?? 0) + 1);
    } else if (e.type === "settle") {
      const t = e as TelemetrySettleEvent;
      settleByRef.set(t.order_id, t);
    } else if (e.type === "guard") {
      const t = e as TelemetryGuardEvent;
      guardByRef.set(t.order_id, t); // last-wins (one per submission; a reprice mints a new ref)
    }
  }

  // Fold the ORDER stream: `place` seeds a record (first-seen order preserved); fill/cancel/reject set the
  // terminal disposition + reason.
  interface Acc {
    place: OrderEvent;
    final_state: OrderFinalState;
    filled: boolean;
    reason?: string;
  }
  const accByRef = new Map<string, Acc>();
  const refOrder: string[] = [];
  for (const e of bus) {
    if (e.stream !== "ORDER") continue;
    const oe = e as OrderEvent;
    if (oe.type === "place") {
      if (!accByRef.has(oe.order_id)) {
        accByRef.set(oe.order_id, { place: oe, final_state: "working", filled: false });
        refOrder.push(oe.order_id);
      }
      continue;
    }
    const acc = accByRef.get(oe.order_id);
    if (acc === undefined) continue; // a terminal event with no place is not a projectable order
    if (oe.type === "fill") {
      acc.filled = true;
      acc.final_state = "filled";
    } else if (oe.type === "reject") {
      acc.final_state = "rejected";
      if (oe.reason !== undefined) acc.reason = oe.reason;
    } else if (oe.type === "cancel") {
      // A fill already made this order terminal; a later cancel/expire does not undo it.
      if (!acc.filled) acc.final_state = oe.reason === "expired-unfilled" ? "expired" : "cancelled";
      if (oe.reason !== undefined) acc.reason = oe.reason;
    }
  }

  const orders: OrderRecord[] = refOrder.map((ref) => {
    const acc = accByRef.get(ref)!;
    const p = acc.place;
    const settle = settleByRef.get(ref);
    const guard = guardByRef.get(ref);
    const filled = settle?.floor_filled ?? acc.filled;
    const support: FillSupport = settle?.support ?? "calibrated";
    return {
      order_id: p.order_id,
      ...(p.plan !== undefined ? { plan: p.plan } : {}),
      ...(p.plan_instance !== undefined ? { plan_instance: p.plan_instance } : {}),
      instrument: p.instrument,
      side: p.side,
      qty: p.qty,
      // ADR-0017: an equity/spot order carries NEITHER a strike NOR a right; only an option leg does.
      // Omit both for a spot order (mirrors the frame's isSpotLeg boundary) rather than substituting a
      // fictional `strike: 0`/`right: "C"` — a phantom zero-strike CALL contract in the machine record
      // (report.json/ledger) that an outsider recomputing the benchmark would misread (kestrel-ldqt).
      ...(p.strike !== undefined ? { strike: p.strike } : {}),
      ...(p.right !== undefined ? { right: p.right } : {}),
      px: round(p.px ?? 0),
      esc_stage: escByRef.get(ref) ?? 0,
      reprice_count: repriceByRef.get(ref) ?? 0,
      final_state: acc.final_state,
      filled,
      pFill: round(settle?.expected_fill_prob ?? (filled ? 1 : 0)),
      support,
      floor_pnl: round(settle?.floor_pnl ?? 0),
      expected_pnl: round(settle?.expected_pnl ?? 0),
      ...(acc.reason !== undefined ? { reason: acc.reason } : {}),
      // Fill-guard evidence (kestrel-9gu.6), when a far-OTM leg carried a `guard` record.
      ...(guard !== undefined
        ? { moneyness: guard.moneyness, covered: guard.covered, directional_cap: guard.directional_cap }
        : {}),
    };
  });

  // ── totals — the floor/expected accounting, re-derived from settle telemetry ──
  // Sum the UNROUNDED per-order P&L then round once (the report's discipline) so the totals byte-match
  // EpisodeReport.totals. The headline is tainted when any non-zero `expected` contribution rode on
  // `extrapolated` support — a cell a grader refuses to bank (CONTEXT: Support flag).
  // The same settle stream also drives fill_claim (a57.4): partition the expected-$ by support so the two
  // claims reconstruct totals.expected exactly. Fail-closed: anything not `calibrated` (an `extrapolated`
  // or unstated flag) buckets as non-bankable — a grader refuses to bank it (bankableEv, 9gu.3).
  let floorSum = 0;
  let expectedSum = 0;
  let calibratedExpected = 0;
  let extrapolatedExpected = 0;
  let calibratedOrders = 0;
  let extrapolatedOrders = 0;
  // The SAMPLED channel (kestrel-9gu.12): present on the settle telemetry ONLY for a seeded run
  // (`sampled_pnl` rides ⇔ the sampler was armed). Folded exactly like floor/expected — sum the
  // unrounded per-order P&L, round once — so `totals.sampled` byte-matches the report's `sampled_usd`.
  let sampledSum = 0;
  let sampledArmed = false;
  let sampledExtrapolated = false;
  const taintReasons: string[] = [];
  // The per-cell expected-$ + support, collected in bus order for the SIGNED partition (kestrel-dpy).
  const claimCells: { support: FillSupport | undefined; ev: number }[] = [];
  // The settle-mark provenance record (kestrel-xwf) — at most one per graded bus (last-wins).
  let settleMarkEv: TelemetrySettleMarkEvent | undefined;
  for (const e of bus) {
    if (e.stream !== "TELEMETRY") continue;
    if (e.type === "settle_mark") {
      settleMarkEv = e as TelemetrySettleMarkEvent;
      continue;
    }
    // The per-wake THETA-BLEED record (theta-cell seam b) — the intra-session mark-to-model of held
    // option legs a cell opts into via `markToModel`. Folded into the floor EXACTLY like a `settle`
    // record's `floor_pnl` (so `totals.floor` carries the stand-down bleed), but it is NOT a per-order
    // settle: it never touches the expected/sampled channels or the support partition. A bus from a
    // cell that did not opt in carries none ⇒ byte-identical (additive-optional, like `settle_mark`).
    if (e.type === "theta_bleed") {
      floorSum += (e as TelemetryThetaBleedEvent).floor_pnl;
      continue;
    }
    if (e.type !== "settle") continue;
    const s = e as TelemetrySettleEvent;
    floorSum += s.floor_pnl;
    expectedSum += s.expected_pnl;
    if (s.sampled_pnl !== undefined) {
      sampledArmed = true;
      sampledSum += s.sampled_pnl;
      // A sampled REALIZATION on non-calibrated support can never be the headline (bankableEv,
      // ADR-0016 §5) — evidence for the gate, judged below through the one shared policy.
      if (s.sampled_filled === true && s.support !== "calibrated") sampledExtrapolated = true;
    }
    claimCells.push({ support: s.support, ev: s.expected_pnl });
    if (s.support === "calibrated") {
      calibratedExpected += s.expected_pnl;
      calibratedOrders += 1;
    } else {
      extrapolatedExpected += s.expected_pnl;
      extrapolatedOrders += 1;
      if (s.expected_pnl !== 0) taintReasons.push(`${s.order_id}: expected banked on extrapolated support`);
    }
  }
  // Settle-mark staleness taint (kestrel-xwf): a stale mark taints the headline — the settled P&L
  // compares against a spot the tape stopped supporting (the 2025-04-09 frozen-underlier phantom
  // loss), so it is NON-BANKABLE. A closing put-call-parity recovery (`source: "parity"`) is an
  // ANNOTATED recovery — the book settled against an honest recovered spot and the reason says so —
  // but the primary feed still died, so the staleness taint stands (fail-closed core, kestrel-pez
  // unification); an unrecovered mark (`mark_uncertain`) is the loudest case, naming the retained
  // frozen level. Re-derived purely from the bus's `settle_mark` TELEMETRY record; a pre-xwf bus
  // carries none ⇒ no record, no retroactive taint (additive-optional, like `guard`).
  const settle_mark: SettleMarkRecord | undefined =
    settleMarkEv === undefined
      ? undefined
      : {
          px: settleMarkEv.px,
          as_of_ts: settleMarkEv.as_of_ts ?? null,
          last_observed_ts: settleMarkEv.last_observed_ts ?? null,
          age_ms: settleMarkEv.age_ms ?? null,
          stale_after_ms: settleMarkEv.stale_after_ms,
          stale: settleMarkEv.stale,
          source: settleMarkEv.source,
          mark_uncertain: settleMarkEv.mark_uncertain,
          note: settleMarkEv.note ?? null,
        };
  if (settle_mark !== undefined && settle_mark.stale) {
    const staleness =
      settle_mark.age_ms === null
        ? `settle mark ${settle_mark.px} has unstated provenance (no spot observation on the tape)`
        : `settle mark ${settle_mark.px} is stale: value last established ${settle_mark.age_ms}ms before settle (> ${settle_mark.stale_after_ms}ms threshold)`;
    taintReasons.push(
      settle_mark.source === "parity"
        ? `${staleness}; recovered via closing put-call parity (annotated recovery) — P&L settled against it is non-bankable (kestrel-xwf)`
        : settle_mark.mark_uncertain
          ? `${staleness}; settle mark uncertain — no closing put-call parity derivable, last-known mark retained — P&L settled against it is non-bankable (kestrel-xwf, fail-closed)`
          : `${staleness} — P&L settled against it is non-bankable (kestrel-xwf)`,
    );
  }

  const totalsFloor = round(floorSum);
  const totalsExpected = round(expectedSum);
  const totalsSampled = sampledArmed ? round(sampledSum) : undefined;

  // ── the headline (kestrel-9gu.12) — selected through the ONE gate policy, from bus bytes alone ──
  // The qualification claim is read fail-closed off the graded META (`sampled_qualification`, stamped by
  // the driver only for a consistent seeded+calibrated run); a malformed or absent claim ⇒ not qualified
  // ⇒ the strict-cross floor stays the headline (9gu.8 AC#7). The taints accumulated above (extrapolated
  // expected-$ + the xwf staleness verdict — parity recovery ANNOTATES but never pardons, so a stale
  // parity mark still taints) ride the selected channel — they never switch it.
  const qualification = readSampledQualificationClaim(meta.sampled_qualification);
  const gate = sampledQualified({
    sampledArmed,
    sampledExtrapolated,
    ...(qualification !== undefined ? { qualification } : {}),
  });
  const selected = selectHeadline(
    { floor: totalsFloor, expected: totalsExpected, ...(totalsSampled !== undefined ? { sampled: totalsSampled } : {}) },
    gate,
    taintReasons,
  );
  const headline: HeadlineFlag = {
    channel: selected.channel,
    usd: selected.usd,
    gate: selected.gate,
    tainted: selected.tainted,
    reasons: selected.reasons,
  };
  const totals: Totals = {
    floor: totalsFloor,
    expected: totalsExpected,
    ...(totalsSampled !== undefined ? { sampled: totalsSampled } : {}),
    headline,
    ...(settle_mark !== undefined ? { settle_mark } : {}),
  };

  // fill_claim — the expected-$ partitioned by support (a57.4), now carrying the SIGNED sub-cells written
  // ONCE (kestrel-dpy, ADR-0014). Fixed order [calibrated, extrapolated] so the array is byte-stable
  // across re-projection. Two invariants held together:
  //   • EXACT reconstruction: Σ slices.expected === totals.expected. The extrapolated slice's `expected`
  //     is DERIVED from totals.expected − calibrated (both on the 1e-8 grid) rather than rounding each raw
  //     sum independently — otherwise double-rounding could let Σ slices disagree by one grid unit on
  //     fine-grained residuals, breaking the reconstruct contract.
  //   • SIGNED sub-cells: `gain` is the honest rounded Σ of non-negative expected-$ (what a subtracting
  //     consumer removes to re-bank, so extrapolated LOSSES survive — ADR-0014's anti-erasure fix), and
  //     `loss` is DERIVED as expected − gain so `expected === gain + loss` holds EXACTLY per slice (any
  //     sub-grid double-rounding lands on the loss cell, which only ever makes bankable more conservative
  //     — fail-closed-safe, never flattering).
  const part = partition(claimCells);
  const calibratedClaim = round(calibratedExpected);
  const extrapolatedClaim = round(totalsExpected - calibratedClaim);
  const calibratedGain = round(part.calibrated.gain);
  const extrapolatedGain = round(part.extrapolated.gain);
  const fill_claim: FillClaim[] = [
    {
      support: "calibrated",
      orders: calibratedOrders,
      expected: calibratedClaim,
      gain: calibratedGain,
      loss: round(calibratedClaim - calibratedGain),
    },
    {
      support: "extrapolated",
      orders: extrapolatedOrders,
      expected: extrapolatedClaim,
      gain: extrapolatedGain,
      loss: round(extrapolatedClaim - extrapolatedGain),
    },
  ];

  // ── certification — the determinism leg (sim); paper/live legs na (a57.3) ─────
  // A declared-but-incomplete experimental envelope (a57.14) — or a complete envelope whose declared
  // training_cutoff fails the model-registry cross-check (kestrel-m9i.23) — fails the record closed to
  // PROVISIONAL with the reasons recorded; a missing/unverifiable identity is never certified-by-implication.
  const certification = certificationOf(session.instance.mode, envelopeReasons);

  // ── rankability — the DERIVED leaderboard-eligibility axis (kestrel-m9i.25) ────
  // A DISTINCT axis from certification: derived HERE from the certification verdict, the m9i.23 cutoff
  // cross-check, and the three governance/Layer-3 attestations off the graded META — never a
  // producer-stamped field (a bogus `meta.rankable`/`meta.rankability` is ignored; the conjunction is
  // recomputed from legs). The clock_honest attestation (ADR-0040 / kestrel-w7la.3) is the fifth leg.
  const rankability = deriveRankability({
    certification,
    cutoffCheck,
    sessionDate: meta.session_date,
    dateBlind: meta.date_blind,
    seasonFrozen: meta.season_frozen,
    clockHonest: meta.clock_honest,
  });

  // ── wake_trace — the clock-honest deliberation record (ADR-0040 / kestrel-w7la.1) ──────────────
  // A pure fold of the bus's WAKE/`deliberation` records (bus_schema v6): per-wake cost + the session
  // total. Record completeness, NOT a score — latency is already priced inside alpha by the fills
  // landing at return-time prices (clock-honest wakes §6). Absent on a latency-blind bus (which
  // carries none), so every existing projected Blotter is byte-identical.
  const deliberations: DeliberationTraceEntry[] = [];
  for (const e of bus) {
    if (e.stream !== "WAKE" || e.type !== "deliberation") continue;
    deliberations.push({
      seq: e.seq,
      wake_seq: e.wake_seq,
      ts: e.ts,
      measured_ms: e.measured_ms,
      buffer_ms: e.buffer_ms,
    });
  }
  const wake_trace: WakeTrace | undefined =
    deliberations.length > 0
      ? {
          deliberations,
          deliberation_ms_total: deliberations.reduce((s, d) => s + d.measured_ms + d.buffer_ms, 0),
        }
      : undefined;

  return {
    session,
    certification,
    rankability,
    journals,
    disarms,
    plans,
    orders,
    totals,
    fill_claim,
    ...(wake_trace !== undefined ? { wake_trace } : {}),
  };
}

/**
 * The certification block project() stamps (ADR-0011). The **determinism** leg claims the projection is
 * reproducible; {@link ./certify.ts} is the EXECUTABLE PROOF of that claim (re-project + byte-compare) —
 * a bug that broke purity makes `certify` refuse, so the embedded claim and the audit agree in a correct
 * system. In `sim` the three paper/live legs are `na` ⇒ `certified`; paper/live carry `provisional` until
 * a57.3 lands those legs (this slice does not evaluate them).
 *
 * FAIL-CLOSED (kestrel-a57.14): a declared-but-incomplete experimental envelope supplies `envelopeReasons`
 * (each naming a missing identity field). ANY such reason forces the verdict to `provisional` regardless of
 * mode and records the reasons — a missing author identity is an explicit PROVISIONAL result, never
 * certified-by-implication and never a silent default. `reasons` is omitted entirely when there are none,
 * so a clean `certified` record stays byte-minimal.
 */
function certificationOf(mode: string, envelopeReasons: readonly string[]): Certification {
  const isSim = mode === "sim";
  const legs = {
    determinism: "pass",
    detectors_bit_for_bit: "na",
    fills_subset_of_live: "na",
    lifecycle_divergence_explained: "na",
  } as const;
  if (envelopeReasons.length > 0) {
    return { legs, verdict: "provisional", reasons: envelopeReasons };
  }
  return { legs, verdict: isSim ? "certified" : "provisional" };
}

/** Read an ATT boolean attestation off the graded META FAIL-CLOSED (kestrel-m9i.25): strictly `true` passes,
 * strictly `false` is a hard-false, ANYTHING else (absent / malformed) is UNKNOWN — never a silent pass on an
 * unstated attestation. */
function attestationLeg(v: unknown): RankableLeg {
  if (v === true) return "pass";
  if (v === false) return "fail";
  return "unknown";
}

/**
 * Derive the {@link Rankability} axis (kestrel-m9i.25) — leaderboard ELIGIBILITY, a DISTINCT axis from
 * {@link Certification}. A CONJUNCTION of five legs computed PURELY from already-stamped fields (never a
 * producer-trusted `rankable`): the certification verdict, the m9i.23 cutoff cross-check on the a57.14
 * envelope (consuming the SAME {@link isPostCutoff} boundary rule, never a second copy), the two ATT
 * governance attestations, and the ADR-0040 clock-honest attestation (kestrel-w7la.3). FAIL-CLOSED — an
 * UNKNOWN leg input ⇒ that leg is `unknown`, the row is NOT rankable, and a NAMED `*-unknown` reason is
 * recorded (never a silent `rankable: true`). Reasons are collected in a FIXED leg order
 * (certified → post_cutoff → date_blind → season_frozen → clock_honest — the fifth leg appended LAST so
 * every pre-w7la.3 reason ordering is byte-stable) for byte-stability (determinism, RUNTIME §0), and are
 * present ONLY when the row is not rankable. Pure and deterministic.
 */
function deriveRankability(input: {
  certification: Certification;
  cutoffCheck: TrainingCutoffCheck | undefined;
  sessionDate: string;
  dateBlind: unknown;
  seasonFrozen: unknown;
  clockHonest: unknown;
}): Rankability {
  const reasons: RankableReason[] = [];

  // Leg 1 — CERTIFIED: the existing a57.14/m9i.23 verdict is `certified` (not `provisional`). Always a
  // definite verdict (never `unknown`) — a non-certified record is simply not leaderboard-comparable.
  const certified: RankableLeg = input.certification.verdict === "certified" ? "pass" : "fail";
  if (certified === "fail") {
    reasons.push({
      kind: "not-certified",
      detail:
        "rankable: certification verdict is 'provisional', not 'certified' — a non-certified record is not " +
        "leaderboard-comparable (kestrel-m9i.25)",
    });
  }

  // Leg 2 — POST-CUTOFF: the tape date is STRICTLY after the model's knowledge cutoff (m9i.23 isPostCutoff),
  // where the cutoff month comes from the registry cross-check on the declared envelope. UNKNOWN (fail-closed)
  // when the cutoff is unverifiable — no complete envelope, an unknown model id, or a declared-registry
  // mismatch (the cross-check already flipped certification to provisional, but the cutoff still cannot gate,
  // so post-cutoff is neither asserted nor denied — it is UNKNOWN, never silently pre- or post-cutoff).
  let post_cutoff: RankableLeg;
  if (input.cutoffCheck === undefined || !input.cutoffCheck.ok) {
    post_cutoff = "unknown";
    reasons.push({
      kind: "cutoff-unknown",
      detail:
        "rankable: the model knowledge cutoff is unverifiable (no complete envelope, an unknown model id, or a " +
        "declared-vs-registry mismatch) — the post-cutoff leg cannot be established, so the row is not rankable " +
        "(fail-closed, kestrel-m9i.25)",
    });
  } else if (isPostCutoff(input.cutoffCheck.cutoffMonth, input.sessionDate)) {
    post_cutoff = "pass";
  } else {
    post_cutoff = "fail";
    reasons.push({
      kind: "pre-cutoff",
      detail:
        `rankable: tape date '${input.sessionDate}' is NOT strictly after the model knowledge cutoff ` +
        `'${input.cutoffCheck.cutoffMonth}' — the model may have known how the day ended, so a PRE-cutoff row is ` +
        "not rankable (kestrel-m9i.25)",
    });
  }

  // Leg 3 — DATE-BLIND: the ATT attestation `meta.date_blind`, read fail-closed.
  const date_blind = attestationLeg(input.dateBlind);
  if (date_blind === "fail") {
    reasons.push({
      kind: "not-date-blind",
      detail:
        "rankable: the run is attested NOT date-blind (meta.date_blind=false) — the agent could read the calendar " +
        "date off the tape, so the row is not rankable (kestrel-m9i.25)",
    });
  } else if (date_blind === "unknown") {
    reasons.push({
      kind: "date-blind-unknown",
      detail:
        "rankable: the date-blind attestation (meta.date_blind) is absent or malformed — UNKNOWN, so the row is " +
        "not rankable (fail-closed, kestrel-m9i.25)",
    });
  }

  // Leg 4 — SEASON-FROZEN: the ATT attestation `meta.season_frozen`, read fail-closed (same as date-blind).
  const season_frozen = attestationLeg(input.seasonFrozen);
  if (season_frozen === "fail") {
    reasons.push({
      kind: "season-not-frozen",
      detail:
        "rankable: the benchmark season is attested NOT frozen (meta.season_frozen=false) — the scenario set is " +
        "not sealed (ADR-0018), so the row is not rankable (kestrel-m9i.25)",
    });
  } else if (season_frozen === "unknown") {
    reasons.push({
      kind: "season-unknown",
      detail:
        "rankable: the season-frozen attestation (meta.season_frozen) is absent or malformed — UNKNOWN, so the " +
        "row is not rankable (fail-closed, kestrel-m9i.25)",
    });
  }

  // Leg 5 — CLOCK-HONEST (ADR-0040 / kestrel-w7la.3, appended LAST): the Layer-3 attestation
  // `meta.clock_honest`, read fail-closed via the SAME attestationLeg rule. The driver stamps `true` or
  // NOTHING — so `unknown` is the latency-blind/unattested session ("…can never ground a latency claim",
  // CONTEXT.md), and `fail` is reachable only via a platform-side revocation (`false`). "No governed
  // season runs latency-blind" (AGENTS.md) made mechanical.
  const clock_honest = attestationLeg(input.clockHonest);
  if (clock_honest === "fail") {
    reasons.push({
      kind: "not-clock-honest",
      detail:
        "rankable: the clock-honest attestation is REVOKED (meta.clock_honest=false, a platform-side revocation " +
        "value the driver never stamps) — the session's latency accounting is marked defective, so the row is " +
        "not rankable (ADR-0040, kestrel-w7la.3)",
    });
  } else if (clock_honest === "unknown") {
    reasons.push({
      kind: "clock-honest-unknown",
      detail:
        "rankable: the clock-honest attestation (meta.clock_honest) is absent or malformed — the session is " +
        "latency-blind or unattested, so the row is not rankable and can never ground a latency claim " +
        "(fail-closed, ADR-0040, kestrel-w7la.3)",
    });
  }

  const rankable =
    certified === "pass" &&
    post_cutoff === "pass" &&
    date_blind === "pass" &&
    season_frozen === "pass" &&
    clock_honest === "pass";
  return {
    legs: { certified, post_cutoff, date_blind, season_frozen, clock_honest },
    rankable,
    // Byte-minimal: reasons present ONLY when the row is not rankable (mirrors a clean certified record).
    ...(reasons.length > 0 ? { reasons } : {}),
  };
}
