Files
Jyotisha/scripts/research/consult_evidence_card_run.py
T
Jesse_ChenandClaude Opus 5.5 560d4fc2dd
Independent Staging Quality Gate / validate (push) Successful in 11m55s
Independent Staging Quality Gate / publish (push) Successful in 3m28s
fix(research): reuse existing handler instead of new __new__ forgeries
Gate run 2958 failed tests/test_api_server_growth_contract.py: the
evidence-card research script added two JyotishAPIHandler forgery sites.
Reuse capture_report_blocked_repairs_golden._handler(); output unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
2026-09-27 01:40:47 +08:00

265 lines
11 KiB
Python

"""Run the consultation evidence-card inventory. Read-only toward the engine.
External VedAstro is not called. The product foreground path still joins a
background gateway; this process replaces that join with the engine's own
blocked payload so local timing is not a network wait. Status text from that
blocked payload is what the model sees when the gateway does not return.
"""
from __future__ import annotations
import argparse
import json
import os
import subprocess
import sys
import time
from pathlib import Path
from typing import Any
ROOT = Path(__file__).resolve().parents[2]
SCRIPTS = ROOT / "scripts"
RESEARCH = Path(__file__).resolve().parent
for path in (ROOT, SCRIPTS, RESEARCH):
if str(path) not in sys.path:
sys.path.insert(0, str(path))
from consult_evidence_card_lib import ( # noqa: E402
QUESTIONS,
card_dependencies,
category_report,
cut_evidence_card,
duplicate_report,
engine_facts,
estimate_tokens,
load_public_charts,
part_b_coverage,
source_matrix,
verbatim_check,
)
def _block_external_vedastro() -> None:
import vedastro_foreground as gateway
def start(self):
self.meta = {
"freshness": "research_not_called",
"external_vedastro": "not_called",
}
self.cached_gateway = gateway._blocked_foreground_vedastro(
reason="research_external_vedastro_not_called",
)
self.future = None
return self
gateway.ForegroundVedastroSession.start = start
def _workflow_body(chart: dict[str, Any], question: dict[str, str]) -> dict[str, Any]:
from consultation_plan_contract import PLAN_VERSION, plan_route_contract
domain = question["domain"]
contract = plan_route_contract(domain)
if contract is None:
raise RuntimeError(f"no plan contract for {domain}")
body = dict(chart["body"])
body.update({
"question": question["question"],
"question_text": question["question"],
"theme": list(contract.themes),
"plan_version": PLAN_VERSION,
"strict_workflow_route": domain,
"required_layers": list(contract.required_layers),
"claim_boundary": contract.claim_boundary,
"plan_depth": "standard",
"requested_domains": list(contract.requested_domains),
"timing_horizon": None,
"precision_boundary": "server_evidence_required",
"required_evidence_categories": list(contract.required_evidence_categories),
"surface": "api_web",
})
return body
def _run_workflow(body: dict[str, Any]) -> dict[str, Any]:
# Reuse the existing golden-capture handler instead of adding another
# handler-forgery site (tests/test_api_server_growth_contract.py).
from capture_report_blocked_repairs_golden import _handler
return _handler()._compute_consultation_workflow(body)
def _project(jobs: list[dict[str, str]], summary_path: Path) -> list[dict[str, Any]]:
spec_path = summary_path.with_suffix(".jobs.json")
spec_path.write_text(json.dumps({"items": jobs}), encoding="utf-8")
tsx = ROOT / "frontend" / "node_modules" / "tsx" / "dist" / "cli.mjs"
env = os.environ.copy()
env["JYOTISHA_PROJECT_ROOT"] = str(ROOT)
command = [
"node",
str(tsx),
str(ROOT / "scripts" / "research" / "project_consult_model_context.ts"),
"project",
str(spec_path),
str(summary_path),
]
completed = subprocess.run(command, cwd=ROOT, env=env, capture_output=True, text=True)
if completed.returncode != 0:
raise RuntimeError(completed.stderr[-4000:] or completed.stdout[-4000:])
return json.loads(summary_path.read_text(encoding="utf-8"))
def _time_layers(chart_body: dict[str, Any]) -> dict[str, float]:
"""Time local layers on one birth payload. VedAstro stays blocked."""
from capture_report_blocked_repairs_golden import _handler
from jyotish_api_server import (
_attach_local_consultation_layers,
_build_consultation_varga_spectrum,
_custom_research_dn_chart,
_planet_longitudes,
)
handler = _handler()
timings: dict[str, float] = {}
def elapsed(name: str, fn, *args, **kwargs):
started = time.perf_counter()
result = fn(*args, **kwargs)
timings[name] = round(time.perf_counter() - started, 4)
return result
chart = elapsed("compute_chart", handler._compute_chart, {
**chart_body,
"skip_vedastro_main_entry_overview": True,
})
planets = chart.get("planets") if isinstance(chart, dict) else {}
ascendant = chart.get("ascendant") if isinstance(chart, dict) else {}
elapsed("attach_local_layers", _attach_local_consultation_layers, handler, chart, chart_body, chart_body)
if isinstance(planets, dict) and isinstance(ascendant, dict) and planets and ascendant:
elapsed("varga_spectrum", _build_consultation_varga_spectrum, handler, planets, ascendant)
elapsed("shadbala", handler._compute_shadbala, {**chart_body, "planets": planets, "ascendant": ascendant})
elapsed("ashtakavarga", handler._compute_ashtakavarga, {"planets": planets, "ascendant": ascendant})
elapsed("functional_benefic_malefic", handler._functional_benefic_malefic_snapshot, planets, ascendant)
try:
module = __import__("divisional_charts_extended", fromlist=["DivisionalChartsCalculator"])
calc = module.DivisionalChartsCalculator()
planet_lons = _planet_longitudes(planets)
asc_lon = float(ascendant.get("lon"))
elapsed("one_research_division", _custom_research_dn_chart, calc, planet_lons, asc_lon, 3)
except Exception as exc:
timings["one_research_division_error"] = exc.__class__.__name__
return timings
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--out", default=str(ROOT / "docs" / "research" / "consult_evidence_card_inventory_2026_09_27.json"))
parser.add_argument("--cache", default="")
parser.add_argument("--only-chart", action="append", default=[])
parser.add_argument("--only-question", action="append", default=[])
parser.add_argument("--skip-timing", action="store_true")
args = parser.parse_args()
if os.environ.get("PYTHONHASHSEED") != "0":
raise SystemExit("Set PYTHONHASHSEED=0 before starting this process (ERR-111).")
_block_external_vedastro()
cache = Path(args.cache) if args.cache else Path(os.environ.get("TEMP", ".")) / "consult-evidence-card-20260927"
cache.mkdir(parents=True, exist_ok=True)
charts = load_public_charts(ROOT)
questions = list(QUESTIONS)
if args.only_chart:
charts = [chart for chart in charts if chart["id"] in args.only_chart]
if args.only_question:
questions = [item for item in questions if item["id"] in args.only_question]
runs = []
jobs = []
for chart in charts:
for question in questions:
run_id = f"{chart['id']}__{question['id']}"
workflow_path = cache / f"{run_id}.workflow.json"
started = time.perf_counter()
workflow = _run_workflow(_workflow_body(chart, question))
wall = round(time.perf_counter() - started, 3)
workflow_path.write_text(json.dumps(workflow, ensure_ascii=False), encoding="utf-8")
projected_path = cache / f"{run_id}.model.json"
jobs.append({
"id": run_id,
"domain": question["domain"],
"question": question["question"],
"workflow_path": str(workflow_path),
"out_path": str(projected_path),
})
runs.append({
"id": run_id,
"chart_id": chart["id"],
"chart_label": chart["label"],
"question_id": question["id"],
"domain": question["domain"],
"wall_seconds": wall,
"workflow_chars": workflow_path.stat().st_size,
"route": (workflow.get("routing") or {}).get("question_type"),
"focus_techniques": (workflow.get("routing") or {}).get("focus_techniques"),
"success": workflow.get("success"),
})
print(f"{run_id} wall={wall}s route={runs[-1]['route']}", flush=True)
summary_path = cache / "projection-summary.json"
projected = {item["id"]: item for item in _project(jobs, summary_path)}
inventory = []
for run, job in zip(runs, jobs):
model_context = json.loads(Path(job["out_path"]).read_text(encoding="utf-8"))
workflow = json.loads(Path(job["workflow_path"]).read_text(encoding="utf-8"))
categories = category_report(model_context)
card = cut_evidence_card(model_context, run["question_id"])
facts = engine_facts(workflow)
check = verbatim_check(card["card"], facts)
inventory.append({
**run,
"projection": projected.get(run["id"]),
"categories": categories,
"duplicates": duplicate_report(model_context),
"card_size": card["size"],
"card_gaps": card["gaps"],
"part_b": part_b_coverage(card["card"], run["question_id"]),
"verbatim": check,
"card_dependencies": card_dependencies(run["question_id"]),
"sample_card": card["card"] if run["chart_id"] == "steve_jobs" and run["question_id"] in {"parents", "career"} else None,
})
timings = {}
if not args.skip_timing:
for chart in charts:
print(f"timing {chart['id']}", flush=True)
try:
timings[chart["id"]] = _time_layers(chart["body"])
except Exception as exc:
timings[chart["id"]] = {"error": exc.__class__.__name__, "message": str(exc)[:300]}
payload = {
"baseline": "76924e3362c0a47d9d8de896c448c66055826f70",
"reference_date": "2026-09-27",
"ayanamsa": "raman",
"node_mode": "mean",
"pythonhashseed": "0",
"external_vedastro": "not_called",
"token_method": estimate_tokens("")["token_method"],
"charts": [
{"id": chart["id"], "label": chart["label"], "source": chart["source"], "case_id": chart["case_id"], "rodden_rating": chart["rodden_rating"]}
for chart in load_public_charts(ROOT)
],
"source_matrix": source_matrix(ROOT),
"runs": inventory,
"layer_timings_seconds": timings,
}
out = Path(args.out)
out.parent.mkdir(parents=True, exist_ok=True)
out.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")
print(f"wrote {out}", flush=True)
return 0
if __name__ == "__main__":
raise SystemExit(main())