1"""WP30 command-line interface. Every subcommand returns a meaningful exit code."""2from __future__ import annotations3import argparse, sys45def main(argv=None):6 ap = argparse.ArgumentParser(prog="wp30")7 sub = ap.add_subparsers(dest="cmd", required=True)8 p = sub.add_parser("doctor"); p.add_argument("--output", default="evidence/environment.json")9 p = sub.add_parser("sources"); p.add_argument("action", choices=["audit"]); p.add_argument("--config", default="configs/literature.yaml")10 p = sub.add_parser("data"); p.add_argument("action", choices=["prepare", "validate"]); p.add_argument("--config", default="configs/data.yaml"); p.add_argument("--manifest", default="data/manifests/splits.json")11 p = sub.add_parser("models"); p.add_argument("action", choices=["probe"]); p.add_argument("--config", default="configs/models.yaml")12 p = sub.add_parser("validate-cache"); p.add_argument("--config", default="configs/cache_validation.yaml")13 p = sub.add_parser("plan"); p.add_argument("--config", required=True); p.add_argument("--output", required=True)14 p = sub.add_parser("run"); p.add_argument("--config", required=True); p.add_argument("--resume", action="store_true"); p.add_argument("--limit", type=int, default=None); p.add_argument("--dry-run", action="store_true")15 p = sub.add_parser("protocol"); p.add_argument("action", choices=["freeze"]); p.add_argument("--config", required=True)16 p = sub.add_parser("analyze"); p.add_argument("--protocol", default="protocol/frozen.json")17 p = sub.add_parser("report"); p.add_argument("--protocol", default="protocol/frozen.json")18 p = sub.add_parser("reproduce"); p.add_argument("--profile", default="reproduction/minimal.yaml")19 p = sub.add_parser("audit-artifacts"); p.add_argument("--root", default=".")20 p = sub.add_parser("train-mapper"); p.add_argument("--config", default="configs/mapper.yaml")21 p = sub.add_parser("worker"); p.add_argument("--port", type=int, default=9430); p.add_argument("--model", required=True)22 a = ap.parse_args(argv)23 if a.cmd == "doctor":24 from .doctor import main as f; return f(a.output)25 if a.cmd == "sources":26 from .literature import audit; return audit(a.config)27 if a.cmd == "data":28 from .data.prepare import prepare, validate29 return prepare(a.config) if a.action == "prepare" else validate(a.manifest)30 if a.cmd == "models":31 from .models_probe import probe; return probe(a.config)32 if a.cmd == "validate-cache":33 from .validate_cache import main as f; return f(a.config)34 if a.cmd == "plan":35 from .runner import plan; return plan(a.config, a.output)36 if a.cmd == "run":37 from .runner import run; return run(a.config, resume=a.resume, limit=a.limit, dry_run=a.dry_run)38 if a.cmd == "protocol":39 from .protocol import freeze; return freeze(a.config)40 if a.cmd == "analyze":41 from .analysis.analyze import main as f; return f(a.protocol)42 if a.cmd == "report":43 from .analysis.report import main as f; return f(a.protocol)44 if a.cmd == "reproduce":45 from .reproduce import main as f; return f(a.profile)46 if a.cmd == "audit-artifacts":47 from .audit import main as f; return f(a.root)48 if a.cmd == "train-mapper":49 from .mapper import train_main; return train_main(a.config)50 if a.cmd == "worker":51 from .transport import serve; return serve(a.port, a.model)52 return 25354if __name__ == "__main__":55 sys.exit(main())56