Skip to main content

autoqec-run

Run the AutoQEC research loop on a given env YAML. Orchestrates the autoqec-ideator / autoqec-coder / autoqec-analyst subagents via the Agent tool, invokes the Runner CLI for training + evaluation, and writes history.jsonl + pareto.json. Use when the user asks "run AutoQEC on <env>", "start a research round", or provides an EnvSpec YAML.

Informations de source

Dépôt
qualit527/qec-ai-decoder
Dernière activité de la source
24 avril 2026 à 11:56
Langue détectée de SKILL.md
anglais
Étoiles
3
Forks
0

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
autoqec-run
description
Run the AutoQEC research loop on a given env YAML. Orchestrates the autoqec-ideator / autoqec-coder / autoqec-analyst subagents via the Agent tool, invokes the Runner CLI for training + evaluation, and writes history.jsonl + pareto.json. Use when the user asks "run AutoQEC on <env>", "start a research round", or provides an EnvSpec YAML.
# /autoqec-run One-shot orchestration recipe for Claude Code chat. The orchestrator (you) drives the loop; three `autoqec-{ideator,coder,analyst}` subagents live behind the `Agent` tool. All shell commands below are written as `python -c "..."` one-liners so the recipe is identical on PowerShell (Windows) and bash / zsh (macOS / Linux). The helpers resolve every path relative to the repo root via `_REPO_ROOT = Path(__file__).resolve().parents[...]` — no cwd assumptions. ## When to use - The user says "run AutoQEC", "start a research round", or provides an env YAML path. - The user wants to see an AI-generated predecoder candidate on an existing env (surface_d5_depol, bb72_depol, etc.). ## Required inputs - `env_yaml` — path to an EnvSpec YAML (e.g. `autoqec/envs/builtin/surface_d5_depol.yaml`). - `rounds` — default `1`. Each round is Ideator → Coder → Runner → Analyst and takes ~2–5 min in dev profile. - `profile` — `dev` (2048 train / 2048 val shots, 3 epochs) or `prod` (8192 train / 8192 val shots, 10 epochs). Val shots matter more than train shots here because Δ_LER stderr scales as 1/√n_val — undersized val makes every round statistically indistinguishable from zero. Default `dev`. ## Default output_mode **Always default to `output_mode: soft_priors`** unless the user or the Ideator's hypothesis explicitly asks for `hard_flip`. `soft_priors` is the only mode with a well-posed supervised training target (DEM-error labels) and a working eval path on both MWPM (per-sample DEM reweighting) and OSD (priors passed to `bposd_decoder`). `hard_flip` is still supported but treats the raw syndrome as a weak surrogate target during training — it will not reliably move `delta_ler` without a problem-specific loss. If you find yourself emitting a DSL with `output_mode: hard_flip` without an explicit Ideator rationale, stop and check. ## Working scratch directory Use Python `tempfile.gettempdir()` when you need to stash intermediate subagent responses. Never hard-code `/tmp/...`. ```bash python -c "import tempfile,os; print(os.path.join(tempfile.gettempdir(), 'autoqec-run'))" ``` Create it once per run; the steps below refer to it as `<SCRATCH>`. ## The loop (per round) Do these steps in order. If any step fails, halt and report the failure to the user — do not silently skip. ### 1. Prepare the run + round directory Pick a run id (UTC `YYYYMMDD-HHMMSS`) if the user did not supply one. All subsequent paths live under `runs/<run_id>/`. Initialise memory **and** the orchestrator trace via the Python helpers — do NOT write `history.jsonl` / `pareto.json` / `log.md` / `orchestrator_trace.md` by hand: ```bash python -c " from autoqec.orchestration.memory import RunMemory from autoqec.orchestration.trace import init_trace RunMemory('runs/<run_id>') init_trace('runs/<run_id>', env_yaml='<env_yaml>', rounds=<N_TOTAL>, profile='<profile>') print('runs/<run_id>') " ``` `init_trace` is called **once per run** (before round 1). If `orchestrator_trace.md` already exists (resuming a killed run), it appends a `_resumed at ..._` divider instead of truncating. Every later step in this SKILL appends sections to that file via `append_section` / `append_note` so you get a chat-level narrative next to `history.jsonl`. ### 2. Build the Ideator prompt ```bash python scripts/run_single_round.py --env-yaml <env_yaml> --run-dir runs/<run_id> --round-idx <N> ``` Capture stdout into a JSON variable (the whole plan dict). The `ideator_prompt` key inside is the string to hand to the subagent. ### 3. Dispatch the Ideator Use the `Agent` tool with `subagent_type="autoqec-ideator"` and pass the `ideator_prompt` verbatim. The subagent returns exactly one fenced ```json block. Validate + parse **and trace** via: ```bash python -c " import sys, json from autoqec.agents.dispatch import parse_response from autoqec.orchestration.trace import append_note, append_section raw = sys.stdin.read() append_section('runs/<run_id>', <N>, 'ideator prompt', <IDEATOR_PROMPT>) append_note('runs/<run_id>', <N>, 'dispatched autoqec-ideator') append_section('runs/<run_id>', <N>, 'ideator raw', raw) parsed = parse_response('ideator', raw) append_section('runs/<run_id>', <N>, 'ideator parsed', parsed) print(json.dumps(parsed)) " ``` Pipe the subagent's raw response on stdin. Required keys (validated automatically by `parse_response`): `hypothesis`, `expected_delta_ler`, `expected_cost_s`, `rationale`. Optional: `dsl_hint`. If `parse_response` raises `ValueError: Invalid ideator response payload:`, the response is malformed — re-dispatch once with the pydantic error appended to the prompt, then give up if it fails again. ### 4. Build the Coder prompt ```bash python -c " import json, sys from pathlib import Path from autoqec.orchestration.memory import RunMemory from autoqec.orchestration.loop import build_coder_prompt hypothesis = json.loads(sys.stdin.read()) mem = RunMemory('runs/<run_id>') schema_md = Path('autoqec/decoders/dsl_schema.py').read_text(encoding='utf-8') print(build_coder_prompt(hypothesis=hypothesis, mem=mem, dsl_schema_md=schema_md)) " ``` Pipe the parsed Ideator JSON on stdin. ### 5. Dispatch the Coder `Agent` tool with `subagent_type="autoqec-coder"`. Required response keys (validated by `parse_response`): `tier`, `dsl_config`, `rationale`. `tier` is `"1"` or `"2"`. Double-check `dsl_config` against `PredecoderDSL` **and trace**: ```bash python -c " import json, sys from autoqec.agents.dispatch import parse_response from autoqec.decoders.dsl_schema import PredecoderDSL from autoqec.orchestration.trace import append_note, append_section raw = sys.stdin.read() append_section('runs/<run_id>', <N>, 'coder prompt', <CODER_PROMPT>) append_note('runs/<run_id>', <N>, 'dispatched autoqec-coder') append_section('runs/<run_id>', <N>, 'coder raw', raw) parsed = parse_response('coder', raw) PredecoderDSL(**parsed['dsl_config']) # raises on schema drift append_section('runs/<run_id>', <N>, 'coder parsed', parsed) print(json.dumps(parsed)) " ``` If validation fails, re-dispatch once with the pydantic error as feedback. Give up after one retry. ## Fork-from decision (§15.2) After the Ideator responds, read its `fork_from` field: | `fork_from` value | Action | |---|---| | `"baseline"` | Call `create_round_worktree(repo_root, run_id, N, slug, fork_from="main")`. | | `"exp/<run_id>/<M>-<slug>"` (string) | Call `create_round_worktree(..., fork_from=<that branch name>)`. | | list of ≥2 branch names | **Compose round**: call `create_compose_worktree(repo_root, run_id, N, slug, parents=<list>)`. If it returns `status="compose_conflict"`: write a `history.jsonl` row via `record_round` with `status=compose_conflict`, `round_attempt_id=<UUID>`, `conflicting_files=<list>`, and skip to the next round (no Runner invocation). | Mint `round_attempt_id` as `str(uuid.uuid4())` **before** calling the Ideator prompt is assembled, and pass it through every subsequent call (Coder prompt, Runner subprocess, Analyst prompt, record_round). ## Runner invocation (worktree path) Use `subprocess_runner.run_round_in_subprocess(cfg, env, round_attempt_id=<uuid>)` with: - `cfg.code_cwd = <worktree_dir>` (from the worktree plan dict) - `cfg.branch = <branch>` (from the plan) - `cfg.fork_from = <Ideator's fork_from value>` - `cfg.compose_mode = <Ideator's compose_mode>` (only for compose rounds) On success (metrics.status == "ok"), the subprocess has already committed the pointer file in the worktree. Proceed to Analyst dispatch. On `status=compose_conflict` or any non-ok status, call `cleanup_round_worktree` (removes the checkout; branch persists unless it was a compose_conflict, in which case `create_compose_worktree` already deleted the branch). ### 6. Write `round_<N>/config.yaml` and invoke the Runner ```bash python -c " import json, sys, yaml from pathlib import Path from autoqec.orchestration.trace import append_note, append_section parsed = json.loads(sys.stdin.read()) out = Path('runs/<run_id>/round_<N>') out.mkdir(parents=True, exist_ok=True) cfg_path = out / 'config.yaml' with cfg_path.open('w', encoding='utf-8') as f: yaml.safe_dump(parsed['dsl_config'], f, sort_keys=False) append_section('runs/<run_id>', <N>, 'config.yaml', cfg_path.read_text(encoding='utf-8'), fence='yaml') append_note('runs/<run_id>', <N>, 'invoking Runner (profile=<profile>)') " python -m cli.autoqec run-round <env_yaml> runs/<run_id>/round_<N>/config.yaml runs/<run_id>/round_<N> --profile <profile> ``` The CLI prints the `RoundMetrics` JSON on stdout. Save it — you also need it for the Analyst. Trace the metrics dict before moving on: ```bash python -c " import json, sys from autoqec.orchestration.trace import append_section metrics = json.loads(sys.stdin.read()) append_section('runs/<run_id>', <N>, 'runner metrics', metrics) " ``` **If `metrics.status != "ok"`**, skip the Analyst and the verifier for this round. Do not call `build_analyst_prompt`, do not dispatch the `autoqec-analyst` subagent, and do not run `independent_verify`. Call `record_round()` at step 10 with only `round_metrics=<metrics>` (omit `verify_verdict` and `verify_report`); the recorder synthesises a fallback summary from `metrics.status` / `status_reason`. ### 7. Build the Analyst prompt (only if `metrics.status == "ok"`) ```bash python -c " from autoqec.orchestration.memory import RunMemory from autoqec.orchestration.loop import build_analyst_prompt mem = RunMemory('runs/<run_id>') print(build_analyst_prompt(mem=mem, round_dir='runs/<run_id>/round_<N>', prev_summary='<prev or empty>')) " ``` ### 8. Dispatch the Analyst `Agent` tool with `subagent_type="autoqec-analyst"`. Required response keys (validated): `summary_1line`, `verdict` (`"candidate"` or `"ignore"`), `next_hypothesis_seed`. After receiving the raw response, validate **and trace**: ```bash python -c " import json, sys from autoqec.agents.dispatch import parse_response from autoqec.orchestration.trace import append_note, append_section raw = sys.stdin.read() append_section('runs/<run_id>', <N>, 'analyst prompt', <ANALYST_PROMPT>) append_note('runs/<run_id>', <N>, 'dispatched autoqec-analyst') append_section('runs/<run_id>', <N>, 'analyst raw', raw) parsed = parse_response('analyst', raw) append_section('runs/<run_id>', <N>, 'analyst parsed', parsed) print(json.dumps(parsed)) " ``` ### 9. Run the independent verifier (automatic) If `metrics.status == "ok"` AND the Analyst verdict is `candidate`: ```python from pathlib import Path from autoqec.envs.schema import load_env_yaml from autoqec.eval.independent_eval import independent_verify from autoqec.orchestration.trace import append_note, append_section append_note("runs/<run_id>", <N>, "running independent verifier") env = load_env_yaml("<ENV_YAML_PATH>") sp = env.noise.seed_policy holdout = list(range(sp.holdout[0], sp.holdout[1] + 1))[:50] report = independent_verify( checkpoint=Path("<ROUND_DIR>/checkpoint.pt"), env_spec=env, holdout_seeds=holdout, ) Path("<ROUND_DIR>/verification_report.json").write_text( report.model_dump_json(indent=2), encoding="utf-8", ) verify_verdict = report.verdict # pass into record_round verify_report = report.model_dump() # ditto append_section("runs/<run_id>", <N>, "verifier report", verify_report) ```
Voir sur GitHub
Ce SKILL.md est tres volumineux, SkillsMP affiche donc ici seulement la premiere section. Voir sur GitHub