136 lines
3.1 KiB
TypeScript
136 lines
3.1 KiB
TypeScript
// TypeScript mirrors of the persisted v2 artifact payload contracts. Detection everywhere is
|
|
// `data.schema_version === 2` + a shape-guard; anything else falls back to the
|
|
// legacy renderers in ArtifactView.
|
|
|
|
// --- A. cte_plan v2 ---------------------------------------------------------
|
|
|
|
export interface CtePlanTable {
|
|
name: string;
|
|
description?: string;
|
|
}
|
|
|
|
export interface CtePlanFilter {
|
|
column: string;
|
|
op: string;
|
|
value: string;
|
|
description?: string;
|
|
rationale?: string;
|
|
}
|
|
|
|
export interface CtePlanCte {
|
|
name: string;
|
|
index: number;
|
|
purpose?: string;
|
|
rationale?: string;
|
|
depends_on?: string[];
|
|
tables?: CtePlanTable[];
|
|
keys?: string[];
|
|
filters?: CtePlanFilter[];
|
|
output_columns?: string[];
|
|
}
|
|
|
|
export interface CtePlanV2 {
|
|
schema_version: 2;
|
|
question?: string;
|
|
strategy?: string;
|
|
ctes: CtePlanCte[];
|
|
}
|
|
|
|
// --- B. cte_result v2 --------------------------------------------------------
|
|
|
|
export interface CteResultColumn {
|
|
name: string;
|
|
description?: string;
|
|
}
|
|
|
|
export interface CteResultPreview {
|
|
columns: string[];
|
|
rows: unknown[][];
|
|
}
|
|
|
|
export interface CteResultV2 {
|
|
schema_version: 2;
|
|
name: string;
|
|
index: number;
|
|
total: number;
|
|
purpose?: string;
|
|
rationale?: string;
|
|
depends_on?: string[];
|
|
sql: string;
|
|
status: "ok" | "error" | string;
|
|
execution_ms?: number;
|
|
row_sample?: number;
|
|
warnings?: string[];
|
|
sql_hash?: string;
|
|
columns?: CteResultColumn[];
|
|
preview?: CteResultPreview;
|
|
note?: string;
|
|
}
|
|
|
|
// --- C. phase summary v2 -----------------------------------------------------
|
|
|
|
export interface PhaseMeta {
|
|
id: string;
|
|
num: number;
|
|
name: string;
|
|
}
|
|
|
|
export interface PhaseCheck {
|
|
label: string;
|
|
status: "ok" | "warn" | "fail" | string;
|
|
detail?: string;
|
|
}
|
|
|
|
export interface PhaseSectionItem {
|
|
label: string;
|
|
table?: string;
|
|
column?: string;
|
|
value?: string;
|
|
kind?: "table" | "column" | "filter" | "join" | "metric" | "note" | string;
|
|
description?: string;
|
|
rationale?: string;
|
|
}
|
|
|
|
export interface PhaseSection {
|
|
title: string;
|
|
items?: PhaseSectionItem[];
|
|
}
|
|
|
|
export interface PhaseTableColumn {
|
|
name: string;
|
|
description?: string;
|
|
value_filter?: string;
|
|
}
|
|
|
|
export interface PhaseTable {
|
|
name: string;
|
|
role: "promoted" | "excluded" | string;
|
|
description?: string;
|
|
columns?: PhaseTableColumn[];
|
|
}
|
|
|
|
export interface PhaseSummaryV2 {
|
|
schema_version: 2;
|
|
phase: PhaseMeta;
|
|
summary?: string;
|
|
checks?: PhaseCheck[];
|
|
sections?: PhaseSection[];
|
|
tables?: PhaseTable[];
|
|
open_questions?: string[];
|
|
}
|
|
|
|
/** Defensive compatibility for malformed v2 artifacts persisted before the gate
|
|
* enforced `open_questions: string[]`. New payloads stay strictly typed as strings. */
|
|
export function phaseOpenQuestionText(value: unknown): string | null {
|
|
if (typeof value === "string") return value.trim() || null;
|
|
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
|
|
const record = value as Record<string, unknown>;
|
|
for (const field of ["question", "label"]) {
|
|
const text = record[field];
|
|
if (typeof text === "string" && text.trim()) return text.trim();
|
|
}
|
|
return null;
|
|
}
|