[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6K7RY1AV42ESY6JTZF0SQRF":3,"skill-same:01M6K7RY1AV42ESY6JTZF0SQRF":92},{"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":40,"linkOnly":41,"markdownContent":42,"markdownBody":43,"frontMatter":44,"refName":46,"commitSha":47,"skillDirectory":48,"forksCount":49,"repositoryHtmlUrl":50,"repositoryHomepageUrl":51,"ownerHtmlUrl":52,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":53,"install":54,"resources":67},"01M6K7RY1AV42ESY6JTZF0SQRF","plan-review",null,"Run a detailed, adversarial multi-agent review of an implementation plan — a GitHub PR, a branch, or a planning document — against the baseline spec, ADR, or prior plan it is meant to honour. Reviews the plan, not the code. Builds a shared inventory, runs up to 7 independent lenses in parallel (completeness, consistency, logic, feasibility, assumptions, testability, baseline-diff), verifies every finding against the repository so that anything without a path:line or a runnable command is dropped, adjudicates by severity, then loops a completeness critic until dry. Writes a findings document to a caller-specified target. Use when the user says \"review this plan\", \"review this PR's plan\", \"does this plan match the spec\", \"red team this implementation plan\", \"what's missing from this plan\", \"check this plan against the ADR\", \"plan review\", or similar. Review-only — never edits the plan, the PR, or any source file.","tbeack\u002Ffsad_playbook","tbeack","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F206807984?v=4","01M6K7Q3C3VRTCVC55T71A1SY9","Theo Beack","01M6K7Q3GDY8TXRQEH984SEE5W",8,"MIT","https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fplan-review\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39],"plan","plan review","review","only","when","implementation plan","reviews","quick","loops","scope","dry","deep","shared","up","never","branch","text","team","critic","inventory","code","2026-11-10 10:12:30",false,"---\ndescription: Run a detailed, adversarial multi-agent review of an implementation plan — a GitHub PR, a branch, or a planning document — against the baseline spec, ADR, or prior plan it is meant to honour. Reviews the plan, not the code. Builds a shared inventory, runs up to 7 independent lenses in parallel (completeness, consistency, logic, feasibility, assumptions, testability, baseline-diff), verifies every finding against the repository so that anything without a path:line or a runnable command is dropped, adjudicates by severity, then loops a completeness critic until dry. Writes a findings document to a caller-specified target. Use when the user says \"review this plan\", \"review this PR's plan\", \"does this plan match the spec\", \"red team this implementation plan\", \"what's missing from this plan\", \"check this plan against the ADR\", \"plan review\", or similar. Review-only — never edits the plan, the PR, or any source file.\nargument-hint: '`\u003Csource> \u003Ctarget> [--baseline \u003Cpath>] [--depth quick|standard|deep] [--scope \u003Ctext>] [--run-dir \u003Cpath>]`'\n---\n\n# fsad-harness:plan-review — Adversarial Implementation-Plan Review\n\n**What this optimizes for:** catching the thing that makes the plan unbuildable *before* anyone starts building it. A plan is cheap to change and expensive to have half-built, so the review is worth running exactly once — here — and its value comes from measuring the plan against two things it cannot check for itself: the baseline it promised to honour, and the repository it will actually land in. What that yields in practice is defined per lens in `lenses.md`, not here.\n\nThis is the **plan-stage gate**. It runs before the code-stage gates (`fsad-harness:code-review-team`, `fsad-harness:sec-review-team`) — there is no code yet.\n\nReview-only. The skill writes exactly two things: the findings document at `target`, and the run directory (`run_dir`, defaulting beside `target` — see Parameters). Nothing else on disk is touched.\n\n---\n\n## Asking the user\n\nThis rule covers every question this skill asks the user: a confirmation, a choice, a missing value, a numbered decision list, or a stop-and-ask. It applies even where a later step says \"ask the user\" or \"ask exactly once\". The user may watch the decisions pane rather than the chat, so a question that only goes to chat can go unanswered.\n\n- **When `mcp__decision-tracker__decision` is in your tool list** (loaded, or named as a deferred tool; load a deferred one with `ToolSearch` first), log each question before you ask it:\n  1. Call it with `action: \"open\"`, the question (ending in `?`), and `options` when the answers are a closed set. Set `required: false` when the work can go on without an answer. A numbered list of questions opens one decision per item. Keep each returned `id`.\n  2. Ask the question in chat as this skill says. The open call does not replace the chat question.\n  3. When the user answers, in chat or as a `Decision Dn: \u003Canswer>` message from the plugin, call the tool with `action: \"close\"`, the `id` and the answer.\n  4. When the change the answer asked for is in place, call it with `action: \"implement\"`, the `id` and a `path:line`.\n- **When the tool is absent**, ask in chat only.\n- An `AskUserQuestion` call is logged on its own. Do not open it again.\n- This rule changes where a question is logged. It does not change when this skill asks, or how many times.\n\n## Parameters\n\n| Parameter | Required | Accepts | Notes |\n|---|---|---|---|\n| `source` | **yes** | A GitHub PR (`#439`, a full URL, or `owner\u002Frepo#N`), a branch name, a file path, or a glob | The plan under review. |\n| `target` | **yes** | A file path | Where the findings document is written. Parent directories are created. |\n| `baseline` | no | Path(s) to a spec, ADR, prior plan, or PR that `source` is meant to honour or supersede | When omitted, candidates are inferred (Step 0.3) and the chosen one is named in the report header. |\n| `depth` | no | `quick` \\| `standard` (default) \\| `deep` | Controls the lens roster, verifier count, and critic rounds (Step 0.4). |\n| `scope` | no | Free text | Narrows the review, e.g. \"schema and migration steps only\". Recorded verbatim in the report header. |\n| `run_dir` | no | A directory path | Where the run artefacts go. Defaults to `\u003Cdirectory containing target>\u002F.plan-review\u002Fruns\u002F\u003Crun_id>\u002F`. Set it to keep artefacts out of the repository, or to place them somewhere the caller's tooling already collects. The internal layout (Step 0.6) is fixed wherever it points. |\n\n**The skill prompts for any required parameter the invocation did not supply, and it never guesses a write path.** If `target` was not given, ask for it — do not infer one from the plan's location, do not default to a filename beside the plan, and do not proceed with a placeholder. If `source` was not given, ask for it — do not review \"the most recent plan\" or \"the current branch\" on your own initiative. A wrong target written confidently is worse than a question.\n\n---\n\n## When to skip\n\nSay so and stop, rather than producing a report that pads a non-problem:\n\n- **Single-step plans.** One step, one file, one acceptance criterion. There is no sequencing to audit, no cross-reference graph, and no baseline drift to measure. A normal read is cheaper and just as good.\n- **Plans with no baseline and no cross-references.** If nothing resolves as `baseline` and the plan cites no ADRs, no sibling documents, no numbered artefacts, and no source files, then five of the seven lenses have nothing to check against — the review degenerates into proofreading. Offer `fsad-harness:spec-review` instead, which judges a document on its own terms.\n- **Pure-copy edits.** Wording, formatting, typo, or link-text changes to an existing plan. Diff the prose; do not convene a review team.\n\nIf the user asks anyway after being told, run it — say what the reduced roster will be first.\n\n---\n\n## Step 0 — Resolve parameters\n\n### 0.1 Resolve `source`\n\n| `source` looks like | Resolution |\n|---|---|\n| `#N`, `owner\u002Frepo#N`, or a PR URL | `gh pr view \u003CN> --json number,title,headRefName,baseRefName,headRefOid,baseRefOid,body,files,url` then `gh pr diff \u003CN>`. |\n| A branch name | `git rev-parse \u003Cbranch>` for the head SHA; merge-base against the default branch for the base SHA; `git diff \u003Cbase>...\u003Cbranch> --stat`. |\n| A file path | The plan document itself. Head SHA = `git rev-parse HEAD`; no base SHA. |\n| A glob | Expand it. If it matches more than one document, list the matches and **ask which is the plan** — the rest become supporting documents, not additional subjects. |\n\nFor every form, establish and record: the **head SHA**, the **base SHA** (where one exists), and **whether the base is behind the repository's default branch**. Pass all three to `consistency-checker`, which owns base drift — its brief in `lenses.md` says how to measure it and how to grade it.\n\nThen collect the plan's supporting documents:\n\n- The **decisions sidecar** — glob for `\u003Cplan-basename>-decisions.md` in the plan's own directory (see Path conventions). Requirements hide there.\n- The **testing document** — any document the plan cross-references whose name matches `test|qa|verification`.\n- For a PR, the **PR body** — it frequently names the baseline the description in the plan file omits.\n\nRead all of them. A document not read cannot be cited, and the completeness critic will ask which ones you skipped.\n\n### 0.2 Resolve `target` and detect a second pass\n\nCreate `target`'s parent directories. Then:\n\n- **`target` does not exist** — first pass. Write a fresh document.\n- **`target` exists** — **second pass.** Read it in full *before* Phase 1, and extract its previous findings into `\u003CRUN_DIR>\u002Fprevious-findings.json`. The new document must:\n  - **Mark resolved** — a previous finding whose evidence no longer reproduces at the new head SHA. Say what changed and cite the new `path:line`.\n  - **Carry forward still-open** — a previous finding that still reproduces, keeping its original identifier and noting how many passes it has survived.\n  - **State what changed** — a \"Since the previous pass\" block naming the previous head SHA, the new head SHA, the counts resolved \u002F still open \u002F newly raised.\n\n  Never silently overwrite a previous pass's findings. A finding that disappears without being marked resolved is a review failure, not a clean bill of health.\n\n### 0.3 Resolve `baseline`\n\nIf `baseline` was supplied, use it. Otherwise infer candidates, in this order, and **state in the report header which was chosen and why**:\n\n1. Any document the PR body or plan preamble names as the thing it implements, supersedes, or follows.\n2. Documents matching `spec|prd|rfc|adr|proposal|design` under the configured spec\u002FADR directories (Path conventions below).\n3. The immediately preceding numbered plan in the same directory, if the plan's own numbering pattern implies one.\n\nIf more than one candidate survives and no signal separates them, **ask**. If none resolves, record `baseline: none` in the header, skip `baseline-diff-auditor`, and say so in Coverage — a silent skip reads as \"nothing was dropped\", which is exactly the false negative this skill exists to prevent.\n\n### 0.4 Resolve `depth` and select the roster\n\n| Lens | `quick` | `standard` | `deep` |\n|---|:---:|:---:|:---:|\n| `completeness-auditor` | ● | ● | ● |\n| `consistency-checker` | ● | ● | ● |\n| `testability-auditor` | ○ | ● | ● |\n| `logic-auditor` | | ● | ● |\n| `assumption-hunter` | | ● | ● |\n| `feasibility-critic` | | ○ | ● |\n| `baseline-diff-auditor` | ○ | ○ | ● |\n\n● = always runs. ○ = conditional, resolved as follows so the counts stay fixed:\n\n- **`quick` runs exactly 3 lenses.** The third slot is `baseline-diff-auditor` when a baseline resolved, `testability-auditor` when none did.\n- **`standard` runs exactly 6 lenses.** The sixth slot is `baseline-diff-auditor` when a baseline resolved, `feasibility-critic` when none did.\n- **`deep` runs all 7, then a duplicate pass of all 7** with different seeds — different reading order, and an instruction to start from the sections the first pass is least likely to have reached. Duplicate-pass output goes to `\u003Clens>-b.findings.jsonl`. 14 lens files.\n\n`baseline-diff-auditor` is **required whenever a baseline resolves**, at every depth. It is skipped only when no baseline resolves. Every lens not run is recorded in Coverage with its reason — silent skipping is forbidden.\n\nVerifier count and critic rounds follow depth: see Phase 3 and Phase 5.\n\n### 0.5 Apply `scope`\n\nIf `scope` is set, pass it verbatim into every lens brief as a narrowing instruction, and record it in the report header. Findings outside scope are not raised. **Log what scope excluded** in Coverage — a narrowed review that reads as a full one is a silent cap.\n\n### 0.6 Set up the run directory\n\n```\nRUN_DIR = \u003Cthe `run_dir` parameter, if given>\n       or \u003Cdirectory containing target>\u002F.plan-review\u002Fruns\u002F\u003Crun_id>\u002F   ← default\n```\n\n`run_id` is an ISO-timestamp-derived slug. Create it before Phase 1. Layout:\n\n```\n\u003CRUN_DIR>\u002F\n├── inventory.json                      # Phase 1 — written before any lens starts\n├── \u003Clens>.findings.jsonl               # Phase 2 — one per lens (deep adds \u003Clens>-b)\n├── verdicts\u002F\u003Cfinding-id>.json          # Phase 3 — one per finding\n├── clusters\u002F\u003Ccluster-id>.json          # Phase 4 — near-duplicates merged across lenses\n├── adjudicated.json                    # Phase 4 — final severity-ranked set\n├── critic\u002Fcompleteness-critic-r\u003CN>.findings.jsonl   # Phase 5 — one per round\n├── coverage.json                       # lenses run\u002Fskipped, rounds, what scope excluded\n└── previous-findings.json              # second pass only\n```\n\nCritic rounds live under `critic\u002F` rather than at the run-dir root deliberately: it keeps `ls \u003CRUN_DIR>\u002F*.findings.jsonl` an exact count of the lenses that ran, which is how the depth roster is audited.\n\n---\n\n## Path conventions — discovered or configured, never assumed\n\nThis skill is repo-agnostic: it hardcodes no project's layout. Every path it reads from and every path it writes to is either **discovered from the repository** or **supplied by the caller**, and every default below is documented. Nothing here is a fixed requirement a project must reorganise itself to satisfy.\n\n### Read paths — discovered or configured\n\n| Concept | How it is resolved | Default used as a search hint | If it can't be resolved |\n|---|---|---|---|\n| Plan location | The `source` parameter. Required; never inferred. | — | **Ask.** Never guess the subject. |\n| Baseline candidates | Step 0.3 — the PR body and plan preamble first, then a glob over conventional spec\u002FADR directories. | `planning\u002Fspec\u002F`, `planning\u002Fprd\u002F`, `docs\u002Fadr\u002F`, `docs\u002Frfc\u002F` | **Ask** only when *several* candidates survive and no signal separates them. When *none* resolves, record `baseline: none`, skip `baseline-diff-auditor`, and say so in Coverage — do not ask, and do not stop. |\n| Decisions sidecar | Glob for `\u003Cplan-basename>-decisions.md` in **the plan's own directory**, whatever that directory is. | same directory as the plan | Absent is normal. Record it and continue. |\n| Testing document | A cross-reference from the plan whose target name matches `test\\|qa\\|verification`. | — no directory assumed | Absent is normal. Record it and continue. |\n| Numbering pattern | Inferred from the plan's own artefact names (e.g. `NNN-slug.md`, `VNNN__slug.sql`). What is done with it is `consistency-checker`'s business. | pattern inferred, never assumed | No inferable pattern means that lens has no collision check to run. Record it in Coverage. |\n\n**A missing read path is a fact about the repository, not an error.** A repo with no `planning\u002F`, no `docs\u002Fadr\u002F`, and no sidecar is a normal input: the probes miss, the affected lenses narrow, Coverage records what was unavailable, and the run completes. The one case that stops and asks is an *ambiguous* input — a glob matching several documents (Step 0.1), or several baseline candidates with nothing to separate them (Step 0.3).\n\n### Write paths — configured, with a derived default\n\nThe skill writes to exactly two places, and neither is guessed:\n\n| Path | How it is set | Default |\n|---|---|---|\n| `target` | **Caller-supplied, always.** Required, never inferred. If it was not given, **ask** — this is the one path the skill will never default. | — |\n| `\u003CRUN_DIR>` | The `run_dir` parameter when given; otherwise derived from `target`. | `\u003Cdirectory containing target>\u002F.plan-review\u002Fruns\u002F\u003Crun_id>\u002F` |\n\nWhat is *not* configurable is the run directory's **internal** layout (Step 0.6) — the filenames and subdirectories are this skill's own convention, because the depth audit and the second-pass logic both read them by name. Callers choose where the run directory lives; they do not rearrange what is inside it.\n\n---\n\n## Phase 1 — Inventory (single agent, before any lens)\n\nBuild `\u003CRUN_DIR>\u002Finventory.json` first. **No lens may start until it exists** — lenses cite inventory IDs, and a lens that re-derives its own inventory produces findings nobody else can cluster against.\n\nSpawn one agent to extract, assigning every item a stable ID:\n\n- **Steps** (`S-01`, …) — every numbered implementation step, with the artefacts it creates or edits.\n- **Requirements** (`R-01`, …) — everything the plan or its sidecar states must be true, including requirements stated only in prose.\n- **Acceptance criteria** (`AC-01`, …) — each with the step that owns it, or `owner: null` if none does.\n- **Cross-references** (`X-01`, …) — file links, ADR numbers, step numbers, sibling documents, testing docs. Each carries `resolves: true|false` against the working tree.\n- **Baseline items** (`B-01`, …) — every requirement, decision, and non-goal in the resolved baseline, by section number. Empty when no baseline resolved.\n- **Ground-truth facts** (`E-01`, …) — for every claim the plan makes *about the repository*, the corresponding repository observation, each carrying the command that produced it and that command's actual output. Walk the `S-`, `R-` and `X-` items and ask of each: what would have to be true on disk or on the default branch for this to hold, and is it? Record the answer either way — a fact that confirms the plan is as useful to a lens as one that contradicts it. Individual lenses state which of these facts they depend on; the inventory's job is to produce them once so no lens has to re-derive them.\n\nEvery inventory item carries an `anchor: {document, heading, quote}`. An item with no anchor is not real.\n\nReport back: the path written and a one-line count per category.\n\n---\n\n## Phase 2 — Adversarial lenses (parallel subagents)\n\n**Read `lenses.md` before spawning.** It holds each lens's question, its evidence obligations, and its worked examples. Spawn one `Agent` per lens from the Step 0.4 roster, passing that lens's brief plus the plan path, the sidecar and testing-doc paths, the baseline path, `\u003CRUN_DIR>\u002Finventory.json`, the head\u002Fbase SHAs, and `scope` if set. Send **all Agent calls for a round in a single message** — lenses must stay blind to each other's findings.\n\nEach lens writes `\u003CRUN_DIR>\u002F\u003Clens>.findings.jsonl`, one JSON object per line, conforming to `schema\u002Ffinding.schema.json`. Omit `verdict`, `cluster_id`, and `canonical` — the orchestrator populates those. A lens that finds nothing writes an **empty file**: zero lines is a checkable clean signal, a missing file is indistinguishable from a crashed agent.\n\nLens tools are read-only apart from one scoped write: `Read`, `Grep`, `Glob`, `Bash` limited to read-only inspection (`ls`, `cat`, `head`, `tail`, `wc`, `find`, `grep`, `git ls-tree`, `git log`, `git diff`, `git show`, `gh pr view`, `gh pr diff`), and `Write` scoped to that lens's own findings file. `Edit` is denied outright.\n\nReport back per lens: the findings-file path and a one-line count by severity.\n\n---\n\n## Phase 3 — Ground-truth verification\n\nEvery finding is a claim until the repository confirms it. Spawn one independent verifier `Agent` per finding — batch all verifier calls for a round into a single message — giving it the finding and the repository, **but not the lens's reasoning**.\n\nThe verifier's job is to **refute**. It must open the cited `path:line` itself, or run the cited command itself, and judge from what it actually sees.\n\n- **Default to `refuted` when uncertain.** A finding survives only when the verifier actively fails to refute it.\n- **A finding whose evidence cannot be produced as a `path:line` or a runnable command is dropped, not softened.** Not downgraded to `minor`, not rephrased as a question — dropped to the \"Considered and dropped\" appendix.\n- **Re-run the command as written and compare counts.** If the finding says \"two matches\" and you get two hundred, the finding is refuted even when its underlying point is sound — the author will run it too and stop trusting the report. The usual cause is an unscoped recursive search picking up this run's directory, the previous pass's document, or a sibling run (see the scope rule in `lenses.md`). Refute it; a lens may re-emit it scoped.\n- Check the three standing false positives: is the quoted plan text actually present and does it say what the finding claims; does another step, the sidecar, or the testing doc already handle this; is this a defect or reviewer preference.\n\nAt `quick` and `standard`, one verifier per finding decides. At `deep`, run **three verifiers per finding with distinct lenses** — *does it reproduce*, *is it actually a defect*, *is it already handled elsewhere* — and require a majority (≥2) to survive; record `votes` and `votes_total`.\n\nThe orchestrator writes each verdict to `\u003CRUN_DIR>\u002Fverdicts\u002F\u003Cfinding-id>.json` and back into the finding record. Neither the verifier nor the original lens performs that write. **Refuted findings are kept, never deleted** — the appendix is what proves the review checked things rather than merely asserted them.\n\n---\n\n## Phase 4 — Adjudication\n\nCluster near-duplicate survivors across lenses into `\u003CRUN_DIR>\u002Fclusters\u002F\u003Ccluster-id>.json`, keep the best-evidenced statement of each as `canonical: true`, and assign severity. Write the ranked result to `\u003CRUN_DIR>\u002Fadjudicated.json`.\n\n| Severity | Meaning |\n|---|---|\n| ? **Merge-blocking** | The plan cannot be implemented as written, or shipping it breaks something live. |\n| ? **Contract gap** | Something the plan is answerable for has no owning mechanism, and no recorded decision explains why. |\n| ? **Minor \u002F mechanical** | Real, evidenced, and narrow — it costs a reader accuracy but does not change what gets built. |\n| ⚖️ **Judgment call for the owner** | An intentional-looking omission the review cannot adjudicate. Frame it as a question, name the two defensible answers, and say what each costs. Never resolve it on the owner's behalf. |\n\nSeverity is assigned from consequence, not from how many lenses raised it. Two lenses agreeing on a stale link is still ?.\n\n---\n\n## Phase 5 — Completeness-critic loop\n\nSpawn one agent with the surviving findings, the refuted findings, the inventory, and the plan. Ask it what **the review** missed:\n\n- Which document in scope was never opened?\n- Which lens was not run, and does its absence leave a real gap?\n- Which claim was accepted on the plan's own authority instead of verified against the repository?\n- Which entity or file the plan touches had its current shape never read?\n- Which inventory item has zero findings anchored to it — nobody quoted it at all?\n\nWhatever it names becomes the next round: re-run the relevant lens(es) with an explicit instruction to focus there, then verify any new findings per Phase 3. Round output goes to `\u003CRUN_DIR>\u002Fcritic\u002Fcompleteness-critic-r\u003CN>.findings.jsonl`.\n\nLoop until a round returns nothing new. **`quick`: no critic loop. `standard`: at most 2 rounds. `deep`: until dry, capped at 6 rounds.**\n\n**Log dropped coverage explicitly** in `coverage.json` and in the report: rounds run, what each surfaced, lenses skipped and why, what `scope` excluded, and any cap that stopped the loop early. A silent cap reads as full coverage — that is the failure mode this phase exists to prevent.\n\n---\n\n## Phase 6 — Findings document\n\nRead `report-template.md` and assemble `target` from it. The template is the contract; populate every section it defines, including Coverage and \"Considered and dropped\".\n\nQuote the plan **verbatim in italics** when the wording is the problem. Cite counts and diff stats. Every claim carries its `path:line` or its runnable command — no hedging adjectives, and no finding reaches the document without one.\n\nReport back to the user: the path written, the verdict line, the count at each severity, and the `RUN_DIR` path.\n\n---\n\n## Rules of engagement\n\n1. **The plan's own claims are evidence of intent, never evidence of fact.** Verify against the repository — open the file, run the command, read the status line.\n2. **Read the decisions sidecar and the testing document, not just the plan.** Requirements hide there, and every lens is expected to have opened them.\n3. **\"Not mentioned\" and \"explicitly out of scope with a reason\" are different findings.** Never conflate them. The first is a gap; the second is a decision, and reporting it as a gap costs the review its credibility.\n4. **Do not propose fixes unless asked.** This is a gate, not implementation. Offer at the end of the run and wait.\n5. **Do not modify the plan, the PR, or any file other than `target` and the run directory.** After a run, `git status --porcelain` must show changes confined to those two.\n\n---\n\n## Non-goals\n\n- **Not a code review.** There is no implementation yet. Use `fsad-harness:code-review-team` once there is.\n- **Not a security review.** Threat modelling of the built system is `fsad-harness:sec-review-team`'s job.\n- **Not an approval.** The document is input to the plan owner's decision, not a merge verdict rendered on their behalf.\n- **Not a rewrite service.** It never edits the plan and never opens a PR.\n- **Not a proposal critique.** Judging a document on its own merits, with no baseline to honour, is `fsad-harness:spec-review`.\n- **Not exhaustive by default.** `quick` and `standard` are bounded on purpose; every bound is logged in Coverage.\n\n---\n\n## Relationship to other skills\n\n| Skill | Stage | Subject | Judged against | Output |\n|---|---|---|---|---|\n| `fsad-harness:spec-review` | Proposal | A spec, PRD, RFC, or design doc | Its own internal consistency | `SPEC-REVIEW.md` beside the document |\n| **`fsad-harness:plan-review`** | **Plan** | **An implementation plan — PR, branch, or planning doc** | **The baseline spec\u002FADR it must honour, and the repository** | **A caller-specified `target`** |\n| `fsad-harness:code-review-team` | Code | A diff or path | Correctness, design, performance, maintainability, testing, API contract | `REVIEW-REPORT.md` |\n| `fsad-harness:sec-review-team` | Code | A codebase or diff | A stack-selected security specialist roster | `REPORT.md` + `known-findings.jsonl` |\n\nRun them in that order. `fsad-harness:plan-review` catches what would otherwise be found in code review at ten times the cost.\n\n---\n\n## Guardrails\n\n- **Never guess a write path.** A missing `target` is a question, not an inference (Parameters).\n- **Never guess the subject.** A glob matching several documents is a question, not a merge (Step 0.1).\n- **Phase 1 completes before Phase 2 starts.** `inventory.json` must exist on disk before the first lens spawns.\n- **`baseline-diff-auditor` runs whenever a baseline resolves** — at every depth. Skipping it is only legal when nothing resolved, and the skip is recorded.\n- **Verifiers default to refuting.** Uncertainty does not survive.\n- **No evidence, no finding.** No `path:line` and no runnable command means dropped to the appendix, not softened into a weaker claim.\n- **Never delete a refuted finding.** It goes to \"Considered and dropped\" with the verifier's reasoning verbatim.\n- **Never silently overwrite a previous pass.** An existing `target` is a second pass with resolved\u002Fcarried-forward\u002Fnew accounting (Step 0.2).\n- **Silent lens-skipping is forbidden**, and so is a silent cap on the critic loop. Both go in Coverage.\n- **The critic loop is bounded** — `standard` at 2 rounds, `deep` at 6. Do not chase marginal findings indefinitely.\n- **Review-only.** The only writable paths for the entire run are `target` and `\u003CRUN_DIR>`.\n","# fsad-harness:plan-review — Adversarial Implementation-Plan Review\n\n**What this optimizes for:** catching the thing that makes the plan unbuildable *before* anyone starts building it. A plan is cheap to change and expensive to have half-built, so the review is worth running exactly once — here — and its value comes from measuring the plan against two things it cannot check for itself: the baseline it promised to honour, and the repository it will actually land in. What that yields in practice is defined per lens in `lenses.md`, not here.\n\nThis is the **plan-stage gate**. It runs before the code-stage gates (`fsad-harness:code-review-team`, `fsad-harness:sec-review-team`) — there is no code yet.\n\nReview-only. The skill writes exactly two things: the findings document at `target`, and the run directory (`run_dir`, defaulting beside `target` — see Parameters). Nothing else on disk is touched.\n\n---\n\n## Asking the user\n\nThis rule covers every question this skill asks the user: a confirmation, a choice, a missing value, a numbered decision list, or a stop-and-ask. It applies even where a later step says \"ask the user\" or \"ask exactly once\". The user may watch the decisions pane rather than the chat, so a question that only goes to chat can go unanswered.\n\n- **When `mcp__decision-tracker__decision` is in your tool list** (loaded, or named as a deferred tool; load a deferred one with `ToolSearch` first), log each question before you ask it:\n  1. Call it with `action: \"open\"`, the question (ending in `?`), and `options` when the answers are a closed set. Set `required: false` when the work can go on without an answer. A numbered list of questions opens one decision per item. Keep each returned `id`.\n  2. Ask the question in chat as this skill says. The open call does not replace the chat question.\n  3. When the user answers, in chat or as a `Decision Dn: \u003Canswer>` message from the plugin, call the tool with `action: \"close\"`, the `id` and the answer.\n  4. When the change the answer asked for is in place, call it with `action: \"implement\"`, the `id` and a `path:line`.\n- **When the tool is absent**, ask in chat only.\n- An `AskUserQuestion` call is logged on its own. Do not open it again.\n- This rule changes where a question is logged. It does not change when this skill asks, or how many times.\n\n## Parameters\n\n| Parameter | Required | Accepts | Notes |\n|---|---|---|---|\n| `source` | **yes** | A GitHub PR (`#439`, a full URL, or `owner\u002Frepo#N`), a branch name, a file path, or a glob | The plan under review. |\n| `target` | **yes** | A file path | Where the findings document is written. Parent directories are created. |\n| `baseline` | no | Path(s) to a spec, ADR, prior plan, or PR that `source` is meant to honour or supersede | When omitted, candidates are inferred (Step 0.3) and the chosen one is named in the report header. |\n| `depth` | no | `quick` \\| `standard` (default) \\| `deep` | Controls the lens roster, verifier count, and critic rounds (Step 0.4). |\n| `scope` | no | Free text | Narrows the review, e.g. \"schema and migration steps only\". Recorded verbatim in the report header. |\n| `run_dir` | no | A directory path | Where the run artefacts go. Defaults to `\u003Cdirectory containing target>\u002F.plan-review\u002Fruns\u002F\u003Crun_id>\u002F`. Set it to keep artefacts out of the repository, or to place them somewhere the caller's tooling already collects. The internal layout (Step 0.6) is fixed wherever it points. |\n\n**The skill prompts for any required parameter the invocation did not supply, and it never guesses a write path.** If `target` was not given, ask for it — do not infer one from the plan's location, do not default to a filename beside the plan, and do not proceed with a placeholder. If `source` was not given, ask for it — do not review \"the most recent plan\" or \"the current branch\" on your own initiative. A wrong target written confidently is worse than a question.\n\n---\n\n## When to skip\n\nSay so and stop, rather than producing a report that pads a non-problem:\n\n- **Single-step plans.** One step, one file, one acceptance criterion. There is no sequencing to audit, no cross-reference graph, and no baseline drift to measure. A normal read is cheaper and just as good.\n- **Plans with no baseline and no cross-references.** If nothing resolves as `baseline` and the plan cites no ADRs, no sibling documents, no numbered artefacts, and no source files, then five of the seven lenses have nothing to check against — the review degenerates into proofreading. Offer `fsad-harness:spec-review` instead, which judges a document on its own terms.\n- **Pure-copy edits.** Wording, formatting, typo, or link-text changes to an existing plan. Diff the prose; do not convene a review team.\n\nIf the user asks anyway after being told, run it — say what the reduced roster will be first.\n\n---\n\n## Step 0 — Resolve parameters\n\n### 0.1 Resolve `source`\n\n| `source` looks like | Resolution |\n|---|---|\n| `#N`, `owner\u002Frepo#N`, or a PR URL | `gh pr view \u003CN> --json number,title,headRefName,baseRefName,headRefOid,baseRefOid,body,files,url` then `gh pr diff \u003CN>`. |\n| A branch name | `git rev-parse \u003Cbranch>` for the head SHA; merge-base against the default branch for the base SHA; `git diff \u003Cbase>...\u003Cbranch> --stat`. |\n| A file path | The plan document itself. Head SHA = `git rev-parse HEAD`; no base SHA. |\n| A glob | Expand it. If it matches more than one document, list the matches and **ask which is the plan** — the rest become supporting documents, not additional subjects. |\n\nFor every form, establish and record: the **head SHA**, the **base SHA** (where one exists), and **whether the base is behind the repository's default branch**. Pass all three to `consistency-checker`, which owns base drift — its brief in `lenses.md` says how to measure it and how to grade it.\n\nThen collect the plan's supporting documents:\n\n- The **decisions sidecar** — glob for `\u003Cplan-basename>-decisions.md` in the plan's own directory (see Path conventions). Requirements hide there.\n- The **testing document** — any document the plan cross-references whose name matches `test|qa|verification`.\n- For a PR, the **PR body** — it frequently names the baseline the description in the plan file omits.\n\nRead all of them. A document not read cannot be cited, and the completeness critic will ask which ones you skipped.\n\n### 0.2 Resolve `target` and detect a second pass\n\nCreate `target`'s parent directories. Then:\n\n- **`target` does not exist** — first pass. Write a fresh document.\n- **`target` exists** — **second pass.** Read it in full *before* Phase 1, and extract its previous findings into `\u003CRUN_DIR>\u002Fprevious-findings.json`. The new document must:\n  - **Mark resolved** — a previous finding whose evidence no longer reproduces at the new head SHA. Say what changed and cite the new `path:line`.\n  - **Carry forward still-open** — a previous finding that still reproduces, keeping its original identifier and noting how many passes it has survived.\n  - **State what changed** — a \"Since the previous pass\" block naming the previous head SHA, the new head SHA, the counts resolved \u002F still open \u002F newly raised.\n\n  Never silently overwrite a previous pass's findings. A finding that disappears without being marked resolved is a review failure, not a clean bill of health.\n\n### 0.3 Resolve `baseline`\n\nIf `baseline` was supplied, use it. Otherwise infer candidates, in this order, and **state in the report header which was chosen and why**:\n\n1. Any document the PR body or plan preamble names as the thing it implements, supersedes, or follows.\n2. Documents matching `spec|prd|rfc|adr|proposal|design` under the configured spec\u002FADR directories (Path conventions below).\n3. The immediately preceding numbered plan in the same directory, if the plan's own numbering pattern implies one.\n\nIf more than one candidate survives and no signal separates them, **ask**. If none resolves, record `baseline: none` in the header, skip `baseline-diff-auditor`, and say so in Coverage — a silent skip reads as \"nothing was dropped\", which is exactly the false negative this skill exists to prevent.\n\n### 0.4 Resolve `depth` and select the roster\n\n| Lens | `quick` | `standard` | `deep` |\n|---|:---:|:---:|:---:|\n| `completeness-auditor` | ● | ● | ● |\n| `consistency-checker` | ● | ● | ● |\n| `testability-auditor` | ○ | ● | ● |\n| `logic-auditor` | | ● | ● |\n| `assumption-hunter` | | ● | ● |\n| `feasibility-critic` | | ○ | ● |\n| `baseline-diff-auditor` | ○ | ○ | ● |\n\n● = always runs. ○ = conditional, resolved as follows so the counts stay fixed:\n\n- **`quick` runs exactly 3 lenses.** The third slot is `baseline-diff-auditor` when a baseline resolved, `testability-auditor` when none did.\n- **`standard` runs exactly 6 lenses.** The sixth slot is `baseline-diff-auditor` when a baseline resolved, `feasibility-critic` when none did.\n- **`deep` runs all 7, then a duplicate pass of all 7** with different seeds — different reading order, and an instruction to start from the sections the first pass is least likely to have reached. Duplicate-pass output goes to `\u003Clens>-b.findings.jsonl`. 14 lens files.\n\n`baseline-diff-auditor` is **required whenever a baseline resolves**, at every depth. It is skipped only when no baseline resolves. Every lens not run is recorded in Coverage with its reason — silent skipping is forbidden.\n\nVerifier count and critic rounds follow depth: see Phase 3 and Phase 5.\n\n### 0.5 Apply `scope`\n\nIf `scope` is set, pass it verbatim into every lens brief as a narrowing instruction, and record it in the report header. Findings outside scope are not raised. **Log what scope excluded** in Coverage — a narrowed review that reads as a full one is a silent cap.\n\n### 0.6 Set up the run directory\n\n```\nRUN_DIR = \u003Cthe `run_dir` parameter, if given>\n       or \u003Cdirectory containing target>\u002F.plan-review\u002Fruns\u002F\u003Crun_id>\u002F   ← default\n```\n\n`run_id` is an ISO-timestamp-derived slug. Create it before Phase 1. Layout:\n\n```\n\u003CRUN_DIR>\u002F\n├── inventory.json                      # Phase 1 — written before any lens starts\n├── \u003Clens>.findings.jsonl               # Phase 2 — one per lens (deep adds \u003Clens>-b)\n├── verdicts\u002F\u003Cfinding-id>.json          # Phase 3 — one per finding\n├── clusters\u002F\u003Ccluster-id>.json          # Phase 4 — near-duplicates merged across lenses\n├── adjudicated.json                    # Phase 4 — final severity-ranked set\n├── critic\u002Fcompleteness-critic-r\u003CN>.findings.jsonl   # Phase 5 — one per round\n├── coverage.json                       # lenses run\u002Fskipped, rounds, what scope excluded\n└── previous-findings.json              # second pass only\n```\n\nCritic rounds live under `critic\u002F` rather than at the run-dir root deliberately: it keeps `ls \u003CRUN_DIR>\u002F*.findings.jsonl` an exact count of the lenses that ran, which is how the depth roster is audited.\n\n---\n\n## Path conventions — discovered or configured, never assumed\n\nThis skill is repo-agnostic: it hardcodes no project's layout. Every path it reads from and every path it writes to is either **discovered from the repository** or **supplied by the caller**, and every default below is documented. Nothing here is a fixed requirement a project must reorganise itself to satisfy.\n\n### Read paths — discovered or configured\n\n| Concept | How it is resolved | Default used as a search hint | If it can't be resolved |\n|---|---|---|---|\n| Plan location | The `source` parameter. Required; never inferred. | — | **Ask.** Never guess the subject. |\n| Baseline candidates | Step 0.3 — the PR body and plan preamble first, then a glob over conventional spec\u002FADR directories. | `planning\u002Fspec\u002F`, `planning\u002Fprd\u002F`, `docs\u002Fadr\u002F`, `docs\u002Frfc\u002F` | **Ask** only when *several* candidates survive and no signal separates them. When *none* resolves, record `baseline: none`, skip `baseline-diff-auditor`, and say so in Coverage — do not ask, and do not stop. |\n| Decisions sidecar | Glob for `\u003Cplan-basename>-decisions.md` in **the plan's own directory**, whatever that directory is. | same directory as the plan | Absent is normal. Record it and continue. |\n| Testing document | A cross-reference from the plan whose target name matches `test\\|qa\\|verification`. | — no directory assumed | Absent is normal. Record it and continue. |\n| Numbering pattern | Inferred from the plan's own artefact names (e.g. `NNN-slug.md`, `VNNN__slug.sql`). What is done with it is `consistency-checker`'s business. | pattern inferred, never assumed | No inferable pattern means that lens has no collision check to run. Record it in Coverage. |\n\n**A missing read path is a fact about the repository, not an error.** A repo with no `planning\u002F`, no `docs\u002Fadr\u002F`, and no sidecar is a normal input: the probes miss, the affected lenses narrow, Coverage records what was unavailable, and the run completes. The one case that stops and asks is an *ambiguous* input — a glob matching several documents (Step 0.1), or several baseline candidates with nothing to separate them (Step 0.3).\n\n### Write paths — configured, with a derived default\n\nThe skill writes to exactly two places, and neither is guessed:\n\n| Path | How it is set | Default |\n|---|---|---|\n| `target` | **Caller-supplied, always.** Required, never inferred. If it was not given, **ask** — this is the one path the skill will never default. | — |\n| `\u003CRUN_DIR>` | The `run_dir` parameter when given; otherwise derived from `target`. | `\u003Cdirectory containing target>\u002F.plan-review\u002Fruns\u002F\u003Crun_id>\u002F` |\n\nWhat is *not* configurable is the run directory's **internal** layout (Step 0.6) — the filenames and subdirectories are this skill's own convention, because the depth audit and the second-pass logic both read them by name. Callers choose where the run directory lives; they do not rearrange what is inside it.\n\n---\n\n## Phase 1 — Inventory (single agent, before any lens)\n\nBuild `\u003CRUN_DIR>\u002Finventory.json` first. **No lens may start until it exists** — lenses cite inventory IDs, and a lens that re-derives its own inventory produces findings nobody else can cluster against.\n\nSpawn one agent to extract, assigning every item a stable ID:\n\n- **Steps** (`S-01`, …) — every numbered implementation step, with the artefacts it creates or edits.\n- **Requirements** (`R-01`, …) — everything the plan or its sidecar states must be true, including requirements stated only in prose.\n- **Acceptance criteria** (`AC-01`, …) — each with the step that owns it, or `owner: null` if none does.\n- **Cross-references** (`X-01`, …) — file links, ADR numbers, step numbers, sibling documents, testing docs. Each carries `resolves: true|false` against the working tree.\n- **Baseline items** (`B-01`, …) — every requirement, decision, and non-goal in the resolved baseline, by section number. Empty when no baseline resolved.\n- **Ground-truth facts** (`E-01`, …) — for every claim the plan makes *about the repository*, the corresponding repository observation, each carrying the command that produced it and that command's actual output. Walk the `S-`, `R-` and `X-` items and ask of each: what would have to be true on disk or on the default branch for this to hold, and is it? Record the answer either way — a fact that confirms the plan is as useful to a lens as one that contradicts it. Individual lenses state which of these facts they depend on; the inventory's job is to produce them once so no lens has to re-derive them.\n\nEvery inventory item carries an `anchor: {document, heading, quote}`. An item with no anchor is not real.\n\nReport back: the path written and a one-line count per category.\n\n---\n\n## Phase 2 — Adversarial lenses (parallel subagents)\n\n**Read `lenses.md` before spawning.** It holds each lens's question, its evidence obligations, and its worked examples. Spawn one `Agent` per lens from the Step 0.4 roster, passing that lens's brief plus the plan path, the sidecar and testing-doc paths, the baseline path, `\u003CRUN_DIR>\u002Finventory.json`, the head\u002Fbase SHAs, and `scope` if set. Send **all Agent calls for a round in a single message** — lenses must stay blind to each other's findings.\n\nEach lens writes `\u003CRUN_DIR>\u002F\u003Clens>.findings.jsonl`, one JSON object per line, conforming to `schema\u002Ffinding.schema.json`. Omit `verdict`, `cluster_id`, and `canonical` — the orchestrator populates those. A lens that finds nothing writes an **empty file**: zero lines is a checkable clean signal, a missing file is indistinguishable from a crashed agent.\n\nLens tools are read-only apart from one scoped write: `Read`, `Grep`, `Glob`, `Bash` limited to read-only inspection (`ls`, `cat`, `head`, `tail`, `wc`, `find`, `grep`, `git ls-tree`, `git log`, `git diff`, `git show`, `gh pr view`, `gh pr diff`), and `Write` scoped to that lens's own findings file. `Edit` is denied outright.\n\nReport back per lens: the findings-file path and a one-line count by severity.\n\n---\n\n## Phase 3 — Ground-truth verification\n\nEvery finding is a claim until the repository confirms it. Spawn one independent verifier `Agent` per finding — batch all verifier calls for a round into a single message — giving it the finding and the repository, **but not the lens's reasoning**.\n\nThe verifier's job is to **refute**. It must open the cited `path:line` itself, or run the cited command itself, and judge from what it actually sees.\n\n- **Default to `refuted` when uncertain.** A finding survives only when the verifier actively fails to refute it.\n- **A finding whose evidence cannot be produced as a `path:line` or a runnable command is dropped, not softened.** Not downgraded to `minor`, not rephrased as a question — dropped to the \"Considered and dropped\" appendix.\n- **Re-run the command as written and compare counts.** If the finding says \"two matches\" and you get two hundred, the finding is refuted even when its underlying point is sound — the author will run it too and stop trusting the report. The usual cause is an unscoped recursive search picking up this run's directory, the previous pass's document, or a sibling run (see the scope rule in `lenses.md`). Refute it; a lens may re-emit it scoped.\n- Check the three standing false positives: is the quoted plan text actually present and does it say what the finding claims; does another step, the sidecar, or the testing doc already handle this; is this a defect or reviewer preference.\n\nAt `quick` and `standard`, one verifier per finding decides. At `deep`, run **three verifiers per finding with distinct lenses** — *does it reproduce*, *is it actually a defect*, *is it already handled elsewhere* — and require a majority (≥2) to survive; record `votes` and `votes_total`.\n\nThe orchestrator writes each verdict to `\u003CRUN_DIR>\u002Fverdicts\u002F\u003Cfinding-id>.json` and back into the finding record. Neither the verifier nor the original lens performs that write. **Refuted findings are kept, never deleted** — the appendix is what proves the review checked things rather than merely asserted them.\n\n---\n\n## Phase 4 — Adjudication\n\nCluster near-duplicate survivors across lenses into `\u003CRUN_DIR>\u002Fclusters\u002F\u003Ccluster-id>.json`, keep the best-evidenced statement of each as `canonical: true`, and assign severity. Write the ranked result to `\u003CRUN_DIR>\u002Fadjudicated.json`.\n\n| Severity | Meaning |\n|---|---|\n| ? **Merge-blocking** | The plan cannot be implemented as written, or shipping it breaks something live. |\n| ? **Contract gap** | Something the plan is answerable for has no owning mechanism, and no recorded decision explains why. |\n| ? **Minor \u002F mechanical** | Real, evidenced, and narrow — it costs a reader accuracy but does not change what gets built. |\n| ⚖️ **Judgment call for the owner** | An intentional-looking omission the review cannot adjudicate. Frame it as a question, name the two defensible answers, and say what each costs. Never resolve it on the owner's behalf. |\n\nSeverity is assigned from consequence, not from how many lenses raised it. Two lenses agreeing on a stale link is still ?.\n\n---\n\n## Phase 5 — Completeness-critic loop\n\nSpawn one agent with the surviving findings, the refuted findings, the inventory, and the plan. Ask it what **the review** missed:\n\n- Which document in scope was never opened?\n- Which lens was not run, and does its absence leave a real gap?\n- Which claim was accepted on the plan's own authority instead of verified against the repository?\n- Which entity or file the plan touches had its current shape never read?\n- Which inventory item has zero findings anchored to it — nobody quoted it at all?\n\nWhatever it names becomes the next round: re-run the relevant lens(es) with an explicit instruction to focus there, then verify any new findings per Phase 3. Round output goes to `\u003CRUN_DIR>\u002Fcritic\u002Fcompleteness-critic-r\u003CN>.findings.jsonl`.\n\nLoop until a round returns nothing new. **`quick`: no critic loop. `standard`: at most 2 rounds. `deep`: until dry, capped at 6 rounds.**\n\n**Log dropped coverage explicitly** in `coverage.json` and in the report: rounds run, what each surfaced, lenses skipped and why, what `scope` excluded, and any cap that stopped the loop early. A silent cap reads as full coverage — that is the failure mode this phase exists to prevent.\n\n---\n\n## Phase 6 — Findings document\n\nRead `report-template.md` and assemble `target` from it. The template is the contract; populate every section it defines, including Coverage and \"Considered and dropped\".\n\nQuote the plan **verbatim in italics** when the wording is the problem. Cite counts and diff stats. Every claim carries its `path:line` or its runnable command — no hedging adjectives, and no finding reaches the document without one.\n\nReport back to the user: the path written, the verdict line, the count at each severity, and the `RUN_DIR` path.\n\n---\n\n## Rules of engagement\n\n1. **The plan's own claims are evidence of intent, never evidence of fact.** Verify against the repository — open the file, run the command, read the status line.\n2. **Read the decisions sidecar and the testing document, not just the plan.** Requirements hide there, and every lens is expected to have opened them.\n3. **\"Not mentioned\" and \"explicitly out of scope with a reason\" are different findings.** Never conflate them. The first is a gap; the second is a decision, and reporting it as a gap costs the review its credibility.\n4. **Do not propose fixes unless asked.** This is a gate, not implementation. Offer at the end of the run and wait.\n5. **Do not modify the plan, the PR, or any file other than `target` and the run directory.** After a run, `git status --porcelain` must show changes confined to those two.\n\n---\n\n## Non-goals\n\n- **Not a code review.** There is no implementation yet. Use `fsad-harness:code-review-team` once there is.\n- **Not a security review.** Threat modelling of the built system is `fsad-harness:sec-review-team`'s job.\n- **Not an approval.** The document is input to the plan owner's decision, not a merge verdict rendered on their behalf.\n- **Not a rewrite service.** It never edits the plan and never opens a PR.\n- **Not a proposal critique.** Judging a document on its own merits, with no baseline to honour, is `fsad-harness:spec-review`.\n- **Not exhaustive by default.** `quick` and `standard` are bounded on purpose; every bound is logged in Coverage.\n\n---\n\n## Relationship to other skills\n\n| Skill | Stage | Subject | Judged against | Output |\n|---|---|---|---|---|\n| `fsad-harness:spec-review` | Proposal | A spec, PRD, RFC, or design doc | Its own internal consistency | `SPEC-REVIEW.md` beside the document |\n| **`fsad-harness:plan-review`** | **Plan** | **An implementation plan — PR, branch, or planning doc** | **The baseline spec\u002FADR it must honour, and the repository** | **A caller-specified `target`** |\n| `fsad-harness:code-review-team` | Code | A diff or path | Correctness, design, performance, maintainability, testing, API contract | `REVIEW-REPORT.md` |\n| `fsad-harness:sec-review-team` | Code | A codebase or diff | A stack-selected security specialist roster | `REPORT.md` + `known-findings.jsonl` |\n\nRun them in that order. `fsad-harness:plan-review` catches what would otherwise be found in code review at ten times the cost.\n\n---\n\n## Guardrails\n\n- **Never guess a write path.** A missing `target` is a question, not an inference (Parameters).\n- **Never guess the subject.** A glob matching several documents is a question, not a merge (Step 0.1).\n- **Phase 1 completes before Phase 2 starts.** `inventory.json` must exist on disk before the first lens spawns.\n- **`baseline-diff-auditor` runs whenever a baseline resolves** — at every depth. Skipping it is only legal when nothing resolved, and the skip is recorded.\n- **Verifiers default to refuting.** Uncertainty does not survive.\n- **No evidence, no finding.** No `path:line` and no runnable command means dropped to the appendix, not softened into a weaker claim.\n- **Never delete a refuted finding.** It goes to \"Considered and dropped\" with the verifier's reasoning verbatim.\n- **Never silently overwrite a previous pass.** An existing `target` is a second pass with resolved\u002Fcarried-forward\u002Fnew accounting (Step 0.2).\n- **Silent lens-skipping is forbidden**, and so is a silent cap on the critic loop. Both go in Coverage.\n- **The critic loop is bounded** — `standard` at 2 rounds, `deep` at 6. Do not chase marginal findings indefinitely.\n- **Review-only.** The only writable paths for the entire run are `target` and `\u003CRUN_DIR>`.\n",{"description":7,"argument-hint":45},"`\u003Csource> \u003Ctarget> [--baseline \u003Cpath>] [--depth quick|standard|deep] [--scope \u003Ctext>] [--run-dir \u003Cpath>]`","main","bf3a412c985273327682c956ca35341c64ce9f8c","skills\u002Fplan-review",4,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook","https:\u002F\u002Ffsad-playbook.vercel.app","https:\u002F\u002Fgithub.com\u002Ftbeack","2026-11-11 21:04:33",{"source":8,"skillName":5,"commands":55,"prompt":65,"zipAvailable":66},[56,59,62],{"tool":57,"command":58},"npx","npx skills add tbeack\u002Ffsad_playbook --skill plan-review",{"tool":60,"command":61},"bunx","bunx skills add tbeack\u002Ffsad_playbook --skill plan-review",{"tool":63,"command":64},"pnpm","pnpm dlx skills add tbeack\u002Ffsad_playbook --skill plan-review","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fplan-review\u002FSKILL.md",true,[68,74,80,84,88],{"path":69,"resourceType":70,"resourceTypeDesc":71,"sizeBytes":72,"sourceHtmlUrl":73},"checks\u002Fexempt-lines.txt","REFERENCE","参考文档",1326,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fplan-review\u002Fchecks\u002Fexempt-lines.txt",{"path":75,"resourceType":76,"resourceTypeDesc":77,"sizeBytes":78,"sourceHtmlUrl":79},"checks\u002Fhygiene-check.py","SCRIPT","脚本",12298,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fplan-review\u002Fchecks\u002Fhygiene-check.py",{"path":81,"resourceType":70,"resourceTypeDesc":71,"sizeBytes":82,"sourceHtmlUrl":83},"lenses.md",22854,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fplan-review\u002Flenses.md",{"path":85,"resourceType":70,"resourceTypeDesc":71,"sizeBytes":86,"sourceHtmlUrl":87},"report-template.md",6659,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fplan-review\u002Freport-template.md",{"path":89,"resourceType":70,"resourceTypeDesc":71,"sizeBytes":90,"sourceHtmlUrl":91},"schema\u002Ffinding.schema.json",7111,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fplan-review\u002Fschema\u002Ffinding.schema.json",[93,114,135,154,174,202],{"skillNo":94,"name":95,"nameZh":6,"description":96,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":97,"categories":98,"keywords":99,"publishedAt":40},"01M6K7W5RTRMRQMWAGXNSX8DM6","sync","Pre-flight sync check for registered projects. Fetches from remote, reports uncommitted changes, and handles four states — up-to-date, ahead, behind (warns + pulls), or diverged (warns, no pull). Supports single-project (cwd detection), named-project (fsad-harness:sync key1 key2), and full-sync (fsad-harness:sync ALL) modes.","https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsync\u002FSKILL.md",[],[95,100,101,102,103,104,32,105,106,107,108,109,110,111,112,113],"pull","harness","detection","projects","check","reports","project","full","remote","states","for","changes","modes","single",{"skillNo":115,"name":116,"nameZh":6,"description":117,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":118,"categories":119,"keywords":125,"publishedAt":40},"01M6K7VY55SWBDD379T9JZVF16","spec-review","Run a detailed, adversarial multi-agent review of a written proposal or specification (spec.md, PRD, RFC, design doc, architecture proposal, business case) — reviews the document, not code. Runs a steelman\u002Finventory pass, then up to 10 specialist lenses (logic, assumptions, evidence, completeness, feasibility, alternatives, consistency, stakeholders, testability, risk), then adversarial validation that defaults to refuting each finding unless it survives, then a loop-until-dry completeness pass. Writes a single severity-ranked SPEC-REVIEW.md next to the document. Use when the user says \"review this spec\", \"adversarial review\", \"poke holes in this proposal\", \"red team this PRD\", \"critique this design doc\", \"what's wrong with this RFC\", \"stress test this plan\", or similar. Review-only — never edits the document.","https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fspec-review\u002FSKILL.md",[120],{"categoryNo":121,"categoryName":122,"taxonomyType":123,"taxonomyTypeDesc":124},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[21,126,127,128,129,39,38,36,130,33,22,32,131,132,30,29,133,134,26,25,23],"spec","spec review","design","architecture","loop","specification","poke","proposal","lens",{"skillNo":136,"name":137,"nameZh":6,"description":138,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":139,"categories":140,"keywords":141,"publishedAt":40},"01M6K7VVD3B0SM3VKJ5W26QPPV","ship","Short alias for \u002Ffsad-harness:ship-it. Wrap up finished work, cut a version, commit, push, and open a PR.","https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fship\u002FSKILL.md",[],[137,142,143,101,144,145,146,147,148,149,32,150,151,152,153,110],"commit","pr","push","open","wrap up","work","short","version","wrap","alias","cut","it",{"skillNo":155,"name":156,"nameZh":6,"description":157,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":158,"categories":159,"keywords":160,"publishedAt":40},"01M6K7VP2QDRNX57KP2RH10FAW","ship-it","Wrap up a finished round of work — verify README and CHANGELOG are current, cut a version if warranted, move completed task files into the completed\u002F folder, then create a feature branch if needed, commit, push, and open a PR. Run after `\u002Ffsad-harness:do-task` has marked one or more tasks done. Takes no arguments.","https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fship-it\u002FSKILL.md",[],[137,161,153,142,162,163,145,164,165,147,34,166,32,167,168,169,170,171,108,172,173],"ship it","tasks","create","Bash","gh pr","fetch","log","files","done","checkout","move","ls","parse",{"skillNo":175,"name":176,"nameZh":6,"description":177,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":178,"categories":179,"keywords":180,"publishedAt":40},"01M6K7VEK1C0MK5BNDHV8S6HCA","set-context","Gather codebase and initiative context before planning starts — runs a graphify build or query when graphify is available locally, falls back to a manual repo sweep otherwise, then asks targeted questions and writes a single context.md. Invocable standalone or as fsad-harness:plan's mandatory Phase 0. Use when the user says \"set context\", \"gather context\", or as the first step of fsad-harness:plan.","https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fset-context\u002FSKILL.md",[],[181,182,183,184,101,185,186,19,187,188,189,190,191,192,193,194,195,196,197,198,199,113,200,201,23],"SET","context","set context","planning","first","graphify","sweep","repo","user","use","build","back","query","as","questions","manual","standalone","path","codebase","phase","gather",{"skillNo":203,"name":204,"nameZh":6,"description":205,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":206,"categories":207,"keywords":212,"publishedAt":40},"01M6K7V17M3MQ92QZ99G294RYM","sec-review-team","Run a multi-agent security review TEAM over a codebase or recent diff. Picks a specialist roster based on detected stack signals (webapp \u002F desktop \u002F iac \u002F llm-agent \u002F container \u002F backend \u002F mobile \u002F etc.) from a library of 13 specialists. Each specialist writes structured JSONL + prose findings in parallel; input-validation-auditor and auth-authz-auditor run a loop-until-dry consensus fan-out (2-8 passes); every deduped finding is adversarially verified by a dedicated validator agent before it can appear in the report. Orchestrator consolidates into a single severity-ranked REPORT.md with deduped root issues, archived per-run under a known-findings.jsonl ledger that drives auto re-review. Distinct from the built-in `\u002Fsecurity-review` (which is a single-pass branch review). Use when the user says \"multi-agent security review\", \"security review team\", \"sec-review team\", \"audit this branch with a team\", \"pre-release hardening team pass\", or similar. Review-only — no fixes.","https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002FSKILL.md",[208,211],{"categoryNo":209,"categoryName":210,"taxonomyType":123,"taxonomyTypeDesc":124},"01JBSEEDCAT000000000000010","后端与接口",{"categoryNo":121,"categoryName":122,"taxonomyType":123,"taxonomyTypeDesc":124},[21,36,213,214,215,216,217,218,219,130,220,34,221,222,223,29,224,225,226,227,228],"sec review team","review team","agent security","security review","run","release","security-review","stack","consensus","auto","mobile","input","re","jsonl","which","verified"]