kestrel.markets
Version:
A typed, token-efficient language + runtime for agentic trading: agents author bounded plans, the runtime fires them at the tick. CLI + typed library + MCP server.
253 lines (239 loc) • 15.2 kB
text/typescript
/**
* # blotter/model-registry — the MODEL_KNOWLEDGE_CUTOFF fence + the pinned month-boundary rule (kestrel-m9i.23)
*
* The declared `envelope.training_cutoff` (a57.14) is the basis for **model-relative holdback**: a tape
* date is "post-cutoff" (holdback-eligible, ranking) iff it falls after the model's knowledge cutoff. A
* DECLARED cutoff is only trustworthy if it AGREES with the platform model registry — so this module is the
* ONE place that holds all three pieces of that verification, co-located so the boundary logic is never
* duplicated (SYSTEM-PROFILE.md line 41; the [PLANNED kestrel-m9i.23] item resolved here):
*
* 1. {@link MODEL_KNOWLEDGE_CUTOFF} — the fence: model id → knowledge-cutoff month (`YYYY-MM`). The local
* MIRROR of the platform `fence.ts` registry (attestation-side, ATT — this repo verifies against a
* pinned copy; it never mutates the platform fence). Keyed by the model id, closed by construction: an
* id with no entry is UNKNOWN (fail-closed), never an open default.
* 2. {@link isPostCutoff} — the SOLE month-boundary rule: a tape date is post-cutoff IFF *strictly after
* the last day of the declared cutoff month*. Declared `2025-10` gates through `2025-10-31` inclusive;
* `2025-11-01` is the first post-cutoff day. This is the only place the boundary is computed — the
* post-cutoff *classification* (kestrel-m9i.25) consumes this function, never a second copy of the rule.
* 3. {@link checkTrainingCutoff} — the fail-closed lookup + declared-vs-registry cross-check. Returns the
* registry cutoff when the declared value is consistent, else a typed {@link TrainingCutoffReason}
* (unknown model id | declared-vs-registry mismatch) NAMING the disagreement — never a silent default,
* never a silent correction of the declared value. The a57.14 projector ({@link ./project.ts}) renders
* the reason's `detail` onto `certification.reasons` and fails the Blotter closed to PROVISIONAL.
*
* PURE and DETERMINISTIC (RUNTIME §0): every export is a function of its arguments (the model id, the
* declared cutoff, the tape date) — no wall clock, no RNG, no I/O. The `TrainingCutoffReason` type lives in
* the built-in-free bus leaf (`../bus/types.ts`, `import type` only) so this module pulls no Bun/node
* built-in into the light type graph (kestrel-exx: no bus BARREL import on a light-reachable path).
*/
import type { TrainingCutoffReason } from "../bus/types.ts";
/**
* The **model knowledge-cutoff fence** (kestrel-m9i.23): model id → knowledge-cutoff month (`YYYY-MM`). The
* local mirror of the platform `fence.ts` `MODEL_KNOWLEDGE_CUTOFF` registry — a declared `training_cutoff`
* is cross-checked against the entry for its model id. Keyed by the model id; an id absent here is UNKNOWN
* and fails closed (never treated as post- or pre-cutoff). The entries are the model ids the graded fixtures
* declare; a new registered model is added HERE (one definition, no drift), matching the platform fence.
*/
export const MODEL_KNOWLEDGE_CUTOFF: Readonly<Record<string, string>> = {
"acme-lm-1": "2025-10",
"acme-lm-2": "2025-10",
"claude-haiku-4-5": "2025-02",
// NOTE: `kimi-k3` is DELIBERATELY absent — its cutoff is unpublished, so it fails closed
// (unknown-model-id). See CUTOFF_UNKNOWN_PENDING below; move it here with a real YYYY-MM once published.
};
/**
* DELIBERATELY-UNREGISTERED models — KNOWN to the roster/lanes but kept OUT of {@link MODEL_KNOWLEDGE_CUTOFF}
* because their training-knowledge cutoff is UNPUBLISHED. Absence from the fence above is the fail-closed
* marker (an id with no cutoff entry is UNKNOWN ⇒ {@link checkTrainingCutoff} returns `unknown-model-id`, so
* the row can never certify as post-cutoff). This constant makes that omission EXPLICIT and greppable — the
* difference between "we forgot" and "we know, and it is deliberately fail-closed until the model card
* publishes the cutoff". Register the real `YYYY-MM` by MOVING the id INTO the map above the moment it is
* published; do NOT guess a cutoff (a guessed cutoff would gate contamination on a fiction). The value here
* is the HUMAN REASON, never a cutoff month — nothing reads it as a boundary.
*
* kestrel-2ojt (owner directive 2026-07-17): Kimi K3 (`kimi-k3` / gateway `moonshotai/kimi-k3`) shipped
* 2026-07-16; weights + model card land 2026-07-27; Moonshot has published NO training cutoff. Until it
* does, K3 is fail-closed here and CANNOT enter the post-cutoff corpus window. A brand-new model's RECENT
* cutoff also SHRINKS its post-cutoff window (less untrained tape to grade over) — flag for the corpus
* program. The platform mirror `apps/api/src/bench/fence.ts` (DAY granularity, `YYYY-MM-DD`) needs the same
* deliberate omission; that is a platform-side follow-up, not editable from this OSS repo.
*/
export const CUTOFF_UNKNOWN_PENDING: Readonly<Record<string, string>> = {
"kimi-k3":
"training cutoff UNPUBLISHED as of 2026-07-17 (shipped 2026-07-16; weights + card 2026-07-27) — fail-closed until Moonshot publishes it (kestrel-2ojt)",
};
/**
* The typed outcome of the fail-closed cross-check: the registry cutoff month when the declared value is
* consistent (`ok: true`), else a typed {@link TrainingCutoffReason} (`ok: false`) — a discriminated result,
* never a silent default and never a silent correction of the declared value.
*/
export type TrainingCutoffCheck =
| { readonly ok: true; readonly cutoffMonth: string }
| { readonly ok: false; readonly reason: TrainingCutoffReason };
/**
* The SOLE month-boundary rule (kestrel-m9i.23): a tape date is **post-cutoff IFF strictly after the last
* day of the declared cutoff month**. For zero-padded ISO tokens that is exactly the tape date's own
* `YYYY-MM` being lexicographically greater than the cutoff's `YYYY-MM`: any day WITHIN the cutoff month —
* including its last day — shares the month key and is NOT after it, and the first day of the following month
* is the first strictly-greater key (the year-wrap is handled by the fixed-width comparison, so a `2025-12`
* cutoff gates through `2025-12-31` and `2026-01-01` is post-cutoff). Declared `2025-03` ⇒ `2025-03-31` is
* NOT post-cutoff, `2025-04-01` IS. Pure and deterministic — no wall clock (RUNTIME §0). This is the ONLY
* place the boundary is computed; consumers (post-cutoff classification, kestrel-m9i.25) call it, never fork it.
*
* @param cutoffMonth the declared cutoff month (`YYYY-MM`)
* @param tapeDate the tape/session date (`YYYY-MM-DD`)
*/
export function isPostCutoff(cutoffMonth: string, tapeDate: string): boolean {
return tapeDate.slice(0, 7) > cutoffMonth;
}
/**
* The fail-closed lookup + declared-vs-registry cross-check (kestrel-m9i.23), keyed by the model id. An
* attestation-side VERIFICATION (ATT), never a rewrite:
*
* - the model id has NO registry entry ⇒ `unknown-model-id`: the declared cutoff cannot be verified, so the
* row cannot certify as post-cutoff (NOT silently treated as post- or pre-cutoff);
* - the model id is registered but the declared cutoff DISAGREES with the registry's ⇒
* `declared-registry-mismatch`: the declared value is RECORDED verbatim (never rewritten to the
* registry's), with both cutoffs named;
* - otherwise the declared cutoff matches the registry ⇒ `ok`, carrying the registry cutoff month.
*
* Pure and deterministic — a function of the model id + the declared cutoff alone (no wall clock, no RNG).
*/
export function checkTrainingCutoff(input: { model: string; declaredCutoff: string }): TrainingCutoffCheck {
const { model, declaredCutoff } = input;
const registry = MODEL_KNOWLEDGE_CUTOFF[model];
if (registry === undefined) {
return {
ok: false,
reason: {
kind: "unknown-model-id",
model,
declared: declaredCutoff,
detail:
`training_cutoff: model id '${model}' is not in the MODEL_KNOWLEDGE_CUTOFF registry — the declared cutoff ` +
`'${declaredCutoff}' cannot be verified; the row is not treated as post- or pre-cutoff (fail-closed, kestrel-m9i.23). ` +
`REMEDY: run the Knowledge-Horizon Eval (kestrel-cf62) and register an 'empirically-bounded' cutoff source ` +
`(see registerEmpiricalBound / docs/research/knowledge-horizon-eval.md)`,
},
};
}
if (registry !== declaredCutoff) {
return {
ok: false,
reason: {
kind: "declared-registry-mismatch",
model,
declared: declaredCutoff,
registry,
detail:
`training_cutoff: declared '${declaredCutoff}' disagrees with the registry cutoff '${registry}' for model id ` +
`'${model}' — the declared value is recorded, never rewritten to the registry's (fail-closed, kestrel-m9i.23)`,
},
};
}
return { ok: true, cutoffMonth: registry };
}
// ─────────────────────────────────────────────────────────────────────────────
// Empirically-bounded cutoff source (kestrel-cf62) — the REMEDY for unknown-model-id
// ─────────────────────────────────────────────────────────────────────────────
/**
* A cutoff whose value is **vendor-published** (a spec claim in {@link MODEL_KNOWLEDGE_CUTOFF}) or
* **empirically-bounded** — MEASURED by the Knowledge-Horizon Eval (kestrel-cf62): a conservative upper
* bound derived from dated-headline discrimination accuracy vs the 50% chance anchor. The empirical kind
* gives the fail-closed `unknown-model-id` path a remedy: probe the model, register the measured bound.
*
* Rule 10 (declared): the empirical bound is a MECHANICAL MEASUREMENT — no capability is attributed.
*/
export type CutoffSource =
| { readonly kind: "vendor-published"; readonly cutoffMonth: string }
| {
readonly kind: "empirically-bounded";
readonly cutoffMonth: string;
/** The exact probe run id — VERSION-PINNING: a bound binds to the model id+version it was measured on. */
readonly probeRunId: string;
/** The PROVIDER-RESPONSE-reported model id the probe run recorded (kestrel-cf62, PR #300 F4):
* the pin's other half — registration refuses when this disagrees with the registry key, so a
* bound measured on one model version can never be filed under another id. */
readonly reportedModelId: string;
/** Path/handle of the fitted-curve artifact kept for audit. */
readonly curveArtifact: string;
/** The declared conservative safety margin (months) ADDED to the latest above-chance bin
* (over-fence headroom — leak-safety requires cutoff ≥ true horizon, PR #300 F1). */
readonly margin: number;
};
/**
* The empirically-bounded registry (kestrel-cf62): model id → measured cutoff source. Populated by a
* probe run via {@link registerEmpiricalBound}; consulted alongside the vendor-published fence. Keyed by
* the EXACT model id the probe reported (version-pinning). Starts empty — a bound exists only once measured.
*/
export const EMPIRICAL_CUTOFF_BOUNDS: Record<string, Extract<CutoffSource, { kind: "empirically-bounded" }>> = {};
/** The version-pinning gate outcome (kestrel-cf62): a validated bound, or a typed refusal NAMING the defect. */
export type EmpiricalBoundCheck =
| { readonly ok: true; readonly source: Extract<CutoffSource, { kind: "empirically-bounded" }> }
| { readonly ok: false; readonly detail: string };
/**
* The VERSION-PINNING gate (kestrel-cf62, PR #300 F4): an `empirically-bounded` source is only
* acceptable if it carries a non-empty `probeRunId` AND a non-empty `reportedModelId` that AGREES
* with the model id being registered AND a non-empty `curveArtifact` AND a non-negative margin AND a
* well-formed `YYYY-MM` cutoff. An unpinned bound (no run id / no artifact) or a MISMATCHED pin (the
* probe's provider-reported model id is not the id being filed) is REFUSED — a registry entry must
* always trace to the exact probe AND the exact model version that produced it. Pure and
* deterministic.
*
* @param model the registry key the bound is being validated FOR (the requested seat id)
*/
export function validateEmpiricalBound(
model: string,
source: Extract<CutoffSource, { kind: "empirically-bounded" }>,
): EmpiricalBoundCheck {
if (!/^\d{4}-\d{2}$/.test(source.cutoffMonth)) {
return { ok: false, detail: `empirical bound cutoffMonth '${source.cutoffMonth}' is not a YYYY-MM month` };
}
if (source.probeRunId.trim() === "") {
return { ok: false, detail: "empirical bound is UNPINNED: probeRunId is empty (version-pinning gate, kestrel-cf62)" };
}
if (source.reportedModelId.trim() === "") {
return { ok: false, detail: "empirical bound is UNPINNED: reportedModelId is empty (version-pinning gate, PR #300 F4)" };
}
if (source.reportedModelId !== model) {
return {
ok: false,
detail:
`empirical bound VERSION-PIN MISMATCH: probe run '${source.probeRunId}' reported model id ` +
`'${source.reportedModelId}' but is being registered for '${model}' — a bound measured on one model ` +
`version is never filed under another id (kestrel-cf62, PR #300 F4)`,
};
}
if (source.curveArtifact.trim() === "") {
return { ok: false, detail: "empirical bound is UNPINNED: curveArtifact is empty (version-pinning gate, kestrel-cf62)" };
}
if (!Number.isFinite(source.margin) || source.margin < 0) {
return { ok: false, detail: `empirical bound margin '${source.margin}' must be a non-negative number of months` };
}
return { ok: true, source };
}
/**
* Register a measured bound for a model id (the remedy the unknown-model-id path names). Passes the
* version-pinning gate first — an unpinned bound is never registered. Returns the check so callers can
* surface the refusal. Keyed by the exact reported model id.
*/
export function registerEmpiricalBound(
model: string,
source: Extract<CutoffSource, { kind: "empirically-bounded" }>,
): EmpiricalBoundCheck {
const check = validateEmpiricalBound(model, source);
if (check.ok) EMPIRICAL_CUTOFF_BOUNDS[model] = source;
return check;
}
/**
* Resolve a model id's cutoff from EITHER source: the vendor-published fence takes precedence (it is the
* attested spec), else a validated empirical bound if one has been measured. Returns null when neither
* exists — still fail-closed, but now the caller knows to run the probe.
*/
export function resolveCutoffSource(model: string): CutoffSource | null {
const vendor = MODEL_KNOWLEDGE_CUTOFF[model];
if (vendor !== undefined) return { kind: "vendor-published", cutoffMonth: vendor };
const empirical = EMPIRICAL_CUTOFF_BOUNDS[model];
if (empirical !== undefined && validateEmpiricalBound(model, empirical).ok) return empirical;
return null;
}