Files
Jyotisha/frontend/src/lib/report-fact-table-schema.ts
T
jesse-uxandClaude Code a12f2c0d26
Independent Staging Quality Gate / validate (push) Failing after 11m4s
Independent Staging Quality Gate / publish (push) Skipped
fix(report): make density facts readable and printable
Unify reader cleanup rules, lock writer table guards, and register the exact fictional timestamp collision. Preserve existing ordinary-report safety contracts and source-data gaps.

Validation: report Node 165/165, final safety 29/29, Python 101/101, Chrome 28/28; both PDFs retain all 130 rows. Full Node 3704 tests with the same 91 baseline failures. Privacy test: 62 passed, 1 failed due to 17 protected-file READ_ERRORs; not a green gate. Build, DB, manual checklist and controlled-login gaps remain documented. User explicitly authorized staging push with these gaps disclosed.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-23 15:26:25 +08:00

47 lines
2.7 KiB
TypeScript

import { z } from "zod";
export const FACT_TABLE_GROUPS = ["vimshottari", "ashtakavarga", "shadbala", "functional_roles", "avasthas", "special_points", "sade_sati", "annual"] as const;
const sourcePath = z.string().min(1).max(400).regex(/^[A-Za-z0-9_.\[\]-]+$/);
const gridShape = {
sourcePath,
note: z.string().max(500),
columns: z.array(z.string().min(1).max(80)).min(1).max(16),
rows: z.array(z.object({
sourcePath,
cells: z.array(z.union([z.string().max(300), z.number().finite(), z.boolean(), z.null()])).min(1).max(16),
}).strict()).max(2000),
};
const within = (child: string, parent: string) => child === parent || child.startsWith(`${parent}.`) || child.startsWith(`${parent}[`);
function validateRows(table: { sourcePath: string; columns: string[]; rows: { sourcePath: string; cells: unknown[] }[] }, context: z.RefinementCtx) {
table.rows.forEach((row, index) => {
if (row.cells.length !== table.columns.length) context.addIssue({ code: "custom", path: ["rows", index], message: "fact_table_cell_count" });
if (!within(row.sourcePath, table.sourcePath)) context.addIssue({ code: "custom", path: ["rows", index, "sourcePath"], message: "fact_table_source_mismatch" });
});
}
export const reportFactSubtableSchema = z.object({
id: z.string().min(1).max(80).regex(/^[a-z][a-z0-9_-]*$/),
title: z.string().min(1).max(120),
...gridShape,
}).strict().superRefine(validateRows);
/** Optional subtables are additive: persisted v2 snapshots keep their original rows. */
export const reportFactTableSchema = z.object({
id: z.enum(FACT_TABLE_GROUPS),
title: z.string().min(1).max(120),
claimStatus: z.enum(["multi_system_consensus", "single_system_inference", "parameter_sensitive", "unclosed_divisional_chart", "user_history_verification_required", "blocked"]),
...gridShape,
subtables: z.array(reportFactSubtableSchema).max(8).optional(),
}).strict().superRefine((table, context) => {
validateRows(table, context);
const subtables = table.subtables ?? [];
if (new Set(subtables.map(subtable => subtable.id)).size !== subtables.length) context.addIssue({ code: "custom", path: ["subtables"], message: "duplicate_fact_subtable" });
subtables.forEach((subtable, index) => {
if (!within(subtable.sourcePath, table.sourcePath)) context.addIssue({ code: "custom", path: ["subtables", index, "sourcePath"], message: "fact_table_source_mismatch" });
});
});
export const reportFactTablesSchema = z.array(reportFactTableSchema).max(8).superRefine((tables, context) => {
if (new Set(tables.map((table) => table.id)).size !== tables.length) context.addIssue({ code: "custom", message: "duplicate_fact_table" });
});
export type ReportFactTable = z.infer<typeof reportFactTableSchema>;
export type ReportFactSubtable = z.infer<typeof reportFactSubtableSchema>;