#!/usr/bin/env python3
"""Public wrapper around the unchanged, frozen two-stage runner."""
import argparse,json,subprocess,sys
from pathlib import Path
p=argparse.ArgumentParser(description='MagicPart: 2-way hypergraph partitioning, cut objective. Requires Python 3.9+.')
p.add_argument('--input',type=Path,required=True);p.add_argument('--imbalance',type=int,choices=[2,10],required=True);p.add_argument('--seed',type=int,default=1);p.add_argument('--output',type=Path,required=True)
a=p.parse_args();root=Path(__file__).resolve().parents[1]
if a.seed<1:p.error('--seed must be positive')
if a.output.exists():p.error('--output must be a new directory; existing results are never overwritten')
cmd=[sys.executable,str(root/'tools/run_recipe.py'),'diffusion_ritz_full_lazy_sigmoid_ritzsubspace8_noinvlam_rawdist','--graph',str(a.input.resolve()),'--epsilon',str(a.imbalance/100),'--seed',str(a.seed),'--output',str(a.output.resolve()),'--bin',str(root/'libexec/magicpart-core'),'--record-infeasible']
r=subprocess.run(cmd)
if r.returncode:sys.exit(r.returncode)
s=json.loads((a.output/'run_summary.json').read_text())
weights=s['stage2']['block_weights'];total=sum(weights)
if not s['final_paper_balance_ok'] or not all((50-a.imbalance)*total<=100*w<=(50+a.imbalance)*total for w in weights):
 print('Final partition fails strict paper balance. Outputs are preserved; this candidate cannot be used.',file=sys.stderr);sys.exit(2)
print('Valid final partition:',a.output/'final.part.2')
