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>
91 lines
4.1 KiB
Python
91 lines
4.1 KiB
Python
"""Optional v2 server-owned fact tables; no writer output accepts these fields."""
|
|
|
|
import math
|
|
import re
|
|
|
|
GROUPS = {"vimshottari", "ashtakavarga", "shadbala", "functional_roles", "avasthas", "special_points", "sade_sati", "annual"}
|
|
PATH = re.compile(r"[A-Za-z0-9_.\[\]-]{1,400}")
|
|
STATUSES = {"multi_system_consensus", "single_system_inference", "parameter_sensitive", "unclosed_divisional_chart", "user_history_verification_required", "blocked"}
|
|
|
|
|
|
def validate_fact_tables(value, add):
|
|
def text(item, maximum, minimum=0):
|
|
return isinstance(item, str) and minimum <= len(item) <= maximum
|
|
|
|
def within(child, parent):
|
|
return isinstance(child, str) and bool(PATH.fullmatch(child)) and (child == parent or child.startswith(parent + ".") or child.startswith(parent + "["))
|
|
|
|
def grid(table, path, parent=None):
|
|
source = table.get("sourcePath")
|
|
if not isinstance(source, str) or not PATH.fullmatch(source):
|
|
add(path, "invalid source path")
|
|
return
|
|
if parent is not None and not within(source, parent):
|
|
add(path, "fact_table_source_mismatch")
|
|
if not text(table.get("title"), 120, 1) or not text(table.get("note"), 500):
|
|
add(path, "invalid text")
|
|
columns = table.get("columns")
|
|
if not isinstance(columns, list) or not 1 <= len(columns) <= 16 or not all(text(c, 80, 1) for c in columns):
|
|
add(path, "invalid columns")
|
|
return
|
|
rows = table.get("rows")
|
|
if not isinstance(rows, list) or len(rows) > 2000:
|
|
add(path, "invalid rows")
|
|
return
|
|
for row in rows:
|
|
if not isinstance(row, dict) or set(row) != {"sourcePath", "cells"}:
|
|
add(path, "invalid row keys")
|
|
continue
|
|
if not within(row["sourcePath"], source):
|
|
add(path, "fact_table_source_mismatch")
|
|
cells = row["cells"]
|
|
if not isinstance(cells, list) or len(cells) != len(columns):
|
|
add(path, "fact_table_cell_count")
|
|
continue
|
|
for cell in cells:
|
|
if cell is None or isinstance(cell, bool) or text(cell, 300):
|
|
continue
|
|
if isinstance(cell, (int, float)) and math.isfinite(cell):
|
|
continue
|
|
add(path, "invalid cell")
|
|
|
|
if not isinstance(value, list) or len(value) > 8:
|
|
add("factTables", "must be array with at most eight groups")
|
|
return
|
|
seen = set()
|
|
required = {"id", "title", "claimStatus", "sourcePath", "note", "columns", "rows"}
|
|
subkeys = required - {"claimStatus"}
|
|
for index, table in enumerate(value):
|
|
path = f"factTables[{index}]"
|
|
if not isinstance(table, dict) or not required <= set(table) or set(table) - required - {"subtables"}:
|
|
add(path, "invalid table keys")
|
|
continue
|
|
group = table["id"]
|
|
if not isinstance(group, str) or group not in GROUPS or group in seen:
|
|
add(path, "invalid or duplicate group")
|
|
else:
|
|
seen.add(group)
|
|
if not isinstance(table["claimStatus"], str) or table["claimStatus"] not in STATUSES:
|
|
add(path, "invalid claim status")
|
|
grid(table, path)
|
|
if "subtables" not in table:
|
|
continue
|
|
children = table["subtables"]
|
|
if not isinstance(children, list) or len(children) > 8:
|
|
add(path, "invalid subtables")
|
|
continue
|
|
child_ids = set()
|
|
for child_index, child in enumerate(children):
|
|
child_path = f"{path}.subtables[{child_index}]"
|
|
if not isinstance(child, dict) or set(child) != subkeys:
|
|
add(child_path, "invalid subtable keys")
|
|
continue
|
|
child_id = child["id"]
|
|
if not text(child_id, 80, 1) or not re.fullmatch(r"[a-z][a-z0-9_-]*", child_id) or child_id in child_ids:
|
|
add(child_path, "invalid or duplicate subtable")
|
|
else:
|
|
child_ids.add(child_id)
|
|
parent = table["sourcePath"]
|
|
if isinstance(parent, str):
|
|
grid(child, child_path, parent)
|