← Files Institutional Equity AnalystARCHIVED FILE
scripts/state_gate.py
2.76 KB · Oct 3, 2026 · 06:37 UTC
#!/usr/bin/env python3
"""Validate dependency-aware research state without third-party packages."""
from __future__ import annotations
import argparse
import json
from pathlib import Path
ALLOWED_MODULE = {"not_started", "in_progress", "blocked", "pass", "fail", "not_applicable"}
ALLOWED_GATE = {"open", "pass", "blocked", "fail"}
def validate(state: dict) -> dict:
errors, warnings = [], []
for key in ["company", "research_cutoff", "valuation_date", "workflow", "modules", "dependencies", "completion_status"]:
if key not in state:
errors.append(f"missing required field: {key}")
modules = state.get("modules", {})
for name, item in modules.items():
if not isinstance(item, dict) or item.get("status") not in ALLOWED_MODULE:
errors.append(f"module {name} has invalid status")
if item.get("status") in {"blocked", "fail", "not_applicable"} and not item.get("reason"):
errors.append(f"module {name} requires reason for status {item.get('status')}")
gates = state.get("dependencies", [])
known = set(modules) | {g.get("gate_id") for g in gates if isinstance(g, dict)}
for gate in gates:
if gate.get("status") not in ALLOWED_GATE:
errors.append(f"gate {gate.get('gate_id')} has invalid status")
missing = [dep for dep in gate.get("requires", []) if dep not in known]
if missing:
errors.append(f"gate {gate.get('gate_id')} has unknown dependencies: {missing}")
if gate.get("status") == "pass":
open_deps = [dep for dep in gate.get("requires", []) if dep in modules and modules[dep].get("status") not in {"pass", "not_applicable"}]
if open_deps:
errors.append(f"gate {gate.get('gate_id')} passed with open dependencies: {open_deps}")
elif not gate.get("reason"):
warnings.append(f"gate {gate.get('gate_id')} should explain non-pass status")
open_items = [name for name, item in modules.items() if item.get("status") not in {"pass", "not_applicable"}]
open_items += [g.get("gate_id") for g in gates if g.get("status") != "pass"]
if state.get("completion_status") == "PASS" and open_items:
errors.append("completion_status PASS conflicts with open modules or gates")
return {"status": "PASS" if not errors and not open_items else "RESEARCH_INCOMPLETE",
"errors": errors, "warnings": warnings, "open_items": open_items}
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("path", type=Path)
args = parser.parse_args()
state = json.loads(args.path.read_text(encoding="utf-8"))
result = validate(state)
print(json.dumps(result, indent=2))
return 0 if result["status"] == "PASS" else 2
if __name__ == "__main__":
raise SystemExit(main())
SHA-256: 2b8b1f71cb1fc6176a202768750dfbd91e55a9d0a50fe4fe123c9a4196f0a2ed