# Apply — what `--fix` runs per finding

Read this only on the `--fix` (Fix) pass. Each Pass-1 finding maps to a concrete
action and a gate: **safe** fixes apply in a batch (idempotent, low-blast-radius);
**confirm-each** fixes show the exact mutation and apply only on an explicit yes;
**delegate** fixes trigger the single-writer tool that owns the change. The
findings→owner mapping lives in the *Fix-home* table in `SKILL.md`; this table adds
the action and gate on top of it.

| Finding | `--fix` action | Gate |
|---|---|---|
| Missing canonical label | `gh label create <name> --color <c> --description "<d>"` | **safe** (batch) |
| AGENTS≡CLAUDE Agent-skills / Development-workflow parity | run the development-workflow injector (`inject-development-workflow --root <repo>`) — upserts both blocks in place | **safe** (batch; idempotent) |
| `dev.lock.primary-branch` unset | same injector (it sets the nested flag) | **safe** (batch) |
| Statusline drift | rewrite the `.claude/settings.json` `statusLine` to the cached-bundle form (jq merge, preserve other keys) | **safe** (batch) |
| `.red/.gitignore` self-ignore missing/incomplete | write `.red/.gitignore` (header + `tmp/` + `state/` + `researches/`) if absent, else append only the missing pattern(s) — never reorder or clobber existing lines; don't `git add` it; print a one-line receipt | **safe** (batch; idempotent) |
| Label synonym / legacy / naming | `gh label rename <old> <new>` (or create canonical + migrate, then retire the old) | **confirm each** — re-tags every issue carrying the old label |
| Legacy/top-level dev-plugin config (flat `lock-primary-branch`, top-level `dev.lock.*`, top-level `afk:`) | migrate the key(s) into the canonical `plugins.dev.*` namespace + delete the top-level orphan in `.red/config.yaml` (safe: the #697 fold reads both, the namespaced form wins) | **confirm each** |
| `blocked:*` on a `ready-for-agent`/`running` issue | `gh issue edit <N> --remove-label blocked:<reason>` (rotate the stale reason) | **confirm each** |
| MCP wiring | add/correct the expected servers in the repo's `.mcp.json` | **confirm each** |
| Version coherence mismatch | **run** the single-writer version/release tool (ADR 0040); never patch a manifest | **delegate** |
| Workflow naming-convention drift | `git mv` the file to the prefix its role requires (`reusable-*` / `rs-*` / `red-*`); filename only, body unchanged; then update any `uses:` + doc references to the old name | **confirm each** — renames a CI file |
| AFK-lane auth gap (`rs-afk-attempt.yml`, no auth secret) | **do not set the secret** — print the per-provider `gh secret set … --repo` guidance + the public-repo org-secret note; delegate to `/red-setup` | **delegate** |
| AFK hook/backpressure static-validation `❌`/`⚠️` (check 12) | **`--fix` cannot auto-fix operator intent** — it cannot know whether the right repair is to rename the script, restore the file, or drop the command. Flag the finding and point at `/red-setup` (re-seed a library hook) or a manual edit; never rewrite `.red/config.yaml` or `.red/hooks/` here, and never execute the command to "check" it. | **delegate** |
| AFK Worktree setup declaration `❌` (check 12) | **Delegate to `/red-setup`** — it inspects package/lock/hook-manager facts, asks the maintainer to confirm exact command(s), and surgically writes `plugins.dev.afk.setup`. Doctor never guesses the install, adds lifecycle flags, or executes the command. | **delegate** |
| Per-plugin runtime distribution `❌`/`⚠️` (check 13) | **re-trigger the launcher fetch** for the plugin (`red-fetch.mjs <plugin> <version>` / rebuild locally) — the cache is launcher-owned, never hand-edited. `cache-corrupt` also removes the bad cached file first so the re-fetch re-downloads. A re-fetch hits the network and rewrites the cache, so it is never a safe batch. | **confirm each** — a network fetch that rewrites the cache |
| `req:<Spec>` dependency edge (check 14) | **do not silently re-label** — a re-point needs the author to pick the right executable slice(s). Surface each offending edge and delegate to `/triage` (re-point) or `/to-tickets` (author the missing slice); never edit the `req:*` label here. | **delegate** |
| Native blocked-by vs `req:N` divergence (check 15) | **do not guess the canonical side** — a divergence means the authoring metadata must be refreshed. Surface each missing native edge / missing `req:N` label and delegate to `/triage`; never add/remove labels or native edges in doctor `--fix`. | **delegate** |
| Native sub-issue vs `spec:N` divergence (check 16) | **run the shared Spec sub-issue reconciler** — attach missing native sub-issue edges for every `spec:N` child and remove stale `needs-slicing` from Specs that already have published slices. Do not remove native-only edges or invent missing labels; surface those as authoring drift. | **safe batch** |
| ask-red router coverage sync (check 17) | **do not patch the router blindly** — a missing or stale entry means the flow map needs a wording check. Surface the exact skill names and apply the ask-red maintenance rule: update `plugins/dev/skills/engineering/ask-red/SKILL.md`, README/bucket docs if registration changed, and rerun the docs contract. | **confirm each** |
| Host toolchain `❌` (check 18) | With explicit approval, an asdf-managed `gh` runs `asdf install github-cli latest && asdf global github-cli latest && asdf reshim github-cli`; apt, brew, and direct-binary gh remedies remain printed instructions and are never executed by the doctor. With explicit approval, install pinned `tq` from the official `reddb-io-tq` crate with Cargo. Never execute a sudo-backed path, patch around drift with a jq fallback, or silently accept an older version. | **confirm each** |
| `.red` lifecycle taxonomy (check 19); tmp janitor (check 19) | **taxonomy findings:** do not auto-move content; each finding names the offending path and target tier/lane. Delegate to the owning writer, or amend ADR 0098 before accepting a new top-level directory or tmp lane. **tmp janitor findings:** run the wired janitor fixer only on audited targets: expired managed lanes from `planTmpJanitor`, stale worker dirs whose represented issues are closed, and unknown tmp-root entries returned by `auditTmpRoot`; re-check `worker.pid` immediately before deleting any worker dir and skip it if live. | taxonomy: **delegate**; tmp janitor: **safe batch** |
| the Worker's state lane (check 20) | **delegate to the dev durable path migration entrypoint** (`red-path-migration` during boot). It must move legacy AFK state into `.red/state/castle/` without overwriting current state, and leave ambiguous legacy residue intact for an operator to inspect. Never hand-delete `.red/state/afk/`, rewrite TOONL history, or patch snapshots in doctor `--fix`. | **delegate** |
| Unlanded `.red/` docs (check 21) | **run the ADR 0092 doc-landing lane** — from an isolated `.red/tmp/worktrees/docs/<slug>` worktree based on freshly fetched `origin/{base}`, copy only the detected docs, commit one `docs:` change, push a branch, open one docs PR, merge it, then re-fetch/re-check. Reuse the shared Docs Sweep plan; never recompute the file list in the fixer. | **confirm each** — pushes a branch, opens a PR, and merges it |
| Red operational probe (check 22) | **run the probe's own canonical fixer** from the registry. For the HTTPS-remote proof probe, rewrite each named local HTTPS remote to its SSH form. For `config.coherence`, show the `.red/config.yaml` diff preview first, then relocate confirmed root-level `dev:`/`afk:` blocks under `plugins.dev.*`; malformed parse fallbacks remain red until the offending line/construct is repaired. A decline leaves the target byte-identical and the finding open. | **confirm each** — rewrites git remote configuration or confirmed config blocks |
| Executable ticket acceptance-criteria lint (check 23) | **delegate to `/triage`** — the issue body needs authoring work: add or refresh `## Acceptance criteria` so every checklist item names a test, command, fixture, or pinned observable behavior. Doctor must not edit labels, post the recipe comment, or invent criteria. | **delegate** |
| HUMAN-ONLY type declaration (check 25) | **merge the missing type into `afk.labels.hitl_types`** in `.red/config.yaml` after showing the insertion diff — append to the existing list, never overwrite it, never duplicate an entry, and never widen the list beyond the labels the tracker actually carries. A decline leaves the file byte-identical and the finding open. A repo with no `.red/config.yaml` is **delegated to `/red-setup`**: only it may create a repository's `.red/`. | **confirm each** — writes `.red/config.yaml` |
| Marketplace registration source (check 26) | **report it and stop** — the `red-skills` registration belongs to red-dev, which acquires RedSkills and wires each host from the tree it manages. `--fix` performs nothing here: repointing a directory-sourced registration at `reddb-io/red-skills` is what the retired standalone installer did on every re-run, and on a red-dev machine it tore out the wiring it claimed to repair (#3978). A `standalone-source` finding is cured by the bootstrap — `mise use --global red-dev@1 && red-dev install` — and a `source-unknown` finding is never touched at all, because re-registering a marketplace we could not read would discard whatever the operator configured. | **delegate** |
| Declared-but-unloaded MCP servers (check 27) | **tell the operator the cure and stop** — restart the session, or run `/reload-plugins`. `--fix` never performs it: the cure belongs to the host session, and a doctor that restarted the session it was invoked from would kill its own caller. Never "heal" this by editing `.mcp.json`, re-registering the marketplace, or starting a server process by hand — the declaration is already correct, only the load is missing. A `session-unobserved` warn is cured by re-running with `--session-mcp`, never by assuming the session is clean. | **delegate** |
| Project registration liveness (check 29) | **delegate to the AFK runtime's independent registration belt** — a recent lapse backed by previously observed work remains recoverable for one registration window and is restored when a fresh queue poll confirms work. If the finding persists on an older installed runtime, upgrade/restart that runtime; never make the doctor invent a selector or register a project itself. | **delegate** |
| Feedback command authority (check 30) | **do not guess which safety side the maintainer intends** — either require the merge queue's `test` status check in branch protection, or remove/widen `plugins.dev.afk.feedback.commands` so local discovery owns the full verdict again. Doctor reports the exact gap and never edits branch protection or validation commands. | **delegate** |
| Context-stack gap (check 1) | run the relevant `memory`/context skill | **delegate** |
