[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6K7V17M3MQ92QZ99G294RYM":3,"skill-same:01M6K7V17M3MQ92QZ99G294RYM":422},{"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":26,"publishedAt":48,"linkOnly":49,"markdownContent":50,"markdownBody":51,"frontMatter":52,"refName":54,"commitSha":55,"skillDirectory":56,"forksCount":57,"repositoryHtmlUrl":58,"repositoryHomepageUrl":59,"ownerHtmlUrl":60,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":61,"install":62,"resources":75},"01M6K7V17M3MQ92QZ99G294RYM","sec-review-team",null,"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.","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\u002Fsec-review-team\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47],"review team","sec review team","team","review","consensus","verified","which","jsonl","re","input","dry","mobile","auto","branch","stack","loop","security-review","release","run","security review","agent security","2026-11-10 10:12:30",false,"---\ndescription: 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.\nargument-hint: '`[target path] [scope: all | \u003Csubdir> | diff vs main] [--lite] [--yes]`'\n---\n\n# Multi-Agent Security Review Team — Orchestration\n\n**What this optimizes for:** two complementary guarantees, in this order of priority. First, coverage-of-absence — a \"clean\" verdict on any category must cite the searches that back it, never a bare assertion. Second, verification-of-positives — a finding only reaches the report after surviving independent adversarial validation (Step 4.5) against a category-appropriate proof standard, with self-reported specialist confidence no longer sufficient on its own. \"Done\" means every roster specialist's owned categories are accounted for (checked-clean, checked-issues-found, or explicitly not-checked with a reason), and every surviving finding in the report is validator-confirmed, not merely raised.\n\nFollow these steps. Review-only. Never apply fixes.\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## Step 0: Pre-run confirmation\n\nThe skill's largest user-facing safety gate. Never spawn specialists without showing this block (unless `--yes` \u002F `auto-approve` is passed).\n\n### 0.1 Parse arguments\n\n- **Target path** — absolute path. If missing, ask: *\"What repo should I review? (absolute path)\"* Verify it exists and is readable.\n- **Scope** — one of:\n  - `all` — full tree\n  - `\u003Csubdir>` — a subdirectory, e.g. `src\u002Fapi\u002F`\n  - `diff vs main` (or `diff vs \u003Cbranch>`) — only files changed on current branch vs target branch\n  If missing, ask: *\"What scope? Full tree, a subdirectory, or a diff?\"*\n- **Flags:**\n  - `--yes` \u002F `-y` — skip confirmation entirely. Default is to confirm.\n  - `--lite` \u002F `-l` — run only the baseline 4 (`secrets-crypto-auditor`, `dependency-supplychain-auditor`, `silent-failure-hunter`, `data-exposure-auditor`) plus `auth-authz-auditor` and `input-validation-auditor` when the stack roster would otherwise include them (5–6 agent subset). Auto-activated when scope is a diff with ≤25 changed files, same threshold as `code-review-team`.\n  - `--full` — force a fresh baseline scan, ignoring any prior run history for this target (see Step 0.1a). Without this flag, a target with prior history runs in re-review mode automatically.\n\n### 0.1a Detect prior run (re-review mode)\n\nEvery run writes its artifacts under a run-scoped directory, `RUN_DIR = \u003CTARGET>\u002F.planning\u002Fsecurity-review\u002Fruns\u002F\u003Crun_id>\u002F` (`run_id` = an ISO-timestamp-derived slug), so a later run never overwrites an earlier one. Runs accumulate a top-level ledger at `\u003CTARGET>\u002F.planning\u002Fsecurity-review\u002Fknown-findings.jsonl` — one record per validator-confirmed `root_issue` ever reported for this target (`root_issue`, `title`, `severity`, `first_seen_run_id`, `first_seen_date`, `file`, `evidence_snippet` — the latter two exist solely so a later run can cheaply re-verify the issue is still actually present before reporting it as \"still open\"; see Step 4.5's ledger-append and re-verification logic).\n\n1. Check whether `\u003CTARGET>\u002F.planning\u002Fsecurity-review\u002Fknown-findings.jsonl` exists.\n2. **Exists, and `--full` was not passed** → `re_review_mode = true`. This run skips `root_issue`s already in the ledger and suppresses all `low`\u002F`info`-severity findings from the report (Step 4.5's re-review filter, `re_review_mode` branch — sec-review-team's severity floor for \"nit-equivalent\" is `low`\u002F`info`, mirroring `code-review-team`'s nit suppression). Announce this in the Step 0.7 confirmation block.\n3. **Missing, or `--full` was passed** → `re_review_mode = false`. This is a baseline scan; every validator-confirmed finding is eligible for the report, and the ledger is (re)built from this run's results.\n\nAll `RUN_DIR`-relative paths referenced in Steps 0.9 through 5 below resolve against the `RUN_DIR` computed here — the ledger itself is the one exception, always written at the top-level `\u003CTARGET>\u002F.planning\u002Fsecurity-review\u002F` regardless of `run_id`.\n\n### 0.2 Enumerate scope\n\nUse git-aware commands (fall back to `find` if not a git repo):\n\n```bash\n# File count + line count (scoped)\ncd \"\u003CTARGET>\"\nif [[ \"\u003CSCOPE>\" == \"all\" ]]; then\n  FILE_COUNT=$(git ls-files | wc -l)\n  LINE_COUNT=$(git ls-files | xargs wc -l 2>\u002Fdev\u002Fnull | tail -1 | awk '{print $1}')\nelif [[ \"\u003CSCOPE>\" == diff* ]]; then\n  BASE=\"${SCOPE#diff vs }\"; BASE=\"${BASE:-main}\"\n  FILES=$(git diff --name-only \"$BASE\"...HEAD)\n  FILE_COUNT=$(echo \"$FILES\" | wc -l)\n  LINE_COUNT=$(echo \"$FILES\" | xargs wc -l 2>\u002Fdev\u002Fnull | tail -1 | awk '{print $1}')\nelse\n  FILE_COUNT=$(git ls-files \"\u003CSCOPE>\" | wc -l)\n  LINE_COUNT=$(git ls-files \"\u003CSCOPE>\" | xargs wc -l 2>\u002Fdev\u002Fnull | tail -1 | awk '{print $1}')\nfi\n```\n\nCap `LINE_COUNT` at 500k (anything larger: warn and suggest scope narrowing).\n\n### 0.3 Detect stack signals\n\nRead the highest-signal manifests first (cheapest): `README.md` top 50 lines, `package.json`, `Cargo.toml`, `pyproject.toml`, `go.mod`, `Gemfile`, `tauri.conf.json`, `Dockerfile`, `.github\u002Fworkflows\u002F` (existence only), `requirements.txt`. Two or three file-reads is enough.\n\nApply each rule in `stack-signals.md` against what you observe. Collect matching signals (multiple can match). Example: a Tauri note app emits `desktop` + `desktop-with-webview`.\n\n### 0.4 Pick default roster\n\nPer `stack-signals.md`: union the specialist sets across all matching stack signals. Always include the baseline 4 (`secrets-crypto-auditor`, `dependency-supplychain-auditor`, `silent-failure-hunter`, `data-exposure-auditor`).\n\n**`--lite` mode** (explicit flag or diff ≤25 files, per 0.1): restrict the roster to the baseline 4 plus `auth-authz-auditor` and `input-validation-auditor` — but only if the stack-signal union would have included them anyway. Do not add either specialist in lite mode if the full-roster resolution wouldn't have included it (e.g. a pure `iac`-only target stays baseline-only in lite mode, not baseline+auth+input-validation). All other stack-specific additions (`iac-auditor`, `container-runtime-auditor`, `frontend-security-auditor`, etc.) are dropped in lite mode. `--lite` never drops `input-validation-auditor` or `auth-authz-auditor` when they'd otherwise be in roster — mirroring `code-review-team`'s decision to keep `security-reviewer` mandatory in its lite roster, on the same reasoning: a missed injection or authz bug outweighs the tokens saved by cutting these two.\n\n### 0.5 Detect scanner availability\n\nFor each scanner in Step 2.5's pre-pass list, run `command -v \u003Cname>`. Flag available vs missing. Missing scanners don't block — they just reduce pre-pass coverage; dependent specialists will work in manual mode.\n\n### 0.6 Estimate runtime + tokens + cost\n\n**Historical baseline** (from the CBP-060 reference run against `recall`, executed on Opus 4.7 — kept as a labeled historical data point, not a current default):\n\n- **Input tokens per specialist:** `~min(40k, 30 + 0.02 × LINE_COUNT)` k tokens — small repos float near 30k overhead; large repos grow linearly with source lines but the agent self-caps reads.\n- **Output tokens per specialist:** `~5–10k` regardless of repo size (findings + prose).\n- **Total tokens:** `input-validation-auditor` and `auth-authz-auditor` each run as a loop-until-dry consensus fan-out when in roster (Step 3a, `MIN_PASSES = 2` .. `MAX_PASSES = 8`), not a single pass. Since the actual pass count (`N`) isn't known until the loop terminates, estimate with `N` at its expected midpoint (`~4`, i.e. `N-1 = 3` extra specialist-equivalents) for a planning estimate, and note the true range spans `MIN_PASSES` to `MAX_PASSES`: `Total tokens ≈ (N_specialists + 3 × N_consensus_specialists_in_roster) × (input + output)`, worst case `(N_specialists + 7 × N_consensus_specialists_in_roster) × (input + output)` if every consensus specialist runs the full 8-pass cap. The Step 4.5 validator adds roughly one more agent call per surviving finding group after consolidation — this can't be sized until findings exist, so note it as \"+validator passes (post-consolidation, ~1 call per finding group)\" rather than folding it into this estimate.\n- **Runtime:** longest-path specialist `≈ 3 min` baseline; add `0.6 sec \u002F file read`. Dependency auditor is typically slowest (`~20–30 min` on a repo with a 700-package `node_modules`). Report estimate as a range: `longest × 1.1` to `longest × 1.5`. The two consensus specialists run their first 2 passes concurrently, then any further passes one at a time until dry or capped — so wall-clock adds roughly one to a few specialists' worth of time depending on how quickly they dry up, not a fixed multiple — plus a consolidation\u002Ftally step afterward (~30s each).\n- **Cost (compute at run time, not from the historical baseline above):** look up the current model tier's per-MTok input\u002Foutput pricing (e.g. via the `claude-api` skill's model catalog or the Models API) for whatever model the orchestrator is actually running on, then compute `(input_tokens × price_in + output_tokens × price_out) \u002F 1_000_000`, using the consensus-adjusted token total above plus the validator caveat. Print `$X.XX` along with the pricing assumption used (model name + rate) so the estimate doesn't silently rot next generation.\n\n### 0.7 Render confirmation block\n\n```\n╭─ sec-review-team ──────────────────────────────────────────╮\n│                                                            │\n│  Target:     \u003Cabsolute path>                               │\n│  Scope:      \u003Cscope>                                       │\n│              \u003CN> files, \u003CN> lines                          │\n│                                                            │\n│  Stack:      \u003Cdetected signals, comma-separated>           │\n│  Model:      \u003Ccurrent model ID>                            │\n│  Mode:       \u003Cfull | lite>                                 │\n│  Run mode:   \u003Cbaseline | re-review (vs run \u003Cprior_run_id>)>│\n│                                                            │\n│  Specialists (\u003CN> in roster):                              │\n│    ✓ secrets-crypto-auditor                                │\n│    ✓ dependency-supplychain-auditor                        │\n│    ✓ silent-failure-hunter                                 │\n│    ✓ data-exposure-auditor                                 │\n│    ✓ auth-authz-auditor          (loop-until-dry consensus) │\n│    ✓ input-validation-auditor    (loop-until-dry consensus) │\n│    ✓ \u003Cstack-specific additions>  (full mode only)          │\n│                                                            │\n│  Pre-pass scanners:                                        │\n│    ✓ gitleaks          (found on PATH)                     │\n│    ✗ trufflehog        (missing — skip)                    │\n│    ✓ semgrep                                               │\n│    ✓ npm audit                                             │\n│    ✗ cargo audit       (missing — skip)                    │\n│                                                            │\n│  Estimated:                                                │\n│    Tokens:    ~\u003CN>k input \u002F ~\u003CN>k output                   │\n│    Runtime:   \u003CN>–\u003CN> min (wall-clock)                     │\n│    Cost:      ~$\u003CN.NN> (\u003Cmodel pricing tier>)              │\n│    + validator passes after consolidation (~1 call\u002Ffinding)│\n│                                                            │\n│  Output:     \u003CTARGET>\u002F.planning\u002Fsecurity-review\u002Fruns\u002F\u003Crun_id>\u002F│\n│              (+ known-findings.jsonl ledger, one level up) │\n│                                                            │\n╰────────────────────────────────────────────────────────────╯\n\nProceed? [y \u002F lite \u002F narrow \u002F add-specialist \u002F drop-specialist \u002F abort]\n```\n\n### 0.8 Handle response\n\n- **y** \u002F **yes** \u002F (`--yes` flag) → continue to Step 1.\n- **lite** → switch to lite roster (per 0.4), re-render 0.7.\n- **narrow** → prompt: *\"Narrow to which subdirectory or diff?\"* — re-run 0.2–0.7 with the new scope.\n- **add-specialist `\u003Cname>`** → append the named specialist if present in `specialists\u002F`, reject if unknown, re-render 0.7.\n- **drop-specialist `\u003Cname>`** → remove from roster, warn if dropping a baseline specialist (*\"secrets-crypto is in the baseline. Drop anyway?\"*), re-render 0.7.\n- **abort** \u002F **n** \u002F **no** \u002F empty response after 60 s (if interactive) → exit cleanly. Do NOT create `.planning\u002Fsecurity-review\u002F`. Do NOT spawn any agent.\n\n### 0.9 Run-metadata capture\n\nAfter confirmation, before Step 1, write `\u003CRUN_DIR>\u002Frun-metadata.json` (`\u003CRUN_DIR>` from Step 0.1a):\n\n```json\n{\n  \"run_id\": \"\u003CISO timestamp>\",\n  \"target\": \"\u003Cabsolute path>\",\n  \"scope\": \"\u003Cscope>\",\n  \"stack_signals\": [\"...\"],\n  \"roster\": [\"...\"],\n  \"mode\": \"full | lite\",\n  \"run_mode\": \"baseline | re-review\",\n  \"prior_run_id\": \"\u003Crun_id of the most recent prior run, or null in baseline mode>\",\n  \"scanners_available\": [\"...\"],\n  \"scanners_missing\": [\"...\"],\n  \"model\": \"\u003Cmodel ID>\",\n  \"estimated_tokens_input\": \u003CN>,\n  \"estimated_tokens_output\": \u003CN>,\n  \"estimated_cost_usd\": \u003CN.NN>,\n  \"confirmed_at\": \"\u003CISO timestamp>\"\n}\n```\n\nThis is consumed later by the consolidation step (fills in REPORT.md header), by re-run comparison, and by telemetry if enabled.\n\n## Step 1: Final roster\n\nLoad only the specialist brief files from `specialists\u002F` that match the confirmed roster. Do not load briefs for specialists not in the roster.\n\n## Step 2: Prepare findings directory\n\nCreate `\u003CRUN_DIR>` (`\u003CTARGET>\u002F.planning\u002Fsecurity-review\u002Fruns\u002F\u003Crun_id>\u002F`) if absent — this also creates the parent `\u003CTARGET>\u002F.planning\u002Fsecurity-review\u002F` on first run. Every specialist\u002Fvalidator\u002Fconsolidation output for this run is written under `RUN_DIR`; only `known-findings.jsonl` lives one level up, at `\u003CTARGET>\u002F.planning\u002Fsecurity-review\u002F`.\n\n**Pollution check:** run `git check-ignore \u003CTARGET>\u002F.planning\u002F` (or grep `.gitignore`). If `.planning\u002F` is NOT ignored, warn the user:\n> \"⚠ `.planning\u002F` is not in the target's .gitignore. Findings land inside the repo. Options: (a) add to .gitignore, (b) write to \u002Ftmp\u002Fsec-review-\u003Ctimestamp>\u002F instead, (c) proceed.\"\n\nRespect choice. Default (no response) is (c).\n\n## Step 2.5: Scanner pre-pass\n\nDeterministic scanners run before the LLM specialists. This is the biggest accuracy-per-token lever in the skill — specialists spend tokens on signal tools can't catch (architectural, multi-step, context-dependent), not re-deriving secret-detection regexes.\n\n### 2.5.1 Scanner inventory\n\n| Scanner | Detects | Command | Feeds specialist |\n|---|---|---|---|\n| `gitleaks` | secrets at rest | `gitleaks detect --source \u003CTARGET> --report-format json --report-path -` | secrets-crypto-auditor |\n| `trufflehog` | secrets (git history + fs) | `trufflehog filesystem \u003CTARGET> --json` | secrets-crypto-auditor |\n| `semgrep` | pattern-based SAST | `semgrep scan --config auto --json --output -` | multi: input-validation, data-exposure, silent-failure (by rule category) |\n| `npm audit` | npm CVEs | `cd \u003CTARGET> && npm audit --json` | dependency-supplychain-auditor |\n| `cargo audit` | crate CVEs | `cd \u003CTARGET> && cargo audit --json` | dependency-supplychain-auditor |\n| `pip-audit` | Python CVEs | `pip-audit -r \u003CTARGET>\u002Frequirements.txt -f json` | dependency-supplychain-auditor |\n| `osv-scanner` | multi-ecosystem CVEs | `osv-scanner -r \u003CTARGET> --format json` | dependency-supplychain-auditor |\n| `bandit` | Python SAST | `bandit -r \u003CTARGET> -f json` | input-validation-auditor (Python targets) |\n| `hadolint` | Dockerfile lint | `hadolint \u003Cfile> -f json` | container-runtime-auditor |\n| `trivy image` | base image CVEs | `trivy image --format json \u003Cimage>` | container-runtime-auditor |\n| `actionlint` | GHA syntax + security | `actionlint -format '{{json .}}'` | ci-cd-security-auditor |\n| `tfsec` | Terraform security | `tfsec \u003CTARGET> --format json` | iac-auditor |\n| `checkov` | IaC security | `checkov -d \u003CTARGET> --output json` | iac-auditor |\n| `retire.js` | known-vulnerable JS libs | `retire --path \u003CTARGET> --outputformat json` | frontend-security-auditor |\n\nFull mapping: see [`docs\u002Fscanner-coverage.md`](docs\u002Fscanner-coverage.md).\n\n### 2.5.2 Detection + invocation\n\nFor each scanner in the inventory:\n\n```bash\nif command -v \u003Cscanner> >\u002Fdev\u002Fnull 2>&1; then\n  run the scanner, capture stdout\n  parse JSON output\n  normalize to finding.schema.json format (see 2.5.3)\n  append to \u003CRUN_DIR>\u002Fscanner-prepass.jsonl\nelse\n  log \"scanner \u003Cname> not available — skipping\"\nfi\n```\n\nRun scanners in parallel where safe (no shared-state conflicts). Wall-clock ceiling per scanner: 120 s (kill if exceeded; log partial results).\n\n### 2.5.3 Normalization\n\nEvery scanner emits different JSON. Normalize each finding to `finding.schema.json` with:\n\n- `id` — `scanner-\u003Cname>-\u003Cindex>` (e.g. `scanner-gitleaks-001`)\n- `specialist` — the specialist this finding is routed to (see inventory above). Even scanner findings get routed; specialists triage them.\n- `source` — `\"scanner-\u003Cname>\"` (so provenance is visible)\n- `severity` — mapped from scanner's severity (`HIGH` → `high`, `MEDIUM` → `medium`, etc.)\n- `confidence` — scanners get `certain` for deterministic rule hits, `likely` for heuristic rules\n- `title`, `root_issue` — from scanner output, slug-normalized\n- `file`, `line_range`, `evidence` — from scanner output\n- `exploit`, `fix` — scanners often omit these; leave `\"\"` and let the specialist agent fill during triage\n\nSave to `\u003CRUN_DIR>\u002Fscanner-prepass.jsonl`.\n\n### 2.5.4 Feed specialists\n\nWhen spawning each specialist in Step 3, include a \"Pre-pass context\" section in the brief:\n\n```\nPre-pass scanner findings relevant to your specialist (from `\u003CRUN_DIR>\u002Fscanner-prepass.jsonl`):\n\n  [N findings from gitleaks]\n  [M findings from semgrep for your category]\n\nTriage rules:\n  1. For each scanner-sourced finding, decide: true-positive \u002F false-positive \u002F needs-investigation.\n     Emit a finding entry in your JSONL with `source: \"scanner-\u003Cname>-confirmed\"` (for true-positive) or\n     `source: \"scanner-\u003Cname>-false-positive\"` (for false-positive triaged out).\n  2. After triage, find what the scanner missed via architectural \u002F cross-file analysis — these go in your\n     JSONL with `source: \"specialist\"` as usual.\n```\n\nSpecialists are not obligated to re-derive secret regexes. Their job is triage + judgment.\n\n### 2.5.5 REPORT.md provenance\n\nThe consolidation step (Step 4) renders `REPORT.md` with a \"Source\" column for each finding so the reader sees which scanner (if any) caught it and whether a specialist confirmed or overturned the triage. Scanner-only confirmations (no specialist review) are flagged with `⚠ unreviewed by specialist` — this happens when a specialist errored before triaging the scanner pre-pass.\n\n### 2.5.6 Scanner unavailability\n\nIf zero scanners are available in the environment, the run continues — specialists do the full job themselves, which is the CBP-060 baseline mode. Log a tooling caveat in REPORT.md so the reader knows coverage is LLM-only.\n\n## Step 3: Spawn specialists in parallel\n\nIssue one `Agent` tool call per specialist in a **single assistant message** — this is what makes them run concurrently.\n\n**`input-validation-auditor` and `auth-authz-auditor` are excluded from this step when they're in roster** — they run via Step 3a's loop-until-dry consensus fan-out instead. Spawn every other roster specialist here as usual (if neither is in roster for this run's stack signals, this step just spawns the full roster as before).\n\nFor each specialist (other than input-validation-auditor and auth-authz-auditor):\n\n- Read its brief file (`specialists\u002F\u003Cname>.md`).\n- Substitute `\u003CTARGET>`, `\u003CSCOPE>`, `\u003CSTACK CONTEXT>`, `\u003CTHREAT_MODEL>`.\n- Pass `allowed-tools` per the specialist's `## Allowed tools` section (hard read-only; Write scoped to the four output-file paths only).\n- Use `preferred_subagent_type` from frontmatter; fall back to `fallback_subagent_type` if unregistered.\n- Read the `effort` frontmatter field (`high` \u002F `medium` \u002F `low`; specialists without the field default to `medium`) and tune the spawn accordingly: `high` (currently `auth-authz-auditor`, `input-validation-auditor` — also applied per-pass in Step 3a) gets the model's extended-thinking \u002F max-effort mode where the runtime exposes one, and no early-stop encouragement in the brief; `low` (currently `privacy-telemetry-auditor`, `ci-cd-security-auditor` — narrower, more mechanical scopes) gets standard effort with an added brief line: \"This scope is narrow — a thorough single pass is sufficient, don't over-invest reasoning budget beyond what the category list requires.\"; `medium` (everything else) gets no effort-specific brief addition. This is a token\u002Flatency lever, not a quality floor — every specialist still runs the full hard-rules\u002Fflag-everything\u002Fvalidator pipeline regardless of effort tier.\n\nPrint to the user before the parallel batch returns:\n\n```\nSpawning \u003CN> specialists in parallel against \u003CTARGET> (scope: \u003CSCOPE>, mode: \u003Cmode>).\n\nEach specialist writes to \u003CRUN_DIR>\u002F\u003Cname>.{md, findings.jsonl, coverage.jsonl, status.json}.\n\nLive progress (run in a separate terminal):\n  watch -n 5 'jq -s \"sort_by(.agent) | map({agent, status, files_read, findings_written})\" \u003CRUN_DIR>\u002F*.status.json'\n\nOr:\n  tail -f \u003CRUN_DIR>\u002F*.status.json\n\nSpawning now. Interim status lines will appear as each specialist returns.\n```\n\n### 3.1 Heartbeat contract (per specialist)\n\nEvery specialist brief instructs the agent to write `\u003Cname>.status.json` at spawn time and to update it as progress happens. Format:\n\n```json\n{\n  \"agent\": \"\u003Cspecialist-name>\",\n  \"status\": \"starting | scanning | writing-findings | completed | errored\",\n  \"started_at\": \"\u003CISO>\",\n  \"finished_at\": \"\u003CISO|null>\",\n  \"files_read\": \u003Cint>,\n  \"findings_written\": \u003Cint>,\n  \"current_file\": \"\u003Cpath|null>\",\n  \"severity_counts\": { \"critical\": 0, \"high\": 0, \"medium\": 0, \"low\": 0 },\n  \"error\": \"\u003Cmessage|null>\"\n}\n```\n\n- On spawn: write with `status: \"starting\"`, `started_at`, counters at 0.\n- Every ~5 file reads: update `files_read`, `current_file`, set `status: \"scanning\"`.\n- On each finding: increment `findings_written`, update `severity_counts`.\n- On completion: set `status: \"completed\"`, `finished_at`, final counts.\n- On error: set `status: \"errored\"`, `finished_at`, populate `error`.\n\nThe agent must flush `.status.json` to disk **before returning from its `Agent` tool call**, so the orchestrator sees the final state once the subagent completes.\n\n### 3.2 Interim reports (orchestrator-side)\n\nBatched `Agent` calls in a single message run concurrently, but the orchestrator receives their results serialized — one completion at a time. As each specialist returns:\n\n1. Read the specialist's `status.json` file to confirm final state.\n2. Print **one line** to the user:\n\n```\n✓ auth-authz-auditor       done    (0C \u002F 2H \u002F 2M \u002F 1L)   [4m 22s]   12 files read\n✓ input-validation-auditor done    (0C \u002F 0H \u002F 0M \u002F 3L)   [3m 15s]    8 files read\n✗ dependency-supplychain-auditor errored after 18m — node_modules walk timed out. Partial findings preserved.\n✓ silent-failure-hunter    done    (0C \u002F 2H \u002F 3M \u002F 3L)   [5m 03s]   14 files read\n...\n```\n\n3. Errored specialists don't block the run. Keep processing completions from the remaining specialists. In Step 4 (consolidate), errored specialists are flagged in REPORT.md with their last-known `status.json` state.\n\n4. After the last specialist returns, print:\n```\nAll \u003CN> specialists completed (\u003CX> done, \u003CY> errored). Consolidating...\n```\n\n### 3.3 Output files per specialist\n\nEach specialist writes four files to `\u003CRUN_DIR>`:\n\n- `\u003Cname>.md` — prose findings (human-readable)\n- `\u003Cname>.findings.jsonl` — per `schema\u002Ffinding.schema.json`\n- `\u003Cname>.coverage.jsonl` — per `schema\u002Fcoverage.schema.json`\n- `\u003Cname>.status.json` — heartbeat \u002F final state\n\n## Step 3a: Multi-pass consensus fan-out (input-validation-auditor, auth-authz-auditor)\n\n`input-validation-auditor` and `auth-authz-auditor` own the two highest-variance tasks in the roster — tracing every external input to its sink, and mapping every endpoint\u002FIPC command to its auth requirement, are both enumerate-everything jobs a single pass under-samples, finding a different random subset of the real issues (and missing others) each run. When either is in the confirmed roster (per Step 0.4 \u002F Step 1), run it through a **loop-until-dry** fan-out — independent passes with the file scope reordered per pass, keeping only findings that reproduce across at least 2 passes, and stopping once a pass stops contributing anything new rather than always running a fixed count — the same design `code-review-team` uses for `correctness-reviewer`\u002F`performance-reviewer` (TBS-044), modeled on Cursor Bugbot's multi-pass agreement design, adapted so effort scales with how much variance the target is actually producing.\n\n`MAX_PASSES = 8` — the hard ceiling regardless of whether passes are still finding new issues. `MIN_PASSES = 2` — the floor, since `hit_count >= 2` can never have a survivor with fewer than 2 passes.\n\nIf neither specialist is in roster for this run (e.g. a pure `iac`-only target), skip this step entirely — Step 3 already spawned the full roster as single-pass.\n\n### 3a.1 File-order rotation\n\nEnumerate the scope's file list once (same enumeration as Step 0.2). For pass `i` (1-indexed, 1..`MAX_PASSES`), rotate the list by `i × floor(len \u002F MAX_PASSES)` positions (wrap-around) before handing it to the specialist brief as an explicit ordered file list — rotating against the fixed ceiling (not however many passes end up running) keeps every pass's ordering distinct regardless of when the loop stops. This produces a materially different read order per pass without depending on random-number generation, which a markdown-driven orchestration can't reliably produce.\n\n### 3a.2 Spawn passes — loop until a round is dry, capped at `MAX_PASSES`\n\nFor each of `input-validation-auditor` and `auth-authz-auditor` that's in roster, independently:\n1. Run passes 1 and 2 (`MIN_PASSES`) concurrently as 2 `Agent` calls in a **single assistant message** — the minimum needed for any `hit_count >= 2` survivor to exist at all.\n2. After every pass (or batch) completes, tally (3a.3) and compare this round's distinct `root_issue` set against the union of every `root_issue` seen in all prior rounds for this specialist:\n   - **This round introduced at least one `root_issue` not seen in any earlier round** → continue: spawn one more pass (`i+1`).\n   - **This round introduced zero new `root_issue`s** → stop. The pass is \"dry\" — further passes are unlikely to surface anything new.\n   - Regardless of dryness, **stop unconditionally once pass `MAX_PASSES` (8) completes.**\n3. Passes after the initial 2 are spawned one at a time (each pass's file rotation depends only on its own fixed index, not on prior results — only the *stopping decision* is sequential).\n\nEach pass uses the specialist's normal brief (substituting `\u003CTARGET>`, `\u003CSCOPE>`, `\u003CSTACK CONTEXT>`, pre-pass scanner findings as usual), with the rotated file order substituted for `\u003CSCOPE>`'s file enumeration, plus an added line: \"This is pass `\u003Ci>` of up to `MAX_PASSES` independent review passes over the same scope, each in a different file order. Review thoroughly as if this were the only pass — do not assume another pass covers what you skip.\"\nEach pass writes to `\u003CRUN_DIR>\u002F\u003Cname>.pass\u003Ci>.findings.jsonl` and `\u003Cname>.pass\u003Ci>.status.json` — **not** the canonical `\u003Cname>.findings.jsonl` \u002F `\u003Cname>.status.json`. The canonical files are written by the tally step below, once the loop terminates.\n\n### 3a.3 Tally and threshold\n\nOnce the loop in 3a.2 terminates (a dry round, or the `MAX_PASSES` cap) with `N` total passes run for a specialist (`MIN_PASSES \u003C= N \u003C= MAX_PASSES`):\n1. Read all `N` `\u003Cname>.pass\u003Ci>.findings.jsonl` files.\n2. Group findings by `root_issue` across the `N` passes.\n3. For each group, compute `hit_count` = number of *distinct* passes it appeared in (1–`N`).\n4. Keep only groups with `hit_count >= 2` — drop the rest as one-off, unreproduced findings (sampling noise or hallucination).\n5. For each surviving group, take the representative finding with the highest `confidence` (ties: earliest pass), tag it with `hit_count`, and write it to the canonical `\u003Cname>.findings.jsonl`, ranked by `hit_count` descending. Union the `coverage.jsonl` entries across all `N` passes into the canonical `\u003Cname>.coverage.jsonl` (a category is `checked-clean` only if all `N` passes checked it clean).\n6. Write the canonical `\u003Cname>.status.json` as `completed`, with `severity_counts` reflecting only the survivors.\n7. Print one line per specialist: `✓ input-validation-auditor consensus: \u003Ckept>\u002F\u003Ctotal distinct root_issues> root_issues survived (hit_count >= 2 of N passes, stopped \u003Con a dry round after pass N | at the MAX_PASSES cap>)`.\n\nStep 4's consolidation reads `\u003Cname>.findings.jsonl` and `\u003Cname>.coverage.jsonl` exactly as it does for every other specialist — it has no knowledge that these came from a variable-length tally rather than a single pass.\n\n## Step 4: Consolidate\n\nRead all `*.findings.jsonl` and `*.coverage.jsonl` from `\u003CRUN_DIR>`. Apply `docs\u002Fconsolidation-template.md`:\n\n1. Group findings by `root_issue` (dedupe across specialists).\n2. For each group: `max(severity)`, `max(confidence)`, `distinct(specialist) → raised_by`, `hit_count` (carried through if present).\n3. Build coverage matrix (category × specialist) from coverage.jsonl. **Completeness-score denominator:** the union of every roster specialist's static \"Coverage categories this specialist owns\" list (from its brief), not `count(coverage.jsonl records actually written)` — an errored specialist that wrote zero coverage records must not shrink the denominator by having its owned categories silently disappear from the count, which would let a less-complete run score higher than a more-complete one. Missing categories score as `not-checked` (shown as ✗ in the matrix), which drags the score down as it should.\n\nEvery deduped group — regardless of confidence — proceeds to Step 4.5. There is no confidence-based pre-filter here; specialists are instructed to flag everything they notice (Step 3's briefs), so the validator step is what decides what's real.\n\nIf any specialist failed schema validation on its JSONL, fall back to prose parse for that specialist and log a warning in REPORT.md.\n\nAs each specialist returns, print an interim-status line: `✓ \u003Cname> done (\u003Ccounts>) [\u003Cruntime>]` or `✗ \u003Cname> errored: \u003Cmsg>`. Don't block on errored specialists.\n\n## Step 4.5: Verify\n\nFor every group produced by Step 4, spawn one validator `Agent` to try to refute it. Batch validator calls into as few concurrent assistant messages as practical (all in one message, unless the finding count is large enough to need splitting for tool-call limits).\n\n**Validator prompt** (substitute the group's consolidated fields):\n\n> Here is a claimed security finding: `\u003Ctitle>` — `\u003Cone-line summary combining evidence + fix from the group>`.\n> Open `\u003Cfile>:\u003Cline_range>`, read the surrounding code and its callers\u002Fentry points.\n> Can you PROVE it's real — with a `file:line` citation AND a working exploit *path* (the concrete chain from an attacker-reachable entry point to the vulnerable sink, since security findings often need a reachability chain rather than a single failing input value)?\n> - Yes → keep, attach the exploit path.\n> - No \u002F can't confirm from the actual code, or the \"vulnerable\" sink is unreachable \u002F already guarded → drop it.\n> Cite `file:line`. Do not infer from naming or pattern-matching alone — verify against the actual code you read, including what calls into and guards the sink.\n\n**Validator subagent constraints:** read-only (`Read`, `Grep`, `Glob`, safe `Bash` allowlist matching the specialist briefs' allowlist); no `Write` access to findings files — it returns its verdict as its final message, which the orchestrator parses.\n\n**Handle the verdict:**\n- **Confirmed** — set `validator_confirmed: true` on the group, attach the cited `exploit_path`. The group proceeds to the report.\n- **Rejected** — set `validator_confirmed: false`. Drop the group from `REPORT.md` entirely. Append it (with the validator's rejection reason) to `\u003CRUN_DIR>\u002Frejected-by-validator.jsonl` for audit\u002Fdebugging — this file is never surfaced in the report body, only mentioned by count in Tooling Caveats.\n- **Validator itself errors\u002Ftimes out** — treat as unconfirmed (drop from report, log to `\u003CRUN_DIR>\u002Frejected-by-validator.jsonl` with `error: true`) rather than blocking the run.\n\nAfter this step, `actionable = [g for g in groups if g.validator_confirmed]` — this replaces the old confidence-based `certain|likely` split that used to gate inclusion here. Everything that survives the validator is actionable by definition; everything that doesn't is dropped, not demoted.\n\n**Re-review filter** (only when `re_review_mode` is true, from Step 0.1a): after computing `actionable`, load `\u003CTARGET>\u002F.planning\u002Fsecurity-review\u002Fknown-findings.jsonl` and split every non-`low`\u002F`info` ledger entry into exactly one of two disjoint sets relative to this run:\n\n- **`reconfirmed_known`** — the entry's `root_issue` also appears in this run's `actionable` (an independent specialist re-found it and the validator re-confirmed it, this run). Drop these groups from `actionable` before rendering the report — already reported in a prior run, don't repeat it — and record `len(reconfirmed_known)` for Step 5's Tooling Caveats. A `reconfirmed_known` entry needs no lightweight re-verification below: this run's fresh validator confirmation is stronger evidence than any stored `file`\u002F`evidence_snippet` grep could provide.\n- **`carried_over_known`** — the entry's `root_issue` does **not** appear in this run's `actionable` (not independently rediscovered this run — its file may be entirely outside this run's `\u003CSCOPE>`, or in scope but simply missed by every specialist this pass). **`\u003CSCOPE>` never gates membership here** — a diff-scoped run's ledger entries for files outside the diff still enter `carried_over_known` exactly like any other not-rediscovered entry; `\u003CSCOPE>` only ever governed which files specialists actively looked at, not which known findings this run is allowed to report status on. The lightweight check below (not scope) is what keeps an unverified claim from being asserted about a file this run never touched. **Before running that check, first look up this run's `\u003CRUN_DIR>\u002Frejected-by-validator.jsonl`:** if the entry's `root_issue` appears there (a specialist rediscovered it this run and the validator explicitly rejected it as fixed\u002Funreachable\u002Falready-guarded), treat that rejection as authoritative and exclude the entry from \"still open\" without running the grep check below — a same-run validator verdict is stronger evidence either way than a stale snippet match.\n\nThen drop every remaining `low`\u002F`info`-severity group from `actionable` outright (sec-review-team's floor tier is never carried forward into the report, mirroring `code-review-team`'s nit suppression) — `low`\u002F`info`-severity ledger entries are excluded from both sets above for the same reason: the floor tier is never carried forward whether it resurfaces in `actionable` or only survives in the ledger. Record the floor-tier-suppressed count — `count(actionable groups dropped as low\u002Finfo this run)` specifically, not ledger-only low\u002Finfo entries, which were never part of either set and were never counted or reported to begin with — for Step 5's Tooling Caveats. Baseline runs (`re_review_mode` false) skip this filter entirely — `reconfirmed_known` and `carried_over_known` are both empty, and there is no still-open bookkeeping to do.\n\n> **Example:** ledger has three non-floor-tier entries — `S1` (file inside this run's diff), `S2` (file outside this run's diff), `S3` (file touched and re-examined this pass). This re-review run's specialists rediscover and the validator reconfirms `S3` this pass → `S3 ∈ reconfirmed_known` (suppressed from the report, no lightweight check needed). `S1` and `S2` are not rediscovered by any specialist this run → both land in `carried_over_known` regardless of scope — `S2` is not dropped just because it's outside the diff.\n\n**Update the ledger:** append every validator-confirmed `root_issue` from *this* run that isn't already in `\u003CTARGET>\u002F.planning\u002Fsecurity-review\u002Fknown-findings.jsonl` (including ones suppressed from this run's report because they matched the re-review filter — the ledger tracks everything ever confirmed, not just what's newly shown) — with `first_seen_run_id` set to this run's `run_id`, `file` set to the finding's `file`, and `evidence_snippet` set to the finding's `evidence` field trimmed to its first line only, up to ~80 characters, whichever is shorter — never spanning a newline, since the re-verification check below matches it line-by-line — for genuinely new entries; `first_seen_run_id`\u002F`first_seen_date` on existing entries are left unchanged (they record provenance, not current state). **Refresh `file`\u002F`evidence_snippet` on every reconfirmation:** whenever a `root_issue` lands in `reconfirmed_known` this run (validator-confirmed, and already had a ledger entry), overwrite that entry's `file`\u002F`evidence_snippet` with this run's finding, regardless of whether the fields were already populated. This is deliberate, not just a legacy-entry backfill: code legitimately moves (refactors, renames), and an entry frozen at its first-confirmed location would eventually cause the lightweight check below to grep a stale, possibly-nonexistent path and wrongly conclude a still-present issue is \"no longer open.\" `first_seen_run_id`\u002F`first_seen_date` still never change on this refresh — only the location\u002Fevidence fields track the most recent confirmation.\n\n**Re-verify \"still open\" claims before reporting them (do not assert by absence alone):** for every `root_issue` in `carried_over_known` not already excluded by this run's `rejected-by-validator.jsonl` (above), don't just count it as \"still open\" because it's still on the ledger — a `carried_over_known` entry may have been fixed since it was first confirmed, and the ledger by itself can't tell you that. Instead:\n1. Look up that `root_issue`'s ledger record's `file` and `evidence_snippet`.\n2. **Legacy entries — no `file`\u002F`evidence_snippet` on record:** these two fields didn't exist in the ledger schema before this re-verification mechanism was added, so any `known-findings.jsonl` written by an earlier version of this skill will have entries missing them. For those, the mechanical check in step 4 below is impossible to run — there's nothing to grep for. Don't treat \"can't check\" the same as \"can't confirm\" (step 4's exclusion rule): fall back to counting the entry toward \"still open\" as before, but tag it in Step 5's caveats as `\u003CN> previously-reported issues counted as still open without re-verification (ledger entry predates file\u002Fevidence tracking)` — this keeps the count from silently shrinking just because older entries lack the new fields, while being honest that those specific counts are unconfirmed. Once any of these `root_issue`s is independently reconfirmed by a specialist in a future run, it moves to that run's `reconfirmed_known` and the ledger-append step refreshes its `file`\u002F`evidence_snippet`, so this caveat category shrinks over time and eventually empties out.\n3. **Path containment check:** resolve `file` against `\u003CTARGET>`. If it resolves outside `\u003CTARGET>`'s tree (via `..` traversal, an absolute path pointing elsewhere, or any other escape) — a ledger value should never do this, but the ledger is ordinary repo-tracked JSON an external contributor could edit — treat it the same as a legacy entry (step 2): can't verify, count with the unverified caveat, and do not read or grep the out-of-tree path. This matters more here than in a general code-quality tool: a false \"no longer open\" on a security ledger entry is a much sharper failure than an unverified path.\n4. **In-tree entries with `file`\u002F`evidence_snippet` on record:** check file existence, then run the grep as a single fixed-string, argument-safe invocation — native argument passing with an explicit `--` separator (e.g. `grep -qF -- \"\u003Cevidence_snippet>\" \"\u003Cresolved_file_path>\"`, never a shell string concatenation), or equivalently the `Grep` tool in literal mode — using the same restricted, read-only tool scope a specialist would use, never an unconstrained shell. If `file` no longer exists at that path, or the grep returns no match, the finding can no longer be confirmed present at that location.\n   - **Critical\u002Fhigh severity:** a miss here is **not** treated as \"confirmed absent\" — treat it as unverified, same bucket as a legacy entry (step 2), and tag it separately in Step 5 as `\u003CN> critical\u002Fhigh previously-reported issues could not be re-verified this run — status unknown, recommend manual check`. A false \"no longer open\" on a still-exploitable vulnerability is the costliest failure mode this whole mechanism exists to avoid — it must never be folded silently into the same exclusion path as a low-severity finding.\n   - **Medium\u002Flow\u002Finfo severity** (below `critical`\u002F`high`, and non-floor-tier): a miss excludes it from the \"still open\" count for this run's report, as before (it may have been fixed, refactored away, or moved somewhere a plain grep won't find).\n5. Only `root_issue`s whose `evidence_snippet` still greps-clean in `file` (step 4) count toward `\u003CP>` in Step 5's \"previously-reported issues still open\" line; legacy entries (step 2), out-of-tree entries (step 3), and critical\u002Fhigh unverified misses (step 4) all count toward `\u003CP>` too, but are called out separately in the caveats as unverified. This is a cheap, mechanical check for the entries that support it, not a full re-review — it catches the common case (the file\u002Fsnippet is simply gone) without re-running a specialist. Perform it as a single loop over all of `carried_over_known` (one script\u002F`Bash` invocation), not one tool call per entry.\n6. This check only affects what gets *reported* as still open this run — it never edits or removes entries from `known-findings.jsonl` itself, which remains a historical record of everything ever confirmed.\n\n> **Example (multi-run backfill trace):** Run N (pre-fix baseline, before this ledger schema existed) confirms `root_issue: S4` and appends it to the ledger with no `file`\u002F`evidence_snippet` (legacy shape). Run N+1 (re-review; no specialist re-finds `S4` this pass): `S4 ∉ actionable` → `S4 ∈ carried_over_known`; its ledger record has no `file`\u002F`evidence_snippet` → step 2's legacy fallback fires → `S4` counts toward `\u003CP>`, tagged \"counted without re-verification.\" Run N+2 (re-review; a specialist independently re-finds `S4` and the validator reconfirms it this pass): `S4 ∈ actionable` and already in the ledger → `S4 ∈ reconfirmed_known` → suppressed from the report, and the ledger-append step's refresh clause (above) now sets `S4`'s `file`\u002F`evidence_snippet` from this run's finding. Run N+3 (re-review; `S4` not re-found again, and its file hasn't moved since N+2): `S4 ∉ actionable` → back in `carried_over_known`, its ledger record has `file`\u002F`evidence_snippet` from N+2 → step 4's grep check runs and `S4` counts toward `\u003CP>` as verified, no caveat. (Had `S4`'s code instead moved to a new file between N+2 and N+3 without being rediscovered, step 4's existence check on the stale N+2 path would fail — for a medium\u002Flow finding this excludes it as before; for a critical\u002Fhigh finding it's flagged unverified rather than silently dropped, per step 4's severity branch above.)\n\nRender `\u003CRUN_DIR>\u002FREPORT.md` from the consolidation template using only the final actionable groups — `\u003CP>` (the still-open count from the re-verification above) is now available for the template.\n\n## Step 5: Deliver\n\nTell the user:\n- Path to `\u003CRUN_DIR>\u002FREPORT.md` and the per-specialist files each (four, or up to nine for the two consensus specialists — canonical + up to 8 per-pass files)\n- Headline severity counts (deduped, validator-confirmed, post-re-review-filter)\n- Top 2–3 fixes by impact\n- Validator summary: `\u003CN> findings confirmed, \u003CM> rejected by the validator` (rejected count only — not the rejected findings themselves, see `rejected-by-validator.jsonl`)\n- If `re_review_mode`: `\u003CP> previously-reported issues still open (not repeated above — see known-findings.jsonl), \u003CQ> low\u002Finfo findings suppressed` — `\u003CP>` is the re-verified `carried_over_known` count (Step 4.5's \"Re-verify still open claims\"), not a raw ledger-match count; if any of `\u003CP>` are legacy entries counted per that step's step 2 (predating `file`\u002F`evidence_snippet` tracking), append `(\u003CL> of these counted without re-verification — ledger entry predates file\u002Fevidence tracking)`; if any critical\u002Fhigh entries hit step 4's unverified branch, append a separate line: `\u003CM> critical\u002Fhigh previously-reported issues could not be re-verified this run — status unknown, recommend manual check`\n- Tooling caveats (scanners unavailable, fallbacks taken, specialists errored)\n- Coverage completeness score\n\nDo NOT apply fixes. Fix workflow → companion skill `\u002Ffsad-harness:sec-review-fixes` (CBP-070).\n\n---\n\n## Related\n- **Specialist library:** `specialists\u002F` (13 briefs)\n- **Stack signals:** `stack-signals.md`\n- **Schemas:** `schema\u002Ffinding.schema.json`, `schema\u002Fcoverage.schema.json`\n- **Shared output-format contract:** `docs\u002Foutput-contract.md`\n- **Consolidation template:** `docs\u002Fconsolidation-template.md`\n- **Design tradeoffs:** `docs\u002Ftradeoffs.md`\n- **Canonical prompt source:** [`markdown\u002Fdesign\u002FTeam_of_security_agents.md`](..\u002F..\u002F..\u002Fmarkdown\u002Fdesign\u002FTeam_of_security_agents.md)\n- **Embedded playbook section:** `fsad-playbook.html` → `#practices\u002Fsecurity-review`\n- **Opus 4.7 validation (historical):** [`markdown\u002Fresearch\u002Fsecurity-review-opus-4.7-validation.md`](..\u002F..\u002F..\u002Fmarkdown\u002Fresearch\u002Fsecurity-review-opus-4.7-validation.md)\n- **Improvement recommendations:** [`markdown\u002Fresearch\u002Fsec-review-recommendations.md`](..\u002F..\u002F..\u002Fmarkdown\u002Fresearch\u002Fsec-review-recommendations.md)\n","# Multi-Agent Security Review Team — Orchestration\n\n**What this optimizes for:** two complementary guarantees, in this order of priority. First, coverage-of-absence — a \"clean\" verdict on any category must cite the searches that back it, never a bare assertion. Second, verification-of-positives — a finding only reaches the report after surviving independent adversarial validation (Step 4.5) against a category-appropriate proof standard, with self-reported specialist confidence no longer sufficient on its own. \"Done\" means every roster specialist's owned categories are accounted for (checked-clean, checked-issues-found, or explicitly not-checked with a reason), and every surviving finding in the report is validator-confirmed, not merely raised.\n\nFollow these steps. Review-only. Never apply fixes.\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## Step 0: Pre-run confirmation\n\nThe skill's largest user-facing safety gate. Never spawn specialists without showing this block (unless `--yes` \u002F `auto-approve` is passed).\n\n### 0.1 Parse arguments\n\n- **Target path** — absolute path. If missing, ask: *\"What repo should I review? (absolute path)\"* Verify it exists and is readable.\n- **Scope** — one of:\n  - `all` — full tree\n  - `\u003Csubdir>` — a subdirectory, e.g. `src\u002Fapi\u002F`\n  - `diff vs main` (or `diff vs \u003Cbranch>`) — only files changed on current branch vs target branch\n  If missing, ask: *\"What scope? Full tree, a subdirectory, or a diff?\"*\n- **Flags:**\n  - `--yes` \u002F `-y` — skip confirmation entirely. Default is to confirm.\n  - `--lite` \u002F `-l` — run only the baseline 4 (`secrets-crypto-auditor`, `dependency-supplychain-auditor`, `silent-failure-hunter`, `data-exposure-auditor`) plus `auth-authz-auditor` and `input-validation-auditor` when the stack roster would otherwise include them (5–6 agent subset). Auto-activated when scope is a diff with ≤25 changed files, same threshold as `code-review-team`.\n  - `--full` — force a fresh baseline scan, ignoring any prior run history for this target (see Step 0.1a). Without this flag, a target with prior history runs in re-review mode automatically.\n\n### 0.1a Detect prior run (re-review mode)\n\nEvery run writes its artifacts under a run-scoped directory, `RUN_DIR = \u003CTARGET>\u002F.planning\u002Fsecurity-review\u002Fruns\u002F\u003Crun_id>\u002F` (`run_id` = an ISO-timestamp-derived slug), so a later run never overwrites an earlier one. Runs accumulate a top-level ledger at `\u003CTARGET>\u002F.planning\u002Fsecurity-review\u002Fknown-findings.jsonl` — one record per validator-confirmed `root_issue` ever reported for this target (`root_issue`, `title`, `severity`, `first_seen_run_id`, `first_seen_date`, `file`, `evidence_snippet` — the latter two exist solely so a later run can cheaply re-verify the issue is still actually present before reporting it as \"still open\"; see Step 4.5's ledger-append and re-verification logic).\n\n1. Check whether `\u003CTARGET>\u002F.planning\u002Fsecurity-review\u002Fknown-findings.jsonl` exists.\n2. **Exists, and `--full` was not passed** → `re_review_mode = true`. This run skips `root_issue`s already in the ledger and suppresses all `low`\u002F`info`-severity findings from the report (Step 4.5's re-review filter, `re_review_mode` branch — sec-review-team's severity floor for \"nit-equivalent\" is `low`\u002F`info`, mirroring `code-review-team`'s nit suppression). Announce this in the Step 0.7 confirmation block.\n3. **Missing, or `--full` was passed** → `re_review_mode = false`. This is a baseline scan; every validator-confirmed finding is eligible for the report, and the ledger is (re)built from this run's results.\n\nAll `RUN_DIR`-relative paths referenced in Steps 0.9 through 5 below resolve against the `RUN_DIR` computed here — the ledger itself is the one exception, always written at the top-level `\u003CTARGET>\u002F.planning\u002Fsecurity-review\u002F` regardless of `run_id`.\n\n### 0.2 Enumerate scope\n\nUse git-aware commands (fall back to `find` if not a git repo):\n\n```bash\n# File count + line count (scoped)\ncd \"\u003CTARGET>\"\nif [[ \"\u003CSCOPE>\" == \"all\" ]]; then\n  FILE_COUNT=$(git ls-files | wc -l)\n  LINE_COUNT=$(git ls-files | xargs wc -l 2>\u002Fdev\u002Fnull | tail -1 | awk '{print $1}')\nelif [[ \"\u003CSCOPE>\" == diff* ]]; then\n  BASE=\"${SCOPE#diff vs }\"; BASE=\"${BASE:-main}\"\n  FILES=$(git diff --name-only \"$BASE\"...HEAD)\n  FILE_COUNT=$(echo \"$FILES\" | wc -l)\n  LINE_COUNT=$(echo \"$FILES\" | xargs wc -l 2>\u002Fdev\u002Fnull | tail -1 | awk '{print $1}')\nelse\n  FILE_COUNT=$(git ls-files \"\u003CSCOPE>\" | wc -l)\n  LINE_COUNT=$(git ls-files \"\u003CSCOPE>\" | xargs wc -l 2>\u002Fdev\u002Fnull | tail -1 | awk '{print $1}')\nfi\n```\n\nCap `LINE_COUNT` at 500k (anything larger: warn and suggest scope narrowing).\n\n### 0.3 Detect stack signals\n\nRead the highest-signal manifests first (cheapest): `README.md` top 50 lines, `package.json`, `Cargo.toml`, `pyproject.toml`, `go.mod`, `Gemfile`, `tauri.conf.json`, `Dockerfile`, `.github\u002Fworkflows\u002F` (existence only), `requirements.txt`. Two or three file-reads is enough.\n\nApply each rule in `stack-signals.md` against what you observe. Collect matching signals (multiple can match). Example: a Tauri note app emits `desktop` + `desktop-with-webview`.\n\n### 0.4 Pick default roster\n\nPer `stack-signals.md`: union the specialist sets across all matching stack signals. Always include the baseline 4 (`secrets-crypto-auditor`, `dependency-supplychain-auditor`, `silent-failure-hunter`, `data-exposure-auditor`).\n\n**`--lite` mode** (explicit flag or diff ≤25 files, per 0.1): restrict the roster to the baseline 4 plus `auth-authz-auditor` and `input-validation-auditor` — but only if the stack-signal union would have included them anyway. Do not add either specialist in lite mode if the full-roster resolution wouldn't have included it (e.g. a pure `iac`-only target stays baseline-only in lite mode, not baseline+auth+input-validation). All other stack-specific additions (`iac-auditor`, `container-runtime-auditor`, `frontend-security-auditor`, etc.) are dropped in lite mode. `--lite` never drops `input-validation-auditor` or `auth-authz-auditor` when they'd otherwise be in roster — mirroring `code-review-team`'s decision to keep `security-reviewer` mandatory in its lite roster, on the same reasoning: a missed injection or authz bug outweighs the tokens saved by cutting these two.\n\n### 0.5 Detect scanner availability\n\nFor each scanner in Step 2.5's pre-pass list, run `command -v \u003Cname>`. Flag available vs missing. Missing scanners don't block — they just reduce pre-pass coverage; dependent specialists will work in manual mode.\n\n### 0.6 Estimate runtime + tokens + cost\n\n**Historical baseline** (from the CBP-060 reference run against `recall`, executed on Opus 4.7 — kept as a labeled historical data point, not a current default):\n\n- **Input tokens per specialist:** `~min(40k, 30 + 0.02 × LINE_COUNT)` k tokens — small repos float near 30k overhead; large repos grow linearly with source lines but the agent self-caps reads.\n- **Output tokens per specialist:** `~5–10k` regardless of repo size (findings + prose).\n- **Total tokens:** `input-validation-auditor` and `auth-authz-auditor` each run as a loop-until-dry consensus fan-out when in roster (Step 3a, `MIN_PASSES = 2` .. `MAX_PASSES = 8`), not a single pass. Since the actual pass count (`N`) isn't known until the loop terminates, estimate with `N` at its expected midpoint (`~4`, i.e. `N-1 = 3` extra specialist-equivalents) for a planning estimate, and note the true range spans `MIN_PASSES` to `MAX_PASSES`: `Total tokens ≈ (N_specialists + 3 × N_consensus_specialists_in_roster) × (input + output)`, worst case `(N_specialists + 7 × N_consensus_specialists_in_roster) × (input + output)` if every consensus specialist runs the full 8-pass cap. The Step 4.5 validator adds roughly one more agent call per surviving finding group after consolidation — this can't be sized until findings exist, so note it as \"+validator passes (post-consolidation, ~1 call per finding group)\" rather than folding it into this estimate.\n- **Runtime:** longest-path specialist `≈ 3 min` baseline; add `0.6 sec \u002F file read`. Dependency auditor is typically slowest (`~20–30 min` on a repo with a 700-package `node_modules`). Report estimate as a range: `longest × 1.1` to `longest × 1.5`. The two consensus specialists run their first 2 passes concurrently, then any further passes one at a time until dry or capped — so wall-clock adds roughly one to a few specialists' worth of time depending on how quickly they dry up, not a fixed multiple — plus a consolidation\u002Ftally step afterward (~30s each).\n- **Cost (compute at run time, not from the historical baseline above):** look up the current model tier's per-MTok input\u002Foutput pricing (e.g. via the `claude-api` skill's model catalog or the Models API) for whatever model the orchestrator is actually running on, then compute `(input_tokens × price_in + output_tokens × price_out) \u002F 1_000_000`, using the consensus-adjusted token total above plus the validator caveat. Print `$X.XX` along with the pricing assumption used (model name + rate) so the estimate doesn't silently rot next generation.\n\n### 0.7 Render confirmation block\n\n```\n╭─ sec-review-team ──────────────────────────────────────────╮\n│                                                            │\n│  Target:     \u003Cabsolute path>                               │\n│  Scope:      \u003Cscope>                                       │\n│              \u003CN> files, \u003CN> lines                          │\n│                                                            │\n│  Stack:      \u003Cdetected signals, comma-separated>           │\n│  Model:      \u003Ccurrent model ID>                            │\n│  Mode:       \u003Cfull | lite>                                 │\n│  Run mode:   \u003Cbaseline | re-review (vs run \u003Cprior_run_id>)>│\n│                                                            │\n│  Specialists (\u003CN> in roster):                              │\n│    ✓ secrets-crypto-auditor                                │\n│    ✓ dependency-supplychain-auditor                        │\n│    ✓ silent-failure-hunter                                 │\n│    ✓ data-exposure-auditor                                 │\n│    ✓ auth-authz-auditor          (loop-until-dry consensus) │\n│    ✓ input-validation-auditor    (loop-until-dry consensus) │\n│    ✓ \u003Cstack-specific additions>  (full mode only)          │\n│                                                            │\n│  Pre-pass scanners:                                        │\n│    ✓ gitleaks          (found on PATH)                     │\n│    ✗ trufflehog        (missing — skip)                    │\n│    ✓ semgrep                                               │\n│    ✓ npm audit                                             │\n│    ✗ cargo audit       (missing — skip)                    │\n│                                                            │\n│  Estimated:                                                │\n│    Tokens:    ~\u003CN>k input \u002F ~\u003CN>k output                   │\n│    Runtime:   \u003CN>–\u003CN> min (wall-clock)                     │\n│    Cost:      ~$\u003CN.NN> (\u003Cmodel pricing tier>)              │\n│    + validator passes after consolidation (~1 call\u002Ffinding)│\n│                                                            │\n│  Output:     \u003CTARGET>\u002F.planning\u002Fsecurity-review\u002Fruns\u002F\u003Crun_id>\u002F│\n│              (+ known-findings.jsonl ledger, one level up) │\n│                                                            │\n╰────────────────────────────────────────────────────────────╯\n\nProceed? [y \u002F lite \u002F narrow \u002F add-specialist \u002F drop-specialist \u002F abort]\n```\n\n### 0.8 Handle response\n\n- **y** \u002F **yes** \u002F (`--yes` flag) → continue to Step 1.\n- **lite** → switch to lite roster (per 0.4), re-render 0.7.\n- **narrow** → prompt: *\"Narrow to which subdirectory or diff?\"* — re-run 0.2–0.7 with the new scope.\n- **add-specialist `\u003Cname>`** → append the named specialist if present in `specialists\u002F`, reject if unknown, re-render 0.7.\n- **drop-specialist `\u003Cname>`** → remove from roster, warn if dropping a baseline specialist (*\"secrets-crypto is in the baseline. Drop anyway?\"*), re-render 0.7.\n- **abort** \u002F **n** \u002F **no** \u002F empty response after 60 s (if interactive) → exit cleanly. Do NOT create `.planning\u002Fsecurity-review\u002F`. Do NOT spawn any agent.\n\n### 0.9 Run-metadata capture\n\nAfter confirmation, before Step 1, write `\u003CRUN_DIR>\u002Frun-metadata.json` (`\u003CRUN_DIR>` from Step 0.1a):\n\n```json\n{\n  \"run_id\": \"\u003CISO timestamp>\",\n  \"target\": \"\u003Cabsolute path>\",\n  \"scope\": \"\u003Cscope>\",\n  \"stack_signals\": [\"...\"],\n  \"roster\": [\"...\"],\n  \"mode\": \"full | lite\",\n  \"run_mode\": \"baseline | re-review\",\n  \"prior_run_id\": \"\u003Crun_id of the most recent prior run, or null in baseline mode>\",\n  \"scanners_available\": [\"...\"],\n  \"scanners_missing\": [\"...\"],\n  \"model\": \"\u003Cmodel ID>\",\n  \"estimated_tokens_input\": \u003CN>,\n  \"estimated_tokens_output\": \u003CN>,\n  \"estimated_cost_usd\": \u003CN.NN>,\n  \"confirmed_at\": \"\u003CISO timestamp>\"\n}\n```\n\nThis is consumed later by the consolidation step (fills in REPORT.md header), by re-run comparison, and by telemetry if enabled.\n\n## Step 1: Final roster\n\nLoad only the specialist brief files from `specialists\u002F` that match the confirmed roster. Do not load briefs for specialists not in the roster.\n\n## Step 2: Prepare findings directory\n\nCreate `\u003CRUN_DIR>` (`\u003CTARGET>\u002F.planning\u002Fsecurity-review\u002Fruns\u002F\u003Crun_id>\u002F`) if absent — this also creates the parent `\u003CTARGET>\u002F.planning\u002Fsecurity-review\u002F` on first run. Every specialist\u002Fvalidator\u002Fconsolidation output for this run is written under `RUN_DIR`; only `known-findings.jsonl` lives one level up, at `\u003CTARGET>\u002F.planning\u002Fsecurity-review\u002F`.\n\n**Pollution check:** run `git check-ignore \u003CTARGET>\u002F.planning\u002F` (or grep `.gitignore`). If `.planning\u002F` is NOT ignored, warn the user:\n> \"⚠ `.planning\u002F` is not in the target's .gitignore. Findings land inside the repo. Options: (a) add to .gitignore, (b) write to \u002Ftmp\u002Fsec-review-\u003Ctimestamp>\u002F instead, (c) proceed.\"\n\nRespect choice. Default (no response) is (c).\n\n## Step 2.5: Scanner pre-pass\n\nDeterministic scanners run before the LLM specialists. This is the biggest accuracy-per-token lever in the skill — specialists spend tokens on signal tools can't catch (architectural, multi-step, context-dependent), not re-deriving secret-detection regexes.\n\n### 2.5.1 Scanner inventory\n\n| Scanner | Detects | Command | Feeds specialist |\n|---|---|---|---|\n| `gitleaks` | secrets at rest | `gitleaks detect --source \u003CTARGET> --report-format json --report-path -` | secrets-crypto-auditor |\n| `trufflehog` | secrets (git history + fs) | `trufflehog filesystem \u003CTARGET> --json` | secrets-crypto-auditor |\n| `semgrep` | pattern-based SAST | `semgrep scan --config auto --json --output -` | multi: input-validation, data-exposure, silent-failure (by rule category) |\n| `npm audit` | npm CVEs | `cd \u003CTARGET> && npm audit --json` | dependency-supplychain-auditor |\n| `cargo audit` | crate CVEs | `cd \u003CTARGET> && cargo audit --json` | dependency-supplychain-auditor |\n| `pip-audit` | Python CVEs | `pip-audit -r \u003CTARGET>\u002Frequirements.txt -f json` | dependency-supplychain-auditor |\n| `osv-scanner` | multi-ecosystem CVEs | `osv-scanner -r \u003CTARGET> --format json` | dependency-supplychain-auditor |\n| `bandit` | Python SAST | `bandit -r \u003CTARGET> -f json` | input-validation-auditor (Python targets) |\n| `hadolint` | Dockerfile lint | `hadolint \u003Cfile> -f json` | container-runtime-auditor |\n| `trivy image` | base image CVEs | `trivy image --format json \u003Cimage>` | container-runtime-auditor |\n| `actionlint` | GHA syntax + security | `actionlint -format '{{json .}}'` | ci-cd-security-auditor |\n| `tfsec` | Terraform security | `tfsec \u003CTARGET> --format json` | iac-auditor |\n| `checkov` | IaC security | `checkov -d \u003CTARGET> --output json` | iac-auditor |\n| `retire.js` | known-vulnerable JS libs | `retire --path \u003CTARGET> --outputformat json` | frontend-security-auditor |\n\nFull mapping: see [`docs\u002Fscanner-coverage.md`](docs\u002Fscanner-coverage.md).\n\n### 2.5.2 Detection + invocation\n\nFor each scanner in the inventory:\n\n```bash\nif command -v \u003Cscanner> >\u002Fdev\u002Fnull 2>&1; then\n  run the scanner, capture stdout\n  parse JSON output\n  normalize to finding.schema.json format (see 2.5.3)\n  append to \u003CRUN_DIR>\u002Fscanner-prepass.jsonl\nelse\n  log \"scanner \u003Cname> not available — skipping\"\nfi\n```\n\nRun scanners in parallel where safe (no shared-state conflicts). Wall-clock ceiling per scanner: 120 s (kill if exceeded; log partial results).\n\n### 2.5.3 Normalization\n\nEvery scanner emits different JSON. Normalize each finding to `finding.schema.json` with:\n\n- `id` — `scanner-\u003Cname>-\u003Cindex>` (e.g. `scanner-gitleaks-001`)\n- `specialist` — the specialist this finding is routed to (see inventory above). Even scanner findings get routed; specialists triage them.\n- `source` — `\"scanner-\u003Cname>\"` (so provenance is visible)\n- `severity` — mapped from scanner's severity (`HIGH` → `high`, `MEDIUM` → `medium`, etc.)\n- `confidence` — scanners get `certain` for deterministic rule hits, `likely` for heuristic rules\n- `title`, `root_issue` — from scanner output, slug-normalized\n- `file`, `line_range`, `evidence` — from scanner output\n- `exploit`, `fix` — scanners often omit these; leave `\"\"` and let the specialist agent fill during triage\n\nSave to `\u003CRUN_DIR>\u002Fscanner-prepass.jsonl`.\n\n### 2.5.4 Feed specialists\n\nWhen spawning each specialist in Step 3, include a \"Pre-pass context\" section in the brief:\n\n```\nPre-pass scanner findings relevant to your specialist (from `\u003CRUN_DIR>\u002Fscanner-prepass.jsonl`):\n\n  [N findings from gitleaks]\n  [M findings from semgrep for your category]\n\nTriage rules:\n  1. For each scanner-sourced finding, decide: true-positive \u002F false-positive \u002F needs-investigation.\n     Emit a finding entry in your JSONL with `source: \"scanner-\u003Cname>-confirmed\"` (for true-positive) or\n     `source: \"scanner-\u003Cname>-false-positive\"` (for false-positive triaged out).\n  2. After triage, find what the scanner missed via architectural \u002F cross-file analysis — these go in your\n     JSONL with `source: \"specialist\"` as usual.\n```\n\nSpecialists are not obligated to re-derive secret regexes. Their job is triage + judgment.\n\n### 2.5.5 REPORT.md provenance\n\nThe consolidation step (Step 4) renders `REPORT.md` with a \"Source\" column for each finding so the reader sees which scanner (if any) caught it and whether a specialist confirmed or overturned the triage. Scanner-only confirmations (no specialist review) are flagged with `⚠ unreviewed by specialist` — this happens when a specialist errored before triaging the scanner pre-pass.\n\n### 2.5.6 Scanner unavailability\n\nIf zero scanners are available in the environment, the run continues — specialists do the full job themselves, which is the CBP-060 baseline mode. Log a tooling caveat in REPORT.md so the reader knows coverage is LLM-only.\n\n## Step 3: Spawn specialists in parallel\n\nIssue one `Agent` tool call per specialist in a **single assistant message** — this is what makes them run concurrently.\n\n**`input-validation-auditor` and `auth-authz-auditor` are excluded from this step when they're in roster** — they run via Step 3a's loop-until-dry consensus fan-out instead. Spawn every other roster specialist here as usual (if neither is in roster for this run's stack signals, this step just spawns the full roster as before).\n\nFor each specialist (other than input-validation-auditor and auth-authz-auditor):\n\n- Read its brief file (`specialists\u002F\u003Cname>.md`).\n- Substitute `\u003CTARGET>`, `\u003CSCOPE>`, `\u003CSTACK CONTEXT>`, `\u003CTHREAT_MODEL>`.\n- Pass `allowed-tools` per the specialist's `## Allowed tools` section (hard read-only; Write scoped to the four output-file paths only).\n- Use `preferred_subagent_type` from frontmatter; fall back to `fallback_subagent_type` if unregistered.\n- Read the `effort` frontmatter field (`high` \u002F `medium` \u002F `low`; specialists without the field default to `medium`) and tune the spawn accordingly: `high` (currently `auth-authz-auditor`, `input-validation-auditor` — also applied per-pass in Step 3a) gets the model's extended-thinking \u002F max-effort mode where the runtime exposes one, and no early-stop encouragement in the brief; `low` (currently `privacy-telemetry-auditor`, `ci-cd-security-auditor` — narrower, more mechanical scopes) gets standard effort with an added brief line: \"This scope is narrow — a thorough single pass is sufficient, don't over-invest reasoning budget beyond what the category list requires.\"; `medium` (everything else) gets no effort-specific brief addition. This is a token\u002Flatency lever, not a quality floor — every specialist still runs the full hard-rules\u002Fflag-everything\u002Fvalidator pipeline regardless of effort tier.\n\nPrint to the user before the parallel batch returns:\n\n```\nSpawning \u003CN> specialists in parallel against \u003CTARGET> (scope: \u003CSCOPE>, mode: \u003Cmode>).\n\nEach specialist writes to \u003CRUN_DIR>\u002F\u003Cname>.{md, findings.jsonl, coverage.jsonl, status.json}.\n\nLive progress (run in a separate terminal):\n  watch -n 5 'jq -s \"sort_by(.agent) | map({agent, status, files_read, findings_written})\" \u003CRUN_DIR>\u002F*.status.json'\n\nOr:\n  tail -f \u003CRUN_DIR>\u002F*.status.json\n\nSpawning now. Interim status lines will appear as each specialist returns.\n```\n\n### 3.1 Heartbeat contract (per specialist)\n\nEvery specialist brief instructs the agent to write `\u003Cname>.status.json` at spawn time and to update it as progress happens. Format:\n\n```json\n{\n  \"agent\": \"\u003Cspecialist-name>\",\n  \"status\": \"starting | scanning | writing-findings | completed | errored\",\n  \"started_at\": \"\u003CISO>\",\n  \"finished_at\": \"\u003CISO|null>\",\n  \"files_read\": \u003Cint>,\n  \"findings_written\": \u003Cint>,\n  \"current_file\": \"\u003Cpath|null>\",\n  \"severity_counts\": { \"critical\": 0, \"high\": 0, \"medium\": 0, \"low\": 0 },\n  \"error\": \"\u003Cmessage|null>\"\n}\n```\n\n- On spawn: write with `status: \"starting\"`, `started_at`, counters at 0.\n- Every ~5 file reads: update `files_read`, `current_file`, set `status: \"scanning\"`.\n- On each finding: increment `findings_written`, update `severity_counts`.\n- On completion: set `status: \"completed\"`, `finished_at`, final counts.\n- On error: set `status: \"errored\"`, `finished_at`, populate `error`.\n\nThe agent must flush `.status.json` to disk **before returning from its `Agent` tool call**, so the orchestrator sees the final state once the subagent completes.\n\n### 3.2 Interim reports (orchestrator-side)\n\nBatched `Agent` calls in a single message run concurrently, but the orchestrator receives their results serialized — one completion at a time. As each specialist returns:\n\n1. Read the specialist's `status.json` file to confirm final state.\n2. Print **one line** to the user:\n\n```\n✓ auth-authz-auditor       done    (0C \u002F 2H \u002F 2M \u002F 1L)   [4m 22s]   12 files read\n✓ input-validation-auditor done    (0C \u002F 0H \u002F 0M \u002F 3L)   [3m 15s]    8 files read\n✗ dependency-supplychain-auditor errored after 18m — node_modules walk timed out. Partial findings preserved.\n✓ silent-failure-hunter    done    (0C \u002F 2H \u002F 3M \u002F 3L)   [5m 03s]   14 files read\n...\n```\n\n3. Errored specialists don't block the run. Keep processing completions from the remaining specialists. In Step 4 (consolidate), errored specialists are flagged in REPORT.md with their last-known `status.json` state.\n\n4. After the last specialist returns, print:\n```\nAll \u003CN> specialists completed (\u003CX> done, \u003CY> errored). Consolidating...\n```\n\n### 3.3 Output files per specialist\n\nEach specialist writes four files to `\u003CRUN_DIR>`:\n\n- `\u003Cname>.md` — prose findings (human-readable)\n- `\u003Cname>.findings.jsonl` — per `schema\u002Ffinding.schema.json`\n- `\u003Cname>.coverage.jsonl` — per `schema\u002Fcoverage.schema.json`\n- `\u003Cname>.status.json` — heartbeat \u002F final state\n\n## Step 3a: Multi-pass consensus fan-out (input-validation-auditor, auth-authz-auditor)\n\n`input-validation-auditor` and `auth-authz-auditor` own the two highest-variance tasks in the roster — tracing every external input to its sink, and mapping every endpoint\u002FIPC command to its auth requirement, are both enumerate-everything jobs a single pass under-samples, finding a different random subset of the real issues (and missing others) each run. When either is in the confirmed roster (per Step 0.4 \u002F Step 1), run it through a **loop-until-dry** fan-out — independent passes with the file scope reordered per pass, keeping only findings that reproduce across at least 2 passes, and stopping once a pass stops contributing anything new rather than always running a fixed count — the same design `code-review-team` uses for `correctness-reviewer`\u002F`performance-reviewer` (TBS-044), modeled on Cursor Bugbot's multi-pass agreement design, adapted so effort scales with how much variance the target is actually producing.\n\n`MAX_PASSES = 8` — the hard ceiling regardless of whether passes are still finding new issues. `MIN_PASSES = 2` — the floor, since `hit_count >= 2` can never have a survivor with fewer than 2 passes.\n\nIf neither specialist is in roster for this run (e.g. a pure `iac`-only target), skip this step entirely — Step 3 already spawned the full roster as single-pass.\n\n### 3a.1 File-order rotation\n\nEnumerate the scope's file list once (same enumeration as Step 0.2). For pass `i` (1-indexed, 1..`MAX_PASSES`), rotate the list by `i × floor(len \u002F MAX_PASSES)` positions (wrap-around) before handing it to the specialist brief as an explicit ordered file list — rotating against the fixed ceiling (not however many passes end up running) keeps every pass's ordering distinct regardless of when the loop stops. This produces a materially different read order per pass without depending on random-number generation, which a markdown-driven orchestration can't reliably produce.\n\n### 3a.2 Spawn passes — loop until a round is dry, capped at `MAX_PASSES`\n\nFor each of `input-validation-auditor` and `auth-authz-auditor` that's in roster, independently:\n1. Run passes 1 and 2 (`MIN_PASSES`) concurrently as 2 `Agent` calls in a **single assistant message** — the minimum needed for any `hit_count >= 2` survivor to exist at all.\n2. After every pass (or batch) completes, tally (3a.3) and compare this round's distinct `root_issue` set against the union of every `root_issue` seen in all prior rounds for this specialist:\n   - **This round introduced at least one `root_issue` not seen in any earlier round** → continue: spawn one more pass (`i+1`).\n   - **This round introduced zero new `root_issue`s** → stop. The pass is \"dry\" — further passes are unlikely to surface anything new.\n   - Regardless of dryness, **stop unconditionally once pass `MAX_PASSES` (8) completes.**\n3. Passes after the initial 2 are spawned one at a time (each pass's file rotation depends only on its own fixed index, not on prior results — only the *stopping decision* is sequential).\n\nEach pass uses the specialist's normal brief (substituting `\u003CTARGET>`, `\u003CSCOPE>`, `\u003CSTACK CONTEXT>`, pre-pass scanner findings as usual), with the rotated file order substituted for `\u003CSCOPE>`'s file enumeration, plus an added line: \"This is pass `\u003Ci>` of up to `MAX_PASSES` independent review passes over the same scope, each in a different file order. Review thoroughly as if this were the only pass — do not assume another pass covers what you skip.\"\nEach pass writes to `\u003CRUN_DIR>\u002F\u003Cname>.pass\u003Ci>.findings.jsonl` and `\u003Cname>.pass\u003Ci>.status.json` — **not** the canonical `\u003Cname>.findings.jsonl` \u002F `\u003Cname>.status.json`. The canonical files are written by the tally step below, once the loop terminates.\n\n### 3a.3 Tally and threshold\n\nOnce the loop in 3a.2 terminates (a dry round, or the `MAX_PASSES` cap) with `N` total passes run for a specialist (`MIN_PASSES \u003C= N \u003C= MAX_PASSES`):\n1. Read all `N` `\u003Cname>.pass\u003Ci>.findings.jsonl` files.\n2. Group findings by `root_issue` across the `N` passes.\n3. For each group, compute `hit_count` = number of *distinct* passes it appeared in (1–`N`).\n4. Keep only groups with `hit_count >= 2` — drop the rest as one-off, unreproduced findings (sampling noise or hallucination).\n5. For each surviving group, take the representative finding with the highest `confidence` (ties: earliest pass), tag it with `hit_count`, and write it to the canonical `\u003Cname>.findings.jsonl`, ranked by `hit_count` descending. Union the `coverage.jsonl` entries across all `N` passes into the canonical `\u003Cname>.coverage.jsonl` (a category is `checked-clean` only if all `N` passes checked it clean).\n6. Write the canonical `\u003Cname>.status.json` as `completed`, with `severity_counts` reflecting only the survivors.\n7. Print one line per specialist: `✓ input-validation-auditor consensus: \u003Ckept>\u002F\u003Ctotal distinct root_issues> root_issues survived (hit_count >= 2 of N passes, stopped \u003Con a dry round after pass N | at the MAX_PASSES cap>)`.\n\nStep 4's consolidation reads `\u003Cname>.findings.jsonl` and `\u003Cname>.coverage.jsonl` exactly as it does for every other specialist — it has no knowledge that these came from a variable-length tally rather than a single pass.\n\n## Step 4: Consolidate\n\nRead all `*.findings.jsonl` and `*.coverage.jsonl` from `\u003CRUN_DIR>`. Apply `docs\u002Fconsolidation-template.md`:\n\n1. Group findings by `root_issue` (dedupe across specialists).\n2. For each group: `max(severity)`, `max(confidence)`, `distinct(specialist) → raised_by`, `hit_count` (carried through if present).\n3. Build coverage matrix (category × specialist) from coverage.jsonl. **Completeness-score denominator:** the union of every roster specialist's static \"Coverage categories this specialist owns\" list (from its brief), not `count(coverage.jsonl records actually written)` — an errored specialist that wrote zero coverage records must not shrink the denominator by having its owned categories silently disappear from the count, which would let a less-complete run score higher than a more-complete one. Missing categories score as `not-checked` (shown as ✗ in the matrix), which drags the score down as it should.\n\nEvery deduped group — regardless of confidence — proceeds to Step 4.5. There is no confidence-based pre-filter here; specialists are instructed to flag everything they notice (Step 3's briefs), so the validator step is what decides what's real.\n\nIf any specialist failed schema validation on its JSONL, fall back to prose parse for that specialist and log a warning in REPORT.md.\n\nAs each specialist returns, print an interim-status line: `✓ \u003Cname> done (\u003Ccounts>) [\u003Cruntime>]` or `✗ \u003Cname> errored: \u003Cmsg>`. Don't block on errored specialists.\n\n## Step 4.5: Verify\n\nFor every group produced by Step 4, spawn one validator `Agent` to try to refute it. Batch validator calls into as few concurrent assistant messages as practical (all in one message, unless the finding count is large enough to need splitting for tool-call limits).\n\n**Validator prompt** (substitute the group's consolidated fields):\n\n> Here is a claimed security finding: `\u003Ctitle>` — `\u003Cone-line summary combining evidence + fix from the group>`.\n> Open `\u003Cfile>:\u003Cline_range>`, read the surrounding code and its callers\u002Fentry points.\n> Can you PROVE it's real — with a `file:line` citation AND a working exploit *path* (the concrete chain from an attacker-reachable entry point to the vulnerable sink, since security findings often need a reachability chain rather than a single failing input value)?\n> - Yes → keep, attach the exploit path.\n> - No \u002F can't confirm from the actual code, or the \"vulnerable\" sink is unreachable \u002F already guarded → drop it.\n> Cite `file:line`. Do not infer from naming or pattern-matching alone — verify against the actual code you read, including what calls into and guards the sink.\n\n**Validator subagent constraints:** read-only (`Read`, `Grep`, `Glob`, safe `Bash` allowlist matching the specialist briefs' allowlist); no `Write` access to findings files — it returns its verdict as its final message, which the orchestrator parses.\n\n**Handle the verdict:**\n- **Confirmed** — set `validator_confirmed: true` on the group, attach the cited `exploit_path`. The group proceeds to the report.\n- **Rejected** — set `validator_confirmed: false`. Drop the group from `REPORT.md` entirely. Append it (with the validator's rejection reason) to `\u003CRUN_DIR>\u002Frejected-by-validator.jsonl` for audit\u002Fdebugging — this file is never surfaced in the report body, only mentioned by count in Tooling Caveats.\n- **Validator itself errors\u002Ftimes out** — treat as unconfirmed (drop from report, log to `\u003CRUN_DIR>\u002Frejected-by-validator.jsonl` with `error: true`) rather than blocking the run.\n\nAfter this step, `actionable = [g for g in groups if g.validator_confirmed]` — this replaces the old confidence-based `certain|likely` split that used to gate inclusion here. Everything that survives the validator is actionable by definition; everything that doesn't is dropped, not demoted.\n\n**Re-review filter** (only when `re_review_mode` is true, from Step 0.1a): after computing `actionable`, load `\u003CTARGET>\u002F.planning\u002Fsecurity-review\u002Fknown-findings.jsonl` and split every non-`low`\u002F`info` ledger entry into exactly one of two disjoint sets relative to this run:\n\n- **`reconfirmed_known`** — the entry's `root_issue` also appears in this run's `actionable` (an independent specialist re-found it and the validator re-confirmed it, this run). Drop these groups from `actionable` before rendering the report — already reported in a prior run, don't repeat it — and record `len(reconfirmed_known)` for Step 5's Tooling Caveats. A `reconfirmed_known` entry needs no lightweight re-verification below: this run's fresh validator confirmation is stronger evidence than any stored `file`\u002F`evidence_snippet` grep could provide.\n- **`carried_over_known`** — the entry's `root_issue` does **not** appear in this run's `actionable` (not independently rediscovered this run — its file may be entirely outside this run's `\u003CSCOPE>`, or in scope but simply missed by every specialist this pass). **`\u003CSCOPE>` never gates membership here** — a diff-scoped run's ledger entries for files outside the diff still enter `carried_over_known` exactly like any other not-rediscovered entry; `\u003CSCOPE>` only ever governed which files specialists actively looked at, not which known findings this run is allowed to report status on. The lightweight check below (not scope) is what keeps an unverified claim from being asserted about a file this run never touched. **Before running that check, first look up this run's `\u003CRUN_DIR>\u002Frejected-by-validator.jsonl`:** if the entry's `root_issue` appears there (a specialist rediscovered it this run and the validator explicitly rejected it as fixed\u002Funreachable\u002Falready-guarded), treat that rejection as authoritative and exclude the entry from \"still open\" without running the grep check below — a same-run validator verdict is stronger evidence either way than a stale snippet match.\n\nThen drop every remaining `low`\u002F`info`-severity group from `actionable` outright (sec-review-team's floor tier is never carried forward into the report, mirroring `code-review-team`'s nit suppression) — `low`\u002F`info`-severity ledger entries are excluded from both sets above for the same reason: the floor tier is never carried forward whether it resurfaces in `actionable` or only survives in the ledger. Record the floor-tier-suppressed count — `count(actionable groups dropped as low\u002Finfo this run)` specifically, not ledger-only low\u002Finfo entries, which were never part of either set and were never counted or reported to begin with — for Step 5's Tooling Caveats. Baseline runs (`re_review_mode` false) skip this filter entirely — `reconfirmed_known` and `carried_over_known` are both empty, and there is no still-open bookkeeping to do.\n\n> **Example:** ledger has three non-floor-tier entries — `S1` (file inside this run's diff), `S2` (file outside this run's diff), `S3` (file touched and re-examined this pass). This re-review run's specialists rediscover and the validator reconfirms `S3` this pass → `S3 ∈ reconfirmed_known` (suppressed from the report, no lightweight check needed). `S1` and `S2` are not rediscovered by any specialist this run → both land in `carried_over_known` regardless of scope — `S2` is not dropped just because it's outside the diff.\n\n**Update the ledger:** append every validator-confirmed `root_issue` from *this* run that isn't already in `\u003CTARGET>\u002F.planning\u002Fsecurity-review\u002Fknown-findings.jsonl` (including ones suppressed from this run's report because they matched the re-review filter — the ledger tracks everything ever confirmed, not just what's newly shown) — with `first_seen_run_id` set to this run's `run_id`, `file` set to the finding's `file`, and `evidence_snippet` set to the finding's `evidence` field trimmed to its first line only, up to ~80 characters, whichever is shorter — never spanning a newline, since the re-verification check below matches it line-by-line — for genuinely new entries; `first_seen_run_id`\u002F`first_seen_date` on existing entries are left unchanged (they record provenance, not current state). **Refresh `file`\u002F`evidence_snippet` on every reconfirmation:** whenever a `root_issue` lands in `reconfirmed_known` this run (validator-confirmed, and already had a ledger entry), overwrite that entry's `file`\u002F`evidence_snippet` with this run's finding, regardless of whether the fields were already populated. This is deliberate, not just a legacy-entry backfill: code legitimately moves (refactors, renames), and an entry frozen at its first-confirmed location would eventually cause the lightweight check below to grep a stale, possibly-nonexistent path and wrongly conclude a still-present issue is \"no longer open.\" `first_seen_run_id`\u002F`first_seen_date` still never change on this refresh — only the location\u002Fevidence fields track the most recent confirmation.\n\n**Re-verify \"still open\" claims before reporting them (do not assert by absence alone):** for every `root_issue` in `carried_over_known` not already excluded by this run's `rejected-by-validator.jsonl` (above), don't just count it as \"still open\" because it's still on the ledger — a `carried_over_known` entry may have been fixed since it was first confirmed, and the ledger by itself can't tell you that. Instead:\n1. Look up that `root_issue`'s ledger record's `file` and `evidence_snippet`.\n2. **Legacy entries — no `file`\u002F`evidence_snippet` on record:** these two fields didn't exist in the ledger schema before this re-verification mechanism was added, so any `known-findings.jsonl` written by an earlier version of this skill will have entries missing them. For those, the mechanical check in step 4 below is impossible to run — there's nothing to grep for. Don't treat \"can't check\" the same as \"can't confirm\" (step 4's exclusion rule): fall back to counting the entry toward \"still open\" as before, but tag it in Step 5's caveats as `\u003CN> previously-reported issues counted as still open without re-verification (ledger entry predates file\u002Fevidence tracking)` — this keeps the count from silently shrinking just because older entries lack the new fields, while being honest that those specific counts are unconfirmed. Once any of these `root_issue`s is independently reconfirmed by a specialist in a future run, it moves to that run's `reconfirmed_known` and the ledger-append step refreshes its `file`\u002F`evidence_snippet`, so this caveat category shrinks over time and eventually empties out.\n3. **Path containment check:** resolve `file` against `\u003CTARGET>`. If it resolves outside `\u003CTARGET>`'s tree (via `..` traversal, an absolute path pointing elsewhere, or any other escape) — a ledger value should never do this, but the ledger is ordinary repo-tracked JSON an external contributor could edit — treat it the same as a legacy entry (step 2): can't verify, count with the unverified caveat, and do not read or grep the out-of-tree path. This matters more here than in a general code-quality tool: a false \"no longer open\" on a security ledger entry is a much sharper failure than an unverified path.\n4. **In-tree entries with `file`\u002F`evidence_snippet` on record:** check file existence, then run the grep as a single fixed-string, argument-safe invocation — native argument passing with an explicit `--` separator (e.g. `grep -qF -- \"\u003Cevidence_snippet>\" \"\u003Cresolved_file_path>\"`, never a shell string concatenation), or equivalently the `Grep` tool in literal mode — using the same restricted, read-only tool scope a specialist would use, never an unconstrained shell. If `file` no longer exists at that path, or the grep returns no match, the finding can no longer be confirmed present at that location.\n   - **Critical\u002Fhigh severity:** a miss here is **not** treated as \"confirmed absent\" — treat it as unverified, same bucket as a legacy entry (step 2), and tag it separately in Step 5 as `\u003CN> critical\u002Fhigh previously-reported issues could not be re-verified this run — status unknown, recommend manual check`. A false \"no longer open\" on a still-exploitable vulnerability is the costliest failure mode this whole mechanism exists to avoid — it must never be folded silently into the same exclusion path as a low-severity finding.\n   - **Medium\u002Flow\u002Finfo severity** (below `critical`\u002F`high`, and non-floor-tier): a miss excludes it from the \"still open\" count for this run's report, as before (it may have been fixed, refactored away, or moved somewhere a plain grep won't find).\n5. Only `root_issue`s whose `evidence_snippet` still greps-clean in `file` (step 4) count toward `\u003CP>` in Step 5's \"previously-reported issues still open\" line; legacy entries (step 2), out-of-tree entries (step 3), and critical\u002Fhigh unverified misses (step 4) all count toward `\u003CP>` too, but are called out separately in the caveats as unverified. This is a cheap, mechanical check for the entries that support it, not a full re-review — it catches the common case (the file\u002Fsnippet is simply gone) without re-running a specialist. Perform it as a single loop over all of `carried_over_known` (one script\u002F`Bash` invocation), not one tool call per entry.\n6. This check only affects what gets *reported* as still open this run — it never edits or removes entries from `known-findings.jsonl` itself, which remains a historical record of everything ever confirmed.\n\n> **Example (multi-run backfill trace):** Run N (pre-fix baseline, before this ledger schema existed) confirms `root_issue: S4` and appends it to the ledger with no `file`\u002F`evidence_snippet` (legacy shape). Run N+1 (re-review; no specialist re-finds `S4` this pass): `S4 ∉ actionable` → `S4 ∈ carried_over_known`; its ledger record has no `file`\u002F`evidence_snippet` → step 2's legacy fallback fires → `S4` counts toward `\u003CP>`, tagged \"counted without re-verification.\" Run N+2 (re-review; a specialist independently re-finds `S4` and the validator reconfirms it this pass): `S4 ∈ actionable` and already in the ledger → `S4 ∈ reconfirmed_known` → suppressed from the report, and the ledger-append step's refresh clause (above) now sets `S4`'s `file`\u002F`evidence_snippet` from this run's finding. Run N+3 (re-review; `S4` not re-found again, and its file hasn't moved since N+2): `S4 ∉ actionable` → back in `carried_over_known`, its ledger record has `file`\u002F`evidence_snippet` from N+2 → step 4's grep check runs and `S4` counts toward `\u003CP>` as verified, no caveat. (Had `S4`'s code instead moved to a new file between N+2 and N+3 without being rediscovered, step 4's existence check on the stale N+2 path would fail — for a medium\u002Flow finding this excludes it as before; for a critical\u002Fhigh finding it's flagged unverified rather than silently dropped, per step 4's severity branch above.)\n\nRender `\u003CRUN_DIR>\u002FREPORT.md` from the consolidation template using only the final actionable groups — `\u003CP>` (the still-open count from the re-verification above) is now available for the template.\n\n## Step 5: Deliver\n\nTell the user:\n- Path to `\u003CRUN_DIR>\u002FREPORT.md` and the per-specialist files each (four, or up to nine for the two consensus specialists — canonical + up to 8 per-pass files)\n- Headline severity counts (deduped, validator-confirmed, post-re-review-filter)\n- Top 2–3 fixes by impact\n- Validator summary: `\u003CN> findings confirmed, \u003CM> rejected by the validator` (rejected count only — not the rejected findings themselves, see `rejected-by-validator.jsonl`)\n- If `re_review_mode`: `\u003CP> previously-reported issues still open (not repeated above — see known-findings.jsonl), \u003CQ> low\u002Finfo findings suppressed` — `\u003CP>` is the re-verified `carried_over_known` count (Step 4.5's \"Re-verify still open claims\"), not a raw ledger-match count; if any of `\u003CP>` are legacy entries counted per that step's step 2 (predating `file`\u002F`evidence_snippet` tracking), append `(\u003CL> of these counted without re-verification — ledger entry predates file\u002Fevidence tracking)`; if any critical\u002Fhigh entries hit step 4's unverified branch, append a separate line: `\u003CM> critical\u002Fhigh previously-reported issues could not be re-verified this run — status unknown, recommend manual check`\n- Tooling caveats (scanners unavailable, fallbacks taken, specialists errored)\n- Coverage completeness score\n\nDo NOT apply fixes. Fix workflow → companion skill `\u002Ffsad-harness:sec-review-fixes` (CBP-070).\n\n---\n\n## Related\n- **Specialist library:** `specialists\u002F` (13 briefs)\n- **Stack signals:** `stack-signals.md`\n- **Schemas:** `schema\u002Ffinding.schema.json`, `schema\u002Fcoverage.schema.json`\n- **Shared output-format contract:** `docs\u002Foutput-contract.md`\n- **Consolidation template:** `docs\u002Fconsolidation-template.md`\n- **Design tradeoffs:** `docs\u002Ftradeoffs.md`\n- **Canonical prompt source:** [`markdown\u002Fdesign\u002FTeam_of_security_agents.md`](..\u002F..\u002F..\u002Fmarkdown\u002Fdesign\u002FTeam_of_security_agents.md)\n- **Embedded playbook section:** `fsad-playbook.html` → `#practices\u002Fsecurity-review`\n- **Opus 4.7 validation (historical):** [`markdown\u002Fresearch\u002Fsecurity-review-opus-4.7-validation.md`](..\u002F..\u002F..\u002Fmarkdown\u002Fresearch\u002Fsecurity-review-opus-4.7-validation.md)\n- **Improvement recommendations:** [`markdown\u002Fresearch\u002Fsec-review-recommendations.md`](..\u002F..\u002F..\u002Fmarkdown\u002Fresearch\u002Fsec-review-recommendations.md)\n",{"description":7,"argument-hint":53},"`[target path] [scope: all | \u003Csubdir> | diff vs main] [--lite] [--yes]`","main","bf3a412c985273327682c956ca35341c64ce9f8c","skills\u002Fsec-review-team",4,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook","https:\u002F\u002Ffsad-playbook.vercel.app","https:\u002F\u002Fgithub.com\u002Ftbeack","2026-11-12 21:05:31",{"source":8,"skillName":5,"commands":63,"prompt":73,"zipAvailable":74},[64,67,70],{"tool":65,"command":66},"npx","npx skills add tbeack\u002Ffsad_playbook --skill sec-review-team",{"tool":68,"command":69},"bunx","bunx skills add tbeack\u002Ffsad_playbook --skill sec-review-team",{"tool":71,"command":72},"pnpm","pnpm dlx skills add tbeack\u002Ffsad_playbook --skill sec-review-team","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002FSKILL.md",true,[76,82,86,90,94,98,102,108,112,116,122,126,130,134,138,142,146,150,154,158,162,166,170,174,178,182,186,190,194,198,202,206,210,214,218,222,226,230,234,238,242,246,250,254,258,262,266,270,274,278,282,286,290,294,298,302,306,310,314,318,322,326,330,334,338,342,346,350,354,358,362,366,370,374,378,382,386,390,394,398,402,406,410,414,418],{"path":77,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":80,"sourceHtmlUrl":81},"docs\u002Fconsolidation-template.md","REFERENCE","参考文档",8413,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Fdocs\u002Fconsolidation-template.md",{"path":83,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":84,"sourceHtmlUrl":85},"docs\u002Foutput-contract.md",3495,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Fdocs\u002Foutput-contract.md",{"path":87,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":88,"sourceHtmlUrl":89},"docs\u002Fscanner-coverage.md",5701,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Fdocs\u002Fscanner-coverage.md",{"path":91,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":92,"sourceHtmlUrl":93},"docs\u002Ftradeoffs.md",5851,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Fdocs\u002Ftradeoffs.md",{"path":95,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":96,"sourceHtmlUrl":97},"fixtures\u002Fcicd-github-actions-vulnerable\u002F.github\u002Fworkflows\u002Fci.yml",825,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fcicd-github-actions-vulnerable\u002F.github\u002Fworkflows\u002Fci.yml",{"path":99,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":100,"sourceHtmlUrl":101},"fixtures\u002Fcicd-github-actions-vulnerable\u002F.github\u002Fworkflows\u002Fdeploy.yml",570,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fcicd-github-actions-vulnerable\u002F.github\u002Fworkflows\u002Fdeploy.yml",{"path":103,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":106,"sourceHtmlUrl":107},"fixtures\u002Fcicd-github-actions-vulnerable\u002Fexpected-coverage.jsonl","OTHER","其他",1283,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fcicd-github-actions-vulnerable\u002Fexpected-coverage.jsonl",{"path":109,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":110,"sourceHtmlUrl":111},"fixtures\u002Fcicd-github-actions-vulnerable\u002Fexpected-findings.jsonl",3809,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fcicd-github-actions-vulnerable\u002Fexpected-findings.jsonl",{"path":113,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":114,"sourceHtmlUrl":115},"fixtures\u002Fcicd-github-actions-vulnerable\u002FREADME-FIXTURE.md",1390,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fcicd-github-actions-vulnerable\u002FREADME-FIXTURE.md",{"path":117,"resourceType":118,"resourceTypeDesc":119,"sizeBytes":120,"sourceHtmlUrl":121},"fixtures\u002Fconcurrency-race-vulnerable\u002Fauth.js","SCRIPT","脚本",1352,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fconcurrency-race-vulnerable\u002Fauth.js",{"path":123,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":124,"sourceHtmlUrl":125},"fixtures\u002Fconcurrency-race-vulnerable\u002Fexpected-coverage.jsonl",1818,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fconcurrency-race-vulnerable\u002Fexpected-coverage.jsonl",{"path":127,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":128,"sourceHtmlUrl":129},"fixtures\u002Fconcurrency-race-vulnerable\u002Fexpected-findings.jsonl",3716,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fconcurrency-race-vulnerable\u002Fexpected-findings.jsonl",{"path":131,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":132,"sourceHtmlUrl":133},"fixtures\u002Fconcurrency-race-vulnerable\u002Fpackage.json",281,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fconcurrency-race-vulnerable\u002Fpackage.json",{"path":135,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":136,"sourceHtmlUrl":137},"fixtures\u002Fconcurrency-race-vulnerable\u002FREADME-FIXTURE.md",1249,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fconcurrency-race-vulnerable\u002FREADME-FIXTURE.md",{"path":139,"resourceType":118,"resourceTypeDesc":119,"sizeBytes":140,"sourceHtmlUrl":141},"fixtures\u002Fconcurrency-race-vulnerable\u002Fsession.js",1062,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fconcurrency-race-vulnerable\u002Fsession.js",{"path":143,"resourceType":118,"resourceTypeDesc":119,"sizeBytes":144,"sourceHtmlUrl":145},"fixtures\u002Fconcurrency-race-vulnerable\u002Fwallet.js",840,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fconcurrency-race-vulnerable\u002Fwallet.js",{"path":147,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":148,"sourceHtmlUrl":149},"fixtures\u002Fcontainer-docker-vulnerable\u002Fdocker-compose.yml",516,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fcontainer-docker-vulnerable\u002Fdocker-compose.yml",{"path":151,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":152,"sourceHtmlUrl":153},"fixtures\u002Fcontainer-docker-vulnerable\u002FDockerfile",484,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fcontainer-docker-vulnerable\u002FDockerfile",{"path":155,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":156,"sourceHtmlUrl":157},"fixtures\u002Fcontainer-docker-vulnerable\u002Fexpected-coverage.jsonl",1286,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fcontainer-docker-vulnerable\u002Fexpected-coverage.jsonl",{"path":159,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":160,"sourceHtmlUrl":161},"fixtures\u002Fcontainer-docker-vulnerable\u002Fexpected-findings.jsonl",4277,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fcontainer-docker-vulnerable\u002Fexpected-findings.jsonl",{"path":163,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":164,"sourceHtmlUrl":165},"fixtures\u002Fcontainer-docker-vulnerable\u002FREADME-FIXTURE.md",1561,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fcontainer-docker-vulnerable\u002FREADME-FIXTURE.md",{"path":167,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":168,"sourceHtmlUrl":169},"fixtures\u002Fdesktop-tauri-vulnerable\u002Fexpected-coverage.jsonl",719,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fdesktop-tauri-vulnerable\u002Fexpected-coverage.jsonl",{"path":171,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":172,"sourceHtmlUrl":173},"fixtures\u002Fdesktop-tauri-vulnerable\u002Fexpected-findings.jsonl",2806,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fdesktop-tauri-vulnerable\u002Fexpected-findings.jsonl",{"path":175,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":176,"sourceHtmlUrl":177},"fixtures\u002Fdesktop-tauri-vulnerable\u002FREADME-FIXTURE.md",1223,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fdesktop-tauri-vulnerable\u002FREADME-FIXTURE.md",{"path":179,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":180,"sourceHtmlUrl":181},"fixtures\u002Fdesktop-tauri-vulnerable\u002Fsrc-tauri\u002Fcapabilities\u002Fdefault.json",266,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fdesktop-tauri-vulnerable\u002Fsrc-tauri\u002Fcapabilities\u002Fdefault.json",{"path":183,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":184,"sourceHtmlUrl":185},"fixtures\u002Fdesktop-tauri-vulnerable\u002Fsrc-tauri\u002FCargo.toml",577,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fdesktop-tauri-vulnerable\u002Fsrc-tauri\u002FCargo.toml",{"path":187,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":188,"sourceHtmlUrl":189},"fixtures\u002Fdesktop-tauri-vulnerable\u002Fsrc-tauri\u002Fsrc\u002Fdb\u002Fschema.sql",188,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fdesktop-tauri-vulnerable\u002Fsrc-tauri\u002Fsrc\u002Fdb\u002Fschema.sql",{"path":191,"resourceType":118,"resourceTypeDesc":119,"sizeBytes":192,"sourceHtmlUrl":193},"fixtures\u002Fdesktop-tauri-vulnerable\u002Fsrc-tauri\u002Fsrc\u002Flib.rs",758,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fdesktop-tauri-vulnerable\u002Fsrc-tauri\u002Fsrc\u002Flib.rs",{"path":195,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":196,"sourceHtmlUrl":197},"fixtures\u002Fdesktop-tauri-vulnerable\u002Fsrc-tauri\u002Ftauri.conf.json",337,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fdesktop-tauri-vulnerable\u002Fsrc-tauri\u002Ftauri.conf.json",{"path":199,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":200,"sourceHtmlUrl":201},"fixtures\u002Fiac-terraform-vulnerable\u002Fexpected-coverage.jsonl",1996,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fiac-terraform-vulnerable\u002Fexpected-coverage.jsonl",{"path":203,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":204,"sourceHtmlUrl":205},"fixtures\u002Fiac-terraform-vulnerable\u002Fexpected-findings.jsonl",4266,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fiac-terraform-vulnerable\u002Fexpected-findings.jsonl",{"path":207,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":208,"sourceHtmlUrl":209},"fixtures\u002Fiac-terraform-vulnerable\u002Fiam.tf",783,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fiac-terraform-vulnerable\u002Fiam.tf",{"path":211,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":212,"sourceHtmlUrl":213},"fixtures\u002Fiac-terraform-vulnerable\u002Fmain.tf",939,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fiac-terraform-vulnerable\u002Fmain.tf",{"path":215,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":216,"sourceHtmlUrl":217},"fixtures\u002Fiac-terraform-vulnerable\u002Fnetwork.tf",659,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fiac-terraform-vulnerable\u002Fnetwork.tf",{"path":219,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":220,"sourceHtmlUrl":221},"fixtures\u002Fiac-terraform-vulnerable\u002FREADME-FIXTURE.md",1508,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fiac-terraform-vulnerable\u002FREADME-FIXTURE.md",{"path":223,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":224,"sourceHtmlUrl":225},"fixtures\u002Fiac-terraform-vulnerable\u002Fterraform.tfvars",164,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fiac-terraform-vulnerable\u002Fterraform.tfvars",{"path":227,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":228,"sourceHtmlUrl":229},"fixtures\u002Fiac-terraform-vulnerable\u002Fvariables.tf",236,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fiac-terraform-vulnerable\u002Fvariables.tf",{"path":231,"resourceType":118,"resourceTypeDesc":119,"sizeBytes":232,"sourceHtmlUrl":233},"fixtures\u002Fllm-agent-python-vulnerable\u002Fagent.py",1776,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fllm-agent-python-vulnerable\u002Fagent.py",{"path":235,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":236,"sourceHtmlUrl":237},"fixtures\u002Fllm-agent-python-vulnerable\u002Fexpected-coverage.jsonl",1712,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fllm-agent-python-vulnerable\u002Fexpected-coverage.jsonl",{"path":239,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":240,"sourceHtmlUrl":241},"fixtures\u002Fllm-agent-python-vulnerable\u002Fexpected-findings.jsonl",5360,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fllm-agent-python-vulnerable\u002Fexpected-findings.jsonl",{"path":243,"resourceType":118,"resourceTypeDesc":119,"sizeBytes":244,"sourceHtmlUrl":245},"fixtures\u002Fllm-agent-python-vulnerable\u002Frag.py",715,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fllm-agent-python-vulnerable\u002Frag.py",{"path":247,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":248,"sourceHtmlUrl":249},"fixtures\u002Fllm-agent-python-vulnerable\u002FREADME-FIXTURE.md",1552,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fllm-agent-python-vulnerable\u002FREADME-FIXTURE.md",{"path":251,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":252,"sourceHtmlUrl":253},"fixtures\u002Fllm-agent-python-vulnerable\u002Frequirements.txt",35,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fllm-agent-python-vulnerable\u002Frequirements.txt",{"path":255,"resourceType":118,"resourceTypeDesc":119,"sizeBytes":256,"sourceHtmlUrl":257},"fixtures\u002Fprivacy-telemetry-vulnerable\u002Fapp.js",1260,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fprivacy-telemetry-vulnerable\u002Fapp.js",{"path":259,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":260,"sourceHtmlUrl":261},"fixtures\u002Fprivacy-telemetry-vulnerable\u002Fexpected-coverage.jsonl",2290,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fprivacy-telemetry-vulnerable\u002Fexpected-coverage.jsonl",{"path":263,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":264,"sourceHtmlUrl":265},"fixtures\u002Fprivacy-telemetry-vulnerable\u002Fexpected-findings.jsonl",3553,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fprivacy-telemetry-vulnerable\u002Fexpected-findings.jsonl",{"path":267,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":268,"sourceHtmlUrl":269},"fixtures\u002Fprivacy-telemetry-vulnerable\u002Findex.html",2195,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fprivacy-telemetry-vulnerable\u002Findex.html",{"path":271,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":272,"sourceHtmlUrl":273},"fixtures\u002Fprivacy-telemetry-vulnerable\u002Fpackage.json",314,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fprivacy-telemetry-vulnerable\u002Fpackage.json",{"path":275,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":276,"sourceHtmlUrl":277},"fixtures\u002Fprivacy-telemetry-vulnerable\u002FREADME-FIXTURE.md",1388,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fprivacy-telemetry-vulnerable\u002FREADME-FIXTURE.md",{"path":279,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":280,"sourceHtmlUrl":281},"fixtures\u002Fpython-django-vulnerable\u002Fexpected-coverage.jsonl",843,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fpython-django-vulnerable\u002Fexpected-coverage.jsonl",{"path":283,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":284,"sourceHtmlUrl":285},"fixtures\u002Fpython-django-vulnerable\u002Fexpected-findings.jsonl",4260,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fpython-django-vulnerable\u002Fexpected-findings.jsonl",{"path":287,"resourceType":118,"resourceTypeDesc":119,"sizeBytes":288,"sourceHtmlUrl":289},"fixtures\u002Fpython-django-vulnerable\u002Fmyapp\u002Fviews.py",1110,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fpython-django-vulnerable\u002Fmyapp\u002Fviews.py",{"path":291,"resourceType":118,"resourceTypeDesc":119,"sizeBytes":292,"sourceHtmlUrl":293},"fixtures\u002Fpython-django-vulnerable\u002Fmyproject\u002Fsettings.py",1240,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fpython-django-vulnerable\u002Fmyproject\u002Fsettings.py",{"path":295,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":296,"sourceHtmlUrl":297},"fixtures\u002Fpython-django-vulnerable\u002FREADME-FIXTURE.md",1399,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fpython-django-vulnerable\u002FREADME-FIXTURE.md",{"path":299,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":300,"sourceHtmlUrl":301},"fixtures\u002Fpython-django-vulnerable\u002Frequirements.txt",186,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fpython-django-vulnerable\u002Frequirements.txt",{"path":303,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":304,"sourceHtmlUrl":305},"fixtures\u002FREADME.md",3671,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002FREADME.md",{"path":307,"resourceType":118,"resourceTypeDesc":119,"sizeBytes":308,"sourceHtmlUrl":309},"fixtures\u002Frun-harness.sh",4557,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Frun-harness.sh",{"path":311,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":312,"sourceHtmlUrl":313},"fixtures\u002Fwebapp-express-vulnerable\u002Fexpected-coverage.jsonl",1076,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fwebapp-express-vulnerable\u002Fexpected-coverage.jsonl",{"path":315,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":316,"sourceHtmlUrl":317},"fixtures\u002Fwebapp-express-vulnerable\u002Fexpected-findings.jsonl",4034,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fwebapp-express-vulnerable\u002Fexpected-findings.jsonl",{"path":319,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":320,"sourceHtmlUrl":321},"fixtures\u002Fwebapp-express-vulnerable\u002Fpackage.json",392,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fwebapp-express-vulnerable\u002Fpackage.json",{"path":323,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":324,"sourceHtmlUrl":325},"fixtures\u002Fwebapp-express-vulnerable\u002FREADME-FIXTURE.md",1876,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fwebapp-express-vulnerable\u002FREADME-FIXTURE.md",{"path":327,"resourceType":118,"resourceTypeDesc":119,"sizeBytes":328,"sourceHtmlUrl":329},"fixtures\u002Fwebapp-express-vulnerable\u002Fsrc\u002Fapp.js",1429,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fwebapp-express-vulnerable\u002Fsrc\u002Fapp.js",{"path":331,"resourceType":118,"resourceTypeDesc":119,"sizeBytes":332,"sourceHtmlUrl":333},"fixtures\u002Fwebapp-express-vulnerable\u002Fsrc\u002Fconfig.js",308,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fwebapp-express-vulnerable\u002Fsrc\u002Fconfig.js",{"path":335,"resourceType":118,"resourceTypeDesc":119,"sizeBytes":336,"sourceHtmlUrl":337},"fixtures\u002Fwebapp-express-vulnerable\u002Fsrc\u002Froutes\u002Fuser.js",878,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fwebapp-express-vulnerable\u002Fsrc\u002Froutes\u002Fuser.js",{"path":339,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":340,"sourceHtmlUrl":341},"fixtures\u002Fwebapp-frontend-vulnerable\u002Fexpected-coverage.jsonl",1395,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fwebapp-frontend-vulnerable\u002Fexpected-coverage.jsonl",{"path":343,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":344,"sourceHtmlUrl":345},"fixtures\u002Fwebapp-frontend-vulnerable\u002Fexpected-findings.jsonl",3926,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fwebapp-frontend-vulnerable\u002Fexpected-findings.jsonl",{"path":347,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":348,"sourceHtmlUrl":349},"fixtures\u002Fwebapp-frontend-vulnerable\u002Findex.html",772,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fwebapp-frontend-vulnerable\u002Findex.html",{"path":351,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":352,"sourceHtmlUrl":353},"fixtures\u002Fwebapp-frontend-vulnerable\u002FREADME-FIXTURE.md",1407,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fwebapp-frontend-vulnerable\u002FREADME-FIXTURE.md",{"path":355,"resourceType":118,"resourceTypeDesc":119,"sizeBytes":356,"sourceHtmlUrl":357},"fixtures\u002Fwebapp-frontend-vulnerable\u002Fserver.js",710,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Ffixtures\u002Fwebapp-frontend-vulnerable\u002Fserver.js",{"path":359,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":360,"sourceHtmlUrl":361},"schema\u002Fcoverage.schema.json",2116,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Fschema\u002Fcoverage.schema.json",{"path":363,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":364,"sourceHtmlUrl":365},"schema\u002Ffinding.schema.json",3629,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Fschema\u002Ffinding.schema.json",{"path":367,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":368,"sourceHtmlUrl":369},"specialists\u002Fauth-authz-auditor.md",4315,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Fspecialists\u002Fauth-authz-auditor.md",{"path":371,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":372,"sourceHtmlUrl":373},"specialists\u002Fci-cd-security-auditor.md",2052,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Fspecialists\u002Fci-cd-security-auditor.md",{"path":375,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":376,"sourceHtmlUrl":377},"specialists\u002Fconcurrency-race-auditor.md",2218,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Fspecialists\u002Fconcurrency-race-auditor.md",{"path":379,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":380,"sourceHtmlUrl":381},"specialists\u002Fcontainer-runtime-auditor.md",2029,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Fspecialists\u002Fcontainer-runtime-auditor.md",{"path":383,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":384,"sourceHtmlUrl":385},"specialists\u002Fdata-exposure-auditor.md",2394,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Fspecialists\u002Fdata-exposure-auditor.md",{"path":387,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":388,"sourceHtmlUrl":389},"specialists\u002Fdependency-supplychain-auditor.md",2563,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Fspecialists\u002Fdependency-supplychain-auditor.md",{"path":391,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":392,"sourceHtmlUrl":393},"specialists\u002Ffrontend-security-auditor.md",2065,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Fspecialists\u002Ffrontend-security-auditor.md",{"path":395,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":396,"sourceHtmlUrl":397},"specialists\u002Fiac-auditor.md",2292,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Fspecialists\u002Fiac-auditor.md",{"path":399,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":400,"sourceHtmlUrl":401},"specialists\u002Finput-validation-auditor.md",3954,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Fspecialists\u002Finput-validation-auditor.md",{"path":403,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":404,"sourceHtmlUrl":405},"specialists\u002Fprivacy-telemetry-auditor.md",2483,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Fspecialists\u002Fprivacy-telemetry-auditor.md",{"path":407,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":408,"sourceHtmlUrl":409},"specialists\u002Fprompt-injection-auditor.md",2378,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Fspecialists\u002Fprompt-injection-auditor.md",{"path":411,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":412,"sourceHtmlUrl":413},"specialists\u002Fsecrets-crypto-auditor.md",3237,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Fspecialists\u002Fsecrets-crypto-auditor.md",{"path":415,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":416,"sourceHtmlUrl":417},"specialists\u002Fsilent-failure-hunter.md",2627,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Fspecialists\u002Fsilent-failure-hunter.md",{"path":419,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":420,"sourceHtmlUrl":421},"stack-signals.md",4637,"https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-team\u002Fstack-signals.md",[423,445,469,488,508,537],{"skillNo":424,"name":425,"nameZh":6,"description":426,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":427,"categories":428,"keywords":429,"publishedAt":48},"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",[],[425,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444],"pull","harness","detection","projects","check","up","reports","project","full","remote","states","for","changes","modes","single",{"skillNo":446,"name":447,"nameZh":6,"description":448,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":449,"categories":450,"keywords":452,"publishedAt":48},"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",[451],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[30,453,454,455,456,457,458,29,42,459,460,435,461,462,463,37,464,465,466,467,468],"spec","spec review","design","architecture","code","inventory","never","only","specification","poke","deep","proposal","lens","quick","reviews","when",{"skillNo":470,"name":471,"nameZh":6,"description":472,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":473,"categories":474,"keywords":475,"publishedAt":48},"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",[],[471,476,477,431,478,479,480,481,482,483,435,484,485,486,487,441],"commit","pr","push","open","wrap up","work","short","version","wrap","alias","cut","it",{"skillNo":489,"name":490,"nameZh":6,"description":491,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":492,"categories":493,"keywords":494,"publishedAt":48},"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",[],[471,495,487,476,496,497,479,498,499,481,40,500,435,501,502,503,504,505,439,506,507],"ship it","tasks","create","Bash","gh pr","fetch","log","files","done","checkout","move","ls","parse",{"skillNo":509,"name":510,"nameZh":6,"description":511,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":512,"categories":513,"keywords":514,"publishedAt":48},"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",[],[515,516,517,518,431,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,444,535,536,468],"SET","context","set context","planning","first","graphify","plan","sweep","repo","user","use","build","back","query","as","questions","manual","standalone","path","codebase","phase","gather",{"skillNo":538,"name":539,"nameZh":6,"description":540,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":541,"categories":542,"keywords":548,"publishedAt":48},"01M6K7TP7VTTPW9H79AEHEVPGK","sec-review-fixes","Companion to `sec-review-team`. Takes the `REPORT.md` or `findings.jsonl` from a security review run and produces fix PRs (one per finding or one consolidated) with interactive approval. Each candidate finding becomes a proposed diff + a regression test that would have caught it + a commit\u002FPR citing the finding ID. Filters by default to `severity IN (critical, high) AND confidence IN (certain, likely)`. Modes: interactive (default), `--dry-run` (produces a fix-plan document with no code changes), `--re-verify` (re-runs sec-review-team against a specific set of finding IDs and reports fixed \u002F still-present \u002F inconclusive). Safeguards: branch-only commits (never main), no force-push, clean-working-tree required, regression-test must pass before commit lands. Use when the user says \"fix the security findings\", \"apply sec-review fixes\", \"open PRs for the security report\", \"re-verify the security fixes\", or similar.","https:\u002F\u002Fgithub.com\u002Ftbeack\u002Ffsad_playbook\u002Fblob\u002Fmain\u002Fskills\u002Fsec-review-fixes\u002FSKILL.md",[543],{"categoryNo":544,"categoryName":545,"taxonomyType":546,"taxonomyTypeDesc":547},"01JBSEEDCAT000000000000034","行政与办公人员","PROFESSION","适用职业",[30,549,550,551,457,515,552,479,553,40,554,459,460,555,556,557,558,54,559,35,468],"fixes","review fixes","sec review fixes","ids","regression","fix","security report","filters","default","clean","critical"]