[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M71RH59GF6HW0FREC73FZ1H1":3,"skill-same:01M71RH59GF6HW0FREC73FZ1H1":188},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":39,"linkOnly":40,"markdownContent":41,"markdownBody":42,"frontMatter":43,"refName":44,"commitSha":45,"skillDirectory":46,"forksCount":47,"repositoryHtmlUrl":48,"repositoryHomepageUrl":6,"ownerHtmlUrl":49,"ownerBlogUrl":6,"ownerDescription":50,"updatedAt":51,"install":52,"resources":65},"01M71RH59GF6HW0FREC73FZ1H1","autospec-run",null,"Use when the user has already run \u002Fautospec-define (or otherwise has a populated set of auto-implement GitHub issues) and wants the implementation half — Phases 4-6 — to run autonomously with admin auto-merge. Supports --profile \u003Cname> filtering against ~\u002F.autospec\u002Fmodel-profiles.yml.","berlinguyinca\u002Fautospec","berlinguyinca","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F16364?v=4","01M71R7C0SWBG05FNHQE4XQ7Y3","Gert Wohlgemuth","01M71R7C1VY5K3Q715RNDDBVGQ",3,"MIT","https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"autospec","autospec run","run","implementation","name","github","admin","with","implement","use","define","filtering","profiles","github issues","merge","when","auto","issues","model","SET","2026-11-10 13:02:02",false,"---\nname: autospec-run\ndescription: Use when the user has already run \u002Fautospec-define (or otherwise has a populated set of auto-implement GitHub issues) and wants the implementation half — Phases 4-6 — to run autonomously with admin auto-merge. Supports --profile \u003Cname> filtering against ~\u002F.autospec\u002Fmodel-profiles.yml.\n---\n\n# autospec-run workflow (harness-neutral)\n\nTake the populated `auto-implement` queue on the current GitHub repo and run the implementation half of the autospec pipeline:\n**autonomous monitor → admin-squash-merge each PR → periodic status updates → final report.**\n\nManage your own context — never exceed 60%. Delegate to subagents whenever your harness supports it; do not investigate, write code, or design directly in the main conversation when a subagent can do it.\n\nAutospec-run is an autonomous loop and should not ask operator questions for normal operations. Only surface a question if a hard blocker requires explicit manual recovery.\n\n\u003C!-- autospec-block:startup-self-update SKILL_NAME=autospec-run -->\n\n## Self-update mode\n\nDecide this purely from the request text the harness handed you. Do NOT\nshell out (no `grep`, `sed`, `[[ =~ ]]`, command substitution, etc.) to\ntest the user's free-form request — passing it through a shell is what\nhistorically tripped harness permission engines (e.g. parse errors near\nbacktick\u002Fpipe characters in the user's prose). Read the request, normalize\nit in your reasoning (collapse whitespace, trim, lowercase), and if the result is\nexactly `update`, this skill enters self-update mode and does NOT run the\nnormal pipeline.\n\n1. **Detect harness** by checking which install path exists for this skill:\n   - Claude Code: `~\u002F.claude\u002Fskills\u002Fautospec-run\u002FSKILL.md`\n   - OpenCode:    `~\u002F.config\u002Fopencode\u002Fagent\u002Fautospec-run.md`\n   - Codex CLI:   `~\u002F.codex\u002Fprompts\u002Fautospec-run.md`\n2. **Re-install the full autospec suite from `main`** by piping the canonical installer:\n   ```bash\n   curl -fsSL https:\u002F\u002Fraw.githubusercontent.com\u002Fberlinguyinca\u002Fautospec\u002Fmain\u002Fbootstrap.sh | bash -s -- --skill all --harness all --update\n   ```\n   Run this one-liner once; it refreshes all autospec skills across all harnesses.\n3. **Show the diff** between the prior installed file(s) and the freshly fetched copy (e.g. `diff \u003C(cat \u003Cprior>) \u003C(curl -fsSL ...SKILL.md)` or the equivalent recorded by the installer).\n4. **Stop.** Do not enter Phase 0 \u002F Phase 1 \u002F any pipeline phase. Print the upgrade summary and return to the user.\n\nIf no install path is detected, print `Self-update: no installed copy of autospec-run found; run install.sh first.` and exit.\n\n## Stop mode\n\nApply the same read-and-normalize approach used for self-update mode (do\nNOT shell out the user's request). If the normalized request is exactly\n`stop`, or `stop` followed by one or more `--\u003Cword>` flags (examples:\n`stop`, `stop --graceful`, `stop --immediate`, `stop --status`,\n`stop --resume`, `stop --help`, `stop --flag`), this skill enters stop\nmode and does NOT run the normal pipeline. When dispatching, pass any\n`--\u003Cflag>` tokens the user provided as separate words to the helper.\n\n1. Dispatch to `bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-stop.sh\" \u003Cargs>`.\n2. Print the helper's stdout to the user.\n3. Stop. Do not enter Phase 0 or any pipeline phase.\n\n## Status mode\n\nApply the same read-and-normalize approach. If the normalized request is exactly\n`status` (or `status` followed by `--\u003Cword>` flags such as `--json` \u002F `--repo` \u002F\n`--stale-secs`), this skill enters status mode and does NOT run the pipeline — it\nprints a one-glance operator view of the live run (in-flight issues with step +\nage + branch + PR + STALE detection, the queue counts, and the stop-flag state)\ninstead of making the operator hand-parse heartbeat JSON.\n\n1. Dispatch to `bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-run-status.sh\" \u003Cargs>`.\n2. Print the helper's stdout to the user.\n3. Stop. Do not enter Phase 0 or any pipeline phase.\n\n## Invocation\n\n```\n\u002Fautospec-run [--profile \u003Cname>]\n```\n\n- `--profile \u003Cname>` — filter the candidate queue against `~\u002F.autospec\u002Fmodel-profiles.yml` so only issues whose `ctx:*` and `reasoning:*` labels fit the named profile are picked up. Issues that exceed the profile on either axis are appended to a `deferred[]` list and printed in the run-end summary.\n- (no flag) — load `~\u002F.autospec\u002Fmodel-profiles.yml`'s `default:` profile and run with it. If the file is missing, run auto-init (below) then exit so the user can review\u002Fedit before re-running.\n- `--profile \u003Cunknown>` — exit non-zero and print the list of available profile names from `~\u002F.autospec\u002Fmodel-profiles.yml`.\n- `--worker-id \u003Cid>` — override the distributed worker identity written to\n  GitHub run-state comments. Otherwise derive it from host, user, harness, pid,\n  and start timestamp.\n- `--coordination-status` — print active workers, claimed issues, blockers,\n  stale claims, conflicts, and the next safe batch, then exit without claiming.\n- `--max-parallel-safe` — print the next safe parallel batch from\n  `autospec queue ready` and exit without claiming.\n- `--claim \u003Cissue>` — attempt a deterministic claim via `autospec claim acquire`\n  and exit with that command's status (`0` claimed, `2` already claimed\u002Fskipped).\n- `--release \u003Cissue>` — release a distributed claim via `autospec claim release`.\n\n### Auto-init `~\u002F.autospec\u002Fmodel-profiles.yml`\n\nIf the file is missing on run start:\n\n**Dispatching to a local model.** A profile resolved to a local model is executed via\n`bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Flocal-dispatch.sh\" --model \u003Ctag>\n--prompt-file \u003Cpath>`, never by calling a runtime directly. It refuses (exit 3) when\nCodex CLI is absent or does not advertise `--oss`, when the capability probe reports the\nmodel is not `dispatch_recommended`, or when no wall-clock bound can be applied — on any\nrefusal, keep the cloud tier. The local GPU is capacity-1, so the helper serializes\ndispatches; never run two local dispatches concurrently.\n\n**Capping fan-out on a local model.** Serialization covers `local-dispatch.sh`; it does\nNOT cover subagents you spawn in this harness, which reach the same node as ordinary\nsessions. Children cost no VRAM — that is committed when the server starts — but each\nclaims a share of a fixed KV pool that has no admission control, so over-subscribing it\nfails every live session rather than the newest. Before any parallel dispatch whose\nchildren run on a local model, cap the width by what the pool funds:\n\n```bash\nW=$(context-budget-check.py --width \"$PLANNED\" --json 2>\u002Fdev\u002Fnull | jq -r .max_width)\n```\n\nUse `min($PLANNED, $W)`. `W \u003C= 1` means run the work inline. If the checker exits 2 —\nserver unreachable, client config unreadable — keep the cloud tier rather than guessing\na width; a wrong guess is not a slower run, it is a failed one for every session on that\nnode. See the capacity-gate section of AGENTS.md.\n\n1. **Discover local supply with the probe — never enumerate models yourself.**\n   ```bash\n   bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fdiscover-model-supply.sh\" --profiles\n   ```\n   Paste its `profiles:` fragment into the file verbatim. The probe measures each\n   model's real context length via `ollama show`, keeps only completion-capable\n   models, writes the original runtime tag as `model:`, and normalizes the profile\n   key (`qwen3:32b` → `qwen3-32b-laptop`).\n\n   Do **not** list models from memory, from the model names you happen to know, or\n   from an inferred parameter count. An earlier revision of this section asked the\n   orchestrator to do exactly that, and on a live host it produced nine local\n   profiles for four real models — including an unrunnable `qwen3-coder-480b` — and\n   rated every one of them `ctx: 64k` when the measured values were 131072 and\n   262144. Enumerating ground truth is the probe's job.\n\n   Read these fields off the probe rather than guessing:\n   - `accelerator.usable` \u002F `accelerator.reason` — a present `nvidia-smi` and a\n     present `\u002Fdev\u002Fnvidia0` do **not** mean a usable GPU. When `usable` is false,\n     surface `reason` to the operator (e.g. `nvml_driver_library_mismatch` is a\n     five-minute fix) instead of silently accepting CPU inference.\n   - `dispatch_recommended` per model — false means the probe found the model but\n     the host cannot run it usefully (no accelerator, or weights exceed the memory\n     budget). Leave those profiles commented out; the probe already does this.\n   - A model set that comes back empty (no `ollama`, daemon down, or zero\n     completion models) means **no local profiles**. Never synthesize one.\n2. If `ANTHROPIC_API_KEY` is set in the environment, append two cloud profiles:\n   `claude-sonnet-cloud` and `claude-opus-cloud`, both `ctx: 120k`,\n   `reasoning: deep`, each with its `model:` id. Also append `claude-haiku-cloud`\n   (`ctx: 64k`, `reasoning: medium`) — `select-model-profile.sh` routes\n   `reasoning:shallow|medium` issues to it, so omitting it silently disables the\n   cheap implementer tier.\n3. If neither Ollama nor `ANTHROPIC_API_KEY` is detected, write a single\n   `claude-sonnet-cloud` default with `ctx: 120k, reasoning: deep` and an\n   `# edit-and-rerun` comment near the top of the file.\n4. Set the top-level `default:` key to whichever profile makes sense (prefer\n   the largest local profile if any, otherwise `claude-sonnet-cloud`).\n5. Print:\n   ```\n   Wrote ~\u002F.autospec\u002Fmodel-profiles.yml. Edit `default:` and profile ceilings,\n   then re-run \u002Fautospec-run [--profile \u003Cname>].\n   ```\n   Exit 0; do not enter Phase 4.\n\nSample auto-init output:\n\n```yaml\n# ~\u002F.autospec\u002Fmodel-profiles.yml — autospec-run profile ceilings.\n# Edit `default:` and individual ceilings, then re-run.\ndefault: claude-sonnet-cloud\nprofiles:\n  qwen3-32b-laptop:\n    model: qwen3:32b   # original runtime tag — what a dispatch sends\n    ctx: 64k           # one of: 32k | 64k | 120k\n    reasoning: medium  # one of: shallow | medium | deep\n    roles: [implementer]  # local profiles serve the implementer only (Guardrail R2)\n  claude-haiku-cloud:\n    model: claude-haiku-4-5\n    ctx: 64k\n    reasoning: medium\n  claude-sonnet-cloud:\n    model: claude-sonnet-5\n    ctx: 120k\n    reasoning: deep\n```\n\n### Profile-filter ordinals\n\n- `ctx: 32k \u003C 64k \u003C 120k`\n- `reasoning: shallow \u003C medium \u003C deep`\n\nA profile P \"fits\" issue I when `I.ctx_label ≤ P.ctx` AND `I.reasoning_label ≤ P.reasoning` on these ordinals.\n\n---\n\n## Required capabilities & harness adapter\n\nThis workflow assumes five capabilities. Map each one to your harness's actual tool. If a capability is missing, use the listed fallback.\n\n| Capability                  | Claude Code                          | OpenCode                                 | Codex CLI                                | Fallback if missing                                |\n|-----------------------------|--------------------------------------|------------------------------------------|------------------------------------------|----------------------------------------------------|\n| Read-only codebase research | `Agent` (subagent_type=Explore)      | `task` agent in read-only mode           | `apply_patch` read-only \u002F shell `grep`   | Do the search in-thread with `rg`\u002F`grep`           |\n| Foreground delegation       | `Agent` (subagent_type=general-purpose) | nested `task` agent, await output     | spawn nested CLI session                 | Do the work in-thread (more context cost)          |\n| Background delegation       | `Agent` with `run_in_background: true` | detached `task` agent                  | nohup'd CLI session writing to a logfile | Run the monitor in a separate terminal\u002Ftmux pane   |\n| Ask the user a question     | `AskUserQuestion`                    | inline prompt                            | inline prompt                            | Ask in the response and wait for the next turn     |\n| Self-paced future wakeup    | `ScheduleWakeup` inside a `\u002Floop`    | a recurring `task` or local `cron`       | local `cron`\u002F`launchd` calling the CLI   | The user runs a status-update prompt manually      |\n| Subagent model tier         | Tier A: `opus` + `ultrathink`; Tier B: `sonnet` + medium thinking | Tier A: top `task` model + high reasoning; Tier B: smaller-tier `task` + medium reasoning | Tier A: top GPT + `reasoning_effort=high`; Tier B: current spark\u002Fcost-optimized Codex + `reasoning_effort=medium` | Honor the per-phase tier mapping in AGENTS.md; retry the same subagent UP on unavailability |\n| Local model dispatch        | not native — `Agent(model:)` takes Claude tiers only; shell out to `local-dispatch.sh` | provider pointed at `:11434\u002Fv1` (or `:8000` for vLLM) | `codex exec --oss --local-provider ollama` | cloud tier (fail closed) |\n\u003C!-- autospec-block:harness-adapter-core -->\n\n**Persistent project notes**: write durable preferences to **`AGENTS.md`** in the repo root — this is the de-facto standard recognized by Claude Code (also reads `CLAUDE.md`), OpenCode, and Codex. If your harness has its own private memory (e.g. Claude Code's `~\u002F.claude\u002F...\u002Fmemory\u002F`), mirror the same content there. Per AGENTS.md, subagent dispatches use a **two-tier policy**: Tier A (top model + extended thinking) for spec work (research, decompose, review\u002Flabel — not used by this skill); Tier B (cheaper model + medium thinking) for implementation work (Phase 4 implementer + LGTM review). The orchestrator keeps the user's invoked model. Fall back UP the tier on quota\u002Fcapacity or other unavailability by retrying the same subagent with the stronger tier while preserving parent context.\n\n## Harness detection (run once at skill start, before Phase 0)\n\nDetect your harness by checking available tools before any phase:\n\n1. **Claude Code** — the `Agent` tool with a `subagent_type` parameter is available.\n   - `TIER_A` = `opus` + `ultrathink`  (the alias, which resolves to the current Claude Opus generation)\n   - `TIER_B` = `sonnet`               (the alias, which resolves to the current Claude Sonnet generation)\n\n2. **OpenCode** — a `task` tool with model\u002Ftier configuration is available (no `subagent_type`).\n   - `TIER_A` = top-tier task model + high reasoning\n   - `TIER_B` = smaller-tier task model + medium reasoning\n\n3. **Codex CLI** — neither `Agent` nor a configurable `task` tool is available; `apply_patch` is the primary edit tool.\n   - `TIER_A` = current top GPT model + `reasoning_effort=high`\n   - `TIER_B` = the spark \u002F cost-optimized variant of the configured model when one exists, else the configured model + `reasoning_effort=medium`\n\n**Fallback rule:** If `TIER_B` is not available in your harness (model unknown, quota\u002Fcapacity failure, authorization failure, or tool call returns an error for that model), silently retry the same subagent dispatch with `TIER_A`. Preserve the parent context on retry by passing a bounded handoff containing the issue number, repo path, branch\u002Fworktree plan, relevant issue body sections, last error, and current queue\u002Fclaim state. Codex native subagents with explicit `agent_type`, `model`, or `reasoning_effort` MUST use a bounded handoff, not a full-history fork; do not ask Codex to inherit\u002Ffork the full parent conversation when those fields are set. If a role-specialized reviewer has a fixed model binding, retry through a fresh configurable independent agent at `TIER_A` with the identical reviewer prompt, evidence inputs, tool budget, and verdict schema. Never fall back to the author\u002Fmain lane or a weaker model. The orchestrator records the requested model, actual model, availability error class, and reviewed head SHA in a sidecar review artifact; never append metadata to the reviewer's byte-exact verdict channel. If no equal-or-stronger independent reviewer can run, fail closed and do not merge. Never ask the user.\n\n**Codex SpawnAgent call-shape contract:** Codex has two valid subagent call shapes. Use the bounded handoff when setting an explicit executor\u002Ftier route: `SpawnAgent({ prompt: bounded_handoff, agent_type: \"executor\", model: TIER_B, reasoning_effort: \"medium\" })`. Use a full-history fork only when inheriting the current conversation without explicit routing: `SpawnAgent({ prompt: full_history_prompt, full_history: true })`. Never combine `full_history: true` with `agent_type`, `model`, or `reasoning_effort`. On Codex dispatch failure, retry once with the other valid shape when that still satisfies the phase's tier rule; if both valid shapes fail, release the claimed issue back to `auto-implement` with a visible blocker comment.\n\nHold `TIER_A` and `TIER_B` for the entire skill run. Every \"Tier A\" and \"Tier B\" reference below resolves to these harness-specific values.\n\n## Relevant memory injection (run-start, once)\n\nBefore executing the main pipeline phases, call the injector to surface relevant saved lessons:\n\n```bash\nbash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Finject-relevant-memory.sh\" \\\n  --context \"\u003Cskill-relevant keywords from request\u002Fissue\u002Fspec>\" \\\n  --top-k 5\n```\n\nPrepend the output block (if non-empty) to your working context. This surfaces lessons like\n`feedback_bash_return_trap_leak.md` that prevent re-occurrence of known pitfalls.\n\n## Run-start batch timestamp (run-start, once)\n\nCapture the run-start instant so the end-of-run gap-remediation phase (Phase 5.5) can scope its review to work shipped during THIS run. Run exactly once, before the Phase 4 monitor launches:\n\n```bash\nbash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Frun-batch-start.sh\" --write\n```\n\nThis writes the UTC ISO 8601 timestamp to `~\u002F.autospec\u002F.run-batch-start` (idempotent within a run; pass `--force` only when intentionally starting a fresh batch window). Phase 5.5 reads it back via `run-batch-start.sh --read`, which yields `BATCH_START_DATE`.\n\n## Explore-on-drain counter reset (run-start, once)\n\nReset the per-repo explore-on-drain cycle counter so a fresh `\u002Fautospec-run` always starts with a clean slate (spec: \"counter resets when the operator clears it or starts a fresh `\u002Fautospec-run`\"). Run once, immediately after the batch-start timestamp above:\n\n```bash\n# Derive the canonical per-repo slug (owner__name) for state scoping.\n_eod_slug=\"$(gh repo view --json nameWithOwner -q .nameWithOwner 2>\u002Fdev\u002Fnull \\\n    | sed 's#\u002F#__#' \\\n    || printf '%s' \"$(git rev-parse --show-toplevel 2>\u002Fdev\u002Fnull || pwd)\" \\\n         | tr '\u002F' '_' | sed 's\u002F^_\u002F\u002F')\"\nrm -f \"$HOME\u002F.autospec\u002Fexplore-on-drain\u002F${_eod_slug}\u002Fcycles\"\n```\n\nThis ensures the cycle cap (`AUTOSPEC_EXPLORE_ON_DRAIN_MAX_CYCLES`, default 3) counts only chains within the current run, not across multiple historical runs. The `_eod_slug` variable is reused in the ALL_DONE block below.\n\n## Single-instance session lock (run-start, once)\n\nAcquire a per-session lock BEFORE launching the Phase 4 monitor so a single\nharness session never runs two concurrent monitors (which collide on the queue\nand on git branches). The lock is keyed by the harness session id, so separate\nsessions still run independently by design.\n\n```bash\nLOCK=\"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-run-session-lock.sh\"\nif ! bash \"$LOCK\" acquire --repo \"{repo}\"; then\n    # exit 3 = a monitor is already active in THIS session.\n    echo \"autospec-run: refusing to start a second monitor in this session.\" >&2\n    bash \"$LOCK\" status\n    # STOP — do NOT launch Phase 4. Halt the active monitor with \u002Fautospec-stop,\n    # or re-run the lock helper with --force to override a stale lock.\n    exit 0\nfi\n```\n\nRelease the lock on EVERY terminal exit of this run — the Phase 6 final report,\nthe `ALL_DONE` shutdown, and stop mode:\n\n```bash\nbash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-run-session-lock.sh\" release\n```\n\nThe lock is advisory and self-scoped: a crashed session's lock only blocks that\nsame session id (a fresh session gets a new id), and `--force` overrides it.\n\n## Phase 4 — Background autonomous monitor\n\n**Fresh-subagent-per-issue (canonical Phase 4 path, formerly single-agent absorbed-discipline).** Each issue is processed by a FRESH top-level subagent dispatched by the orchestrator — expand → implement → finalize → peer-review → evaluate-findings → PR → merge — in that subagent's own context. The orchestrator NEVER implements in its own context; it only claims, dispatches, and waits. Each subagent receives full tool access because it is a top-level `Agent` call launched directly by the main session orchestrator. **Constraint:** Subagents spawned by background `Agent` calls do NOT inherit the `Agent` tool, so nested monitors cannot dispatch inner implementers. Phase 4 implementers must be top-level agents launched directly by the main session orchestrator, not nested inside a monitor. The `process(ISSUE)` notation below is shorthand for \"dispatch a fresh top-level subagent to do this work\", NOT in-context implementation by the orchestrator. Batch>1 is an explicit operator opt-in via `AUTOSPEC_BATCH_SIZE=N`; the default is 1 (one issue per subagent). The `reasoning:deep` force-to-1 rule is retained: deep issues stay batch=1 even under an operator `AUTOSPEC_BATCH_SIZE=N` override.\n\nRecord this durable preference in `AGENTS.md` (idempotent — skip if already present):\n\n> **Auto-merge authority for auto-implement PRs.** Admin-merge auto-implement PRs (through `autospec-guarded-merge.sh`, never a bare `gh pr merge`) when (a) the full target-repo validation\u002Ftest suite has passed locally after the branch is current with `main`, (b) all **non-advisory** required CI checks pass — checks matching `AUTOSPEC_PR_ADVISORY_CHECKS` (default `AUTOSPEC_MAIN_HEALTH_IGNORE_CHECKS`; e.g. self-hosted TeamCity) are advisory and may be pending **or failing** once the full local suite is green, (c) the self-review subagent returned `LGTM`, (d) PR closes an `auto-implement` issue from a `feat\u002F*` branch.\n\n**Off-peak tip:** For queues of 10+ issues (8+ hour runs), consider launching at night or on weekends. Usage limits are shared across all sessions — running long batches off-peak preserves daytime tokens for interactive work.\n\n**Usage-limit recovery guard.** Before launching the monitor, determine the exact non-interactive command that can relaunch this same `\u002Fautospec-run` invocation in the current repo and store it in `AUTOSPEC_RESUME_COMMAND` if the harness has not already set one. This must be a real shell command, for example the same Claude Code, Codex CLI, OpenCode, tmux, or wrapper command the operator used to start the run with the same `--profile` and repo path. Do not ask the user for it during a running monitor.\n\n**Durable run registry (crash-resume).** At monitor launch, also persist that same relaunch command to the durable run registry so it survives a host\u002Fsession crash and reboot — the session env var `AUTOSPEC_RESUME_COMMAND` does not. Write it once per launch with the identical command:\n\n```bash\nREGISTRY=\"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-run-registry.sh\"\nif [ -f \"$REGISTRY\" ] && [ -n \"${AUTOSPEC_RESUME_COMMAND:-}\" ]; then\n  bash \"$REGISTRY\" write --repo \"$(gh repo view --json nameWithOwner --jq .nameWithOwner)\" \\\n    --repo-dir \"$(pwd)\" --harness \"\u003Cclaude|codex|opencode>\" --command \"$AUTOSPEC_RESUME_COMMAND\"\nfi\n```\n\n`\u002Fautospec-resume` reads `~\u002F.autospec\u002Factive-runs\u002F\u003Crepo-slug>.json` on a fresh start to relaunch this run. The registry is the only durable carrier of the relaunch command across reboot.\n\nWhen a harness reports a deterministic usage-limit\u002Fquota\u002Fcapacity pause with a known reset time or wait duration, do not spend tokens diagnosing the message. Immediately arm the shell supervisor and exit:\n\n```bash\nUSAGE_LIMIT=\"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-usage-limit.sh\"\nif [ -n \"${AUTOSPEC_USAGE_LIMIT_RESUME_AT:-}\" ]; then\n  bash \"$USAGE_LIMIT\" arm --harness \"\u003Cclaude|codex|opencode>\" --repo-dir \"$(pwd)\" \\\n    --command \"$AUTOSPEC_RESUME_COMMAND\" --resume-at \"$AUTOSPEC_USAGE_LIMIT_RESUME_AT\"\n  exit 0\nelif [ -n \"${AUTOSPEC_USAGE_LIMIT_WAIT_SECONDS:-}\" ]; then\n  bash \"$USAGE_LIMIT\" arm --harness \"\u003Cclaude|codex|opencode>\" --repo-dir \"$(pwd)\" \\\n    --command \"$AUTOSPEC_RESUME_COMMAND\" --wait-seconds \"$AUTOSPEC_USAGE_LIMIT_WAIT_SECONDS\"\n  exit 0\nfi\n```\n\nThe helper writes `~\u002F.autospec\u002Fusage-limits\u002F\u003Crun-id>.json`, starts a background daemon, polls every 300 seconds by default, and relaunches the recorded command after the reset time. This is intentionally shell-only so recovery does not require an LLM turn after the usage limit has already been hit.\n\nThen launch a **background monitor loop** — the orchestrator relaunches the monitor with fresh context after each batch of `AUTOSPEC_BATCH_SIZE` issues (default: 1). The monitor is stateless: all persistent state lives in GitHub labels and heartbeat files, so relaunches are always safe.\n\n**Codex Wait call-shape contract:** When awaiting a native Codex `wait_agent` call, omit `timeout_ms` or pass an integer greater than or equal to `10000`. Never pass `timeout_ms` below `10000`; the native router rejects it before the executor can report progress. Keep waiting through task notifications until the monitor reaches a terminal state.\n\n```\nbatch_num=1\nwhile true:\n  launch background subagent paused before its first claim (pass batch_num; AUTOSPEC_BATCH_SIZE=${AUTOSPEC_BATCH_SIZE:-1})\n  capture the returned ACTUAL_SESSION_ID and bind it into that child's durable session context as WAIT_TARGET_SESSION_ID\n  do not allow the child to claim work until it can pass that exact WAIT_TARGET_SESSION_ID to `autospec claim acquire --session-id`\n  wait for task-notification (monitor agent completes)\n\n  if Wait returns `write_stdin failed` with `stdin is closed`:\n    inspect durable agent\u002Fsession state once for a live recovery path\n    if the child is reported live:\n      attempt one harness reattach to the exact failed Wait target\n      if reattach succeeds: continue waiting for task-notification\n      explicitly terminate and reap the child through the harness process API\n      if termination and reap cannot be proven: stop without typed recovery or label mutation\n    require durable proof that the child exited or was terminated and reaped\n    use the actual session ID from the failed Wait target (never infer it from an environment variable)\n    read the immutable heartbeat binding for ACTUAL_SESSION_ID before inspecting any current claim state\n    BOUND_HEARTBEAT=\"$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fheartbeat-read.sh\" --repo {repo} --session-id \"\u003CACTUAL_SESSION_ID>\")\" or stop without typed recovery or label mutation\n    ISSUE=\"$(printf '%s' \"$BOUND_HEARTBEAT\" | jq -er '.issue | select((type == \"string\" and length > 0) or (type == \"number\" and . > 0)) | tostring')\" or stop\n    BRANCH=\"$(printf '%s' \"$BOUND_HEARTBEAT\" | jq -er '.branch | select(type == \"string\")')\" or stop\n    WORKER_ID=\"$(printf '%s' \"$BOUND_HEARTBEAT\" | jq -er '.worker_id | select(type == \"string\" and length > 0)')\" or stop\n    CLAIM_ID=\"$(printf '%s' \"$BOUND_HEARTBEAT\" | jq -er '.claim_id | select(type == \"string\" and length > 0)')\" or stop\n    if the binding is absent, malformed, or legacy\u002Funbound: stop without typed recovery or label mutation\n    never read CLAIM_ID from the currently active claim after Wait fails; a successor may already own the same issue, worker, and branch\n    run `\"${AUTOSPEC_BIN:-autospec}\" autonomous implementer-wait-failed --repo {repo} --issue \"\u003CISSUE>\" --worker-id \"\u003CWORKER_ID>\" --branch \"\u003CBRANCH>\" --claim-id \"\u003CCLAIM_ID>\" --session-id \"\u003CACTUAL_SESSION_ID>\" --diagnostic \"\u003CREDACTED_WAIT_ERROR>\"`\n    if typed recovery exits non-zero: log the surfaced recovery failure and stop processing that issue\n    never mutate labels inline or overwrite a successor claim\n    continue  # start a fresh monitor batch from the restored auto-implement queue\n\n  # Read and consume the batch-done signal.\n  if [ -f \"$HOME\u002F.autospec\u002Fbatch-done.json\" ]; then\n    status=$(jq -r .status \"$HOME\u002F.autospec\u002Fbatch-done.json\" 2>\u002Fdev\u002Fnull || echo \"BATCH_COMPLETE\")\n    rm -f \"$HOME\u002F.autospec\u002Fbatch-done.json\"\n  else\n    status=\"BATCH_COMPLETE\"   # monitor crashed \u002F overflowed — safe to relaunch\n  fi\n\n  if [ \"$status\" = \"ALL_DONE\" ]; then\n    # Queue drained — consult explore-on-drain.sh to decide whether to\n    # auto-chain into \u002Fautospec-explore or exit normally to Phase 6.\n    # The helper encapsulates: flag check → autonomy gate → dry-well guard\n    # → per-repo cycle-cap.  It emits \"chain\" or \"stop\"; default is \"stop\".\n    # Pass AUTOSPEC_REPO so the helper scopes state to this repo without\n    # calling gh a second time (uses the same slug as the run-start reset).\n    _drain_decision=$(AUTOSPEC_REPO=\"${AUTOSPEC_REPO:-{repo}}\" \\\n        bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fexplore-on-drain.sh\")\n    if [ \"$_drain_decision\" = \"chain\" ]; then\n      echo \"[orchestrator] explore-on-drain: chaining into \u002Fautospec-explore on sandbox branch\"\n      # Record the PR merge watermark before explore starts so we can count\n      # only the PRs it ships (used by the dry-well sentinel below).\n      _eod_before=\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"\n      \u002Fautospec-explore   # runs on its own sandbox branch, NEVER main\n      # Count PRs merged by this explore cycle and write the dry-well sentinel.\n      # explore-on-drain.sh reads this before the NEXT chain decision:\n      # if the count is 0 it emits \"stop\" (dry-well guard).\n      _eod_shipped=\"$(gh pr list --state merged \\\n          --json mergedAt,labels \\\n          --jq \"[.[] | select(.mergedAt >= \\\"${_eod_before}\\\" and any(.labels[]; .name == \\\"autospec-explore\\\"))] | length\" \\\n          2>\u002Fdev\u002Fnull || echo 1)\"\n      mkdir -p \"$HOME\u002F.autospec\u002Fexplore-on-drain\u002F${_eod_slug}\"\n      printf '%s\\n' \"${_eod_shipped}\" \\\n          > \"$HOME\u002F.autospec\u002Fexplore-on-drain\u002F${_eod_slug}\u002Flast-shipped\"\n    fi\n    break   # proceed to Phase 6 final report\n  fi\n\n  batch_num=$((batch_num + 1))\n  echo \"[orchestrator] batch $((batch_num - 1)) complete — relaunching monitor with fresh context (batch ${batch_num})\"\n  # continue immediately, no sleep\n```\n\n**Continuation contract:** BATCH_COMPLETE is a continuation signal, not a terminal state. reasoning:deep may reduce a single monitor batch to one issue, but the orchestrator MUST relaunch automatically until ALL_DONE. Never tell the operator to rerun `\u002Fautospec-run` after BATCH_COMPLETE; the current invocation owns the relaunch loop until the queue is empty or a hard blocker stops it.\n\nPass the following prompt verbatim to each background subagent:\n\n> You are the auto-implement monitor for `{repo}`. Process `auto-implement` issues one at a time. Exit after processing `AUTOSPEC_BATCH_SIZE` issues (default: 1) by writing `~\u002F.autospec\u002Fbatch-done.json` — the orchestrator will relaunch you with fresh context.\n\n> **Harness adaptation (loop persistence).** The `while true:` below is pseudocode. In Claude Code, use `\u002Floop` or `ScheduleWakeup` to persist across turns. In Codex CLI and OpenCode, you lack a built-in loop primitive — implement persistence via one of these patterns:\n> 1. **Shell wrapper (preferred):** `exec bash \u003C\u003C 'EOF'\n> while true; do\n>   # ... monitor logic ...\n> done\n> EOF` — keeps a single bash process alive with your agent dispatching subcommands inside it.\n> 2. **nohup background process:** `nohup bash -c 'while true; do ...; sleep 1; done' > ~\u002F.autospec\u002Fmonitor.log 2>&1 &`\n> 3. **tmux pane:** `tmux new-window 'bash \u003C\u003C '''HEREDOC'''\n> while true; do ...; done\n> HEREDOC'`\n> **Session batching:** Exit after processing `AUTOSPEC_BATCH_SIZE` issues (default 1) by writing `~\u002F.autospec\u002Fbatch-done.json` with `status=BATCH_COMPLETE`. BATCH_COMPLETE is a continuation signal, not a terminal state; the orchestrator relaunches you with fresh context. When the queue is fully drained, write `status=ALL_DONE` instead. This keeps each monitor session short to prevent context overflow.\n\n>\n> **Profile load (run-start, once).** If `--profile \u003Cname>` was passed, look it up in `~\u002F.autospec\u002Fmodel-profiles.yml`; if `\u003Cname>` is not a key under `profiles:`, exit non-zero and print the available names. If no flag was passed, load the file's `default:` profile. If the file is missing, run auto-init and exit (per the Invocation section).\n>\n> **Missing-label warning (run-start, once).** Count open `auto-implement` issues that lack either a `ctx:*` or a `reasoning:*` label. If non-zero, print `WARN: N issues lack model-fit labels (ctx:* \u002F reasoning:*); they will be treated as ctx:64k, reasoning:medium. Run \u002Fautospec-classify to backfill.` Exactly once at run start.\n>\n> **Shared helper scripts.** Helper scripts live at `${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}` after installation. Do not assume the target repository has an autospec `scripts\u002F` directory.\n>\n> Outer loop:\n> ```\n> # Before the loop (run-once init):\n> #   batch_issue_count=0\n> #   BATCH_SIZE=\"${AUTOSPEC_BATCH_SIZE:-1}\"\n> #   [ \"$BATCH_SIZE\" -gt 0 ] 2>\u002Fdev\u002Fnull || BATCH_SIZE=1   # guard against 0 or negative\n> #   rm -f \"$HOME\u002F.autospec\u002Fbatch-done.json\"   # clear stale file from prior crash\n>\n> while true:\n>   deferred = []   # issues skipped because they exceed the active profile\n>\n>   # Startup\u002Fper-scan heartbeat reconciliation — run before candidate selection.\n>   # This deletes closed\u002Fmerged\u002Forphaned heartbeats, rejects old schemas like\n>   # {\"issue\":407,\"status\":\"in_progress\"}, normalizes current schemas, and\n>   # releases any `claimed` heartbeat older than AUTOSPEC_WATCHDOG_CLAIMED_TIMEOUT_SECS (default: 1800).\n>   if [ -d \"$HOME\u002F.autospec\u002Fprocess-heartbeats\" ]; then\n>     if command -v bash >\u002Fdev\u002Fnull 2>&1; then\n>       bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-watchdog.sh\"\n>     elif command -v pwsh >\u002Fdev\u002Fnull 2>&1; then\n>       pwsh -NoProfile -ExecutionPolicy Bypass -File \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-watchdog.ps1\"\n>     elif command -v powershell >\u002Fdev\u002Fnull 2>&1; then\n>       powershell -NoProfile -ExecutionPolicy Bypass -File \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-watchdog.ps1\"\n>     else\n>       echo \"[watchdog] neither bash nor powershell found; skipping heartbeat reconciliation.\"\n>     fi\n>   fi\n\n>   # Backlog grooming preflight — run exactly one existing-backlog grooming\n>   # cycle before each queue scan when grooming policy is auto\u002Fon. The helper\n>   # invokes autonomous-promote-open-issues.sh --apply, but mutations are still\n>   # protected by the orchestrator's double gate: --apply AND grooming policy\n>   # in {auto,on}. This is no discovery: do not run Tier 2-4 discovery and do\n>   # not file new issues from this preflight.\n>   GROOM_PREFLIGHT=\"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Frun-groom-preflight.sh\"\n>   [ -x \"$GROOM_PREFLIGHT\" ] || GROOM_PREFLIGHT=\"skills\u002Fautospec-run\u002Fscripts\u002Frun-groom-preflight.sh\"\n>   if [ -f \"$GROOM_PREFLIGHT\" ]; then\n>     bash \"$GROOM_PREFLIGHT\" \\\n>       --repo \"{repo}\" \\\n>       --report \"${AUTOSPEC_RUN_REPORT:-$HOME\u002F.autospec\u002Fautospec-run-report.md}\" || true\n>   else\n>     echo \"WARN: backlog grooming preflight helper missing; continuing drain\"\n>   fi\n\n### Queue priority sort (autospec-review interlock)\n\nWhen selecting the next `auto-implement` issue, sort:\n\n1. First: issues with label `priority:high` (e.g. `[REGRESSION]`\n   issues filed by autospec-review). Within `priority:high`, oldest\n   first.\n2. Then: all other `auto-implement` issues, oldest first.\n\n`priority:high` always wins over age. This guarantees regression\nissues unblock the queue before continuing with normal feature work.\n\n### Fab implementer routing (label → gate)\n\nDecide each claimed issue's implementer gate from its labels with the\n`fab-route.sh` helper (resolved like the other coordinator scripts):\n\n```bash\nFAB_ROUTE=\"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Ffab-route.sh\"\n[ -x \"$FAB_ROUTE\" ] || FAB_ROUTE=\"skills\u002Fautospec-run\u002Fscripts\u002Ffab-route.sh\"\nGATE=$(gh issue view \"$ISSUE\" --json labels --jq '[.labels[].name] | join(\",\")' \\\n  | bash \"$FAB_ROUTE\" --stdin)\n```\n\n- `GATE=fab` — the issue carries `area:fab` or `autospec:fab-flow`. Dispatch the\n  **fab implementer**: its full-suite gate is clean regen\n  (`rm -rf build && .venv\u002Fbin\u002Fpython src\u002Fgenerate.py`) → `stl-release-gate.py`\n  on affected models (blocking geometry stages must pass; vision is advisory) →\n  unittest, and the Primary smoke is the model's focused regression test.\n- `GATE=growth` — the issue carries `growth:artifact`. Keep the **standard\n  implementer**, and add one **content-quality gate** to Phase 4 before the\n  standard reviewer + `growth-ethics` + `autospec-secaudit` gates: run\n  `${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fgrowth-content-quality-precheck.sh`\n  on the changed content (deterministic pre-checks: keyword-density ceiling,\n  FTC-disclosure presence, citation presence), then a `TIER_A` reviewer for\n  E-E-A-T \u002F brand-voice, wrapped in the standard 5-attempt adaptive-retry loop\n  that feeds findings back as directives. A failing gate blocks merge\n  (fail-closed); it never ships unreviewed growth content. This makes the gate\n  fire for every path that reaches a `growth:artifact` issue — the autonomous\n  Tier-1 drain and `\u002Fautospec-grow-run` R1 alike.\n- `GATE=default` — every other issue keeps the standard implementer + gate.\n\nThe branch is the only difference; the fab branch's gate prose lives in\n`prompts\u002Fphase4-implementer.md`. Routing is a pure label decision (no substring\nmatch: `area:fabric` stays `default`), so it is deterministic and testable.\n\n### Distributed coordinator selection\n\nBefore choosing `ready[0]`, resolve the Rust control-plane binary:\n\n```bash\nAUTOSPEC_QUEUE_BIN=\"${AUTOSPEC_QUEUE_BIN:-${AUTOSPEC_BIN:-autospec}}\"\n```\n\nIf `--coordination-status` is active, run `autospec queue ready --repo {repo}\n--batch-size \"${AUTOSPEC_BATCH_SIZE:-1}\"`, print the JSON, and exit. If\n`--max-parallel-safe` is active, print only the `.batch` array and exit.\n\nDuring the normal monitor loop:\n\n> **Issue intent safety claim gate.** `autospec claim acquire` reads the current\n> labels and issue body, validates the reviewed Safety review block, performs the\n> label transition, and confirms the lowest-ID run-state comment. The monitor\n> never reimplements that safety or lease transition with `gh issue edit`.\n\n> **Portfolio admission and reconciliation gate.** Before the label transition,\n> `autospec claim acquire` also consults the typed portfolio graph and refuses\n> the claim (no label mutation, no run-state comment) until the issue's\n> `autospec:portfolio-item` marker is bound to its verified primary delivery\n> Project (`kind: spec_portfolio`) and every typed repository-local\n> (`Depends on issue #N`) and cross-repository\n> (`Depends on \u003Ccanonical-issue-url>`) dependency is terminal-success in its own\n> repository. Unavailable or contradictory predecessor state fails closed as\n> Blocked, and an unbound or mismatched marker blocks the claim. Admission\n> expands queue gating only; it does not change merge authority after a child\n> is admitted. Reconciliation runs after each Phase 4 lifecycle boundary\n> (claim, PR open, merge, terminal failure), after parent reconciliation, and\n> during monitor sweeps (step 2 below), so the primary Project projection and\n> dependency edges reflect the latest authoritative issue\u002FPR\u002FCI facts before\n> the next admission decision. The monitor never reimplements Project binding\n> or dependency admission with `gh` commands; a missing typed command fails\n> the monitor start visibly.\n\n0. Reconcile parents whose children may have closed outside autospec before\n   selecting work:\n   ```bash\n   _parent_slug=$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Frepo-slug.sh\" --canonical \"{repo}\")\n   export AUTOSPEC_PARENT_STATE_ROOT=\"${AUTOSPEC_PARENT_STATE_ROOT:-$HOME\u002F.autospec\u002Fparent-state\u002F$_parent_slug}\"\n   if ! \"${AUTOSPEC_BIN:-autospec}\" parent sweep --repo {repo}; then\n     echo \"[monitor] WARN: parent sweep failed; remote parent state is unknown and will be retried\" >&2\n   fi\n   ```\n1. Run `autospec queue ready --repo {repo} --batch-size \"$effective_batch_size\"`\n   after watchdog reconciliation and profile filtering.\n2. Reconcile delivery portfolios before admission: for each ready candidate\n   whose body carries an `autospec:portfolio-item` marker, run\n   `autospec portfolio reconcile --portfolio \u003CID>` (ID from the marker) so the\n   typed graph and the primary Project projection reflect the latest\n   authoritative issue\u002FPR\u002FCI facts. Candidates without a marker are outside\n   the portfolio gate. A reconcile failure fails closed: the candidate is\n   skipped this sweep and is never admitted on inferred dependency readiness.\n3. Use `.ready[0].number` as the next issue candidate.\n4. Claim it through `autospec claim acquire --issue \"$ISSUE\" --repo {repo}\n   --worker-id \"${AUTOSPEC_WORKER_ID:-\u003Cderived>}\" --branch \"\u003CBRANCH>\"`. The\n   portfolio admission gate inside the claim refuses a candidate whose primary\n   Project binding is missing or whose typed dependencies are not ready; a\n   refusal surfaces as a non-success claim exit and takes the skip-and-refresh\n   handling below.\n5. Treat claim exit `2` as a normal lost-race or conflict outcome: refresh the\n   queue and try another candidate without failing the batch.\n6. On failure, stop, or retry exhaustion, call `autospec claim release` before\n   returning `auto-implement` to the queue.\n\n### Final safety-stamp contract\n\n`autospec queue review-safety` is the only automatic writer of issue-intent\nsafety outcomes. After an admission surface persists its final issue body and\nadds interim `auto-implement`, it must invoke the exact target:\n\n```bash\nautospec queue review-safety --repo {repo} --limit 1 --issue \u003CN>\n```\n\nOnly the command's `pass: 1` total admits that invocation. The ready queue and\nclaim command consume Rust's typed passing evidence and refuse a missing,\nambiguous, or blocking result. They never reconstruct, stamp, or replace a\nsafety decision with `gh` commands or `lint issue safety` output.\n\nThe GitHub `autospec-run-state` comment written by the Rust control plane is the\ncross-workstation source of truth. Local process heartbeat files remain useful\nfor same-host progress and compatibility, but they are not authoritative across\nmachines. If the Rust command is unavailable, fail the monitor start visibly;\ndo not fall back to an inline label-swap path.\n\n>   # Deterministic outer-loop decision: stop-sentinel check, ready-queue scan,\n>   # and ALL_DONE detection are handled by the monitor-outer-loop.sh script.\n>   # The monitor invokes it at the top of each iteration and follows the\n>   # emitted action. Issue details (title, URL, labels, body) are fetched\n>   # later via issue-snapshot.sh after the claim.\n>   OUTER_LOOP_OUT=\"$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fmonitor-outer-loop.sh\" \\\n>     --repo \"{repo}\" --batch-num \"${batch_num:-1}\" --batch-issue-count \"$batch_issue_count\")\"\n>   ACTION=\"$(printf '%s' \"$OUTER_LOOP_OUT\" | awk '{print $1}' | cut -d= -f2)\"\n>   case \"$ACTION\" in\n>     claim)\n>       ISSUE=\"$(printf '%s' \"$OUTER_LOOP_OUT\" | awk '{print $2}' | cut -d= -f2)\"\n>       ;;\n>     sleep)\n>       REASON=\"$(printf '%s' \"$OUTER_LOOP_OUT\" | awk '{print $2}' | cut -d= -f2)\"\n>       echo \"[monitor] $REASON — sleeping 300s\"\n>       sleep 300\n>       continue\n>       ;;\n>     all_done)\n>       echo \"[monitor] all issues processed — writing ALL_DONE and exiting\"\n>       HARD SHUTDOWN — emit final report (incl. deferred summary, see Phase 6)\n>       ;;\n>     stop)\n>       MODE=\"$(printf '%s' \"$OUTER_LOOP_OUT\" | awk '{print $2}' | cut -d= -f2)\"\n>       echo \"[monitor] stop signal received: $MODE — exiting\"\n>       HARD SHUTDOWN with final report\n>       exit 0\n>       ;;\n>   esac\n>   # Service watch: heartbeat reconciliation already runs before each candidate scan; every 12 iterations also runs a cheap nudge\u002Freclaim pass for long-lived workers.\n>   monitor_tick=$((monitor_tick + 1))\n>   if [ \"$monitor_tick\" -ge 12 ]; then\n>     monitor_tick=0\n>     if [ -d \"$HOME\u002F.autospec\u002Fprocess-heartbeats\" ]; then\n>       # Default reclaim window: 10800s (3h). For local single-threaded workers set\n>       # AUTOSPEC_WATCHDOG_RECLAIM_SECS=43200 (12h) before launch.\n>       export AUTOSPEC_WATCHDOG_RECLAIM_SECS=\"${AUTOSPEC_WATCHDOG_RECLAIM_SECS:-10800}\"\n>       export AUTOSPEC_WATCHDOG_STALE_SECS=\"${AUTOSPEC_WATCHDOG_STALE_SECS:-1800}\"\n>       # Cheap service wake-up pass: use low-cost model only.\n>       if command -v bash >\u002Fdev\u002Fnull 2>&1; then\n>         # Dispatch one background watchdog helper (cheap model) to iterate stale entries.\n>         bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-watchdog.sh\"\n>       elif command -v pwsh >\u002Fdev\u002Fnull 2>&1; then\n>         # Windows fallback: PowerShell helper.\n>         pwsh -NoProfile -ExecutionPolicy Bypass -File \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-watchdog.ps1\"\n>       elif command -v powershell >\u002Fdev\u002Fnull 2>&1; then\n>         # Windows fallback: classic PowerShell fallback.\n>         powershell -NoProfile -ExecutionPolicy Bypass -File \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-watchdog.ps1\"\n>       else\n>         echo \"[watchdog] neither bash nor powershell found; skipping service-watch pass.\"\n>       fi\n>     fi\n>   fi\n>   # effective_batch_size probe — recomputed each outer-loop tick (not cached).\n>   # reasoning:deep may reduce a single monitor batch to one issue for fresh context.\n>   # This is not a run stop: the orchestrator MUST relaunch automatically until ALL_DONE.\n>   _next_reasoning=$(gh issue view \"${ready[0]}\" --json labels \\\n>     --jq '[.labels[].name | select(startswith(\"reasoning:\"))] | first \u002F\u002F \"reasoning:medium\"' \\\n>     2>\u002Fdev\u002Fnull || echo \"reasoning:medium\")\n>   if [ \"$_next_reasoning\" = \"reasoning:deep\" ]; then\n>     effective_batch_size=1\n>   else\n>     effective_batch_size=\"${AUTOSPEC_BATCH_SIZE:-1}\"\n>     [ \"$effective_batch_size\" -gt 0 ] 2>\u002Fdev\u002Fnull || effective_batch_size=1\n>   fi\n>   echo \"[monitor] effective_batch_size=$effective_batch_size (next issue reasoning: $_next_reasoning)\"\n>   ISSUE = ready[0]\n>   # Security prerequisite pre-dispatch gate. Re-read the live body and labels\n>   # before claim\u002Fdispatch so a post-classification edit cannot bypass the\n>   # portfolio gate. A security child is one containing any of the generated\n>   # Evidence consumed \u002F Controls covered \u002F Prerequisites headings. Its\n>   # Prerequisites section must be absent, exactly `none`, or contain only\n>   # bullet lines whose content begins `verified:`. Anything else is removed\n>   # from the ready queue and marked visibly; never dispatch it.\n>   _security_body=\"$(gh issue view \"$ISSUE\" --repo {repo} --json body --jq .body)\"\n>   if printf '%s\\n' \"$_security_body\" | grep -qE '^## (Evidence consumed|Controls covered|Prerequisites)[[:space:]]*$'; then\n>     _prerequisites=\"$(printf '%s\\n' \"$_security_body\" | awk '\n>       \u002F^## Prerequisites[[:space:]]*$\u002F {inside=1; next}\n>       \u002F^## \u002F && inside {exit}\n>       inside && NF {sub(\u002F^[[:space:]]*-[[:space:]]*\u002F, \"\"); print}\n>     ')\"\n>     if [ -n \"$_prerequisites\" ] && [ \"$_prerequisites\" != \"none\" ] \\\n>       && printf '%s\\n' \"$_prerequisites\" | grep -qv '^verified:'; then\n>       echo \"code_health:security_prerequisite_blocked issue=$ISSUE\" >&2\n>       gh issue comment \"$ISSUE\" --repo {repo} --body \\\n>         \"code_health:security_prerequisite_blocked — every security prerequisite must be verified before dispatch.\"\n>       gh issue edit \"$ISSUE\" --repo {repo} \\\n>         --remove-label auto-implement --add-label autospec:blocked-prerequisite\n>       ready = ready without ISSUE\n>       continue\n>     fi\n>   fi\n>   # Portfolio admission gate (enforced inside claim acquire, never here): the\n>   # claim is refused before label mutation until the issue's\n>   # autospec:portfolio-item marker is bound to its verified primary delivery\n>   # Project and every typed in-repo \u002F cross-repository dependency is\n>   # terminal-success. A refusal is a non-zero claim exit and takes the\n>   # skip-and-refresh path below; never re-implement binding or dependency\n>   # admission with gh commands.\n>   # Atomic claim: autospec claim acquire is the SOLE claim path. It performs the\n>   # check-and-swap (auto-implement -> in-progress-by-bot) atomically with a\n>   # read-back verification, so the hot loop NEVER re-implements the inline\n>   # label swap. Multiple monitors can race the same candidate; exactly one\n>   # wins (exit 0), the rest lose (non-zero) and skip to the next candidate.\n>   claim_json=\"$(\"$AUTOSPEC_CLAIM_BIN\" claim acquire --issue \"$ISSUE\" --repo {repo} --worker-id \"${AUTOSPEC_WORKER_ID:-$(hostname):${USER:-unknown}:monitor:$$}\" --branch \"${BRANCH:-}\" --session-id \"${WAIT_TARGET_SESSION_ID:?missing durable Wait target session binding}\")\" && claim_rc=0 || claim_rc=$?\n>   # exit 1 = hard usage error (never a race signal); exit 2 = lost race.\n>   # Split them: a misconfigured claim (rc 1 or any other non-2 non-zero) must\n>   # surface an operator-visible WARN, not masquerade as a silently-dropped\n>   # lost race (rc 2). rc 0 falls through to ownership below.\n>   if [ \"$claim_rc\" -eq 2 ]; then\n>     echo \"[monitor] claim lost for #$ISSUE (rc=$claim_rc); refreshing queue\"\n>     READY_REMOVE=$(printf \"%s\\n%s\" \"$READY_REMOVE\" \"$ISSUE\" | grep -v \"^${ISSUE}$\" || true)\n>     ready=($READY_REMOVE)\n>     continue\n>   elif [ \"$claim_rc\" -ne 0 ]; then\n>     echo \"[monitor] WARN: claim hard error for #$ISSUE (rc=$claim_rc) — usage\u002Fconfig error, NOT a lost race; skipping. Check autospec claim acquire invocation.\" >&2\n>     READY_REMOVE=$(printf \"%s\\n%s\" \"$READY_REMOVE\" \"$ISSUE\" | grep -v \"^${ISSUE}$\" || true)\n>     ready=($READY_REMOVE)\n>     continue\n>   fi\n>   # exit 0 only: this monitor now owns #$ISSUE. claim acquire has already\n>   # persisted both the per-issue heartbeat and immutable session sidecar.\n>   CLAIM_ID=\"$(printf '%s' \"$claim_json\" | jq -er '.claim_id | select(type == \"string\" and length > 0)')\" || exit 1\n>   CLAIM_WORKER_ID=\"$(printf '%s' \"$claim_json\" | jq -er '.worker_id | select(type == \"string\" and length > 0)')\" || exit 1\n>   bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fheartbeat-read.sh\" --repo \"{repo}\" --session-id \"$WAIT_TARGET_SESSION_ID\" >\u002Fdev\u002Fnull || exit 1\n>   bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fnotify.sh\" \"autospec #$ISSUE: claimed\" \"Starting implementation on {repo}\" || true\n>   # Issue start summary — print before dispatching process(ISSUE) so the operator\n>   # knows exactly what the monitor is about to work on.\n>   # Single API call — body+title+url+labels in ONE `gh issue view` (D5: duplicate-read elimination).\n>   # issue-snapshot.sh wraps that one call and caches the JSON per issue; later steps\n>   # (start summary, implementer\u002Freviewer prompt assembly) reuse the file instead of\n>   # re-fetching. --refresh: labels may have transitioned since the previous run.\n>   _issue_snapshot_file=\"$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fissue-snapshot.sh\" get \"$ISSUE\" --refresh 2>\u002Fdev\u002Fnull || true)\"\n>   _issue_body_file=\"\u002Ftmp\u002Fissue-${ISSUE}-body.md\"\n>   if [ -n \"${_issue_snapshot_file:-}\" ] && [ -f \"${_issue_snapshot_file:-}\" ]; then\n>     jq -r '.body \u002F\u002F \"\"' \"$_issue_snapshot_file\" > \"$_issue_body_file\"\n>     ISSUE_TITLE=$(jq -r '.title \u002F\u002F \"\"' \"$_issue_snapshot_file\")\n>     ISSUE_URL=$(jq -r '.url \u002F\u002F \"\"' \"$_issue_snapshot_file\")\n>     ISSUE_LABELS=$(jq -r '[.labels[]?.name] | join(\", \")' \"$_issue_snapshot_file\")\n>   else\n>     # fetch failed — fail open with empty metadata (same end state as a gh outage)\n>     : > \"$_issue_body_file\"; ISSUE_TITLE=\"\"; ISSUE_URL=\"\"; ISSUE_LABELS=\"\"\n>   fi\n>   ISSUE_GOAL=$(awk '\n>     BEGIN{in_goal=0}\n>     \u002F^## Goal[[:space:]]*$\u002F {in_goal=1; next}\n>     \u002F^## \u002F && in_goal {exit}\n>     in_goal && NF {print; exit}\n>   ' \"$_issue_body_file\")\n>   [ -n \"$ISSUE_GOAL\" ] || ISSUE_GOAL=$(awk 'NF && $0 !~ \u002F^#\u002F {print; exit}' \"$_issue_body_file\")\n>   ISSUE_SMOKE=$(awk '\n>     \u002F### Primary smoke test\u002F {seen=1; next}\n>     seen && \u002F^```\u002F {fence++; next}\n>     seen && fence==1 && NF && $0 !~ \u002F^[[:space:]]*#\u002F {print; exit}\n>   ' \"$_issue_body_file\")\n>   ISSUE_SCOPE=$(awk '\n>     \u002F^## Implementation outline[[:space:]]*$\u002F {in_scope=1; next}\n>     \u002F^## \u002F && in_scope {exit}\n>     in_scope && \u002F^- \u002F {gsub(\u002F^- \u002F,\"\"); print; count++; if (count>=3) exit}\n>   ' \"$_issue_body_file\" | paste -sd '; ' -)\n>   echo \"[monitor] starting #$ISSUE: ${ISSUE_TITLE:-\u003Cuntitled>}\"\n>   echo \"[monitor] url: ${ISSUE_URL:-\u003Cunknown>}\"\n>   echo \"[monitor] labels: ${ISSUE_LABELS:-\u003Cnone>}\"\n>   echo \"[monitor] goal: ${ISSUE_GOAL:-\u003Cnot provided>}\"\n>   echo \"[monitor] smoke: ${ISSUE_SMOKE:-\u003Cnot provided>}\"\n>   echo \"[monitor] scope: ${ISSUE_SCOPE:-\u003Cnot provided>}\"\n>   process(ISSUE)   # single-agent absorbed-discipline — the monitor IS the implementer; see template below\n>   batch_issue_count=$((batch_issue_count + 1))\n>   if [ \"$batch_issue_count\" -ge \"${effective_batch_size:-$BATCH_SIZE}\" ]; then\n>     bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fdiary-write.sh\" \\\n>       --phase 4 --event monitor-exit \\\n>       --body \"Monitor BATCH_COMPLETE: batch=${batch_num:-1} processed=$batch_issue_count repo={repo}\" \\\n>       2>\u002Fdev\u002Fnull || true\n>     printf '{\"batch\":%s,\"processed\":%s,\"repo\":\"%s\",\"ts\":%s,\"status\":\"BATCH_COMPLETE\"}\\n' \\\n>       \"${batch_num:-1}\" \"$batch_issue_count\" \"{repo}\" \"$(date -u +%s)\" \\\n>       > \"$HOME\u002F.autospec\u002Fbatch-done.json\"\n>     echo \"[monitor] batch ${batch_num:-1}: processed $batch_issue_count\u002F${effective_batch_size:-$BATCH_SIZE} issues — writing batch-done.json and exiting for fresh context\"\n>     exit 0\n>   fi\n>   # Immediate next-issue pickup: NO SLEEP after process(ISSUE). Re-enter the top\n>   # of this loop immediately so the fresh queue scan can pick any issue unblocked\n>   # by the merge or failure cleanup that just completed.\n> ```\n>\n> ### Parallel implementer worktree isolation\n>\n> Background `Agent` implementers in the same git workdir collide on `git checkout`\n> even when their file-level scopes are disjoint — first agent to call\n> `git checkout -b \u003CBRANCH>` wins; the second lands on the wrong branch and must\n> recover via cherry-pick. File-level disjointness is necessary but NOT sufficient\n> for parallel safety; the collision is at the git-branch level.\n>\n> When dispatching multiple Phase 4 implementers in parallel, the orchestrator\n> MUST wrap each dispatch via `dispatch-implementer.sh` (or an inline\n> equivalent that produces the same contract):\n>\n> 1. Create a per-issue worktree at `\u002Ftmp\u002Fwt-\u003CBRANCH>` off `origin\u002Fmain` via\n>    `git worktree add -b \u003CBRANCH> \u002Ftmp\u002Fwt-\u003CBRANCH> origin\u002Fmain`.\n> 2. Pre-pend the implementer prompt with an explicit workdir directive naming\n>    `\u002Ftmp\u002Fwt-\u003CBRANCH>` and forbidding `cd`\u002F`git checkout` into the main checkout\n>    or sibling branches.\n> 3. On agent completion, remove the worktree via\n>    `git worktree remove --force \u002Ftmp\u002Fwt-\u003CBRANCH>` (defer cleanup until the PR\n>    has merged so the worktree stays available for retries).\n>\n> Sequential dispatch in the main checkout is the safe default; worktree-isolated\n> parallel dispatch is the only safe parallelism. See `dispatch-implementer.sh`\n> and `tests\u002Fautospec-run\u002Ftest_parallel_dispatch.bats` for the canonical contract.\n>\n> ### Sandbox branch contract (autospec-explore PR-base integration)\n>\n> When `.autospec\u002Fexplore-mode.json` is present (written by\n> `explore-sandbox.sh`), the Phase 4 implementer MUST target the sandbox\n> branch from that file's `branch` field as PR base instead of `main`, and MUST\n> refuse `gh pr merge` against `main` while the file is present (refusal\n> identifier: `code_health:explore_main_merge_refused`). The full contract lives\n> in `skills\u002Fautospec-run\u002Fprompts\u002Fphase4-implementer.md` under \"Sandbox branch\n> contract\" and \"No accidental main merges\"; the trio enforces it via lockstep.\n>\n> ### Implementer prompt selection (turbo-integration routing)\n>\n> Before dispatching, read the issue's labels:\n>\n> ```bash\n> labels=$(gh issue view \u003CISSUE> --json labels --jq '[.labels[].name] | join(\",\")')\n> ```\n>\n> - **If `labels` contains `autospec:v2-flow`** — load the prompt template from `skills\u002Fautospec-run\u002Fprompts\u002Fphase4-implementer.md` (relative to this skill's install location, or via `AUTOSPEC_SKILLS_DIR`\u002Fthe harness's skill mount). That prompt embeds the absorbed-discipline path: expand → implement → finalize → peer-review (via `codex exec`) → evaluate-findings. **Wire the D3 cached prefix (spec Phase 2 child C):** do NOT send the `phase4-implementer.md` body alone — prepend the `gen-implementer-prompt.sh` static cached prefix so the default v2 path stops re-reading SKILL.md + AGENTS.md + the RULE_ID table uncached. Assemble the combined v2 prompt by handing `phase4-implementer.md` to `--body-file`, which forwards it to `bundle-static-context.sh --static-body` so it lands INSIDE the cached prefix. It is one fixed template, so emitting it below the boundary re-sent it uncached on every dispatch and every retry:\n>   ```bash\n>   # Reuse the single body fetch written at process(ISSUE) start (D5).\n>   v2_combined_prompt=$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fgen-implementer-prompt.sh\" \\\n>     --issue-body \"\u002Ftmp\u002Fissue-\u003CISSUE>-body.md\" \\\n>     --branch \"\u003CBRANCH>\" \\\n>     --issue-labels \"\u003CISSUE_LABELS>\" \\\n>     --repo \"\u003CREPO>\" \\\n>     --body-file \"skills\u002Fautospec-run\u002Fprompts\u002Fphase4-implementer.md\")\n>   ```\n>   `gen-implementer-prompt.sh` emits the static cached prefix (framed by `\u003C!-- CACHE BOUNDARY -->` markers, containing SKILL.md + AGENTS.md + RULE_ID table + tag-filtered saved-memory) first; the `phase4-implementer.md` body and the issue assignment ride below it as the dynamic suffix. Pass the prefix block (up to and including the closing `\u003C!-- CACHE BOUNDARY -->`) with `cache_control: { type: \"ephemeral\" }` so Anthropic's prompt cache reuses it across dispatches in the same monitor session. This only changes prompt **assembly\u002Fcaching** — the implementer's absorbed-discipline BEHAVIOR (every step in `phase4-implementer.md`) is unchanged.\n>   UI\u002Fclient-interaction issues handled by that prompt must record exactly one\n>   browser verification state in the PR body's `## Validation` section:\n>   `browser-verified`, `fallback-smoke-only`, or `not-run`. Harness-caused\n>   Browser connector skips that produce `fallback-smoke-only` or `not-run` must\n>   open or link a browser remediation issue with the redacted error detail before\n>   merge.\n> - **Otherwise** — use the legacy inline prompt below (current behavior). Legacy path is retained until every pre-v2 issue has drained.\n>\n> Both paths share the same outer monitor loop (queue scan, lock-step compliance, label-based locking, heartbeat updates, post-process pickup). The selection only changes the inner subagent prompt body.\n>\n> `process(ISSUE)` is single-agent absorbed-discipline: the monitor agent performs the implementation work itself, in-context, using the prompt below as its working brief. There is NO nested subagent dispatch here — subagents spawned by background `Agent` calls do NOT inherit the `Agent` tool, so the monitor must own the work directly:\n>\n> **Prompt construction (cache-prefix + dynamic suffix):**\n> Before dispatch, the orchestrator builds the subagent prompt. Two options:\n>\n> **Option A (recommended): `gen-implementer-prompt.sh`** — standalone assembler:\n>    ```bash\n>    # Reuse the single body fetch written at process(ISSUE) start (D5).\n>    combined_prompt=$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fgen-implementer-prompt.sh\" \\\n>      --issue-body \"\u002Ftmp\u002Fissue-\u003CISSUE>-body.md\" \\\n>      --branch \"\u003CBRANCH>\" \\\n>      --issue-labels \"\u003CISSUE_LABELS>\" \\\n>      --repo \"\u003CREPO>\")\n>    ```\n>\n> **Option B (legacy): `bundle-and-dispatch.sh`** — wraps bundle-static-context internally:\n>\n> 1. **Static cached prefix + dynamic suffix** — call `bundle-and-dispatch.sh` to assemble the combined prompt:\n>    ```bash\n>    # Write dynamic suffix to a temp file first\n>    _suffix_file=$(mktemp -t autospec-suffix-XXXXXX.txt)\n>    trap 'rm -f \"$_suffix_file\"' EXIT\n>    printf '%s\\n' \"\u003CISSUE_BODY_AND_DIRECTIVES>\" > \"$_suffix_file\"\n>    combined_prompt=$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fbundle-and-dispatch.sh\" \\\n>      --role implementer \\\n>      --issue-labels \"\u003CISSUE_LABELS>\" \\\n>      --dynamic-suffix-file \"$_suffix_file\")\n>    ```\n>    `bundle-and-dispatch.sh` calls `bundle-static-context.sh` internally to emit the static cached\n>    prefix (framed by `\u003C!-- CACHE BOUNDARY -->` markers, containing implementer-contract.md +\n>    the AGENTS.md quality-contract section with the RULE_ID table + lockstep rules +\n>    implementer scaffolding + the --static-body template), then appends the tag-filtered\n>    saved-memory and the dynamic suffix after the closing marker. The prefix does NOT hold\n>    SKILL.md itself, and saved-memory is deliberately below the marker because it is\n>    label-filtered and so cannot be byte-stable.\n>    Pass the prefix block (up to and including the closing `\u003C!-- CACHE BOUNDARY -->`) with\n>    `cache_control: { type: \"ephemeral\" }` so Anthropic's prompt cache can reuse it across\n>    dispatches in the same monitor session (5-min TTL).\n>\n> 2. **Dynamic uncached suffix** — appended by `bundle-and-dispatch.sh` after the cached prefix:\n>    the issue body, per-iteration findings (if retry > 1), branch name, and \"begin coding now\".\n>\n> 3. **Resolve the implementer model (deterministic — do this before dispatching)** — the issue's\n>    `reasoning:*` label decides which profile implements it, and the profile carries the concrete\n>    model id. Ask the selector rather than deciding yourself:\n>    ```bash\n>    _impl_model=$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fselect-model-profile.sh\" \\\n>      --labels \"\u003CISSUE_LABELS>\" \\\n>      --print-model) || _impl_model=\"\"\n>    ```\n>    If `_impl_model` is **non-empty**, dispatch the implementer subagent with that model in place of\n>    the harness-detected `TIER_B`. If the selector exits 3 (empty output — no `model:` key is\n>    resolvable, which is the case for an auto-initialised `~\u002F.autospec\u002Fmodel-profiles.yml`), keep\n>    `TIER_B` exactly as detected. Never invent a model id, and never widen this override:\n>    - It applies to the **implementer dispatch only**. The reviewer keeps its own tier — a reviewer\n>      must never run on a weaker model than the implementer it is checking.\n>    - The fall-back-**up** rule still holds: if the resolved model is unavailable at dispatch time\n>      (quota, capacity, authorization), silently retry the same dispatch at `TIER_B`, then `TIER_A`.\n>\n> The combined prompt sent to the subagent is:\n>\n> ```\n> **Model tier:** `TIER_B` (implementation work) — cheaper model with medium thinking; resolved at startup. Silently fall back to `TIER_A` if unavailable.\n>\n> **Hard limits.** Max 40 tool calls per issue. Max 3 self-review iterations. If you rewrite the same file twice with no test progress, abort: comment the blocker on the issue, release the lock label, exit. No wall-clock cap.\n>\n> Implement GitHub issue #\u003CISSUE>: \"\u003CTITLE>\" on {repo}. Spec is the issue body below.\n>\n> ===ISSUE BODY===\n> \u003CBODY>\n> ===END===\n>\n> ## Team personality as execution lens\n>\n> Read the issue body's **Team personality** section before choosing an\n> approach. Let that team shape what you emphasize: a reliability\u002Fbackend team\n> should scrutinize operational safety and data boundaries, a frontend\u002Fproduct\n> team should scrutinize user workflow and accessibility, a security-sensitive\n> team should scrutinize trust boundaries and abuse cases, and so on. Do not\n> invent extra scope; use the team personality to decide which risks deserve\n> extra attention while still satisfying the issue's concrete acceptance\n> criteria.\n>\n> Keep a progress heartbeat so the monitor can prove forward movement:\n> - Create\u002Fupdate `~\u002F.autospec\u002Fprocess-heartbeats\u002F\u003Crepo-slug>\u002F\u003CISSUE>.json` at each major step:\n>   - `claimed`, `expand_start`, `worktree_ready`, `tests_started`, `tests_passed`, `pr_created`, `smoke_retry`, `reviewed`, `merged`, `failed`\n> - Recovery-bound schema: `{\"issue\":\"\u003CISSUE>\",\"branch\":\"\u003CBRANCH>\",\"step\":\"\u003CSTEP>\",\"ts\":\u003Cunix_epoch>,\"pr\":\"\u003CPR>\",\"repo\":\"{repo}\",\"host\":\"\u003CHOST>\",\"worker_id\":\"\u003CWORKER_ID>\",\"claim_id\":\"\u003CCLAIM_ID>\",\"session_id\":\"\u003CWAIT_TARGET_SESSION_ID>\"}`. `heartbeat-write.sh` creates the exact-session sidecar once: an identical identity refresh preserves it, while any session\u002Fissue\u002Fworker\u002Fbranch\u002Fclaim mismatch fails closed before updating liveness. Legacy heartbeats without that sidecar remain valid only for liveness and fail closed for Wait recovery.\n> - Delete this file on terminal SUCCESS\u002FFAILURE in both clean and failure paths.\n> - Transition notifications: on `tests_passed`, `pr_created`, `merged`, and `failed` call\n>   `bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fnotify.sh\" \"\u003Ctitle>\" \"\u003Cbody>\" || true`\n>   once per transition. Dedup with `_notify_fired=\"\"` (reset per issue) and the pattern\n>   `case \"$_notify_fired\" in *:\u003CSTEP>:*) ;; *) _notify_fired=\"${_notify_fired}:\u003CSTEP>:\"; bash ... || true ;; esac`.\n>\n> ## Project rules you MUST honor\n>\n> \u003Cverbatim concatenation of relevant feedback_*.md bodies — injected by bundle-static-context.sh --role implementer before dispatch>\n>\n> ## RULE_IDs (from AGENTS.md ## Implementation-quality contract)\n>\n> \u003Cverbatim RULE_ID table from AGENTS.md — injected by bundle-static-context.sh --role implementer>\n>\n> ## Acceptance criteria as constraints\n>\n> \u003Cverbatim AC checkbox list from issue body — every checkbox must be green before push>\n>\n> 0. **Heartbeat refresh at expand start.** The very first action before any expand work (reading files, pattern survey, verifying paths) is to refresh the heartbeat to `expand_start`. This covers the claim→worktree_ready window: the monitor wrote `claimed` when it dispatched you; without this refresh the watchdog may falsely reclaim the issue during a long expand phase.\n>    ```bash\n>    bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fheartbeat-write.sh\" \\\n>      --issue \"\u003CISSUE>\" --branch \"${BRANCH:-}\" --step expand_start --repo \"{repo}\" \\\n>      --worker-id \"$CLAIM_WORKER_ID\" --claim-id \"$CLAIM_ID\" --session-id \"$WAIT_TARGET_SESSION_ID\"\n>    ```\n> 1. **PR-aware recovery ladder, then worktree.** Resolve the branch state FIRST, then act on the verdict. NEVER `cd`\u002F`git checkout`\u002F`git commit` in the primary checkout — all work happens in a linked worktree off `origin\u002Fmain`.\n>    \u003C!-- worktree-ladder:begin -->\n>    ```bash\n>    cd {repo_root} && git fetch origin\n>    LADDER=$(bash ${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fworktree-guard.sh resolve-branch --branch \u003CBRANCH> --repo {repo})\n>    STATE=$(printf '%s' \"$LADDER\" | sed -n 's\u002F.*\"state\":\"\\([^\"]*\\)\".*\u002F\\1\u002Fp')\n>    PR=$(printf '%s' \"$LADDER\" | sed -n 's\u002F.*\"pr\":\\([0-9]*\\).*\u002F\\1\u002Fp')\n>    case \"$STATE\" in\n>      open-pr)\n>        # #886 recovery: a PR already exists. SKIP implementation entirely.\n>        # Check out the existing PR in a fresh worktree, run the issue's\n>        # verification (tests + validate.sh) and the standard review loop\n>        # against the EXISTING PR, then merge if green. Never re-implement.\n>        bash ${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fworktree-guard.sh create --branch \u003CBRANCH> --path \u002Ftmp\u002Fwt-\u003CBRANCH> --adopt\n>        cd \u002Ftmp\u002Fwt-\u003CBRANCH>\n>        gh pr checkout \"$PR\"\n>        echo \"[ladder] open-pr #$PR — skip implementation; verify + review + merge existing PR\"\n>        ;;\n>      branch-only)\n>        # #917 recovery: the branch exists with un-PR'd work. Adopt it in a\n>        # fresh worktree and CONTINUE the remaining work (do not start over).\n>        bash ${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fworktree-guard.sh create --branch \u003CBRANCH> --path \u002Ftmp\u002Fwt-\u003CBRANCH> --adopt\n>        cd \u002Ftmp\u002Fwt-\u003CBRANCH>\n>        echo \"[ladder] branch-only — adopted \u003CBRANCH>; continue remaining work\"\n>        ;;\n>      fresh|*)\n>        # No branch, no PR: create a new worktree off origin\u002Fmain.\n>        bash ${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fworktree-guard.sh create --branch \u003CBRANCH> --path \u002Ftmp\u002Fwt-\u003CBRANCH>\n>        cd \u002Ftmp\u002Fwt-\u003CBRANCH>\n>        echo \"[ladder] fresh — created \u003CBRANCH>\"\n>        ;;\n>    esac\n>    # Reset repo-local state roots after entering the issue worktree. Parent\n>    # autospec-run processes may export AUTOSPEC_REPO_DIR for the primary\n>    # checkout; premerge\u002Fvalidation helpers must read mutable artifacts such as\n>    # .autospec\u002Fqa-verdict.json from this active worktree instead.\n>    export AUTOSPEC_REPO_DIR=\"$PWD\"\n>    # MANDATORY assert gate: MUST exit 0 before the first file edit\u002Fcommit. A\n>    # non-zero exit (in_primary_checkout \u002F dirty \u002F stale_base \u002F wrong_branch) is NEVER worked\n>    # around — comment the emitted code_health identifier on the issue, restore\n>    # the `auto-implement` label (swap `in-progress-by-bot` → `auto-implement`),\n>    # remove the heartbeat, and stop this issue.\n>    if ! bash ${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fworktree-guard.sh assert --expected-branch \u003CBRANCH> --branch-pattern 'feat\u002F*'; then\n>      gh issue comment \u003CISSUE> --body \"worktree-guard assert failed (see code_health identifier above); restoring auto-implement\"\n>      gh issue edit \u003CISSUE> --remove-label in-progress-by-bot --add-label auto-implement\n>      exit 1\n>    fi\n>    ```\n>    \u003C!-- worktree-ladder:end -->\n>    On the `open-pr` path the verification bar EQUALS fresh work — full tests + the standard review loop, never a blind merge. Cleanup is identical for every path: after the merge is confirmed (or on terminal failure), `git worktree remove` the linked worktree and `git worktree prune`; never delete un-pushed work before merge.\n\u003C!-- autospec-block:runtime-resource-preflight -->\n> 1b. **Claim the edit surface (claim-guard), nested inside the issue claim.** After the `worktree-guard.sh assert` gate passes and BEFORE the first file edit, take a fine-grained lease on the skill(s)\u002Fpaths this issue will touch so a concurrent session in another worktree cannot stomp the same trio+golden surface. This is the inner layer of the three-layer caller pattern (worktree-guard → claim-guard scan → claim-guard acquire); it composes with — and sits inside — the issue-level lease you already hold. Set `TARGETS` to the space-separated skill names and\u002For repo-relative paths the issue's **Files touched** lists.\n>    \u003C!-- claim-guard-acquire:begin -->\n>    ```bash\n>    TARGETS=\"\u003Cspace-separated skills\u002Fpaths from the issue's Files touched>\"\n>    bash ${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fworktree-guard.sh assert --expected-branch \u003CBRANCH> --branch-pattern 'feat\u002F*' || exit $?\n>    bash ${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fclaim-guard.sh scan $TARGETS || true\n>    if ! AUTOSPEC_CLAIM_GUARD=strict bash ${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fclaim-guard.sh acquire $TARGETS; then\n>      gh issue comment \u003CISSUE> --body \"claim-guard acquire conflict (see code_health:claim_conflict identifier above); another live session owns this edit surface — restoring auto-implement\"\n>      gh issue edit \u003CISSUE> --remove-label in-progress-by-bot --add-label auto-implement\n>      exit 6\n>    fi\n>    ```\n>    \u003C!-- claim-guard-acquire:end -->\n>    `scan` is advisory (it warns on overlapping open PRs \u002F worktrees \u002F live claims but never blocks); `acquire` is all-or-nothing and exits `6` on `claim_conflict`. Hold this lease across the whole edit+test+PR step. **Refresh rides the existing heartbeat tick** — at each heartbeat write also run `bash ${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fclaim-guard.sh refresh` (no new loop) so a slow-but-live editor is never reclaimed. **Release on PR open**: immediately after `gh pr create` succeeds, run `bash ${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fclaim-guard.sh release $TARGETS` (the lease has served its purpose once the work is captured in a PR). `AUTOSPEC_CLAIM_GUARD=off` or an unwritable store degrades the whole block to a no-op and NEVER blocks the issue.\n> 2. TDD per AGENTS.md: failing test first → implement → refactor → commit. NO DB\u002Fexternal mocks. Follow file paths and signatures from the issue body verbatim.\n> 3. **Full test suite gate.** Run the target repo's full validation\u002Ftest suite, not only the Primary smoke test. Command resolution order:\n>    1. If `AUTOSPEC_FULL_TEST_COMMAND` is set, run `bash -lc \"$AUTOSPEC_FULL_TEST_COMMAND\"`.\n>    2. Else run every command listed under the issue's **Operator\u002Ffull verification** section.\n>    3. Else run the repo-standard full suite: `autospec validate` when present; otherwise use the ecosystem default (`npm test`, `pytest`, `go test .\u002F...`, `cargo test --no-fail-fast`, `mvn test`, etc.). The suite must run every target to completion — cargo gets `--no-fail-fast`, pytest must NOT carry `-x`\u002F`--maxfail`, and `go test` must NOT carry `-failfast` — or the pass\u002Ffail evidence is a truncated run.\n>    If the full suite fails, fix the failure, recommit, rerun the full suite, and repeat. Do NOT dispatch LGTM review while the full suite is failing. Do NOT run `gh pr merge` while the full suite is failing. Record the exact full-suite command and passing output summary in the PR comment or final report.\n>    Once the suite first passes, fire the transition notification: `case \"$_notify_fired\" in *:tests_passed:*) ;; *) _notify_fired=\"${_notify_fired}:tests_passed:\"; bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fnotify.sh\" \"autospec #\u003CISSUE>: tests_passed\" \"Full suite green on {repo}\" || true ;; esac`\n> 3a. **autospec-test gate** (run when `skills\u002Fautospec-test\u002Fscripts\u002Frun-gate.sh` exists in the repo): invoke the gate against the PR's target repo root. Handle exit codes per spec §7a\u002F§7b:\n>    ```bash\n>    GATE_SCRIPT=\"skills\u002Fautospec-test\u002Fscripts\u002Frun-gate.sh\"\n>    if [ -f \"$GATE_SCRIPT\" ] && [ -f \".autospec\u002Ftest.yml\" ]; then\n>      GATE_JSON_OUT=$(mktemp -t autospec-gate-XXXXXX.json)\n>      trap 'rm -f \"$GATE_JSON_OUT\"' EXIT\n>      bash \"$GATE_SCRIPT\" . --output-gate \"$GATE_JSON_OUT\" --pr \"\u003CPR>\" --repo \"{repo}\" || GATE_EXIT=$?\n>      case \"${GATE_EXIT:-0}\" in\n>        0) echo \"[gate] autospec-test: passed\" ;;\n>        1) echo \"[gate] autospec-test: blocked — PR comment posted, labels applied; continuing review loop\" ;;\n>        2) echo \"[gate] autospec-test: fatal (exit 2) — halt batch\"; exit 2 ;;\n>      esac\n>    fi\n>    ```\n>    Exit 0: proceed to merge. Exit 1: block PR (post comment + labels; do NOT merge; treat as review finding). Exit 2: halt entire batch (comment on issue, label `in-progress-by-bot` → `auto-implement`, exit monitor).\n> 3b. \u003C!-- docs-drift-gate:begin -->\n> ## Docs drift gate\n> Run after autospec-test gate, before LGTM review. Skip if issue body contains a line matching `^docs:\\s*skip\\s*$` (case-insensitive). On `drift`\u002F`missing_scope`\u002F`example_stale` the classifier emits the pinned `regenerate` action carrying the affected scopes; the gate self-heals by invoking `\u002Fautospec-doc` (via `doc-orchestrator.mjs`) scoped to ONLY those scopes, re-verifying the regenerated pages with `verify-examples.mjs`, and committing `docs: regenerate \u003Cscopes>` onto the SAME PR branch. **Doc generation NEVER blocks the code PR** — generation\u002Fverification failure only warns, applies the `docs:failed` label, and comments; the code review loop continues. Only the regenerate commit's own example verification gates the regenerated docs (failing pages are NOT committed):\n>    ```bash\n>    if ! grep -qiE '^docs:[[:space:]]*skip[[:space:]]*$' \"\u002Ftmp\u002Fissue-\u003CISSUE>-body.md\" 2>\u002Fdev\u002Fnull; then\n>      SCRIPTS_DIR=\"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\"\n>      DOC_SCRIPTS_DIR=\"${AUTOSPEC_DOC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fskills\u002Fautospec-doc\u002Fscripts}\"\n>      DRIFT_JSON=\"$(bash \"$SCRIPTS_DIR\u002Fcheck-doc-drift.sh\" --pr \"\u003CPR>\" 2>\u002Ftmp\u002Fdrift-\u003CPR>.err)\"; drift_exit=$?\n>      if [ \"$drift_exit\" = \"0\" ]; then\n>        : # no drift — continue to LGTM\n>      else\n>        # drift_exit 1 (drift\u002Fexample_stale) or 2 (missing_scope): classify, then\n>        # self-heal in-PR when the classifier emits the `regenerate` action.\n>        VERDICT_JSON=\"$(printf '%s' \"$DRIFT_JSON\" | node \"$SCRIPTS_DIR\u002Floop-classifier-docs-extension.mjs\" --drift-json - --issue \"\u003CISSUE>\" --pr \"\u003CPR>\" 2>\u002Fdev\u002Fnull || true)\"\n>        ACTION=\"$(printf '%s' \"$VERDICT_JSON\" | node -e 'let s=\"\";process.stdin.on(\"data\",d=>s+=d).on(\"end\",()=>{try{process.stdout.write((JSON.parse(s).action)||\"\")}catch{}})' 2>\u002Fdev\u002Fnull || true)\"\n>        if [ \"$ACTION\" = \"regenerate\" ]; then\n>          # Scopes the classifier flagged — always extract for labelling\u002Freporting.\n>          mapfile -t SCOPES \u003C \u003C(printf '%s' \"$VERDICT_JSON\" | node -e 'let s=\"\";process.stdin.on(\"data\",d=>s+=d).on(\"end\",()=>{try{for(const x of (JSON.parse(s).scopes||[]))console.log(x)}catch{}})' 2>\u002Fdev\u002Fnull || true)\n>          gh issue edit \u003CISSUE> --add-label \"docs:drift\" 2>\u002Fdev\u002Fnull || true\n>          # Resolve the auto_regenerate switch (D2 gate conditional).\n>          # Reads config from .autospec\u002Fautospec.yml, issue body from single-fetch file, and\n>          # AUTOSPEC_WITH_DOCS env. Precedence: docs:skip (already handled above) >\n>          # docs:generate > config auto_regenerate=true > AUTOSPEC_WITH_DOCS=1 > default-off.\n>          _REGEN=$(node --input-type=module \u003C\u003C'__REGEN_EOF__' 2>\u002Fdev\u002Fnull || echo \"0\"\n>          import { resolveAutoRegenerate, loadConfig } from '${AUTOSPEC_DOC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fskills\u002Fautospec-doc\u002Fscripts}\u002Fdoc-config.mjs';\n>          import fs from 'node:fs';\n>          const cfg = (() => { try { return loadConfig('.autospec\u002Fautospec.yml'); } catch { return {}; } })();\n>          const body = (() => { try { return fs.readFileSync('\u002Ftmp\u002Fissue-\u003CISSUE>-body.md','utf8'); } catch { return ''; } })();\n>          const flag = process.env.AUTOSPEC_WITH_DOCS === '1';\n>          const { generate } = resolveAutoRegenerate({ config: cfg, issueBody: body, withDocsFlag: flag });\n>          process.stdout.write(generate ? '1' : '0');\n> __REGEN_EOF__\n>          )\n>          if [ \"${_REGEN:-0}\" = \"1\" ]; then\n>            # auto_regenerate is ON — run the regenerate self-heal path.\n>            doc_ok=1\n>            if node \"$DOC_SCRIPTS_DIR\u002Fdoc-orchestrator.mjs\" 2>\u002Ftmp\u002Fdocgen-\u003CPR>.err; then\n>              # Re-verify regenerated pages; only verified pages are committed.\n>              if [ \"${#SCOPES[@]}\" -gt 0 ] && node \"$DOC_SCRIPTS_DIR\u002Fverify-examples.mjs\" \"${SCOPES[@]}\" 2>\u002Ftmp\u002Fdocverify-\u003CPR>.err; then\n>                if ! git diff --quiet -- \"${SCOPES[@]}\" 2>\u002Fdev\u002Fnull; then\n>                  git add -- \"${SCOPES[@]}\"\n>                  git commit -m \"docs: regenerate ${SCOPES[*]}\" || doc_ok=0\n>                  git push || doc_ok=0\n>                fi\n>              else\n>                doc_ok=0  # example verification failed — do NOT commit regenerated docs\n>              fi\n>            else\n>              doc_ok=0    # generation failed\n>            fi\n>            if [ \"$doc_ok\" = \"0\" ]; then\n>              gh issue edit \u003CISSUE> --add-label \"docs:failed\" 2>\u002Fdev\u002Fnull || true\n>              gh pr comment \u003CPR> --body \"$(printf 'docs: regenerate self-heal failed (generation or example verification) — code PR NOT blocked. Scopes: %s' \"${SCOPES[*]:-\u003Cnone>}\")\" 2>\u002Fdev\u002Fnull || true\n>            else\n>              gh pr comment \u003CPR> --body \"$(printf 'docs: regenerated %s in-PR (examples re-verified).' \"${SCOPES[*]:-\u003Cnone>}\")\" 2>\u002Fdev\u002Fnull || true\n>            fi\n>          else\n>            # auto_regenerate is OFF — log and continue; detection\u002Flabels already applied.\n>            echo \"docs: regeneration skipped (auto_regenerate=false)\"\n>          fi\n>        else\n>          # No regenerate verdict — surface drift for operator review; do not block.\n>          gh pr comment \u003CPR> --body \"$(printf 'docs drift detected — no self-heal action emitted:\\n\\n```json\\n%s\\n```' \"$DRIFT_JSON\")\" 2>\u002Fdev\u002Fnull || true\n>          gh issue edit \u003CISSUE> --add-label \"docs:drift\" 2>\u002Fdev\u002Fnull || true\n>          if [ \"$drift_exit\" = \"2\" ]; then gh issue edit \u003CISSUE> --add-label \"docs:missing-scope\" 2>\u002Fdev\u002Fnull || true; fi\n>        fi\n>      fi\n>    else\n>      gh pr comment \u003CPR> --body \"docs: drift check skipped (docs:skip in issue body)\" 2>\u002Fdev\u002Fnull || true\n>      gh issue edit \u003CISSUE> --add-label \"docs:skipped\" 2>\u002Fdev\u002Fnull || true\n>    fi\n>    ```\n>    \u003C!-- docs-drift-gate:end -->\n> 4. \u003C!-- RETRY-LOOP:begin --> Adaptive commit loop (MAX_IMPL_RETRIES):\n>    ```bash\n>    attempt=1\n>    MAX_IMPL_RETRIES=\"${MAX_IMPL_RETRIES:-5}\"\n>    directive_context=\"\"\n>    while [ \"$attempt\" -le \"$MAX_IMPL_RETRIES\" ]; do\n>      # Conventional commits (feat:\u002Ffix:\u002Ftest:\u002Fdocs:\u002Frefactor:). NEVER bypass hooks. NEVER amend.\n>      if git commit -m \"\u003Cconventional-commit-message>\"; then\n>        # pre-commit hook passed — verify AC bats tests are green\n>        if bats tests\u002Fac\u002Fissue-\u003CISSUE>.bats 2>\u002Fdev\u002Fnull; then\n>          break  # success\n>        fi\n>        # AC tests still failing — treat as lint failure, roll back commit\n>        git reset HEAD~1\n>      fi\n>      # Capture lint directives for next attempt\n>      findings=$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Flint-implementation.sh\" --pre-commit --staged --directives 2>\u002Fdev\u002Fnull || true)\n>      if [ -n \"$findings\" ]; then\n>        directive_context=\"${directive_context}\n>\n> ## Retry attempt ${attempt} findings\n> ${findings}\n>\n> Fix these BEFORE the next code generation.\"\n>      fi\n>      attempt=$((attempt + 1))\n>    done\n>    if [ \"$attempt\" -gt \"$MAX_IMPL_RETRIES\" ]; then\n>      gh issue comment \u003CISSUE> --body \"Implementer hit max retries; manual intervention needed\"\n>      gh issue edit \u003CISSUE> --remove-label \"auto-implement-active\" 2>\u002Fdev\u002Fnull || true\n>      exit 1\n>    fi\n>    ```\n>    \u003C!-- RETRY-LOOP:end -->\n> 4a. \u003C!-- pr-size-pre-push:begin --> **Deterministic PR_SIZE pre-push gate.**\n>    Define this helper in the monitor shell and run it before any remote mutation:\n>    ```bash\n>    # pr-size-helper:begin\n>    run_pr_size_gate() {\n>      # Takes no arguments. A harness substitutes its slash-command argument\n>      # into $1\u002F$2\u002F$3 when it renders this skill body, so reading positionals\n>      # here would let a caller's argument overwrite the gate's own inputs\n>      # (issue #3101). Inputs arrive as named variables set by the call site.\n>      if [ -z \"${PR_SIZE_PHASE:-}\" ] || [ -z \"${PR_SIZE_BASE_OID:-}\" ] \\\n>        || [ -z \"${PR_SIZE_HEAD_OID:-}\" ]; then\n>        printf 'ERROR:PR_SIZE: missing PR_SIZE_PHASE\u002FPR_SIZE_BASE_OID\u002FPR_SIZE_HEAD_OID\\n'\n>        return 1\n>      fi\n>      PR_SIZE_DIFF=$(mktemp -t autospec-pr-size-XXXXXX.diff) || return 1\n>      git diff --binary \"$PR_SIZE_BASE_OID\" \"$PR_SIZE_HEAD_OID\" >\"$PR_SIZE_DIFF\" || {\n>        rm -f \"$PR_SIZE_DIFF\"\n>        return 1\n>      }\n>      PR_SIZE_RC=0\n>      PR_SIZE_OUTPUT=$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Flint-implementation.sh\" \\\n>        --diff-file \"$PR_SIZE_DIFF\" --issue \u003CISSUE>) || PR_SIZE_RC=$?\n>      rm -f \"$PR_SIZE_DIFF\"\n>      printf '%s\\n' \"$PR_SIZE_OUTPUT\"\n>      if [ \"$PR_SIZE_RC\" -ne 0 ] || printf '%s\\n' \"$PR_SIZE_OUTPUT\" | grep -q '^ERROR:PR_SIZE:'; then\n>        printf 'ERROR:PR_SIZE: %s rejected exact diff %s..%s\\n' \\\n>          \"$PR_SIZE_PHASE\" \"$PR_SIZE_BASE_OID\" \"$PR_SIZE_HEAD_OID\"\n>        return 1\n>      fi\n>      printf '%s\\n' 'INFO:PR_SIZE: acceptance'\n>    }\n>    # pr-size-helper:end\n>    # pr-size-pre-push-exec:begin\n>    PR_SIZE_PHASE=pre-push\n>    PR_SIZE_BASE_OID=$(git merge-base \"origin\u002F${AUTOSPEC_BASE_BRANCH:-main}\" HEAD) || exit 1\n>    PR_SIZE_HEAD_OID=$(git rev-parse HEAD) || exit 1\n>    PR_SIZE_EVIDENCE=$(run_pr_size_gate) || {\n>      printf '%s\\n' \"$PR_SIZE_EVIDENCE\"\n>      exit 1\n>    }\n>    printf '%s\\n' \"$PR_SIZE_EVIDENCE\"\n>    printf '%s\\n' \"$PR_SIZE_EVIDENCE\" | grep -qxF 'INFO:PR_SIZE: acceptance' || exit 1\n>    # pr-size-pre-push-exec:end\n>    ```\n>    The deterministic linter rejects the first over-limit values: **401 changed lines**,\n>    **9 raw files**, or **4 logical units**. On rejection, preserve the branch and do not\n>    run `git push`, `gh pr create`, `gh pr ready`, or any merge command.\n>    \u003C!-- pr-size-pre-push:end -->\n> 5. Push: git push -u origin \u003CBRANCH>\n>    ```bash\n>    # Stop-sentinel: abort if an immediate stop flag is present after this step.\n>    if ! bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-stop-check.sh\" \"$ISSUE\" \"$BRANCH\" \"$LAST_STEP\"; then\n>      exit 0\n>    fi\n>    ```\n> 6. PR: build the body deterministically instead of writing it out — the closing\n>    reference, the change list, and the verification line are all already in the\n>    branch, and restating them costs output tokens to reproduce what git holds:\n>    ```bash\n>    # mktemp, not a fixed \u002Ftmp\u002F...-\u003CISSUE> path: two implementers working the same\n>    # issue NUMBER in different repos would otherwise overwrite each other's body.\n>    PR_SUMMARY_FILE=$(mktemp -t autospec-pr-summary-XXXXXX) || exit 1\n>    PR_BODY_FILE=$(mktemp -t autospec-pr-body-XXXXXX) || exit 1\n>    # Write ONLY the summary — the part no template can derive: what this change\n>    # does and which alternative it rejected. Everything else is assembled.\n>    # A quoted heredoc, because the summary is MULTI-PARAGRAPH markdown: printf\n>    # '%s\\n' would flatten it to one line, and any literal % in it is a format\n>    # string. 'EOF' is quoted so backticks and $ in the prose are not expanded.\n>    cat > \"$PR_SUMMARY_FILE\" \u003C\u003C'PR_SUMMARY_EOF'\n>    \u003Csummary>\n>    PR_SUMMARY_EOF\n>    bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fcompose-pr-body.sh\" \\\n>      --issue \"\u003CISSUE>\" --summary-file \"$PR_SUMMARY_FILE\" \\\n>      > \"$PR_BODY_FILE\" || exit 1\n>    ```\n>    Exit 3 from the composer means the commit range is empty: do NOT run\n>    `gh pr create`, and investigate why the branch has no commits.\n>    Then — BEFORE `gh pr create` — assert the composed body actually carries the\n>    closing keyword. A merged PR without it leaves its issue open: finished work\n>    becomes indistinguishable from pending work. A title-style `(#\u003CISSUE>)`\n>    reference is NOT equivalent; GitHub auto-closes only on the body keyword.\n>    ```bash\n>    bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fcompose-pr-body.sh\" \\\n>      --assert-closes \"$PR_BODY_FILE\" || exit 1\n>    ```\n>    Exit 4 means the body carries no `Closes #\u003CISSUE>` keyword: do NOT run\n>    `gh pr create`.\n>    Then: gh pr create --base main --head \u003CBRANCH> --title \"\u003CTITLE>\" --body-file \"$PR_BODY_FILE\". Capture PR. Immediately after the PR opens, release the claim-guard lease taken in step 1a: `bash ${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fclaim-guard.sh release $TARGETS`.\n>    Fire the transition notification: `case \"$_notify_fired\" in *:pr_created:*) ;; *) _notify_fired=\"${_notify_fired}:pr_created:\"; bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fnotify.sh\" \"autospec #\u003CISSUE>: pr_created\" \"PR #\u003CPR> opened on {repo}\" || true ;; esac`\n>    After the LLM subagent returns, record telemetry (tokens JSON written by the harness to `.autospec\u002Ftokens-\u003CISSUE>.json` if present):\n>    ```bash\n>    if [ -f \".autospec\u002Ftokens-\u003CISSUE>.json\" ]; then\n>      bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Frecord-telemetry.sh\" \\\n>        --dispatch-id \"\u003CDISPATCH_ID>\" --role implementer --issue \"\u003CISSUE>\" \\\n>        --tokens-json \".autospec\u002Ftokens-\u003CISSUE>.json\"\n>    fi\n>    ```\n> 7. Inner loop (max 3 iterations):\n>    ```bash\n>    # Stop-sentinel: abort if an immediate stop flag is present after this step.\n>    if ! bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-stop-check.sh\" \"$ISSUE\" \"$BRANCH\" \"$LAST_STEP\"; then\n>      exit 0\n>    fi\n>    ```\n>    - Run the **Primary smoke test** from the issue body. If it fails, fix and recommit before review.\n>    - Run the **Full test suite gate** before fused guardian + LGTM review. If it fails, fix and recommit, rerun the full suite, and do not dispatch review until the full suite passes.\n>    - **Fused guardian + LGTM review** (one subagent does both — saves one dispatch per inner-loop iteration):\n>      \u003C!-- guardian-block:begin -->\n>      Run deterministic lint first (no subagent cost):\n>        rm -f \u002Ftmp\u002Fguardian-\u003CPR>.md\n>        if [ \"${AUTOSPEC_NO_GUARDIAN:-0}\" != \"1\" ]; then\n>          bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Flint-implementation.sh\" \u003CPR> --issue \u003CISSUE> >> \u002Ftmp\u002Fguardian-\u003CPR>.md 2>&1\n>        fi\n>        det_exit=$?\n>\n>      Reuse lens (issues #1439\u002F#1440\u002F#1442): when armed, extract the reuse-triage\n>      RULE_IDs from the deterministic findings so the reviewer prompt receives the\n>      build-vs-buy block. Flag-OFF or no reuse hits → `_reuse_flags_file` stays empty\n>      → the reviewer prompt is byte-identical to today (the `${_reuse_flags_file:+…}`\n>      expansion below adds nothing):\n>        ```bash\n>        _reuse_flags_file=\"\"\n>        if [ \"${AUTOSPEC_REUSE_LENS:-}\" = \"1\" ] && [ -f \u002Ftmp\u002Fguardian-\u003CPR>.md ]; then\n>          _reuse_candidate=$(mktemp -t autospec-reuse-flags-XXXXXX)\n>          grep -E '^(REINVENT_REPO_UTIL|NEW_DEP_UNJUSTIFIED|NEW_ABSTRACTION_SINGLE_CALLER):' \\\n>            \u002Ftmp\u002Fguardian-\u003CPR>.md > \"$_reuse_candidate\" 2>\u002Fdev\u002Fnull || true\n>          if [ -s \"$_reuse_candidate\" ]; then _reuse_flags_file=\"$_reuse_candidate\"; fi\n>        fi\n>        ```\n>\n>      **Model tier:** `TIER_B` for ALL issues — including `regression` and `priority:high`. The single fused reviewer carries the regression gap-check (see brief below), so no second Tier-A pass is dispatched. **Escape hatch:** `AUTOSPEC_REVIEWER_TIER` overrides the reviewer tier — unset (or any value other than `opus`) → `TIER_B` (sonnet); set `AUTOSPEC_REVIEWER_TIER=opus` to restore `TIER_A` for the reviewer. Silently fall back to `TIER_A` if `TIER_B` is unavailable. For a fixed-role model binding, use a fresh configurable `TIER_A` independent reviewer rather than retrying the same unavailable binding. The replacement must receive the byte-equivalent assembled prompt and evidence, inspect the current head independently, and return the same byte-exact `LGTM`\u002Ffindings contract. The orchestrator writes reviewer metadata (`requested_model`, `actual_model`, `fallback_reason`, `head_sha`) to a sidecar evidence artifact, never to the verdict channel. Availability fallback never converts substantive findings into `LGTM`; if the replacement cannot run, block the merge.\n>\n>      **Assemble reviewer prompt** — call `gen-reviewer-prompt.sh` to compose the combined prompt (static cached prefix + dynamic suffix):\n>      ```bash\n>      # Reuse the single body fetch from process(ISSUE) start (D5).\n>      # SHA-gated diff re-fetch: only re-fetch the PR diff when the branch head changed.\n>      _current_head=$(gh pr view \u003CPR> --json headRefOid --jq .headRefOid 2>\u002Fdev\u002Fnull || echo \"\")\n>      if [ -z \"${_reviewer_pr_diff_file:-}\" ] || [ \"${_reviewer_last_head:-}\" != \"$_current_head\" ]; then\n>        _reviewer_pr_diff_file=$(mktemp -t autospec-pr-diff-XXXXXX.diff)\n>        gh pr diff \u003CPR> > \"$_reviewer_pr_diff_file\"\n>        _reviewer_last_head=\"$_current_head\"\n>      fi\n>      combined_reviewer_prompt=$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fgen-reviewer-prompt.sh\" \\\n>        --pr-diff \"$_reviewer_pr_diff_file\" \\\n>        --issue-body \"\u002Ftmp\u002Fissue-\u003CISSUE>-body.md\" \\\n>        --prev-findings \"\u002Ftmp\u002Fguardian-\u003CPR>.md\" \\\n>        --issue-labels \"\u003CISSUE_LABELS>\" \\\n>        --repo \"\u003CREPO>\" \\\n>        ${_reuse_flags_file:+--reuse-flags \"$_reuse_flags_file\"})\n>      ```\n>      Pass `combined_reviewer_prompt` as the reviewer subagent prompt. The static cached prefix is framed by `\u003C!-- CACHE BOUNDARY -->` markers; pass it with `cache_control: { type: \"ephemeral\" }` so Anthropic's prompt cache can reuse it across inner-loop iterations.\n>\n>      Dispatch ONE **foreground subagent** with this brief:\n>        > You are the implementation reviewer for PR #\u003CPR> on {repo}, closing issue #\u003CISSUE>.\n>        >\n>        > ## Review counter-team as review lens\n>        >\n>        > Read the issue body's **Review counter-team** section before reviewing.\n>        > Review from that independent team's perspective and challenge likely blind spots\n>        > from the implementation team's **Team personality**. Stay inside the issue\n>        > scope: do not request unrelated rewrites, but do raise findings when the PR\n>        > misses risks the counter-team was selected to notice.\n>        >\n>        > **Part 1 — Guardian (contract compliance)** — skip if `AUTOSPEC_NO_GUARDIAN=1`:\n>        > 1. Read AGENTS.md `## Implementation-quality contract` for the RULE_ID table and directive map.\n>        > 2. Read issue #\u003CISSUE> body — note `## Implementation scope`, `## Implementation outline`, `## Tests required`, and any `Guardian: skip-*` lines.\n>        > 3. Read deterministic findings in \u002Ftmp\u002Fguardian-\u003CPR>.md (populated by lint-implementation.sh; may be empty if guardian disabled).\n>        > 4. Run `gh pr diff \u003CPR>` and `gh pr view \u003CPR> --json files,title,body`.\n>        > 5. Apply LLM-tier RULE_IDs (HALLUCINATED_API, DUPLICATE_CODE, STRING_MATCH_DOMAIN_LOGIC, REPEATED_STRUCTURE_AS_CODE, DOC_OUT_OF_SYNC semantic pass, INVENTED_CONFIG). For DUPLICATE_CODE, explicitly search for existing components, helpers, validators, API clients, request wrappers, error banners, fixtures, and test utilities before accepting new generated code. For STRING_MATCH_DOMAIN_LOGIC, flag any function that encodes domain meaning via substring-on-name checks when the file already imports a proper-representation library (Python rdkit\u002Fast\u002Furllib.parse\u002Fdatetime\u002Fipaddress\u002Flxml\u002Fjsonschema; JS\u002FTS URL\u002FDate\u002FAST\u002Fzod\u002Fajv\u002Fjoi; Go net\u002Furl\u002Ftime\u002Fgo\u002Fast\u002Fnet.ParseIP; Java java.net.URI\u002Fjava.time\u002FJavaParser\u002Fjavax.validation; Scala java.net.URI\u002Fjava.time\u002Fscalameta\u002Frefined\u002Fcirce; Rust url::Url\u002Fchrono\u002Ftime\u002Fsyn\u002Fstd::net::IpAddr\u002Fserde). For REPEATED_STRUCTURE_AS_CODE, flag any function whose body has ≥5 branches sharing identical structural shape (Python if\u002Felif, Java\u002FScala switch\u002Fmatch, Rust match arms, Go switch cases, JS if\u002Felse) — direct the implementer to extract into a table + single dispatcher loop. For each new component, module, function, endpoint, worker, hook, or test helper, require a spec-linked reason, reuse check, public contract, proof test, and \"what breaks if wrong\" answer. Collect as `RULE_ID:\u003Cpath>:\u003Cline>: \u003Cdesc>`. Honor `Guardian: skip-*` with `INFO:` lines.\n>        >\n>        > **Part 2 — LGTM (correctness review):** Using the same diff and issue body already in context:\n>        > 6. Check correctness, edge cases, missing tests, AGENTS.md compliance (TDD, no mocks, conventional commits), whether every new code unit exists for a concrete issue\u002Fspec requirement rather than convenience, and whether deprecated routes, caches, buckets, stores, workers, config keys, UI paths, docs, specs, tests, or fixtures were removed instead of revived to make tests pass.\n>        > 6a. For anything touching authentication, signing, encryption, or credential handling: ask \"Is this crypto\u002Fdependency defending against a party who can actually reach this data path, or is it re-proving what the transport already proved?\" If TLS to a named host, a process boundary, or an existing gate already establishes the property, flag the re-establishment. The reverse also holds: if a token could arrive by another route (forwarded by a client, read from a header), it must be verified properly, and that boundary must be pinned by a comment at the code.\n>        > 7. Collect findings as a numbered list.\n>        > 8. Critical self-question before LGTM: \"What else could still pass here while the real user workflow fails, and how could this be better?\" Check especially mocked-vs-deployed behavior, external service assumptions, fallback paths, user-visible outcomes, and missing no-mock smoke coverage. If the answer is actionable inside the issue scope, emit it as a finding or required test.\n>      \u003C!-- guardian-block:end -->\n>        > 8a. **data-scope invariant lens (diagnostic\u002Ffilter endpoints):** When the issue touches endpoints, dashboards, reports, or diagnostics that accept optional job\u002Fsample\u002Ffilter parameters, verify filters never widen to unrelated records. empty optional filters reject unless documented as a deliberate all-records mode. Require concrete evidence for `job-only`, `sample-only`, `job+sample`, `unsupported-filter`, and `empty-filter` paths; unsupported-filter and empty-filter cases must prove rejection or a documented scoped response, not silent broadening.\n>        > 9. **Regression gap-check (MANDATORY for `regression`\u002F`priority:high` issues; skip otherwise):** ask \"would the reviewer have caught the original gap?\" If the fused review as written would NOT have caught the gap this regression closes, add the missing checklist item(s) to `reports\u002Fautospec-review\u002Freviewer-lessons.md` (one entry per item, with parent `gap_id` and date) and apply those new checks to this diff before issuing the verdict. This folds the former second-pass regression meta-review into this single reviewer pass — the reviewer-lessons write-path is preserved here; there is no second Tier-A dispatch.\n>        >\n>        > **Hard limit:** max **25 tool calls total** (Parts 1 + 2 combined). If budget exhausted, append `RULE_ID:OUT_OF_SCOPE: reviewer budget exhausted; PR needs human review` and proceed to verdict.\n>        >\n>        > **Simplicity axis is ADVISE-only (anti-gold-plating):** the reuse \u002F build-vs-buy \u002F \"how could this be better?\" axis may argue only toward *less* code — reuse a named existing util (`scripts\u002Flib\u002F`, repo source), adopt a named library, or delete an unneeded abstraction — and only when tied to a named acceptance criterion. It may NEVER emit a `BLOCK` that demands *more* code, a new abstraction, or speculative generality; such suggestions are at most `ADVISE` and never halt the commit. Every reuse verdict must name the matched util or library (evidence-bound), never assert a match from belief.\n>        >\n>        > **Verdict:** If Part 1 has ZERO blocking findings (INFO lines OK) AND Part 2 has no findings: return ONLY the token: `LGTM`. Otherwise return a numbered findings list — RULE_ID findings first, then LGTM findings. A reuse `BLOCK` is provisional until it survives the refute pass below.\n>\n>      **Reuse-BLOCK refute pass (before consuming the verdict):** If the findings list contains a build-vs-buy \u002F reuse `BLOCK`, do NOT halt on it yet. Dispatch a **cheap refute pass** — one short `TIER_B` second voter (≤5 tool calls) whose only job is to *kill* the BLOCK: `rg`-search the repo for the named util\u002Flibrary and confirm the claimed reuse target actually exists, is reachable, and fits this call site. **Majority rules:** keep the BLOCK only if the refuter also upholds it; if the refuter refutes it (the named target is absent, unreachable, or ill-fitting), demote that BLOCK to `ADVISE`, drop it from the blocking findings, and continue. If demotion leaves no remaining blocking findings, treat the verdict as `LGTM`. This keeps a hallucinated \"library exists\" from stalling the merge (`feedback_llm_validator_adaptive_retry`). **Record the outcome of this reuse `BLOCK` decision to the reuse-lens ledger HERE** (issue #1442) — at the decision point, so precision = upheld ÷ total is computed only over real reuse BLOCKs and never from phantom rows on clean passes. Set `_reuse_block_raised=1`, `_reuse_trigger` to the flagged RULE_ID, and `_reuse_upheld=true` when the refuter upheld the BLOCK or `_reuse_upheld=false` when it was refuted\u002Fdemoted-to-ADVISE, then:\n>      **Draw the refuter from a different vendor than the proposer.** Two dispatches to the same model family share failure modes and tend to be wrong together, which is the one case this second vote exists to catch — so resolve the refuter's vendor before dispatching it, passing the harness you detected in step 1 of Phase 0 as `--proposer`:\n>        ```bash\n>        REFUTE_VENDOR=$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fverify-voter-vendor.sh\" \\\n>          --proposer \"\u003CHARNESS>\") || REFUTE_VENDOR=\n>        ```\n>        Run the refute pass on `$REFUTE_VENDOR`'s own `TIER_B` — vendor is the independence lever, tier is the quality lever, and this changes only the former. An **empty** `REFUTE_VENDOR` (exit 3: single-harness host, or every alternative already failed over) means keep the same-harness `TIER_B` refuter: a same-vendor second vote is weaker than a cross-vendor one but still better than none, and the script refuses to name the proposer's own vendor rather than report an independence the host cannot provide.\n>        **On a quota failure, re-resolve rather than give up.** If the refuter's dispatch fails with a 429 \u002F quota \u002F capacity error, call the script again adding `--unavailable \u003Cthat vendor>` and dispatch to what it returns; a 429 is the only ground-truth quota signal available, since `usage-observe.sh` reports `observable=false` for all three harnesses. Repeat until it exits 3, then fall back to the same-harness refuter.\n>        ```bash\n>        if [ \"${AUTOSPEC_REUSE_LENS:-}\" = \"1\" ] && [ \"${_reuse_block_raised:-0}\" = \"1\" ]; then\n>          bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Finterrogation-ledger.sh\" record \\\n>            --issue \"\u003CISSUE>\" --pr \"\u003CPR>\" --trigger \"${_reuse_trigger:-REINVENT_REPO_UTIL}\" \\\n>            --verdict BLOCK --upheld \"${_reuse_upheld:-true}\" \\\n>          || true  # write failure is best-effort; never blocks the PR\n>        fi\n>        ```\n>\n>      If `LGTM` && det_exit == 0:\n>        gh pr comment \u003CPR> --body \"\u003C!-- guardian-block --> Review: clean. \u003C!-- \u002F-->\"\n>        run **Full test suite gate** and record the exact full-suite command and passing output summary\n>        bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fci-wait.sh\" \u003CPR>  # fire-and-forget sentinel\n>        if [ -f \".autospec\u002Ftokens-\u003CISSUE>-reviewer.json\" ]; then\n>          bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Frecord-telemetry.sh\" \\\n>            --dispatch-id \"\u003CDISPATCH_ID>-reviewer\" --role reviewer --issue \"\u003CISSUE>\" \\\n>            --tokens-json \".autospec\u002Ftokens-\u003CISSUE>-reviewer.json\"\n>        fi\n>        # Reuse-lens verdict is recorded at the refute-pass decision point above\n>        # (issue #1442), not here — recording in this LGTM-only branch produced\n>        # phantom BLOCK rows on clean passes and never recorded upheld BLOCKs.\n>        # monitor exits to parking state HERE — orchestrator relaunches when ~\u002F.autospec\u002Fci-state\u002F\u003CPR>.signal settles\n>        # On relaunch: run ci-wait-poll.sh \u003CPR>; break SUCCESS if exit 0 (pass)\n>        break SUCCESS only if the full suite passed and required checks pass.\n>      If `LGTM` but det_exit != 0:\n>        Treat deterministic findings as blocking. Comment, fix, recommit, push. Continue inner loop.\n>      If findings list:\n>        gh pr comment \u003CPR> --edit-last --body \"\u003C!-- guardian-block:begin -->\\n## Review findings (iter \u003CK>\u002F3)\\n\u003Cfindings>\\n\u003C!-- guardian-block:end -->\"\n>        Append findings to implementer retry context. Continue inner loop (counts toward 3-iter cap).\n>      On 3-iter exhaustion with non-LGTM:\n>        gh label create guardian-blocked --color e11d21 --force --repo {repo}\n>        gh issue edit \u003CISSUE> --add-label guardian-blocked\n>        Run failure cleanup (comment, swap label, close PR).\n>        rm -f \u002Ftmp\u002Fguardian-\u003CPR>.md\n>      \u003C!-- guardian-block:end -->\n>    - **Regression coverage** for `regression`\u002F`priority:high` issues is handled inside the single fused reviewer brief (Part 2 item 9 above): the reviewer self-asks \"would the reviewer have caught the original gap?\", writes any missing checks to `reports\u002Fautospec-review\u002Freviewer-lessons.md`, and applies them before its verdict. No second Tier-A dispatch.\n>    - If LGTM: break SUCCESS.\n>    ```bash\n>    # Stop-sentinel: abort if an immediate stop flag is present after this step.\n>    if ! bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-stop-check.sh\" \"$ISSUE\" \"$BRANCH\" \"$LAST_STEP\"; then\n>      exit 0\n>    fi\n>    ```\n> 8. SUCCESS: Run the **rebase-and-retest pre-merge gate** before admin-merging. Addresses cross-session CI rot (issue #307): two PRs each green against pre-merge main can together break main, so we re-prove this PR against post-merge main. Cap is `AUTOSPEC_REBASE_MAX_ATTEMPTS` (default 3). The gate ends with the admin-merge, so do NOT issue a second merge after the block.\n>    ```bash\n>    max_attempts=\"${AUTOSPEC_REBASE_MAX_ATTEMPTS:-3}\"\n>    attempt=0\n>    # Advisory checks (e.g. self-hosted TeamCity) are operator-declared via\n>    # AUTOSPEC_PR_ADVISORY_CHECKS, defaulting to the same regex the conductor's\n>    # main-health gate already honors (AUTOSPEC_MAIN_HEALTH_IGNORE_CHECKS) —\n>    # one shared definition. Unset\u002Fempty (\"^$\") matches no real check name, so\n>    # default behavior is unchanged: every FAILURE blocks.\n>    adv=\"${AUTOSPEC_PR_ADVISORY_CHECKS:-${AUTOSPEC_MAIN_HEALTH_IGNORE_CHECKS:-^$}}\"\n>    wait_for_ci_green() {\n>        while :; do\n>            rollup=$(gh pr view \u003CPR> --json statusCheckRollup --jq '.statusCheckRollup \u002F\u002F []')\n>            pending=$(printf '%s' \"$rollup\" | jq --arg adv \"$adv\" '[.[] | select((((.name \u002F\u002F .context \u002F\u002F \"\") as $n | $n != \"\" and ($n | test($adv)))) | not) | select(.conclusion == null)] | length')\n>            bad=$(printf '%s' \"$rollup\" | jq --arg adv \"$adv\" '[.[] | select((((.name \u002F\u002F .context \u002F\u002F \"\") as $n | $n != \"\" and ($n | test($adv)))) | not) | select(.conclusion==\"FAILURE\" or .conclusion==\"CANCELLED\" or .conclusion==\"TIMED_OUT\" or .conclusion==\"ACTION_REQUIRED\")] | length')\n>            total=$(printf '%s' \"$rollup\" | jq 'length')\n>            if [ \"$bad\" != \"0\" ]; then\n>                # Distinguish inherited base-branch CI rot from branch-caused failures\n>                # before blocking. Capture the PR head rollup and the current base\n>                # commit's check\u002Fstatus contexts as merge evidence, then let\n>                # ci-status-compare.sh emit classification plus blocked_branch and\n>                # blocked_inherited arrays for the PR comment\u002Ffinal report.\n>                base_sha=$(gh pr view \u003CPR> --json baseRefOid --jq .baseRefOid)\n>                head_checks=\"\u002Ftmp\u002Fautospec-ci-head-\u003CPR>.json\"\n>                base_checks=\"\u002Ftmp\u002Fautospec-ci-base-\u003CPR>.json\"\n>                base_check_runs=\"\u002Ftmp\u002Fautospec-ci-base-check-runs-\u003CPR>.json\"\n>                base_statuses=\"\u002Ftmp\u002Fautospec-ci-base-statuses-\u003CPR>.json\"\n>                compare_json=\"\u002Ftmp\u002Fautospec-ci-compare-\u003CPR>.json\"\n>                printf '%s\\n' \"$rollup\" > \"$head_checks\"\n>                gh api \"repos\u002F{repo}\u002Fcommits\u002F$base_sha\u002Fcheck-runs\" --paginate \\\n>                  --jq '[.check_runs[] | {name, conclusion, status, detailsUrl: .details_url}]' \\\n>                  > \"$base_check_runs\"\n>                gh api \"repos\u002F{repo}\u002Fcommits\u002F$base_sha\u002Fstatus\" \\\n>                  --jq '[.statuses[] | {context, state, targetUrl: .target_url}]' \\\n>                  > \"$base_statuses\"\n>                jq -s 'add' \"$base_check_runs\" \"$base_statuses\" > \"$base_checks\"\n>                bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fci-status-compare.sh\" \\\n>                  --head \"$head_checks\" --base \"$base_checks\" > \"$compare_json\"\n>                classification=$(jq -r '.classification' \"$compare_json\")\n>                target_url=$(jq -r '.target_url \u002F\u002F \"\"' \"$compare_json\")\n>                case \"$classification\" in\n>                  inherited)\n>                    gh issue comment \u003CISSUE> --body \"PR #\u003CPR>: required checks are red, but ci-status-compare classified them as inherited base-branch CI rot (blocked_inherited). Merge evidence: ${target_url:-see attached rollup}; compare artifact: \\`$compare_json\\`. Pausing for operator review instead of marking the branch broken.\"\n>                    exit 1\n>                    ;;\n>                  branch_caused)\n>                    gh issue comment \u003CISSUE> --body \"PR #\u003CPR>: required checks failed and ci-status-compare classified them as branch-caused (blocked_branch). Merge evidence: ${target_url:-see attached rollup}; compare artifact: \\`$compare_json\\`.\"\n>                    exit 1\n>                    ;;\n>                  *)\n>                    gh issue comment \u003CISSUE> --body \"PR #\u003CPR>: required checks looked bad but ci-status-compare returned \\`$classification\\`; pausing for operator review. Compare artifact: \\`$compare_json\\`.\"\n>                    exit 1\n>                    ;;\n>                esac\n>            fi\n>            if [ \"$total\" != \"0\" ] && [ \"$pending\" = \"0\" ]; then return 0; fi\n>            sleep 30\n>        done\n>    }\n>    while [ \"$attempt\" -lt \"$max_attempts\" ]; do\n>        state=$(gh pr view \u003CPR> --json mergeStateStatus --jq .mergeStateStatus)\n>        # mergeStateStatus values: CLEAN | BEHIND | BLOCKED | DIRTY | HAS_HOOKS | UNKNOWN | UNSTABLE\n>        case \"$state\" in\n>            CLEAN|HAS_HOOKS|UNSTABLE) break ;;\n>            BEHIND)\n>                if ! gh pr update-branch \u003CPR>; then\n>                    gh issue comment \u003CISSUE> --body \"PR #\u003CPR>: \\`gh pr update-branch\\` failed (auth\u002Fapi\u002Fconflict). Pausing for operator review.\"\n>                    exit 1\n>                fi\n>                wait_for_ci_green\n>                ;;\n>            DIRTY)\n>                gh issue comment \u003CISSUE> --body \"PR #\u003CPR> has a merge conflict against main; needs human resolution.\"\n>                exit 1\n>                ;;\n>            BLOCKED) sleep 30; wait_for_ci_green ;;\n>            *) sleep 15 ;;\n>        esac\n>        attempt=$((attempt + 1))\n>    done\n>    if [ \"$attempt\" -ge \"$max_attempts\" ]; then\n>        gh issue comment \u003CISSUE> --body \"PR #\u003CPR>: rebase-and-retest stalled after $max_attempts attempts; main is moving faster than CI completes. Pausing for operator review.\"\n>        exit 1\n>    fi\n>    # Mandatory final local proof after the branch is current with main.\n>    # Run the **Full test suite gate** here using the same command resolution order\n>    # (`AUTOSPEC_FULL_TEST_COMMAND`, Operator\u002Ffull verification, then `autospec validate` fallback).\n>    # If it fails, fix the failure, recommit, push, rerun the full suite and review, and do NOT run `gh pr merge`.\n>    #\n>    # Final quality gate (pre-merge, fail-closed): after the full suite passes and\n>    # before admin-merging, discover repository-specific whole-workspace quality\n>    # commands and run each one from the target repo root. Discovery covers every\n>    # language whose marker is present, not only Rust:\n>    #   1. If AUTOSPEC_FINAL_QUALITY_COMMAND is set it OVERRIDES discovery: that\n>    #      command is the only one run, and no marker is inspected.\n>    #   2. Otherwise `discover-quality-commands.sh` emits one `marker\u003CTAB>command`\n>    #      line per present marker - Cargo.toml -> `cargo clippy --workspace --all-targets -- -D warnings`,\n>    #      `*.sh` -> shellcheck, package.json -> `npm run lint`, pyproject.toml ->\n>    #      `ruff check`, go.mod -> `go vet .\u002F... && golangci-lint run`.\n>    #   3. A marker present whose linter is NOT installed is never a silent pass:\n>    #      the gate fails closed with rule=\u003Clanguage>-unavailable before running anything.\n>    # Treat every discovered command as required merge evidence. Do NOT run `gh pr merge` while the final quality gate is failing.\n>    # On failure, post\u002Fcomment a\n>    # `FINAL_QUALITY_GATE_FAILED` block that includes the command plus one finding\n>    # record with `crate`, `file`, `line`, and `rule` fields (use `unknown` only when\n>    # the tool output genuinely omits a field), then return to the fix\u002Frecommit\u002Fretry\n>    # loop and rerun the full suite plus final quality gate before merge.\n>    _QG=\"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fdiscover-quality-commands.sh\"\n>    # Fail closed first: a present marker whose linter is absent blocks the merge.\n>    bash \"$_QG\" --missing-tools > \u002Ftmp\u002Fautospec-quality-missing.txt\n>    if [ -s \u002Ftmp\u002Fautospec-quality-missing.txt ]; then\n>      IFS=\"$(printf '\\t')\" read -r _marker _cmd _lang _tool \u003C \u002Ftmp\u002Fautospec-quality-missing.txt\n>      gh issue comment \u003CISSUE> --body \"FINAL_QUALITY_GATE_FAILED command=$_cmd crate=unknown file=$_marker line=1 rule=${_lang}-unavailable tool=$_tool\"\n>      exit 1\n>    fi\n>    # Run every discovered command from the repo root. Cargo.toml is skipped in this\n>    # loop because the Rust-specialized block below runs clippy exactly once and\n>    # parses its diagnostics into crate\u002Ffile\u002Fline\u002Frule.\n>    bash \"$_QG\" > \u002Ftmp\u002Fautospec-quality-commands.txt\n>    while IFS=\"$(printf '\\t')\" read -r _marker _cmd; do\n>      if [ \"$_marker\" = \"Cargo.toml\" ]; then continue; fi\n>      sh -lc \"$_cmd\" || {\n>        gh issue comment \u003CISSUE> --body \"FINAL_QUALITY_GATE_FAILED command=$_cmd crate=unknown file=$_marker line=unknown rule=quality-command-failed\"\n>        exit 1\n>      }\n>    done \u003C \u002Ftmp\u002Fautospec-quality-commands.txt\n>    # The Rust marker keeps its specialized evidence path; the override skips it too.\n>    if [ -z \"${AUTOSPEC_FINAL_QUALITY_COMMAND:-}\" ]; then\n>    if [ -f Cargo.toml ]; then\n>      if ! command -v cargo >\u002Fdev\u002Fnull 2>&1; then\n>        gh issue comment \u003CISSUE> --body \"FINAL_QUALITY_GATE_FAILED command=cargo-metadata crate=unknown file=Cargo.toml line=1 rule=cargo-unavailable\"\n>        exit 1\n>      fi\n>      if ! cargo metadata --no-deps --format-version=1 >\u002Ftmp\u002Fautospec-cargo-metadata.json 2>\u002Ftmp\u002Fautospec-cargo-metadata.err; then\n>        _metadata_err=$(tr '\n' ' ' \u003C\u002Ftmp\u002Fautospec-cargo-metadata.err | sed 's\u002F[[:space:]][[:space:]]*\u002F \u002Fg; s\u002F^ \u002F\u002F; s\u002F $\u002F\u002F' | cut -c1-500)\n>        gh issue comment \u003CISSUE> --body \"FINAL_QUALITY_GATE_FAILED command=cargo-metadata crate=unknown file=Cargo.toml line=1 rule=${_metadata_err:-metadata-failed}\"\n>        exit 1\n>      fi\n>      if ! cargo clippy --workspace --all-targets -- -D warnings >\u002Ftmp\u002Fautospec-final-quality-clippy.log 2>&1; then\n>        # Preserve raw clippy output and summarize the first diagnostic in a stable schema for reviewers.\n>        _crate=$(jq -r '.packages[0].name \u002F\u002F \"unknown\"' \u002Ftmp\u002Fautospec-cargo-metadata.json 2>\u002Fdev\u002Fnull || printf 'unknown')\n>        _location=$(grep -m1 -E '^[[:space:]]*-->' \u002Ftmp\u002Fautospec-final-quality-clippy.log | sed -E 's\u002F^[[:space:]]*-->[[:space:]]*\u002F\u002F' || true)\n>        _file=$(printf '%s' \"$_location\" | awk -F: '{print $1}')\n>        _line=$(printf '%s' \"$_location\" | awk -F: '{print $2}')\n>        _rule=$(grep -m1 -Eo 'clippy::[A-Za-z0-9_]+' \u002Ftmp\u002Fautospec-final-quality-clippy.log || true)\n>        if [ -z \"$_rule\" ]; then _rule=$(grep -m1 -E 'warning:|error:' \u002Ftmp\u002Fautospec-final-quality-clippy.log | sed 's\u002F^ *\u002F\u002F' | cut -c1-200 || true); fi\n>        gh issue comment \u003CISSUE> --body \"FINAL_QUALITY_GATE_FAILED command=cargo-clippy crate=${_crate:-unknown} file=${_file:-unknown} line=${_line:-unknown} rule=${_rule:-unknown}\"\n>        exit 1\n>      fi\n>    fi\n>    fi\n>    \u003C!-- pr-size-final-merge:begin -->\n>    # Query GitHub after update-branch, review, and final local proof. The live PR\n>    # endpoints are authoritative; stale local OIDs can never create acceptance.\n>    # If the shell boundary discarded the helper, redefine it exactly as in step 4a.\n>    # pr-size-final-merge-exec:begin\n>    PR_SIZE_REMOTE_OIDS=$(gh pr view \u003CPR> --json baseRefOid,headRefOid \\\n>      --jq '[.baseRefOid, .headRefOid] | @tsv') || exit 1\n>    [ \"$(printf '%s\\n' \"$PR_SIZE_REMOTE_OIDS\" | awk -F '\\t' \\\n>      'NF == 2 && $1 != \"\" && $2 != \"\" { print \"valid\" }')\" = \"valid\" ] || exit 1\n>    PR_SIZE_BASE_OID=$(printf '%s\\n' \"$PR_SIZE_REMOTE_OIDS\" | cut -f1)\n>    PR_SIZE_HEAD_OID=$(printf '%s\\n' \"$PR_SIZE_REMOTE_OIDS\" | cut -f2)\n>    git fetch --no-tags origin \\\n>      \"+refs\u002Fheads\u002F${AUTOSPEC_BASE_BRANCH:-main}:refs\u002Fremotes\u002Forigin\u002F${AUTOSPEC_BASE_BRANCH:-main}\" \\\n>      \"+refs\u002Fheads\u002F\u003CBRANCH>:refs\u002Fremotes\u002Forigin\u002F\u003CBRANCH>\" || exit 1\n>    git cat-file -e \"${PR_SIZE_BASE_OID}^{commit}\" || exit 1\n>    git cat-file -e \"${PR_SIZE_HEAD_OID}^{commit}\" || exit 1\n>    [ \"$(git rev-parse \"origin\u002F${AUTOSPEC_BASE_BRANCH:-main}\")\" = \"$PR_SIZE_BASE_OID\" ] || exit 1\n>    [ \"$(git rev-parse \"origin\u002F\u003CBRANCH>\")\" = \"$PR_SIZE_HEAD_OID\" ] || exit 1\n>    [ \"$(git rev-parse HEAD)\" = \"$PR_SIZE_HEAD_OID\" ] || exit 1\n>    PR_SIZE_PHASE=final-pre-merge\n>    PR_SIZE_EVIDENCE=$(run_pr_size_gate) || {\n>      printf '%s\\n' \"$PR_SIZE_EVIDENCE\"\n>      exit 1\n>    }\n>    printf '%s\\n' \"$PR_SIZE_EVIDENCE\"\n>    # Reviewer evidence is accepted only as this complete line; prefixes,\n>    # suffixes, summaries, and inferred approval are not acceptance.\n>    printf '%s\\n' \"$PR_SIZE_EVIDENCE\" | grep -qxF 'INFO:PR_SIZE: acceptance' || exit 1\n>    # pr-size-final-merge-exec:end\n>    \u003C!-- pr-size-final-merge:end -->\n>    # Blast-radius domain fence at the merge chokepoint (issue #1732). The guarded-merge\n>    # wrapper classifies the PR's ACTUAL changed files against the repo's fenced_surfaces\n>    # registry and refuses to merge a fenced-surface diff (the wrapper applies the\n>    # human-review quarantine label and comments) unless the PR carries the\n>    # `autospec:fenced-approved` override label; otherwise\n>    # it performs the same admin squash-merge. Call it INSTEAD of a bare `gh pr merge --admin`\n>    # so \"merge without the fence check\" requires deliberately bypassing the wrapper.\n>    # exit 0 = merged (allowed\u002Foverridden); 1 = quarantined (NOT merged); 3 = review quorum refused (NOT merged); 2 = fail-closed error.\n>    # This replaces the historical bare `gh pr merge \u003CPR> --admin --squash --delete-branch`.\n>    # pr-size-guarded-merge-exec:begin\n>    run_guarded_pr_size_merge() {\n>      bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-guarded-merge.sh\" \\\n>        --pr \u003CPR> --repo {repo} \\\n>        --merge-args \"--admin --squash --delete-branch --match-head-commit $PR_SIZE_HEAD_OID\"\n>    }\n>    # pr-size-guarded-merge-exec:end\n>    if run_guarded_pr_size_merge; then\n>      :\n>    else\n>      _gm_rc=$?\n>      if [ \"$_gm_rc\" -eq 1 ] || [ \"$_gm_rc\" -eq 3 ]; then\n>        \"$AUTOSPEC_CLAIM_BIN\" claim release --issue \"\u003CISSUE>\" --repo {repo} --worker-id \"$CLAIM_WORKER_ID\" --claim-id \"$CLAIM_ID\" --state needs-human --branch \"\u003CBRANCH>\" --pr \"\u003CPR>\" || true\n>        if [ \"$_gm_rc\" -eq 3 ]; then\n>          echo \"[monitor] #\u003CISSUE> review quorum REFUSED (rc=3): needs review\u002Fquorum or an operator review_quorum policy; PR NOT merged, left needs-human\"\n>        else\n>          echo \"[monitor] #\u003CISSUE> quarantined by blast-radius fence: fenced surface, left needs-human; PR NOT merged\"\n>        fi\n>      elif [ \"$_gm_rc\" -eq 4 ]; then\n>        echo \"[monitor] #\u003CISSUE> review quorum could not be checked (rc=4, gh\u002Ftransport failure): PR NOT merged; retry later\"\n>      else\n>        echo \"[monitor] #\u003CISSUE> guarded-merge fail-closed (rc=$_gm_rc): PR NOT merged; pausing for operator review\"\n>      fi\n>      rm -f \"\u002Ftmp\u002Fissue-\u003CISSUE>-body.md\" || true\n>      exit 0\n>    fi\n>    \"$AUTOSPEC_CLAIM_BIN\" claim release --issue \"\u003CISSUE>\" --repo {repo} \\\n>      --worker-id \"$CLAIM_WORKER_ID\" --claim-id \"$CLAIM_ID\" \\\n>      --state merged --branch \"\u003CBRANCH>\" --pr \"\u003CPR>\" || true\n>    _parent_slug=$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Frepo-slug.sh\" --canonical \"{repo}\")\n>    export AUTOSPEC_PARENT_STATE_ROOT=\"${AUTOSPEC_PARENT_STATE_ROOT:-$HOME\u002F.autospec\u002Fparent-state\u002F$_parent_slug}\"\n>    if ! \"$AUTOSPEC_CLAIM_BIN\" parent reconcile-child --repo {repo} --child \"\u003CISSUE>\"; then\n>      gh issue comment \"\u003CISSUE>\" --repo {repo} --body \"Parent reconciliation failed after merge; remote parent state is unknown and will be retried by the recurring parent sweep.\"\n>      echo \"[monitor] WARN: parent reconciliation failed for merged child #\u003CISSUE>\" >&2\n>    fi\n>    # Portfolio lifecycle boundary: a merged child is an authoritative fact\n>    # for the typed portfolio graph; the monitor sweep's portfolio\n>    # reconciliation (step 2) publishes it to the primary Project before the\n>    # next admission decision.\n>    case \"$_notify_fired\" in *:merged:*) ;; *) _notify_fired=\"${_notify_fired}:merged:\"; bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fnotify.sh\" \"autospec #\u003CISSUE>: merged\" \"PR #\u003CPR> merged on {repo}\" || true ;; esac\n>    ```\n>    The block ends with the admin-merge and merged-state claim release; merge auto-closes the issue.\n>    ```bash\n>    # Stop-sentinel: abort if an immediate stop flag is present after this step.\n>    if ! bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-stop-check.sh\" \"$ISSUE\" \"$BRANCH\" \"$LAST_STEP\"; then\n>      exit 0\n>    fi\n>    ```\n>    \u003C!-- token-report:begin -->\n>    Post the per-issue token report (best-effort; never fails the run):\n>    ```bash\n>    # Orchestrator writes .autospec\u002Ftokens-\u003CISSUE>.json from Agent-result usage\n>    # (harness-dependent, best-effort; absent fields → null, never blocking).\n>    bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fpost-token-report.sh\" \\\n>      --issue \"\u003CISSUE>\" --repo \"\u003CREPO>\" \\\n>      --tokens-json \".autospec\u002Ftokens-\u003CISSUE>.json\" || true\n>    ```\n>    \u003C!-- token-report:end -->\n>    # Cleanup single-fetch body temp file on terminal success (D5).\n>    rm -f \"\u002Ftmp\u002Fissue-\u003CISSUE>-body.md\" || true\n> 9. FAILURE (loop exhausted): comment failure on issue, swap label `in-progress-by-bot` → `auto-implement`, `gh pr close \u003CPR> --delete-branch`.\n>    Fire the terminal failure notification: `case \"$_notify_fired\" in *:failed:*) ;; *) _notify_fired=\"${_notify_fired}:failed:\"; bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fnotify.sh\" \"autospec #\u003CISSUE>: failed\" \"Implementation failed on {repo}\" || true ;; esac`\n>    Cleanup single-fetch body temp file on terminal failure: `rm -f \"\u002Ftmp\u002Fissue-\u003CISSUE>-body.md\" || true`\n> 10. Cleanup: run `autospec runtime env down --repo \u002Ftmp\u002Fwt-\u003CBRANCH> --mode \"${AUTOSPEC_RUNTIME_MODE:-auto}\" --purge-maven`; then run `bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-runtime-worktree-cleanup.sh\" \u002Ftmp\u002Fwt-\u003CBRANCH>`; only after both succeed, run `cd \u002F && git -C {repo_root} worktree remove \u002Ftmp\u002Fwt-\u003CBRANCH> --force`.\n> 11. Report: PR number, outcome, one-paragraph summary.\n>\n> Hard rules: NEVER push to main, force-push, or bypass hooks. Only `autospec parent` may update or close an umbrella issue. gh CLI only.\n> ```\n>\n> Hard rules for the monitor: ONE issue at a time, sequential. Only `autospec parent` may update or close an umbrella issue. On transient gh errors retry once. Do NOT ask the user — auto-merge authority is granted in AGENTS.md.\n>\n> Final output when shutdown: numbered list of every processed issue with PR # and outcome.\n\nCapture the agent ID \u002F log path for monitoring.\n\nIf your harness lacks background delegation: open a separate terminal\u002Ftmux pane, run the monitor prompt in a fresh session there, and have it write progress to a logfile that Phase 5 can tail.\n\n### Running concurrent workers\n\nautospec-run is designed for concurrent operation across separate harness sessions (e.g., two Claude Code sessions in different terminals, or two Codex CLI processes). Each session runs an independent monitor. Three layers enforce safety:\n\n1. **Atomic claim** — `autospec claim acquire` check-and-swaps `auto-implement → in-progress-by-bot` plus writes an `autospec-run-state` GitHub comment. The **GitHub comment is the cross-machine source of truth**, not the local heartbeat.\n2. **Worktree isolation** — each issue gets its own `\u002Ftmp\u002Fwt-\u003Cbranch>` so two workers never share a worktree.\n3. **Per-session lock** — the session-lock (see above) ensures a single harness session never runs two concurrent monitors; separate sessions run independently by design.\n\nTo launch a second concurrent worker:\n\n```bash\n# Terminal 1 — first worker (already running)\nAUTOSPEC_WORKER_ID=\"$(hostname):user:shell:$$\" \u002Fautospec-run\n\n# Terminal 2 — second worker (fresh session, distinct worker id)\nAUTOSPEC_WORKER_ID=\"$(hostname):user:shell:$$\" \u002Fautospec-run\n```\n\nEach session derives its own `AUTOSPEC_WORKER_ID` if not overridden; the default form is `host:user:harness:pid`. Set it explicitly when two sessions run on the same host to guarantee uniqueness.\n\n**Watchdog tuning for long concurrent runs.** The watchdog cross-checks the GitHub run-state comment before releasing any `claimed` heartbeat, so a live sibling's claim is never reclaimed. The tunable env vars (set in every concurrent terminal):\n\n| Variable | Default | Purpose |\n|---|---|---|\n| `AUTOSPEC_MAX_CONCURRENT_REPO_WORKERS` | `0` (disabled) | Repo-wide active-worker cap. When active `in-progress-by-bot` issues meet the cap, `autospec queue ready` returns an empty `.batch` while still reporting `.ready`. Use this to throttle one workstation or a cluster. |\n| `AUTOSPEC_RUN_ONLY_ISSUES` | unset (unconstrained) | Space-separated issue-number allowlist. When set and non-empty, `autospec queue ready` scopes `.ready`\u002F`.blocked`\u002F`.batch` to only those issue numbers — set by the autonomous conductor's dispatch-time provenance split so the operator and self-originated batches each drain their own subset. Unset or empty keeps the full-queue scan. |\n| `AUTOSPEC_CLAIM_LEASE_SECONDS` | `10800` | Cross-machine claim lease TTL written into the GitHub run-state comment and used by `autospec claim acquire` stale-reclaim decisions. |\n| `AUTOSPEC_CLAIM_SETTLE_SECONDS` | `0.2` | Short post-upsert readback delay so simultaneous comment creates converge before a worker reports claim success. |\n| `AUTOSPEC_CLAIM_CONFIRM_READS` | `5` | Number of settled lowest-lock readbacks required before `autospec claim acquire` reports claim success. |\n| `AUTOSPEC_WATCHDOG_CLAIMED_TIMEOUT_SECS` | `1800` | Minimum age before a `claimed` heartbeat triggers the GitHub cross-check. Set higher (e.g., `3600`) for hosts with slow worktree setup. |\n| `AUTOSPEC_WATCHDOG_RECLAIM_SECS` | `10800` | Legacy fallback for claim lease age when `AUTOSPEC_CLAIM_LEASE_SECONDS` is unset; also used by watchdog stale cleanup. |\n| `AUTOSPEC_WATCHDOG_STALE_SECS` | `1800` | Age at which a heartbeat is considered stale for nudging. |\n\nIf a cross-check GitHub API call fails (offline \u002F rate-limited), the watchdog treats the claim as live and skips the reclaim — fail-safe by design.\n\nRecommended starting caps:\n\n| Deployment | `AUTOSPEC_MAX_CONCURRENT_REPO_WORKERS` | `AUTOSPEC_BATCH_SIZE` | `AUTOSPEC_CLAIM_LEASE_SECONDS` |\n|---|---:|---:|---:|\n| 10 workers | `6` | `1` | `10800` |\n| 25 workers | `12` | `1` | `10800` |\n| 50 workers | `20` | `1` | `14400` |\n\n## Phase 5 — Periodic status updates\n\nSet up a recurring check (every ~25 min) using your harness's self-paced wakeup capability. Each tick:\n\n```bash\ngh issue list --repo {repo} --label auto-implement,in-progress-by-bot,awaiting-merge --state all --json number,state,labels\ngh pr list --repo {repo} --state all --json number,state,title --limit 20\n```\n\nPost a one-paragraph delta to the user (newly closed issues, newly merged PRs, failures, blockers). If two consecutive ticks have nothing new, slow to ~50 min cadence to reduce noise. Stop the loop when:\n- the monitor agent reports completion, OR\n- all child issues are CLOSED, OR\n- the user explicitly stops.\n\nIf your harness lacks self-paced wakeup: register a local `cron`\u002F`launchd` job that runs the same status-check prompt at the chosen cadence, OR ask the user to invoke `status-update` manually.\n\n**Resolving `references\u002F` paths.** The reference pointers below are written relative to the autospec repo root, which is where the validation gate resolves them. Inside a target repo that path does not exist: resolve against this skill's own installed directory instead — `~\u002F.claude\u002Fskills\u002Fautospec-run\u002Freferences\u002F`, `$CODEX_HOME\u002Fskills\u002Fautospec-run\u002Freferences\u002F`, or `$HOME\u002F.autospec\u002Fskills\u002Fautospec-run\u002Freferences\u002F` — and fall back to the `~\u002F.autospec\u002Frepo` checkout. A pointer that will not resolve is a stop-and-report condition, never a skipped step.\n\n## Phase 6 — Final report\n\n**MUST** read `skills\u002Fautospec-run\u002Freferences\u002Fend-of-run.md` (section \"Phase 6 — Final report\") and follow it when the monitor terminates: it defines the Done challenge, the final summary, and the `.autospec\u002Frun-summary.md` write via `autospec-write-run-summary.sh`.\n\n## Phase 5.5 — End-of-run gap remediation\n\n**MUST** read `skills\u002Fautospec-run\u002Freferences\u002Fend-of-run.md` (section \"Phase 5.5 — End-of-run gap remediation\") and follow it after the last issue in the batch closes\u002Fmerges (queue drains, `ALL_DONE`), before the final report: the bounded broad-review → file-survivors → converge loop plus the docs \u002F security \u002F fab-completeness dimensions, and the `autospec-gap-miner.sh` closeout invocation that mines run evidence into `docs\u002Fmemory\u002Fautospec-gap-ledger.md`. Skip the whole phase when `~\u002F.autospec\u002Fno-review.flag` exists or `--no-postreview` was passed.\n\n## Phase 5.6 — Repo quality audit\n\n**MUST** read `skills\u002Fautospec-run\u002Freferences\u002Fend-of-run.md` (section \"Phase 5.6 — Repo quality audit\") and run `repo-quality-audit.sh` after Phase 5.5 converges or hits its cap, before Phase 6 writes the final run summary.\n\n## Advisor escalation\n\n**MUST** read `skills\u002Fautospec-run\u002Freferences\u002Fend-of-run.md` (section \"Advisor escalation\") before escalating any bounded hard decision to a TIER_A advisor (protocol, gates, and the `reviewer` gate).\n\n## Constraints (apply throughout)\n\n- **Cadence**: sub-hour polling needs an in-session background subagent or a local cron. Cloud cron services (e.g. Anthropic remote routines) typically have a 1-hour minimum and are not appropriate.\n- **TDD non-negotiable** per AGENTS.md. Real services in tests, no DB mocks.\n- **Branch-per-issue**, conventional commits, no force-push, no hook bypass.\n- **Auto-merge** on success per AGENTS.md. Do not ask.\n- **Context budget**: stay under 60%. Delegate everything possible.\n- **Failure isolation**: a failed issue restores its `auto-implement` label so the next monitor cycle picks it up; it does not block the cascade unless dependent issues are downstream.\n- **Fresh repo**: if Phase 0 created the repo, the very first commit is the scaffold (incl. `AGENTS.md`); the spec lands as the second commit; child branches branch off that `main`.\n- **Small-LLM target**: child issues are sized and pre-staged for 32B-class local LLMs (e.g. qwen3-32B \u002F Qwen3-30B-A3B on Ollama, 48 GB-class Macs). Bias toward smaller issues, sectional spec anchors, pre-staged file pointers, checkbox AC, and one Primary smoke test.\n\n## Autonomous mode\n\n`\u002Fautospec-run` is already autonomous (no operator gates during normal\noperation). When invoked with `--autonomous`, or when\n`~\u002F.autospec\u002Fautonomous.flag` exists, the monitor:\n\n- Tags run-state telemetry with `autonomous=true` so Phase 5.5 gap\n  remediation and Phase 6 final reports can distinguish autonomous runs\n  from interactive ones.\n- Honors the same safety guardrails as `\u002Fautospec` and `\u002Fautospec-define`:\n  destructive remote actions, out-of-scope file changes, and the token cost gate\n  (`AUTOSPEC_AUTONOMOUS_TOKEN_CAP`) still\n  surface confirmations via `autospec-autonomy-gate.sh --check all`,\n  exit 1 = ask anyway.\n- Does NOT add any additional user-facing gates. The flag is informational\n  here — the run loop's existing \"only ask on hard blocker\" rule already\n  matches autonomous semantics.\n\nPass `--autonomous` from `\u002Fautospec-define`'s handoff (or set it\nexplicitly) to preserve cross-phase telemetry continuity. Existing\n`feedback_autospec_autonomy_scope.md` rules remain in force.\n","# autospec-run workflow (harness-neutral)\n\nTake the populated `auto-implement` queue on the current GitHub repo and run the implementation half of the autospec pipeline:\n**autonomous monitor → admin-squash-merge each PR → periodic status updates → final report.**\n\nManage your own context — never exceed 60%. Delegate to subagents whenever your harness supports it; do not investigate, write code, or design directly in the main conversation when a subagent can do it.\n\nAutospec-run is an autonomous loop and should not ask operator questions for normal operations. Only surface a question if a hard blocker requires explicit manual recovery.\n\n\u003C!-- autospec-block:startup-self-update SKILL_NAME=autospec-run -->\n\n## Self-update mode\n\nDecide this purely from the request text the harness handed you. Do NOT\nshell out (no `grep`, `sed`, `[[ =~ ]]`, command substitution, etc.) to\ntest the user's free-form request — passing it through a shell is what\nhistorically tripped harness permission engines (e.g. parse errors near\nbacktick\u002Fpipe characters in the user's prose). Read the request, normalize\nit in your reasoning (collapse whitespace, trim, lowercase), and if the result is\nexactly `update`, this skill enters self-update mode and does NOT run the\nnormal pipeline.\n\n1. **Detect harness** by checking which install path exists for this skill:\n   - Claude Code: `~\u002F.claude\u002Fskills\u002Fautospec-run\u002FSKILL.md`\n   - OpenCode:    `~\u002F.config\u002Fopencode\u002Fagent\u002Fautospec-run.md`\n   - Codex CLI:   `~\u002F.codex\u002Fprompts\u002Fautospec-run.md`\n2. **Re-install the full autospec suite from `main`** by piping the canonical installer:\n   ```bash\n   curl -fsSL https:\u002F\u002Fraw.githubusercontent.com\u002Fberlinguyinca\u002Fautospec\u002Fmain\u002Fbootstrap.sh | bash -s -- --skill all --harness all --update\n   ```\n   Run this one-liner once; it refreshes all autospec skills across all harnesses.\n3. **Show the diff** between the prior installed file(s) and the freshly fetched copy (e.g. `diff \u003C(cat \u003Cprior>) \u003C(curl -fsSL ...SKILL.md)` or the equivalent recorded by the installer).\n4. **Stop.** Do not enter Phase 0 \u002F Phase 1 \u002F any pipeline phase. Print the upgrade summary and return to the user.\n\nIf no install path is detected, print `Self-update: no installed copy of autospec-run found; run install.sh first.` and exit.\n\n## Stop mode\n\nApply the same read-and-normalize approach used for self-update mode (do\nNOT shell out the user's request). If the normalized request is exactly\n`stop`, or `stop` followed by one or more `--\u003Cword>` flags (examples:\n`stop`, `stop --graceful`, `stop --immediate`, `stop --status`,\n`stop --resume`, `stop --help`, `stop --flag`), this skill enters stop\nmode and does NOT run the normal pipeline. When dispatching, pass any\n`--\u003Cflag>` tokens the user provided as separate words to the helper.\n\n1. Dispatch to `bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-stop.sh\" \u003Cargs>`.\n2. Print the helper's stdout to the user.\n3. Stop. Do not enter Phase 0 or any pipeline phase.\n\n## Status mode\n\nApply the same read-and-normalize approach. If the normalized request is exactly\n`status` (or `status` followed by `--\u003Cword>` flags such as `--json` \u002F `--repo` \u002F\n`--stale-secs`), this skill enters status mode and does NOT run the pipeline — it\nprints a one-glance operator view of the live run (in-flight issues with step +\nage + branch + PR + STALE detection, the queue counts, and the stop-flag state)\ninstead of making the operator hand-parse heartbeat JSON.\n\n1. Dispatch to `bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-run-status.sh\" \u003Cargs>`.\n2. Print the helper's stdout to the user.\n3. Stop. Do not enter Phase 0 or any pipeline phase.\n\n## Invocation\n\n```\n\u002Fautospec-run [--profile \u003Cname>]\n```\n\n- `--profile \u003Cname>` — filter the candidate queue against `~\u002F.autospec\u002Fmodel-profiles.yml` so only issues whose `ctx:*` and `reasoning:*` labels fit the named profile are picked up. Issues that exceed the profile on either axis are appended to a `deferred[]` list and printed in the run-end summary.\n- (no flag) — load `~\u002F.autospec\u002Fmodel-profiles.yml`'s `default:` profile and run with it. If the file is missing, run auto-init (below) then exit so the user can review\u002Fedit before re-running.\n- `--profile \u003Cunknown>` — exit non-zero and print the list of available profile names from `~\u002F.autospec\u002Fmodel-profiles.yml`.\n- `--worker-id \u003Cid>` — override the distributed worker identity written to\n  GitHub run-state comments. Otherwise derive it from host, user, harness, pid,\n  and start timestamp.\n- `--coordination-status` — print active workers, claimed issues, blockers,\n  stale claims, conflicts, and the next safe batch, then exit without claiming.\n- `--max-parallel-safe` — print the next safe parallel batch from\n  `autospec queue ready` and exit without claiming.\n- `--claim \u003Cissue>` — attempt a deterministic claim via `autospec claim acquire`\n  and exit with that command's status (`0` claimed, `2` already claimed\u002Fskipped).\n- `--release \u003Cissue>` — release a distributed claim via `autospec claim release`.\n\n### Auto-init `~\u002F.autospec\u002Fmodel-profiles.yml`\n\nIf the file is missing on run start:\n\n**Dispatching to a local model.** A profile resolved to a local model is executed via\n`bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Flocal-dispatch.sh\" --model \u003Ctag>\n--prompt-file \u003Cpath>`, never by calling a runtime directly. It refuses (exit 3) when\nCodex CLI is absent or does not advertise `--oss`, when the capability probe reports the\nmodel is not `dispatch_recommended`, or when no wall-clock bound can be applied — on any\nrefusal, keep the cloud tier. The local GPU is capacity-1, so the helper serializes\ndispatches; never run two local dispatches concurrently.\n\n**Capping fan-out on a local model.** Serialization covers `local-dispatch.sh`; it does\nNOT cover subagents you spawn in this harness, which reach the same node as ordinary\nsessions. Children cost no VRAM — that is committed when the server starts — but each\nclaims a share of a fixed KV pool that has no admission control, so over-subscribing it\nfails every live session rather than the newest. Before any parallel dispatch whose\nchildren run on a local model, cap the width by what the pool funds:\n\n```bash\nW=$(context-budget-check.py --width \"$PLANNED\" --json 2>\u002Fdev\u002Fnull | jq -r .max_width)\n```\n\nUse `min($PLANNED, $W)`. `W \u003C= 1` means run the work inline. If the checker exits 2 —\nserver unreachable, client config unreadable — keep the cloud tier rather than guessing\na width; a wrong guess is not a slower run, it is a failed one for every session on that\nnode. See the capacity-gate section of AGENTS.md.\n\n1. **Discover local supply with the probe — never enumerate models yourself.**\n   ```bash\n   bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fdiscover-model-supply.sh\" --profiles\n   ```\n   Paste its `profiles:` fragment into the file verbatim. The probe measures each\n   model's real context length via `ollama show`, keeps only completion-capable\n   models, writes the original runtime tag as `model:`, and normalizes the profile\n   key (`qwen3:32b` → `qwen3-32b-laptop`).\n\n   Do **not** list models from memory, from the model names you happen to know, or\n   from an inferred parameter count. An earlier revision of this section asked the\n   orchestrator to do exactly that, and on a live host it produced nine local\n   profiles for four real models — including an unrunnable `qwen3-coder-480b` — and\n   rated every one of them `ctx: 64k` when the measured values were 131072 and\n   262144. Enumerating ground truth is the probe's job.\n\n   Read these fields off the probe rather than guessing:\n   - `accelerator.usable` \u002F `accelerator.reason` — a present `nvidia-smi` and a\n     present `\u002Fdev\u002Fnvidia0` do **not** mean a usable GPU. When `usable` is false,\n     surface `reason` to the operator (e.g. `nvml_driver_library_mismatch` is a\n     five-minute fix) instead of silently accepting CPU inference.\n   - `dispatch_recommended` per model — false means the probe found the model but\n     the host cannot run it usefully (no accelerator, or weights exceed the memory\n     budget). Leave those profiles commented out; the probe already does this.\n   - A model set that comes back empty (no `ollama`, daemon down, or zero\n     completion models) means **no local profiles**. Never synthesize one.\n2. If `ANTHROPIC_API_KEY` is set in the environment, append two cloud profiles:\n   `claude-sonnet-cloud` and `claude-opus-cloud`, both `ctx: 120k`,\n   `reasoning: deep`, each with its `model:` id. Also append `claude-haiku-cloud`\n   (`ctx: 64k`, `reasoning: medium`) — `select-model-profile.sh` routes\n   `reasoning:shallow|medium` issues to it, so omitting it silently disables the\n   cheap implementer tier.\n3. If neither Ollama nor `ANTHROPIC_API_KEY` is detected, write a single\n   `claude-sonnet-cloud` default with `ctx: 120k, reasoning: deep` and an\n   `# edit-and-rerun` comment near the top of the file.\n4. Set the top-level `default:` key to whichever profile makes sense (prefer\n   the largest local profile if any, otherwise `claude-sonnet-cloud`).\n5. Print:\n   ```\n   Wrote ~\u002F.autospec\u002Fmodel-profiles.yml. Edit `default:` and profile ceilings,\n   then re-run \u002Fautospec-run [--profile \u003Cname>].\n   ```\n   Exit 0; do not enter Phase 4.\n\nSample auto-init output:\n\n```yaml\n# ~\u002F.autospec\u002Fmodel-profiles.yml — autospec-run profile ceilings.\n# Edit `default:` and individual ceilings, then re-run.\ndefault: claude-sonnet-cloud\nprofiles:\n  qwen3-32b-laptop:\n    model: qwen3:32b   # original runtime tag — what a dispatch sends\n    ctx: 64k           # one of: 32k | 64k | 120k\n    reasoning: medium  # one of: shallow | medium | deep\n    roles: [implementer]  # local profiles serve the implementer only (Guardrail R2)\n  claude-haiku-cloud:\n    model: claude-haiku-4-5\n    ctx: 64k\n    reasoning: medium\n  claude-sonnet-cloud:\n    model: claude-sonnet-5\n    ctx: 120k\n    reasoning: deep\n```\n\n### Profile-filter ordinals\n\n- `ctx: 32k \u003C 64k \u003C 120k`\n- `reasoning: shallow \u003C medium \u003C deep`\n\nA profile P \"fits\" issue I when `I.ctx_label ≤ P.ctx` AND `I.reasoning_label ≤ P.reasoning` on these ordinals.\n\n---\n\n## Required capabilities & harness adapter\n\nThis workflow assumes five capabilities. Map each one to your harness's actual tool. If a capability is missing, use the listed fallback.\n\n| Capability                  | Claude Code                          | OpenCode                                 | Codex CLI                                | Fallback if missing                                |\n|-----------------------------|--------------------------------------|------------------------------------------|------------------------------------------|----------------------------------------------------|\n| Read-only codebase research | `Agent` (subagent_type=Explore)      | `task` agent in read-only mode           | `apply_patch` read-only \u002F shell `grep`   | Do the search in-thread with `rg`\u002F`grep`           |\n| Foreground delegation       | `Agent` (subagent_type=general-purpose) | nested `task` agent, await output     | spawn nested CLI session                 | Do the work in-thread (more context cost)          |\n| Background delegation       | `Agent` with `run_in_background: true` | detached `task` agent                  | nohup'd CLI session writing to a logfile | Run the monitor in a separate terminal\u002Ftmux pane   |\n| Ask the user a question     | `AskUserQuestion`                    | inline prompt                            | inline prompt                            | Ask in the response and wait for the next turn     |\n| Self-paced future wakeup    | `ScheduleWakeup` inside a `\u002Floop`    | a recurring `task` or local `cron`       | local `cron`\u002F`launchd` calling the CLI   | The user runs a status-update prompt manually      |\n| Subagent model tier         | Tier A: `opus` + `ultrathink`; Tier B: `sonnet` + medium thinking | Tier A: top `task` model + high reasoning; Tier B: smaller-tier `task` + medium reasoning | Tier A: top GPT + `reasoning_effort=high`; Tier B: current spark\u002Fcost-optimized Codex + `reasoning_effort=medium` | Honor the per-phase tier mapping in AGENTS.md; retry the same subagent UP on unavailability |\n| Local model dispatch        | not native — `Agent(model:)` takes Claude tiers only; shell out to `local-dispatch.sh` | provider pointed at `:11434\u002Fv1` (or `:8000` for vLLM) | `codex exec --oss --local-provider ollama` | cloud tier (fail closed) |\n\u003C!-- autospec-block:harness-adapter-core -->\n\n**Persistent project notes**: write durable preferences to **`AGENTS.md`** in the repo root — this is the de-facto standard recognized by Claude Code (also reads `CLAUDE.md`), OpenCode, and Codex. If your harness has its own private memory (e.g. Claude Code's `~\u002F.claude\u002F...\u002Fmemory\u002F`), mirror the same content there. Per AGENTS.md, subagent dispatches use a **two-tier policy**: Tier A (top model + extended thinking) for spec work (research, decompose, review\u002Flabel — not used by this skill); Tier B (cheaper model + medium thinking) for implementation work (Phase 4 implementer + LGTM review). The orchestrator keeps the user's invoked model. Fall back UP the tier on quota\u002Fcapacity or other unavailability by retrying the same subagent with the stronger tier while preserving parent context.\n\n## Harness detection (run once at skill start, before Phase 0)\n\nDetect your harness by checking available tools before any phase:\n\n1. **Claude Code** — the `Agent` tool with a `subagent_type` parameter is available.\n   - `TIER_A` = `opus` + `ultrathink`  (the alias, which resolves to the current Claude Opus generation)\n   - `TIER_B` = `sonnet`               (the alias, which resolves to the current Claude Sonnet generation)\n\n2. **OpenCode** — a `task` tool with model\u002Ftier configuration is available (no `subagent_type`).\n   - `TIER_A` = top-tier task model + high reasoning\n   - `TIER_B` = smaller-tier task model + medium reasoning\n\n3. **Codex CLI** — neither `Agent` nor a configurable `task` tool is available; `apply_patch` is the primary edit tool.\n   - `TIER_A` = current top GPT model + `reasoning_effort=high`\n   - `TIER_B` = the spark \u002F cost-optimized variant of the configured model when one exists, else the configured model + `reasoning_effort=medium`\n\n**Fallback rule:** If `TIER_B` is not available in your harness (model unknown, quota\u002Fcapacity failure, authorization failure, or tool call returns an error for that model), silently retry the same subagent dispatch with `TIER_A`. Preserve the parent context on retry by passing a bounded handoff containing the issue number, repo path, branch\u002Fworktree plan, relevant issue body sections, last error, and current queue\u002Fclaim state. Codex native subagents with explicit `agent_type`, `model`, or `reasoning_effort` MUST use a bounded handoff, not a full-history fork; do not ask Codex to inherit\u002Ffork the full parent conversation when those fields are set. If a role-specialized reviewer has a fixed model binding, retry through a fresh configurable independent agent at `TIER_A` with the identical reviewer prompt, evidence inputs, tool budget, and verdict schema. Never fall back to the author\u002Fmain lane or a weaker model. The orchestrator records the requested model, actual model, availability error class, and reviewed head SHA in a sidecar review artifact; never append metadata to the reviewer's byte-exact verdict channel. If no equal-or-stronger independent reviewer can run, fail closed and do not merge. Never ask the user.\n\n**Codex SpawnAgent call-shape contract:** Codex has two valid subagent call shapes. Use the bounded handoff when setting an explicit executor\u002Ftier route: `SpawnAgent({ prompt: bounded_handoff, agent_type: \"executor\", model: TIER_B, reasoning_effort: \"medium\" })`. Use a full-history fork only when inheriting the current conversation without explicit routing: `SpawnAgent({ prompt: full_history_prompt, full_history: true })`. Never combine `full_history: true` with `agent_type`, `model`, or `reasoning_effort`. On Codex dispatch failure, retry once with the other valid shape when that still satisfies the phase's tier rule; if both valid shapes fail, release the claimed issue back to `auto-implement` with a visible blocker comment.\n\nHold `TIER_A` and `TIER_B` for the entire skill run. Every \"Tier A\" and \"Tier B\" reference below resolves to these harness-specific values.\n\n## Relevant memory injection (run-start, once)\n\nBefore executing the main pipeline phases, call the injector to surface relevant saved lessons:\n\n```bash\nbash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Finject-relevant-memory.sh\" \\\n  --context \"\u003Cskill-relevant keywords from request\u002Fissue\u002Fspec>\" \\\n  --top-k 5\n```\n\nPrepend the output block (if non-empty) to your working context. This surfaces lessons like\n`feedback_bash_return_trap_leak.md` that prevent re-occurrence of known pitfalls.\n\n## Run-start batch timestamp (run-start, once)\n\nCapture the run-start instant so the end-of-run gap-remediation phase (Phase 5.5) can scope its review to work shipped during THIS run. Run exactly once, before the Phase 4 monitor launches:\n\n```bash\nbash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Frun-batch-start.sh\" --write\n```\n\nThis writes the UTC ISO 8601 timestamp to `~\u002F.autospec\u002F.run-batch-start` (idempotent within a run; pass `--force` only when intentionally starting a fresh batch window). Phase 5.5 reads it back via `run-batch-start.sh --read`, which yields `BATCH_START_DATE`.\n\n## Explore-on-drain counter reset (run-start, once)\n\nReset the per-repo explore-on-drain cycle counter so a fresh `\u002Fautospec-run` always starts with a clean slate (spec: \"counter resets when the operator clears it or starts a fresh `\u002Fautospec-run`\"). Run once, immediately after the batch-start timestamp above:\n\n```bash\n# Derive the canonical per-repo slug (owner__name) for state scoping.\n_eod_slug=\"$(gh repo view --json nameWithOwner -q .nameWithOwner 2>\u002Fdev\u002Fnull \\\n    | sed 's#\u002F#__#' \\\n    || printf '%s' \"$(git rev-parse --show-toplevel 2>\u002Fdev\u002Fnull || pwd)\" \\\n         | tr '\u002F' '_' | sed 's\u002F^_\u002F\u002F')\"\nrm -f \"$HOME\u002F.autospec\u002Fexplore-on-drain\u002F${_eod_slug}\u002Fcycles\"\n```\n\nThis ensures the cycle cap (`AUTOSPEC_EXPLORE_ON_DRAIN_MAX_CYCLES`, default 3) counts only chains within the current run, not across multiple historical runs. The `_eod_slug` variable is reused in the ALL_DONE block below.\n\n## Single-instance session lock (run-start, once)\n\nAcquire a per-session lock BEFORE launching the Phase 4 monitor so a single\nharness session never runs two concurrent monitors (which collide on the queue\nand on git branches). The lock is keyed by the harness session id, so separate\nsessions still run independently by design.\n\n```bash\nLOCK=\"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-run-session-lock.sh\"\nif ! bash \"$LOCK\" acquire --repo \"{repo}\"; then\n    # exit 3 = a monitor is already active in THIS session.\n    echo \"autospec-run: refusing to start a second monitor in this session.\" >&2\n    bash \"$LOCK\" status\n    # STOP — do NOT launch Phase 4. Halt the active monitor with \u002Fautospec-stop,\n    # or re-run the lock helper with --force to override a stale lock.\n    exit 0\nfi\n```\n\nRelease the lock on EVERY terminal exit of this run — the Phase 6 final report,\nthe `ALL_DONE` shutdown, and stop mode:\n\n```bash\nbash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-run-session-lock.sh\" release\n```\n\nThe lock is advisory and self-scoped: a crashed session's lock only blocks that\nsame session id (a fresh session gets a new id), and `--force` overrides it.\n\n## Phase 4 — Background autonomous monitor\n\n**Fresh-subagent-per-issue (canonical Phase 4 path, formerly single-agent absorbed-discipline).** Each issue is processed by a FRESH top-level subagent dispatched by the orchestrator — expand → implement → finalize → peer-review → evaluate-findings → PR → merge — in that subagent's own context. The orchestrator NEVER implements in its own context; it only claims, dispatches, and waits. Each subagent receives full tool access because it is a top-level `Agent` call launched directly by the main session orchestrator. **Constraint:** Subagents spawned by background `Agent` calls do NOT inherit the `Agent` tool, so nested monitors cannot dispatch inner implementers. Phase 4 implementers must be top-level agents launched directly by the main session orchestrator, not nested inside a monitor. The `process(ISSUE)` notation below is shorthand for \"dispatch a fresh top-level subagent to do this work\", NOT in-context implementation by the orchestrator. Batch>1 is an explicit operator opt-in via `AUTOSPEC_BATCH_SIZE=N`; the default is 1 (one issue per subagent). The `reasoning:deep` force-to-1 rule is retained: deep issues stay batch=1 even under an operator `AUTOSPEC_BATCH_SIZE=N` override.\n\nRecord this durable preference in `AGENTS.md` (idempotent — skip if already present):\n\n> **Auto-merge authority for auto-implement PRs.** Admin-merge auto-implement PRs (through `autospec-guarded-merge.sh`, never a bare `gh pr merge`) when (a) the full target-repo validation\u002Ftest suite has passed locally after the branch is current with `main`, (b) all **non-advisory** required CI checks pass — checks matching `AUTOSPEC_PR_ADVISORY_CHECKS` (default `AUTOSPEC_MAIN_HEALTH_IGNORE_CHECKS`; e.g. self-hosted TeamCity) are advisory and may be pending **or failing** once the full local suite is green, (c) the self-review subagent returned `LGTM`, (d) PR closes an `auto-implement` issue from a `feat\u002F*` branch.\n\n**Off-peak tip:** For queues of 10+ issues (8+ hour runs), consider launching at night or on weekends. Usage limits are shared across all sessions — running long batches off-peak preserves daytime tokens for interactive work.\n\n**Usage-limit recovery guard.** Before launching the monitor, determine the exact non-interactive command that can relaunch this same `\u002Fautospec-run` invocation in the current repo and store it in `AUTOSPEC_RESUME_COMMAND` if the harness has not already set one. This must be a real shell command, for example the same Claude Code, Codex CLI, OpenCode, tmux, or wrapper command the operator used to start the run with the same `--profile` and repo path. Do not ask the user for it during a running monitor.\n\n**Durable run registry (crash-resume).** At monitor launch, also persist that same relaunch command to the durable run registry so it survives a host\u002Fsession crash and reboot — the session env var `AUTOSPEC_RESUME_COMMAND` does not. Write it once per launch with the identical command:\n\n```bash\nREGISTRY=\"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-run-registry.sh\"\nif [ -f \"$REGISTRY\" ] && [ -n \"${AUTOSPEC_RESUME_COMMAND:-}\" ]; then\n  bash \"$REGISTRY\" write --repo \"$(gh repo view --json nameWithOwner --jq .nameWithOwner)\" \\\n    --repo-dir \"$(pwd)\" --harness \"\u003Cclaude|codex|opencode>\" --command \"$AUTOSPEC_RESUME_COMMAND\"\nfi\n```\n\n`\u002Fautospec-resume` reads `~\u002F.autospec\u002Factive-runs\u002F\u003Crepo-slug>.json` on a fresh start to relaunch this run. The registry is the only durable carrier of the relaunch command across reboot.\n\nWhen a harness reports a deterministic usage-limit\u002Fquota\u002Fcapacity pause with a known reset time or wait duration, do not spend tokens diagnosing the message. Immediately arm the shell supervisor and exit:\n\n```bash\nUSAGE_LIMIT=\"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-usage-limit.sh\"\nif [ -n \"${AUTOSPEC_USAGE_LIMIT_RESUME_AT:-}\" ]; then\n  bash \"$USAGE_LIMIT\" arm --harness \"\u003Cclaude|codex|opencode>\" --repo-dir \"$(pwd)\" \\\n    --command \"$AUTOSPEC_RESUME_COMMAND\" --resume-at \"$AUTOSPEC_USAGE_LIMIT_RESUME_AT\"\n  exit 0\nelif [ -n \"${AUTOSPEC_USAGE_LIMIT_WAIT_SECONDS:-}\" ]; then\n  bash \"$USAGE_LIMIT\" arm --harness \"\u003Cclaude|codex|opencode>\" --repo-dir \"$(pwd)\" \\\n    --command \"$AUTOSPEC_RESUME_COMMAND\" --wait-seconds \"$AUTOSPEC_USAGE_LIMIT_WAIT_SECONDS\"\n  exit 0\nfi\n```\n\nThe helper writes `~\u002F.autospec\u002Fusage-limits\u002F\u003Crun-id>.json`, starts a background daemon, polls every 300 seconds by default, and relaunches the recorded command after the reset time. This is intentionally shell-only so recovery does not require an LLM turn after the usage limit has already been hit.\n\nThen launch a **background monitor loop** — the orchestrator relaunches the monitor with fresh context after each batch of `AUTOSPEC_BATCH_SIZE` issues (default: 1). The monitor is stateless: all persistent state lives in GitHub labels and heartbeat files, so relaunches are always safe.\n\n**Codex Wait call-shape contract:** When awaiting a native Codex `wait_agent` call, omit `timeout_ms` or pass an integer greater than or equal to `10000`. Never pass `timeout_ms` below `10000`; the native router rejects it before the executor can report progress. Keep waiting through task notifications until the monitor reaches a terminal state.\n\n```\nbatch_num=1\nwhile true:\n  launch background subagent paused before its first claim (pass batch_num; AUTOSPEC_BATCH_SIZE=${AUTOSPEC_BATCH_SIZE:-1})\n  capture the returned ACTUAL_SESSION_ID and bind it into that child's durable session context as WAIT_TARGET_SESSION_ID\n  do not allow the child to claim work until it can pass that exact WAIT_TARGET_SESSION_ID to `autospec claim acquire --session-id`\n  wait for task-notification (monitor agent completes)\n\n  if Wait returns `write_stdin failed` with `stdin is closed`:\n    inspect durable agent\u002Fsession state once for a live recovery path\n    if the child is reported live:\n      attempt one harness reattach to the exact failed Wait target\n      if reattach succeeds: continue waiting for task-notification\n      explicitly terminate and reap the child through the harness process API\n      if termination and reap cannot be proven: stop without typed recovery or label mutation\n    require durable proof that the child exited or was terminated and reaped\n    use the actual session ID from the failed Wait target (never infer it from an environment variable)\n    read the immutable heartbeat binding for ACTUAL_SESSION_ID before inspecting any current claim state\n    BOUND_HEARTBEAT=\"$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fheartbeat-read.sh\" --repo {repo} --session-id \"\u003CACTUAL_SESSION_ID>\")\" or stop without typed recovery or label mutation\n    ISSUE=\"$(printf '%s' \"$BOUND_HEARTBEAT\" | jq -er '.issue | select((type == \"string\" and length > 0) or (type == \"number\" and . > 0)) | tostring')\" or stop\n    BRANCH=\"$(printf '%s' \"$BOUND_HEARTBEAT\" | jq -er '.branch | select(type == \"string\")')\" or stop\n    WORKER_ID=\"$(printf '%s' \"$BOUND_HEARTBEAT\" | jq -er '.worker_id | select(type == \"string\" and length > 0)')\" or stop\n    CLAIM_ID=\"$(printf '%s' \"$BOUND_HEARTBEAT\" | jq -er '.claim_id | select(type == \"string\" and length > 0)')\" or stop\n    if the binding is absent, malformed, or legacy\u002Funbound: stop without typed recovery or label mutation\n    never read CLAIM_ID from the currently active claim after Wait fails; a successor may already own the same issue, worker, and branch\n    run `\"${AUTOSPEC_BIN:-autospec}\" autonomous implementer-wait-failed --repo {repo} --issue \"\u003CISSUE>\" --worker-id \"\u003CWORKER_ID>\" --branch \"\u003CBRANCH>\" --claim-id \"\u003CCLAIM_ID>\" --session-id \"\u003CACTUAL_SESSION_ID>\" --diagnostic \"\u003CREDACTED_WAIT_ERROR>\"`\n    if typed recovery exits non-zero: log the surfaced recovery failure and stop processing that issue\n    never mutate labels inline or overwrite a successor claim\n    continue  # start a fresh monitor batch from the restored auto-implement queue\n\n  # Read and consume the batch-done signal.\n  if [ -f \"$HOME\u002F.autospec\u002Fbatch-done.json\" ]; then\n    status=$(jq -r .status \"$HOME\u002F.autospec\u002Fbatch-done.json\" 2>\u002Fdev\u002Fnull || echo \"BATCH_COMPLETE\")\n    rm -f \"$HOME\u002F.autospec\u002Fbatch-done.json\"\n  else\n    status=\"BATCH_COMPLETE\"   # monitor crashed \u002F overflowed — safe to relaunch\n  fi\n\n  if [ \"$status\" = \"ALL_DONE\" ]; then\n    # Queue drained — consult explore-on-drain.sh to decide whether to\n    # auto-chain into \u002Fautospec-explore or exit normally to Phase 6.\n    # The helper encapsulates: flag check → autonomy gate → dry-well guard\n    # → per-repo cycle-cap.  It emits \"chain\" or \"stop\"; default is \"stop\".\n    # Pass AUTOSPEC_REPO so the helper scopes state to this repo without\n    # calling gh a second time (uses the same slug as the run-start reset).\n    _drain_decision=$(AUTOSPEC_REPO=\"${AUTOSPEC_REPO:-{repo}}\" \\\n        bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fexplore-on-drain.sh\")\n    if [ \"$_drain_decision\" = \"chain\" ]; then\n      echo \"[orchestrator] explore-on-drain: chaining into \u002Fautospec-explore on sandbox branch\"\n      # Record the PR merge watermark before explore starts so we can count\n      # only the PRs it ships (used by the dry-well sentinel below).\n      _eod_before=\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"\n      \u002Fautospec-explore   # runs on its own sandbox branch, NEVER main\n      # Count PRs merged by this explore cycle and write the dry-well sentinel.\n      # explore-on-drain.sh reads this before the NEXT chain decision:\n      # if the count is 0 it emits \"stop\" (dry-well guard).\n      _eod_shipped=\"$(gh pr list --state merged \\\n          --json mergedAt,labels \\\n          --jq \"[.[] | select(.mergedAt >= \\\"${_eod_before}\\\" and any(.labels[]; .name == \\\"autospec-explore\\\"))] | length\" \\\n          2>\u002Fdev\u002Fnull || echo 1)\"\n      mkdir -p \"$HOME\u002F.autospec\u002Fexplore-on-drain\u002F${_eod_slug}\"\n      printf '%s\\n' \"${_eod_shipped}\" \\\n          > \"$HOME\u002F.autospec\u002Fexplore-on-drain\u002F${_eod_slug}\u002Flast-shipped\"\n    fi\n    break   # proceed to Phase 6 final report\n  fi\n\n  batch_num=$((batch_num + 1))\n  echo \"[orchestrator] batch $((batch_num - 1)) complete — relaunching monitor with fresh context (batch ${batch_num})\"\n  # continue immediately, no sleep\n```\n\n**Continuation contract:** BATCH_COMPLETE is a continuation signal, not a terminal state. reasoning:deep may reduce a single monitor batch to one issue, but the orchestrator MUST relaunch automatically until ALL_DONE. Never tell the operator to rerun `\u002Fautospec-run` after BATCH_COMPLETE; the current invocation owns the relaunch loop until the queue is empty or a hard blocker stops it.\n\nPass the following prompt verbatim to each background subagent:\n\n> You are the auto-implement monitor for `{repo}`. Process `auto-implement` issues one at a time. Exit after processing `AUTOSPEC_BATCH_SIZE` issues (default: 1) by writing `~\u002F.autospec\u002Fbatch-done.json` — the orchestrator will relaunch you with fresh context.\n\n> **Harness adaptation (loop persistence).** The `while true:` below is pseudocode. In Claude Code, use `\u002Floop` or `ScheduleWakeup` to persist across turns. In Codex CLI and OpenCode, you lack a built-in loop primitive — implement persistence via one of these patterns:\n> 1. **Shell wrapper (preferred):** `exec bash \u003C\u003C 'EOF'\n> while true; do\n>   # ... monitor logic ...\n> done\n> EOF` — keeps a single bash process alive with your agent dispatching subcommands inside it.\n> 2. **nohup background process:** `nohup bash -c 'while true; do ...; sleep 1; done' > ~\u002F.autospec\u002Fmonitor.log 2>&1 &`\n> 3. **tmux pane:** `tmux new-window 'bash \u003C\u003C '''HEREDOC'''\n> while true; do ...; done\n> HEREDOC'`\n> **Session batching:** Exit after processing `AUTOSPEC_BATCH_SIZE` issues (default 1) by writing `~\u002F.autospec\u002Fbatch-done.json` with `status=BATCH_COMPLETE`. BATCH_COMPLETE is a continuation signal, not a terminal state; the orchestrator relaunches you with fresh context. When the queue is fully drained, write `status=ALL_DONE` instead. This keeps each monitor session short to prevent context overflow.\n\n>\n> **Profile load (run-start, once).** If `--profile \u003Cname>` was passed, look it up in `~\u002F.autospec\u002Fmodel-profiles.yml`; if `\u003Cname>` is not a key under `profiles:`, exit non-zero and print the available names. If no flag was passed, load the file's `default:` profile. If the file is missing, run auto-init and exit (per the Invocation section).\n>\n> **Missing-label warning (run-start, once).** Count open `auto-implement` issues that lack either a `ctx:*` or a `reasoning:*` label. If non-zero, print `WARN: N issues lack model-fit labels (ctx:* \u002F reasoning:*); they will be treated as ctx:64k, reasoning:medium. Run \u002Fautospec-classify to backfill.` Exactly once at run start.\n>\n> **Shared helper scripts.** Helper scripts live at `${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}` after installation. Do not assume the target repository has an autospec `scripts\u002F` directory.\n>\n> Outer loop:\n> ```\n> # Before the loop (run-once init):\n> #   batch_issue_count=0\n> #   BATCH_SIZE=\"${AUTOSPEC_BATCH_SIZE:-1}\"\n> #   [ \"$BATCH_SIZE\" -gt 0 ] 2>\u002Fdev\u002Fnull || BATCH_SIZE=1   # guard against 0 or negative\n> #   rm -f \"$HOME\u002F.autospec\u002Fbatch-done.json\"   # clear stale file from prior crash\n>\n> while true:\n>   deferred = []   # issues skipped because they exceed the active profile\n>\n>   # Startup\u002Fper-scan heartbeat reconciliation — run before candidate selection.\n>   # This deletes closed\u002Fmerged\u002Forphaned heartbeats, rejects old schemas like\n>   # {\"issue\":407,\"status\":\"in_progress\"}, normalizes current schemas, and\n>   # releases any `claimed` heartbeat older than AUTOSPEC_WATCHDOG_CLAIMED_TIMEOUT_SECS (default: 1800).\n>   if [ -d \"$HOME\u002F.autospec\u002Fprocess-heartbeats\" ]; then\n>     if command -v bash >\u002Fdev\u002Fnull 2>&1; then\n>       bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-watchdog.sh\"\n>     elif command -v pwsh >\u002Fdev\u002Fnull 2>&1; then\n>       pwsh -NoProfile -ExecutionPolicy Bypass -File \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-watchdog.ps1\"\n>     elif command -v powershell >\u002Fdev\u002Fnull 2>&1; then\n>       powershell -NoProfile -ExecutionPolicy Bypass -File \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-watchdog.ps1\"\n>     else\n>       echo \"[watchdog] neither bash nor powershell found; skipping heartbeat reconciliation.\"\n>     fi\n>   fi\n\n>   # Backlog grooming preflight — run exactly one existing-backlog grooming\n>   # cycle before each queue scan when grooming policy is auto\u002Fon. The helper\n>   # invokes autonomous-promote-open-issues.sh --apply, but mutations are still\n>   # protected by the orchestrator's double gate: --apply AND grooming policy\n>   # in {auto,on}. This is no discovery: do not run Tier 2-4 discovery and do\n>   # not file new issues from this preflight.\n>   GROOM_PREFLIGHT=\"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Frun-groom-preflight.sh\"\n>   [ -x \"$GROOM_PREFLIGHT\" ] || GROOM_PREFLIGHT=\"skills\u002Fautospec-run\u002Fscripts\u002Frun-groom-preflight.sh\"\n>   if [ -f \"$GROOM_PREFLIGHT\" ]; then\n>     bash \"$GROOM_PREFLIGHT\" \\\n>       --repo \"{repo}\" \\\n>       --report \"${AUTOSPEC_RUN_REPORT:-$HOME\u002F.autospec\u002Fautospec-run-report.md}\" || true\n>   else\n>     echo \"WARN: backlog grooming preflight helper missing; continuing drain\"\n>   fi\n\n### Queue priority sort (autospec-review interlock)\n\nWhen selecting the next `auto-implement` issue, sort:\n\n1. First: issues with label `priority:high` (e.g. `[REGRESSION]`\n   issues filed by autospec-review). Within `priority:high`, oldest\n   first.\n2. Then: all other `auto-implement` issues, oldest first.\n\n`priority:high` always wins over age. This guarantees regression\nissues unblock the queue before continuing with normal feature work.\n\n### Fab implementer routing (label → gate)\n\nDecide each claimed issue's implementer gate from its labels with the\n`fab-route.sh` helper (resolved like the other coordinator scripts):\n\n```bash\nFAB_ROUTE=\"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Ffab-route.sh\"\n[ -x \"$FAB_ROUTE\" ] || FAB_ROUTE=\"skills\u002Fautospec-run\u002Fscripts\u002Ffab-route.sh\"\nGATE=$(gh issue view \"$ISSUE\" --json labels --jq '[.labels[].name] | join(\",\")' \\\n  | bash \"$FAB_ROUTE\" --stdin)\n```\n\n- `GATE=fab` — the issue carries `area:fab` or `autospec:fab-flow`. Dispatch the\n  **fab implementer**: its full-suite gate is clean regen\n  (`rm -rf build && .venv\u002Fbin\u002Fpython src\u002Fgenerate.py`) → `stl-release-gate.py`\n  on affected models (blocking geometry stages must pass; vision is advisory) →\n  unittest, and the Primary smoke is the model's focused regression test.\n- `GATE=growth` — the issue carries `growth:artifact`. Keep the **standard\n  implementer**, and add one **content-quality gate** to Phase 4 before the\n  standard reviewer + `growth-ethics` + `autospec-secaudit` gates: run\n  `${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fgrowth-content-quality-precheck.sh`\n  on the changed content (deterministic pre-checks: keyword-density ceiling,\n  FTC-disclosure presence, citation presence), then a `TIER_A` reviewer for\n  E-E-A-T \u002F brand-voice, wrapped in the standard 5-attempt adaptive-retry loop\n  that feeds findings back as directives. A failing gate blocks merge\n  (fail-closed); it never ships unreviewed growth content. This makes the gate\n  fire for every path that reaches a `growth:artifact` issue — the autonomous\n  Tier-1 drain and `\u002Fautospec-grow-run` R1 alike.\n- `GATE=default` — every other issue keeps the standard implementer + gate.\n\nThe branch is the only difference; the fab branch's gate prose lives in\n`prompts\u002Fphase4-implementer.md`. Routing is a pure label decision (no substring\nmatch: `area:fabric` stays `default`), so it is deterministic and testable.\n\n### Distributed coordinator selection\n\nBefore choosing `ready[0]`, resolve the Rust control-plane binary:\n\n```bash\nAUTOSPEC_QUEUE_BIN=\"${AUTOSPEC_QUEUE_BIN:-${AUTOSPEC_BIN:-autospec}}\"\n```\n\nIf `--coordination-status` is active, run `autospec queue ready --repo {repo}\n--batch-size \"${AUTOSPEC_BATCH_SIZE:-1}\"`, print the JSON, and exit. If\n`--max-parallel-safe` is active, print only the `.batch` array and exit.\n\nDuring the normal monitor loop:\n\n> **Issue intent safety claim gate.** `autospec claim acquire` reads the current\n> labels and issue body, validates the reviewed Safety review block, performs the\n> label transition, and confirms the lowest-ID run-state comment. The monitor\n> never reimplements that safety or lease transition with `gh issue edit`.\n\n> **Portfolio admission and reconciliation gate.** Before the label transition,\n> `autospec claim acquire` also consults the typed portfolio graph and refuses\n> the claim (no label mutation, no run-state comment) until the issue's\n> `autospec:portfolio-item` marker is bound to its verified primary delivery\n> Project (`kind: spec_portfolio`) and every typed repository-local\n> (`Depends on issue #N`) and cross-repository\n> (`Depends on \u003Ccanonical-issue-url>`) dependency is terminal-success in its own\n> repository. Unavailable or contradictory predecessor state fails closed as\n> Blocked, and an unbound or mismatched marker blocks the claim. Admission\n> expands queue gating only; it does not change merge authority after a child\n> is admitted. Reconciliation runs after each Phase 4 lifecycle boundary\n> (claim, PR open, merge, terminal failure), after parent reconciliation, and\n> during monitor sweeps (step 2 below), so the primary Project projection and\n> dependency edges reflect the latest authoritative issue\u002FPR\u002FCI facts before\n> the next admission decision. The monitor never reimplements Project binding\n> or dependency admission with `gh` commands; a missing typed command fails\n> the monitor start visibly.\n\n0. Reconcile parents whose children may have closed outside autospec before\n   selecting work:\n   ```bash\n   _parent_slug=$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Frepo-slug.sh\" --canonical \"{repo}\")\n   export AUTOSPEC_PARENT_STATE_ROOT=\"${AUTOSPEC_PARENT_STATE_ROOT:-$HOME\u002F.autospec\u002Fparent-state\u002F$_parent_slug}\"\n   if ! \"${AUTOSPEC_BIN:-autospec}\" parent sweep --repo {repo}; then\n     echo \"[monitor] WARN: parent sweep failed; remote parent state is unknown and will be retried\" >&2\n   fi\n   ```\n1. Run `autospec queue ready --repo {repo} --batch-size \"$effective_batch_size\"`\n   after watchdog reconciliation and profile filtering.\n2. Reconcile delivery portfolios before admission: for each ready candidate\n   whose body carries an `autospec:portfolio-item` marker, run\n   `autospec portfolio reconcile --portfolio \u003CID>` (ID from the marker) so the\n   typed graph and the primary Project projection reflect the latest\n   authoritative issue\u002FPR\u002FCI facts. Candidates without a marker are outside\n   the portfolio gate. A reconcile failure fails closed: the candidate is\n   skipped this sweep and is never admitted on inferred dependency readiness.\n3. Use `.ready[0].number` as the next issue candidate.\n4. Claim it through `autospec claim acquire --issue \"$ISSUE\" --repo {repo}\n   --worker-id \"${AUTOSPEC_WORKER_ID:-\u003Cderived>}\" --branch \"\u003CBRANCH>\"`. The\n   portfolio admission gate inside the claim refuses a candidate whose primary\n   Project binding is missing or whose typed dependencies are not ready; a\n   refusal surfaces as a non-success claim exit and takes the skip-and-refresh\n   handling below.\n5. Treat claim exit `2` as a normal lost-race or conflict outcome: refresh the\n   queue and try another candidate without failing the batch.\n6. On failure, stop, or retry exhaustion, call `autospec claim release` before\n   returning `auto-implement` to the queue.\n\n### Final safety-stamp contract\n\n`autospec queue review-safety` is the only automatic writer of issue-intent\nsafety outcomes. After an admission surface persists its final issue body and\nadds interim `auto-implement`, it must invoke the exact target:\n\n```bash\nautospec queue review-safety --repo {repo} --limit 1 --issue \u003CN>\n```\n\nOnly the command's `pass: 1` total admits that invocation. The ready queue and\nclaim command consume Rust's typed passing evidence and refuse a missing,\nambiguous, or blocking result. They never reconstruct, stamp, or replace a\nsafety decision with `gh` commands or `lint issue safety` output.\n\nThe GitHub `autospec-run-state` comment written by the Rust control plane is the\ncross-workstation source of truth. Local process heartbeat files remain useful\nfor same-host progress and compatibility, but they are not authoritative across\nmachines. If the Rust command is unavailable, fail the monitor start visibly;\ndo not fall back to an inline label-swap path.\n\n>   # Deterministic outer-loop decision: stop-sentinel check, ready-queue scan,\n>   # and ALL_DONE detection are handled by the monitor-outer-loop.sh script.\n>   # The monitor invokes it at the top of each iteration and follows the\n>   # emitted action. Issue details (title, URL, labels, body) are fetched\n>   # later via issue-snapshot.sh after the claim.\n>   OUTER_LOOP_OUT=\"$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fmonitor-outer-loop.sh\" \\\n>     --repo \"{repo}\" --batch-num \"${batch_num:-1}\" --batch-issue-count \"$batch_issue_count\")\"\n>   ACTION=\"$(printf '%s' \"$OUTER_LOOP_OUT\" | awk '{print $1}' | cut -d= -f2)\"\n>   case \"$ACTION\" in\n>     claim)\n>       ISSUE=\"$(printf '%s' \"$OUTER_LOOP_OUT\" | awk '{print $2}' | cut -d= -f2)\"\n>       ;;\n>     sleep)\n>       REASON=\"$(printf '%s' \"$OUTER_LOOP_OUT\" | awk '{print $2}' | cut -d= -f2)\"\n>       echo \"[monitor] $REASON — sleeping 300s\"\n>       sleep 300\n>       continue\n>       ;;\n>     all_done)\n>       echo \"[monitor] all issues processed — writing ALL_DONE and exiting\"\n>       HARD SHUTDOWN — emit final report (incl. deferred summary, see Phase 6)\n>       ;;\n>     stop)\n>       MODE=\"$(printf '%s' \"$OUTER_LOOP_OUT\" | awk '{print $2}' | cut -d= -f2)\"\n>       echo \"[monitor] stop signal received: $MODE — exiting\"\n>       HARD SHUTDOWN with final report\n>       exit 0\n>       ;;\n>   esac\n>   # Service watch: heartbeat reconciliation already runs before each candidate scan; every 12 iterations also runs a cheap nudge\u002Freclaim pass for long-lived workers.\n>   monitor_tick=$((monitor_tick + 1))\n>   if [ \"$monitor_tick\" -ge 12 ]; then\n>     monitor_tick=0\n>     if [ -d \"$HOME\u002F.autospec\u002Fprocess-heartbeats\" ]; then\n>       # Default reclaim window: 10800s (3h). For local single-threaded workers set\n>       # AUTOSPEC_WATCHDOG_RECLAIM_SECS=43200 (12h) before launch.\n>       export AUTOSPEC_WATCHDOG_RECLAIM_SECS=\"${AUTOSPEC_WATCHDOG_RECLAIM_SECS:-10800}\"\n>       export AUTOSPEC_WATCHDOG_STALE_SECS=\"${AUTOSPEC_WATCHDOG_STALE_SECS:-1800}\"\n>       # Cheap service wake-up pass: use low-cost model only.\n>       if command -v bash >\u002Fdev\u002Fnull 2>&1; then\n>         # Dispatch one background watchdog helper (cheap model) to iterate stale entries.\n>         bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-watchdog.sh\"\n>       elif command -v pwsh >\u002Fdev\u002Fnull 2>&1; then\n>         # Windows fallback: PowerShell helper.\n>         pwsh -NoProfile -ExecutionPolicy Bypass -File \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-watchdog.ps1\"\n>       elif command -v powershell >\u002Fdev\u002Fnull 2>&1; then\n>         # Windows fallback: classic PowerShell fallback.\n>         powershell -NoProfile -ExecutionPolicy Bypass -File \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-watchdog.ps1\"\n>       else\n>         echo \"[watchdog] neither bash nor powershell found; skipping service-watch pass.\"\n>       fi\n>     fi\n>   fi\n>   # effective_batch_size probe — recomputed each outer-loop tick (not cached).\n>   # reasoning:deep may reduce a single monitor batch to one issue for fresh context.\n>   # This is not a run stop: the orchestrator MUST relaunch automatically until ALL_DONE.\n>   _next_reasoning=$(gh issue view \"${ready[0]}\" --json labels \\\n>     --jq '[.labels[].name | select(startswith(\"reasoning:\"))] | first \u002F\u002F \"reasoning:medium\"' \\\n>     2>\u002Fdev\u002Fnull || echo \"reasoning:medium\")\n>   if [ \"$_next_reasoning\" = \"reasoning:deep\" ]; then\n>     effective_batch_size=1\n>   else\n>     effective_batch_size=\"${AUTOSPEC_BATCH_SIZE:-1}\"\n>     [ \"$effective_batch_size\" -gt 0 ] 2>\u002Fdev\u002Fnull || effective_batch_size=1\n>   fi\n>   echo \"[monitor] effective_batch_size=$effective_batch_size (next issue reasoning: $_next_reasoning)\"\n>   ISSUE = ready[0]\n>   # Security prerequisite pre-dispatch gate. Re-read the live body and labels\n>   # before claim\u002Fdispatch so a post-classification edit cannot bypass the\n>   # portfolio gate. A security child is one containing any of the generated\n>   # Evidence consumed \u002F Controls covered \u002F Prerequisites headings. Its\n>   # Prerequisites section must be absent, exactly `none`, or contain only\n>   # bullet lines whose content begins `verified:`. Anything else is removed\n>   # from the ready queue and marked visibly; never dispatch it.\n>   _security_body=\"$(gh issue view \"$ISSUE\" --repo {repo} --json body --jq .body)\"\n>   if printf '%s\\n' \"$_security_body\" | grep -qE '^## (Evidence consumed|Controls covered|Prerequisites)[[:space:]]*$'; then\n>     _prerequisites=\"$(printf '%s\\n' \"$_security_body\" | awk '\n>       \u002F^## Prerequisites[[:space:]]*$\u002F {inside=1; next}\n>       \u002F^## \u002F && inside {exit}\n>       inside && NF {sub(\u002F^[[:space:]]*-[[:space:]]*\u002F, \"\"); print}\n>     ')\"\n>     if [ -n \"$_prerequisites\" ] && [ \"$_prerequisites\" != \"none\" ] \\\n>       && printf '%s\\n' \"$_prerequisites\" | grep -qv '^verified:'; then\n>       echo \"code_health:security_prerequisite_blocked issue=$ISSUE\" >&2\n>       gh issue comment \"$ISSUE\" --repo {repo} --body \\\n>         \"code_health:security_prerequisite_blocked — every security prerequisite must be verified before dispatch.\"\n>       gh issue edit \"$ISSUE\" --repo {repo} \\\n>         --remove-label auto-implement --add-label autospec:blocked-prerequisite\n>       ready = ready without ISSUE\n>       continue\n>     fi\n>   fi\n>   # Portfolio admission gate (enforced inside claim acquire, never here): the\n>   # claim is refused before label mutation until the issue's\n>   # autospec:portfolio-item marker is bound to its verified primary delivery\n>   # Project and every typed in-repo \u002F cross-repository dependency is\n>   # terminal-success. A refusal is a non-zero claim exit and takes the\n>   # skip-and-refresh path below; never re-implement binding or dependency\n>   # admission with gh commands.\n>   # Atomic claim: autospec claim acquire is the SOLE claim path. It performs the\n>   # check-and-swap (auto-implement -> in-progress-by-bot) atomically with a\n>   # read-back verification, so the hot loop NEVER re-implements the inline\n>   # label swap. Multiple monitors can race the same candidate; exactly one\n>   # wins (exit 0), the rest lose (non-zero) and skip to the next candidate.\n>   claim_json=\"$(\"$AUTOSPEC_CLAIM_BIN\" claim acquire --issue \"$ISSUE\" --repo {repo} --worker-id \"${AUTOSPEC_WORKER_ID:-$(hostname):${USER:-unknown}:monitor:$$}\" --branch \"${BRANCH:-}\" --session-id \"${WAIT_TARGET_SESSION_ID:?missing durable Wait target session binding}\")\" && claim_rc=0 || claim_rc=$?\n>   # exit 1 = hard usage error (never a race signal); exit 2 = lost race.\n>   # Split them: a misconfigured claim (rc 1 or any other non-2 non-zero) must\n>   # surface an operator-visible WARN, not masquerade as a silently-dropped\n>   # lost race (rc 2). rc 0 falls through to ownership below.\n>   if [ \"$claim_rc\" -eq 2 ]; then\n>     echo \"[monitor] claim lost for #$ISSUE (rc=$claim_rc); refreshing queue\"\n>     READY_REMOVE=$(printf \"%s\\n%s\" \"$READY_REMOVE\" \"$ISSUE\" | grep -v \"^${ISSUE}$\" || true)\n>     ready=($READY_REMOVE)\n>     continue\n>   elif [ \"$claim_rc\" -ne 0 ]; then\n>     echo \"[monitor] WARN: claim hard error for #$ISSUE (rc=$claim_rc) — usage\u002Fconfig error, NOT a lost race; skipping. Check autospec claim acquire invocation.\" >&2\n>     READY_REMOVE=$(printf \"%s\\n%s\" \"$READY_REMOVE\" \"$ISSUE\" | grep -v \"^${ISSUE}$\" || true)\n>     ready=($READY_REMOVE)\n>     continue\n>   fi\n>   # exit 0 only: this monitor now owns #$ISSUE. claim acquire has already\n>   # persisted both the per-issue heartbeat and immutable session sidecar.\n>   CLAIM_ID=\"$(printf '%s' \"$claim_json\" | jq -er '.claim_id | select(type == \"string\" and length > 0)')\" || exit 1\n>   CLAIM_WORKER_ID=\"$(printf '%s' \"$claim_json\" | jq -er '.worker_id | select(type == \"string\" and length > 0)')\" || exit 1\n>   bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fheartbeat-read.sh\" --repo \"{repo}\" --session-id \"$WAIT_TARGET_SESSION_ID\" >\u002Fdev\u002Fnull || exit 1\n>   bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fnotify.sh\" \"autospec #$ISSUE: claimed\" \"Starting implementation on {repo}\" || true\n>   # Issue start summary — print before dispatching process(ISSUE) so the operator\n>   # knows exactly what the monitor is about to work on.\n>   # Single API call — body+title+url+labels in ONE `gh issue view` (D5: duplicate-read elimination).\n>   # issue-snapshot.sh wraps that one call and caches the JSON per issue; later steps\n>   # (start summary, implementer\u002Freviewer prompt assembly) reuse the file instead of\n>   # re-fetching. --refresh: labels may have transitioned since the previous run.\n>   _issue_snapshot_file=\"$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fissue-snapshot.sh\" get \"$ISSUE\" --refresh 2>\u002Fdev\u002Fnull || true)\"\n>   _issue_body_file=\"\u002Ftmp\u002Fissue-${ISSUE}-body.md\"\n>   if [ -n \"${_issue_snapshot_file:-}\" ] && [ -f \"${_issue_snapshot_file:-}\" ]; then\n>     jq -r '.body \u002F\u002F \"\"' \"$_issue_snapshot_file\" > \"$_issue_body_file\"\n>     ISSUE_TITLE=$(jq -r '.title \u002F\u002F \"\"' \"$_issue_snapshot_file\")\n>     ISSUE_URL=$(jq -r '.url \u002F\u002F \"\"' \"$_issue_snapshot_file\")\n>     ISSUE_LABELS=$(jq -r '[.labels[]?.name] | join(\", \")' \"$_issue_snapshot_file\")\n>   else\n>     # fetch failed — fail open with empty metadata (same end state as a gh outage)\n>     : > \"$_issue_body_file\"; ISSUE_TITLE=\"\"; ISSUE_URL=\"\"; ISSUE_LABELS=\"\"\n>   fi\n>   ISSUE_GOAL=$(awk '\n>     BEGIN{in_goal=0}\n>     \u002F^## Goal[[:space:]]*$\u002F {in_goal=1; next}\n>     \u002F^## \u002F && in_goal {exit}\n>     in_goal && NF {print; exit}\n>   ' \"$_issue_body_file\")\n>   [ -n \"$ISSUE_GOAL\" ] || ISSUE_GOAL=$(awk 'NF && $0 !~ \u002F^#\u002F {print; exit}' \"$_issue_body_file\")\n>   ISSUE_SMOKE=$(awk '\n>     \u002F### Primary smoke test\u002F {seen=1; next}\n>     seen && \u002F^```\u002F {fence++; next}\n>     seen && fence==1 && NF && $0 !~ \u002F^[[:space:]]*#\u002F {print; exit}\n>   ' \"$_issue_body_file\")\n>   ISSUE_SCOPE=$(awk '\n>     \u002F^## Implementation outline[[:space:]]*$\u002F {in_scope=1; next}\n>     \u002F^## \u002F && in_scope {exit}\n>     in_scope && \u002F^- \u002F {gsub(\u002F^- \u002F,\"\"); print; count++; if (count>=3) exit}\n>   ' \"$_issue_body_file\" | paste -sd '; ' -)\n>   echo \"[monitor] starting #$ISSUE: ${ISSUE_TITLE:-\u003Cuntitled>}\"\n>   echo \"[monitor] url: ${ISSUE_URL:-\u003Cunknown>}\"\n>   echo \"[monitor] labels: ${ISSUE_LABELS:-\u003Cnone>}\"\n>   echo \"[monitor] goal: ${ISSUE_GOAL:-\u003Cnot provided>}\"\n>   echo \"[monitor] smoke: ${ISSUE_SMOKE:-\u003Cnot provided>}\"\n>   echo \"[monitor] scope: ${ISSUE_SCOPE:-\u003Cnot provided>}\"\n>   process(ISSUE)   # single-agent absorbed-discipline — the monitor IS the implementer; see template below\n>   batch_issue_count=$((batch_issue_count + 1))\n>   if [ \"$batch_issue_count\" -ge \"${effective_batch_size:-$BATCH_SIZE}\" ]; then\n>     bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fdiary-write.sh\" \\\n>       --phase 4 --event monitor-exit \\\n>       --body \"Monitor BATCH_COMPLETE: batch=${batch_num:-1} processed=$batch_issue_count repo={repo}\" \\\n>       2>\u002Fdev\u002Fnull || true\n>     printf '{\"batch\":%s,\"processed\":%s,\"repo\":\"%s\",\"ts\":%s,\"status\":\"BATCH_COMPLETE\"}\\n' \\\n>       \"${batch_num:-1}\" \"$batch_issue_count\" \"{repo}\" \"$(date -u +%s)\" \\\n>       > \"$HOME\u002F.autospec\u002Fbatch-done.json\"\n>     echo \"[monitor] batch ${batch_num:-1}: processed $batch_issue_count\u002F${effective_batch_size:-$BATCH_SIZE} issues — writing batch-done.json and exiting for fresh context\"\n>     exit 0\n>   fi\n>   # Immediate next-issue pickup: NO SLEEP after process(ISSUE). Re-enter the top\n>   # of this loop immediately so the fresh queue scan can pick any issue unblocked\n>   # by the merge or failure cleanup that just completed.\n> ```\n>\n> ### Parallel implementer worktree isolation\n>\n> Background `Agent` implementers in the same git workdir collide on `git checkout`\n> even when their file-level scopes are disjoint — first agent to call\n> `git checkout -b \u003CBRANCH>` wins; the second lands on the wrong branch and must\n> recover via cherry-pick. File-level disjointness is necessary but NOT sufficient\n> for parallel safety; the collision is at the git-branch level.\n>\n> When dispatching multiple Phase 4 implementers in parallel, the orchestrator\n> MUST wrap each dispatch via `dispatch-implementer.sh` (or an inline\n> equivalent that produces the same contract):\n>\n> 1. Create a per-issue worktree at `\u002Ftmp\u002Fwt-\u003CBRANCH>` off `origin\u002Fmain` via\n>    `git worktree add -b \u003CBRANCH> \u002Ftmp\u002Fwt-\u003CBRANCH> origin\u002Fmain`.\n> 2. Pre-pend the implementer prompt with an explicit workdir directive naming\n>    `\u002Ftmp\u002Fwt-\u003CBRANCH>` and forbidding `cd`\u002F`git checkout` into the main checkout\n>    or sibling branches.\n> 3. On agent completion, remove the worktree via\n>    `git worktree remove --force \u002Ftmp\u002Fwt-\u003CBRANCH>` (defer cleanup until the PR\n>    has merged so the worktree stays available for retries).\n>\n> Sequential dispatch in the main checkout is the safe default; worktree-isolated\n> parallel dispatch is the only safe parallelism. See `dispatch-implementer.sh`\n> and `tests\u002Fautospec-run\u002Ftest_parallel_dispatch.bats` for the canonical contract.\n>\n> ### Sandbox branch contract (autospec-explore PR-base integration)\n>\n> When `.autospec\u002Fexplore-mode.json` is present (written by\n> `explore-sandbox.sh`), the Phase 4 implementer MUST target the sandbox\n> branch from that file's `branch` field as PR base instead of `main`, and MUST\n> refuse `gh pr merge` against `main` while the file is present (refusal\n> identifier: `code_health:explore_main_merge_refused`). The full contract lives\n> in `skills\u002Fautospec-run\u002Fprompts\u002Fphase4-implementer.md` under \"Sandbox branch\n> contract\" and \"No accidental main merges\"; the trio enforces it via lockstep.\n>\n> ### Implementer prompt selection (turbo-integration routing)\n>\n> Before dispatching, read the issue's labels:\n>\n> ```bash\n> labels=$(gh issue view \u003CISSUE> --json labels --jq '[.labels[].name] | join(\",\")')\n> ```\n>\n> - **If `labels` contains `autospec:v2-flow`** — load the prompt template from `skills\u002Fautospec-run\u002Fprompts\u002Fphase4-implementer.md` (relative to this skill's install location, or via `AUTOSPEC_SKILLS_DIR`\u002Fthe harness's skill mount). That prompt embeds the absorbed-discipline path: expand → implement → finalize → peer-review (via `codex exec`) → evaluate-findings. **Wire the D3 cached prefix (spec Phase 2 child C):** do NOT send the `phase4-implementer.md` body alone — prepend the `gen-implementer-prompt.sh` static cached prefix so the default v2 path stops re-reading SKILL.md + AGENTS.md + the RULE_ID table uncached. Assemble the combined v2 prompt by handing `phase4-implementer.md` to `--body-file`, which forwards it to `bundle-static-context.sh --static-body` so it lands INSIDE the cached prefix. It is one fixed template, so emitting it below the boundary re-sent it uncached on every dispatch and every retry:\n>   ```bash\n>   # Reuse the single body fetch written at process(ISSUE) start (D5).\n>   v2_combined_prompt=$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fgen-implementer-prompt.sh\" \\\n>     --issue-body \"\u002Ftmp\u002Fissue-\u003CISSUE>-body.md\" \\\n>     --branch \"\u003CBRANCH>\" \\\n>     --issue-labels \"\u003CISSUE_LABELS>\" \\\n>     --repo \"\u003CREPO>\" \\\n>     --body-file \"skills\u002Fautospec-run\u002Fprompts\u002Fphase4-implementer.md\")\n>   ```\n>   `gen-implementer-prompt.sh` emits the static cached prefix (framed by `\u003C!-- CACHE BOUNDARY -->` markers, containing SKILL.md + AGENTS.md + RULE_ID table + tag-filtered saved-memory) first; the `phase4-implementer.md` body and the issue assignment ride below it as the dynamic suffix. Pass the prefix block (up to and including the closing `\u003C!-- CACHE BOUNDARY -->`) with `cache_control: { type: \"ephemeral\" }` so Anthropic's prompt cache reuses it across dispatches in the same monitor session. This only changes prompt **assembly\u002Fcaching** — the implementer's absorbed-discipline BEHAVIOR (every step in `phase4-implementer.md`) is unchanged.\n>   UI\u002Fclient-interaction issues handled by that prompt must record exactly one\n>   browser verification state in the PR body's `## Validation` section:\n>   `browser-verified`, `fallback-smoke-only`, or `not-run`. Harness-caused\n>   Browser connector skips that produce `fallback-smoke-only` or `not-run` must\n>   open or link a browser remediation issue with the redacted error detail before\n>   merge.\n> - **Otherwise** — use the legacy inline prompt below (current behavior). Legacy path is retained until every pre-v2 issue has drained.\n>\n> Both paths share the same outer monitor loop (queue scan, lock-step compliance, label-based locking, heartbeat updates, post-process pickup). The selection only changes the inner subagent prompt body.\n>\n> `process(ISSUE)` is single-agent absorbed-discipline: the monitor agent performs the implementation work itself, in-context, using the prompt below as its working brief. There is NO nested subagent dispatch here — subagents spawned by background `Agent` calls do NOT inherit the `Agent` tool, so the monitor must own the work directly:\n>\n> **Prompt construction (cache-prefix + dynamic suffix):**\n> Before dispatch, the orchestrator builds the subagent prompt. Two options:\n>\n> **Option A (recommended): `gen-implementer-prompt.sh`** — standalone assembler:\n>    ```bash\n>    # Reuse the single body fetch written at process(ISSUE) start (D5).\n>    combined_prompt=$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fgen-implementer-prompt.sh\" \\\n>      --issue-body \"\u002Ftmp\u002Fissue-\u003CISSUE>-body.md\" \\\n>      --branch \"\u003CBRANCH>\" \\\n>      --issue-labels \"\u003CISSUE_LABELS>\" \\\n>      --repo \"\u003CREPO>\")\n>    ```\n>\n> **Option B (legacy): `bundle-and-dispatch.sh`** — wraps bundle-static-context internally:\n>\n> 1. **Static cached prefix + dynamic suffix** — call `bundle-and-dispatch.sh` to assemble the combined prompt:\n>    ```bash\n>    # Write dynamic suffix to a temp file first\n>    _suffix_file=$(mktemp -t autospec-suffix-XXXXXX.txt)\n>    trap 'rm -f \"$_suffix_file\"' EXIT\n>    printf '%s\\n' \"\u003CISSUE_BODY_AND_DIRECTIVES>\" > \"$_suffix_file\"\n>    combined_prompt=$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fbundle-and-dispatch.sh\" \\\n>      --role implementer \\\n>      --issue-labels \"\u003CISSUE_LABELS>\" \\\n>      --dynamic-suffix-file \"$_suffix_file\")\n>    ```\n>    `bundle-and-dispatch.sh` calls `bundle-static-context.sh` internally to emit the static cached\n>    prefix (framed by `\u003C!-- CACHE BOUNDARY -->` markers, containing implementer-contract.md +\n>    the AGENTS.md quality-contract section with the RULE_ID table + lockstep rules +\n>    implementer scaffolding + the --static-body template), then appends the tag-filtered\n>    saved-memory and the dynamic suffix after the closing marker. The prefix does NOT hold\n>    SKILL.md itself, and saved-memory is deliberately below the marker because it is\n>    label-filtered and so cannot be byte-stable.\n>    Pass the prefix block (up to and including the closing `\u003C!-- CACHE BOUNDARY -->`) with\n>    `cache_control: { type: \"ephemeral\" }` so Anthropic's prompt cache can reuse it across\n>    dispatches in the same monitor session (5-min TTL).\n>\n> 2. **Dynamic uncached suffix** — appended by `bundle-and-dispatch.sh` after the cached prefix:\n>    the issue body, per-iteration findings (if retry > 1), branch name, and \"begin coding now\".\n>\n> 3. **Resolve the implementer model (deterministic — do this before dispatching)** — the issue's\n>    `reasoning:*` label decides which profile implements it, and the profile carries the concrete\n>    model id. Ask the selector rather than deciding yourself:\n>    ```bash\n>    _impl_model=$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fselect-model-profile.sh\" \\\n>      --labels \"\u003CISSUE_LABELS>\" \\\n>      --print-model) || _impl_model=\"\"\n>    ```\n>    If `_impl_model` is **non-empty**, dispatch the implementer subagent with that model in place of\n>    the harness-detected `TIER_B`. If the selector exits 3 (empty output — no `model:` key is\n>    resolvable, which is the case for an auto-initialised `~\u002F.autospec\u002Fmodel-profiles.yml`), keep\n>    `TIER_B` exactly as detected. Never invent a model id, and never widen this override:\n>    - It applies to the **implementer dispatch only**. The reviewer keeps its own tier — a reviewer\n>      must never run on a weaker model than the implementer it is checking.\n>    - The fall-back-**up** rule still holds: if the resolved model is unavailable at dispatch time\n>      (quota, capacity, authorization), silently retry the same dispatch at `TIER_B`, then `TIER_A`.\n>\n> The combined prompt sent to the subagent is:\n>\n> ```\n> **Model tier:** `TIER_B` (implementation work) — cheaper model with medium thinking; resolved at startup. Silently fall back to `TIER_A` if unavailable.\n>\n> **Hard limits.** Max 40 tool calls per issue. Max 3 self-review iterations. If you rewrite the same file twice with no test progress, abort: comment the blocker on the issue, release the lock label, exit. No wall-clock cap.\n>\n> Implement GitHub issue #\u003CISSUE>: \"\u003CTITLE>\" on {repo}. Spec is the issue body below.\n>\n> ===ISSUE BODY===\n> \u003CBODY>\n> ===END===\n>\n> ## Team personality as execution lens\n>\n> Read the issue body's **Team personality** section before choosing an\n> approach. Let that team shape what you emphasize: a reliability\u002Fbackend team\n> should scrutinize operational safety and data boundaries, a frontend\u002Fproduct\n> team should scrutinize user workflow and accessibility, a security-sensitive\n> team should scrutinize trust boundaries and abuse cases, and so on. Do not\n> invent extra scope; use the team personality to decide which risks deserve\n> extra attention while still satisfying the issue's concrete acceptance\n> criteria.\n>\n> Keep a progress heartbeat so the monitor can prove forward movement:\n> - Create\u002Fupdate `~\u002F.autospec\u002Fprocess-heartbeats\u002F\u003Crepo-slug>\u002F\u003CISSUE>.json` at each major step:\n>   - `claimed`, `expand_start`, `worktree_ready`, `tests_started`, `tests_passed`, `pr_created`, `smoke_retry`, `reviewed`, `merged`, `failed`\n> - Recovery-bound schema: `{\"issue\":\"\u003CISSUE>\",\"branch\":\"\u003CBRANCH>\",\"step\":\"\u003CSTEP>\",\"ts\":\u003Cunix_epoch>,\"pr\":\"\u003CPR>\",\"repo\":\"{repo}\",\"host\":\"\u003CHOST>\",\"worker_id\":\"\u003CWORKER_ID>\",\"claim_id\":\"\u003CCLAIM_ID>\",\"session_id\":\"\u003CWAIT_TARGET_SESSION_ID>\"}`. `heartbeat-write.sh` creates the exact-session sidecar once: an identical identity refresh preserves it, while any session\u002Fissue\u002Fworker\u002Fbranch\u002Fclaim mismatch fails closed before updating liveness. Legacy heartbeats without that sidecar remain valid only for liveness and fail closed for Wait recovery.\n> - Delete this file on terminal SUCCESS\u002FFAILURE in both clean and failure paths.\n> - Transition notifications: on `tests_passed`, `pr_created`, `merged`, and `failed` call\n>   `bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fnotify.sh\" \"\u003Ctitle>\" \"\u003Cbody>\" || true`\n>   once per transition. Dedup with `_notify_fired=\"\"` (reset per issue) and the pattern\n>   `case \"$_notify_fired\" in *:\u003CSTEP>:*) ;; *) _notify_fired=\"${_notify_fired}:\u003CSTEP>:\"; bash ... || true ;; esac`.\n>\n> ## Project rules you MUST honor\n>\n> \u003Cverbatim concatenation of relevant feedback_*.md bodies — injected by bundle-static-context.sh --role implementer before dispatch>\n>\n> ## RULE_IDs (from AGENTS.md ## Implementation-quality contract)\n>\n> \u003Cverbatim RULE_ID table from AGENTS.md — injected by bundle-static-context.sh --role implementer>\n>\n> ## Acceptance criteria as constraints\n>\n> \u003Cverbatim AC checkbox list from issue body — every checkbox must be green before push>\n>\n> 0. **Heartbeat refresh at expand start.** The very first action before any expand work (reading files, pattern survey, verifying paths) is to refresh the heartbeat to `expand_start`. This covers the claim→worktree_ready window: the monitor wrote `claimed` when it dispatched you; without this refresh the watchdog may falsely reclaim the issue during a long expand phase.\n>    ```bash\n>    bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fheartbeat-write.sh\" \\\n>      --issue \"\u003CISSUE>\" --branch \"${BRANCH:-}\" --step expand_start --repo \"{repo}\" \\\n>      --worker-id \"$CLAIM_WORKER_ID\" --claim-id \"$CLAIM_ID\" --session-id \"$WAIT_TARGET_SESSION_ID\"\n>    ```\n> 1. **PR-aware recovery ladder, then worktree.** Resolve the branch state FIRST, then act on the verdict. NEVER `cd`\u002F`git checkout`\u002F`git commit` in the primary checkout — all work happens in a linked worktree off `origin\u002Fmain`.\n>    \u003C!-- worktree-ladder:begin -->\n>    ```bash\n>    cd {repo_root} && git fetch origin\n>    LADDER=$(bash ${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fworktree-guard.sh resolve-branch --branch \u003CBRANCH> --repo {repo})\n>    STATE=$(printf '%s' \"$LADDER\" | sed -n 's\u002F.*\"state\":\"\\([^\"]*\\)\".*\u002F\\1\u002Fp')\n>    PR=$(printf '%s' \"$LADDER\" | sed -n 's\u002F.*\"pr\":\\([0-9]*\\).*\u002F\\1\u002Fp')\n>    case \"$STATE\" in\n>      open-pr)\n>        # #886 recovery: a PR already exists. SKIP implementation entirely.\n>        # Check out the existing PR in a fresh worktree, run the issue's\n>        # verification (tests + validate.sh) and the standard review loop\n>        # against the EXISTING PR, then merge if green. Never re-implement.\n>        bash ${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fworktree-guard.sh create --branch \u003CBRANCH> --path \u002Ftmp\u002Fwt-\u003CBRANCH> --adopt\n>        cd \u002Ftmp\u002Fwt-\u003CBRANCH>\n>        gh pr checkout \"$PR\"\n>        echo \"[ladder] open-pr #$PR — skip implementation; verify + review + merge existing PR\"\n>        ;;\n>      branch-only)\n>        # #917 recovery: the branch exists with un-PR'd work. Adopt it in a\n>        # fresh worktree and CONTINUE the remaining work (do not start over).\n>        bash ${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fworktree-guard.sh create --branch \u003CBRANCH> --path \u002Ftmp\u002Fwt-\u003CBRANCH> --adopt\n>        cd \u002Ftmp\u002Fwt-\u003CBRANCH>\n>        echo \"[ladder] branch-only — adopted \u003CBRANCH>; continue remaining work\"\n>        ;;\n>      fresh|*)\n>        # No branch, no PR: create a new worktree off origin\u002Fmain.\n>        bash ${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fworktree-guard.sh create --branch \u003CBRANCH> --path \u002Ftmp\u002Fwt-\u003CBRANCH>\n>        cd \u002Ftmp\u002Fwt-\u003CBRANCH>\n>        echo \"[ladder] fresh — created \u003CBRANCH>\"\n>        ;;\n>    esac\n>    # Reset repo-local state roots after entering the issue worktree. Parent\n>    # autospec-run processes may export AUTOSPEC_REPO_DIR for the primary\n>    # checkout; premerge\u002Fvalidation helpers must read mutable artifacts such as\n>    # .autospec\u002Fqa-verdict.json from this active worktree instead.\n>    export AUTOSPEC_REPO_DIR=\"$PWD\"\n>    # MANDATORY assert gate: MUST exit 0 before the first file edit\u002Fcommit. A\n>    # non-zero exit (in_primary_checkout \u002F dirty \u002F stale_base \u002F wrong_branch) is NEVER worked\n>    # around — comment the emitted code_health identifier on the issue, restore\n>    # the `auto-implement` label (swap `in-progress-by-bot` → `auto-implement`),\n>    # remove the heartbeat, and stop this issue.\n>    if ! bash ${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fworktree-guard.sh assert --expected-branch \u003CBRANCH> --branch-pattern 'feat\u002F*'; then\n>      gh issue comment \u003CISSUE> --body \"worktree-guard assert failed (see code_health identifier above); restoring auto-implement\"\n>      gh issue edit \u003CISSUE> --remove-label in-progress-by-bot --add-label auto-implement\n>      exit 1\n>    fi\n>    ```\n>    \u003C!-- worktree-ladder:end -->\n>    On the `open-pr` path the verification bar EQUALS fresh work — full tests + the standard review loop, never a blind merge. Cleanup is identical for every path: after the merge is confirmed (or on terminal failure), `git worktree remove` the linked worktree and `git worktree prune`; never delete un-pushed work before merge.\n\u003C!-- autospec-block:runtime-resource-preflight -->\n> 1b. **Claim the edit surface (claim-guard), nested inside the issue claim.** After the `worktree-guard.sh assert` gate passes and BEFORE the first file edit, take a fine-grained lease on the skill(s)\u002Fpaths this issue will touch so a concurrent session in another worktree cannot stomp the same trio+golden surface. This is the inner layer of the three-layer caller pattern (worktree-guard → claim-guard scan → claim-guard acquire); it composes with — and sits inside — the issue-level lease you already hold. Set `TARGETS` to the space-separated skill names and\u002For repo-relative paths the issue's **Files touched** lists.\n>    \u003C!-- claim-guard-acquire:begin -->\n>    ```bash\n>    TARGETS=\"\u003Cspace-separated skills\u002Fpaths from the issue's Files touched>\"\n>    bash ${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fworktree-guard.sh assert --expected-branch \u003CBRANCH> --branch-pattern 'feat\u002F*' || exit $?\n>    bash ${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fclaim-guard.sh scan $TARGETS || true\n>    if ! AUTOSPEC_CLAIM_GUARD=strict bash ${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fclaim-guard.sh acquire $TARGETS; then\n>      gh issue comment \u003CISSUE> --body \"claim-guard acquire conflict (see code_health:claim_conflict identifier above); another live session owns this edit surface — restoring auto-implement\"\n>      gh issue edit \u003CISSUE> --remove-label in-progress-by-bot --add-label auto-implement\n>      exit 6\n>    fi\n>    ```\n>    \u003C!-- claim-guard-acquire:end -->\n>    `scan` is advisory (it warns on overlapping open PRs \u002F worktrees \u002F live claims but never blocks); `acquire` is all-or-nothing and exits `6` on `claim_conflict`. Hold this lease across the whole edit+test+PR step. **Refresh rides the existing heartbeat tick** — at each heartbeat write also run `bash ${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fclaim-guard.sh refresh` (no new loop) so a slow-but-live editor is never reclaimed. **Release on PR open**: immediately after `gh pr create` succeeds, run `bash ${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fclaim-guard.sh release $TARGETS` (the lease has served its purpose once the work is captured in a PR). `AUTOSPEC_CLAIM_GUARD=off` or an unwritable store degrades the whole block to a no-op and NEVER blocks the issue.\n> 2. TDD per AGENTS.md: failing test first → implement → refactor → commit. NO DB\u002Fexternal mocks. Follow file paths and signatures from the issue body verbatim.\n> 3. **Full test suite gate.** Run the target repo's full validation\u002Ftest suite, not only the Primary smoke test. Command resolution order:\n>    1. If `AUTOSPEC_FULL_TEST_COMMAND` is set, run `bash -lc \"$AUTOSPEC_FULL_TEST_COMMAND\"`.\n>    2. Else run every command listed under the issue's **Operator\u002Ffull verification** section.\n>    3. Else run the repo-standard full suite: `autospec validate` when present; otherwise use the ecosystem default (`npm test`, `pytest`, `go test .\u002F...`, `cargo test --no-fail-fast`, `mvn test`, etc.). The suite must run every target to completion — cargo gets `--no-fail-fast`, pytest must NOT carry `-x`\u002F`--maxfail`, and `go test` must NOT carry `-failfast` — or the pass\u002Ffail evidence is a truncated run.\n>    If the full suite fails, fix the failure, recommit, rerun the full suite, and repeat. Do NOT dispatch LGTM review while the full suite is failing. Do NOT run `gh pr merge` while the full suite is failing. Record the exact full-suite command and passing output summary in the PR comment or final report.\n>    Once the suite first passes, fire the transition notification: `case \"$_notify_fired\" in *:tests_passed:*) ;; *) _notify_fired=\"${_notify_fired}:tests_passed:\"; bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fnotify.sh\" \"autospec #\u003CISSUE>: tests_passed\" \"Full suite green on {repo}\" || true ;; esac`\n> 3a. **autospec-test gate** (run when `skills\u002Fautospec-test\u002Fscripts\u002Frun-gate.sh` exists in the repo): invoke the gate against the PR's target repo root. Handle exit codes per spec §7a\u002F§7b:\n>    ```bash\n>    GATE_SCRIPT=\"skills\u002Fautospec-test\u002Fscripts\u002Frun-gate.sh\"\n>    if [ -f \"$GATE_SCRIPT\" ] && [ -f \".autospec\u002Ftest.yml\" ]; then\n>      GATE_JSON_OUT=$(mktemp -t autospec-gate-XXXXXX.json)\n>      trap 'rm -f \"$GATE_JSON_OUT\"' EXIT\n>      bash \"$GATE_SCRIPT\" . --output-gate \"$GATE_JSON_OUT\" --pr \"\u003CPR>\" --repo \"{repo}\" || GATE_EXIT=$?\n>      case \"${GATE_EXIT:-0}\" in\n>        0) echo \"[gate] autospec-test: passed\" ;;\n>        1) echo \"[gate] autospec-test: blocked — PR comment posted, labels applied; continuing review loop\" ;;\n>        2) echo \"[gate] autospec-test: fatal (exit 2) — halt batch\"; exit 2 ;;\n>      esac\n>    fi\n>    ```\n>    Exit 0: proceed to merge. Exit 1: block PR (post comment + labels; do NOT merge; treat as review finding). Exit 2: halt entire batch (comment on issue, label `in-progress-by-bot` → `auto-implement`, exit monitor).\n> 3b. \u003C!-- docs-drift-gate:begin -->\n> ## Docs drift gate\n> Run after autospec-test gate, before LGTM review. Skip if issue body contains a line matching `^docs:\\s*skip\\s*$` (case-insensitive). On `drift`\u002F`missing_scope`\u002F`example_stale` the classifier emits the pinned `regenerate` action carrying the affected scopes; the gate self-heals by invoking `\u002Fautospec-doc` (via `doc-orchestrator.mjs`) scoped to ONLY those scopes, re-verifying the regenerated pages with `verify-examples.mjs`, and committing `docs: regenerate \u003Cscopes>` onto the SAME PR branch. **Doc generation NEVER blocks the code PR** — generation\u002Fverification failure only warns, applies the `docs:failed` label, and comments; the code review loop continues. Only the regenerate commit's own example verification gates the regenerated docs (failing pages are NOT committed):\n>    ```bash\n>    if ! grep -qiE '^docs:[[:space:]]*skip[[:space:]]*$' \"\u002Ftmp\u002Fissue-\u003CISSUE>-body.md\" 2>\u002Fdev\u002Fnull; then\n>      SCRIPTS_DIR=\"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\"\n>      DOC_SCRIPTS_DIR=\"${AUTOSPEC_DOC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fskills\u002Fautospec-doc\u002Fscripts}\"\n>      DRIFT_JSON=\"$(bash \"$SCRIPTS_DIR\u002Fcheck-doc-drift.sh\" --pr \"\u003CPR>\" 2>\u002Ftmp\u002Fdrift-\u003CPR>.err)\"; drift_exit=$?\n>      if [ \"$drift_exit\" = \"0\" ]; then\n>        : # no drift — continue to LGTM\n>      else\n>        # drift_exit 1 (drift\u002Fexample_stale) or 2 (missing_scope): classify, then\n>        # self-heal in-PR when the classifier emits the `regenerate` action.\n>        VERDICT_JSON=\"$(printf '%s' \"$DRIFT_JSON\" | node \"$SCRIPTS_DIR\u002Floop-classifier-docs-extension.mjs\" --drift-json - --issue \"\u003CISSUE>\" --pr \"\u003CPR>\" 2>\u002Fdev\u002Fnull || true)\"\n>        ACTION=\"$(printf '%s' \"$VERDICT_JSON\" | node -e 'let s=\"\";process.stdin.on(\"data\",d=>s+=d).on(\"end\",()=>{try{process.stdout.write((JSON.parse(s).action)||\"\")}catch{}})' 2>\u002Fdev\u002Fnull || true)\"\n>        if [ \"$ACTION\" = \"regenerate\" ]; then\n>          # Scopes the classifier flagged — always extract for labelling\u002Freporting.\n>          mapfile -t SCOPES \u003C \u003C(printf '%s' \"$VERDICT_JSON\" | node -e 'let s=\"\";process.stdin.on(\"data\",d=>s+=d).on(\"end\",()=>{try{for(const x of (JSON.parse(s).scopes||[]))console.log(x)}catch{}})' 2>\u002Fdev\u002Fnull || true)\n>          gh issue edit \u003CISSUE> --add-label \"docs:drift\" 2>\u002Fdev\u002Fnull || true\n>          # Resolve the auto_regenerate switch (D2 gate conditional).\n>          # Reads config from .autospec\u002Fautospec.yml, issue body from single-fetch file, and\n>          # AUTOSPEC_WITH_DOCS env. Precedence: docs:skip (already handled above) >\n>          # docs:generate > config auto_regenerate=true > AUTOSPEC_WITH_DOCS=1 > default-off.\n>          _REGEN=$(node --input-type=module \u003C\u003C'__REGEN_EOF__' 2>\u002Fdev\u002Fnull || echo \"0\"\n>          import { resolveAutoRegenerate, loadConfig } from '${AUTOSPEC_DOC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fskills\u002Fautospec-doc\u002Fscripts}\u002Fdoc-config.mjs';\n>          import fs from 'node:fs';\n>          const cfg = (() => { try { return loadConfig('.autospec\u002Fautospec.yml'); } catch { return {}; } })();\n>          const body = (() => { try { return fs.readFileSync('\u002Ftmp\u002Fissue-\u003CISSUE>-body.md','utf8'); } catch { return ''; } })();\n>          const flag = process.env.AUTOSPEC_WITH_DOCS === '1';\n>          const { generate } = resolveAutoRegenerate({ config: cfg, issueBody: body, withDocsFlag: flag });\n>          process.stdout.write(generate ? '1' : '0');\n> __REGEN_EOF__\n>          )\n>          if [ \"${_REGEN:-0}\" = \"1\" ]; then\n>            # auto_regenerate is ON — run the regenerate self-heal path.\n>            doc_ok=1\n>            if node \"$DOC_SCRIPTS_DIR\u002Fdoc-orchestrator.mjs\" 2>\u002Ftmp\u002Fdocgen-\u003CPR>.err; then\n>              # Re-verify regenerated pages; only verified pages are committed.\n>              if [ \"${#SCOPES[@]}\" -gt 0 ] && node \"$DOC_SCRIPTS_DIR\u002Fverify-examples.mjs\" \"${SCOPES[@]}\" 2>\u002Ftmp\u002Fdocverify-\u003CPR>.err; then\n>                if ! git diff --quiet -- \"${SCOPES[@]}\" 2>\u002Fdev\u002Fnull; then\n>                  git add -- \"${SCOPES[@]}\"\n>                  git commit -m \"docs: regenerate ${SCOPES[*]}\" || doc_ok=0\n>                  git push || doc_ok=0\n>                fi\n>              else\n>                doc_ok=0  # example verification failed — do NOT commit regenerated docs\n>              fi\n>            else\n>              doc_ok=0    # generation failed\n>            fi\n>            if [ \"$doc_ok\" = \"0\" ]; then\n>              gh issue edit \u003CISSUE> --add-label \"docs:failed\" 2>\u002Fdev\u002Fnull || true\n>              gh pr comment \u003CPR> --body \"$(printf 'docs: regenerate self-heal failed (generation or example verification) — code PR NOT blocked. Scopes: %s' \"${SCOPES[*]:-\u003Cnone>}\")\" 2>\u002Fdev\u002Fnull || true\n>            else\n>              gh pr comment \u003CPR> --body \"$(printf 'docs: regenerated %s in-PR (examples re-verified).' \"${SCOPES[*]:-\u003Cnone>}\")\" 2>\u002Fdev\u002Fnull || true\n>            fi\n>          else\n>            # auto_regenerate is OFF — log and continue; detection\u002Flabels already applied.\n>            echo \"docs: regeneration skipped (auto_regenerate=false)\"\n>          fi\n>        else\n>          # No regenerate verdict — surface drift for operator review; do not block.\n>          gh pr comment \u003CPR> --body \"$(printf 'docs drift detected — no self-heal action emitted:\\n\\n```json\\n%s\\n```' \"$DRIFT_JSON\")\" 2>\u002Fdev\u002Fnull || true\n>          gh issue edit \u003CISSUE> --add-label \"docs:drift\" 2>\u002Fdev\u002Fnull || true\n>          if [ \"$drift_exit\" = \"2\" ]; then gh issue edit \u003CISSUE> --add-label \"docs:missing-scope\" 2>\u002Fdev\u002Fnull || true; fi\n>        fi\n>      fi\n>    else\n>      gh pr comment \u003CPR> --body \"docs: drift check skipped (docs:skip in issue body)\" 2>\u002Fdev\u002Fnull || true\n>      gh issue edit \u003CISSUE> --add-label \"docs:skipped\" 2>\u002Fdev\u002Fnull || true\n>    fi\n>    ```\n>    \u003C!-- docs-drift-gate:end -->\n> 4. \u003C!-- RETRY-LOOP:begin --> Adaptive commit loop (MAX_IMPL_RETRIES):\n>    ```bash\n>    attempt=1\n>    MAX_IMPL_RETRIES=\"${MAX_IMPL_RETRIES:-5}\"\n>    directive_context=\"\"\n>    while [ \"$attempt\" -le \"$MAX_IMPL_RETRIES\" ]; do\n>      # Conventional commits (feat:\u002Ffix:\u002Ftest:\u002Fdocs:\u002Frefactor:). NEVER bypass hooks. NEVER amend.\n>      if git commit -m \"\u003Cconventional-commit-message>\"; then\n>        # pre-commit hook passed — verify AC bats tests are green\n>        if bats tests\u002Fac\u002Fissue-\u003CISSUE>.bats 2>\u002Fdev\u002Fnull; then\n>          break  # success\n>        fi\n>        # AC tests still failing — treat as lint failure, roll back commit\n>        git reset HEAD~1\n>      fi\n>      # Capture lint directives for next attempt\n>      findings=$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Flint-implementation.sh\" --pre-commit --staged --directives 2>\u002Fdev\u002Fnull || true)\n>      if [ -n \"$findings\" ]; then\n>        directive_context=\"${directive_context}\n>\n> ## Retry attempt ${attempt} findings\n> ${findings}\n>\n> Fix these BEFORE the next code generation.\"\n>      fi\n>      attempt=$((attempt + 1))\n>    done\n>    if [ \"$attempt\" -gt \"$MAX_IMPL_RETRIES\" ]; then\n>      gh issue comment \u003CISSUE> --body \"Implementer hit max retries; manual intervention needed\"\n>      gh issue edit \u003CISSUE> --remove-label \"auto-implement-active\" 2>\u002Fdev\u002Fnull || true\n>      exit 1\n>    fi\n>    ```\n>    \u003C!-- RETRY-LOOP:end -->\n> 4a. \u003C!-- pr-size-pre-push:begin --> **Deterministic PR_SIZE pre-push gate.**\n>    Define this helper in the monitor shell and run it before any remote mutation:\n>    ```bash\n>    # pr-size-helper:begin\n>    run_pr_size_gate() {\n>      # Takes no arguments. A harness substitutes its slash-command argument\n>      # into $1\u002F$2\u002F$3 when it renders this skill body, so reading positionals\n>      # here would let a caller's argument overwrite the gate's own inputs\n>      # (issue #3101). Inputs arrive as named variables set by the call site.\n>      if [ -z \"${PR_SIZE_PHASE:-}\" ] || [ -z \"${PR_SIZE_BASE_OID:-}\" ] \\\n>        || [ -z \"${PR_SIZE_HEAD_OID:-}\" ]; then\n>        printf 'ERROR:PR_SIZE: missing PR_SIZE_PHASE\u002FPR_SIZE_BASE_OID\u002FPR_SIZE_HEAD_OID\\n'\n>        return 1\n>      fi\n>      PR_SIZE_DIFF=$(mktemp -t autospec-pr-size-XXXXXX.diff) || return 1\n>      git diff --binary \"$PR_SIZE_BASE_OID\" \"$PR_SIZE_HEAD_OID\" >\"$PR_SIZE_DIFF\" || {\n>        rm -f \"$PR_SIZE_DIFF\"\n>        return 1\n>      }\n>      PR_SIZE_RC=0\n>      PR_SIZE_OUTPUT=$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Flint-implementation.sh\" \\\n>        --diff-file \"$PR_SIZE_DIFF\" --issue \u003CISSUE>) || PR_SIZE_RC=$?\n>      rm -f \"$PR_SIZE_DIFF\"\n>      printf '%s\\n' \"$PR_SIZE_OUTPUT\"\n>      if [ \"$PR_SIZE_RC\" -ne 0 ] || printf '%s\\n' \"$PR_SIZE_OUTPUT\" | grep -q '^ERROR:PR_SIZE:'; then\n>        printf 'ERROR:PR_SIZE: %s rejected exact diff %s..%s\\n' \\\n>          \"$PR_SIZE_PHASE\" \"$PR_SIZE_BASE_OID\" \"$PR_SIZE_HEAD_OID\"\n>        return 1\n>      fi\n>      printf '%s\\n' 'INFO:PR_SIZE: acceptance'\n>    }\n>    # pr-size-helper:end\n>    # pr-size-pre-push-exec:begin\n>    PR_SIZE_PHASE=pre-push\n>    PR_SIZE_BASE_OID=$(git merge-base \"origin\u002F${AUTOSPEC_BASE_BRANCH:-main}\" HEAD) || exit 1\n>    PR_SIZE_HEAD_OID=$(git rev-parse HEAD) || exit 1\n>    PR_SIZE_EVIDENCE=$(run_pr_size_gate) || {\n>      printf '%s\\n' \"$PR_SIZE_EVIDENCE\"\n>      exit 1\n>    }\n>    printf '%s\\n' \"$PR_SIZE_EVIDENCE\"\n>    printf '%s\\n' \"$PR_SIZE_EVIDENCE\" | grep -qxF 'INFO:PR_SIZE: acceptance' || exit 1\n>    # pr-size-pre-push-exec:end\n>    ```\n>    The deterministic linter rejects the first over-limit values: **401 changed lines**,\n>    **9 raw files**, or **4 logical units**. On rejection, preserve the branch and do not\n>    run `git push`, `gh pr create`, `gh pr ready`, or any merge command.\n>    \u003C!-- pr-size-pre-push:end -->\n> 5. Push: git push -u origin \u003CBRANCH>\n>    ```bash\n>    # Stop-sentinel: abort if an immediate stop flag is present after this step.\n>    if ! bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-stop-check.sh\" \"$ISSUE\" \"$BRANCH\" \"$LAST_STEP\"; then\n>      exit 0\n>    fi\n>    ```\n> 6. PR: build the body deterministically instead of writing it out — the closing\n>    reference, the change list, and the verification line are all already in the\n>    branch, and restating them costs output tokens to reproduce what git holds:\n>    ```bash\n>    # mktemp, not a fixed \u002Ftmp\u002F...-\u003CISSUE> path: two implementers working the same\n>    # issue NUMBER in different repos would otherwise overwrite each other's body.\n>    PR_SUMMARY_FILE=$(mktemp -t autospec-pr-summary-XXXXXX) || exit 1\n>    PR_BODY_FILE=$(mktemp -t autospec-pr-body-XXXXXX) || exit 1\n>    # Write ONLY the summary — the part no template can derive: what this change\n>    # does and which alternative it rejected. Everything else is assembled.\n>    # A quoted heredoc, because the summary is MULTI-PARAGRAPH markdown: printf\n>    # '%s\\n' would flatten it to one line, and any literal % in it is a format\n>    # string. 'EOF' is quoted so backticks and $ in the prose are not expanded.\n>    cat > \"$PR_SUMMARY_FILE\" \u003C\u003C'PR_SUMMARY_EOF'\n>    \u003Csummary>\n>    PR_SUMMARY_EOF\n>    bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fcompose-pr-body.sh\" \\\n>      --issue \"\u003CISSUE>\" --summary-file \"$PR_SUMMARY_FILE\" \\\n>      > \"$PR_BODY_FILE\" || exit 1\n>    ```\n>    Exit 3 from the composer means the commit range is empty: do NOT run\n>    `gh pr create`, and investigate why the branch has no commits.\n>    Then — BEFORE `gh pr create` — assert the composed body actually carries the\n>    closing keyword. A merged PR without it leaves its issue open: finished work\n>    becomes indistinguishable from pending work. A title-style `(#\u003CISSUE>)`\n>    reference is NOT equivalent; GitHub auto-closes only on the body keyword.\n>    ```bash\n>    bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fcompose-pr-body.sh\" \\\n>      --assert-closes \"$PR_BODY_FILE\" || exit 1\n>    ```\n>    Exit 4 means the body carries no `Closes #\u003CISSUE>` keyword: do NOT run\n>    `gh pr create`.\n>    Then: gh pr create --base main --head \u003CBRANCH> --title \"\u003CTITLE>\" --body-file \"$PR_BODY_FILE\". Capture PR. Immediately after the PR opens, release the claim-guard lease taken in step 1a: `bash ${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fclaim-guard.sh release $TARGETS`.\n>    Fire the transition notification: `case \"$_notify_fired\" in *:pr_created:*) ;; *) _notify_fired=\"${_notify_fired}:pr_created:\"; bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fnotify.sh\" \"autospec #\u003CISSUE>: pr_created\" \"PR #\u003CPR> opened on {repo}\" || true ;; esac`\n>    After the LLM subagent returns, record telemetry (tokens JSON written by the harness to `.autospec\u002Ftokens-\u003CISSUE>.json` if present):\n>    ```bash\n>    if [ -f \".autospec\u002Ftokens-\u003CISSUE>.json\" ]; then\n>      bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Frecord-telemetry.sh\" \\\n>        --dispatch-id \"\u003CDISPATCH_ID>\" --role implementer --issue \"\u003CISSUE>\" \\\n>        --tokens-json \".autospec\u002Ftokens-\u003CISSUE>.json\"\n>    fi\n>    ```\n> 7. Inner loop (max 3 iterations):\n>    ```bash\n>    # Stop-sentinel: abort if an immediate stop flag is present after this step.\n>    if ! bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-stop-check.sh\" \"$ISSUE\" \"$BRANCH\" \"$LAST_STEP\"; then\n>      exit 0\n>    fi\n>    ```\n>    - Run the **Primary smoke test** from the issue body. If it fails, fix and recommit before review.\n>    - Run the **Full test suite gate** before fused guardian + LGTM review. If it fails, fix and recommit, rerun the full suite, and do not dispatch review until the full suite passes.\n>    - **Fused guardian + LGTM review** (one subagent does both — saves one dispatch per inner-loop iteration):\n>      \u003C!-- guardian-block:begin -->\n>      Run deterministic lint first (no subagent cost):\n>        rm -f \u002Ftmp\u002Fguardian-\u003CPR>.md\n>        if [ \"${AUTOSPEC_NO_GUARDIAN:-0}\" != \"1\" ]; then\n>          bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Flint-implementation.sh\" \u003CPR> --issue \u003CISSUE> >> \u002Ftmp\u002Fguardian-\u003CPR>.md 2>&1\n>        fi\n>        det_exit=$?\n>\n>      Reuse lens (issues #1439\u002F#1440\u002F#1442): when armed, extract the reuse-triage\n>      RULE_IDs from the deterministic findings so the reviewer prompt receives the\n>      build-vs-buy block. Flag-OFF or no reuse hits → `_reuse_flags_file` stays empty\n>      → the reviewer prompt is byte-identical to today (the `${_reuse_flags_file:+…}`\n>      expansion below adds nothing):\n>        ```bash\n>        _reuse_flags_file=\"\"\n>        if [ \"${AUTOSPEC_REUSE_LENS:-}\" = \"1\" ] && [ -f \u002Ftmp\u002Fguardian-\u003CPR>.md ]; then\n>          _reuse_candidate=$(mktemp -t autospec-reuse-flags-XXXXXX)\n>          grep -E '^(REINVENT_REPO_UTIL|NEW_DEP_UNJUSTIFIED|NEW_ABSTRACTION_SINGLE_CALLER):' \\\n>            \u002Ftmp\u002Fguardian-\u003CPR>.md > \"$_reuse_candidate\" 2>\u002Fdev\u002Fnull || true\n>          if [ -s \"$_reuse_candidate\" ]; then _reuse_flags_file=\"$_reuse_candidate\"; fi\n>        fi\n>        ```\n>\n>      **Model tier:** `TIER_B` for ALL issues — including `regression` and `priority:high`. The single fused reviewer carries the regression gap-check (see brief below), so no second Tier-A pass is dispatched. **Escape hatch:** `AUTOSPEC_REVIEWER_TIER` overrides the reviewer tier — unset (or any value other than `opus`) → `TIER_B` (sonnet); set `AUTOSPEC_REVIEWER_TIER=opus` to restore `TIER_A` for the reviewer. Silently fall back to `TIER_A` if `TIER_B` is unavailable. For a fixed-role model binding, use a fresh configurable `TIER_A` independent reviewer rather than retrying the same unavailable binding. The replacement must receive the byte-equivalent assembled prompt and evidence, inspect the current head independently, and return the same byte-exact `LGTM`\u002Ffindings contract. The orchestrator writes reviewer metadata (`requested_model`, `actual_model`, `fallback_reason`, `head_sha`) to a sidecar evidence artifact, never to the verdict channel. Availability fallback never converts substantive findings into `LGTM`; if the replacement cannot run, block the merge.\n>\n>      **Assemble reviewer prompt** — call `gen-reviewer-prompt.sh` to compose the combined prompt (static cached prefix + dynamic suffix):\n>      ```bash\n>      # Reuse the single body fetch from process(ISSUE) start (D5).\n>      # SHA-gated diff re-fetch: only re-fetch the PR diff when the branch head changed.\n>      _current_head=$(gh pr view \u003CPR> --json headRefOid --jq .headRefOid 2>\u002Fdev\u002Fnull || echo \"\")\n>      if [ -z \"${_reviewer_pr_diff_file:-}\" ] || [ \"${_reviewer_last_head:-}\" != \"$_current_head\" ]; then\n>        _reviewer_pr_diff_file=$(mktemp -t autospec-pr-diff-XXXXXX.diff)\n>        gh pr diff \u003CPR> > \"$_reviewer_pr_diff_file\"\n>        _reviewer_last_head=\"$_current_head\"\n>      fi\n>      combined_reviewer_prompt=$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fgen-reviewer-prompt.sh\" \\\n>        --pr-diff \"$_reviewer_pr_diff_file\" \\\n>        --issue-body \"\u002Ftmp\u002Fissue-\u003CISSUE>-body.md\" \\\n>        --prev-findings \"\u002Ftmp\u002Fguardian-\u003CPR>.md\" \\\n>        --issue-labels \"\u003CISSUE_LABELS>\" \\\n>        --repo \"\u003CREPO>\" \\\n>        ${_reuse_flags_file:+--reuse-flags \"$_reuse_flags_file\"})\n>      ```\n>      Pass `combined_reviewer_prompt` as the reviewer subagent prompt. The static cached prefix is framed by `\u003C!-- CACHE BOUNDARY -->` markers; pass it with `cache_control: { type: \"ephemeral\" }` so Anthropic's prompt cache can reuse it across inner-loop iterations.\n>\n>      Dispatch ONE **foreground subagent** with this brief:\n>        > You are the implementation reviewer for PR #\u003CPR> on {repo}, closing issue #\u003CISSUE>.\n>        >\n>        > ## Review counter-team as review lens\n>        >\n>        > Read the issue body's **Review counter-team** section before reviewing.\n>        > Review from that independent team's perspective and challenge likely blind spots\n>        > from the implementation team's **Team personality**. Stay inside the issue\n>        > scope: do not request unrelated rewrites, but do raise findings when the PR\n>        > misses risks the counter-team was selected to notice.\n>        >\n>        > **Part 1 — Guardian (contract compliance)** — skip if `AUTOSPEC_NO_GUARDIAN=1`:\n>        > 1. Read AGENTS.md `## Implementation-quality contract` for the RULE_ID table and directive map.\n>        > 2. Read issue #\u003CISSUE> body — note `## Implementation scope`, `## Implementation outline`, `## Tests required`, and any `Guardian: skip-*` lines.\n>        > 3. Read deterministic findings in \u002Ftmp\u002Fguardian-\u003CPR>.md (populated by lint-implementation.sh; may be empty if guardian disabled).\n>        > 4. Run `gh pr diff \u003CPR>` and `gh pr view \u003CPR> --json files,title,body`.\n>        > 5. Apply LLM-tier RULE_IDs (HALLUCINATED_API, DUPLICATE_CODE, STRING_MATCH_DOMAIN_LOGIC, REPEATED_STRUCTURE_AS_CODE, DOC_OUT_OF_SYNC semantic pass, INVENTED_CONFIG). For DUPLICATE_CODE, explicitly search for existing components, helpers, validators, API clients, request wrappers, error banners, fixtures, and test utilities before accepting new generated code. For STRING_MATCH_DOMAIN_LOGIC, flag any function that encodes domain meaning via substring-on-name checks when the file already imports a proper-representation library (Python rdkit\u002Fast\u002Furllib.parse\u002Fdatetime\u002Fipaddress\u002Flxml\u002Fjsonschema; JS\u002FTS URL\u002FDate\u002FAST\u002Fzod\u002Fajv\u002Fjoi; Go net\u002Furl\u002Ftime\u002Fgo\u002Fast\u002Fnet.ParseIP; Java java.net.URI\u002Fjava.time\u002FJavaParser\u002Fjavax.validation; Scala java.net.URI\u002Fjava.time\u002Fscalameta\u002Frefined\u002Fcirce; Rust url::Url\u002Fchrono\u002Ftime\u002Fsyn\u002Fstd::net::IpAddr\u002Fserde). For REPEATED_STRUCTURE_AS_CODE, flag any function whose body has ≥5 branches sharing identical structural shape (Python if\u002Felif, Java\u002FScala switch\u002Fmatch, Rust match arms, Go switch cases, JS if\u002Felse) — direct the implementer to extract into a table + single dispatcher loop. For each new component, module, function, endpoint, worker, hook, or test helper, require a spec-linked reason, reuse check, public contract, proof test, and \"what breaks if wrong\" answer. Collect as `RULE_ID:\u003Cpath>:\u003Cline>: \u003Cdesc>`. Honor `Guardian: skip-*` with `INFO:` lines.\n>        >\n>        > **Part 2 — LGTM (correctness review):** Using the same diff and issue body already in context:\n>        > 6. Check correctness, edge cases, missing tests, AGENTS.md compliance (TDD, no mocks, conventional commits), whether every new code unit exists for a concrete issue\u002Fspec requirement rather than convenience, and whether deprecated routes, caches, buckets, stores, workers, config keys, UI paths, docs, specs, tests, or fixtures were removed instead of revived to make tests pass.\n>        > 6a. For anything touching authentication, signing, encryption, or credential handling: ask \"Is this crypto\u002Fdependency defending against a party who can actually reach this data path, or is it re-proving what the transport already proved?\" If TLS to a named host, a process boundary, or an existing gate already establishes the property, flag the re-establishment. The reverse also holds: if a token could arrive by another route (forwarded by a client, read from a header), it must be verified properly, and that boundary must be pinned by a comment at the code.\n>        > 7. Collect findings as a numbered list.\n>        > 8. Critical self-question before LGTM: \"What else could still pass here while the real user workflow fails, and how could this be better?\" Check especially mocked-vs-deployed behavior, external service assumptions, fallback paths, user-visible outcomes, and missing no-mock smoke coverage. If the answer is actionable inside the issue scope, emit it as a finding or required test.\n>      \u003C!-- guardian-block:end -->\n>        > 8a. **data-scope invariant lens (diagnostic\u002Ffilter endpoints):** When the issue touches endpoints, dashboards, reports, or diagnostics that accept optional job\u002Fsample\u002Ffilter parameters, verify filters never widen to unrelated records. empty optional filters reject unless documented as a deliberate all-records mode. Require concrete evidence for `job-only`, `sample-only`, `job+sample`, `unsupported-filter`, and `empty-filter` paths; unsupported-filter and empty-filter cases must prove rejection or a documented scoped response, not silent broadening.\n>        > 9. **Regression gap-check (MANDATORY for `regression`\u002F`priority:high` issues; skip otherwise):** ask \"would the reviewer have caught the original gap?\" If the fused review as written would NOT have caught the gap this regression closes, add the missing checklist item(s) to `reports\u002Fautospec-review\u002Freviewer-lessons.md` (one entry per item, with parent `gap_id` and date) and apply those new checks to this diff before issuing the verdict. This folds the former second-pass regression meta-review into this single reviewer pass — the reviewer-lessons write-path is preserved here; there is no second Tier-A dispatch.\n>        >\n>        > **Hard limit:** max **25 tool calls total** (Parts 1 + 2 combined). If budget exhausted, append `RULE_ID:OUT_OF_SCOPE: reviewer budget exhausted; PR needs human review` and proceed to verdict.\n>        >\n>        > **Simplicity axis is ADVISE-only (anti-gold-plating):** the reuse \u002F build-vs-buy \u002F \"how could this be better?\" axis may argue only toward *less* code — reuse a named existing util (`scripts\u002Flib\u002F`, repo source), adopt a named library, or delete an unneeded abstraction — and only when tied to a named acceptance criterion. It may NEVER emit a `BLOCK` that demands *more* code, a new abstraction, or speculative generality; such suggestions are at most `ADVISE` and never halt the commit. Every reuse verdict must name the matched util or library (evidence-bound), never assert a match from belief.\n>        >\n>        > **Verdict:** If Part 1 has ZERO blocking findings (INFO lines OK) AND Part 2 has no findings: return ONLY the token: `LGTM`. Otherwise return a numbered findings list — RULE_ID findings first, then LGTM findings. A reuse `BLOCK` is provisional until it survives the refute pass below.\n>\n>      **Reuse-BLOCK refute pass (before consuming the verdict):** If the findings list contains a build-vs-buy \u002F reuse `BLOCK`, do NOT halt on it yet. Dispatch a **cheap refute pass** — one short `TIER_B` second voter (≤5 tool calls) whose only job is to *kill* the BLOCK: `rg`-search the repo for the named util\u002Flibrary and confirm the claimed reuse target actually exists, is reachable, and fits this call site. **Majority rules:** keep the BLOCK only if the refuter also upholds it; if the refuter refutes it (the named target is absent, unreachable, or ill-fitting), demote that BLOCK to `ADVISE`, drop it from the blocking findings, and continue. If demotion leaves no remaining blocking findings, treat the verdict as `LGTM`. This keeps a hallucinated \"library exists\" from stalling the merge (`feedback_llm_validator_adaptive_retry`). **Record the outcome of this reuse `BLOCK` decision to the reuse-lens ledger HERE** (issue #1442) — at the decision point, so precision = upheld ÷ total is computed only over real reuse BLOCKs and never from phantom rows on clean passes. Set `_reuse_block_raised=1`, `_reuse_trigger` to the flagged RULE_ID, and `_reuse_upheld=true` when the refuter upheld the BLOCK or `_reuse_upheld=false` when it was refuted\u002Fdemoted-to-ADVISE, then:\n>      **Draw the refuter from a different vendor than the proposer.** Two dispatches to the same model family share failure modes and tend to be wrong together, which is the one case this second vote exists to catch — so resolve the refuter's vendor before dispatching it, passing the harness you detected in step 1 of Phase 0 as `--proposer`:\n>        ```bash\n>        REFUTE_VENDOR=$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fverify-voter-vendor.sh\" \\\n>          --proposer \"\u003CHARNESS>\") || REFUTE_VENDOR=\n>        ```\n>        Run the refute pass on `$REFUTE_VENDOR`'s own `TIER_B` — vendor is the independence lever, tier is the quality lever, and this changes only the former. An **empty** `REFUTE_VENDOR` (exit 3: single-harness host, or every alternative already failed over) means keep the same-harness `TIER_B` refuter: a same-vendor second vote is weaker than a cross-vendor one but still better than none, and the script refuses to name the proposer's own vendor rather than report an independence the host cannot provide.\n>        **On a quota failure, re-resolve rather than give up.** If the refuter's dispatch fails with a 429 \u002F quota \u002F capacity error, call the script again adding `--unavailable \u003Cthat vendor>` and dispatch to what it returns; a 429 is the only ground-truth quota signal available, since `usage-observe.sh` reports `observable=false` for all three harnesses. Repeat until it exits 3, then fall back to the same-harness refuter.\n>        ```bash\n>        if [ \"${AUTOSPEC_REUSE_LENS:-}\" = \"1\" ] && [ \"${_reuse_block_raised:-0}\" = \"1\" ]; then\n>          bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Finterrogation-ledger.sh\" record \\\n>            --issue \"\u003CISSUE>\" --pr \"\u003CPR>\" --trigger \"${_reuse_trigger:-REINVENT_REPO_UTIL}\" \\\n>            --verdict BLOCK --upheld \"${_reuse_upheld:-true}\" \\\n>          || true  # write failure is best-effort; never blocks the PR\n>        fi\n>        ```\n>\n>      If `LGTM` && det_exit == 0:\n>        gh pr comment \u003CPR> --body \"\u003C!-- guardian-block --> Review: clean. \u003C!-- \u002F-->\"\n>        run **Full test suite gate** and record the exact full-suite command and passing output summary\n>        bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fci-wait.sh\" \u003CPR>  # fire-and-forget sentinel\n>        if [ -f \".autospec\u002Ftokens-\u003CISSUE>-reviewer.json\" ]; then\n>          bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Frecord-telemetry.sh\" \\\n>            --dispatch-id \"\u003CDISPATCH_ID>-reviewer\" --role reviewer --issue \"\u003CISSUE>\" \\\n>            --tokens-json \".autospec\u002Ftokens-\u003CISSUE>-reviewer.json\"\n>        fi\n>        # Reuse-lens verdict is recorded at the refute-pass decision point above\n>        # (issue #1442), not here — recording in this LGTM-only branch produced\n>        # phantom BLOCK rows on clean passes and never recorded upheld BLOCKs.\n>        # monitor exits to parking state HERE — orchestrator relaunches when ~\u002F.autospec\u002Fci-state\u002F\u003CPR>.signal settles\n>        # On relaunch: run ci-wait-poll.sh \u003CPR>; break SUCCESS if exit 0 (pass)\n>        break SUCCESS only if the full suite passed and required checks pass.\n>      If `LGTM` but det_exit != 0:\n>        Treat deterministic findings as blocking. Comment, fix, recommit, push. Continue inner loop.\n>      If findings list:\n>        gh pr comment \u003CPR> --edit-last --body \"\u003C!-- guardian-block:begin -->\\n## Review findings (iter \u003CK>\u002F3)\\n\u003Cfindings>\\n\u003C!-- guardian-block:end -->\"\n>        Append findings to implementer retry context. Continue inner loop (counts toward 3-iter cap).\n>      On 3-iter exhaustion with non-LGTM:\n>        gh label create guardian-blocked --color e11d21 --force --repo {repo}\n>        gh issue edit \u003CISSUE> --add-label guardian-blocked\n>        Run failure cleanup (comment, swap label, close PR).\n>        rm -f \u002Ftmp\u002Fguardian-\u003CPR>.md\n>      \u003C!-- guardian-block:end -->\n>    - **Regression coverage** for `regression`\u002F`priority:high` issues is handled inside the single fused reviewer brief (Part 2 item 9 above): the reviewer self-asks \"would the reviewer have caught the original gap?\", writes any missing checks to `reports\u002Fautospec-review\u002Freviewer-lessons.md`, and applies them before its verdict. No second Tier-A dispatch.\n>    - If LGTM: break SUCCESS.\n>    ```bash\n>    # Stop-sentinel: abort if an immediate stop flag is present after this step.\n>    if ! bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-stop-check.sh\" \"$ISSUE\" \"$BRANCH\" \"$LAST_STEP\"; then\n>      exit 0\n>    fi\n>    ```\n> 8. SUCCESS: Run the **rebase-and-retest pre-merge gate** before admin-merging. Addresses cross-session CI rot (issue #307): two PRs each green against pre-merge main can together break main, so we re-prove this PR against post-merge main. Cap is `AUTOSPEC_REBASE_MAX_ATTEMPTS` (default 3). The gate ends with the admin-merge, so do NOT issue a second merge after the block.\n>    ```bash\n>    max_attempts=\"${AUTOSPEC_REBASE_MAX_ATTEMPTS:-3}\"\n>    attempt=0\n>    # Advisory checks (e.g. self-hosted TeamCity) are operator-declared via\n>    # AUTOSPEC_PR_ADVISORY_CHECKS, defaulting to the same regex the conductor's\n>    # main-health gate already honors (AUTOSPEC_MAIN_HEALTH_IGNORE_CHECKS) —\n>    # one shared definition. Unset\u002Fempty (\"^$\") matches no real check name, so\n>    # default behavior is unchanged: every FAILURE blocks.\n>    adv=\"${AUTOSPEC_PR_ADVISORY_CHECKS:-${AUTOSPEC_MAIN_HEALTH_IGNORE_CHECKS:-^$}}\"\n>    wait_for_ci_green() {\n>        while :; do\n>            rollup=$(gh pr view \u003CPR> --json statusCheckRollup --jq '.statusCheckRollup \u002F\u002F []')\n>            pending=$(printf '%s' \"$rollup\" | jq --arg adv \"$adv\" '[.[] | select((((.name \u002F\u002F .context \u002F\u002F \"\") as $n | $n != \"\" and ($n | test($adv)))) | not) | select(.conclusion == null)] | length')\n>            bad=$(printf '%s' \"$rollup\" | jq --arg adv \"$adv\" '[.[] | select((((.name \u002F\u002F .context \u002F\u002F \"\") as $n | $n != \"\" and ($n | test($adv)))) | not) | select(.conclusion==\"FAILURE\" or .conclusion==\"CANCELLED\" or .conclusion==\"TIMED_OUT\" or .conclusion==\"ACTION_REQUIRED\")] | length')\n>            total=$(printf '%s' \"$rollup\" | jq 'length')\n>            if [ \"$bad\" != \"0\" ]; then\n>                # Distinguish inherited base-branch CI rot from branch-caused failures\n>                # before blocking. Capture the PR head rollup and the current base\n>                # commit's check\u002Fstatus contexts as merge evidence, then let\n>                # ci-status-compare.sh emit classification plus blocked_branch and\n>                # blocked_inherited arrays for the PR comment\u002Ffinal report.\n>                base_sha=$(gh pr view \u003CPR> --json baseRefOid --jq .baseRefOid)\n>                head_checks=\"\u002Ftmp\u002Fautospec-ci-head-\u003CPR>.json\"\n>                base_checks=\"\u002Ftmp\u002Fautospec-ci-base-\u003CPR>.json\"\n>                base_check_runs=\"\u002Ftmp\u002Fautospec-ci-base-check-runs-\u003CPR>.json\"\n>                base_statuses=\"\u002Ftmp\u002Fautospec-ci-base-statuses-\u003CPR>.json\"\n>                compare_json=\"\u002Ftmp\u002Fautospec-ci-compare-\u003CPR>.json\"\n>                printf '%s\\n' \"$rollup\" > \"$head_checks\"\n>                gh api \"repos\u002F{repo}\u002Fcommits\u002F$base_sha\u002Fcheck-runs\" --paginate \\\n>                  --jq '[.check_runs[] | {name, conclusion, status, detailsUrl: .details_url}]' \\\n>                  > \"$base_check_runs\"\n>                gh api \"repos\u002F{repo}\u002Fcommits\u002F$base_sha\u002Fstatus\" \\\n>                  --jq '[.statuses[] | {context, state, targetUrl: .target_url}]' \\\n>                  > \"$base_statuses\"\n>                jq -s 'add' \"$base_check_runs\" \"$base_statuses\" > \"$base_checks\"\n>                bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fci-status-compare.sh\" \\\n>                  --head \"$head_checks\" --base \"$base_checks\" > \"$compare_json\"\n>                classification=$(jq -r '.classification' \"$compare_json\")\n>                target_url=$(jq -r '.target_url \u002F\u002F \"\"' \"$compare_json\")\n>                case \"$classification\" in\n>                  inherited)\n>                    gh issue comment \u003CISSUE> --body \"PR #\u003CPR>: required checks are red, but ci-status-compare classified them as inherited base-branch CI rot (blocked_inherited). Merge evidence: ${target_url:-see attached rollup}; compare artifact: \\`$compare_json\\`. Pausing for operator review instead of marking the branch broken.\"\n>                    exit 1\n>                    ;;\n>                  branch_caused)\n>                    gh issue comment \u003CISSUE> --body \"PR #\u003CPR>: required checks failed and ci-status-compare classified them as branch-caused (blocked_branch). Merge evidence: ${target_url:-see attached rollup}; compare artifact: \\`$compare_json\\`.\"\n>                    exit 1\n>                    ;;\n>                  *)\n>                    gh issue comment \u003CISSUE> --body \"PR #\u003CPR>: required checks looked bad but ci-status-compare returned \\`$classification\\`; pausing for operator review. Compare artifact: \\`$compare_json\\`.\"\n>                    exit 1\n>                    ;;\n>                esac\n>            fi\n>            if [ \"$total\" != \"0\" ] && [ \"$pending\" = \"0\" ]; then return 0; fi\n>            sleep 30\n>        done\n>    }\n>    while [ \"$attempt\" -lt \"$max_attempts\" ]; do\n>        state=$(gh pr view \u003CPR> --json mergeStateStatus --jq .mergeStateStatus)\n>        # mergeStateStatus values: CLEAN | BEHIND | BLOCKED | DIRTY | HAS_HOOKS | UNKNOWN | UNSTABLE\n>        case \"$state\" in\n>            CLEAN|HAS_HOOKS|UNSTABLE) break ;;\n>            BEHIND)\n>                if ! gh pr update-branch \u003CPR>; then\n>                    gh issue comment \u003CISSUE> --body \"PR #\u003CPR>: \\`gh pr update-branch\\` failed (auth\u002Fapi\u002Fconflict). Pausing for operator review.\"\n>                    exit 1\n>                fi\n>                wait_for_ci_green\n>                ;;\n>            DIRTY)\n>                gh issue comment \u003CISSUE> --body \"PR #\u003CPR> has a merge conflict against main; needs human resolution.\"\n>                exit 1\n>                ;;\n>            BLOCKED) sleep 30; wait_for_ci_green ;;\n>            *) sleep 15 ;;\n>        esac\n>        attempt=$((attempt + 1))\n>    done\n>    if [ \"$attempt\" -ge \"$max_attempts\" ]; then\n>        gh issue comment \u003CISSUE> --body \"PR #\u003CPR>: rebase-and-retest stalled after $max_attempts attempts; main is moving faster than CI completes. Pausing for operator review.\"\n>        exit 1\n>    fi\n>    # Mandatory final local proof after the branch is current with main.\n>    # Run the **Full test suite gate** here using the same command resolution order\n>    # (`AUTOSPEC_FULL_TEST_COMMAND`, Operator\u002Ffull verification, then `autospec validate` fallback).\n>    # If it fails, fix the failure, recommit, push, rerun the full suite and review, and do NOT run `gh pr merge`.\n>    #\n>    # Final quality gate (pre-merge, fail-closed): after the full suite passes and\n>    # before admin-merging, discover repository-specific whole-workspace quality\n>    # commands and run each one from the target repo root. Discovery covers every\n>    # language whose marker is present, not only Rust:\n>    #   1. If AUTOSPEC_FINAL_QUALITY_COMMAND is set it OVERRIDES discovery: that\n>    #      command is the only one run, and no marker is inspected.\n>    #   2. Otherwise `discover-quality-commands.sh` emits one `marker\u003CTAB>command`\n>    #      line per present marker - Cargo.toml -> `cargo clippy --workspace --all-targets -- -D warnings`,\n>    #      `*.sh` -> shellcheck, package.json -> `npm run lint`, pyproject.toml ->\n>    #      `ruff check`, go.mod -> `go vet .\u002F... && golangci-lint run`.\n>    #   3. A marker present whose linter is NOT installed is never a silent pass:\n>    #      the gate fails closed with rule=\u003Clanguage>-unavailable before running anything.\n>    # Treat every discovered command as required merge evidence. Do NOT run `gh pr merge` while the final quality gate is failing.\n>    # On failure, post\u002Fcomment a\n>    # `FINAL_QUALITY_GATE_FAILED` block that includes the command plus one finding\n>    # record with `crate`, `file`, `line`, and `rule` fields (use `unknown` only when\n>    # the tool output genuinely omits a field), then return to the fix\u002Frecommit\u002Fretry\n>    # loop and rerun the full suite plus final quality gate before merge.\n>    _QG=\"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fdiscover-quality-commands.sh\"\n>    # Fail closed first: a present marker whose linter is absent blocks the merge.\n>    bash \"$_QG\" --missing-tools > \u002Ftmp\u002Fautospec-quality-missing.txt\n>    if [ -s \u002Ftmp\u002Fautospec-quality-missing.txt ]; then\n>      IFS=\"$(printf '\\t')\" read -r _marker _cmd _lang _tool \u003C \u002Ftmp\u002Fautospec-quality-missing.txt\n>      gh issue comment \u003CISSUE> --body \"FINAL_QUALITY_GATE_FAILED command=$_cmd crate=unknown file=$_marker line=1 rule=${_lang}-unavailable tool=$_tool\"\n>      exit 1\n>    fi\n>    # Run every discovered command from the repo root. Cargo.toml is skipped in this\n>    # loop because the Rust-specialized block below runs clippy exactly once and\n>    # parses its diagnostics into crate\u002Ffile\u002Fline\u002Frule.\n>    bash \"$_QG\" > \u002Ftmp\u002Fautospec-quality-commands.txt\n>    while IFS=\"$(printf '\\t')\" read -r _marker _cmd; do\n>      if [ \"$_marker\" = \"Cargo.toml\" ]; then continue; fi\n>      sh -lc \"$_cmd\" || {\n>        gh issue comment \u003CISSUE> --body \"FINAL_QUALITY_GATE_FAILED command=$_cmd crate=unknown file=$_marker line=unknown rule=quality-command-failed\"\n>        exit 1\n>      }\n>    done \u003C \u002Ftmp\u002Fautospec-quality-commands.txt\n>    # The Rust marker keeps its specialized evidence path; the override skips it too.\n>    if [ -z \"${AUTOSPEC_FINAL_QUALITY_COMMAND:-}\" ]; then\n>    if [ -f Cargo.toml ]; then\n>      if ! command -v cargo >\u002Fdev\u002Fnull 2>&1; then\n>        gh issue comment \u003CISSUE> --body \"FINAL_QUALITY_GATE_FAILED command=cargo-metadata crate=unknown file=Cargo.toml line=1 rule=cargo-unavailable\"\n>        exit 1\n>      fi\n>      if ! cargo metadata --no-deps --format-version=1 >\u002Ftmp\u002Fautospec-cargo-metadata.json 2>\u002Ftmp\u002Fautospec-cargo-metadata.err; then\n>        _metadata_err=$(tr '\n' ' ' \u003C\u002Ftmp\u002Fautospec-cargo-metadata.err | sed 's\u002F[[:space:]][[:space:]]*\u002F \u002Fg; s\u002F^ \u002F\u002F; s\u002F $\u002F\u002F' | cut -c1-500)\n>        gh issue comment \u003CISSUE> --body \"FINAL_QUALITY_GATE_FAILED command=cargo-metadata crate=unknown file=Cargo.toml line=1 rule=${_metadata_err:-metadata-failed}\"\n>        exit 1\n>      fi\n>      if ! cargo clippy --workspace --all-targets -- -D warnings >\u002Ftmp\u002Fautospec-final-quality-clippy.log 2>&1; then\n>        # Preserve raw clippy output and summarize the first diagnostic in a stable schema for reviewers.\n>        _crate=$(jq -r '.packages[0].name \u002F\u002F \"unknown\"' \u002Ftmp\u002Fautospec-cargo-metadata.json 2>\u002Fdev\u002Fnull || printf 'unknown')\n>        _location=$(grep -m1 -E '^[[:space:]]*-->' \u002Ftmp\u002Fautospec-final-quality-clippy.log | sed -E 's\u002F^[[:space:]]*-->[[:space:]]*\u002F\u002F' || true)\n>        _file=$(printf '%s' \"$_location\" | awk -F: '{print $1}')\n>        _line=$(printf '%s' \"$_location\" | awk -F: '{print $2}')\n>        _rule=$(grep -m1 -Eo 'clippy::[A-Za-z0-9_]+' \u002Ftmp\u002Fautospec-final-quality-clippy.log || true)\n>        if [ -z \"$_rule\" ]; then _rule=$(grep -m1 -E 'warning:|error:' \u002Ftmp\u002Fautospec-final-quality-clippy.log | sed 's\u002F^ *\u002F\u002F' | cut -c1-200 || true); fi\n>        gh issue comment \u003CISSUE> --body \"FINAL_QUALITY_GATE_FAILED command=cargo-clippy crate=${_crate:-unknown} file=${_file:-unknown} line=${_line:-unknown} rule=${_rule:-unknown}\"\n>        exit 1\n>      fi\n>    fi\n>    fi\n>    \u003C!-- pr-size-final-merge:begin -->\n>    # Query GitHub after update-branch, review, and final local proof. The live PR\n>    # endpoints are authoritative; stale local OIDs can never create acceptance.\n>    # If the shell boundary discarded the helper, redefine it exactly as in step 4a.\n>    # pr-size-final-merge-exec:begin\n>    PR_SIZE_REMOTE_OIDS=$(gh pr view \u003CPR> --json baseRefOid,headRefOid \\\n>      --jq '[.baseRefOid, .headRefOid] | @tsv') || exit 1\n>    [ \"$(printf '%s\\n' \"$PR_SIZE_REMOTE_OIDS\" | awk -F '\\t' \\\n>      'NF == 2 && $1 != \"\" && $2 != \"\" { print \"valid\" }')\" = \"valid\" ] || exit 1\n>    PR_SIZE_BASE_OID=$(printf '%s\\n' \"$PR_SIZE_REMOTE_OIDS\" | cut -f1)\n>    PR_SIZE_HEAD_OID=$(printf '%s\\n' \"$PR_SIZE_REMOTE_OIDS\" | cut -f2)\n>    git fetch --no-tags origin \\\n>      \"+refs\u002Fheads\u002F${AUTOSPEC_BASE_BRANCH:-main}:refs\u002Fremotes\u002Forigin\u002F${AUTOSPEC_BASE_BRANCH:-main}\" \\\n>      \"+refs\u002Fheads\u002F\u003CBRANCH>:refs\u002Fremotes\u002Forigin\u002F\u003CBRANCH>\" || exit 1\n>    git cat-file -e \"${PR_SIZE_BASE_OID}^{commit}\" || exit 1\n>    git cat-file -e \"${PR_SIZE_HEAD_OID}^{commit}\" || exit 1\n>    [ \"$(git rev-parse \"origin\u002F${AUTOSPEC_BASE_BRANCH:-main}\")\" = \"$PR_SIZE_BASE_OID\" ] || exit 1\n>    [ \"$(git rev-parse \"origin\u002F\u003CBRANCH>\")\" = \"$PR_SIZE_HEAD_OID\" ] || exit 1\n>    [ \"$(git rev-parse HEAD)\" = \"$PR_SIZE_HEAD_OID\" ] || exit 1\n>    PR_SIZE_PHASE=final-pre-merge\n>    PR_SIZE_EVIDENCE=$(run_pr_size_gate) || {\n>      printf '%s\\n' \"$PR_SIZE_EVIDENCE\"\n>      exit 1\n>    }\n>    printf '%s\\n' \"$PR_SIZE_EVIDENCE\"\n>    # Reviewer evidence is accepted only as this complete line; prefixes,\n>    # suffixes, summaries, and inferred approval are not acceptance.\n>    printf '%s\\n' \"$PR_SIZE_EVIDENCE\" | grep -qxF 'INFO:PR_SIZE: acceptance' || exit 1\n>    # pr-size-final-merge-exec:end\n>    \u003C!-- pr-size-final-merge:end -->\n>    # Blast-radius domain fence at the merge chokepoint (issue #1732). The guarded-merge\n>    # wrapper classifies the PR's ACTUAL changed files against the repo's fenced_surfaces\n>    # registry and refuses to merge a fenced-surface diff (the wrapper applies the\n>    # human-review quarantine label and comments) unless the PR carries the\n>    # `autospec:fenced-approved` override label; otherwise\n>    # it performs the same admin squash-merge. Call it INSTEAD of a bare `gh pr merge --admin`\n>    # so \"merge without the fence check\" requires deliberately bypassing the wrapper.\n>    # exit 0 = merged (allowed\u002Foverridden); 1 = quarantined (NOT merged); 3 = review quorum refused (NOT merged); 2 = fail-closed error.\n>    # This replaces the historical bare `gh pr merge \u003CPR> --admin --squash --delete-branch`.\n>    # pr-size-guarded-merge-exec:begin\n>    run_guarded_pr_size_merge() {\n>      bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-guarded-merge.sh\" \\\n>        --pr \u003CPR> --repo {repo} \\\n>        --merge-args \"--admin --squash --delete-branch --match-head-commit $PR_SIZE_HEAD_OID\"\n>    }\n>    # pr-size-guarded-merge-exec:end\n>    if run_guarded_pr_size_merge; then\n>      :\n>    else\n>      _gm_rc=$?\n>      if [ \"$_gm_rc\" -eq 1 ] || [ \"$_gm_rc\" -eq 3 ]; then\n>        \"$AUTOSPEC_CLAIM_BIN\" claim release --issue \"\u003CISSUE>\" --repo {repo} --worker-id \"$CLAIM_WORKER_ID\" --claim-id \"$CLAIM_ID\" --state needs-human --branch \"\u003CBRANCH>\" --pr \"\u003CPR>\" || true\n>        if [ \"$_gm_rc\" -eq 3 ]; then\n>          echo \"[monitor] #\u003CISSUE> review quorum REFUSED (rc=3): needs review\u002Fquorum or an operator review_quorum policy; PR NOT merged, left needs-human\"\n>        else\n>          echo \"[monitor] #\u003CISSUE> quarantined by blast-radius fence: fenced surface, left needs-human; PR NOT merged\"\n>        fi\n>      elif [ \"$_gm_rc\" -eq 4 ]; then\n>        echo \"[monitor] #\u003CISSUE> review quorum could not be checked (rc=4, gh\u002Ftransport failure): PR NOT merged; retry later\"\n>      else\n>        echo \"[monitor] #\u003CISSUE> guarded-merge fail-closed (rc=$_gm_rc): PR NOT merged; pausing for operator review\"\n>      fi\n>      rm -f \"\u002Ftmp\u002Fissue-\u003CISSUE>-body.md\" || true\n>      exit 0\n>    fi\n>    \"$AUTOSPEC_CLAIM_BIN\" claim release --issue \"\u003CISSUE>\" --repo {repo} \\\n>      --worker-id \"$CLAIM_WORKER_ID\" --claim-id \"$CLAIM_ID\" \\\n>      --state merged --branch \"\u003CBRANCH>\" --pr \"\u003CPR>\" || true\n>    _parent_slug=$(bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Frepo-slug.sh\" --canonical \"{repo}\")\n>    export AUTOSPEC_PARENT_STATE_ROOT=\"${AUTOSPEC_PARENT_STATE_ROOT:-$HOME\u002F.autospec\u002Fparent-state\u002F$_parent_slug}\"\n>    if ! \"$AUTOSPEC_CLAIM_BIN\" parent reconcile-child --repo {repo} --child \"\u003CISSUE>\"; then\n>      gh issue comment \"\u003CISSUE>\" --repo {repo} --body \"Parent reconciliation failed after merge; remote parent state is unknown and will be retried by the recurring parent sweep.\"\n>      echo \"[monitor] WARN: parent reconciliation failed for merged child #\u003CISSUE>\" >&2\n>    fi\n>    # Portfolio lifecycle boundary: a merged child is an authoritative fact\n>    # for the typed portfolio graph; the monitor sweep's portfolio\n>    # reconciliation (step 2) publishes it to the primary Project before the\n>    # next admission decision.\n>    case \"$_notify_fired\" in *:merged:*) ;; *) _notify_fired=\"${_notify_fired}:merged:\"; bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fnotify.sh\" \"autospec #\u003CISSUE>: merged\" \"PR #\u003CPR> merged on {repo}\" || true ;; esac\n>    ```\n>    The block ends with the admin-merge and merged-state claim release; merge auto-closes the issue.\n>    ```bash\n>    # Stop-sentinel: abort if an immediate stop flag is present after this step.\n>    if ! bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-stop-check.sh\" \"$ISSUE\" \"$BRANCH\" \"$LAST_STEP\"; then\n>      exit 0\n>    fi\n>    ```\n>    \u003C!-- token-report:begin -->\n>    Post the per-issue token report (best-effort; never fails the run):\n>    ```bash\n>    # Orchestrator writes .autospec\u002Ftokens-\u003CISSUE>.json from Agent-result usage\n>    # (harness-dependent, best-effort; absent fields → null, never blocking).\n>    bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fpost-token-report.sh\" \\\n>      --issue \"\u003CISSUE>\" --repo \"\u003CREPO>\" \\\n>      --tokens-json \".autospec\u002Ftokens-\u003CISSUE>.json\" || true\n>    ```\n>    \u003C!-- token-report:end -->\n>    # Cleanup single-fetch body temp file on terminal success (D5).\n>    rm -f \"\u002Ftmp\u002Fissue-\u003CISSUE>-body.md\" || true\n> 9. FAILURE (loop exhausted): comment failure on issue, swap label `in-progress-by-bot` → `auto-implement`, `gh pr close \u003CPR> --delete-branch`.\n>    Fire the terminal failure notification: `case \"$_notify_fired\" in *:failed:*) ;; *) _notify_fired=\"${_notify_fired}:failed:\"; bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fnotify.sh\" \"autospec #\u003CISSUE>: failed\" \"Implementation failed on {repo}\" || true ;; esac`\n>    Cleanup single-fetch body temp file on terminal failure: `rm -f \"\u002Ftmp\u002Fissue-\u003CISSUE>-body.md\" || true`\n> 10. Cleanup: run `autospec runtime env down --repo \u002Ftmp\u002Fwt-\u003CBRANCH> --mode \"${AUTOSPEC_RUNTIME_MODE:-auto}\" --purge-maven`; then run `bash \"${AUTOSPEC_SCRIPTS_DIR:-$HOME\u002F.autospec\u002Fscripts}\u002Fautospec-runtime-worktree-cleanup.sh\" \u002Ftmp\u002Fwt-\u003CBRANCH>`; only after both succeed, run `cd \u002F && git -C {repo_root} worktree remove \u002Ftmp\u002Fwt-\u003CBRANCH> --force`.\n> 11. Report: PR number, outcome, one-paragraph summary.\n>\n> Hard rules: NEVER push to main, force-push, or bypass hooks. Only `autospec parent` may update or close an umbrella issue. gh CLI only.\n> ```\n>\n> Hard rules for the monitor: ONE issue at a time, sequential. Only `autospec parent` may update or close an umbrella issue. On transient gh errors retry once. Do NOT ask the user — auto-merge authority is granted in AGENTS.md.\n>\n> Final output when shutdown: numbered list of every processed issue with PR # and outcome.\n\nCapture the agent ID \u002F log path for monitoring.\n\nIf your harness lacks background delegation: open a separate terminal\u002Ftmux pane, run the monitor prompt in a fresh session there, and have it write progress to a logfile that Phase 5 can tail.\n\n### Running concurrent workers\n\nautospec-run is designed for concurrent operation across separate harness sessions (e.g., two Claude Code sessions in different terminals, or two Codex CLI processes). Each session runs an independent monitor. Three layers enforce safety:\n\n1. **Atomic claim** — `autospec claim acquire` check-and-swaps `auto-implement → in-progress-by-bot` plus writes an `autospec-run-state` GitHub comment. The **GitHub comment is the cross-machine source of truth**, not the local heartbeat.\n2. **Worktree isolation** — each issue gets its own `\u002Ftmp\u002Fwt-\u003Cbranch>` so two workers never share a worktree.\n3. **Per-session lock** — the session-lock (see above) ensures a single harness session never runs two concurrent monitors; separate sessions run independently by design.\n\nTo launch a second concurrent worker:\n\n```bash\n# Terminal 1 — first worker (already running)\nAUTOSPEC_WORKER_ID=\"$(hostname):user:shell:$$\" \u002Fautospec-run\n\n# Terminal 2 — second worker (fresh session, distinct worker id)\nAUTOSPEC_WORKER_ID=\"$(hostname):user:shell:$$\" \u002Fautospec-run\n```\n\nEach session derives its own `AUTOSPEC_WORKER_ID` if not overridden; the default form is `host:user:harness:pid`. Set it explicitly when two sessions run on the same host to guarantee uniqueness.\n\n**Watchdog tuning for long concurrent runs.** The watchdog cross-checks the GitHub run-state comment before releasing any `claimed` heartbeat, so a live sibling's claim is never reclaimed. The tunable env vars (set in every concurrent terminal):\n\n| Variable | Default | Purpose |\n|---|---|---|\n| `AUTOSPEC_MAX_CONCURRENT_REPO_WORKERS` | `0` (disabled) | Repo-wide active-worker cap. When active `in-progress-by-bot` issues meet the cap, `autospec queue ready` returns an empty `.batch` while still reporting `.ready`. Use this to throttle one workstation or a cluster. |\n| `AUTOSPEC_RUN_ONLY_ISSUES` | unset (unconstrained) | Space-separated issue-number allowlist. When set and non-empty, `autospec queue ready` scopes `.ready`\u002F`.blocked`\u002F`.batch` to only those issue numbers — set by the autonomous conductor's dispatch-time provenance split so the operator and self-originated batches each drain their own subset. Unset or empty keeps the full-queue scan. |\n| `AUTOSPEC_CLAIM_LEASE_SECONDS` | `10800` | Cross-machine claim lease TTL written into the GitHub run-state comment and used by `autospec claim acquire` stale-reclaim decisions. |\n| `AUTOSPEC_CLAIM_SETTLE_SECONDS` | `0.2` | Short post-upsert readback delay so simultaneous comment creates converge before a worker reports claim success. |\n| `AUTOSPEC_CLAIM_CONFIRM_READS` | `5` | Number of settled lowest-lock readbacks required before `autospec claim acquire` reports claim success. |\n| `AUTOSPEC_WATCHDOG_CLAIMED_TIMEOUT_SECS` | `1800` | Minimum age before a `claimed` heartbeat triggers the GitHub cross-check. Set higher (e.g., `3600`) for hosts with slow worktree setup. |\n| `AUTOSPEC_WATCHDOG_RECLAIM_SECS` | `10800` | Legacy fallback for claim lease age when `AUTOSPEC_CLAIM_LEASE_SECONDS` is unset; also used by watchdog stale cleanup. |\n| `AUTOSPEC_WATCHDOG_STALE_SECS` | `1800` | Age at which a heartbeat is considered stale for nudging. |\n\nIf a cross-check GitHub API call fails (offline \u002F rate-limited), the watchdog treats the claim as live and skips the reclaim — fail-safe by design.\n\nRecommended starting caps:\n\n| Deployment | `AUTOSPEC_MAX_CONCURRENT_REPO_WORKERS` | `AUTOSPEC_BATCH_SIZE` | `AUTOSPEC_CLAIM_LEASE_SECONDS` |\n|---|---:|---:|---:|\n| 10 workers | `6` | `1` | `10800` |\n| 25 workers | `12` | `1` | `10800` |\n| 50 workers | `20` | `1` | `14400` |\n\n## Phase 5 — Periodic status updates\n\nSet up a recurring check (every ~25 min) using your harness's self-paced wakeup capability. Each tick:\n\n```bash\ngh issue list --repo {repo} --label auto-implement,in-progress-by-bot,awaiting-merge --state all --json number,state,labels\ngh pr list --repo {repo} --state all --json number,state,title --limit 20\n```\n\nPost a one-paragraph delta to the user (newly closed issues, newly merged PRs, failures, blockers). If two consecutive ticks have nothing new, slow to ~50 min cadence to reduce noise. Stop the loop when:\n- the monitor agent reports completion, OR\n- all child issues are CLOSED, OR\n- the user explicitly stops.\n\nIf your harness lacks self-paced wakeup: register a local `cron`\u002F`launchd` job that runs the same status-check prompt at the chosen cadence, OR ask the user to invoke `status-update` manually.\n\n**Resolving `references\u002F` paths.** The reference pointers below are written relative to the autospec repo root, which is where the validation gate resolves them. Inside a target repo that path does not exist: resolve against this skill's own installed directory instead — `~\u002F.claude\u002Fskills\u002Fautospec-run\u002Freferences\u002F`, `$CODEX_HOME\u002Fskills\u002Fautospec-run\u002Freferences\u002F`, or `$HOME\u002F.autospec\u002Fskills\u002Fautospec-run\u002Freferences\u002F` — and fall back to the `~\u002F.autospec\u002Frepo` checkout. A pointer that will not resolve is a stop-and-report condition, never a skipped step.\n\n## Phase 6 — Final report\n\n**MUST** read `skills\u002Fautospec-run\u002Freferences\u002Fend-of-run.md` (section \"Phase 6 — Final report\") and follow it when the monitor terminates: it defines the Done challenge, the final summary, and the `.autospec\u002Frun-summary.md` write via `autospec-write-run-summary.sh`.\n\n## Phase 5.5 — End-of-run gap remediation\n\n**MUST** read `skills\u002Fautospec-run\u002Freferences\u002Fend-of-run.md` (section \"Phase 5.5 — End-of-run gap remediation\") and follow it after the last issue in the batch closes\u002Fmerges (queue drains, `ALL_DONE`), before the final report: the bounded broad-review → file-survivors → converge loop plus the docs \u002F security \u002F fab-completeness dimensions, and the `autospec-gap-miner.sh` closeout invocation that mines run evidence into `docs\u002Fmemory\u002Fautospec-gap-ledger.md`. Skip the whole phase when `~\u002F.autospec\u002Fno-review.flag` exists or `--no-postreview` was passed.\n\n## Phase 5.6 — Repo quality audit\n\n**MUST** read `skills\u002Fautospec-run\u002Freferences\u002Fend-of-run.md` (section \"Phase 5.6 — Repo quality audit\") and run `repo-quality-audit.sh` after Phase 5.5 converges or hits its cap, before Phase 6 writes the final run summary.\n\n## Advisor escalation\n\n**MUST** read `skills\u002Fautospec-run\u002Freferences\u002Fend-of-run.md` (section \"Advisor escalation\") before escalating any bounded hard decision to a TIER_A advisor (protocol, gates, and the `reviewer` gate).\n\n## Constraints (apply throughout)\n\n- **Cadence**: sub-hour polling needs an in-session background subagent or a local cron. Cloud cron services (e.g. Anthropic remote routines) typically have a 1-hour minimum and are not appropriate.\n- **TDD non-negotiable** per AGENTS.md. Real services in tests, no DB mocks.\n- **Branch-per-issue**, conventional commits, no force-push, no hook bypass.\n- **Auto-merge** on success per AGENTS.md. Do not ask.\n- **Context budget**: stay under 60%. Delegate everything possible.\n- **Failure isolation**: a failed issue restores its `auto-implement` label so the next monitor cycle picks it up; it does not block the cascade unless dependent issues are downstream.\n- **Fresh repo**: if Phase 0 created the repo, the very first commit is the scaffold (incl. `AGENTS.md`); the spec lands as the second commit; child branches branch off that `main`.\n- **Small-LLM target**: child issues are sized and pre-staged for 32B-class local LLMs (e.g. qwen3-32B \u002F Qwen3-30B-A3B on Ollama, 48 GB-class Macs). Bias toward smaller issues, sectional spec anchors, pre-staged file pointers, checkbox AC, and one Primary smoke test.\n\n## Autonomous mode\n\n`\u002Fautospec-run` is already autonomous (no operator gates during normal\noperation). When invoked with `--autonomous`, or when\n`~\u002F.autospec\u002Fautonomous.flag` exists, the monitor:\n\n- Tags run-state telemetry with `autonomous=true` so Phase 5.5 gap\n  remediation and Phase 6 final reports can distinguish autonomous runs\n  from interactive ones.\n- Honors the same safety guardrails as `\u002Fautospec` and `\u002Fautospec-define`:\n  destructive remote actions, out-of-scope file changes, and the token cost gate\n  (`AUTOSPEC_AUTONOMOUS_TOKEN_CAP`) still\n  surface confirmations via `autospec-autonomy-gate.sh --check all`,\n  exit 1 = ask anyway.\n- Does NOT add any additional user-facing gates. The flag is informational\n  here — the run loop's existing \"only ask on hard blocker\" rule already\n  matches autonomous semantics.\n\nPass `--autonomous` from `\u002Fautospec-define`'s handoff (or set it\nexplicitly) to preserve cross-phase telemetry continuity. Existing\n`feedback_autospec_autonomy_scope.md` rules remain in force.\n",{"name":5,"description":7},"main","9e7f04357ff46ab731d4f56a4ac5ca5449c13bb0","skills\u002Fautospec-run",1,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec","https:\u002F\u002Fgithub.com\u002Fberlinguyinca","Love to lead, code, cook and contribute to open source and believe that you can learn anything you set your mind too.\r\n","2026-11-11 07:09:35",{"source":8,"skillName":5,"commands":53,"prompt":63,"zipAvailable":64},[54,57,60],{"tool":55,"command":56},"npx","npx skills add berlinguyinca\u002Fautospec --skill autospec-run",{"tool":58,"command":59},"bunx","bunx skills add berlinguyinca\u002Fautospec --skill autospec-run",{"tool":61,"command":62},"pnpm","pnpm dlx skills add berlinguyinca\u002Fautospec --skill autospec-run","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002FSKILL.md",true,[66,72,78,82,86,90,94,98,102,106,110,114,118,122,126,130,134,138,142,146,150,156,160,164,168,172,176,180,184],{"path":67,"resourceType":68,"resourceTypeDesc":69,"sizeBytes":70,"sourceHtmlUrl":71},"codex\u002Fprompt.md","REFERENCE","参考文档",131567,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Fcodex\u002Fprompt.md",{"path":73,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":76,"sourceHtmlUrl":77},"install.sh","SCRIPT","脚本",14610,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Finstall.sh",{"path":79,"resourceType":68,"resourceTypeDesc":69,"sizeBytes":80,"sourceHtmlUrl":81},"opencode\u002Fagent.md",131892,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Fopencode\u002Fagent.md",{"path":83,"resourceType":68,"resourceTypeDesc":69,"sizeBytes":84,"sourceHtmlUrl":85},"prompts\u002Fimplementer-contract.md",24596,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Fprompts\u002Fimplementer-contract.md",{"path":87,"resourceType":68,"resourceTypeDesc":69,"sizeBytes":88,"sourceHtmlUrl":89},"prompts\u002Fphase4-implementer.md",41075,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Fprompts\u002Fphase4-implementer.md",{"path":91,"resourceType":68,"resourceTypeDesc":69,"sizeBytes":92,"sourceHtmlUrl":93},"prompts\u002Freviewer-contract.md",12011,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Fprompts\u002Freviewer-contract.md",{"path":95,"resourceType":68,"resourceTypeDesc":69,"sizeBytes":96,"sourceHtmlUrl":97},"README.md",6307,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002FREADME.md",{"path":99,"resourceType":68,"resourceTypeDesc":69,"sizeBytes":100,"sourceHtmlUrl":101},"references\u002Fend-of-run.md",19618,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Freferences\u002Fend-of-run.md",{"path":103,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":104,"sourceHtmlUrl":105},"scripts\u002Fautospec-run-session-lock.sh",4429,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Fscripts\u002Fautospec-run-session-lock.sh",{"path":107,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":108,"sourceHtmlUrl":109},"scripts\u002Fautospec-run-status.sh",10645,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Fscripts\u002Fautospec-run-status.sh",{"path":111,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":112,"sourceHtmlUrl":113},"scripts\u002Fdocs-completeness-gaps.sh",8102,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Fscripts\u002Fdocs-completeness-gaps.sh",{"path":115,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":116,"sourceHtmlUrl":117},"scripts\u002Ffab-completeness.sh",5134,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Fscripts\u002Ffab-completeness.sh",{"path":119,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":120,"sourceHtmlUrl":121},"scripts\u002Ffab-route.sh",3436,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Fscripts\u002Ffab-route.sh",{"path":123,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":124,"sourceHtmlUrl":125},"scripts\u002Fheartbeat-read.sh",6940,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Fscripts\u002Fheartbeat-read.sh",{"path":127,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":128,"sourceHtmlUrl":129},"scripts\u002Fheartbeat-write.sh",9505,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Fscripts\u002Fheartbeat-write.sh",{"path":131,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":132,"sourceHtmlUrl":133},"scripts\u002Findependent-review-adapter.sh",7745,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Fscripts\u002Findependent-review-adapter.sh",{"path":135,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":136,"sourceHtmlUrl":137},"scripts\u002Finvoke-review.sh",7646,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Fscripts\u002Finvoke-review.sh",{"path":139,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":140,"sourceHtmlUrl":141},"scripts\u002Fpost-token-report.sh",7086,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Fscripts\u002Fpost-token-report.sh",{"path":143,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":144,"sourceHtmlUrl":145},"scripts\u002Frun-groom-preflight.sh",3739,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Fscripts\u002Frun-groom-preflight.sh",{"path":147,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":148,"sourceHtmlUrl":149},"scripts\u002Fselect-model-profile.sh",11839,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Fscripts\u002Fselect-model-profile.sh",{"path":151,"resourceType":152,"resourceTypeDesc":153,"sizeBytes":154,"sourceHtmlUrl":155},"tests\u002Fduplicate-read.bats","OTHER","其他",9426,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Ftests\u002Fduplicate-read.bats",{"path":157,"resourceType":152,"resourceTypeDesc":153,"sizeBytes":158,"sourceHtmlUrl":159},"tests\u002Fintegration\u002Fphase4-drift-gate.bats",2991,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Ftests\u002Fintegration\u002Fphase4-drift-gate.bats",{"path":161,"resourceType":152,"resourceTypeDesc":153,"sizeBytes":162,"sourceHtmlUrl":163},"tests\u002Fintegration\u002Fphase55-docs-completeness.bats",6102,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Ftests\u002Fintegration\u002Fphase55-docs-completeness.bats",{"path":165,"resourceType":152,"resourceTypeDesc":153,"sizeBytes":166,"sourceHtmlUrl":167},"tests\u002Fphase4-fab-routing.bats",2197,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Ftests\u002Fphase4-fab-routing.bats",{"path":169,"resourceType":152,"resourceTypeDesc":153,"sizeBytes":170,"sourceHtmlUrl":171},"tests\u002Fphase55-fab-completeness.bats",5753,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Ftests\u002Fphase55-fab-completeness.bats",{"path":173,"resourceType":152,"resourceTypeDesc":153,"sizeBytes":174,"sourceHtmlUrl":175},"tests\u002Fpost-token-report.bats",8369,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Ftests\u002Fpost-token-report.bats",{"path":177,"resourceType":152,"resourceTypeDesc":153,"sizeBytes":178,"sourceHtmlUrl":179},"tests\u002Freviewer-tier.bats",3126,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Ftests\u002Freviewer-tier.bats",{"path":181,"resourceType":152,"resourceTypeDesc":153,"sizeBytes":182,"sourceHtmlUrl":183},"tests\u002Ftest_watchdog_claim_timeout.bats",9699,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Ftests\u002Ftest_watchdog_claim_timeout.bats",{"path":185,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":186,"sourceHtmlUrl":187},"uninstall.sh",3937,"https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-run\u002Funinstall.sh",[189,202,211,220,242,265],{"skillNo":190,"name":191,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":192,"categories":193,"keywords":199,"publishedAt":39},"01M71RJHYMKPTC9AAPXWQ6F4RT","trio-pass-skill","https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Flockstep-trio-pass\u002FSKILL.md",[194],{"categoryNo":195,"categoryName":196,"taxonomyType":197,"taxonomyTypeDesc":198},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[200,201],"trio","trio pass skill",{"skillNo":203,"name":204,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":205,"categories":206,"keywords":208,"publishedAt":39},"01M71RJFBQ1KAF9XM3T3Y4VMSK","duo-pass-skill","https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Flockstep-duo-pass\u002FSKILL.md",[207],{"categoryNo":195,"categoryName":196,"taxonomyType":197,"taxonomyTypeDesc":198},[209,210],"duo pass skill","duo",{"skillNo":212,"name":213,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":214,"categories":215,"keywords":217,"publishedAt":39},"01M71RJDT1TB3P9TRWR6A534FB","duo-divergence-skill","https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Flockstep-duo-divergence\u002FSKILL.md",[216],{"categoryNo":195,"categoryName":196,"taxonomyType":197,"taxonomyTypeDesc":198},[218,210,219],"duo divergence skill","divergence",{"skillNo":221,"name":19,"nameZh":6,"description":222,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":223,"categories":224,"keywords":228,"publishedAt":39},"01M71RJAC4NNEQSYBDSY3NZS73","Use when the user wants to ship a feature end-to-end across multiple commits — bootstraps repo if missing, brainstorms a design spec, decomposes into linked GitHub issues, or splits an existing spec into issues, then runs an autonomous implementation loop with auto-merge.","https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec\u002FSKILL.md",[225],{"categoryNo":226,"categoryName":227,"taxonomyType":197,"taxonomyTypeDesc":198},"01JBSEEDCAT000000000000015","视觉设计",[19,229,230,36,231,232,35,233,34,234,235,33,236,237,32,238,239,240,241,28],"ship a feature","end","design","autonomous","loop","across","design spec","ship","implementation loop","feature","commits","repo","missing",{"skillNo":243,"name":244,"nameZh":6,"description":245,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":246,"categories":247,"keywords":248,"publishedAt":39},"01M71RJ4F9HT8PT26CKNM9XE1M","autospec-upgrade","Use when the user wants to upgrade an Angular, Next.js, or React project to the latest official versions safely — by locking observable behavior before touching versions, upgrading one major at a time with official codemods, and gating completion on mutation score rather than coverage theater.","https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-upgrade\u002FSKILL.md",[],[249,19,250,251,252,253,254,255,256,34,257,258,259,260,28,261,262,26,263,264],"autospec upgrade","upgrade","mutation","coverage","official","project","time","gating","angular","react","next","at","Next.js","one","behavior","latest",{"skillNo":266,"name":267,"nameZh":6,"description":268,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":269,"categories":270,"keywords":276,"publishedAt":39},"01M71RJ28FJ4PM6DXHB7T5CF8H","autospec-ui-audit","Use when a React Router application needs a deterministic whole-site route inventory before UI, UX, navigation, or evidence auditing begins.","https:\u002F\u002Fgithub.com\u002Fberlinguyinca\u002Fautospec\u002Fblob\u002Fmain\u002Fskills\u002Fautospec-ui-audit\u002FSKILL.md",[271],{"categoryNo":272,"categoryName":273,"taxonomyType":274,"taxonomyTypeDesc":275},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",[277,19,278,279,280,28,281,282,283,284,285,286,287,288,289,258,290,34,291],"ui audit","audit","autospec ui audit","ui","inventory","evidence","deterministic","route","ux","site","react router","navigation","application","needs","router"]