import { html } from "./report-format.js";
const outcomes = { passed: "Recorded pass", failed: "Recorded fail", unmeasured: "No main measurement" } as const;
const allowances = { "unused-initial": "Initial unused", "final-available": "Final available", exhausted: "Final consumed", unknown: "Allowance unknown" } as const;
const executionRecords = { "main-measured": "Main measurement recorded", "candidate-measured": "Candidate measured · outcome not projected", "candidate-failed": "Candidate run: FAIL", "candidate-passed": "Candidate run: PASS", "never-run": "Never run", unknown: "Execution evidence unknown" } as const;
const candidateOutcomes = { passed: "Latest candidate run: PASS", failed: "Latest candidate run: FAIL", "not-projected": "Latest candidate outcome not projected" } as const;
const readiness = { "not-assessed": "Not assessed here", "reviewed-candidate": "Candidate source reviewed", "needs-preparation": "Preparation needed" } as const;
export interface CatalogOverviewRow {
scenarioId: string;
mainOutcome: keyof typeof outcomes;
allowance: keyof typeof allowances;
sourceReadiness: keyof typeof readiness;
executionRecord: keyof typeof executionRecords;
latestCandidateOutcome?: keyof typeof candidateOutcomes;
}
export interface CatalogOverview {
schema: "paperclip.catalog-overview/v2";
asOf: string;
definitions: { lazy: number; legacy: number; featureAreas: number; capabilities: number; declaredGaps: number };
accounting: { mainMeasurements: number; retainedRawResults: number; closedSlots: number; exhaustedFinals: number; theoreticalMainCeiling: number };
rows: CatalogOverviewRow[];
}
function object(value: unknown, keys: readonly string[], optional: readonly string[] = []): Record {
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Invalid catalog overview object");
const row = value as Record;
if (Object.keys(row).some(key => !keys.includes(key) && !optional.includes(key)) || keys.some(key => !Object.hasOwn(row, key))) throw new Error("Unexpected catalog overview fields");
return row;
}
function integer(value: unknown): number {
if (!Number.isSafeInteger(value) || (value as number) < 0) throw new Error("Invalid catalog overview count");
return value as number;
}
function choice(value: unknown, choices: T): keyof T {
if (typeof value !== "string" || !Object.hasOwn(choices, value)) throw new Error("Invalid catalog overview state");
return value as keyof T;
}
export function parseCatalogOverview(value: unknown): CatalogOverview {
const input = object(value, ["schema", "asOf", "definitions", "accounting", "rows"]);
if (input.schema !== "paperclip.catalog-overview/v2" || typeof input.asOf !== "string" || !/^\d{4}-\d{2}-\d{2}T[\d:.]+Z$/.test(input.asOf) || !Number.isFinite(Date.parse(input.asOf))) throw new Error("Invalid catalog overview snapshot");
const d = object(input.definitions, ["lazy", "legacy", "featureAreas", "capabilities", "declaredGaps"]);
const definitions = { lazy: integer(d.lazy), legacy: integer(d.legacy), featureAreas: integer(d.featureAreas), capabilities: integer(d.capabilities), declaredGaps: integer(d.declaredGaps) };
if (definitions.lazy !== 242 || definitions.legacy !== 2 || definitions.featureAreas !== 35 || definitions.capabilities !== 191) throw new Error("Frozen catalog scope changed");
const a = object(input.accounting, ["mainMeasurements", "retainedRawResults", "closedSlots", "exhaustedFinals", "theoreticalMainCeiling"]);
const accounting = { mainMeasurements: integer(a.mainMeasurements), retainedRawResults: integer(a.retainedRawResults), closedSlots: integer(a.closedSlots), exhaustedFinals: integer(a.exhaustedFinals), theoreticalMainCeiling: integer(a.theoreticalMainCeiling) };
if (!Array.isArray(input.rows) || input.rows.length !== 244) throw new Error("Expected 244 catalog metadata rows");
const rows = input.rows.map(value => {
const row = object(value, ["scenarioId", "mainOutcome", "allowance", "sourceReadiness", "executionRecord"], ["latestCandidateOutcome"]);
if (typeof row.scenarioId !== "string" || !/^[a-z][a-z0-9-]*\.[a-z][a-z0-9-]*$/.test(row.scenarioId)) throw new Error("Invalid public catalog ID");
return { scenarioId: row.scenarioId, mainOutcome: choice(row.mainOutcome, outcomes), allowance: choice(row.allowance, allowances), sourceReadiness: choice(row.sourceReadiness, readiness), executionRecord: choice(row.executionRecord, executionRecords),
...(Object.hasOwn(row, "latestCandidateOutcome") ? { latestCandidateOutcome: choice(row.latestCandidateOutcome, candidateOutcomes) } : {}) };
});
if (new Set(rows.map(row => row.scenarioId)).size !== 244 || new Set(rows.map(row => row.scenarioId.split(".")[0])).size !== 35) throw new Error("Duplicate or incomplete catalog metadata");
for (const row of rows) {
if ((row.mainOutcome !== "unmeasured") !== (row.executionRecord === "main-measured") || (row.allowance === "unused-initial") !== (row.executionRecord === "never-run")
|| (row.latestCandidateOutcome !== undefined && ["never-run", "unknown"].includes(row.executionRecord))) throw new Error("Inconsistent recorded execution scope");
}
const measured = rows.filter(row => row.mainOutcome !== "unmeasured").length;
const knownExhausted = rows.filter(row => row.allowance === "exhausted").length;
if (accounting.mainMeasurements < measured || accounting.retainedRawResults < accounting.mainMeasurements || accounting.closedSlots < accounting.retainedRawResults || accounting.exhaustedFinals < knownExhausted
|| accounting.exhaustedFinals > knownExhausted + rows.filter(row => row.allowance === "unknown").length || accounting.theoreticalMainCeiling > 244) throw new Error("Inconsistent catalog accounting");
return { schema: "paperclip.catalog-overview/v2", asOf: input.asOf, definitions, accounting, rows };
}
function label(value: string) {
const text = value.replaceAll("-", " ");
return text.charAt(0).toUpperCase() + text.slice(1);
}
function nextAction(row: CatalogOverviewRow) {
if (row.allowance === "unknown") return "Recover ordinal evidence; keep allowance unknown";
if (row.mainOutcome === "passed") return "Retain the recorded outcome and its scope";
if (row.allowance === "exhausted") return "Review the retained outcome; no further attempt";
if (row.sourceReadiness === "needs-preparation") return "Prepare source, then review execution gates";
return row.allowance === "unused-initial" ? "Review source and execution gates for the initial" : "Review the initial cause and final execution gates";
}
function executionLabel(row: CatalogOverviewRow) {
return executionRecords[row.executionRecord] + (row.latestCandidateOutcome ? ` · ${candidateOutcomes[row.latestCandidateOutcome]}` : "");
}
const exampleIds = ["projects.create-project", "projects.archive-project", "tasks.edit-properties", "tasks.comment-with-reference", "documents-artifacts.write-plan", "documents-artifacts.produce-download", "inbox-search.restore-archive"];
export interface CatalogScenarioDescription { query: string; expectedOutcome: string }
export function renderCatalogOverview(value: unknown, descriptions: ReadonlyMap = new Map()) {
const data = parseCatalogOverview(value);
const count = (state: CatalogOverviewRow["mainOutcome"]) => data.rows.filter(row => row.mainOutcome === state).length;
const features = [...new Set(data.rows.map(row => row.scenarioId.split(".")[0]!))].sort();
const ceilingComparison = data.accounting.theoreticalMainCeiling < 196 ? "below" : data.accounting.theoreticalMainCeiling === 196 ? "equal to" : "above";
const examples = exampleIds.filter(id => data.rows.some(row => row.scenarioId === id && row.mainOutcome === "passed"));
return `
Chat feature catalog · private preview
All 244 scenarios
Recorded outcomes, remaining allowances and source readiness, shown separately.
Snapshot ${html(data.asOf)}
${count("passed")}Recorded feature-work passes
${count("failed")}Latest main failures
${count("unmeasured")}Without a main measurement
${count("passed") + count("failed")} main cases · ${data.accounting.mainMeasurements} main measurements. The ${count("unmeasured")} without a main measurement include ${data.rows.filter(row => row.allowance === "unused-initial").length} unused initials; these are different sets.
${data.rows.filter(row => row.executionRecord.startsWith("candidate-") || row.latestCandidateOutcome !== undefined).length} cases measured outside main · ${data.rows.filter(row => row.executionRecord === "never-run").length} never run · ${data.rows.filter(row => row.executionRecord === "unknown").length} with unknown execution evidence. A missing main measurement is not a claim that the case never ran. Candidate PASS and FAIL stay outside the main qualification total.
The theoretical eligible main ceiling is ${data.accounting.theoreticalMainCeiling}/244, ${ceilingComparison} the 196-case target. This is an upper bound, not a forecast or an execution approval.
${html(label(row.scenarioId.split(".")[1]!))}${html(label(row.scenarioId.split(".")[0]!))}${html(row.scenarioId)}${descriptions.has(row.scenarioId) ? `What this test asks
Human request: ${html(descriptions.get(row.scenarioId)!.query)}