feat: import reproducible timing validation
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Merge pinned NuGet metadata with the container runtime reflection probe."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse, json
|
||||
from pathlib import Path
|
||||
|
||||
def build_archive(candidate: Path, runtime: Path) -> dict:
|
||||
metadata=json.loads(candidate.read_text(encoding="utf-8")); probe=json.loads(runtime.read_text(encoding="utf-8"))
|
||||
return {**metadata,"assembly_version":probe["version"],"assembly_informational_version":probe["informational_version"],"public_methods":probe["methods"],"public_method_contracts":probe["method_contracts"],"runtime_image_id":"sha256:ea4f5eec20952a885a89566fc35cf3295b3228375b715a0f1af9e5a3c0c2eebf","runtime_image_digest":"sha256:d32bd65cf5843f413e81f5d917057c82da99737cb1637e905a1a4bc2e7ec6c8d"}
|
||||
|
||||
def main()->int:
|
||||
p=argparse.ArgumentParser(description=__doc__);p.add_argument("runtime",type=Path);p.add_argument("--candidate",type=Path,default=Path("references/oracle/vedastro_nuget_candidate_1_2_0.json"));p.add_argument("--output",type=Path,required=True);a=p.parse_args();r=build_archive(a.candidate,a.runtime);a.output.parent.mkdir(parents=True,exist_ok=True);a.output.write_text(json.dumps(r,ensure_ascii=False,indent=2,sort_keys=True)+"\n",encoding="utf-8");print(json.dumps({"status":r["status"],"method_count":len(r["public_methods"])},sort_keys=True));return 0
|
||||
if __name__=="__main__":raise SystemExit(main())
|
||||
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Validate independently labeled day-level timing holdout annotations."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse, json
|
||||
from pathlib import Path
|
||||
|
||||
REQUIRED={"case_id","domain","label","start","end","source_url","adjudicator","time_uncertainty_days"}
|
||||
|
||||
def validate(path: Path) -> dict:
|
||||
data=json.loads(path.read_text(encoding="utf-8")); rows=data.get("annotations") or []; errors=[]
|
||||
for i,row in enumerate(rows):
|
||||
for key in sorted(REQUIRED-set(row)): errors.append({"row":i,"field":key,"error":"missing"})
|
||||
if row.get("label") not in {"target_event","no_target_event"}: errors.append({"row":i,"field":"label","error":"invalid"})
|
||||
if not str(row.get("source_url") or "").startswith(("https://","http://")): errors.append({"row":i,"field":"source_url","error":"not_public_url"})
|
||||
positives=sum(r.get("label")=="target_event" for r in rows); negatives=sum(r.get("label")=="no_target_event" for r in rows)
|
||||
gate=data.get("frozen_gate") or {}; ready=not errors and positives>=gate.get("minimum_independent_cases",20) and negatives>=gate.get("minimum_independent_negative_intervals",80)
|
||||
return {"scope":"day_level_holdout_validation","annotation_count":len(rows),"positive_count":positives,"negative_count":negatives,"errors":errors,"status":"ready_for_blind_replay" if ready else "awaiting_independent_labels","production_tuning_allowed":False}
|
||||
|
||||
def main()->int:
|
||||
p=argparse.ArgumentParser(description=__doc__);p.add_argument("manifest",type=Path);a=p.parse_args();r=validate(a.manifest);print(json.dumps(r,ensure_ascii=False,indent=2,sort_keys=True));return 0
|
||||
if __name__=="__main__":raise SystemExit(main())
|
||||
@@ -451,6 +451,8 @@ def execute_consultation_workflow(
|
||||
surface: str = 'api_web',
|
||||
chart_override: dict | None = None,
|
||||
) -> dict:
|
||||
from scripts.timing_precision_contract import build_timing_precision_contract
|
||||
|
||||
birth_payload = handler._high_rigor_birth_payload(body)
|
||||
themes = handler._high_rigor_requested_themes(body)
|
||||
events = handler._high_rigor_events(body)
|
||||
@@ -524,6 +526,7 @@ def execute_consultation_workflow(
|
||||
if body.get('require_external_parity') and external_parity_gate.get('status') != 'pass':
|
||||
result['success'] = False
|
||||
result['blocked_reason'] = 'external_parity_not_passed'
|
||||
result['timing_precision_contract'] = build_timing_precision_contract(body.get('timing'))
|
||||
return result
|
||||
|
||||
chart = dict(chart_override) if isinstance(chart_override, dict) else {}
|
||||
@@ -711,6 +714,7 @@ def execute_consultation_workflow(
|
||||
result['blocked_reason'] = 'external_parity_not_passed'
|
||||
if body.get('return_high_rigor_shape'):
|
||||
result['endpoint'] = 'high_rigor_workflow'
|
||||
result['timing_precision_contract'] = build_timing_precision_contract(body.get('timing'))
|
||||
return result
|
||||
|
||||
|
||||
|
||||
@@ -6300,6 +6300,9 @@ def main():
|
||||
output_json(result)
|
||||
sys.exit(0 if result.get('valid', True) else 1)
|
||||
result = cmds[args.command](args)
|
||||
if args.command in {'predict', 'full-reading'} and isinstance(result, dict):
|
||||
from timing_precision_contract import build_timing_precision_contract
|
||||
result['timing_precision_contract'] = build_timing_precision_contract(result.get('timing'))
|
||||
if getattr(args, 'table', False):
|
||||
output_table(args.command, result)
|
||||
else:
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Classify parity mismatches by evidence shape without choosing truth by vote."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from collections import Counter
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
VARGA_SECTIONS = {"D2", "D4", "D9", "D10"}
|
||||
|
||||
|
||||
def _category(section: str, differing: list[str]) -> tuple[str, str]:
|
||||
if section in VARGA_SECTIONS and differing == ["VedAstro"]:
|
||||
return (
|
||||
"endpoint_or_varga_semantics",
|
||||
"Confirm VedAstro endpoint returns the requested varga under the same ayanamsa/node/method contract.",
|
||||
)
|
||||
if section.startswith("ashtakavarga"):
|
||||
return (
|
||||
"ashtakavarga_table_or_contributor_variant",
|
||||
"Compare contributor tables, Lagna inclusion, shodhana state, and BAV/SAV row semantics.",
|
||||
)
|
||||
if section == "shadbala_components":
|
||||
return (
|
||||
"shadbala_formula_variant",
|
||||
"Compare component formula, units, local solar context, aspect model, and Chesta lineage before totals.",
|
||||
)
|
||||
if section == "shadbala_total":
|
||||
return (
|
||||
"derived_total_from_component_variants",
|
||||
"Do not arbitrate totals until all six component variants and Virupa/Rupa units are aligned.",
|
||||
)
|
||||
if differing == ["VedAstro"]:
|
||||
return (
|
||||
"vedastro_deployment_or_method_drift",
|
||||
"Replay against an identified VedAstro build and method; hosted anonymous output cannot decide truth.",
|
||||
)
|
||||
return (
|
||||
"cross_engine_numeric_or_schema_difference",
|
||||
"Normalize versions, schema paths, units, and formula variants; require an external worked example.",
|
||||
)
|
||||
|
||||
|
||||
def arbitrate_manifest(path: str | Path) -> dict[str, Any]:
|
||||
manifest_path = Path(path)
|
||||
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
||||
rows: list[dict[str, Any]] = []
|
||||
categories: Counter[str] = Counter()
|
||||
for source in manifest.get("comparison_rows") or []:
|
||||
if source.get("status") != "mismatch":
|
||||
continue
|
||||
local = source.get("local_value")
|
||||
differing = sorted(
|
||||
engine for engine, value in (source.get("oracle_values") or {}).items() if value != local
|
||||
)
|
||||
category, closure = _category(str(source.get("section")), differing)
|
||||
categories[category] += 1
|
||||
rows.append({
|
||||
"section": source.get("section"),
|
||||
"field": source.get("field"),
|
||||
"local_value": local,
|
||||
"oracle_values": source.get("oracle_values"),
|
||||
"differing_engines": differing,
|
||||
"category": category,
|
||||
"closure_requirement": closure,
|
||||
"truth_status": "unresolved",
|
||||
})
|
||||
return {
|
||||
"scope": "three_engine_field_level_mismatch_arbitration",
|
||||
"manifest_path": str(manifest_path),
|
||||
"truth_policy": "no_majority_vote",
|
||||
"mismatch_count": len(rows),
|
||||
"classified_count": sum(categories.values()),
|
||||
"unclassified_count": len(rows) - sum(categories.values()),
|
||||
"category_counts": dict(sorted(categories.items())),
|
||||
"rows": rows,
|
||||
"status": "classified_unresolved" if rows else "no_mismatches",
|
||||
}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("manifest", nargs="?", default="references/oracle/three_engine_parity_replay_manifest.json")
|
||||
parser.add_argument("--output", type=Path)
|
||||
args = parser.parse_args()
|
||||
report = arbitrate_manifest(args.manifest)
|
||||
text = json.dumps(report, ensure_ascii=False, indent=2, sort_keys=True) + "\n"
|
||||
if args.output:
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.output.write_text(text, encoding="utf-8")
|
||||
print(text, end="")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Honest three-layer timing contract for uncalibrated day/month rankings."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
|
||||
def build_timing_precision_contract(payload: dict[str, Any] | None = None) -> dict[str, Any]:
|
||||
source = payload if isinstance(payload, dict) else {}
|
||||
candidates = source.get("candidate_windows") if isinstance(source.get("candidate_windows"), list) else []
|
||||
triggers = source.get("exact_triggers") if isinstance(source.get("exact_triggers"), list) else []
|
||||
verified_window = source.get("verified_window") or source.get("broad_window")
|
||||
return {
|
||||
"timing_precision": "candidate_day_window" if candidates else "broad_window_only",
|
||||
"claim_status": "exploratory_unvalidated",
|
||||
"verified_window": verified_window,
|
||||
"candidate_windows": candidates,
|
||||
"exact_triggers": triggers,
|
||||
"promotion_gate": {
|
||||
"status": "blocked",
|
||||
"required": "new_independently_labeled_day_level_holdout",
|
||||
"current_negative_controls_reusable_for_tuning": False,
|
||||
},
|
||||
"boundary": "候选日期未通过独立日级 holdout 验证,不能作为确定事件承诺;精确时间仅表示技术触发点。",
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Attribute Xalen Shadbala and Ashtakavarga differences by formula and unit."""
|
||||
|
||||
from __future__ import annotations
|
||||
import argparse,json
|
||||
from collections import Counter
|
||||
from pathlib import Path
|
||||
|
||||
FORMULAS={
|
||||
"sthana":("precise sapta-varga dignity with compound temporary relationships and moolatrikona","Xalen sapta-varga dignity using fixed unit friendship scores","formula_variant","Virupa"),
|
||||
"dig":("longitude distance from exact powerless bhava midpoint / 3","house-number distance from strongest house, linearly scaled","geometry_variant","Virupa"),
|
||||
"kala":("actual local sunrise/sunset, declination and ahargana Varsha/Maasa/Vaara/Hora","clock day_fraction with nominal 06:00 sunrise plus JD-derived lords","solar_context_variant","Virupa"),
|
||||
"chesta":("bounded BPHS/Surya mean-motion Seeghrochcha implementation","speed bands: retrograde=60, stationary=30, direct=15; Sun/Moon=30","motion_model_variant","Virupa"),
|
||||
"drik":("continuous Sphuta Drishti curve, natural benefic/malefic, divided by 4","house-bin graded Vedic aspects, natural benefic/malefic, divided by 4","aspect_interpolation_variant","Virupa"),
|
||||
}
|
||||
|
||||
def build_report(path:Path)->dict:
|
||||
d=json.loads(path.read_text(encoding="utf-8")); rows=[]; counts=Counter()
|
||||
for r in d["rows"]:
|
||||
if r["status"]!="mismatch" or r["section"] not in {"shadbala_components","shadbala_total","ashtakavarga_bav","ashtakavarga_sav"}:continue
|
||||
item={"section":r["section"],"field":r["field"],"local_value":r["local_value"],"xalen_value":r["xalen_value"]}
|
||||
if r["section"]=="shadbala_components":
|
||||
component=r["field"].split(".",1)[1]; local,xalen,category,unit=FORMULAS[component];item.update(category=category,unit=unit,local_formula=local,xalen_formula=xalen,truth_status="method_variant_unresolved")
|
||||
elif r["section"]=="shadbala_total": item.update(category="derived_total_from_five_component_variants",unit="Virupa",local_formula="sum of six displayed components",xalen_formula="sum of six displayed components",truth_status="defer_until_components_arbitrated")
|
||||
else:
|
||||
lv,xv=r["local_value"],r["xalen_value"]; delta=[b-a for a,b in zip(lv,xv)];item.update(category="contributor_table_variant",unit="bindu_count",delta_by_sign=delta,local_formula="PVR/PyJHora worked-example calibrated 8-contributor BAV tables; SAV excludes Lagna row",xalen_formula="Xalen BPHS-labelled 8-contributor tables; returned SAV sums seven planetary rows",row_total_local=sum(lv),row_total_xalen=sum(xv),truth_status="requires_external_worked_example_per_contributor")
|
||||
counts[item["category"]]+=1;rows.append(item)
|
||||
return {"scope":"xalen_formula_unit_attribution","row_count":len(rows),"classified_count":sum(counts.values()),"category_counts":dict(sorted(counts.items())),"rows":rows,"status":"classified_method_variants_not_truth"}
|
||||
|
||||
def main()->int:
|
||||
p=argparse.ArgumentParser(description=__doc__);p.add_argument("comparison",type=Path,nargs="?",default=Path("references/oracle/xalen_fourth_oracle_comparison_2026_07_17.json"));p.add_argument("--output",type=Path);a=p.parse_args();r=build_report(a.comparison);text=json.dumps(r,ensure_ascii=False,indent=2,sort_keys=True)+"\n";
|
||||
if a.output:a.output.parent.mkdir(parents=True,exist_ok=True);a.output.write_text(text,encoding="utf-8")
|
||||
print(text,end="");return 0
|
||||
if __name__=="__main__":raise SystemExit(main())
|
||||
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Compare Xalen shared-input and independent VSOP87 ephemeris modes."""
|
||||
from __future__ import annotations
|
||||
import argparse,json
|
||||
from pathlib import Path
|
||||
|
||||
def compare(shared_path:Path,independent_path:Path)->dict:
|
||||
s=json.loads(shared_path.read_text(encoding='utf-8'))['raw'];i=json.loads(independent_path.read_text(encoding='utf-8'))['raw'];positions={}
|
||||
for name,a in s['effective_positions'].items():
|
||||
b=i['effective_positions'][name];delta=(b['longitude']-a['longitude']+180)%360-180;positions[name]={'shared_longitude':a['longitude'],'independent_longitude':b['longitude'],'longitude_delta_deg':delta,'speed_delta_deg_per_day':b['speed']-a['speed']}
|
||||
varga_diffs=sum(s['varga'][d][p]!=i['varga'][d][p] for d in s['varga'] for p in s['varga'][d]);av_diffs=sum(s['ashtakavarga']['bav'][p]!=i['ashtakavarga']['bav'][p] for p in s['ashtakavarga']['bav'])+(s['ashtakavarga']['sav']!=i['ashtakavarga']['sav']);shad={p:i['shadbala'][p]['total']-s['shadbala'][p]['total'] for p in s['shadbala']}
|
||||
return {'scope':'xalen_ephemeris_mode_comparison','shared_mode':s['ephemeris_mode'],'independent_mode':i['ephemeris_mode'],'independent_engine':'Xalen Almanac.default_vedic VSOP87 analytical + Xalen Lahiri','positions':positions,'maximum_absolute_longitude_delta_deg':max(abs(v['longitude_delta_deg']) for v in positions.values()),'varga_difference_count':varga_diffs,'ashtakavarga_difference_count':av_diffs,'shadbala_total_delta_virupas':shad,'boundary':'Independent mode recomputes seven planetary longitudes/speeds; house numbers remain shared input.'}
|
||||
|
||||
def main()->int:
|
||||
p=argparse.ArgumentParser(description=__doc__);p.add_argument('--shared',type=Path,default=Path('references/oracle/artifacts/xalen_steve_jobs_high_rigor_raw.json'));p.add_argument('--independent',type=Path,default=Path('references/oracle/artifacts/xalen_steve_jobs_independent_ephemeris_raw.json'));p.add_argument('--output',type=Path,required=True);a=p.parse_args();r=compare(a.shared,a.independent);a.output.parent.mkdir(parents=True,exist_ok=True);a.output.write_text(json.dumps(r,ensure_ascii=False,indent=2,sort_keys=True)+'\n',encoding='utf-8');print(json.dumps({'max_delta':r['maximum_absolute_longitude_delta_deg'],'varga_diffs':r['varga_difference_count']},sort_keys=True));return 0
|
||||
if __name__=='__main__':raise SystemExit(main())
|
||||
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Run the pinned Apache-2.0 Xalen oracle probe and preserve raw JSON."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
MANIFEST = ROOT / "benchmarks/xalen_oracle/Cargo.toml"
|
||||
COMMIT = "cc6edbec1f748ebdc4950ae6198f575c5ada73fa"
|
||||
|
||||
|
||||
def run_probe(payload: dict) -> dict:
|
||||
completed = subprocess.run(
|
||||
["cargo", "run", "--quiet", "--locked", "--manifest-path", str(MANIFEST)],
|
||||
input=json.dumps(payload), text=True, capture_output=True, timeout=300, check=False,
|
||||
)
|
||||
if completed.returncode != 0:
|
||||
raise RuntimeError(completed.stderr.strip() or "xalen probe failed")
|
||||
raw = json.loads(completed.stdout)
|
||||
return {
|
||||
"status": "raw_verified",
|
||||
"engine": "xalen-ephemeris",
|
||||
"source_commit": COMMIT,
|
||||
"license": "Apache-2.0",
|
||||
"raw": raw,
|
||||
"boundary": "Fourth observation only; no majority-vote truth promotion.",
|
||||
}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("input", type=Path)
|
||||
parser.add_argument("--mode", choices=["shared_input", "independent_ephemeris"], default="shared_input")
|
||||
parser.add_argument("--output", type=Path)
|
||||
args = parser.parse_args()
|
||||
payload = json.loads(args.input.read_text(encoding="utf-8"))
|
||||
payload["mode"] = args.mode
|
||||
report = run_probe(payload)
|
||||
text = json.dumps(report, ensure_ascii=False, indent=2, sort_keys=True) + "\n"
|
||||
if args.output:
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.output.write_text(text, encoding="utf-8")
|
||||
print(text, end="")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Add pinned Xalen observations to the existing field-level parity rows."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from collections import Counter
|
||||
from pathlib import Path
|
||||
|
||||
RASHI = {"Mesha":"Aries","Vrishabha":"Taurus","Mithuna":"Gemini","Karka":"Cancer","Simha":"Leo","Kanya":"Virgo","Tula":"Libra","Vrishchika":"Scorpio","Dhanu":"Sagittarius","Makara":"Capricorn","Kumbha":"Aquarius","Meena":"Pisces"}
|
||||
COMPONENT = {"sthana":"sthana", "kala":"kala", "dig":"dig", "chesta":"chesta", "naisargika":"naisargika", "drik":"drik"}
|
||||
|
||||
|
||||
def _xalen_value(row: dict, raw: dict):
|
||||
section, field = row["section"], row["field"]
|
||||
if section in {"D1", "D2", "D4", "D9", "D10"}:
|
||||
planet = field.split(".", 1)[0]
|
||||
return RASHI[raw["varga"][section][planet]]
|
||||
if section == "ashtakavarga_bav":
|
||||
return raw["ashtakavarga"]["bav"][field]
|
||||
if section == "ashtakavarga_sav":
|
||||
return raw["ashtakavarga"]["sav"]
|
||||
if section == "shadbala_components":
|
||||
planet, component = field.split(".", 1)
|
||||
return raw["shadbala"][planet][COMPONENT[component]]
|
||||
if section == "shadbala_total":
|
||||
return raw["shadbala"][field]["total"]
|
||||
return None
|
||||
|
||||
|
||||
def compare(manifest_path: Path, xalen_path: Path) -> dict:
|
||||
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
||||
envelope = json.loads(xalen_path.read_text(encoding="utf-8"))
|
||||
raw = envelope["raw"]
|
||||
rows, counts = [], Counter()
|
||||
for source in manifest["comparison_rows"]:
|
||||
value = _xalen_value(source, raw)
|
||||
if value is None:
|
||||
continue
|
||||
local = source["local_value"]
|
||||
if isinstance(local, (int, float)) and isinstance(value, (int, float)):
|
||||
matched = abs(float(local) - float(value)) <= 0.05
|
||||
else:
|
||||
matched = local == value
|
||||
status = "match" if matched else "mismatch"
|
||||
counts[status] += 1
|
||||
rows.append({"section":source["section"],"field":source["field"],"local_value":local,"xalen_value":value,"status":status})
|
||||
return {"scope":"xalen_fourth_oracle_comparison","source_commit":envelope["source_commit"],"license":envelope["license"],"truth_policy":"fourth_observation_not_truth","row_count":len(rows),"match_count":counts["match"],"mismatch_count":counts["mismatch"],"rows":rows}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
p=argparse.ArgumentParser(description=__doc__); p.add_argument("--manifest",type=Path,default=Path("references/oracle/three_engine_parity_replay_manifest.json")); p.add_argument("--xalen",type=Path,default=Path("references/oracle/artifacts/xalen_steve_jobs_high_rigor_raw.json")); p.add_argument("--output",type=Path); a=p.parse_args()
|
||||
report=compare(a.manifest,a.xalen); text=json.dumps(report,ensure_ascii=False,indent=2,sort_keys=True)+"\n"
|
||||
if a.output: a.output.parent.mkdir(parents=True,exist_ok=True); a.output.write_text(text,encoding="utf-8")
|
||||
print(text,end=""); return 0
|
||||
|
||||
|
||||
if __name__ == "__main__": raise SystemExit(main())
|
||||
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Replay pinned Xalen shared-input formulas across public AA birth cases."""
|
||||
|
||||
from __future__ import annotations
|
||||
import argparse,hashlib,json,subprocess,sys
|
||||
from pathlib import Path
|
||||
from scripts.xalen_oracle_adapter import run_probe
|
||||
|
||||
ROOT=Path(__file__).resolve().parents[1]; SIGNS=['Aries','Taurus','Gemini','Cancer','Leo','Virgo','Libra','Scorpio','Sagittarius','Capricorn','Aquarius','Pisces']; PLANETS=['Sun','Moon','Mars','Mercury','Jupiter','Venus','Saturn']
|
||||
|
||||
def chart_input(subject:dict)->dict:
|
||||
cmd=[sys.executable,'scripts/jyotish_engine.py','chart']
|
||||
for key in ('year','month','day','hour','minute','lat','lon','tz'):cmd += [f'--{key}',str(subject[key])]
|
||||
cmd += ['--ayanamsa','lahiri','--node-mode','mean']
|
||||
done=subprocess.run(cmd,cwd=ROOT,text=True,capture_output=True,timeout=60,check=False)
|
||||
if done.returncode:raise RuntimeError(done.stderr)
|
||||
chart=json.loads(done.stdout);birth=chart['birth_info'];planets=[]
|
||||
for name in PLANETS:
|
||||
p=chart['planets'][name];planets.append({'name':name,'longitude':p['lon'],'speed':p['speed'],'house':p['house']})
|
||||
return {'jd':birth['julian_day'],'day_fraction':(subject['hour']+subject['minute']/60)/24,'asc_sign_idx':SIGNS.index(chart['ascendant']['sign']),'planets':planets}
|
||||
|
||||
def run_batch(manifests:list[Path],limit:int=5,mode:str='shared_input')->dict:
|
||||
cases=[]
|
||||
for path in manifests:
|
||||
for case in json.loads(path.read_text(encoding='utf-8')).get('cases') or []:
|
||||
subject=case['subject'];source=subject.get('birth_source') or {}
|
||||
if source.get('time_accuracy_rating')!='AA' or any(c['case_id']==case['case_id'] for c in cases):continue
|
||||
payload=chart_input(subject);payload['mode']=mode;probe=run_probe(payload);raw=probe['raw'];digest=hashlib.sha256(json.dumps(raw,sort_keys=True,separators=(',',':')).encode()).hexdigest()
|
||||
cases.append({'case_id':case['case_id'],'name':subject['name'],'birth_source':source,'input_mode':mode,'input':payload,'xalen_raw':raw,'raw_sha256':digest})
|
||||
if len(cases)>=limit:break
|
||||
if len(cases)>=limit:break
|
||||
return {'scope':'xalen_multi_public_case_replay','mode':mode,'case_count':len(cases),'source_commit':'cc6edbec1f748ebdc4950ae6198f575c5ada73fa','license':'Apache-2.0','cases':cases,'boundary':'Shared mode isolates formulas; independent mode recomputes seven-planet ephemeris while retaining shared houses.'}
|
||||
|
||||
def main()->int:
|
||||
p=argparse.ArgumentParser(description=__doc__);p.add_argument('--limit',type=int,default=5);p.add_argument('--mode',choices=['shared_input','independent_ephemeris'],default='shared_input');p.add_argument('--output',type=Path,required=True);a=p.parse_args();r=run_batch([ROOT/'references/real_case_calibration/replay_manifest.json',ROOT/'references/real_case_calibration/replay_manifest_probe3_v2.json'],a.limit,a.mode);a.output.parent.mkdir(parents=True,exist_ok=True);a.output.write_text(json.dumps(r,ensure_ascii=False,indent=2,sort_keys=True)+'\n',encoding='utf-8');print(json.dumps({'case_count':r['case_count'],'mode':r['mode']},sort_keys=True));return 0
|
||||
if __name__=='__main__':raise SystemExit(main())
|
||||
Reference in New Issue
Block a user