Files
Jyotisha/scripts/xalen_public_case_batch.py
T
2026-07-17 22:19:09 +08:00

37 lines
3.0 KiB
Python

#!/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())