[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M78CEBF8MGZNEDFY2ABV7GF2":3,"skill-same:01M78CEBF8MGZNEDFY2ABV7GF2":76},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":18,"linkOnly":19,"markdownContent":20,"markdownBody":21,"frontMatter":22,"refName":26,"commitSha":27,"skillDirectory":28,"forksCount":29,"repositoryHtmlUrl":30,"repositoryHomepageUrl":6,"ownerHtmlUrl":31,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":32,"install":33,"resources":45},"01M78CEBF8MGZNEDFY2ABV7GF2","swarm-pr-review",null,"Run a graph-guided, tool-augmented PR review using context packing, parallel exploration, mandatory repository-agnostic risk-family coverage with dispatch scaled to diff size and risk, independent reviewer validation, critic challenge, and metrics writeback. Use for deep pull request review with low false-positive tolerance and high recall in any repository, on any agent harness (structured lane controller, native parallel subagents, or single-context sequential passes).","zaxbysauce\u002Fzmem","zaxbysauce","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F10211642?v=4","01M78CD0J751DPXGF3YVNH6VCH","01M78CD0JZPBW7BJHV1MST3CTZ",0,"MIT","https:\u002F\u002Fgithub.com\u002Fzaxbysauce\u002Fzmem\u002Fblob\u002Fmain\u002Fskills\u002Fswarm-pr-review\u002FSKILL.md",[],[],"2026-11-15 14:19:17",false,"---\nname: swarm-pr-review\naudience: swarm-plugin\ndescription: Run a graph-guided, tool-augmented PR review using context packing, parallel exploration, mandatory repository-agnostic risk-family coverage with dispatch scaled to diff size and risk, independent reviewer validation, critic challenge, and metrics writeback. Use for deep pull request review with low false-positive tolerance and high recall in any repository, on any agent harness (structured lane controller, native parallel subagents, or single-context sequential passes).\ndisable-model-invocation: true\nswarm-contract-digest: 103ae1c77229\n---\n\n# \u002Fswarm-pr-review\n\nRun a structured, high-confidence PR review that maximizes valid findings without flooding the user with unvalidated noise.\n\n## Graph-first evidence contract\n\nAfter binding the exact diff, use `repo_map` `diff_context` and `impact_cone`; add `route_trace` and `data_trace` for changes that cross trust or data boundaries. Graph evidence is advisory only. If freshness is stale or inconclusive, confidence is low, source is missing, the language is unsupported\u002Fdynamic, the graph is absent, or an action fails, inspect the direct source, Git diff, and searches before validating a finding.\n\nThe review ladder is:\n\n**Scope → obligations → context pack → deterministic signals → parallel explorers → repository-agnostic risk-family coverage (dispatch scaled by depth tier) → independent reviewer validation → critic challenge → grouped synthesis → metrics \u002F knowledge writeback.**\n\n## Handoff To PR Feedback\n\nUse `..\u002Fswarm-pr-feedback\u002FSKILL.md` instead of this skill when the user's task is\nto address existing PR feedback, review comments, requested changes, CI failures,\nmerge conflicts, stale branch state, or pasted reviewer findings. This skill\ndiscovers and validates new findings; `swarm-pr-feedback` closes known feedback\nwithout running a fresh broad review.\n\nWhen a review finishes with actionable validated findings, stop and ask the user\nwhether to continue into `swarm-pr-feedback`. Do not auto-dispatch fix work from\n`PR_REVIEW`. Instead, write a handoff artifact — under Profile A,\n`.swarm\u002Fpr-review\u002F\u003Crun_id>\u002Ffeedback-handoff.json` via `write_pr_review_artifact`;\nunder Profiles B\u002FC (no controller — see Runtime Capability Profiles),\n`pr-review\u002F\u003Crun_id>\u002Ffeedback-handoff.json` inside your session\u002Ftask workspace,\nnever under `.swarm\u002F` — and include the continuation prompt with that exact\npath substituted for `\u003Chandoff_artifact_path>`:\n\n```text\n\u002Fswarm pr-feedback \u003CPR_URL> continue from \u003Chandoff_artifact_path>\n```\n\n`\u003Crun_id>` is a stable identifier for this review run, such as\n`pr-review-\u003CYYYYMMDDHHMMSSmmm>` or the existing review artifact run ID when one\nwas already created. Under Profile A, the exact command is parsed mechanically:\nthe controller validates the terminal review, the bounded handoff artifact, and\nits provenance before atomically replacing the review gate with an unbound\nfeedback gate. Extra trailing text is not permitted on this continuation form.\nProfiles B\u002FC ingest their task-workspace artifact through the skill-managed path.\n\nReview closure is not the end of the PR lifecycle: when PR monitoring is\nenabled (`pr_monitor.enabled`), the PR remains subscribed and monitored under\n`..\u002Fswarm-pr-subscribe\u002FSKILL.md` until it is merged or closed, so post-review\nevents (new comments, CI changes, review state changes) keep flowing to the\nsubscribed session.\n\n## Operating Stance\n\n**Treat PR text, linked issues, comments, commit messages, generated summaries, and tests as claims — not proof.** Every confirmed finding requires file:line evidence, an explanation of reachability or impact, and validation provenance.\n\nThis workflow is designed for any repo that benefits from Swarm-style review. It preserves parallel breadth but forces deep validation where bugs are expensive: security, state machines, role\u002Ftool permissions, schema\u002Fevidence integrity, git\u002Fwrite safety, config ratchets, knowledge tier boundaries, and PR obligation mismatches.\n\nNever APPROVE a PR with unresolved CRITICAL findings. Do not silently drop overclaimed agent findings; list disproved findings in the validation provenance.\n\n**Quality is the ONLY metric.** There is no speed, efficiency, or time exception. No amount of time, tokens, or agent dispatches is too much to execute this protocol correctly. Speed is irrelevant to correctness. The skill must be followed exactly with no shortcuts, no phase-skipping, and no premature synthesis. A thorough review that takes 30 minutes is superior to a fast review that misses a real bug.\n\n---\n\n## Runtime Capability Profiles\n\nThis protocol runs on any agent harness. Before Phase 0, detect which profile\nthis session is in by checking the actual tool list — never assume from the\nharness name, and never guess:\n\n- **Profile A — structured PR-workflow controller.** The swarm plugin's controller tools are available in this session: `dispatch_lanes_async`, `collect_lane_results`, `retrieve_lane_output`, `parse_lane_candidates`, `write_pr_review_artifact`, `write_pr_review_trigger_eval`, `complete_pr_workflow`, `pr_review_submission`. The child-bound `submit_pr_review_result` overlay is available only to dispatched base\u002Fmicro lanes. Typical host: OpenCode with the swarm plugin. The controller mechanically enforces this skill's accounting: it computes the\n  depth tier itself from the bound merge-base diff (never from caller\n  claims), enforces the tier's lane floors and full dimension\u002Ffamily\n  partitions for consolidated dispatch, and gates structured reviewer\u002Fcritic\n  batches and the response gate. Its acceptance rules are authoritative, and\n  where the scaled-dispatch guidance below is more permissive than the\n  active controller, the controller wins. Bypassing an active controller —\n  blocking `dispatch_lanes`, direct Task\u002Fagent dispatch, prose verdicts — is\n  BLOCKED.\n- **Profile B — native parallel subagents, no controller.** The controller\n  tools are absent, but the harness can spawn independent fresh-context\n  subagents (for example Claude Code's `Agent`\u002F`Task` tool, or the native\n  subagent mechanisms in Codex and ZCode). Run the same phases, role\n  boundaries, row contracts, and join barriers; you are the accounting layer\n  the controller would otherwise be: bind the exact `pr_head_sha` in every\n  lane prompt, record per-lane provenance (lane id, head SHA) on every ledger\n  row, settle every lane before the next phase begins, and persist ledgers to\n  files in your harness's session\u002Ftask workspace. Never write runtime\n  artifacts under `.swarm\u002F` — that directory belongs to the plugin controller.\n- **Profile C — single context, no subagents.** The harness cannot spawn\n  independent subagents in-session. Execute the same phases as strictly\n  separated sequential passes — candidate generation, then reviewer\n  validation, then critic challenge — re-deriving rather than restating\n  earlier reasoning in each pass, with the same ledger rows and per-family\n  attestations. Disclose in the validation provenance that reviewer\u002Fcritic\n  independence was procedural (separate passes in one context), not\n  contextual.\n\n| Harness (typical) | Profile | Lane dispatch | Ledger persistence | Completion gate |\n|---|---|---|---|---|\n| OpenCode + swarm plugin | A | `dispatch_lanes_async` \u002F `collect_lane_results` | `write_pr_review_artifact`, `write_pr_review_trigger_eval` | `complete_pr_workflow` |\n| Claude Code | B | parallel `Agent`\u002F`Task` subagents | ledger files in the session task workspace | Pre-Synthesis Gate checklist |\n| OpenAI Codex | B | parallel subagents (fresh context) | ledger files in working notes | Pre-Synthesis Gate checklist |\n| ZCode | B | parallel subagents (fresh context) | ledger files in working notes | Pre-Synthesis Gate checklist |\n\nHost-native JSON-schema transport is optional and currently unregistered on the\ntested host matrix, so Profile A uses the child-bound `submit_pr_review_result`\ntool as its supported baseline. Any future native integration must implement\nthe fixed internal `promptJsonSchema({ sessionId, agent, schema, parts })` seam\nand pass adapter-present, unsupported-before-execution, provider-failure,\ntimeout, and per-session capability tests before registration.\n\n**Completion-gate assurance is NOT equivalent across profiles.** Only Profile A\nenforces completion MECHANICALLY: the controller's `complete_pr_workflow` receipt\ngate refuses synthesis unless base coverage, the 11-family trigger ledger, and the\nreviewer\u002Fcritic artifacts are all present and head-bound. Profiles B and C rely on\nthe operator executing the Pre-Synthesis Gate checklist themselves — there is no\nruntime receipt gate that refuses a partial synthesis. Treat B\u002FC as PROCEDURAL\nassurance only; do not claim mechanical completion parity with Profile A for this\nrepository unless a controller-equivalent receipt gate is added for those profiles.\n\nVerify each row against your own current tool list before relying on it; a\nharness may gain or lose capabilities between versions. OpenCode, Claude Code,\nCodex, and ZCode can all spawn fresh-context subagents in current versions —\nrun Profile B wherever the session actually exposes that capability; reserve\nProfile C for sessions that genuinely lack a subagent mechanism, never assigning\na harness to Profile C by name alone. The absence of the controller is NOT a\nBLOCKED condition — Profiles B and C are legitimate execution paths whose\ncompletion gate is PROCEDURAL (see the note above), not the mechanically\nenforced receipt gate Profile A provides.\nBLOCKED is reserved for bypassing an active controller and for coverage gaps\nthat remain unclosable after bounded retries on any profile.\n\n### Profile A controller quick reference\n\nThis is the concise mechanical contract for an active structured controller.\nThe detailed phases below explain the reasoning, but they do not override this\nordering, vocabulary, or schema.\n\n- Base `workflow_lane` IDs (all six): `intent-architecture`,\n  `correctness-state`, `tests-falsifiability`, `security-trust`,\n  `reliability-performance`, `compatibility-delivery`.\n- Trigger\u002Fmicro `workflow_lane` IDs (all eleven): `auth-identity-secrets`,\n  `untrusted-input-boundaries`, `subprocess-platform`, `concurrency-state`,\n  `dependencies-build-release`, `api-schema-migrations`,\n  `test-infrastructure`, `ui-accessibility-i18n`, `privacy-observability`,\n  `generated-provenance`, `unclassified-risk`.\n- Base candidate header:\n  `[CANDIDATE] | candidate_id | lane | severity | category | file:line | claim | evidence_summary | impact_context | confidence | risk_impact | risk_tags`\n- Base clean attestation:\n  `[CLEAN] | lane | coverage_scope | evidence`\n- Micro\u002Fcouncil candidate header:\n  `[CANDIDATE] | candidate_id | micro_lane | severity | category | file:line | claim | invariant_violated | evidence_summary | confidence | risk_impact | risk_tags`\n- Micro\u002Fcouncil clean attestation:\n  `[CLEAN] | micro_lane | coverage_scope | evidence`\n- Severity is exactly `INFO | LOW | MEDIUM | HIGH | CRITICAL`; confidence is\n  exactly `LOW | MEDIUM | HIGH`.\n\nController order is exact: bind the immutable head\u002Fbase range; dispatch,\nsettle, and parse base lanes; evaluate every trigger row; dispatch micro lanes;\nsettle and parse every matched micro family; persist the trigger evaluation;\nensure each base\u002Fmicro child lane submits exactly one child-bound structured\nreceipt; persist post-explorer findings; run reviewers;\nrun critics; then persist the final artifact and complete the workflow. Transcript\n`[CANDIDATE]` \u002F `[CLEAN]` rows are deprecated legacy compatibility only for\nlanes whose snapped `pr_review_legacy_transcript_compatibility` contract\nexplicitly enables them.\nThe **initial** micro dispatch MUST supply the complete trigger-evaluation\nledger; that dispatch freezes it for the session.\nAny subsequent micro batch in that same session MAY omit `trigger_evaluation`\nand reuse the frozen ledger. If a subsequent batch explicitly supplies a copy,\nthat copy MUST remain exactly identical to the frozen ledger.\n\nAll machine-readable candidate headers, candidate rows, and clean attestations\nmust be emitted as unfenced plain text. Markdown fences shown in this skill are\ndocumentation fences only; emitting the backticks causes the controller to\nignore those rows as quoted\u002Fexample material.\n\n---\n\n## Review Modes\n\n### Default layered workflow\n\nAlways run the default layered workflow (mechanically enforced under Profile A). Explorers produce only candidates. The orchestrator does not confirm or disprove candidates.\n\n### Council mode — opt in only\n\nCouncil mode applies only when the user explicitly says one of:\n\n- `council`\n- `independent review`\n- `N-agent review`\n- `\u002Fcouncil`\n- `[COUNCIL MODE]`\n- `[MODE: PR_REVIEW … council=true]`\n- `assume all work is wrong`\n\nCouncil mode supplements the default mechanical workflow; it never replaces or weakens it. Even when council mode is triggered, first complete the base-dimension coverage (the tier-floored base dispatch under Profile A — the exact-six wave at depth tier L), micro-lane ledger persistence, and every repository-agnostic risk-family evaluation at the same exact `pr_head_sha`. Route supplementary council output into the candidate ledger before independent reviewer classification. If the council request arrives after classification has begun, run the council as an additional candidate pass and dispatch a new structured reviewer batch for those candidates before synthesis.\n\n---\n\n## Anti-Self-Review Rule\n\nThe main thread \u002F orchestrator MUST NOT classify, confirm, disprove, or judge explorer candidates in the default workflow.\n\nThe orchestrator may:\n\n- determine scope,\n- build or request the context pack,\n- launch explorers and the full risk-family micro coverage (every family evaluated; lane count per depth tier and profile),\n- extract candidates from lane artifacts via `parse_lane_candidates` (Profile A) or by collecting the structured `[CANDIDATE]` rows from lane reports (Profiles B\u002FC),\n- filter, group, and chunk candidates for reviewer dispatch,\n- route candidates to reviewers,\n- route reviewer-confirmed findings to critics,\n- group validated findings,\n- prepare the final report.\n\nThe orchestrator MUST NOT:\n\n- re-read a candidate's target code to decide if it is valid,\n- silently downgrade or discard an explorer candidate,\n- treat tool output as a confirmed finding,\n- report a finding that no reviewer validated,\n- classify or judge candidates based on preview text alone — always use the structured parser output (Profile A) or the verbatim-collected `[CANDIDATE]` rows (Profiles B\u002FC).\n\nIf the orchestrator catches itself validating code, it must stop and delegate validation to a reviewer subagent.\n\nException: in explicit Council mode only, the main thread may act as the independent reviewer as described in the Council Mode section. Prefer a reviewer subagent when available.\n\n---\n\n## Scope Detection\n\nDetermine review scope using this priority:\n\n1. explicit user-provided PR URL, PR number, commit, branch, or file scope,\n2. current feature branch diff vs the remote-tracking base ref (`origin\u002Fmain`,\n   `origin\u002Fmaster`; a local `main`\u002F`master` only as a last resort — it is only as\n   fresh as the last fetch and yields a different merge base),\n3. staged changes,\n4. latest commit,\n5. user-specified files or directories.\n\nRecord:\n\n- base ref,\n- head ref,\n- commit range,\n- changed files,\n- deleted files,\n- generated files,\n- lockfiles,\n- test files,\n- docs\u002Fconfig\u002Fschema files,\n- whether the working tree is dirty.\n\nIf scope cannot be determined, review the narrowest safe scope available and state the limitation.\n\n### Pre-flight git ref availability\n\nBefore launching explorers (Phase 3), perform this exact standalone sequence:\n\n1. Resolve and retain the authoritative full `pr_head_sha` from PR metadata.\n2. Verify the working tree is clean with `git status --porcelain`. If it is\n   dirty at all — tracked changes, untracked files, or both — call\n   `prepare_pr_workflow_checkout` (Profile A). The tool supports\n   self-discovery: call it with no `paths` argument to auto-discover and\n   preserve every dirty path in one step, including untracked files; an\n   already-clean tree returns a no-op (nothing is stashed, no receipt is\n   written). Pass explicit `paths` only when you already have the exact,\n   bounded list of dirty tracked files and want the older exact-match\n   contract. Without the controller (Profiles B\u002FC), do not blind-stash over\n   dirty state: surface tracked changes to the user, or abort. Do not issue\n   `git stash` through shell.\n   Treat the controller's Git-state result as final for this attempt: `clean`\n   proceeds, `stashable` permits exactly one checkout-preparation call, and\n   `recovery-required` or `indeterminate` means report the typed\n   `required_action`, abort\u002Fclear any already-active gate, and stop. Retry only\n   when the controller explicitly returns `retryable: true`; never fight an\n   unmerged index or in-progress Git operation with repeated stash attempts.\n3. Fetch the PR head as one standalone command, for example\n   `git fetch origin refs\u002Fpull\u002F\u003CN>\u002Fhead`. Do not compose fetch and checkout.\n3a. Fetch the base branch as its own standalone command, for example\n   `git fetch origin main`. Skipping this is the single most common cause of a\n   rejected dispatch: the merge base is recomputed against `base_ref`, and a\n   local `main`\u002F`refs\u002Fheads\u002Fmain` that was never refreshed resolves to a\n   different commit than `origin\u002Fmain` for the same `base_sha`.\n4. Prove the full commit exists locally with two portable standalone commands:\n   `git rev-parse --verify \u003Cfull_pr_head_sha>^0`, then\n   `git cat-file -t \u003Cfull_pr_head_sha>`. The second command must print\n   `commit`. This avoids shell\u002Fwrapper parsing differences around the\n   `^{commit}` suffix on Windows.\n5. Check out the exact PR filesystem with\n   `git switch --detach \u003Cfull_pr_head_sha>`. Do not use `--track FETCH_HEAD`:\n   `FETCH_HEAD` is not a remote-tracking branch.\n6. Confirm `git rev-parse HEAD` equals the full `pr_head_sha`, bind that exact\n   head (Profile A: through the first PR-review controller call; Profiles B\u002FC:\n   record it at the top of the findings ledger and repeat it in every lane\n   prompt), and finish this before dispatching explorer lanes.\n\nExplorer agents read files from the working tree, not from git history. Passing\nthe commit range in a prompt cannot substitute for this checkout because\n`Read` \u002F `Glob` \u002F `Grep` operate on the filesystem.\n- Explicitly pass the verified merge-base range (`base_sha...pr_head_sha`) in every explorer delegation so explorers inspect exactly the bound PR diff. Include `base_ref` only as the live ref used to recompute `base_sha`; do not substitute a two-dot branch-tip range.\n\nIf refs cannot be fetched or checked out, state the limitation in the context pack.\n\n### Shell rules under the PR_REVIEW gate\n\nThe gate accepts one command per tool call — never compose commands with\n`&&`, `;`, shell pipelines, redirects (`>`, `>>`, `\u003C`), or `$(...)`\u002F`` ` ``\nsubstitution. The only literal-pipe exception is inside one closed\ndouble-quoted `gh api --jq` argument with no backslash-escaped nested double\nquotes; that escape is ambiguous under `cmd.exe`. The exception does not\npermit an outer pipeline or any other control syntax.\nA single leading `cd \u003Cdir> &&` prefix and a trailing `2>&1` suffix are\ntolerated, but only on read-only commands. State-transition verbs — `git\nfetch`, `git checkout`, `git switch`, `git branch`, and `gh pr checkout` —\nmust always run bare: no `cd` prefix, no `2>&1` suffix.\n\nAllowed read-only `git` subcommands: `status`, `log`, `show`, `diff`,\n`rev-parse`, `merge-base`, `ls-files`, `grep`, `blame`, `cat-file`,\n`for-each-ref`, `branch --list` (listing only — mutation flags are blocked),\n`remote -v`, and `config --get`.\n\nPrefer tools over raw shell for state that a single read-only command cannot\ncover cleanly:\n\n- `pr_workflow_status` — observe local HEAD, branch, dirty-file state,\n  remotes, and gate state in one read-only call.\n- `gh_evidence` — bounded PR\u002Fissue\u002Frun metadata without a shell round-trip.\n- If `gh` is not installed, the web fetch tool against the equivalent\n  `api.github.com` REST URL is the degraded read-only path.\n\n## Phase 0A: Existing PR Signal Ingestion\n\nWhen reviewing a PR, ingest and triage every existing signal BEFORE starting\nPhase 0. These are candidate generators and obligation sources, not\npre-confirmed findings.\n\n### PR title and body compliance check\n\nBefore deeper analysis, discover whether the repository defines a PR\npublication contract (for example a local `commit-pr` skill, `CONTRIBUTING`\nguidance, a PR template, or a CI check such as `pr-standards`). If it does,\nverify the PR against that contract and record any gap as an advisory ledger\nitem. If it does not, do not invent opencode-swarm-specific title\u002Fbody\nsections; still verify that the PR text is not misleading about what the diff\ndoes or proves.\n\nAt minimum, check:\n\n- required title\u002Fbody\u002Flinked-issue structure from the discovered repository\n  contract,\n- issue-closing, migration, release-note, invariant, or test-plan claims made\n  in the PR text,\n- whether those claims are supported by the actual diff and the current issue\n  state.\n\n**Issue-closing claim-integrity check:** if the PR body uses an issue-closing\nkeyword such as `Closes #\u003Cissue-number>`, verify (a) the issue is currently open\n(`gh issue view \u003CN> --json state` when the host is GitHub), and (b) the diff\naddresses the issue's acceptance criteria (read the issue, map each criterion\nto changed files\u002Fsymbols, and inspect the diff for those areas). If the issue\nis already closed by another merged PR, do NOT re-close it — the duplicate\nclosing reference is misleading. If the issue is open but the diff does not\naddress the acceptance criteria, mark the claim as `UNVERIFIED — claim\nintegrity` in the validation provenance and surface the unresolved gap to the\nuser before synthesis.\n\nContract non-compliance is a ledger item (advisory unless the repository\nexplicitly makes it blocking). If the PR is from an external contributor, note\nthe compliance gap for the maintainer to address before merge.\n\nThis intake includes:\n\n- review comments, review summaries, requested changes, and bot findings,\n- CI\u002Fcheck failures, annotations, and relevant logs,\n- mergeability\u002Fconflicts, `mergeStateStatus`, and stale\u002Fbase-drift state,\n- PR body claims, linked issues, acceptance criteria, and test-plan claims,\n- commit messages and app\u002Fbot commits on the PR branch.\n\nWhen multiple CI\u002Fcheck runs have the same name, reconcile them by head SHA and\ntime: the latest run for the exact bound head SHA supersedes an older same-check\nrun on that same head. Keep an older failure only as historical diagnostic\nevidence; do not report it as the current PR state after a newer same-head run\nhas completed successfully.\n\nWhen thread resolution state matters, prefer GraphQL review-thread inspection.\nIf GraphQL is unavailable, keep the signal and mark\n`resolution_state: UNKNOWN`; do not drop it from scope.\n\n### Step 1 — Fetch all PR feedback surfaces\n\nThe commands below are GitHub examples. On GitLab, Bitbucket, Gerrit, or\nanother code host, use the host's API\u002Fconnector\u002FCLI to enumerate the same full\nsurface, including pagination and unresolved-thread state. Host choice never\nreduces the intake ledger.\n\n```bash\n# Issue comments (general PR thread)\ngh api --paginate repos\u002F{owner}\u002F{repo}\u002Fissues\u002F{PR_NUMBER}\u002Fcomments\n\n# Review comments (inline code comments)\ngh api --paginate repos\u002F{owner}\u002F{repo}\u002Fpulls\u002F{PR_NUMBER}\u002Fcomments\n\n# Review summaries (approve\u002Frequest-changes\u002Fcomment events)\ngh api --paginate repos\u002F{owner}\u002F{repo}\u002Fpulls\u002F{PR_NUMBER}\u002Freviews\n```\n\n`--paginate` requests every REST page. These three calls are gate-allowed as\nwritten. A literal jq filter passed as one closed double-quoted `gh api --jq`\nargument is also allowed when it needs no backslash-escaped nested double\nquotes; use `gh_evidence` when a portable filter cannot meet that shape. A real\nshell pipeline to `jq` or another command remains blocked. To\nseparate bot\u002Fautomated reviews (Copilot, Codex, CodeRabbit, etc.) from human\nones, apply the same predicate in context to the JSON already returned above\n— `user.type == \"Bot\"` or a `user.login` match against\n`bot|copilot|coderabbit|codex` (case-insensitive) — instead of re-fetching\nwith a shell-side `--jq` filter. `gh_evidence` with `target: \"pr\"` and\n`fields: \"comments\"` is the sanctioned read-only tool path for the same PR\ncomment data when a tool call is preferred over a raw shell command. `gh pr\nview --json comments,reviews` is convenience-only because those fields have\nitem caps; never use it as the authoritative \"all signals\" intake.\n\n### Step 2 — Classify each comment\n\n| Category | Action |\n|----------|--------|\n| **Human review with file:line evidence** | Add as candidate finding with `source: existing-review` — still needs reviewer validation |\n| **Bot\u002Fautomated finding with specific code reference** | Add as candidate finding with `source: bot-review` — high false-positive rate, treat as unverified |\n| **General feedback \u002F style preference** | Add as advisory obligation |\n| **Resolved\u002Foutdated comment** | Skip — note in report under \"Ingested Resolved Comments\" |\n| **Requested changes not yet addressed** | Add as HIGH-priority obligation |\n\n### Step 3 — Merge into review pipeline\n\nAll ingested comments become candidate findings or obligations. They follow the\nsame Phase 3-8 pipeline as freshly discovered findings. Ingested findings are\nNOT pre-confirmed — they still require independent reviewer validation per the\nAnti-Self-Review Rule.\n\n**Comment-ledger output:**\n```\n[INGESTED] | source | category | file:line (if applicable) | original_author | status: PENDING_VALIDATION \u002F SKIPPED_OUTDATED \u002F ADVISORY\n```\n\n### Anti-patterns\n- ✗ Ignoring bot reviews because \"bots produce false positives\" — they also catch real issues\n- ✗ Pre-confirming human review comments without independent validation — even senior reviewers make mistakes\n- ✗ Skipping inline review comments and only reading the summary — inline comments contain the evidence\n\n## Phase 0B: Mergeability and Branch-State Intake\n\nBefore investing effort in review lanes, verify the PR is mergeable and record\nbranch-state signals. `PR_REVIEW` remains read-only: do not resolve conflicts,\ncommit, push, rebase, merge, or reset from this mode. Instead, carry current\nmergeability, stale-head, and branch-drift facts into the review ledger and the\nfeedback handoff artifact.\n\n### Step 1 — Check merge state\n\nThe field names and values below are GitHub-specific examples. On another code\nhost, record the equivalent mergeability, conflict, required-check, base-drift,\nand stale-head signals and preserve the same read-only behavior.\n\n```bash\ngh pr view \u003CPR_NUMBER> --json mergeable,mergeStateStatus\n```\n\nThe response has two independent fields. Handle each:\n\n**`mergeable` field** — whether GitHub can compute mergeability:\n| Value | Meaning | Action |\n|-------|---------|--------|\n| `MERGEABLE` | No conflicts detected | Proceed — check `mergeStateStatus` below |\n| `CONFLICTING` | Merge conflicts exist | Record the blocker, keep the review read-only, and hand conflict resolution to `swarm-pr-feedback` |\n| `UNKNOWN` | GitHub still computing | Wait 30s, re-check |\n\n**`mergeStateStatus` field** — overall branch state:\n| Value | Action |\n|-------|--------|\n| `CLEAN` | All checks pass, no conflicts — proceed to Phase 0 |\n| `BEHIND` | Branch behind base — note in report; non-blocking if merge queue handles it |\n| `DIRTY` | Merge conflicts exist — keep reviewing, but record the conflict as a first-class blocker in the ledger and handoff artifact |\n| `BLOCKED` | External blocker (branch protection, failing required check) — investigate and record the blocker |\n\n### Step 2 — Record conflicts and blockers (when CONFLICTING or DIRTY)\n\nWhen the PR has merge conflicts:\n\n1. **Determine the PR's base branch and verify the state**, as separate\n   standalone commands — never with `$(...)` command substitution, which the\n   PR_REVIEW gate blocks:\n   - Read the base ref: `gh pr view \u003CPR_NUMBER> --json baseRefName` (or\n     `gh_evidence` with `target: \"pr\"`, `fields: \"baseRefName\"`).\n   - Fetch it by its literal value, substituted for `\u003Cbase-ref>`:\n     `git fetch origin \u003Cbase-ref>`.\n   - Re-check merge state: `gh pr view \u003CPR_NUMBER> --json\n     mergeable,mergeStateStatus,baseRefName,headRefName`.\n\n2. **Capture the affected scope without changing the branch:**\n   - List the files or subsystems implicated by the conflict if GitHub exposes them,\n     or note that the exact conflict set is still unknown.\n   - Identify whether the conflict appears mechanical (lockfile \u002F generated output \u002F\n     simple overlap) or semantic (logic changed on both sides). This is triage\n     signal for the follow-on feedback run, not permission to resolve it here.\n\n3. **Record explicit next action for the handoff artifact:**\n   - `CONFLICT-### | mechanical | likely resolvable during pr-feedback`\n   - `CONFLICT-### | semantic | requires focused fix + validation during pr-feedback`\n   - `STALE-### | behind base by policy` when the branch is only stale, not conflicted\n\n4. **Document in report:** List the branch-state facts, why they matter to the\n   review, and what `swarm-pr-feedback` must verify before it edits code.\n\n### Conflict resolution anti-patterns\n- ✗ Accepting \"ours\" or \"theirs\" for all conflicts without reading them\n- ✗ Resolving semantic conflicts without understanding both sides\n- ✗ Pushing resolution without running tests on the merged result\n- ✗ Treating `PR_REVIEW` as the place to fix branch state — this mode stays read-only\n\n## Phase 0B-bis: Pre-Handoff Parallel Work Snapshot\n\nWhen the review surfaces findings that will likely need `swarm-pr-feedback`,\nre-check for **parallel work** since the last fetch. The PR author, the bot\nreviewer, or another swarm may have pushed commits while you were reviewing.\nThis is still read-only: capture the remote state so the handoff artifact starts\nfrom the right branch facts.\n\n### Step 1 — Compare remote state (read-only, no post-bind fetch)\n\nOnce the PR head is bound, the gate allows only the exact bound tracking\nfetch (when one is armed), and a detached review HEAD has no tracking branch\nto refetch against — `git fetch origin \u003Cpr-branch>` is blocked here. Compare\nstate through the read-only API instead, as one standalone command:\n\n```bash\ngh pr view \u003CPR_NUMBER> --json headRefOid,commits\n```\n\nor the equivalent `gh_evidence` call with `target: \"pr\"` and\n`fields: \"headRefOid,commits\"`. If the returned `headRefOid` differs from the\n`pr_head_sha` bound at the start of this review, the remote has moved; the\n`commits` field lists every commit's message and author to date, enough to\njudge relevance to the pending findings. (The legitimate place to `git fetch`\nis the pre-bind sequence under \"Pre-flight git ref availability\" above — this\nstep never repeats that fetch post-bind.)\n\n### Step 2 — Evaluate new commits\n\nFor each new commit on the remote (identified by comparing `headRefOid` \u002F\n`commits` above against the SHA bound at the start of the review):\n\n1. **Read the commit message from the `commits` field above.** For file\n   scope, use one standalone read-only call —\n   `gh api repos\u002F{owner}\u002F{repo}\u002Fcommits\u002F\u003Csha>` — rather than a local\n   `git show`: the new commit's object is not fetched locally post-bind.\n2. **Compare against the pending handoff scope:**\n   - Does the remote commit touch the same files as the validated findings?\n   - Does the remote commit appear to already address a finding you planned to\n     hand off?\n   - Does the remote commit introduce a new branch-state fact the handoff should\n     mention?\n3. **Default stance: prefer the remote state as the next baseline.** When the\n   bundled copy is available (plugin runtimes), run the\n   `file:.swarm\u002Fbundled-skills\u002Fparallel-work-check\u002FSKILL.md`\n   protocol for the formal decision template; otherwise apply the three\n   outcomes below directly. Record the outcome in the handoff artifact.\n\n### Step 3 — Three outcomes\n\n- **Parallel work supersedes:** Mark the older local checkout as stale in the\n  handoff artifact and tell `swarm-pr-feedback` to re-check out the current\n  remote head before editing.\n- **Parallel work complements:** Carry both the validated findings and the new\n  remote commits into the handoff artifact so `swarm-pr-feedback` can verify the\n  combined state before patching.\n- **Parallel work unrelated:** Note that the remote moved, but keep the same\n  validated finding set.\n\n### Anti-patterns\n\n- ✗ Pushing your fix without checking if the remote already fixed it — causes\n  duplicate work and may even fail the push if the commits conflict\n- ✗ Force-pushing over parallel work because \"I started this first\" — the\n  parallel agent may have access to context you don't (different swarm\n  configuration, different model, different time budget)\n- ✗ Blindly taking remote work without verifying it's actually better — the\n  parallel work may be incomplete or take a different approach that doesn't\n  match the original finding's intent\n\n### Example: parallel swarm superseded local fix work\n\nSee `references\u002Fparallel-work-example.md` for the worked PARALLEL WORK CHECK\ntranscript (remote supersession, abandon-use-remote decision).\n\n---\n\n# Default Review Workflow\n\n## Phase 0: Context Pack and Review Signal Collection\n\nBefore launching explorers, build a compact `swarm-pr-review-context`. Under\nProfile A, do not create a scratch context-pack file after the controller gate\nactivates: PR_REVIEW intentionally blocks arbitrary writes. Put the bounded\nshared scope, obligations, deterministic signals, and impact hints in\n`common_prompt`, and require every lane to inspect the exact bound diff itself.\nUnder Profiles B\u002FC, keep the context in working notes or a local artifact only\nwhen that runtime permits the write.\n\nThe context pack must include, when available:\n\n```json\n{\n  \"scope\": {\n    \"base_ref\": \"...\",\n    \"head_ref\": \"...\",\n    \"commit_range\": \"...\",\n    \"changed_files\": [],\n    \"changed_hunks\": [],\n    \"public_api_changes\": [],\n    \"deleted_or_renamed_files\": [],\n    \"generated_files\": []\n  },\n  \"pr_metadata\": {\n    \"title\": \"...\",\n    \"body_claims\": [],\n    \"checkboxes\": [],\n    \"linked_issues\": [],\n    \"review_comments\": [],\n    \"commit_messages\": []\n  },\n  \"obligations\": [],\n  \"repo_graph\": {\n    \"source\": \".swarm\u002Frepo-graph.json or fallback search\",\n    \"changed_symbols\": [],\n    \"callers\": [],\n    \"callees\": [],\n    \"imports\": [],\n    \"exports\": [],\n    \"sibling_implementations\": []\n  },\n  \"deterministic_signals\": {\n    \"ci\": [],\n    \"tests\": [],\n    \"coverage_delta\": [],\n    \"lint_typecheck_build\": [],\n    \"security_scanners\": [],\n    \"dependency_audit\": [],\n    \"secrets_scan\": [],\n    \"mutation_testing\": []\n  },\n  \"swarm_artifacts\": {\n    \"evidence_bundles\": [],\n    \"knowledge_hits\": [],\n    \"phase_state\": [],\n    \"metrics\": []\n  },\n  \"risk_triggers\": []\n}\n```\n\n### Context pack rules\n\n- Diff-only review is allowed for quick orientation, but not enough to confirm nontrivial findings.\n- For every changed production file, identify at least one caller, consumer, import path, route entrypoint, or reason none exists.\n- If `.swarm\u002Frepo-graph.json` exists, use it to seed impact cones.\n- If no repo graph exists, build a shallow impact cone using imports, exports, symbol search, route registration, CLI registration, or test references.\n- Pull in relevant `.swarm\u002Fevidence\u002F`, `.swarm\u002Fstate`, `.swarm\u002Fknowledge`, or hive\u002Fproject knowledge entries when present.\n- Historical knowledge may guide candidate generation but cannot confirm a finding by itself.\n- Mark stale, quarantined, or cross-project knowledge as advisory until independently verified in this repo.\n\n---\n\n## Review Finding Persistence\n\nDo not rely on conversation context to preserve review findings. On Profile A,\nuse `write_pr_review_artifact` with `kind: \"findings\"`; the controller creates\nand appends `.swarm\u002Fpr-review\u002F\u003Crun_id>\u002Ffindings.jsonl` without granting generic\nwrite authority over `.swarm\u002F`. On Profiles B\u002FC, append the same records to a\n`findings.jsonl` ledger in your harness workspace (never under `.swarm\u002F`), with\nthe review head SHA recorded at the top.\n\nEach persisted finding record must include at least:\n\n```json\n{\"finding_id\":\"F-001\",\"status\":\"PENDING\",\"file_line\":\"src\u002Ffile.ts:123\",\"evidence\":\"quote, command output, lane id, or reviewer rationale\",\"next_action\":\"route_to_reviewer\",\"severity\":\"HIGH\"}\n```\n\nMinimum field contract:\n\n- `finding_id`: stable ID from the candidate\u002Freviewer\u002Fcritic ledger.\n- `status`: one of `PENDING`, `CONFIRMED`, `DISPROVED`, or `PRE_EXISTING`.\n- `file_line`: exact `file:line`, or `N\u002FA` with reason when cross-file.\n- `evidence`: compact source-backed proof (lane\u002Freviewer\u002Fcritic IDs or command output references when available).\n- `next_action`: `route_to_reviewer`, `route_to_critic`, `report`, `suppress_with_reason`, or `handoff_to_feedback`.\n- `severity`: REQUIRED at every boundary — omitting it is a violation, not a shortcut. Vocabulary is the VERDICT dialect `INFO|LOW|MEDIUM|HIGH|CRITICAL|NONE`. At `post_explorer` it must equal the severity of the `[CANDIDATE]` row the record projects (so never `NONE`, which no candidate row can declare) — except the mechanically derived `CLEAN-REVIEW` sentinel emitted when discovery found nothing, whose severity is `NONE`; at `post_reviewer` the reviewer `final_severity`; at `post_critic` the **critic** `final_severity` for critic-routed records, otherwise the reviewer's (issue #2279).\n\nPersist after every major validation boundary (Profile A via the controller\ncalls below; Profiles B\u002FC by appending the same boundary-tagged records to the\nledger file):\n\n1. **Post-explorer:** persist as soon as the base wave settles and its\n   candidates parse — BEFORE micro dispatch — by calling\n   `write_pr_review_artifact` with `boundary: \"post_explorer\"` and the\n   base-derived candidates as `PENDING` with their lane provenance. This\n   base-only write is the compaction recovery point for everything before\n   trigger evaluation; it must cover exactly the base-derived inventory\n   (micro ids are refused as `extra:` at this point). After trigger\n   evaluation a full-inventory `post_explorer` write (base+micro) is also\n   admissible and supersedes the early checkpoint as the recovery point.\n2. **Post-reviewer:** after Phase 6 reviewer validation, call the controller\n   with `boundary: \"post_reviewer\"` and update each reviewed\n   record to `CONFIRMED`, `DISPROVED`, `PRE_EXISTING`, or keep `PENDING` with a\n   concrete `next_action` if more evidence is required.\n3. **Post-critic:** after Phase 8 critic challenge, call the controller with\n   `boundary: \"post_critic\"` and update final status, the authoritative\n   `severity`, and final reporting or handoff action.\n\n**Enforced order, dispositions, and error reporting (Profile A).** The\ntrigger evaluation must complete before every findings boundary EXCEPT the\nbase-only `post_explorer` write above, which is admissible right after base\nsettlement (issue #2280); beyond that exception checkpoints run strictly\n`post_explorer` → `post_reviewer` → `post_critic`, each requiring the prior\ncheckpoint persisted, and `post_reviewer`\u002F`post_critic` must exactly cover\nthe FULL (base+micro) candidate inventory against the persisted trigger-eval\nartifact; records must match the authoritative reviewer\u002Fcritic\nverdict rows, and an invalid payload is rejected in ONE call listing every\nviolation as `finding_id: field expected \u003Cvalue>, got \u003Cvalue>`. Full contract\n(write order, dispositions, severity authority table, handoff schema):\nreferences\u002Ffindings-persistence-contract.md.\n\nResume\u002Freload procedure: read the latest `findings.jsonl` and reconstruct the\nledger from disk before dispatching more lanes; the base-only `post_explorer`\ncheckpoint alone is enough to resume after a compaction between base\nsettlement and the micro wave (re-dispatch micro, re-run trigger evaluation,\nthen continue with full-inventory boundaries); surface a missing artifact as\na coverage gap, never reclassify from memory; append (latest record wins).\n\n---\n\n## Phase 1: Intent Reconstruction \u002F Obligation Extraction\n\nReconstruct what the PR is obligated to deliver before looking for bugs.\n\nUse deterministic precedence, highest to lowest:\n\n1. PR checkboxes and acceptance criteria,\n2. linked issues \u002F tickets,\n3. explicit user request in the current conversation,\n4. commit scopes and commit messages,\n5. test names and test assertions,\n6. interface diff \u002F exported API changes,\n7. changelog, README, migration, or docs edits,\n8. LLM synthesis only when no higher-precedence source exists.\n\nOutput an obligation list:\n\n```text\nO-001 | source | claim | affected files\u002Fsymbols | status: UNVERIFIED | evidence refs: []\n```\n\nFor each obligation, record:\n\n- source,\n- exact claim,\n- affected files or symbols,\n- verification status: `UNVERIFIED → IN_PROGRESS → MET \u002F PARTIALLY_MET \u002F NOT_MET \u002F UNVERIFIABLE`,\n- linked finding ID when unmet,\n- reason if unverifiable.\n\nTests are claims. A passing or added test does not prove the obligation unless the reviewer inspects the assertion strength and relevant code path.\n\n### Quantitative claim verification\n\nPR body numerical claims (test counts, coverage percentages, assertion counts, performance benchmarks) are obligations, not proof. For each quantitative claim:\n\n1. Extract the claim and its source (PR body, comment, commit message).\n2. Verify against actual tool output or CI artifacts when available.\n3. If the claim cannot be independently verified, mark the obligation `UNVERIFIABLE` with reason.\n4. If the claim is disproved by evidence, create a finding linking the discrepancy.\n\nCommon patterns to verify:\n- \"N tests pass\" → count actual test results from CI logs or test runner output\n- \"N% coverage\" → compare against coverage report\n- \"No regressions\" → verify against test runner failure count\n\n---\n\n## Phase 2: Deterministic Signal Ingestion\n\nIngest deterministic signals as candidate generators. They are never final findings.\n\nUse available local artifacts first. Run safe read-only or standard project validation commands only when appropriate for the environment.\n\nCandidate signal sources include:\n\n- CI failures and logs,\n- test failures,\n- coverage delta,\n- lint\u002Ftypecheck\u002Fbuild output,\n- `git diff --check`,\n- dependency audit output,\n- lockfile diff,\n- CodeQL alerts,\n- Semgrep or SAST findings,\n- secrets scan findings,\n- license scan findings,\n- mutation testing output,\n- package manager warnings,\n- generated schema diffs.\n\nRecord each signal as:\n\n```text\n[TOOL_CANDIDATE] | tool | severity | file:line | claim | raw_signal_summary | confidence\n```\n\nTool candidate rules:\n\n- Confirm reachability before reporting.\n- Confirm PR-introducedness before reporting as a PR blocker.\n- When `placeholder_scan` output is used as a signal, pass `added_lines` (file path → PR-added line numbers from the merge-base diff) so only added lines drive the scan; a placeholder finding on an unchanged line is a pre-existing-debt candidate, not a PR blocker. If added-line mapping is unavailable, treat the findings as unscoped and cross-check them against the PR diff before recording the row.\n- Confirm that a framework, schema, middleware, caller guard, or test isolation rule does not already mitigate it.\n- Do not report scanner output verbatim without reviewer validation.\n- Redact secrets; never paste raw credentials into the final output.\n\n---\n\n## Phase 3: Parallel Base Explorer Lanes\n\n### Review depth tiers (size × risk)\n\nBefore dispatching, classify the PR into a depth tier from the context pack.\nRecord the tier and the active capability profile in the ledger and in the\nfinal validation provenance. The tier scales how many subagents you spawn —\nnever which review dimensions or risk families get evaluated:\n\n| Tier | Diff shape | Dispatch shape (Profiles B\u002FC) |\n|---|---|---|\n| S | ≤ ~100 changed lines, ≤ 5 files, no risk triggers | Consolidate: 1–2 explorer lanes covering all six dimensions (B), or one candidate-generation pass (C); Phase 4 risk families fold into the same lanes as an explicit per-family checklist |\n| M | ≤ ~1500 changed lines, or any risk trigger | Dedicated lanes for the triggered dimensions\u002Ffamilies; consolidate the remaining thin dimensions into 1–2 lanes |\n| L | > ~1500 changed lines, > ~50 files, multi-subsystem, or security-sensitive surface | Full fan-out: one lane per dimension (six) and per-family micro dispatch in Phase 4 |\n\nRisk triggers (any one escalates to at least tier M, and the triggered\ndimension\u002Ffamily always gets a dedicated lane at M and above):\nauth\u002Fidentity\u002Fsessions\u002Fpermissions\u002Fsecrets\u002Fcryptography; untrusted-input\nparsing or new input\u002Foutput boundaries; subprocess\u002Fshell\u002Ffilesystem execution;\nconcurrency, state machines, retries, caching; dependency, lockfile, install,\nCI, or release changes; public API, schema, config, or migration changes;\npayments or PII handling; generated, vendored, or binary artifacts.\n\nScaling is one-directional: a larger tier or an active controller may demand\nmore lanes than the table; nothing — repository size, elapsed time, token\ncost, or predicted simplicity — permits fewer lanes than the classified tier,\nand no tier permits skipping a dimension or family. Under Profile A the\ncontroller computes the tier itself from the bound `base_sha...pr_head_sha`\ndiff (`--numstat` totals; an uncomputable diff fails strict to tier L) and\n mechanically enforces the matching floors on every base and micro batch. When a project explicitly enables the `pr_review_resilience` policy (it is\n DISABLED by default), the initial base wave is\n staged at tiers M\u002FL: `pr_review_wave_stage: \"canary\"` \u002F `pr_review_wave_attempt: 0`\n launches one singleton base lane first, then\n `pr_review_wave_stage: \"fanout\"` carries only the remaining unresolved\n obligations in exactly one follow-up fanout batch. Tier S keeps the legacy single\n consolidated base batch because staged resilience does not apply there. If\n that policy is disabled, the initial base wave falls back to the historical\n non-staged behavior: tier L may launch all six singleton base lanes together\n in one batch, while tiers S\u002FM may use consolidated lanes that declare their\n complete `owned_workflow_lanes` set — every dimension still owned exactly\n once and attested. Micro batches retain the historical tier-L full fan-out\n floor (one micro-lane per family on every micro batch, not only the first),\n while tiers S and M may consolidate families so long as every family is still\n owned exactly once and attested per family. With staged resilience enabled, a\n tier-L base **retry** may consolidate only dimensions that are still\n unresolved because their prior attempts reached a recorded terminal failure\n and no lane for that dimension is currently live or in flight, subject to two\n lane floors: no single lane may own all six dimensions, and — counted\n cumulatively across every recorded base batch, not per batch, and including\n batches the capacity GC has since dropped — the six dimensions must stay\n backed by at least four distinct lanes (each dimension no consolidated lane\n claims counts as one, plus the FEWEST declared consolidated lanes that\n suffice to cover the rest). That permits a small consolidation as failure\n recovery and rejects re-doing the whole wave in two or three lanes, whether\n the attempt is disguised as overlapping or duplicate consolidations —\n declaring more lanes than the cover needs buys no budget. Dimensions with a\n successful source are complete and MUST NOT be re-dispatched; dimensions with\n a live or in-flight source are not yet eligible for the retry set. The retry\n attempt itself still stays exactly one singleton canary call plus exactly one\n unresolved-only fanout call, never multiple fanout batches and never a fresh\n all-six singleton re-dispatch. Risk triggers\nremain caller-side escalation on every profile: dispatch MORE than the floor\nwhenever a trigger warrants it.\n\n### Dispatch\n\nUnder Profile A, dispatch base lanes with `dispatch_lanes_async`, set\n`mode: \"swarm-pr-review:base\"`, assign each lane its exact `workflow_lane`\nidentifier from the table below, bind every batch with the exact current\n`pr_head_sha`, record each returned `batch_id`, and pass the exact reviewed\nmerge base and its base ref as `base_sha` and `base_ref`. Use the\nREMOTE-TRACKING form for `base_ref` (`origin\u002Fmain`, not `main` or\n`refs\u002Fheads\u002Fmain`) and compute `base_sha` against that same ref, so the\ncontroller's recomputation matches yours. When a project explicitly enables the\n`pr_review_resilience` policy (DISABLED by default), tier-M\u002FL initial base dispatch is\n staged exactly as a singleton canary batch (`pr_review_wave_stage: \"canary\"`,\n `pr_review_wave_attempt: 0`) followed by exactly one fanout batch\n(`pr_review_wave_stage: \"fanout\"`) that include only still-unresolved\nobligations. Tier S stays on one consolidated batch. If the policy is\ndisabled, the legacy non-staged initial base wave is still valid: tier L may\npass all six singleton base specs together in one batch, while tiers S\u002FM may\npass the consolidated batch shape that partitions the same six dimensions.\nEvery later base retry, micro, council, reviewer, and critic dispatch repeats\nthose same exact bindings. The controller recomputes\n`git merge-base -- \u003Cbase_ref> \u003Cpr_head_sha>`, rejects mismatches, and replaces\ncaller `scope` text with the complete verified `base_sha...pr_head_sha` PR diff;\ncaller scope is retained only as a non-authoritative focus hint. Continue only non-dependent architect\nwork: refine the obligation ledger, inspect PR metadata, prepare micro-lane\ntrigger checks, and run deterministic read-only local tools. The runtime rejects\npartial, duplicate, mislabelled, or non-explorer base waves. Do not synthesize\nfindings from running lanes. Keep each lane `prompt` compact: send the shared\nreview context (PR diff, obligation ledger, scope) ONCE via the `common_prompt`\nfield, or have lanes read it from a file by absolute path, instead of inlining\nthe same large blob into all six prompts — oversized inline prompts produce\nmalformed or truncated tool-call JSON and force clumsy file workarounds.\n\nAll six dimensions must be covered on every PR — \"small PR\", \"docs-only\", and\n\"CI-only\" change what each dimension examines, never whether it is evaluated.\nEvery dimension ends in its own `[CANDIDATE]` rows or a fully populated\nper-dimension `[CLEAN]` attestation. Under Profile A, the top-level\n`pr_review_resilience` config (DISABLED by default; opt in with `enabled: true`) requires depth tiers M\u002FL to\nstage each base attempt as a singleton `pr_review_wave_stage: \"canary\"` batch\nfollowed by its matching `\"fanout\"` batch. Attempt 0 still has to cover all six\ndimensions exactly once across the combined canary+fanout ownership: tier M\nneeds at least three combined lanes, tier L needs six singleton combined lanes,\nand every later retry attempt may carry forward only the still-unresolved\nobligations into its canary\u002Ffanout pair. Use one singleton canary lane; attempts\nare numbered with `pr_review_wave_attempt`, and the\npolicy permits attempt 0 plus two retry attempts (1 and 2). If the project leaves\n`pr_review_resilience` at its default `enabled: false`, or the computed tier is S,\nProfile A uses the legacy single-wave base dispatch. Under Profiles B\u002FC, the\ndepth tier governs lane count the same way — a tier-S diff may cover the six\ndimensions in one or two consolidated lanes — while dimension coverage and\nper-dimension attestation remain mandatory.\n\nUnder Profile B, dispatch the same wave as parallel subagents through your\nharness's subagent tool: one subagent per dimension by default, consolidated\nper the depth tier for small diffs. Every lane prompt must carry the exact\n`pr_head_sha`, the verified `base_sha...pr_head_sha` range, its assigned\n`workflow_lane` identifier(s), and the explorer context contract below; append\nevery returned report to the findings ledger with its lane id and head SHA\nbefore any reviewer dispatch. Under Profile C, run the same lanes as\nsequential candidate-generation passes with the same per-lane ledger records.\nThe join barrier is universal: all base lanes settle before Phase 4 completes\nor synthesis begins, whichever layer enforces it.\n\n**Incremental collection (Profile A):** While base lanes are running, poll with `collect_lane_results` (without `wait` (or `wait: false`)) to check progress and process settled lanes as they complete — call `retrieve_lane_output` for full text when `output_ref` is present, then extract candidates via `parse_lane_candidates`, update the candidate ledger, validate output quality — while continuing independent architect work (obligation refinement, micro-lane trigger checks, local reads) between polls. Only use `wait: true` if lanes are still pending and no more independent work remains. While polling, a `pending_liveness` entry on a still-pending lane is a DIAGNOSTIC only (issue #2280): `stalledSuspect: true` means the lane has been pending for minutes and the host does not report its session live — note the lane id, `pendingMs`, and `hostStatus` and investigate, but never auto-cancel, retry, or replace the lane on this signal; read `degradedReason` precisely (issue #2815): `probe-skipped-no-budget` means the observer's own probe budget was already exhausted and NO host probe ran — it carries no information about the lane's session — while `probe-timeout` means a probe ran and hit its deadline; either way the ~30-minute presumed-stale sweep remains the only terminal backstop. Under Profile B, harvest each subagent report as it completes and update the ledger between arrivals; block on stragglers only when no independent work remains. **`collect_lane_results` is an OBSERVER (issue #2381).** Its wait budget (`timeout_ms`) bounds THAT CALL ONLY. An expired wait budget does not cancel, kill, or fail a lane, and it is not evidence that a lane died; `timeout_ms: 0` is a valid immediate, non-destructive snapshot, and an unavailable host messages client likewise reports stored lane state without terminalizing anything. Whenever lanes remain unsettled the result carries `pending_lanes` (batch id, lane id, stored status, and `output_ref` when one exists) regardless of `include_pending`, so outstanding work is never silently omitted. When a collection returns pending lanes you have exactly two observer moves: poll again, or let the ~30-minute presumed-stale sweep settle genuinely dead lanes. Explicit cancellation is a separate authorized action (`cancel_lane_batch` with `confirm: true` plus a reason); the collector itself never cancels, and busy\u002Fretry lanes are live evidence, not failure. Do NOT abort the PR workflow, re-dispatch the lane, or report a lane as failed merely because an observer call expired or the host client was briefly unavailable.\n\nInline `output` is delivered on the first poll that observes a lane settled; subsequent polls carry `output_omitted_repeat: true` with metadata and `output_ref`, and full text is retrieved via `retrieve_lane_output`.\n\nHost transport metadata is not stronger than the durable artifact. A truncated inline preview is accepted when its full `output_ref` artifact passes every identity, digest, revision, ownership, and row-coverage check. If the host status call times out, collection treats readiness as unknown and may inspect messages under a separate bounded budget, but it settles the lane only when the latest assistant message carries terminal proof. Only base and micro discovery lanes may retain independently validated positive `[CANDIDATE]` coverage from an incomplete transcript; council, reviewer, and critic outputs remain fail-closed and require retry. Incompleteness can never establish `[CLEAN]`, including for sibling dimensions in a consolidated lane. Every accepted transport recovery is disclosed in `salvaged_workflow_lanes`, with typed per-lane reasons in `salvaged_workflow_lane_recoveries`. See `references\u002Flane-output-recoverability.md`.\n\nBefore Phase 4 or synthesis, all base lanes must be settled. `dispatch_lanes_async` accepts a maximum of 8 lanes per call; base lanes (6) and micro-lanes (Phase 4) are dispatched in separate calls by design. Do not let one lane's conclusions bias another lane.\n\n**COVERAGE GATE — zero tolerance for unclosed gaps.** After `collect_lane_results`, verify every lane produced validated output. Two failure modes exist:\n- **Mode A (empty output):** Lane returns 0 chars, `status: cancelled`, `output_digest` matches SHA-256 of empty string (`e3b0c442...b855`).\n- **Mode B (invalid structured output):** Under Profile A, collection reports `status: failed` with a named contract predicate while retaining the non-empty preview, digest, and `output_ref`; the artifact has zero valid `[CANDIDATE]` rows and no parseable `[CLEAN] | lane | coverage_scope | evidence` attestation. Under Profiles B\u002FC, treat the equivalent non-empty report as failed when parsing yields zero candidates and no valid clean attestation. The non-empty transcript is diagnostic evidence, never coverage proof.\n\nFor ANY lane that failed (either mode):\n1. **Retry** (initial dispatch plus 2 retries — PR_REVIEW_MICRO_FAMILY_RETRY_BUDGET; each micro-family dispatch acknowledgment records one counted attempt in gate state) with materially different parameters — different session or prompt decomposition, while preserving the required structured async mode and exact head provenance.\n2. If a base lane fails under Profile A, retry only the unresolved `workflow_lane` identifiers with `dispatch_lanes_async`, `mode: \"swarm-pr-review:base\"`, the same exact `pr_head_sha`, explorer agents, and the staged-resilience fields when that policy is enabled: a singleton `pr_review_wave_stage: \"canary\"` first, then a matching `\"fanout\"` batch only for the remaining unresolved obligations. The durable gate joins successful provenance across the initial wave and retry batches, carries unresolved obligations forward attempt by attempt, and rejects typed `retry_exhausted` or `circuit_open` outcomes before any new lane is launched. While that controller is active, blocking `dispatch_lanes` and direct Task dispatch are not equivalent because they cannot satisfy the structured provenance gate. Under Profiles B\u002FC, retry only the failed `workflow_lane` identifiers with a fresh subagent or pass, the same exact `pr_head_sha`, and a materially different prompt decomposition.\n3. If no equivalent alternative can be verified AND every launched lane is terminal or explicitly cancelled, **settle N-of-6 truthfully (issue #2383)** instead of discarding validated work: admit the terminal settlement with `write_pr_review_artifact` (`kind: \"findings\"`, `boundary: \"post_explorer\"`, the sentinel `CLEAN-REVIEW` record when no candidates exist, and `partial_base_coverage: { unresolved_dimensions: [\u003Cexactly the dimensions that are not covered>] }`), run the remaining phases over the covered dimensions' findings, and complete with `complete_pr_workflow` carrying the verdict the settlement allows. NEVER fabricate coverage, NEVER present an unresolved dimension as reviewed, and NEVER let a partial report approve.\n4. **Terminal report kinds (issue #2383):** all six dimensions covered → `COMPLETE` (verdict may be APPROVE, REQUEST_CHANGES, or INCOMPLETE); at least one covered → `PARTIAL` (verdict must be REQUEST_CHANGES or INCOMPLETE; validated findings from covered dimensions remain publishable); zero covered → `NO_COVERAGE` (skip the findings ladder entirely, call `complete_pr_workflow` with `report_verdict: \"INCOMPLETE\"` directly — the completion returns a truthful operational report with per-dimension reasons and never claims a code-quality review). A still-live lane blocks settlement: poll again, authorize an explicit `cancel_lane_batch` (`confirm: true` + reason; busy\u002Fretry lanes are refused), or let the presumed-stale sweep settle it first.\n5. Under Profile A, when the bind\u002Fcheckout path itself is genuinely unreachable or the workflow is publication-armed and exact publication cannot proceed, use the bounded recovery exits: `abort_pr_workflow` with `mode: \"PR_REVIEW\"`, `kind: \"recovery\"`, and a non-empty one-line `reason` for an unrecoverable unbound\u002Fbound gate, or `kind: \"armed_recovery\"` (issue #2383) for a publication-armed wedge — then `prepare_pr_workflow_checkout` with `operation: \"restore\"`. Abort remains a recovery tool for the genuinely unrecoverable, never a shortcut past a settleable coverage obligation.\n\n### PARTIAL-settlement recovery (all lanes terminal)\n\nBase settlement requires every launched lane to be TERMINAL — settled, failed,\nor explicitly cancelled — NOT full coverage. With partial coverage (at least one\ndimension covered), the review proceeds instead of aborting: dispatch the FIRST\n`swarm-pr-review:micro` batch with the complete 11-row `trigger_evaluation`\nparameter inline on `dispatch_lanes_async` (that dispatch freezes the canonical\nledger), persist it with `write_pr_review_trigger_eval`, run the validation\nlanes, then finish with `complete_pr_workflow` carrying the verdict PARTIAL\ncoverage allows (REQUEST_CHANGES or INCOMPLETE — never APPROVE). The\nNO_COVERAGE short-circuit applies only at zero coverage. A\n`write_pr_review_trigger_eval` rejection saying the canonical ledger is missing\nmeans the first micro dispatch has not frozen it yet — supply the inline\nparameter; it is not a deadlock.\n\n### Contract-failure diagnosis and recovery\n\nUnder Profile A, `dispatch_lanes_async` adds the authoritative\ncontroller-appended row contract and exact lane identity to every explorer\nprompt. Do not duplicate that contract in `common_prompt`: duplicated copies\ncan drift, compete for prompt budget, and are not the controller's acceptance\nboundary.\n\nWhen collection or a later coverage gate rejects a lane, first isolate the\nemitting validator named by the diagnostic. Preserve the rejected artifact and\nbuild a minimal correct single-lane reproduction using the same workflow mode,\nlane identity, exact head, and canonical row. Before retrying, distinguish the\nthree independent input layers: the header schema, data-row values, and tool\nargument shape. A correct header does not repair an invalid severity or lane\nvalue, and correct row data does not repair malformed dispatch JSON. Benign shape defects (evidence pipes, marker rows, verdict-row pipes, a header re-emitted as a data row) are auto-repaired and recorded as salvage — never a retry reason alone; the `parse_lane_candidates` receipt discloses them as `repair_kinds`, and a `[CLEAN]` attestation discredited beside a same-lane `[CANDIDATE]` row as `clean_attestation_salvaged` + `clean_attestation_salvage_reason` (the parse SUCCEEDS and the attestation still supplies no coverage) (contract and fidelity boundaries: `references\u002Flane-output-recoverability.md`).\n\nClassify incidents from actual user-visible harm and the first failed predicate; the shared\nrow parser proves row structure only, a post-hoc fallback is recovery evidence, and the\ngate separately verifies durable provenance (see `references\u002Flane-output-recoverability.md`).\n\nIf a controller denial omits the failed predicate, expected contract, or lane\nidentity, record that as an opacity defect and escalate it with the preserved\nartifact and minimal reproduction. An opaque denial is not proof that correct\ninput was rejected. Do not guess at hidden predicates, weaken acceptance, or\nswitch to blocking\u002Fdirect-Task dispatch; repair the named contract when it is\navailable, otherwise stop at the coverage gate with the diagnostic gap.\n\n### Candidate extraction via parser\n\nUnder Profile A, after `collect_lane_results` returns for base lanes, process\neach lane result that carries an `output_ref`. The orchestrator MUST use the\ncandidate parser rather than preview-text extraction:\n\n1. For each singleton base `output_ref`, call `parse_lane_candidates` with\n   `output_ref`, `producer: \"swarm-pr-review\"`,\n   `expected_family: \"base_explorer\"`, and `expected_lane` set to the exact\n   `workflow_lane` declared at dispatch. For a consolidated tier-S\u002FM lane, call\n   the parser once for each owned dimension with that dimension as\n   `expected_lane` and pass `expected_lanes` as the lane's complete\n   `owned_workflow_lanes` array on every call. The parser reads the full artifact\n   from disk (no preview truncation issue), rejects unowned rows, and returns\n   structured `ParseResultWithSidecar` records.\n2. Filter the returned `candidates[]` by `producer: \"swarm-pr-review\"` plus the\n   exact `source_batch_id` and `source_lane_id` from the base dispatch. Treat a\n   family mismatch or parse error as a lane-output failure; family metadata is\n   not the acceptance boundary.\n3. Group the filtered candidates into reviewer-sized chunks:\n   - by file area (group by the directory or module of the `file_line` field),\n   - by category (group by the `category` field),\n   - by count (target max 50 candidates per chunk; smaller chunks are fine).\n4. Stage reviewer-sized chunks, but do not dispatch reviewers yet. Phase 4 must\n   complete trigger accounting and settle every launched micro-lane first.\n\nIf a lane has `output_degraded: true`, no usable `output_ref`, or `transcript_incomplete: true` without typed positive-candidate recovery, apply the COVERAGE GATE (Phase 3). An incomplete base or micro discovery lane may proceed only when it is explicitly named by a `salvaged_workflow_lane_recoveries` entry whose `kind` is `transcript-incomplete-terminal-candidate`; that recovery validates the retained positive `[CANDIDATE]` row only. Council, reviewer, and critic lanes never qualify for this incomplete-transcript recovery and must retry. Recovery never validates `[CLEAN]`, candidate absence, an unowned sibling lane, or an incomplete lane with no matching entry. Do not use blocking or direct-Task fallbacks while the controller is active, mark affected candidates UNVERIFIED to proceed, or infer candidate absence from a preview. Under Profiles B\u002FC, which have no typed recovery validation, a truncated, incomplete, empty, or attestation-free subagent report is the same lane-output failure and takes the same COVERAGE GATE.\n\nAfter candidate parsing and before reviewer dispatch, persist the post-explorer\ncandidate ledger. The base-only write is admissible immediately after base\nsettlement — it is the durable recovery point for context compaction from base\nsettlement onward; once trigger evaluation completes, a full-inventory\n(base+micro) `post_explorer` write may refresh it ahead of Phase 6.\n\n**Profiles B\u002FC row convention:** without the parser, the `[CANDIDATE]` row\nformat is the extraction contract itself. Explorers emit the rows directly in\ntheir reports (see the Explorer Prompt Template reference); the orchestrator\ncollects them verbatim, validates each row's field count and lane id, and\ntreats malformed rows — or output with neither `[CANDIDATE]` rows nor a fully\npopulated `[CLEAN]` attestation — as a lane-output failure under the COVERAGE\nGATE. If the parser is unavailable under Profile A, the same row convention\napplies as a fallback, but the orchestrator SHOULD use the parser as the\nprimary extraction mechanism.\n\n**lane id uniqueness for parallel dispatches:** When re-dispatching failed or\nre-running explorer lanes, every `dispatch_lanes_async` or `dispatch_lanes`\nlane `id` MUST be unique within that dispatch batch and should include lane and\nattempt suffixes (e.g., `pr_review_explore_lane1_attempt2`). Never reuse an id\nin the same batch unless intentionally replacing that exact lane before dispatch.\n\nExplorers optimize for recall. Over-reporting is expected. Explorers produce candidates only.\n\nThe six dimensions are a fixed **check-type** partition, not an area\npartition: every PR needs all six review dimensions, and the lanes\ndeliberately overlap by file, each receiving the same diff (via\n`common_prompt` under Profile A) and viewing it through a different lens. Six\ndimensions are this workflow's high-assurance coverage floor, not a claim that\nresearch proves a universal optimal agent count — the published evidence\nfavors complementary, distinct-lens reviewers over duplicated generalists, and\nfinding rates rise with diff size, which is why dispatch (not coverage)\nfollows the depth tier. Repository policy may add scrutiny but may never\nreduce the six dimensions. Coverage is guaranteed by all six dimensions\nreading the whole diff, so the disjoint-partition rule that governs area-split\nfan-outs does not apply.\n\n| `workflow_lane` | Focus | Required checks |\n|---|---|---|\n| `intent-architecture` | Intent, scope, architecture, and integration | obligation mapping, design fit, callers\u002Fconsumers, sibling patterns, docs and claimed-vs-actual behavior |\n| `correctness-state` | Functional correctness, data\u002Fstate flow, edge cases, and failure paths | input domains, nullability, ordering, transactions, error behavior, rollback, backwards behavior |\n| `tests-falsifiability` | Tests, test validity, regressions, and claimed validation | assertion strength, negative paths, isolation, fixtures, deterministic timing, missing proof |\n| `security-trust` | Security, privacy, trust boundaries, unsafe inputs\u002Fsinks, and supply chain | authorization, injection, secrets, provenance, dependency risk, data exposure, abuse paths |\n| `reliability-performance` | Reliability, concurrency, retries, resource bounds, and performance | races, retry semantics, timeouts, lifecycle, caching, algorithmic cost, operational failure modes |\n| `compatibility-delivery` | API\u002Fschema\u002Fconfig compatibility, maintainability, build\u002Fdeploy, docs, and release behavior | public contracts, migrations, runtime\u002Fplatform support, packaging, CI, rollout and recovery guidance |\n\n### Explorer context contract\n\nEvery explorer must inspect or explicitly mark unavailable:\n\n1. the changed hunk,\n2. at least one caller, consumer, or downstream impact-cone node,\n3. at least one callee, dependency, or upstream assumption,\n4. at least one sibling implementation or prior pattern,\n5. the nearest relevant test or missing-test location,\n6. deterministic signal entries mapped to its files\u002Fsymbols,\n7. relevant Swarm knowledge\u002Fevidence entries, if present.\n8. the exact bound review range to analyze (`base_sha...pr_head_sha`),\n\n### Explorer output format\n\nExplorers emit structured candidate records. The parser reads the full lane\nartifact and extracts these records. The canonical record shape is:\n\nThe fence below is documentation formatting only. Emit the header and all\nmachine-readable rows as unfenced plain text; do not emit the backticks.\n\n```text\n[CANDIDATE] | candidate_id | lane | severity | category | file:line | claim | evidence_summary | impact_context | confidence | risk_impact | risk_tags\n```\n\nProfile A now treats `submit_pr_review_result` as the authoritative settlement path for base and micro discovery lanes. The caller-bound structured receipt dominates later prose, truncation, or transcript incompleteness. Transcript candidate\u002Fclean rows remain deprecated compatibility only when `pr_review_legacy_transcript_compatibility` was explicitly enabled for that lane and no structured receipt exists; a present-but-invalid structured result fails closed and never falls back.\n\nWhen compatibility mode is active, Profile A stores the full assistant transcript. The parser locates the first pipe-delimited line whose first field is exactly `[CANDIDATE]`, ignores unmarked preamble, and requires the exact canonical base\u002Fmicro header; malformed markers or marker-prefixed rows without a header fail closed. The controller refuses a missing marker. Markerless positional fallback remains only for legacy callers outside that trust boundary; explorers should put the canonical header first.\n\nThe confidence data value must be exactly LOW, MEDIUM, or HIGH.\n\nUnder Profile A the parser-backed transcript path is compatibility-only; a successful `submit_pr_review_result` receipt is authoritative. On Profiles B\u002FC — and on a Profile A lane whose snapped contract explicitly enables deprecated legacy transcript compatibility and lacks a structured receipt — the explorer emits `[CANDIDATE]` rows directly as the extraction contract.\n\nExplorers must not use `CONFIRMED`, `DISPROVED`, or `PRE_EXISTING`.\n\nA base lane that finds no surviving candidates must submit exactly one structured CLEAN result and then stop. Only a lane in the deprecated transcript-compatibility path may instead emit exactly one fully populated clean row:\n\nThe fence below is documentation formatting only. Emit the clean attestation\nas unfenced plain text; do not emit the backticks.\n\n```text\n[CLEAN] | lane | coverage_scope | evidence\n```\n\nHeader-only `[CLEAN]` markers, prose-only \"clean\" claims, or empty output do\nnot settle the lane.\n\n---\n\n## Phase 4: Mandatory Repository-Agnostic Micro-Lanes\n\nAfter base lanes settle, inspect the exact diff\u002Fcontext pack to focus every row\nin the micro-lane map and print a mandatory ledger with one row per map row:\n\n```text\n[TRIGGER-EVAL] | trigger_row | MATCHED\u002FNOT_TRIGGERED | focus_evidence\n```\n\nFocus evidence must name the changed files, manifests, imports\u002Fsymbols, semantic\nsignals, or explicit absence conditions. Use `MATCHED` when the exact diff has\nan applicable surface and dispatch that family; use `NOT_TRIGGERED` only when\nthe row was evaluated and concrete absence evidence proves it inapplicable.\n`unclassified-risk` is the always-`MATCHED` fallback. A `NOT_TRIGGERED` row is\nnot a waiver or a micro artifact and carries no source batch\u002Flane provenance.\nRepository identity, technology stack, PR size, elapsed time, or predicted risk\nnever justifies skipping a row.\n\nEvery row in the map is a risk **family** that must be evaluated against the\ndiff on every PR, in every repository. What scales with the depth tier is the\ndispatch shape — how many subagents carry that evaluation — never the\nevaluation itself. Each `MATCHED` family must end in its own attestation:\n`[CANDIDATE]` rows naming the family, or one fully populated per-family\n`[CLEAN]` row. `NOT_TRIGGERED` families end in the ledger with absence evidence\nand must not be dispatched.\n\n**Profile A dispatch.** Launch the micro coverage with\n`dispatch_lanes_async` and `mode: \"swarm-pr-review:micro\"`. At depth tier L,\ndispatch one focused micro-lane for every `MATCHED` row, each lane's\n`workflow_lane` equal to its trigger ID; because the dispatcher accepts at\nmost eight lanes per call, split large matched sets across bounded async\nbatches. At tiers S and M,\nconsolidated lanes may each own several families: set `workflow_lane` to one\nowned trigger ID and declare the complete `owned_workflow_lanes` set — every\nmatched family owned exactly once across the dispatch, and every owned family\nattested in that lane's output, or the lane fails for all of them. Include\nthe complete exact-set\n`trigger_evaluation` ledger and the same exact current `pr_head_sha` in the\ninitial micro dispatch, in a separate batch from base lanes (those inline `trigger_evaluation` rows carry only `trigger_id`, `result`, and `evidence` — they must never include `source_batch_id` or `source_lane_id`, which belong only to `write_pr_review_trigger_eval`'s `rows`). That first\ndispatch freezes the ledger for the session. A subsequent same-session micro\nbatch may omit `trigger_evaluation` and reuse the frozen ledger; when it\nexplicitly supplies a copy, the copy must remain exactly identical. The\nruntime rejects unrelated or duplicate micro-lanes within a batch, and final\nledger persistence rejects any row whose completed owning-lane provenance is\nabsent. One bounded exception (issue #2835): a sweep-settled liveness-terminal lane may back a `MATCHED` row as a disclosed dead family (never APPROVEable; cancellations never qualify) — conditions in `references\u002Flane-output-recoverability.md`.\nPoll incrementally, then settle every launched lane. Persist\nthe complete ledger with `write_pr_review_trigger_eval`; its rows use the stable\ntrigger IDs below. Every `MATCHED` row includes its returned `source_batch_id`\nand `source_lane_id`; every `NOT_TRIGGERED` row must omit both fields. Missing,\nextra, duplicate, malformed, or incorrectly provenanced rows make persistence\nfail and Phase 4 BLOCKED. Evidence is frozen by the first micro dispatch and is\nauthoritative thereafter. The final writer may omit its duplicate `evidence`\nfields; if it includes reworded evidence, the writer ignores that copy and\npersists the frozen values. It still requires the exact frozen classifications,\nplus provenance for every `MATCHED` row. The tool atomically writes\n`.swarm\u002Fpr-review\u002F\u003Crun_id>\u002Ftrigger-eval.json`, separate from `findings.jsonl`;\npass the exact reviewed merge-base as `base_sha`, the exact live base branch\ntip\u002Fref used to compute it as `base_ref`, and the same `pr_head_sha` to the\nwriter. The writer runs bounded `git merge-base -- \u003Cbase_ref> \u003Cpr_head_sha>` and\nrejects any claimed `base_sha` that is not the exact result. When that bounded re-check is unavailable (git timeout, spawn failure, unresolvable ref) but the supplied `base_ref` and `base_sha` exactly equal the durably bound review scope, the writer proceeds and discloses `base_verification: bound_fallback` on the receipt, which synthesis must surface in the final review report (`references\u002Flane-output-recoverability.md`); every other outcome stays fail-closed. It accepts only an\nexact eleven-row v2 receipt backed by verifiable provenance (identity, ownership, digest, retained artifact); a coverage-QUALITY failure is disclosed on the receipt as `coverage_degradations` and the run proceeds, with synthesis disclosing degraded families — unless the family is receipt-settled, in which case it is recorded as `receipt_covered_families` (never a degradation) and synthesis discloses it as receipt-covered (`references\u002Flane-output-recoverability.md`). `NOT_TRIGGERED` rows are provenance-free. Counts are recomputed and\nmust agree. It never uses keyword or path classification alone as absence\nevidence. Any head mismatch makes persistence fail. Historical unversioned and\nschema-v1 all-`MATCHED` receipts remain readable, but new writes are strict v2.\nDo not add trigger results to the finding-status enum.\n\n**Profiles B\u002FC dispatch.** Scale the lane shape to the depth tier while\nkeeping all eleven family evaluations:\n\n- Tier L: one focused lane per `MATCHED` family, mirroring Profile A.\n- Tier M: dispatch the `MATCHED` families across at least the controller's\n  matched-set consolidation floor; `NOT_TRIGGERED` rows remain ledger-only.\n- Tier S: dispatch the `MATCHED` set in one or more consolidated micro lanes or\n  sequentially separated passes; keep `NOT_TRIGGERED` rows ledger-only.\n\nWhatever the dispatch shape: the ledger keeps one `[TRIGGER-EVAL]` row per\nfamily; each `MATCHED` row's focus evidence names the lane or pass that\nevaluated it and gets its own `[CANDIDATE]`\u002F`[CLEAN]` attestation naming the\nfamily id; each `NOT_TRIGGERED` row records absence evidence without an\nartifact; and the completed ledger is persisted as `trigger-eval.json` in the\nsession\u002Ftask workspace before reviewer dispatch. A matched family with no\nattestation row is an unclosed coverage gap.\n\nFor each micro lane in Profile A, prefer the single structured\n`submit_pr_review_result` receipt over transcript parsing. Only for a lane\nwhose snapped contract explicitly enables deprecated transcript compatibility\nand lacks a structured receipt should you fall back to `parse_lane_candidates` against its `output_ref`, with\n`producer: \"swarm-pr-review\"`, `expected_family: \"micro_lane\"`, and\n`expected_micro_lane` set to the launch-micro-lane value from the\nprovenance-linked trigger row. When the artifact came from a consolidated\ntier-S\u002FM lane (its dispatch declared more than one `owned_workflow_lanes`\nentry), also pass `expected_micro_lanes` set to that lane's complete\n`owned_workflow_lanes` array — the same set already declared at micro\ndispatch time. Without it, the parser has no way to tell a sibling owned\nfamily's row from a genuinely out-of-scope one: every row belonging to the\nlane's other owned families is treated as a parse error instead of being\nskipped as out-of-scope, which can also invalidate that lane's own otherwise-valid\n`[CLEAN]` attestation for the family being extracted. Omit `expected_micro_lanes`\nonly for a singleton (tier-L) lane. Accept a candidate only when its `producer`,\n`source_batch_id`, and `source_lane_id` match an allow-listed tuple from the\noriginal or retry micro dispatch and its `micro_lane` matches that trigger row;\nnever filter acceptance by `row_format_family`. A zero-candidate artifact is\nclean only when the parser returns exactly one provenance-matching persisted\n`clean_attestation` whose `micro_lane` matches the trigger row, zero parse\nerrors, zero malformed rows, and a complete, non-degraded source:\n\n```text\n[CLEAN] | micro_lane | coverage_scope | evidence\n```\n\nHeader-only or malformed zero output is `UNATTESTED`; apply the COVERAGE GATE (Phase 3). Under Profile A, the structured async PR-workflow path must preserve `L1`, exact-head, batch, and workflow-lane provenance; the active controller rejects blocking and direct-Task substitutes, and Task-derived findings or CLEAN prose cannot satisfy Phase 4's controller ledger unless the lane explicitly runs deprecated transcript compatibility. Under Profiles B\u002FC, acceptance is the row contract: accept a candidate or clean row only when its `micro_lane` matches the trigger row, and treat prose-only \"clean\" claims as `UNATTESTED`.\n\nEach micro-lane receives:\n\n- exact files and hunks in scope,\n- related obligations,\n- impact cone entries,\n- relevant deterministic signals,\n- related historical knowledge with quarantine\u002Fstaleness status,\n- expected invariants,\n- structured candidate output — parser-extracted under Profile A; on Profiles\n  B\u002FC the micro-lane emits `[CANDIDATE]`\u002F`[CLEAN]` rows directly as the\n  extraction contract.\n\n### Repository-agnostic mandatory micro-lane map\n\nEvery row is evaluated in every repository. Diff\u002Fcontext analysis determines\nwhether it is `MATCHED` or `NOT_TRIGGERED`; paths or keywords alone are not\nsufficient absence evidence. Repository policy\nmay require supplementary specialist review outside this canonical ledger, but\nsupplementary work never replaces these portable rows. The `unclassified-risk`\nfamily is always `MATCHED` to cover novel failure modes and classification gaps.\n\n> **Trigger-ID namespace — do not mix (issue #1931).** The `trigger_id` field\n> passed to `write_pr_review_trigger_eval` accepts **only** the 11 micro-lane\n> IDs in the table below. Three different namespaces appear in this skill and\n> they are NOT interchangeable:\n>\n> | Namespace | Example values | Used where? | Valid as `trigger_id`? |\n> | --- | --- | --- | --- |\n> | Micro-lane IDs (this table) | `auth-identity-secrets`, `untrusted-input-boundaries`, ... | `workflow_lane` of `swarm-pr-review:micro` dispatch; `trigger_id` of trigger-eval rows | **YES — only these** |\n> | Base-lane IDs | `intent-architecture`, `correctness-state`, `tests-falsifiability`, `security-trust`, `reliability-performance`, `compatibility-delivery` | `workflow_lane` of `swarm-pr-review:base` dispatch; validated by `enforcePrReviewBaseDimensions` | NO |\n> | Dispatch modes | `swarm-pr-review:base`, `swarm-pr-review:micro`, `swarm-pr-review:reviewer`, `swarm-pr-review:critic` | `mode` field of `dispatch_lanes_async` | NO |\n>\n> The writer rejects unknown trigger IDs with the list of valid IDs. Short\n> informal names (`correctness`, `security`, `deps`, `docs`, `tests`, `perf`)\n> sometimes appear in prose summaries; they are shorthand, not literal IDs.\n\n| Trigger ID | Scope | Trigger in diff or context pack | Launch micro-lane | Invariants to check |\n|---|---|---|---|---|\n| `auth-identity-secrets` | universal | authentication, authorization, identity, sessions, permissions, secrets, cryptography | Identity and secret boundaries | least privilege, confused-deputy paths, credential lifecycle, cryptographic misuse, safe defaults |\n| `untrusted-input-boundaries` | universal | parsing, serialization, queries, templates\u002Frendering, file or network input\u002Foutput | Untrusted input and sink analysis | injection, traversal, SSRF, unsafe deserialization, output escaping, resource limits |\n| `subprocess-platform` | universal | subprocesses, shell commands, filesystem operations, OS\u002Fruntime-specific code | Subprocess and platform safety | array argv, bounded execution, path containment, portability, cleanup, non-interactive behavior |\n| `concurrency-state` | universal | queues, caches, retries, transactions, locks, state machines, async coordination | Concurrency and state transitions | races, atomicity, idempotency, retry accounting, rollback, stale state, bounded growth |\n| `dependencies-build-release` | universal | dependency manifests, lockfiles, installers, build scripts, CI, packaging, deployment | Dependency and delivery integrity | provenance, version\u002Flock consistency, install safety, platform matrices, rollback and release completeness |\n| `api-schema-migrations` | universal | public API, wire\u002Fschema\u002Fconfig\u002Fstorage formats, migrations, feature flags | Compatibility and migration safety | backward\u002Fforward compatibility, defaults, validation, mixed-version operation, recovery |\n| `test-infrastructure` | universal | tests, mocks, fixtures, harnesses, coverage, CI matrices | Test validity and isolation | meaningful assertions, contamination, determinism, negative paths, cross-platform proof, test theater |\n| `ui-accessibility-i18n` | universal | user interfaces, interaction flows, rendering, accessibility, localization | UI and human-interface quality | keyboard\u002Fscreen-reader behavior, focus, error states, responsive behavior, locale-safe formatting |\n| `privacy-observability` | universal | telemetry, logs, analytics, traces, retention, diagnostics | Privacy and observability safety | minimization, redaction, consent, retention, stable metrics, non-gameable evidence |\n| `generated-provenance` | universal | generated, vendored, binary, model-produced, codegen or checked-in build artifacts | Generated artifact provenance | reproducibility, source linkage, tamper evidence, reviewable diffs, licensing and stale output |\n| `unclassified-risk` | universal | any changed artifact or behavior not confidently classified by the rows above | Unclassified high-risk fallback | full change-path review, hidden trust boundaries, novel failure modes, missing specialist classification |\n\nMicro-lane output format:\n\nThe fence below is documentation formatting only. Emit the header and all\nmachine-readable rows as unfenced plain text; do not emit the backticks.\n\n```text\n[CANDIDATE] | candidate_id | micro_lane | severity | category | file:line | claim | invariant_violated | evidence_summary | confidence | risk_impact | risk_tags\n[CLEAN] | micro_lane | coverage_scope | evidence\n```\n\n---\n\n## Phase 5: Swarm-Native Verifier Routing\n\nUse Swarm-native agents and artifacts when available. If exact agent names are unavailable, route the same task to the closest equivalent reviewer\u002Fcritic role. On harnesses without the plugin, most `.swarm\u002F` artifacts will not exist: mark those rows N\u002FA in the validation provenance rather than fabricating them.\n\n| Swarm verifier \u002F artifact | When to use | Purpose |\n|---|---|---|\n| `critic_drift_verifier` | obligation-vs-code, docs-vs-code, phase\u002Fgate changes, schema\u002Fconfig changes | detect drift between stated behavior and actual implementation |\n| `critic_hallucination_verifier` | external APIs, package claims, URLs, CLI flags, GitHub behavior, model\u002Ftool names | verify claims against source or mark as unverified |\n| `curator_phase` | before exploration and after synthesis | retrieve relevant lessons; write back confirmed true positives \u002F false positives |\n| `test_engineer` | confirmed\u002Fborderline correctness, security, state, schema, or config findings | propose or run falsification probes and regression tests |\n| `.swarm\u002Frepo-graph.json` | all nontrivial code changes | build impact cones and sibling-pattern checks |\n| `.swarm\u002Fevidence\u002F` | schema, phase, state, council, and guardrail changes | verify evidence compatibility and serialized provenance |\n| Tool-returned `.swarm\u002Fevidence\u002F` artifacts | after synthesis | record review quality only at paths actually returned by invoked evidence tools; never invent a metrics path |\n\nVerifier output is advisory until incorporated by the independent reviewer or critic.\n\n---\n\n## Phase 6: Independent Reviewer Confirmation\n\n**Reviewer-dispatch join barrier:** reviewer dispatch MUST NOT begin until the\nexact eleven-row micro-lane ledger is complete and persisted, every launched\n`MATCHED` micro lane is settled with its owned families attested or disclosed as a dead family on the trigger receipt (#2835), every\n`NOT_TRIGGERED` row has concrete absence evidence and no provenance, and every\naccepted micro result has parser-derived provenance (Profile A) or a valid\nCLEAN attestation.\n\nRoute candidates to reviewer subagents. The orchestrator routes candidates\nin bounded chunks produced by the candidate extraction in Phase 3-4. Each\nreviewer lane receives a bounded list of candidates from a single chunk — by\nfile area, category, or count — not the full candidate set. The reviewer must\nre-read the candidate's file:line evidence and relevant context pack entries\ndirectly.\n\nA reviewer or critic chunk may own any non-empty subset of the current\ninventory. On a retry, that subset may overlap prior successful work; the lane\ncontract is the assigned item set for that chunk, not a requirement to re-own\nthe full inventory every time.\n\nUnder Profile A, dispatch reviewer chunks with `dispatch_lanes_async`,\n`mode: \"swarm-pr-review:reviewer\"`, a unique non-empty `workflow_lane` per\nchunk, `review_item_ids` containing the exact candidate IDs assigned to that\nchunk, reviewer-role agents only, and the same exact `pr_head_sha`. The runtime\nrequires one parseable `[REVIEWED]` row for every structurally assigned ID; a\nsingle marker or partial subset cannot settle the lane. Direct Task\nreviewers are rejected by the active controller because they cannot carry the\ndurable batch and head provenance it requires. Under Profile B, dispatch each\nchunk to a fresh reviewer subagent — never the agent or conversation that\ngenerated the candidates — carrying the chunk's candidate IDs, the exact\n`pr_head_sha`, and the required checks below. Under Profile C, run a separate\nreviewer pass per chunk that re-reads every cited file:line before\nclassifying. The one-parseable-`[REVIEWED]`-row-per-assigned-ID contract is\nuniversal.\n\nUnder Profile A, for every structured PR-review dispatch, the runtime appends\nan authoritative controller block after caller-authored prompt text. It binds the exact\n`workflow_lane`, PR head, content revision, declared scope, and assigned item\nIDs and explicitly forbids speed\u002Ftime\u002Ftoken waivers. Caller prompt text cannot\noverride that block; output with placeholders, invented IDs, generic assurances,\nor evidence unrelated to the bound lane does not settle the artifact.\n\nReviewer ownership is not accepted as an architect assertion. Under Profile A,\nthe controller derives the immutable candidate inventory from the\nintegrity-checked base, mandatory micro-lane, and council artifacts; under\nProfiles B\u002FC, the orchestrator derives the same inventory from the persisted\nledgers. Either way, successful reviewer batches compose item by item: the\nunion of their accepted `review_item_ids` must equal that inventory exactly,\nwith the newest successful verdict winning for each item. If discovery produces\nno candidates,\nthe derived sentinel is `CLEAN-REVIEW`, which still requires one independent\nsemantic reviewer row (a fresh subagent on Profile B; a separate reviewer pass\non Profile C).\n\nCandidate IDs must therefore be globally unique across every discovery\nartifact in the run. Prefix IDs with the stable workflow-lane ID (or use\nanother deterministic globally unique scheme); duplicate IDs fail closed\ninstead of being silently merged.\n\n### Noise budget and universal validation\n\nBefore reviewer dispatch, the orchestrator may suppress candidates that match ANY of the following (each suppression still requires mandatory disclosure):\n- purely stylistic without correctness, security, test, maintainability, or user-impact implications,\n- exact duplicates of a candidate already queued for validation,\n- explorer-stated confidence=LOW with zero structural evidence (no file:line, no code path, no invariant reference).\n\nEvery suppressed candidate must appear in the final report under \"Suppressed Candidates\" with the reason. Suppression without disclosure is a hard rule violation.\n\n**All remaining candidates — regardless of severity — must be routed to independent reviewer validation.** Severity alone does not determine validation eligibility; it determines routing priority. A LOW-severity candidate with file:line evidence and a specific code path gets the same reviewer attention as a HIGH-severity candidate.\n\nCandidates not routed to reviewers must be listed as UNVERIFIED with reason in the validation provenance. Do not silently drop them.\n\n### Reviewer required checks\n\nFor each candidate, the reviewer must determine:\n\n- exact file:line evidence,\n- whether the issue is introduced by this PR or pre-existing,\n- reachability from realistic execution paths,\n- whether caller guards, schema validation, middleware, framework defaults, feature flags, or state-machine constraints mitigate it,\n- whether tests cover the negative path,\n- whether sibling files or docs must change together,\n- whether the severity is justified,\n- the smallest falsification probe that would prove or disprove it.\n\n### Reviewer classifications\n\n| Classification | Meaning |\n|---|---|\n| `CONFIRMED` | Evidence is real, reachable or structurally proven, and introduced or exposed by this PR |\n| `DISPROVED` | Candidate claim is incorrect, unreachable, mitigated, or based on a misunderstanding |\n| `UNVERIFIED` | Available evidence is insufficient to determine validity |\n| `PRE_EXISTING` | Issue exists on the base branch and is not materially worsened by this PR |\n\n### Evidence classifications\n\n| Type | Definition |\n|---|---|\n| `STRUCTURALLY_PROVEN` | File:line evidence directly demonstrates the bug or violated invariant |\n| `EXECUTION_PROVEN` | A test, trace, reproduction, or command demonstrates failure |\n| `STATIC_TRACE_PROVEN` | Static analysis plus reviewed path\u002Fcontext demonstrates reachability |\n| `PLAUSIBLE_BUT_UNVERIFIED` | Pattern suggests risk, but reachability or mitigation is unresolved |\n\nReviewer output format:\n\n```text\n[REVIEWED] | item_id | classification | evidence_type | severity | introduced_by_pr | file:line | rationale | probe | reviewer_notes | risk_impact | risk_tags\n```\n\nCLEAN-REVIEW sentinel and DISPROVED\u002FPRE_EXISTING row details: see\n`references\u002Fparser-dry-run.md`.\n\nEvery reviewer response must end with one parseable `[REVIEWED]` row per\nassigned candidate. A malformed `[REVIEWED]` row is not a verdict: re-dispatch\nwith the exact contract (max 2), then mark the reviewer dimension BLOCKED if no\nvalid row returns.\n\nAfter reviewer lanes settle, persist the post-reviewer finding ledger before\ncritic routing or synthesis. The artifact must preserve `CONFIRMED`,\n`DISPROVED`, `PRE_EXISTING`, and still-`PENDING` records with reviewer IDs and\nnext actions.\n\nCounterbalanced reviewer passes (#2906): when the candidate inventory holds more\nthan one item, dispatch the reviewer phase as two batches over the same inventory;\nthe controller alternates presentation order A (canonical) \u002F B (reversed), stamps\n`presentation_order` on each batch receipt, and marks each merged verdict\n`order_agreement` (agree\u002Fdisagree\u002Fsingle); unstable items are auto-flagged to the\ncritic and the report marks and counts them. Detail: references\u002Fcounterbalancing.md.\n\n---\n\n## Phase 7: Falsification Probe Requirement\n\nEach confirmed nontrivial finding must include at least one falsification artifact:\n\n- runnable failing command,\n- proposed regression test,\n- mutation that current tests fail to kill,\n- static-analysis trace,\n- minimal execution path,\n- exact reason no runtime probe is available.\n\nNontrivial means any finding that affects correctness, security, state transitions, write authority, git safety, config, schema\u002Fevidence integrity, model\u002Ftool permissions, external fetches, persistence, or user-visible behavior.\n\nA finding may still be reported without a runnable command if it is structurally proven, but the report must state why a runtime probe was not available.\n\n---\n\n## Phase 8: Critic Challenge\n\nRoute reviewer-confirmed CRITICAL and HIGH findings to a critic always. Route a MEDIUM finding only when its typed risk metadata says so (issue #2383): `risk_impact: \"HIGH_IMPACT\"`, or any `risk_tags` entry (`SECURITY`, `AUTH_PERMISSIONS`, `STATE_INTEGRITY`, `WRITE_PATH`, `EVIDENCE_INTEGRITY`, `GIT`, `CONFIGURATION`). An ordinary MEDIUM (`risk_impact: \"ORDINARY\"`, no tags) is NOT critic-routed. `risk_impact: \"UNKNOWN\"` always routes to critic — never guess impact you could not assess, and never let file paths, dimension names, or prose override the typed `risk_impact`\u002F`risk_tags` the reviewer row carries.\n\nThe controller derives critic ownership from the typed reviewer rows through the one shared production predicate; every newly written CONFIRMED finding must supply `risk_impact` and `risk_tags` (the write boundary rejects a CONFIRMED record without them, and unknown tag values fail the row). Completion is blocked until that exact derived inventory has valid critic rows — unless an admitted N-of-M verdict settlement (issue #3101) discloses a liveness-dead critic lane, whose receipt-backed CRITIC_UNAVAILABLE rows count as terminal settlements.\n\nReviewer and critic settlement MUST compose successful verdicts item by item\nacross complementary partial batches. The newest successful claim wins each\nitem; malformed or stale batches contribute nothing without erasing healthy\nsibling claims. Collection MUST validate exact lane ownership atomically, and\ncritic claims MUST bind to the exact reviewer row for their item. Settlement is\nitem completeness, not lane completeness. Follow the full retry, legacy,\nbinding, and diagnostic contract in\n[`references\u002Fverdict-settlement-contract.md`](references\u002Fverdict-settlement-contract.md).\n\nUnder Profile A, dispatch critic chunks with `dispatch_lanes_async`,\n`mode: \"swarm-pr-review:critic\"`, a unique non-empty `workflow_lane` per\nchunk, `review_item_ids` containing the exact finding IDs assigned to that\nchunk, critic-role agents only, and the same exact `pr_head_sha`. The runtime\nrequires one parseable `[CRITIC]` row for every structurally assigned ID and\nrequires the reviewer phase to have settled — every item in the current\ninventory holding a successful reviewer verdict, composed across batches —\nbefore a critic wave.\nUnder Profile B, dispatch each critic chunk to a fresh subagent that was\nneither the explorer nor the reviewer for those findings; under Profile C, run\na separate critic pass. The one-parseable-`[CRITIC]`-row-per-assigned-ID\ncontract and the reviewer-before-critic ordering are universal.\n\nThe critic must challenge:\n\n- severity inflation,\n- weak or incomplete evidence,\n- missing mitigating context,\n- false reachability assumptions,\n- framework or middleware defaults,\n- schema validation gates,\n- state-machine constraints,\n- feature flags or dead code,\n- pre-existing status,\n- non-actionable or unsafe fix recommendations,\n- sibling-file gaps,\n- whether multiple comments should be grouped into one root cause.\n\nCritic output format:\n\n```text\n[CRITIC] | item_id | status | severity | rationale | required_change\n```\n\n## Verdict row contract\n\nThe `[CRITIC]` row in the format above is **mandatory contract**, not advisory output. A critic response that does not end with that exact row format is treated as a planning preamble, not a verdict, and must be re-dispatched. Do not proceed past Phase 8 join barrier until each dispatched critic lane has produced a parseable `[CRITIC]` row.\n\n**Re-dispatch trigger:** when a critic lane response is missing the verdict row, the orchestrator must automatically re-dispatch that lane with the explicit instruction: \"Your final line MUST be exactly the Phase 8 contract row: `[CRITIC] | item_id | status | severity | rationale | required_change`. Use only enum values from `references\u002Ffindings-persistence-contract.md`. A response without that exact row will be treated as a planning message and re-dispatched.\" Do not synthesize findings from the planning preamble; only from the re-dispatched verdict.\n\n`NEEDS_MORE_EVIDENCE` is deliberately non-terminal and never satisfies critic\nsettlement. Re-dispatch a narrower critic\u002Fprobe lane or report the dimension\nBLOCKED. Terminal critic rows are cross-field checked: `DISPROVED` requires\n`NONE`, `UPHELD` requires CRITICAL\u002FHIGH\u002FMEDIUM, and `DOWNGRADED` cannot remain\nCRITICAL.\n\n**COVERAGE GATE alignment:** Critic lane failures apply the COVERAGE GATE (Phase 3) — under Profile A via `dispatch_lanes_async` with `mode: \"swarm-pr-review:critic\"` and the same exact `pr_head_sha`; under Profiles B\u002FC via a fresh critic subagent or pass. Do NOT mark findings UNVERIFIED or continue past the gap. The orchestrator NEVER fabricates a critic verdict by parsing prose, by tolerating a planning preamble, by presenting partial findings as complete beyond the truthful N-of-6 settlement, or by silently accepting reduced coverage.\n\nRefuted findings become `DISPROVED` or `ADVISORY`, depending on critic rationale. Downgrades must be listed in the final validation provenance.\n\nAfter critic lanes settle, persist the post-critic finding ledger before final\nsynthesis. This artifact is the source of truth for resumed reporting and for\nany later `swarm-pr-feedback` handoff.\n\n---\n\n## Runtime-Aware False-Positive Guard Checklist\n\nBefore confirming any finding, the reviewer and critic must check all that apply:\n\n- [ ] Schema validation gate: does schema validation reject malformed input before the flagged line?\n- [ ] Middleware interception: does middleware handle the request or command before the flagged path?\n- [ ] Framework default mitigation: does the framework inherently prevent this class of issue?\n- [ ] Caller context correctness: who invokes this code, and can untrusted input reach it?\n- [ ] Execution reachability: is the path reachable, or behind a feature flag, dead branch, build-only path, or commented-out code?\n- [ ] State-machine constraints: do ordering rules, locks, mutexes, phase gates, or transition guards prevent the state?\n- [ ] Permission boundary: does role\u002Ftool mapping prevent the operation?\n- [ ] Data lifetime: is the flagged state persisted, serialized, logged, or only transient?\n- [ ] Cross-platform behavior: does Windows\u002FmacOS\u002FLinux path or shell behavior change the result?\n- [ ] Test environment mismatch: is the finding only true under a mock or fixture that cannot occur in production?\n\nIf a mitigation applies and was not accounted for, downgrade to `ADVISORY`, `UNVERIFIED`, or `DISPROVED`.\n\n---\n\n## Phase 9: Synthesis, Grouping, and Noise Budget\n\nBefore final output:\n\n- group duplicate candidates by root cause,\n- report one finding per root cause,\n- attach all affected file:line references under that finding,\n- separate ship blockers from advisory notes,\n- suppress pure style\u002Fnit findings unless they indicate correctness, security, test, maintainability, or user-impact risk,\n- distinguish PR-introduced from pre-existing,\n- distinguish confirmed from plausible-but-unverified,\n- include disproved agent\u002Ftool claims,\n- keep final comments actionable.\n\n### Finding ID format\n\n```text\nF-001 | severity | category | root cause | affected file:line refs | reviewer | critic status\n```\n\n### Suggested final grouping\n\n1. Ship blockers,\n2. Important non-blockers,\n3. Test \u002F coverage gaps,\n4. Pre-existing issues,\n5. Unverified plausible risks,\n6. Disproved candidates \u002F false positives,\n7. Clean lane summary.\n\n---\n\n## Phase 10: Metrics and Knowledge Writeback\n\nAt the end of the review, include review quality metrics in the final report's\nvalidation provenance. Persist them only through an invoked evidence tool and\nrecord the exact `.swarm\u002Fevidence\u002F` path returned by that tool; if no invoked\ntool supports metrics (including all of Profiles B\u002FC), state `NOT PERSISTED —\nno metrics evidence writer` and keep the metrics block in the final report and\nsession ledger rather than naming a nonexistent command or path.\n\nRecord:\n\n- raw candidates by base lane,\n- raw candidates by micro-lane,\n- deterministic tool candidates,\n- reviewer-confirmed findings,\n- reviewer-disproved findings,\n- reviewer-unverified findings,\n- critic-upheld findings,\n- critic-downgraded findings,\n- critic-disproved findings,\n- final reported findings,\n- suppressed non-actionable candidates,\n- recurring false-positive patterns,\n- commands or probes used,\n- token\u002Ftime cost if available,\n- accepted\u002Ffixed findings when known.\n\nKnowledge writeback rules:\n\n- Write back only validated true positives or validated false-positive patterns.\n- Include file patterns, invariant, evidence, and why it was confirmed\u002Fdisproved.\n- Mark repo-specific lessons as project-tier unless there is strong evidence they generalize.\n- Never promote quarantined or unvalidated knowledge to hive-tier.\n- Never store secrets, private tokens, or raw sensitive logs.\n\n---\n\n## Phase 11: Post-Fix Re-verification\n\nWhen the PR author pushes fixes after a review, perform a targeted re-verification before updating the verdict.\n\n### Re-verification scope\n\nOnly re-verify findings the author claims to have fixed. Do not re-run the full review pipeline.\n\n### Re-verification steps\n\n1. For each finding the author claims fixed:\n   a. Read the changed file(s) from the updated branch at the specific lines referenced in the original finding.\n   b. Verify the fix addresses the root cause, not just the symptom.\n   c. Check that the fix does not introduce a new issue in the same area.\n2. Run CI checks on the updated branch to confirm no regressions.\n3. For findings the author did not address, carry forward the original finding with unchanged status.\n\n### Re-verification output\n\n```\n[REVERIFIED] | finding_id | FIXED \u002F PARTIALLY_FIXED \u002F NOT_FIXED \u002F NEW_ISSUE | evidence | updated_severity\n```\n\n- `FIXED`: the root cause is resolved and no new issue introduced.\n- `PARTIALLY_FIXED`: the root cause is partially addressed or a residual concern remains.\n- `NOT_FIXED`: the root cause persists unchanged.\n- `NEW_ISSUE`: the fix introduced a new problem at the same location.\n\nUpdate the verdict only after re-verifying all previously blocking findings.\n\n---\n\nFor the full parser-based candidate extraction dry-run example, read `references\u002Fparser-dry-run.md`.\n\n---\n\n# Council Mode Workflow\n\nCouncil mode is opt-in only and adversarial.\n\nWhen triggered:\n\n1. Build the same context pack as default mode.\n2. After the default base-dimension and risk-family coverage is complete, launch all supplementary council agents. Under Profile A, use one `dispatch_lanes_async` call with `mode: \"swarm-pr-review:council\"`, the same exact `pr_head_sha`, and one unique `workflow_lane` per council member; continue independent context preparation while they run, polling with `collect_lane_results` (without `wait`) to process settled agents incrementally, and use `wait: true` only when no independent work remains. All agents must be settled and their candidates added to the ledger before reviewer classification; under Profile A the runtime enforces this join barrier, and blocking, sequential, or direct-Task fallback is not equivalent to the structured council dispatch — bypassing the active controller is `BLOCKED`. Under Profile B, dispatch council members as parallel subagents with the same marker contract and settle them all before reviewer classification; under Profile C, run each council lens as a separate sequential pass.\n3. Each council agent assumes all work is wrong until code evidence proves otherwise.\n4. Each agent hunts within its lane only.\n5. Council uses the micro-lane row family: `[CANDIDATE] | candidate_id | micro_lane | severity | category | file:line | claim | invariant_violated | evidence_summary | confidence | risk_impact | risk_tags`. Emit one row per `EVIDENCE_FOUND` or `SUSPICIOUS` claim, or a fully populated `[CLEAN] | micro_lane | coverage_scope | evidence` row when no candidate survives. Put the exact council `workflow_lane` value in the `micro_lane` data field. Council prose without one of those markers does not settle the lane.\n6. Agents must not return `CONFIRMED`, `DISPROVED`, or final severity; candidate severity remains provisional until reviewer classification.\n7. The independent reviewer then classifies every council candidate as `CONFIRMED`, `DISPROVED`, `UNVERIFIED`, or `PRE_EXISTING`.\n8. Apply critic challenge to reviewer-confirmed HIGH\u002FCRITICAL or borderline findings.\n9. Final synthesis distinguishes real blockers, real low-severity issues, accepted caveats, disproved council claims, and follow-up quality work.\n\nDefault council lanes:\n\n- correctness and edge cases,\n- security and trust boundaries,\n- dependency and deployment safety,\n- docs and intent-vs-actual,\n- tests and falsifiability,\n- performance and architecture when risk justifies it.\n\nCouncil prompt requirements:\n\n- branch and commit range,\n- context pack summary,\n- files owned by that lane,\n- relevant impact cone,\n- explicit checklist,\n- strict output cap,\n- `EVIDENCE_FOUND \u002F SUSPICIOUS \u002F CLEAN` only,\n- file:line evidence required for `EVIDENCE_FOUND`.\n\nCouncil findings are supplementary, not authoritative overrides. Do not adopt council severities or claims without independent validation.\n\n---\n\n# Merge Recommendation Table\n\n| Verdict | Condition | `report_verdict` |\n|---|---|---|\n| `APPROVE` | zero unresolved CRITICAL findings, zero unresolved HIGH findings, all blocking obligations MET, no required validation phase failed | `APPROVE` -> APPROVE |\n| `APPROVE_WITH_NOTES` | zero unresolved CRITICAL findings, HIGH findings are downgraded\u002Fadvisory only, obligations MET or explicitly non-blocking | `APPROVE_WITH_NOTES` -> APPROVE |\n| `REQUEST_CHANGES` | any unresolved HIGH finding, any NOT_MET blocking obligation, multiple MEDIUM findings with the same root cause, or validation\u002Fprobe evidence indicates user-impacting risk | `REQUEST_CHANGES` -> REQUEST_CHANGES |\n| `BLOCK` | any unresolved CRITICAL finding, unsafe write\u002Fgit\u002Fsecurity issue, evidence integrity break, role\u002Ftool permission bypass, or config ratchet violation that can disable required protections | `BLOCK` -> REQUEST_CHANGES |\n| `INCOMPLETE` | machine-only terminal - forced under NO_COVERAGE, permitted under PARTIAL or COMPLETE (issue #2383) | `INCOMPLETE` -> INCOMPLETE |\n\n---\n\n# Hard Rules\n\n0. Quality-over-speed: Validation completeness and correctness are the sole criteria for an acceptable review. Time, token count, and agent dispatch count are irrelevant. Do not trade validation breadth or depth for speed.\n\n1. Never APPROVE with unresolved CRITICAL findings.\n2. Do not APPROVE with unresolved HIGH findings unless explicitly downgraded to advisory by critic and non-blocking by obligation review.\n3. Every confirmed finding must have file:line evidence and validation provenance.\n4. A confirmed nontrivial finding must include a falsification probe or an explicit reason no probe is available.\n5. Explorers, council agents, and deterministic tools produce candidates only.\n6. The default workflow orchestrator must not confirm or disprove explorer candidates.\n7. Tool output is not proof. Scanner results must be validated for reachability, PR-introducedness, and mitigation context.\n8. PR text, generated summaries, tests, and comments are claims, not proof.\n9. Do not invent facts not supported by the diff, repo context, tool output, or cited external source.\n10. Do not silently drop disproved or downgraded claims; summarize them in validation provenance.\n11. Obligation precedence is deterministic. Do not skip higher-precedence sources to fill gaps with LLM synthesis.\n12. Do not leak secrets from logs, evidence bundles, config files, URLs, or scanner output.\n13. Do not recommend destructive git or filesystem actions as fixes unless they are clearly scoped, safe, and necessary.\n14. If subagents fail, timeout, or return malformed output, retry with corrected parameters (the initial attempt plus up to 2 retries — aborting after only the first retry is one bounded retry early) through the dispatch mechanism of the active profile — Profile A: the same structured `dispatch_lanes_async` workflow mode and exact `pr_head_sha`, where blocking or direct-Task dispatch cannot preserve the durable provenance contract and is not an equivalent fallback; Profiles B\u002FC: a fresh subagent or pass bound to the same exact `pr_head_sha`. If retries fail, the affected coverage dimension is BLOCKED and must be surfaced to the user before synthesis — except that a micro family whose every lane is liveness-terminal with no retained artifact settles through the disclosed dead-family path on the trigger receipt (issue #2835; the micro-family dispatch ledger enforces the retry budget mechanically — three recorded dispatch attempts before the admission stops failing closed) instead of BLOCKED, and abort is legitimate only after that settlement path has been exhausted or is unavailable. Do not fabricate validation results, do not present partial findings as complete or beyond the truthful N-of-6 settlement (issue #2383), and do not silently mark candidates UNVERIFIED to proceed past the gap.\n\n15. If context pack, repo graph, deterministic signals, or Swarm artifacts are unavailable, retry with alternative access paths. If a source that should exist on the active profile is still unavailable after retry, the affected coverage dimension is BLOCKED and must be surfaced to the user. A source that cannot exist on the active profile (for example `.swarm\u002F` artifacts outside Profile A) is marked N\u002FA in the validation provenance instead — N\u002FA is disclosure, never a waiver of the dimensions and families that must still be covered. Do not proceed to synthesis with unclosed coverage gaps under a \"best available evidence\" rationale — the architect is not authorized to produce a degraded review that hides a coverage gap; the disclosed N-of-6 PARTIAL\u002FNO_COVERAGE settlement (issue #2383) is the only sanctioned partial exit.\n\n---\n\n# Pre-Synthesis Gate — Mandatory\n\nBefore writing the final output, print this checklist with filled values. Every blank field means the final output is invalid.\n\n```text\n[VALIDATION] scope selected: ___\n[VALIDATION] capability profile (A\u002FB\u002FC) and depth tier (S\u002FM\u002FL): ___ \u002F ___\n[VALIDATION] context pack built: YES\u002FNO — ___\n[VALIDATION] obligation count: ___\n[VALIDATION] repo graph \u002F impact cone source: ___\n[VALIDATION] deterministic signals ingested: ___\n[VALIDATION] lane dispatch mechanism: controller \u002F native subagents \u002F sequential passes — ___\n[VALIDATION] terminal coverage: COMPLETE (6\u002F6) OR PARTIAL (___\u002F6 + unresolved dimensions settled) OR NO_COVERAGE (0\u002F6) (issue #2383; lanes dispatched: ___)\n[VALIDATION] base explorer lanes returned: ___ \u002F ___\n[VALIDATION] micro risk families evaluated and attested: ___ \u002F 11 OR BLOCKED — \u003Cmissing rows> (micro lanes dispatched: ___)\n[VALIDATION] Swarm verifier routing used: ___\n[VALIDATION] raw candidates: ___\n[VALIDATION] tool candidates: ___\n[VALIDATION] reviewer lanes dispatched: ___\n[VALIDATION] reviewer lanes returned with parseable `[REVIEWED]` rows: ___ \u002F ___\n[VALIDATION] findings confirmed by reviewer: ___\n[VALIDATION] findings rejected by reviewer as false positive: ___\n[VALIDATION] findings marked PRE_EXISTING: ___\n[VALIDATION] findings left UNVERIFIED: ___\n[VALIDATION] findings escalated to critic: ___\n[VALIDATION] critic dispatched: ___ OR \"SKIPPED — no typed critic-routed finding (CRITICAL\u002FHIGH, MEDIUM+HIGH_IMPACT, MEDIUM+risk_tags, or UNKNOWN)\"\n[VALIDATION] critic returned: ___ OR \"N\u002FA\"\n[VALIDATION] findings upheld by critic: ___\n[VALIDATION] findings downgraded by critic: ___\n[VALIDATION] findings disproved by critic: ___\n[VALIDATION] falsification probes included: ___\n[VALIDATION] grouped root-cause findings: ___\n[VALIDATION] metrics \u002F knowledge writeback: ___\n[VALIDATION] all explorers verified to diff against PR branch, not HEAD: YES\u002FNO\n[VALIDATION] noise-filter suppressed candidates: ___ (count, each with reason in final report)\n[VALIDATION] all non-suppressed candidates routed to reviewer: YES\u002FNO\n```\n\nIf any reviewer lane lacks a parseable `[REVIEWED]` row after bounded\nre-dispatch, the reviewer dimension is BLOCKED. Do not infer or silently\ndowngrade a verdict.\n\n**COVERAGE GATE CONDITION:** If ANY validation dimension shows incomplete coverage that was not settled through the truthful N-of-6 terminal settlement (issue #2383) — lanes that failed and were not closed by retry or verified equivalent alternative, CI that did not run, tools that were unavailable after retry — the Pre-Synthesis Gate FAILS — apply the COVERAGE GATE (Phase 3). Do not proceed to final output. Surface unclosed gaps with exact failing dimensions and retry\u002Fequivalence evidence.\n\n---\n\n# Final Output Format\n\nProduce the final review in this order:\n\n## PR intent\n\nSummarize the obligations and user-visible intent.\n\n## Implementation summary\n\nSummarize what changed, including major files, public APIs, schemas, configs, tests, and Swarm artifacts.\n\n## Intended vs actual mapping\n\n| Obligation | Source | Actual evidence | Status | Linked finding |\n|---|---|---|---|---|\n\nUse `MET`, `PARTIALLY_MET`, `NOT_MET`, or `UNVERIFIABLE`.\n\n## Validation provenance\n\nInclude:\n\n- context pack limitations,\n- explorer lanes launched and returned,\n- micro-lanes triggered,\n- deterministic signals ingested,\n- reviewer identity \u002F role for each finding,\n- critic result for each escalated finding,\n- findings DISPROVED by reviewer with reason,\n- findings DOWNGRADED by critic with reason,\n- findings left UNVERIFIED with reason.\n\nIf zero findings, explicitly state:\n\n```text\nNo confirmed findings — all validated lanes CLEAN.\n```\n\nThen provide a lane-by-lane clean summary.\n\n## Confirmed findings\n\nFor each finding:\n\n```text\nF-001 — Severity — Category — Root cause\nFiles: path:line, path:line\nStatus: CONFIRMED \u002F critic status\nEvidence type: STRUCTURALLY_PROVEN \u002F EXECUTION_PROVEN \u002F STATIC_TRACE_PROVEN\nWhy it matters:\nValidation:\nFalsification probe:\nSuggested fix:\n```\n\n## Pre-existing findings\n\nList separately from PR-introduced findings.\n\n## Unverified but plausible risks\n\nOnly include if useful and clearly labeled as unverified.\n\n## Test \u002F coverage gaps\n\nFocus on missing tests that would catch real risks, not generic coverage requests.\n\n## Disproved candidates and false positives\n\nList concise reasons for notable false positives from explorers, tools, council agents, or reviewers.\n\n## Verdict\n\nUse one display verdict; the value after `->` is its exact `complete_pr_workflow`\n`report_verdict` (#2494 vocabulary bridge; severity\u002Faction policy owned by #2491):\n\n- `APPROVE` -> APPROVE\n- `APPROVE_WITH_NOTES` -> APPROVE (notes stay in the report body)\n- `REQUEST_CHANGES` -> REQUEST_CHANGES\n- `BLOCK` -> REQUEST_CHANGES\n\n## Merge recommendation\n\nExplain the recommendation in one short paragraph and list required actions before merge if applicable.\n\n## Feedback handoff\n\nWhen the review produced actionable validated findings or operational blockers,\ncall `write_pr_review_artifact` with `kind: \"handoff\"` (Profile A). The controller writes\n`.swarm\u002Fpr-review\u002F\u003Crun_id>\u002Ffeedback-handoff.json` only when its finding IDs\nexactly match the latest confirmed `handoff_to_feedback` records. On Profiles\nB\u002FC, write the same handoff content to the session\u002Ftask workspace path\ndescribed in \"Handoff To PR Feedback\" and reference that path in the\ncontinuation prompt. Include:\n\n- the handoff artifact path,\n- the preserved finding IDs and provenance that `swarm-pr-feedback` must carry\n  forward,\n- and an explicit question asking whether to continue into\n  `swarm-pr-feedback`.\n\nUse this exact continuation prompt format, substituting the exact path from\nwhichever profile applies (`.swarm\u002Fpr-review\u002F\u003Crun_id>\u002Ffeedback-handoff.json`\nunder Profile A, or the session\u002Ftask workspace path under Profiles B\u002FC — never\nmix the two):\n\n```text\n\u002Fswarm pr-feedback \u003CPR_URL> continue from \u003Chandoff_artifact_path>\n```\n\nWriting the validated handoff durably records one consent offer bound to the exact workflow instance, handoff digest, PR head\u002FURL, and actionable finding set; the first exact continuation confirms it and transitions modes. Internal creation never auto-routes, and malformed, non-actionable, or detached records cannot start PR_FEEDBACK.\n\n---\n\nFor reviewer, critic, and explorer prompt templates, read `references\u002Fprompt-templates.md`.\n\nUnder Profile A, after metrics and durable review artifacts are complete, but\nbefore emitting the user-facing final report, call `complete_pr_workflow` with\nmode `PR_REVIEW`, the same exact\n`pr_head_sha`, and the terminal `report_verdict` the coverage kind allows (issue #2383). The tool refuses to clear the session gate while required base,\ntrigger, declared reviewer\u002Fcritic, or open-lane obligations remain incomplete.\nWhile the gate remains active, the runtime prepends a workflow-active banner\nto the first substantive text part of each architect message (the model's text\nis preserved below the banner; later parts of the same message, and blank\nparts, are left untouched) and re-wakes an idle parent session. A\nuser interruption pauses every automatic wake path until a later explicit user\nturn settles; the durable gate remains available to continue or abort. Only\nemit the final report after the completion tool confirms that the gate cleared.\nIf it reports `checkout_restore_required`, call\n`prepare_pr_workflow_checkout` with `operation: \"restore\"` before returning to\nthe user. When `checkout_restore_receipts` lists multiple entries, one restore\ncall reapplies all receipts that share the recorded destination; an optional\nlisted `stash_oid` is an exact inventory assertion, not a selector that leaves\nthe other receipts pending. Successfully applied stashes remain in Git as\nexplicit safety backups and are listed in `retained_stash_oids`; the controller\nnever drops a mutable `stash@{n}` selector. Restoration is\nconservative: a dirty\u002Fconflicted checkout, mixed destinations, another active\nPR session, a missing stash, or an invalid recovery receipt returns a\nmanual-recovery diagnostic without resetting or dropping preserved state.\nLegacy receipts derive the exact original commit from the stash and restore a\nuniquely matching local branch when one exists (otherwise detached).\n\nUnder Profiles B\u002FC, no mechanical response gate exists: the Pre-Synthesis Gate\nchecklist is the completion gate. Emit the final report only after every line\nis filled, every dimension and family attested, and every BLOCKED item surfaced.\n\n## Aborting an unrecoverable review (Profile A)\n\nThe mechanical gate can leave the session stuck if the PR head cannot be\nfetched or checked out — for example when a compound `git fetch … && git\ncheckout …` is repeatedly rejected as read-only shell syntax (the runtime\nrequires each git intake command to be a single standalone command), when\nthe PR ref is missing, or when the working tree is on the wrong branch and\nthe merge-base bind can never verify. In that state the response gate\nsuspends further auto-resumes for either of two independent reasons: a\nsmall number of consecutive unproductive wakes (the durable gate `revision`\ndid not advance), or the total wake ceiling being reached (tier-scaled\ndefaults S=12 \u002F M=54 \u002F L=102, overridable via the `totalWakeCeiling`\noption, and in-memory\u002Fper-process so the count resets on plugin reload and\nwhen the durable gate clears — but NOT across the PR_REVIEW → PR_FEEDBACK\nhandoff, which keeps accumulating). Either suspension appends a\n`pr_workflow_wake_suspended` record to `.swarm\u002Fevents.jsonl` naming the\nreason, both counters, the tier, and the ceiling in force — read that first\nwhen diagnosing why a review stopped resuming. Either way, the only exits\nare:\n\n1. **Diagnose and retry the canonical standalone sequence.** Run\n   `git fetch origin refs\u002Fpull\u002F\u003CN>\u002Fhead`, verify with\n   `git rev-parse --verify \u003Cfull_pr_head_sha>^0` and\n   `git cat-file -t \u003Cfull_pr_head_sha>` (which must print `commit`), then run\n   `git switch --detach \u003Cfull_pr_head_sha>`. Do not use `--track FETCH_HEAD`.\n   Confirm `git rev-parse HEAD` equals the authoritative PR head, then recompute the exact\n   merge base with `git merge-base -- \u003Cbase_ref> \u003Cpr_head_sha>` (single\n   command) and retry the `swarm-pr-review:base` dispatch with the exact\n   `pr_head_sha`, `base_sha`, and `base_ref`.\n2. **Call `abort_pr_workflow`** with `mode: \"PR_REVIEW\"`, `kind: \"recovery\"`,\n   and a one-line `reason` describing the blocker. The tool clears the durable gate state\n   and stops the auto-resume loop. It refuses only while PR workflow lanes are still LIVE (a recent `updatedAt`); collect those with `collect_lane_results` first.\n   Lanes idle past the 30-minute staleness horizon settle as presumed-stale instead of blocking, disclosed as `presumed_stale_lanes` on the response and in `.swarm\u002Fevents.jsonl`; a schema-invalid (but JSON-parseable) gate state no longer defeats abort either. See `references\u002Flane-output-recoverability.md`.\n   It accepts both unbound and bound PR_REVIEW workflows so an unrecoverable bind\u002Fcheckout blocker cannot strand the gate. Settled discovery or validation\n   lanes with incomplete coverage use the truthful N-of-6 settlement path instead\n   of aborting. An audit event is appended to `.swarm\u002Fevents.jsonl`. After a legitimate abort the run's validated findings stay exportable: call\n   `export_pr_review_partial_results` (`run_id` + `pr_head_sha`) for a partial, non-authoritative salvage artifact — never a submission, never consent.\n   When the tool reports `checkout_restore_required`, immediately call `prepare_pr_workflow_checkout` with `operation: \"restore\"`; do not leave the\n   user detached from their original checkout with a hidden preserved stash.\n3. **Ask the user to run `\u002Fswarm abort-pr-workflow`** (a human-only\n   restricted command; the agent cannot invoke it via `swarm_command`).\n   This is the recovery path when the wake budget has suspended and the\n   architect cannot make further tool progress.\n\nA second, unrelated stranding class is **trigger-ledger drift**. This is not a\nfetch\u002Fcheckout problem: it means a later micro-lane explicitly supplied a\n`trigger_evaluation` that disagrees with the canonical ledger frozen by the\nfirst micro dispatch. A same-session retry may instead omit that argument and\nreuse the frozen ledger. When a later dispatch does supply a copy, the run\nfails closed in two places, with different strictness — at ledger bind time\n`bindPrReviewTriggerLedger` rejects a trigger_evaluation whose frozen-row digest\n(`trigger_id`, `result`, and `evidence` together) differs from the first\ndispatch's, and at receipt finalize time `write_pr_review_trigger_eval` rejects\nrows whose per-family `result` (classification) differs from the frozen ledger.\nThe finalize gate is deliberately narrower than the bind gate: evidence may be\nomitted or reworded at the receipt, but classifications must still agree. If a\nlater dispatch genuinely cannot converge with the frozen ledger, the exits are\nthe abort paths listed above (`abort_pr_workflow` or `\u002Fswarm abort-pr-workflow`),\nor re-dispatching the disagreeing lane so its trigger_evaluation converges with\nthe frozen ledger before re-binding.\n\nAbort is a recovery tool, not a coverage shortcut. Use it only when the\nbind\u002Fcheckout path is genuinely unreachable; never use it to skip a coverage\nobligation that is still recoverable, merely expensive, or inconvenient. When\nlanes have settled short of full coverage, the terminal N-of-6 settlement (issue\n#2383) is the truthful exit — not abort. For a publication-armed workflow whose exact\npublication cannot proceed, `abort_pr_workflow` with `kind: \"armed_recovery\"`\n(plus the armed recovery identity fields from `pr_workflow_status`) is the\naudited escape: it settles lanes, invalidates the staged publication\nauthorization, preserves validated work, and leaves a recoverable terminal\nstate; exact approved publication via `complete_pr_workflow` remains available\nand preferred whenever it can proceed.\n\nOn Profiles B\u002FC there is no durable gate or auto-resume loop to clear: if the\nhead bind is genuinely unreachable or bounded lane recovery is exhausted,\nreport the blocker to the user and stop.\n\n## Contract addendum (2026-10-12)\n\n- **Candidate rows are defect claims only.** Never emit verification notes,\n  confirmations, or coverage observations as CANDIDATE rows, and no\n  INFO-severity candidates — confirmations belong in the lane's\n  attestation\u002FCLEAN row. A misattributed or confirmatory candidate inflates\n  reviewer adjudication for zero signal.\n","# \u002Fswarm-pr-review\n\nRun a structured, high-confidence PR review that maximizes valid findings without flooding the user with unvalidated noise.\n\n## Graph-first evidence contract\n\nAfter binding the exact diff, use `repo_map` `diff_context` and `impact_cone`; add `route_trace` and `data_trace` for changes that cross trust or data boundaries. Graph evidence is advisory only. If freshness is stale or inconclusive, confidence is low, source is missing, the language is unsupported\u002Fdynamic, the graph is absent, or an action fails, inspect the direct source, Git diff, and searches before validating a finding.\n\nThe review ladder is:\n\n**Scope → obligations → context pack → deterministic signals → parallel explorers → repository-agnostic risk-family coverage (dispatch scaled by depth tier) → independent reviewer validation → critic challenge → grouped synthesis → metrics \u002F knowledge writeback.**\n\n## Handoff To PR Feedback\n\nUse `..\u002Fswarm-pr-feedback\u002FSKILL.md` instead of this skill when the user's task is\nto address existing PR feedback, review comments, requested changes, CI failures,\nmerge conflicts, stale branch state, or pasted reviewer findings. This skill\ndiscovers and validates new findings; `swarm-pr-feedback` closes known feedback\nwithout running a fresh broad review.\n\nWhen a review finishes with actionable validated findings, stop and ask the user\nwhether to continue into `swarm-pr-feedback`. Do not auto-dispatch fix work from\n`PR_REVIEW`. Instead, write a handoff artifact — under Profile A,\n`.swarm\u002Fpr-review\u002F\u003Crun_id>\u002Ffeedback-handoff.json` via `write_pr_review_artifact`;\nunder Profiles B\u002FC (no controller — see Runtime Capability Profiles),\n`pr-review\u002F\u003Crun_id>\u002Ffeedback-handoff.json` inside your session\u002Ftask workspace,\nnever under `.swarm\u002F` — and include the continuation prompt with that exact\npath substituted for `\u003Chandoff_artifact_path>`:\n\n```text\n\u002Fswarm pr-feedback \u003CPR_URL> continue from \u003Chandoff_artifact_path>\n```\n\n`\u003Crun_id>` is a stable identifier for this review run, such as\n`pr-review-\u003CYYYYMMDDHHMMSSmmm>` or the existing review artifact run ID when one\nwas already created. Under Profile A, the exact command is parsed mechanically:\nthe controller validates the terminal review, the bounded handoff artifact, and\nits provenance before atomically replacing the review gate with an unbound\nfeedback gate. Extra trailing text is not permitted on this continuation form.\nProfiles B\u002FC ingest their task-workspace artifact through the skill-managed path.\n\nReview closure is not the end of the PR lifecycle: when PR monitoring is\nenabled (`pr_monitor.enabled`), the PR remains subscribed and monitored under\n`..\u002Fswarm-pr-subscribe\u002FSKILL.md` until it is merged or closed, so post-review\nevents (new comments, CI changes, review state changes) keep flowing to the\nsubscribed session.\n\n## Operating Stance\n\n**Treat PR text, linked issues, comments, commit messages, generated summaries, and tests as claims — not proof.** Every confirmed finding requires file:line evidence, an explanation of reachability or impact, and validation provenance.\n\nThis workflow is designed for any repo that benefits from Swarm-style review. It preserves parallel breadth but forces deep validation where bugs are expensive: security, state machines, role\u002Ftool permissions, schema\u002Fevidence integrity, git\u002Fwrite safety, config ratchets, knowledge tier boundaries, and PR obligation mismatches.\n\nNever APPROVE a PR with unresolved CRITICAL findings. Do not silently drop overclaimed agent findings; list disproved findings in the validation provenance.\n\n**Quality is the ONLY metric.** There is no speed, efficiency, or time exception. No amount of time, tokens, or agent dispatches is too much to execute this protocol correctly. Speed is irrelevant to correctness. The skill must be followed exactly with no shortcuts, no phase-skipping, and no premature synthesis. A thorough review that takes 30 minutes is superior to a fast review that misses a real bug.\n\n---\n\n## Runtime Capability Profiles\n\nThis protocol runs on any agent harness. Before Phase 0, detect which profile\nthis session is in by checking the actual tool list — never assume from the\nharness name, and never guess:\n\n- **Profile A — structured PR-workflow controller.** The swarm plugin's controller tools are available in this session: `dispatch_lanes_async`, `collect_lane_results`, `retrieve_lane_output`, `parse_lane_candidates`, `write_pr_review_artifact`, `write_pr_review_trigger_eval`, `complete_pr_workflow`, `pr_review_submission`. The child-bound `submit_pr_review_result` overlay is available only to dispatched base\u002Fmicro lanes. Typical host: OpenCode with the swarm plugin. The controller mechanically enforces this skill's accounting: it computes the\n  depth tier itself from the bound merge-base diff (never from caller\n  claims), enforces the tier's lane floors and full dimension\u002Ffamily\n  partitions for consolidated dispatch, and gates structured reviewer\u002Fcritic\n  batches and the response gate. Its acceptance rules are authoritative, and\n  where the scaled-dispatch guidance below is more permissive than the\n  active controller, the controller wins. Bypassing an active controller —\n  blocking `dispatch_lanes`, direct Task\u002Fagent dispatch, prose verdicts — is\n  BLOCKED.\n- **Profile B — native parallel subagents, no controller.** The controller\n  tools are absent, but the harness can spawn independent fresh-context\n  subagents (for example Claude Code's `Agent`\u002F`Task` tool, or the native\n  subagent mechanisms in Codex and ZCode). Run the same phases, role\n  boundaries, row contracts, and join barriers; you are the accounting layer\n  the controller would otherwise be: bind the exact `pr_head_sha` in every\n  lane prompt, record per-lane provenance (lane id, head SHA) on every ledger\n  row, settle every lane before the next phase begins, and persist ledgers to\n  files in your harness's session\u002Ftask workspace. Never write runtime\n  artifacts under `.swarm\u002F` — that directory belongs to the plugin controller.\n- **Profile C — single context, no subagents.** The harness cannot spawn\n  independent subagents in-session. Execute the same phases as strictly\n  separated sequential passes — candidate generation, then reviewer\n  validation, then critic challenge — re-deriving rather than restating\n  earlier reasoning in each pass, with the same ledger rows and per-family\n  attestations. Disclose in the validation provenance that reviewer\u002Fcritic\n  independence was procedural (separate passes in one context), not\n  contextual.\n\n| Harness (typical) | Profile | Lane dispatch | Ledger persistence | Completion gate |\n|---|---|---|---|---|\n| OpenCode + swarm plugin | A | `dispatch_lanes_async` \u002F `collect_lane_results` | `write_pr_review_artifact`, `write_pr_review_trigger_eval` | `complete_pr_workflow` |\n| Claude Code | B | parallel `Agent`\u002F`Task` subagents | ledger files in the session task workspace | Pre-Synthesis Gate checklist |\n| OpenAI Codex | B | parallel subagents (fresh context) | ledger files in working notes | Pre-Synthesis Gate checklist |\n| ZCode | B | parallel subagents (fresh context) | ledger files in working notes | Pre-Synthesis Gate checklist |\n\nHost-native JSON-schema transport is optional and currently unregistered on the\ntested host matrix, so Profile A uses the child-bound `submit_pr_review_result`\ntool as its supported baseline. Any future native integration must implement\nthe fixed internal `promptJsonSchema({ sessionId, agent, schema, parts })` seam\nand pass adapter-present, unsupported-before-execution, provider-failure,\ntimeout, and per-session capability tests before registration.\n\n**Completion-gate assurance is NOT equivalent across profiles.** Only Profile A\nenforces completion MECHANICALLY: the controller's `complete_pr_workflow` receipt\ngate refuses synthesis unless base coverage, the 11-family trigger ledger, and the\nreviewer\u002Fcritic artifacts are all present and head-bound. Profiles B and C rely on\nthe operator executing the Pre-Synthesis Gate checklist themselves — there is no\nruntime receipt gate that refuses a partial synthesis. Treat B\u002FC as PROCEDURAL\nassurance only; do not claim mechanical completion parity with Profile A for this\nrepository unless a controller-equivalent receipt gate is added for those profiles.\n\nVerify each row against your own current tool list before relying on it; a\nharness may gain or lose capabilities between versions. OpenCode, Claude Code,\nCodex, and ZCode can all spawn fresh-context subagents in current versions —\nrun Profile B wherever the session actually exposes that capability; reserve\nProfile C for sessions that genuinely lack a subagent mechanism, never assigning\na harness to Profile C by name alone. The absence of the controller is NOT a\nBLOCKED condition — Profiles B and C are legitimate execution paths whose\ncompletion gate is PROCEDURAL (see the note above), not the mechanically\nenforced receipt gate Profile A provides.\nBLOCKED is reserved for bypassing an active controller and for coverage gaps\nthat remain unclosable after bounded retries on any profile.\n\n### Profile A controller quick reference\n\nThis is the concise mechanical contract for an active structured controller.\nThe detailed phases below explain the reasoning, but they do not override this\nordering, vocabulary, or schema.\n\n- Base `workflow_lane` IDs (all six): `intent-architecture`,\n  `correctness-state`, `tests-falsifiability`, `security-trust`,\n  `reliability-performance`, `compatibility-delivery`.\n- Trigger\u002Fmicro `workflow_lane` IDs (all eleven): `auth-identity-secrets`,\n  `untrusted-input-boundaries`, `subprocess-platform`, `concurrency-state`,\n  `dependencies-build-release`, `api-schema-migrations`,\n  `test-infrastructure`, `ui-accessibility-i18n`, `privacy-observability`,\n  `generated-provenance`, `unclassified-risk`.\n- Base candidate header:\n  `[CANDIDATE] | candidate_id | lane | severity | category | file:line | claim | evidence_summary | impact_context | confidence | risk_impact | risk_tags`\n- Base clean attestation:\n  `[CLEAN] | lane | coverage_scope | evidence`\n- Micro\u002Fcouncil candidate header:\n  `[CANDIDATE] | candidate_id | micro_lane | severity | category | file:line | claim | invariant_violated | evidence_summary | confidence | risk_impact | risk_tags`\n- Micro\u002Fcouncil clean attestation:\n  `[CLEAN] | micro_lane | coverage_scope | evidence`\n- Severity is exactly `INFO | LOW | MEDIUM | HIGH | CRITICAL`; confidence is\n  exactly `LOW | MEDIUM | HIGH`.\n\nController order is exact: bind the immutable head\u002Fbase range; dispatch,\nsettle, and parse base lanes; evaluate every trigger row; dispatch micro lanes;\nsettle and parse every matched micro family; persist the trigger evaluation;\nensure each base\u002Fmicro child lane submits exactly one child-bound structured\nreceipt; persist post-explorer findings; run reviewers;\nrun critics; then persist the final artifact and complete the workflow. Transcript\n`[CANDIDATE]` \u002F `[CLEAN]` rows are deprecated legacy compatibility only for\nlanes whose snapped `pr_review_legacy_transcript_compatibility` contract\nexplicitly enables them.\nThe **initial** micro dispatch MUST supply the complete trigger-evaluation\nledger; that dispatch freezes it for the session.\nAny subsequent micro batch in that same session MAY omit `trigger_evaluation`\nand reuse the frozen ledger. If a subsequent batch explicitly supplies a copy,\nthat copy MUST remain exactly identical to the frozen ledger.\n\nAll machine-readable candidate headers, candidate rows, and clean attestations\nmust be emitted as unfenced plain text. Markdown fences shown in this skill are\ndocumentation fences only; emitting the backticks causes the controller to\nignore those rows as quoted\u002Fexample material.\n\n---\n\n## Review Modes\n\n### Default layered workflow\n\nAlways run the default layered workflow (mechanically enforced under Profile A). Explorers produce only candidates. The orchestrator does not confirm or disprove candidates.\n\n### Council mode — opt in only\n\nCouncil mode applies only when the user explicitly says one of:\n\n- `council`\n- `independent review`\n- `N-agent review`\n- `\u002Fcouncil`\n- `[COUNCIL MODE]`\n- `[MODE: PR_REVIEW … council=true]`\n- `assume all work is wrong`\n\nCouncil mode supplements the default mechanical workflow; it never replaces or weakens it. Even when council mode is triggered, first complete the base-dimension coverage (the tier-floored base dispatch under Profile A — the exact-six wave at depth tier L), micro-lane ledger persistence, and every repository-agnostic risk-family evaluation at the same exact `pr_head_sha`. Route supplementary council output into the candidate ledger before independent reviewer classification. If the council request arrives after classification has begun, run the council as an additional candidate pass and dispatch a new structured reviewer batch for those candidates before synthesis.\n\n---\n\n## Anti-Self-Review Rule\n\nThe main thread \u002F orchestrator MUST NOT classify, confirm, disprove, or judge explorer candidates in the default workflow.\n\nThe orchestrator may:\n\n- determine scope,\n- build or request the context pack,\n- launch explorers and the full risk-family micro coverage (every family evaluated; lane count per depth tier and profile),\n- extract candidates from lane artifacts via `parse_lane_candidates` (Profile A) or by collecting the structured `[CANDIDATE]` rows from lane reports (Profiles B\u002FC),\n- filter, group, and chunk candidates for reviewer dispatch,\n- route candidates to reviewers,\n- route reviewer-confirmed findings to critics,\n- group validated findings,\n- prepare the final report.\n\nThe orchestrator MUST NOT:\n\n- re-read a candidate's target code to decide if it is valid,\n- silently downgrade or discard an explorer candidate,\n- treat tool output as a confirmed finding,\n- report a finding that no reviewer validated,\n- classify or judge candidates based on preview text alone — always use the structured parser output (Profile A) or the verbatim-collected `[CANDIDATE]` rows (Profiles B\u002FC).\n\nIf the orchestrator catches itself validating code, it must stop and delegate validation to a reviewer subagent.\n\nException: in explicit Council mode only, the main thread may act as the independent reviewer as described in the Council Mode section. Prefer a reviewer subagent when available.\n\n---\n\n## Scope Detection\n\nDetermine review scope using this priority:\n\n1. explicit user-provided PR URL, PR number, commit, branch, or file scope,\n2. current feature branch diff vs the remote-tracking base ref (`origin\u002Fmain`,\n   `origin\u002Fmaster`; a local `main`\u002F`master` only as a last resort — it is only as\n   fresh as the last fetch and yields a different merge base),\n3. staged changes,\n4. latest commit,\n5. user-specified files or directories.\n\nRecord:\n\n- base ref,\n- head ref,\n- commit range,\n- changed files,\n- deleted files,\n- generated files,\n- lockfiles,\n- test files,\n- docs\u002Fconfig\u002Fschema files,\n- whether the working tree is dirty.\n\nIf scope cannot be determined, review the narrowest safe scope available and state the limitation.\n\n### Pre-flight git ref availability\n\nBefore launching explorers (Phase 3), perform this exact standalone sequence:\n\n1. Resolve and retain the authoritative full `pr_head_sha` from PR metadata.\n2. Verify the working tree is clean with `git status --porcelain`. If it is\n   dirty at all — tracked changes, untracked files, or both — call\n   `prepare_pr_workflow_checkout` (Profile A). The tool supports\n   self-discovery: call it with no `paths` argument to auto-discover and\n   preserve every dirty path in one step, including untracked files; an\n   already-clean tree returns a no-op (nothing is stashed, no receipt is\n   written). Pass explicit `paths` only when you already have the exact,\n   bounded list of dirty tracked files and want the older exact-match\n   contract. Without the controller (Profiles B\u002FC), do not blind-stash over\n   dirty state: surface tracked changes to the user, or abort. Do not issue\n   `git stash` through shell.\n   Treat the controller's Git-state result as final for this attempt: `clean`\n   proceeds, `stashable` permits exactly one checkout-preparation call, and\n   `recovery-required` or `indeterminate` means report the typed\n   `required_action`, abort\u002Fclear any already-active gate, and stop. Retry only\n   when the controller explicitly returns `retryable: true`; never fight an\n   unmerged index or in-progress Git operation with repeated stash attempts.\n3. Fetch the PR head as one standalone command, for example\n   `git fetch origin refs\u002Fpull\u002F\u003CN>\u002Fhead`. Do not compose fetch and checkout.\n3a. Fetch the base branch as its own standalone command, for example\n   `git fetch origin main`. Skipping this is the single most common cause of a\n   rejected dispatch: the merge base is recomputed against `base_ref`, and a\n   local `main`\u002F`refs\u002Fheads\u002Fmain` that was never refreshed resolves to a\n   different commit than `origin\u002Fmain` for the same `base_sha`.\n4. Prove the full commit exists locally with two portable standalone commands:\n   `git rev-parse --verify \u003Cfull_pr_head_sha>^0`, then\n   `git cat-file -t \u003Cfull_pr_head_sha>`. The second command must print\n   `commit`. This avoids shell\u002Fwrapper parsing differences around the\n   `^{commit}` suffix on Windows.\n5. Check out the exact PR filesystem with\n   `git switch --detach \u003Cfull_pr_head_sha>`. Do not use `--track FETCH_HEAD`:\n   `FETCH_HEAD` is not a remote-tracking branch.\n6. Confirm `git rev-parse HEAD` equals the full `pr_head_sha`, bind that exact\n   head (Profile A: through the first PR-review controller call; Profiles B\u002FC:\n   record it at the top of the findings ledger and repeat it in every lane\n   prompt), and finish this before dispatching explorer lanes.\n\nExplorer agents read files from the working tree, not from git history. Passing\nthe commit range in a prompt cannot substitute for this checkout because\n`Read` \u002F `Glob` \u002F `Grep` operate on the filesystem.\n- Explicitly pass the verified merge-base range (`base_sha...pr_head_sha`) in every explorer delegation so explorers inspect exactly the bound PR diff. Include `base_ref` only as the live ref used to recompute `base_sha`; do not substitute a two-dot branch-tip range.\n\nIf refs cannot be fetched or checked out, state the limitation in the context pack.\n\n### Shell rules under the PR_REVIEW gate\n\nThe gate accepts one command per tool call — never compose commands with\n`&&`, `;`, shell pipelines, redirects (`>`, `>>`, `\u003C`), or `$(...)`\u002F`` ` ``\nsubstitution. The only literal-pipe exception is inside one closed\ndouble-quoted `gh api --jq` argument with no backslash-escaped nested double\nquotes; that escape is ambiguous under `cmd.exe`. The exception does not\npermit an outer pipeline or any other control syntax.\nA single leading `cd \u003Cdir> &&` prefix and a trailing `2>&1` suffix are\ntolerated, but only on read-only commands. State-transition verbs — `git\nfetch`, `git checkout`, `git switch`, `git branch`, and `gh pr checkout` —\nmust always run bare: no `cd` prefix, no `2>&1` suffix.\n\nAllowed read-only `git` subcommands: `status`, `log`, `show`, `diff`,\n`rev-parse`, `merge-base`, `ls-files`, `grep`, `blame`, `cat-file`,\n`for-each-ref`, `branch --list` (listing only — mutation flags are blocked),\n`remote -v`, and `config --get`.\n\nPrefer tools over raw shell for state that a single read-only command cannot\ncover cleanly:\n\n- `pr_workflow_status` — observe local HEAD, branch, dirty-file state,\n  remotes, and gate state in one read-only call.\n- `gh_evidence` — bounded PR\u002Fissue\u002Frun metadata without a shell round-trip.\n- If `gh` is not installed, the web fetch tool against the equivalent\n  `api.github.com` REST URL is the degraded read-only path.\n\n## Phase 0A: Existing PR Signal Ingestion\n\nWhen reviewing a PR, ingest and triage every existing signal BEFORE starting\nPhase 0. These are candidate generators and obligation sources, not\npre-confirmed findings.\n\n### PR title and body compliance check\n\nBefore deeper analysis, discover whether the repository defines a PR\npublication contract (for example a local `commit-pr` skill, `CONTRIBUTING`\nguidance, a PR template, or a CI check such as `pr-standards`). If it does,\nverify the PR against that contract and record any gap as an advisory ledger\nitem. If it does not, do not invent opencode-swarm-specific title\u002Fbody\nsections; still verify that the PR text is not misleading about what the diff\ndoes or proves.\n\nAt minimum, check:\n\n- required title\u002Fbody\u002Flinked-issue structure from the discovered repository\n  contract,\n- issue-closing, migration, release-note, invariant, or test-plan claims made\n  in the PR text,\n- whether those claims are supported by the actual diff and the current issue\n  state.\n\n**Issue-closing claim-integrity check:** if the PR body uses an issue-closing\nkeyword such as `Closes #\u003Cissue-number>`, verify (a) the issue is currently open\n(`gh issue view \u003CN> --json state` when the host is GitHub), and (b) the diff\naddresses the issue's acceptance criteria (read the issue, map each criterion\nto changed files\u002Fsymbols, and inspect the diff for those areas). If the issue\nis already closed by another merged PR, do NOT re-close it — the duplicate\nclosing reference is misleading. If the issue is open but the diff does not\naddress the acceptance criteria, mark the claim as `UNVERIFIED — claim\nintegrity` in the validation provenance and surface the unresolved gap to the\nuser before synthesis.\n\nContract non-compliance is a ledger item (advisory unless the repository\nexplicitly makes it blocking). If the PR is from an external contributor, note\nthe compliance gap for the maintainer to address before merge.\n\nThis intake includes:\n\n- review comments, review summaries, requested changes, and bot findings,\n- CI\u002Fcheck failures, annotations, and relevant logs,\n- mergeability\u002Fconflicts, `mergeStateStatus`, and stale\u002Fbase-drift state,\n- PR body claims, linked issues, acceptance criteria, and test-plan claims,\n- commit messages and app\u002Fbot commits on the PR branch.\n\nWhen multiple CI\u002Fcheck runs have the same name, reconcile them by head SHA and\ntime: the latest run for the exact bound head SHA supersedes an older same-check\nrun on that same head. Keep an older failure only as historical diagnostic\nevidence; do not report it as the current PR state after a newer same-head run\nhas completed successfully.\n\nWhen thread resolution state matters, prefer GraphQL review-thread inspection.\nIf GraphQL is unavailable, keep the signal and mark\n`resolution_state: UNKNOWN`; do not drop it from scope.\n\n### Step 1 — Fetch all PR feedback surfaces\n\nThe commands below are GitHub examples. On GitLab, Bitbucket, Gerrit, or\nanother code host, use the host's API\u002Fconnector\u002FCLI to enumerate the same full\nsurface, including pagination and unresolved-thread state. Host choice never\nreduces the intake ledger.\n\n```bash\n# Issue comments (general PR thread)\ngh api --paginate repos\u002F{owner}\u002F{repo}\u002Fissues\u002F{PR_NUMBER}\u002Fcomments\n\n# Review comments (inline code comments)\ngh api --paginate repos\u002F{owner}\u002F{repo}\u002Fpulls\u002F{PR_NUMBER}\u002Fcomments\n\n# Review summaries (approve\u002Frequest-changes\u002Fcomment events)\ngh api --paginate repos\u002F{owner}\u002F{repo}\u002Fpulls\u002F{PR_NUMBER}\u002Freviews\n```\n\n`--paginate` requests every REST page. These three calls are gate-allowed as\nwritten. A literal jq filter passed as one closed double-quoted `gh api --jq`\nargument is also allowed when it needs no backslash-escaped nested double\nquotes; use `gh_evidence` when a portable filter cannot meet that shape. A real\nshell pipeline to `jq` or another command remains blocked. To\nseparate bot\u002Fautomated reviews (Copilot, Codex, CodeRabbit, etc.) from human\nones, apply the same predicate in context to the JSON already returned above\n— `user.type == \"Bot\"` or a `user.login` match against\n`bot|copilot|coderabbit|codex` (case-insensitive) — instead of re-fetching\nwith a shell-side `--jq` filter. `gh_evidence` with `target: \"pr\"` and\n`fields: \"comments\"` is the sanctioned read-only tool path for the same PR\ncomment data when a tool call is preferred over a raw shell command. `gh pr\nview --json comments,reviews` is convenience-only because those fields have\nitem caps; never use it as the authoritative \"all signals\" intake.\n\n### Step 2 — Classify each comment\n\n| Category | Action |\n|----------|--------|\n| **Human review with file:line evidence** | Add as candidate finding with `source: existing-review` — still needs reviewer validation |\n| **Bot\u002Fautomated finding with specific code reference** | Add as candidate finding with `source: bot-review` — high false-positive rate, treat as unverified |\n| **General feedback \u002F style preference** | Add as advisory obligation |\n| **Resolved\u002Foutdated comment** | Skip — note in report under \"Ingested Resolved Comments\" |\n| **Requested changes not yet addressed** | Add as HIGH-priority obligation |\n\n### Step 3 — Merge into review pipeline\n\nAll ingested comments become candidate findings or obligations. They follow the\nsame Phase 3-8 pipeline as freshly discovered findings. Ingested findings are\nNOT pre-confirmed — they still require independent reviewer validation per the\nAnti-Self-Review Rule.\n\n**Comment-ledger output:**\n```\n[INGESTED] | source | category | file:line (if applicable) | original_author | status: PENDING_VALIDATION \u002F SKIPPED_OUTDATED \u002F ADVISORY\n```\n\n### Anti-patterns\n- ✗ Ignoring bot reviews because \"bots produce false positives\" — they also catch real issues\n- ✗ Pre-confirming human review comments without independent validation — even senior reviewers make mistakes\n- ✗ Skipping inline review comments and only reading the summary — inline comments contain the evidence\n\n## Phase 0B: Mergeability and Branch-State Intake\n\nBefore investing effort in review lanes, verify the PR is mergeable and record\nbranch-state signals. `PR_REVIEW` remains read-only: do not resolve conflicts,\ncommit, push, rebase, merge, or reset from this mode. Instead, carry current\nmergeability, stale-head, and branch-drift facts into the review ledger and the\nfeedback handoff artifact.\n\n### Step 1 — Check merge state\n\nThe field names and values below are GitHub-specific examples. On another code\nhost, record the equivalent mergeability, conflict, required-check, base-drift,\nand stale-head signals and preserve the same read-only behavior.\n\n```bash\ngh pr view \u003CPR_NUMBER> --json mergeable,mergeStateStatus\n```\n\nThe response has two independent fields. Handle each:\n\n**`mergeable` field** — whether GitHub can compute mergeability:\n| Value | Meaning | Action |\n|-------|---------|--------|\n| `MERGEABLE` | No conflicts detected | Proceed — check `mergeStateStatus` below |\n| `CONFLICTING` | Merge conflicts exist | Record the blocker, keep the review read-only, and hand conflict resolution to `swarm-pr-feedback` |\n| `UNKNOWN` | GitHub still computing | Wait 30s, re-check |\n\n**`mergeStateStatus` field** — overall branch state:\n| Value | Action |\n|-------|--------|\n| `CLEAN` | All checks pass, no conflicts — proceed to Phase 0 |\n| `BEHIND` | Branch behind base — note in report; non-blocking if merge queue handles it |\n| `DIRTY` | Merge conflicts exist — keep reviewing, but record the conflict as a first-class blocker in the ledger and handoff artifact |\n| `BLOCKED` | External blocker (branch protection, failing required check) — investigate and record the blocker |\n\n### Step 2 — Record conflicts and blockers (when CONFLICTING or DIRTY)\n\nWhen the PR has merge conflicts:\n\n1. **Determine the PR's base branch and verify the state**, as separate\n   standalone commands — never with `$(...)` command substitution, which the\n   PR_REVIEW gate blocks:\n   - Read the base ref: `gh pr view \u003CPR_NUMBER> --json baseRefName` (or\n     `gh_evidence` with `target: \"pr\"`, `fields: \"baseRefName\"`).\n   - Fetch it by its literal value, substituted for `\u003Cbase-ref>`:\n     `git fetch origin \u003Cbase-ref>`.\n   - Re-check merge state: `gh pr view \u003CPR_NUMBER> --json\n     mergeable,mergeStateStatus,baseRefName,headRefName`.\n\n2. **Capture the affected scope without changing the branch:**\n   - List the files or subsystems implicated by the conflict if GitHub exposes them,\n     or note that the exact conflict set is still unknown.\n   - Identify whether the conflict appears mechanical (lockfile \u002F generated output \u002F\n     simple overlap) or semantic (logic changed on both sides). This is triage\n     signal for the follow-on feedback run, not permission to resolve it here.\n\n3. **Record explicit next action for the handoff artifact:**\n   - `CONFLICT-### | mechanical | likely resolvable during pr-feedback`\n   - `CONFLICT-### | semantic | requires focused fix + validation during pr-feedback`\n   - `STALE-### | behind base by policy` when the branch is only stale, not conflicted\n\n4. **Document in report:** List the branch-state facts, why they matter to the\n   review, and what `swarm-pr-feedback` must verify before it edits code.\n\n### Conflict resolution anti-patterns\n- ✗ Accepting \"ours\" or \"theirs\" for all conflicts without reading them\n- ✗ Resolving semantic conflicts without understanding both sides\n- ✗ Pushing resolution without running tests on the merged result\n- ✗ Treating `PR_REVIEW` as the place to fix branch state — this mode stays read-only\n\n## Phase 0B-bis: Pre-Handoff Parallel Work Snapshot\n\nWhen the review surfaces findings that will likely need `swarm-pr-feedback`,\nre-check for **parallel work** since the last fetch. The PR author, the bot\nreviewer, or another swarm may have pushed commits while you were reviewing.\nThis is still read-only: capture the remote state so the handoff artifact starts\nfrom the right branch facts.\n\n### Step 1 — Compare remote state (read-only, no post-bind fetch)\n\nOnce the PR head is bound, the gate allows only the exact bound tracking\nfetch (when one is armed), and a detached review HEAD has no tracking branch\nto refetch against — `git fetch origin \u003Cpr-branch>` is blocked here. Compare\nstate through the read-only API instead, as one standalone command:\n\n```bash\ngh pr view \u003CPR_NUMBER> --json headRefOid,commits\n```\n\nor the equivalent `gh_evidence` call with `target: \"pr\"` and\n`fields: \"headRefOid,commits\"`. If the returned `headRefOid` differs from the\n`pr_head_sha` bound at the start of this review, the remote has moved; the\n`commits` field lists every commit's message and author to date, enough to\njudge relevance to the pending findings. (The legitimate place to `git fetch`\nis the pre-bind sequence under \"Pre-flight git ref availability\" above — this\nstep never repeats that fetch post-bind.)\n\n### Step 2 — Evaluate new commits\n\nFor each new commit on the remote (identified by comparing `headRefOid` \u002F\n`commits` above against the SHA bound at the start of the review):\n\n1. **Read the commit message from the `commits` field above.** For file\n   scope, use one standalone read-only call —\n   `gh api repos\u002F{owner}\u002F{repo}\u002Fcommits\u002F\u003Csha>` — rather than a local\n   `git show`: the new commit's object is not fetched locally post-bind.\n2. **Compare against the pending handoff scope:**\n   - Does the remote commit touch the same files as the validated findings?\n   - Does the remote commit appear to already address a finding you planned to\n     hand off?\n   - Does the remote commit introduce a new branch-state fact the handoff should\n     mention?\n3. **Default stance: prefer the remote state as the next baseline.** When the\n   bundled copy is available (plugin runtimes), run the\n   `file:.swarm\u002Fbundled-skills\u002Fparallel-work-check\u002FSKILL.md`\n   protocol for the formal decision template; otherwise apply the three\n   outcomes below directly. Record the outcome in the handoff artifact.\n\n### Step 3 — Three outcomes\n\n- **Parallel work supersedes:** Mark the older local checkout as stale in the\n  handoff artifact and tell `swarm-pr-feedback` to re-check out the current\n  remote head before editing.\n- **Parallel work complements:** Carry both the validated findings and the new\n  remote commits into the handoff artifact so `swarm-pr-feedback` can verify the\n  combined state before patching.\n- **Parallel work unrelated:** Note that the remote moved, but keep the same\n  validated finding set.\n\n### Anti-patterns\n\n- ✗ Pushing your fix without checking if the remote already fixed it — causes\n  duplicate work and may even fail the push if the commits conflict\n- ✗ Force-pushing over parallel work because \"I started this first\" — the\n  parallel agent may have access to context you don't (different swarm\n  configuration, different model, different time budget)\n- ✗ Blindly taking remote work without verifying it's actually better — the\n  parallel work may be incomplete or take a different approach that doesn't\n  match the original finding's intent\n\n### Example: parallel swarm superseded local fix work\n\nSee `references\u002Fparallel-work-example.md` for the worked PARALLEL WORK CHECK\ntranscript (remote supersession, abandon-use-remote decision).\n\n---\n\n# Default Review Workflow\n\n## Phase 0: Context Pack and Review Signal Collection\n\nBefore launching explorers, build a compact `swarm-pr-review-context`. Under\nProfile A, do not create a scratch context-pack file after the controller gate\nactivates: PR_REVIEW intentionally blocks arbitrary writes. Put the bounded\nshared scope, obligations, deterministic signals, and impact hints in\n`common_prompt`, and require every lane to inspect the exact bound diff itself.\nUnder Profiles B\u002FC, keep the context in working notes or a local artifact only\nwhen that runtime permits the write.\n\nThe context pack must include, when available:\n\n```json\n{\n  \"scope\": {\n    \"base_ref\": \"...\",\n    \"head_ref\": \"...\",\n    \"commit_range\": \"...\",\n    \"changed_files\": [],\n    \"changed_hunks\": [],\n    \"public_api_changes\": [],\n    \"deleted_or_renamed_files\": [],\n    \"generated_files\": []\n  },\n  \"pr_metadata\": {\n    \"title\": \"...\",\n    \"body_claims\": [],\n    \"checkboxes\": [],\n    \"linked_issues\": [],\n    \"review_comments\": [],\n    \"commit_messages\": []\n  },\n  \"obligations\": [],\n  \"repo_graph\": {\n    \"source\": \".swarm\u002Frepo-graph.json or fallback search\",\n    \"changed_symbols\": [],\n    \"callers\": [],\n    \"callees\": [],\n    \"imports\": [],\n    \"exports\": [],\n    \"sibling_implementations\": []\n  },\n  \"deterministic_signals\": {\n    \"ci\": [],\n    \"tests\": [],\n    \"coverage_delta\": [],\n    \"lint_typecheck_build\": [],\n    \"security_scanners\": [],\n    \"dependency_audit\": [],\n    \"secrets_scan\": [],\n    \"mutation_testing\": []\n  },\n  \"swarm_artifacts\": {\n    \"evidence_bundles\": [],\n    \"knowledge_hits\": [],\n    \"phase_state\": [],\n    \"metrics\": []\n  },\n  \"risk_triggers\": []\n}\n```\n\n### Context pack rules\n\n- Diff-only review is allowed for quick orientation, but not enough to confirm nontrivial findings.\n- For every changed production file, identify at least one caller, consumer, import path, route entrypoint, or reason none exists.\n- If `.swarm\u002Frepo-graph.json` exists, use it to seed impact cones.\n- If no repo graph exists, build a shallow impact cone using imports, exports, symbol search, route registration, CLI registration, or test references.\n- Pull in relevant `.swarm\u002Fevidence\u002F`, `.swarm\u002Fstate`, `.swarm\u002Fknowledge`, or hive\u002Fproject knowledge entries when present.\n- Historical knowledge may guide candidate generation but cannot confirm a finding by itself.\n- Mark stale, quarantined, or cross-project knowledge as advisory until independently verified in this repo.\n\n---\n\n## Review Finding Persistence\n\nDo not rely on conversation context to preserve review findings. On Profile A,\nuse `write_pr_review_artifact` with `kind: \"findings\"`; the controller creates\nand appends `.swarm\u002Fpr-review\u002F\u003Crun_id>\u002Ffindings.jsonl` without granting generic\nwrite authority over `.swarm\u002F`. On Profiles B\u002FC, append the same records to a\n`findings.jsonl` ledger in your harness workspace (never under `.swarm\u002F`), with\nthe review head SHA recorded at the top.\n\nEach persisted finding record must include at least:\n\n```json\n{\"finding_id\":\"F-001\",\"status\":\"PENDING\",\"file_line\":\"src\u002Ffile.ts:123\",\"evidence\":\"quote, command output, lane id, or reviewer rationale\",\"next_action\":\"route_to_reviewer\",\"severity\":\"HIGH\"}\n```\n\nMinimum field contract:\n\n- `finding_id`: stable ID from the candidate\u002Freviewer\u002Fcritic ledger.\n- `status`: one of `PENDING`, `CONFIRMED`, `DISPROVED`, or `PRE_EXISTING`.\n- `file_line`: exact `file:line`, or `N\u002FA` with reason when cross-file.\n- `evidence`: compact source-backed proof (lane\u002Freviewer\u002Fcritic IDs or command output references when available).\n- `next_action`: `route_to_reviewer`, `route_to_critic`, `report`, `suppress_with_reason`, or `handoff_to_feedback`.\n- `severity`: REQUIRED at every boundary — omitting it is a violation, not a shortcut. Vocabulary is the VERDICT dialect `INFO|LOW|MEDIUM|HIGH|CRITICAL|NONE`. At `post_explorer` it must equal the severity of the `[CANDIDATE]` row the record projects (so never `NONE`, which no candidate row can declare) — except the mechanically derived `CLEAN-REVIEW` sentinel emitted when discovery found nothing, whose severity is `NONE`; at `post_reviewer` the reviewer `final_severity`; at `post_critic` the **critic** `final_severity` for critic-routed records, otherwise the reviewer's (issue #2279).\n\nPersist after every major validation boundary (Profile A via the controller\ncalls below; Profiles B\u002FC by appending the same boundary-tagged records to the\nledger file):\n\n1. **Post-explorer:** persist as soon as the base wave settles and its\n   candidates parse — BEFORE micro dispatch — by calling\n   `write_pr_review_artifact` with `boundary: \"post_explorer\"` and the\n   base-derived candidates as `PENDING` with their lane provenance. This\n   base-only write is the compaction recovery point for everything before\n   trigger evaluation; it must cover exactly the base-derived inventory\n   (micro ids are refused as `extra:` at this point). After trigger\n   evaluation a full-inventory `post_explorer` write (base+micro) is also\n   admissible and supersedes the early checkpoint as the recovery point.\n2. **Post-reviewer:** after Phase 6 reviewer validation, call the controller\n   with `boundary: \"post_reviewer\"` and update each reviewed\n   record to `CONFIRMED`, `DISPROVED`, `PRE_EXISTING`, or keep `PENDING` with a\n   concrete `next_action` if more evidence is required.\n3. **Post-critic:** after Phase 8 critic challenge, call the controller with\n   `boundary: \"post_critic\"` and update final status, the authoritative\n   `severity`, and final reporting or handoff action.\n\n**Enforced order, dispositions, and error reporting (Profile A).** The\ntrigger evaluation must complete before every findings boundary EXCEPT the\nbase-only `post_explorer` write above, which is admissible right after base\nsettlement (issue #2280); beyond that exception checkpoints run strictly\n`post_explorer` → `post_reviewer` → `post_critic`, each requiring the prior\ncheckpoint persisted, and `post_reviewer`\u002F`post_critic` must exactly cover\nthe FULL (base+micro) candidate inventory against the persisted trigger-eval\nartifact; records must match the authoritative reviewer\u002Fcritic\nverdict rows, and an invalid payload is rejected in ONE call listing every\nviolation as `finding_id: field expected \u003Cvalue>, got \u003Cvalue>`. Full contract\n(write order, dispositions, severity authority table, handoff schema):\nreferences\u002Ffindings-persistence-contract.md.\n\nResume\u002Freload procedure: read the latest `findings.jsonl` and reconstruct the\nledger from disk before dispatching more lanes; the base-only `post_explorer`\ncheckpoint alone is enough to resume after a compaction between base\nsettlement and the micro wave (re-dispatch micro, re-run trigger evaluation,\nthen continue with full-inventory boundaries); surface a missing artifact as\na coverage gap, never reclassify from memory; append (latest record wins).\n\n---\n\n## Phase 1: Intent Reconstruction \u002F Obligation Extraction\n\nReconstruct what the PR is obligated to deliver before looking for bugs.\n\nUse deterministic precedence, highest to lowest:\n\n1. PR checkboxes and acceptance criteria,\n2. linked issues \u002F tickets,\n3. explicit user request in the current conversation,\n4. commit scopes and commit messages,\n5. test names and test assertions,\n6. interface diff \u002F exported API changes,\n7. changelog, README, migration, or docs edits,\n8. LLM synthesis only when no higher-precedence source exists.\n\nOutput an obligation list:\n\n```text\nO-001 | source | claim | affected files\u002Fsymbols | status: UNVERIFIED | evidence refs: []\n```\n\nFor each obligation, record:\n\n- source,\n- exact claim,\n- affected files or symbols,\n- verification status: `UNVERIFIED → IN_PROGRESS → MET \u002F PARTIALLY_MET \u002F NOT_MET \u002F UNVERIFIABLE`,\n- linked finding ID when unmet,\n- reason if unverifiable.\n\nTests are claims. A passing or added test does not prove the obligation unless the reviewer inspects the assertion strength and relevant code path.\n\n### Quantitative claim verification\n\nPR body numerical claims (test counts, coverage percentages, assertion counts, performance benchmarks) are obligations, not proof. For each quantitative claim:\n\n1. Extract the claim and its source (PR body, comment, commit message).\n2. Verify against actual tool output or CI artifacts when available.\n3. If the claim cannot be independently verified, mark the obligation `UNVERIFIABLE` with reason.\n4. If the claim is disproved by evidence, create a finding linking the discrepancy.\n\nCommon patterns to verify:\n- \"N tests pass\" → count actual test results from CI logs or test runner output\n- \"N% coverage\" → compare against coverage report\n- \"No regressions\" → verify against test runner failure count\n\n---\n\n## Phase 2: Deterministic Signal Ingestion\n\nIngest deterministic signals as candidate generators. They are never final findings.\n\nUse available local artifacts first. Run safe read-only or standard project validation commands only when appropriate for the environment.\n\nCandidate signal sources include:\n\n- CI failures and logs,\n- test failures,\n- coverage delta,\n- lint\u002Ftypecheck\u002Fbuild output,\n- `git diff --check`,\n- dependency audit output,\n- lockfile diff,\n- CodeQL alerts,\n- Semgrep or SAST findings,\n- secrets scan findings,\n- license scan findings,\n- mutation testing output,\n- package manager warnings,\n- generated schema diffs.\n\nRecord each signal as:\n\n```text\n[TOOL_CANDIDATE] | tool | severity | file:line | claim | raw_signal_summary | confidence\n```\n\nTool candidate rules:\n\n- Confirm reachability before reporting.\n- Confirm PR-introducedness before reporting as a PR blocker.\n- When `placeholder_scan` output is used as a signal, pass `added_lines` (file path → PR-added line numbers from the merge-base diff) so only added lines drive the scan; a placeholder finding on an unchanged line is a pre-existing-debt candidate, not a PR blocker. If added-line mapping is unavailable, treat the findings as unscoped and cross-check them against the PR diff before recording the row.\n- Confirm that a framework, schema, middleware, caller guard, or test isolation rule does not already mitigate it.\n- Do not report scanner output verbatim without reviewer validation.\n- Redact secrets; never paste raw credentials into the final output.\n\n---\n\n## Phase 3: Parallel Base Explorer Lanes\n\n### Review depth tiers (size × risk)\n\nBefore dispatching, classify the PR into a depth tier from the context pack.\nRecord the tier and the active capability profile in the ledger and in the\nfinal validation provenance. The tier scales how many subagents you spawn —\nnever which review dimensions or risk families get evaluated:\n\n| Tier | Diff shape | Dispatch shape (Profiles B\u002FC) |\n|---|---|---|\n| S | ≤ ~100 changed lines, ≤ 5 files, no risk triggers | Consolidate: 1–2 explorer lanes covering all six dimensions (B), or one candidate-generation pass (C); Phase 4 risk families fold into the same lanes as an explicit per-family checklist |\n| M | ≤ ~1500 changed lines, or any risk trigger | Dedicated lanes for the triggered dimensions\u002Ffamilies; consolidate the remaining thin dimensions into 1–2 lanes |\n| L | > ~1500 changed lines, > ~50 files, multi-subsystem, or security-sensitive surface | Full fan-out: one lane per dimension (six) and per-family micro dispatch in Phase 4 |\n\nRisk triggers (any one escalates to at least tier M, and the triggered\ndimension\u002Ffamily always gets a dedicated lane at M and above):\nauth\u002Fidentity\u002Fsessions\u002Fpermissions\u002Fsecrets\u002Fcryptography; untrusted-input\nparsing or new input\u002Foutput boundaries; subprocess\u002Fshell\u002Ffilesystem execution;\nconcurrency, state machines, retries, caching; dependency, lockfile, install,\nCI, or release changes; public API, schema, config, or migration changes;\npayments or PII handling; generated, vendored, or binary artifacts.\n\nScaling is one-directional: a larger tier or an active controller may demand\nmore lanes than the table; nothing — repository size, elapsed time, token\ncost, or predicted simplicity — permits fewer lanes than the classified tier,\nand no tier permits skipping a dimension or family. Under Profile A the\ncontroller computes the tier itself from the bound `base_sha...pr_head_sha`\ndiff (`--numstat` totals; an uncomputable diff fails strict to tier L) and\n mechanically enforces the matching floors on every base and micro batch. When a project explicitly enables the `pr_review_resilience` policy (it is\n DISABLED by default), the initial base wave is\n staged at tiers M\u002FL: `pr_review_wave_stage: \"canary\"` \u002F `pr_review_wave_attempt: 0`\n launches one singleton base lane first, then\n `pr_review_wave_stage: \"fanout\"` carries only the remaining unresolved\n obligations in exactly one follow-up fanout batch. Tier S keeps the legacy single\n consolidated base batch because staged resilience does not apply there. If\n that policy is disabled, the initial base wave falls back to the historical\n non-staged behavior: tier L may launch all six singleton base lanes together\n in one batch, while tiers S\u002FM may use consolidated lanes that declare their\n complete `owned_workflow_lanes` set — every dimension still owned exactly\n once and attested. Micro batches retain the historical tier-L full fan-out\n floor (one micro-lane per family on every micro batch, not only the first),\n while tiers S and M may consolidate families so long as every family is still\n owned exactly once and attested per family. With staged resilience enabled, a\n tier-L base **retry** may consolidate only dimensions that are still\n unresolved because their prior attempts reached a recorded terminal failure\n and no lane for that dimension is currently live or in flight, subject to two\n lane floors: no single lane may own all six dimensions, and — counted\n cumulatively across every recorded base batch, not per batch, and including\n batches the capacity GC has since dropped — the six dimensions must stay\n backed by at least four distinct lanes (each dimension no consolidated lane\n claims counts as one, plus the FEWEST declared consolidated lanes that\n suffice to cover the rest). That permits a small consolidation as failure\n recovery and rejects re-doing the whole wave in two or three lanes, whether\n the attempt is disguised as overlapping or duplicate consolidations —\n declaring more lanes than the cover needs buys no budget. Dimensions with a\n successful source are complete and MUST NOT be re-dispatched; dimensions with\n a live or in-flight source are not yet eligible for the retry set. The retry\n attempt itself still stays exactly one singleton canary call plus exactly one\n unresolved-only fanout call, never multiple fanout batches and never a fresh\n all-six singleton re-dispatch. Risk triggers\nremain caller-side escalation on every profile: dispatch MORE than the floor\nwhenever a trigger warrants it.\n\n### Dispatch\n\nUnder Profile A, dispatch base lanes with `dispatch_lanes_async`, set\n`mode: \"swarm-pr-review:base\"`, assign each lane its exact `workflow_lane`\nidentifier from the table below, bind every batch with the exact current\n`pr_head_sha`, record each returned `batch_id`, and pass the exact reviewed\nmerge base and its base ref as `base_sha` and `base_ref`. Use the\nREMOTE-TRACKING form for `base_ref` (`origin\u002Fmain`, not `main` or\n`refs\u002Fheads\u002Fmain`) and compute `base_sha` against that same ref, so the\ncontroller's recomputation matches yours. When a project explicitly enables the\n`pr_review_resilience` policy (DISABLED by default), tier-M\u002FL initial base dispatch is\n staged exactly as a singleton canary batch (`pr_review_wave_stage: \"canary\"`,\n `pr_review_wave_attempt: 0`) followed by exactly one fanout batch\n(`pr_review_wave_stage: \"fanout\"`) that include only still-unresolved\nobligations. Tier S stays on one consolidated batch. If the policy is\ndisabled, the legacy non-staged initial base wave is still valid: tier L may\npass all six singleton base specs together in one batch, while tiers S\u002FM may\npass the consolidated batch shape that partitions the same six dimensions.\nEvery later base retry, micro, council, reviewer, and critic dispatch repeats\nthose same exact bindings. The controller recomputes\n`git merge-base -- \u003Cbase_ref> \u003Cpr_head_sha>`, rejects mismatches, and replaces\ncaller `scope` text with the complete verified `base_sha...pr_head_sha` PR diff;\ncaller scope is retained only as a non-authoritative focus hint. Continue only non-dependent architect\nwork: refine the obligation ledger, inspect PR metadata, prepare micro-lane\ntrigger checks, and run deterministic read-only local tools. The runtime rejects\npartial, duplicate, mislabelled, or non-explorer base waves. Do not synthesize\nfindings from running lanes. Keep each lane `prompt` compact: send the shared\nreview context (PR diff, obligation ledger, scope) ONCE via the `common_prompt`\nfield, or have lanes read it from a file by absolute path, instead of inlining\nthe same large blob into all six prompts — oversized inline prompts produce\nmalformed or truncated tool-call JSON and force clumsy file workarounds.\n\nAll six dimensions must be covered on every PR — \"small PR\", \"docs-only\", and\n\"CI-only\" change what each dimension examines, never whether it is evaluated.\nEvery dimension ends in its own `[CANDIDATE]` rows or a fully populated\nper-dimension `[CLEAN]` attestation. Under Profile A, the top-level\n`pr_review_resilience` config (DISABLED by default; opt in with `enabled: true`) requires depth tiers M\u002FL to\nstage each base attempt as a singleton `pr_review_wave_stage: \"canary\"` batch\nfollowed by its matching `\"fanout\"` batch. Attempt 0 still has to cover all six\ndimensions exactly once across the combined canary+fanout ownership: tier M\nneeds at least three combined lanes, tier L needs six singleton combined lanes,\nand every later retry attempt may carry forward only the still-unresolved\nobligations into its canary\u002Ffanout pair. Use one singleton canary lane; attempts\nare numbered with `pr_review_wave_attempt`, and the\npolicy permits attempt 0 plus two retry attempts (1 and 2). If the project leaves\n`pr_review_resilience` at its default `enabled: false`, or the computed tier is S,\nProfile A uses the legacy single-wave base dispatch. Under Profiles B\u002FC, the\ndepth tier governs lane count the same way — a tier-S diff may cover the six\ndimensions in one or two consolidated lanes — while dimension coverage and\nper-dimension attestation remain mandatory.\n\nUnder Profile B, dispatch the same wave as parallel subagents through your\nharness's subagent tool: one subagent per dimension by default, consolidated\nper the depth tier for small diffs. Every lane prompt must carry the exact\n`pr_head_sha`, the verified `base_sha...pr_head_sha` range, its assigned\n`workflow_lane` identifier(s), and the explorer context contract below; append\nevery returned report to the findings ledger with its lane id and head SHA\nbefore any reviewer dispatch. Under Profile C, run the same lanes as\nsequential candidate-generation passes with the same per-lane ledger records.\nThe join barrier is universal: all base lanes settle before Phase 4 completes\nor synthesis begins, whichever layer enforces it.\n\n**Incremental collection (Profile A):** While base lanes are running, poll with `collect_lane_results` (without `wait` (or `wait: false`)) to check progress and process settled lanes as they complete — call `retrieve_lane_output` for full text when `output_ref` is present, then extract candidates via `parse_lane_candidates`, update the candidate ledger, validate output quality — while continuing independent architect work (obligation refinement, micro-lane trigger checks, local reads) between polls. Only use `wait: true` if lanes are still pending and no more independent work remains. While polling, a `pending_liveness` entry on a still-pending lane is a DIAGNOSTIC only (issue #2280): `stalledSuspect: true` means the lane has been pending for minutes and the host does not report its session live — note the lane id, `pendingMs`, and `hostStatus` and investigate, but never auto-cancel, retry, or replace the lane on this signal; read `degradedReason` precisely (issue #2815): `probe-skipped-no-budget` means the observer's own probe budget was already exhausted and NO host probe ran — it carries no information about the lane's session — while `probe-timeout` means a probe ran and hit its deadline; either way the ~30-minute presumed-stale sweep remains the only terminal backstop. Under Profile B, harvest each subagent report as it completes and update the ledger between arrivals; block on stragglers only when no independent work remains. **`collect_lane_results` is an OBSERVER (issue #2381).** Its wait budget (`timeout_ms`) bounds THAT CALL ONLY. An expired wait budget does not cancel, kill, or fail a lane, and it is not evidence that a lane died; `timeout_ms: 0` is a valid immediate, non-destructive snapshot, and an unavailable host messages client likewise reports stored lane state without terminalizing anything. Whenever lanes remain unsettled the result carries `pending_lanes` (batch id, lane id, stored status, and `output_ref` when one exists) regardless of `include_pending`, so outstanding work is never silently omitted. When a collection returns pending lanes you have exactly two observer moves: poll again, or let the ~30-minute presumed-stale sweep settle genuinely dead lanes. Explicit cancellation is a separate authorized action (`cancel_lane_batch` with `confirm: true` plus a reason); the collector itself never cancels, and busy\u002Fretry lanes are live evidence, not failure. Do NOT abort the PR workflow, re-dispatch the lane, or report a lane as failed merely because an observer call expired or the host client was briefly unavailable.\n\nInline `output` is delivered on the first poll that observes a lane settled; subsequent polls carry `output_omitted_repeat: true` with metadata and `output_ref`, and full text is retrieved via `retrieve_lane_output`.\n\nHost transport metadata is not stronger than the durable artifact. A truncated inline preview is accepted when its full `output_ref` artifact passes every identity, digest, revision, ownership, and row-coverage check. If the host status call times out, collection treats readiness as unknown and may inspect messages under a separate bounded budget, but it settles the lane only when the latest assistant message carries terminal proof. Only base and micro discovery lanes may retain independently validated positive `[CANDIDATE]` coverage from an incomplete transcript; council, reviewer, and critic outputs remain fail-closed and require retry. Incompleteness can never establish `[CLEAN]`, including for sibling dimensions in a consolidated lane. Every accepted transport recovery is disclosed in `salvaged_workflow_lanes`, with typed per-lane reasons in `salvaged_workflow_lane_recoveries`. See `references\u002Flane-output-recoverability.md`.\n\nBefore Phase 4 or synthesis, all base lanes must be settled. `dispatch_lanes_async` accepts a maximum of 8 lanes per call; base lanes (6) and micro-lanes (Phase 4) are dispatched in separate calls by design. Do not let one lane's conclusions bias another lane.\n\n**COVERAGE GATE — zero tolerance for unclosed gaps.** After `collect_lane_results`, verify every lane produced validated output. Two failure modes exist:\n- **Mode A (empty output):** Lane returns 0 chars, `status: cancelled`, `output_digest` matches SHA-256 of empty string (`e3b0c442...b855`).\n- **Mode B (invalid structured output):** Under Profile A, collection reports `status: failed` with a named contract predicate while retaining the non-empty preview, digest, and `output_ref`; the artifact has zero valid `[CANDIDATE]` rows and no parseable `[CLEAN] | lane | coverage_scope | evidence` attestation. Under Profiles B\u002FC, treat the equivalent non-empty report as failed when parsing yields zero candidates and no valid clean attestation. The non-empty transcript is diagnostic evidence, never coverage proof.\n\nFor ANY lane that failed (either mode):\n1. **Retry** (initial dispatch plus 2 retries — PR_REVIEW_MICRO_FAMILY_RETRY_BUDGET; each micro-family dispatch acknowledgment records one counted attempt in gate state) with materially different parameters — different session or prompt decomposition, while preserving the required structured async mode and exact head provenance.\n2. If a base lane fails under Profile A, retry only the unresolved `workflow_lane` identifiers with `dispatch_lanes_async`, `mode: \"swarm-pr-review:base\"`, the same exact `pr_head_sha`, explorer agents, and the staged-resilience fields when that policy is enabled: a singleton `pr_review_wave_stage: \"canary\"` first, then a matching `\"fanout\"` batch only for the remaining unresolved obligations. The durable gate joins successful provenance across the initial wave and retry batches, carries unresolved obligations forward attempt by attempt, and rejects typed `retry_exhausted` or `circuit_open` outcomes before any new lane is launched. While that controller is active, blocking `dispatch_lanes` and direct Task dispatch are not equivalent because they cannot satisfy the structured provenance gate. Under Profiles B\u002FC, retry only the failed `workflow_lane` identifiers with a fresh subagent or pass, the same exact `pr_head_sha`, and a materially different prompt decomposition.\n3. If no equivalent alternative can be verified AND every launched lane is terminal or explicitly cancelled, **settle N-of-6 truthfully (issue #2383)** instead of discarding validated work: admit the terminal settlement with `write_pr_review_artifact` (`kind: \"findings\"`, `boundary: \"post_explorer\"`, the sentinel `CLEAN-REVIEW` record when no candidates exist, and `partial_base_coverage: { unresolved_dimensions: [\u003Cexactly the dimensions that are not covered>] }`), run the remaining phases over the covered dimensions' findings, and complete with `complete_pr_workflow` carrying the verdict the settlement allows. NEVER fabricate coverage, NEVER present an unresolved dimension as reviewed, and NEVER let a partial report approve.\n4. **Terminal report kinds (issue #2383):** all six dimensions covered → `COMPLETE` (verdict may be APPROVE, REQUEST_CHANGES, or INCOMPLETE); at least one covered → `PARTIAL` (verdict must be REQUEST_CHANGES or INCOMPLETE; validated findings from covered dimensions remain publishable); zero covered → `NO_COVERAGE` (skip the findings ladder entirely, call `complete_pr_workflow` with `report_verdict: \"INCOMPLETE\"` directly — the completion returns a truthful operational report with per-dimension reasons and never claims a code-quality review). A still-live lane blocks settlement: poll again, authorize an explicit `cancel_lane_batch` (`confirm: true` + reason; busy\u002Fretry lanes are refused), or let the presumed-stale sweep settle it first.\n5. Under Profile A, when the bind\u002Fcheckout path itself is genuinely unreachable or the workflow is publication-armed and exact publication cannot proceed, use the bounded recovery exits: `abort_pr_workflow` with `mode: \"PR_REVIEW\"`, `kind: \"recovery\"`, and a non-empty one-line `reason` for an unrecoverable unbound\u002Fbound gate, or `kind: \"armed_recovery\"` (issue #2383) for a publication-armed wedge — then `prepare_pr_workflow_checkout` with `operation: \"restore\"`. Abort remains a recovery tool for the genuinely unrecoverable, never a shortcut past a settleable coverage obligation.\n\n### PARTIAL-settlement recovery (all lanes terminal)\n\nBase settlement requires every launched lane to be TERMINAL — settled, failed,\nor explicitly cancelled — NOT full coverage. With partial coverage (at least one\ndimension covered), the review proceeds instead of aborting: dispatch the FIRST\n`swarm-pr-review:micro` batch with the complete 11-row `trigger_evaluation`\nparameter inline on `dispatch_lanes_async` (that dispatch freezes the canonical\nledger), persist it with `write_pr_review_trigger_eval`, run the validation\nlanes, then finish with `complete_pr_workflow` carrying the verdict PARTIAL\ncoverage allows (REQUEST_CHANGES or INCOMPLETE — never APPROVE). The\nNO_COVERAGE short-circuit applies only at zero coverage. A\n`write_pr_review_trigger_eval` rejection saying the canonical ledger is missing\nmeans the first micro dispatch has not frozen it yet — supply the inline\nparameter; it is not a deadlock.\n\n### Contract-failure diagnosis and recovery\n\nUnder Profile A, `dispatch_lanes_async` adds the authoritative\ncontroller-appended row contract and exact lane identity to every explorer\nprompt. Do not duplicate that contract in `common_prompt`: duplicated copies\ncan drift, compete for prompt budget, and are not the controller's acceptance\nboundary.\n\nWhen collection or a later coverage gate rejects a lane, first isolate the\nemitting validator named by the diagnostic. Preserve the rejected artifact and\nbuild a minimal correct single-lane reproduction using the same workflow mode,\nlane identity, exact head, and canonical row. Before retrying, distinguish the\nthree independent input layers: the header schema, data-row values, and tool\nargument shape. A correct header does not repair an invalid severity or lane\nvalue, and correct row data does not repair malformed dispatch JSON. Benign shape defects (evidence pipes, marker rows, verdict-row pipes, a header re-emitted as a data row) are auto-repaired and recorded as salvage — never a retry reason alone; the `parse_lane_candidates` receipt discloses them as `repair_kinds`, and a `[CLEAN]` attestation discredited beside a same-lane `[CANDIDATE]` row as `clean_attestation_salvaged` + `clean_attestation_salvage_reason` (the parse SUCCEEDS and the attestation still supplies no coverage) (contract and fidelity boundaries: `references\u002Flane-output-recoverability.md`).\n\nClassify incidents from actual user-visible harm and the first failed predicate; the shared\nrow parser proves row structure only, a post-hoc fallback is recovery evidence, and the\ngate separately verifies durable provenance (see `references\u002Flane-output-recoverability.md`).\n\nIf a controller denial omits the failed predicate, expected contract, or lane\nidentity, record that as an opacity defect and escalate it with the preserved\nartifact and minimal reproduction. An opaque denial is not proof that correct\ninput was rejected. Do not guess at hidden predicates, weaken acceptance, or\nswitch to blocking\u002Fdirect-Task dispatch; repair the named contract when it is\navailable, otherwise stop at the coverage gate with the diagnostic gap.\n\n### Candidate extraction via parser\n\nUnder Profile A, after `collect_lane_results` returns for base lanes, process\neach lane result that carries an `output_ref`. The orchestrator MUST use the\ncandidate parser rather than preview-text extraction:\n\n1. For each singleton base `output_ref`, call `parse_lane_candidates` with\n   `output_ref`, `producer: \"swarm-pr-review\"`,\n   `expected_family: \"base_explorer\"`, and `expected_lane` set to the exact\n   `workflow_lane` declared at dispatch. For a consolidated tier-S\u002FM lane, call\n   the parser once for each owned dimension with that dimension as\n   `expected_lane` and pass `expected_lanes` as the lane's complete\n   `owned_workflow_lanes` array on every call. The parser reads the full artifact\n   from disk (no preview truncation issue), rejects unowned rows, and returns\n   structured `ParseResultWithSidecar` records.\n2. Filter the returned `candidates[]` by `producer: \"swarm-pr-review\"` plus the\n   exact `source_batch_id` and `source_lane_id` from the base dispatch. Treat a\n   family mismatch or parse error as a lane-output failure; family metadata is\n   not the acceptance boundary.\n3. Group the filtered candidates into reviewer-sized chunks:\n   - by file area (group by the directory or module of the `file_line` field),\n   - by category (group by the `category` field),\n   - by count (target max 50 candidates per chunk; smaller chunks are fine).\n4. Stage reviewer-sized chunks, but do not dispatch reviewers yet. Phase 4 must\n   complete trigger accounting and settle every launched micro-lane first.\n\nIf a lane has `output_degraded: true`, no usable `output_ref`, or `transcript_incomplete: true` without typed positive-candidate recovery, apply the COVERAGE GATE (Phase 3). An incomplete base or micro discovery lane may proceed only when it is explicitly named by a `salvaged_workflow_lane_recoveries` entry whose `kind` is `transcript-incomplete-terminal-candidate`; that recovery validates the retained positive `[CANDIDATE]` row only. Council, reviewer, and critic lanes never qualify for this incomplete-transcript recovery and must retry. Recovery never validates `[CLEAN]`, candidate absence, an unowned sibling lane, or an incomplete lane with no matching entry. Do not use blocking or direct-Task fallbacks while the controller is active, mark affected candidates UNVERIFIED to proceed, or infer candidate absence from a preview. Under Profiles B\u002FC, which have no typed recovery validation, a truncated, incomplete, empty, or attestation-free subagent report is the same lane-output failure and takes the same COVERAGE GATE.\n\nAfter candidate parsing and before reviewer dispatch, persist the post-explorer\ncandidate ledger. The base-only write is admissible immediately after base\nsettlement — it is the durable recovery point for context compaction from base\nsettlement onward; once trigger evaluation completes, a full-inventory\n(base+micro) `post_explorer` write may refresh it ahead of Phase 6.\n\n**Profiles B\u002FC row convention:** without the parser, the `[CANDIDATE]` row\nformat is the extraction contract itself. Explorers emit the rows directly in\ntheir reports (see the Explorer Prompt Template reference); the orchestrator\ncollects them verbatim, validates each row's field count and lane id, and\ntreats malformed rows — or output with neither `[CANDIDATE]` rows nor a fully\npopulated `[CLEAN]` attestation — as a lane-output failure under the COVERAGE\nGATE. If the parser is unavailable under Profile A, the same row convention\napplies as a fallback, but the orchestrator SHOULD use the parser as the\nprimary extraction mechanism.\n\n**lane id uniqueness for parallel dispatches:** When re-dispatching failed or\nre-running explorer lanes, every `dispatch_lanes_async` or `dispatch_lanes`\nlane `id` MUST be unique within that dispatch batch and should include lane and\nattempt suffixes (e.g., `pr_review_explore_lane1_attempt2`). Never reuse an id\nin the same batch unless intentionally replacing that exact lane before dispatch.\n\nExplorers optimize for recall. Over-reporting is expected. Explorers produce candidates only.\n\nThe six dimensions are a fixed **check-type** partition, not an area\npartition: every PR needs all six review dimensions, and the lanes\ndeliberately overlap by file, each receiving the same diff (via\n`common_prompt` under Profile A) and viewing it through a different lens. Six\ndimensions are this workflow's high-assurance coverage floor, not a claim that\nresearch proves a universal optimal agent count — the published evidence\nfavors complementary, distinct-lens reviewers over duplicated generalists, and\nfinding rates rise with diff size, which is why dispatch (not coverage)\nfollows the depth tier. Repository policy may add scrutiny but may never\nreduce the six dimensions. Coverage is guaranteed by all six dimensions\nreading the whole diff, so the disjoint-partition rule that governs area-split\nfan-outs does not apply.\n\n| `workflow_lane` | Focus | Required checks |\n|---|---|---|\n| `intent-architecture` | Intent, scope, architecture, and integration | obligation mapping, design fit, callers\u002Fconsumers, sibling patterns, docs and claimed-vs-actual behavior |\n| `correctness-state` | Functional correctness, data\u002Fstate flow, edge cases, and failure paths | input domains, nullability, ordering, transactions, error behavior, rollback, backwards behavior |\n| `tests-falsifiability` | Tests, test validity, regressions, and claimed validation | assertion strength, negative paths, isolation, fixtures, deterministic timing, missing proof |\n| `security-trust` | Security, privacy, trust boundaries, unsafe inputs\u002Fsinks, and supply chain | authorization, injection, secrets, provenance, dependency risk, data exposure, abuse paths |\n| `reliability-performance` | Reliability, concurrency, retries, resource bounds, and performance | races, retry semantics, timeouts, lifecycle, caching, algorithmic cost, operational failure modes |\n| `compatibility-delivery` | API\u002Fschema\u002Fconfig compatibility, maintainability, build\u002Fdeploy, docs, and release behavior | public contracts, migrations, runtime\u002Fplatform support, packaging, CI, rollout and recovery guidance |\n\n### Explorer context contract\n\nEvery explorer must inspect or explicitly mark unavailable:\n\n1. the changed hunk,\n2. at least one caller, consumer, or downstream impact-cone node,\n3. at least one callee, dependency, or upstream assumption,\n4. at least one sibling implementation or prior pattern,\n5. the nearest relevant test or missing-test location,\n6. deterministic signal entries mapped to its files\u002Fsymbols,\n7. relevant Swarm knowledge\u002Fevidence entries, if present.\n8. the exact bound review range to analyze (`base_sha...pr_head_sha`),\n\n### Explorer output format\n\nExplorers emit structured candidate records. The parser reads the full lane\nartifact and extracts these records. The canonical record shape is:\n\nThe fence below is documentation formatting only. Emit the header and all\nmachine-readable rows as unfenced plain text; do not emit the backticks.\n\n```text\n[CANDIDATE] | candidate_id | lane | severity | category | file:line | claim | evidence_summary | impact_context | confidence | risk_impact | risk_tags\n```\n\nProfile A now treats `submit_pr_review_result` as the authoritative settlement path for base and micro discovery lanes. The caller-bound structured receipt dominates later prose, truncation, or transcript incompleteness. Transcript candidate\u002Fclean rows remain deprecated compatibility only when `pr_review_legacy_transcript_compatibility` was explicitly enabled for that lane and no structured receipt exists; a present-but-invalid structured result fails closed and never falls back.\n\nWhen compatibility mode is active, Profile A stores the full assistant transcript. The parser locates the first pipe-delimited line whose first field is exactly `[CANDIDATE]`, ignores unmarked preamble, and requires the exact canonical base\u002Fmicro header; malformed markers or marker-prefixed rows without a header fail closed. The controller refuses a missing marker. Markerless positional fallback remains only for legacy callers outside that trust boundary; explorers should put the canonical header first.\n\nThe confidence data value must be exactly LOW, MEDIUM, or HIGH.\n\nUnder Profile A the parser-backed transcript path is compatibility-only; a successful `submit_pr_review_result` receipt is authoritative. On Profiles B\u002FC — and on a Profile A lane whose snapped contract explicitly enables deprecated legacy transcript compatibility and lacks a structured receipt — the explorer emits `[CANDIDATE]` rows directly as the extraction contract.\n\nExplorers must not use `CONFIRMED`, `DISPROVED`, or `PRE_EXISTING`.\n\nA base lane that finds no surviving candidates must submit exactly one structured CLEAN result and then stop. Only a lane in the deprecated transcript-compatibility path may instead emit exactly one fully populated clean row:\n\nThe fence below is documentation formatting only. Emit the clean attestation\nas unfenced plain text; do not emit the backticks.\n\n```text\n[CLEAN] | lane | coverage_scope | evidence\n```\n\nHeader-only `[CLEAN]` markers, prose-only \"clean\" claims, or empty output do\nnot settle the lane.\n\n---\n\n## Phase 4: Mandatory Repository-Agnostic Micro-Lanes\n\nAfter base lanes settle, inspect the exact diff\u002Fcontext pack to focus every row\nin the micro-lane map and print a mandatory ledger with one row per map row:\n\n```text\n[TRIGGER-EVAL] | trigger_row | MATCHED\u002FNOT_TRIGGERED | focus_evidence\n```\n\nFocus evidence must name the changed files, manifests, imports\u002Fsymbols, semantic\nsignals, or explicit absence conditions. Use `MATCHED` when the exact diff has\nan applicable surface and dispatch that family; use `NOT_TRIGGERED` only when\nthe row was evaluated and concrete absence evidence proves it inapplicable.\n`unclassified-risk` is the always-`MATCHED` fallback. A `NOT_TRIGGERED` row is\nnot a waiver or a micro artifact and carries no source batch\u002Flane provenance.\nRepository identity, technology stack, PR size, elapsed time, or predicted risk\nnever justifies skipping a row.\n\nEvery row in the map is a risk **family** that must be evaluated against the\ndiff on every PR, in every repository. What scales with the depth tier is the\ndispatch shape — how many subagents carry that evaluation — never the\nevaluation itself. Each `MATCHED` family must end in its own attestation:\n`[CANDIDATE]` rows naming the family, or one fully populated per-family\n`[CLEAN]` row. `NOT_TRIGGERED` families end in the ledger with absence evidence\nand must not be dispatched.\n\n**Profile A dispatch.** Launch the micro coverage with\n`dispatch_lanes_async` and `mode: \"swarm-pr-review:micro\"`. At depth tier L,\ndispatch one focused micro-lane for every `MATCHED` row, each lane's\n`workflow_lane` equal to its trigger ID; because the dispatcher accepts at\nmost eight lanes per call, split large matched sets across bounded async\nbatches. At tiers S and M,\nconsolidated lanes may each own several families: set `workflow_lane` to one\nowned trigger ID and declare the complete `owned_workflow_lanes` set — every\nmatched family owned exactly once across the dispatch, and every owned family\nattested in that lane's output, or the lane fails for all of them. Include\nthe complete exact-set\n`trigger_evaluation` ledger and the same exact current `pr_head_sha` in the\ninitial micro dispatch, in a separate batch from base lanes (those inline `trigger_evaluation` rows carry only `trigger_id`, `result`, and `evidence` — they must never include `source_batch_id` or `source_lane_id`, which belong only to `write_pr_review_trigger_eval`'s `rows`). That first\ndispatch freezes the ledger for the session. A subsequent same-session micro\nbatch may omit `trigger_evaluation` and reuse the frozen ledger; when it\nexplicitly supplies a copy, the copy must remain exactly identical. The\nruntime rejects unrelated or duplicate micro-lanes within a batch, and final\nledger persistence rejects any row whose completed owning-lane provenance is\nabsent. One bounded exception (issue #2835): a sweep-settled liveness-terminal lane may back a `MATCHED` row as a disclosed dead family (never APPROVEable; cancellations never qualify) — conditions in `references\u002Flane-output-recoverability.md`.\nPoll incrementally, then settle every launched lane. Persist\nthe complete ledger with `write_pr_review_trigger_eval`; its rows use the stable\ntrigger IDs below. Every `MATCHED` row includes its returned `source_batch_id`\nand `source_lane_id`; every `NOT_TRIGGERED` row must omit both fields. Missing,\nextra, duplicate, malformed, or incorrectly provenanced rows make persistence\nfail and Phase 4 BLOCKED. Evidence is frozen by the first micro dispatch and is\nauthoritative thereafter. The final writer may omit its duplicate `evidence`\nfields; if it includes reworded evidence, the writer ignores that copy and\npersists the frozen values. It still requires the exact frozen classifications,\nplus provenance for every `MATCHED` row. The tool atomically writes\n`.swarm\u002Fpr-review\u002F\u003Crun_id>\u002Ftrigger-eval.json`, separate from `findings.jsonl`;\npass the exact reviewed merge-base as `base_sha`, the exact live base branch\ntip\u002Fref used to compute it as `base_ref`, and the same `pr_head_sha` to the\nwriter. The writer runs bounded `git merge-base -- \u003Cbase_ref> \u003Cpr_head_sha>` and\nrejects any claimed `base_sha` that is not the exact result. When that bounded re-check is unavailable (git timeout, spawn failure, unresolvable ref) but the supplied `base_ref` and `base_sha` exactly equal the durably bound review scope, the writer proceeds and discloses `base_verification: bound_fallback` on the receipt, which synthesis must surface in the final review report (`references\u002Flane-output-recoverability.md`); every other outcome stays fail-closed. It accepts only an\nexact eleven-row v2 receipt backed by verifiable provenance (identity, ownership, digest, retained artifact); a coverage-QUALITY failure is disclosed on the receipt as `coverage_degradations` and the run proceeds, with synthesis disclosing degraded families — unless the family is receipt-settled, in which case it is recorded as `receipt_covered_families` (never a degradation) and synthesis discloses it as receipt-covered (`references\u002Flane-output-recoverability.md`). `NOT_TRIGGERED` rows are provenance-free. Counts are recomputed and\nmust agree. It never uses keyword or path classification alone as absence\nevidence. Any head mismatch makes persistence fail. Historical unversioned and\nschema-v1 all-`MATCHED` receipts remain readable, but new writes are strict v2.\nDo not add trigger results to the finding-status enum.\n\n**Profiles B\u002FC dispatch.** Scale the lane shape to the depth tier while\nkeeping all eleven family evaluations:\n\n- Tier L: one focused lane per `MATCHED` family, mirroring Profile A.\n- Tier M: dispatch the `MATCHED` families across at least the controller's\n  matched-set consolidation floor; `NOT_TRIGGERED` rows remain ledger-only.\n- Tier S: dispatch the `MATCHED` set in one or more consolidated micro lanes or\n  sequentially separated passes; keep `NOT_TRIGGERED` rows ledger-only.\n\nWhatever the dispatch shape: the ledger keeps one `[TRIGGER-EVAL]` row per\nfamily; each `MATCHED` row's focus evidence names the lane or pass that\nevaluated it and gets its own `[CANDIDATE]`\u002F`[CLEAN]` attestation naming the\nfamily id; each `NOT_TRIGGERED` row records absence evidence without an\nartifact; and the completed ledger is persisted as `trigger-eval.json` in the\nsession\u002Ftask workspace before reviewer dispatch. A matched family with no\nattestation row is an unclosed coverage gap.\n\nFor each micro lane in Profile A, prefer the single structured\n`submit_pr_review_result` receipt over transcript parsing. Only for a lane\nwhose snapped contract explicitly enables deprecated transcript compatibility\nand lacks a structured receipt should you fall back to `parse_lane_candidates` against its `output_ref`, with\n`producer: \"swarm-pr-review\"`, `expected_family: \"micro_lane\"`, and\n`expected_micro_lane` set to the launch-micro-lane value from the\nprovenance-linked trigger row. When the artifact came from a consolidated\ntier-S\u002FM lane (its dispatch declared more than one `owned_workflow_lanes`\nentry), also pass `expected_micro_lanes` set to that lane's complete\n`owned_workflow_lanes` array — the same set already declared at micro\ndispatch time. Without it, the parser has no way to tell a sibling owned\nfamily's row from a genuinely out-of-scope one: every row belonging to the\nlane's other owned families is treated as a parse error instead of being\nskipped as out-of-scope, which can also invalidate that lane's own otherwise-valid\n`[CLEAN]` attestation for the family being extracted. Omit `expected_micro_lanes`\nonly for a singleton (tier-L) lane. Accept a candidate only when its `producer`,\n`source_batch_id`, and `source_lane_id` match an allow-listed tuple from the\noriginal or retry micro dispatch and its `micro_lane` matches that trigger row;\nnever filter acceptance by `row_format_family`. A zero-candidate artifact is\nclean only when the parser returns exactly one provenance-matching persisted\n`clean_attestation` whose `micro_lane` matches the trigger row, zero parse\nerrors, zero malformed rows, and a complete, non-degraded source:\n\n```text\n[CLEAN] | micro_lane | coverage_scope | evidence\n```\n\nHeader-only or malformed zero output is `UNATTESTED`; apply the COVERAGE GATE (Phase 3). Under Profile A, the structured async PR-workflow path must preserve `L1`, exact-head, batch, and workflow-lane provenance; the active controller rejects blocking and direct-Task substitutes, and Task-derived findings or CLEAN prose cannot satisfy Phase 4's controller ledger unless the lane explicitly runs deprecated transcript compatibility. Under Profiles B\u002FC, acceptance is the row contract: accept a candidate or clean row only when its `micro_lane` matches the trigger row, and treat prose-only \"clean\" claims as `UNATTESTED`.\n\nEach micro-lane receives:\n\n- exact files and hunks in scope,\n- related obligations,\n- impact cone entries,\n- relevant deterministic signals,\n- related historical knowledge with quarantine\u002Fstaleness status,\n- expected invariants,\n- structured candidate output — parser-extracted under Profile A; on Profiles\n  B\u002FC the micro-lane emits `[CANDIDATE]`\u002F`[CLEAN]` rows directly as the\n  extraction contract.\n\n### Repository-agnostic mandatory micro-lane map\n\nEvery row is evaluated in every repository. Diff\u002Fcontext analysis determines\nwhether it is `MATCHED` or `NOT_TRIGGERED`; paths or keywords alone are not\nsufficient absence evidence. Repository policy\nmay require supplementary specialist review outside this canonical ledger, but\nsupplementary work never replaces these portable rows. The `unclassified-risk`\nfamily is always `MATCHED` to cover novel failure modes and classification gaps.\n\n> **Trigger-ID namespace — do not mix (issue #1931).** The `trigger_id` field\n> passed to `write_pr_review_trigger_eval` accepts **only** the 11 micro-lane\n> IDs in the table below. Three different namespaces appear in this skill and\n> they are NOT interchangeable:\n>\n> | Namespace | Example values | Used where? | Valid as `trigger_id`? |\n> | --- | --- | --- | --- |\n> | Micro-lane IDs (this table) | `auth-identity-secrets`, `untrusted-input-boundaries`, ... | `workflow_lane` of `swarm-pr-review:micro` dispatch; `trigger_id` of trigger-eval rows | **YES — only these** |\n> | Base-lane IDs | `intent-architecture`, `correctness-state`, `tests-falsifiability`, `security-trust`, `reliability-performance`, `compatibility-delivery` | `workflow_lane` of `swarm-pr-review:base` dispatch; validated by `enforcePrReviewBaseDimensions` | NO |\n> | Dispatch modes | `swarm-pr-review:base`, `swarm-pr-review:micro`, `swarm-pr-review:reviewer`, `swarm-pr-review:critic` | `mode` field of `dispatch_lanes_async` | NO |\n>\n> The writer rejects unknown trigger IDs with the list of valid IDs. Short\n> informal names (`correctness`, `security`, `deps`, `docs`, `tests`, `perf`)\n> sometimes appear in prose summaries; they are shorthand, not literal IDs.\n\n| Trigger ID | Scope | Trigger in diff or context pack | Launch micro-lane | Invariants to check |\n|---|---|---|---|---|\n| `auth-identity-secrets` | universal | authentication, authorization, identity, sessions, permissions, secrets, cryptography | Identity and secret boundaries | least privilege, confused-deputy paths, credential lifecycle, cryptographic misuse, safe defaults |\n| `untrusted-input-boundaries` | universal | parsing, serialization, queries, templates\u002Frendering, file or network input\u002Foutput | Untrusted input and sink analysis | injection, traversal, SSRF, unsafe deserialization, output escaping, resource limits |\n| `subprocess-platform` | universal | subprocesses, shell commands, filesystem operations, OS\u002Fruntime-specific code | Subprocess and platform safety | array argv, bounded execution, path containment, portability, cleanup, non-interactive behavior |\n| `concurrency-state` | universal | queues, caches, retries, transactions, locks, state machines, async coordination | Concurrency and state transitions | races, atomicity, idempotency, retry accounting, rollback, stale state, bounded growth |\n| `dependencies-build-release` | universal | dependency manifests, lockfiles, installers, build scripts, CI, packaging, deployment | Dependency and delivery integrity | provenance, version\u002Flock consistency, install safety, platform matrices, rollback and release completeness |\n| `api-schema-migrations` | universal | public API, wire\u002Fschema\u002Fconfig\u002Fstorage formats, migrations, feature flags | Compatibility and migration safety | backward\u002Fforward compatibility, defaults, validation, mixed-version operation, recovery |\n| `test-infrastructure` | universal | tests, mocks, fixtures, harnesses, coverage, CI matrices | Test validity and isolation | meaningful assertions, contamination, determinism, negative paths, cross-platform proof, test theater |\n| `ui-accessibility-i18n` | universal | user interfaces, interaction flows, rendering, accessibility, localization | UI and human-interface quality | keyboard\u002Fscreen-reader behavior, focus, error states, responsive behavior, locale-safe formatting |\n| `privacy-observability` | universal | telemetry, logs, analytics, traces, retention, diagnostics | Privacy and observability safety | minimization, redaction, consent, retention, stable metrics, non-gameable evidence |\n| `generated-provenance` | universal | generated, vendored, binary, model-produced, codegen or checked-in build artifacts | Generated artifact provenance | reproducibility, source linkage, tamper evidence, reviewable diffs, licensing and stale output |\n| `unclassified-risk` | universal | any changed artifact or behavior not confidently classified by the rows above | Unclassified high-risk fallback | full change-path review, hidden trust boundaries, novel failure modes, missing specialist classification |\n\nMicro-lane output format:\n\nThe fence below is documentation formatting only. Emit the header and all\nmachine-readable rows as unfenced plain text; do not emit the backticks.\n\n```text\n[CANDIDATE] | candidate_id | micro_lane | severity | category | file:line | claim | invariant_violated | evidence_summary | confidence | risk_impact | risk_tags\n[CLEAN] | micro_lane | coverage_scope | evidence\n```\n\n---\n\n## Phase 5: Swarm-Native Verifier Routing\n\nUse Swarm-native agents and artifacts when available. If exact agent names are unavailable, route the same task to the closest equivalent reviewer\u002Fcritic role. On harnesses without the plugin, most `.swarm\u002F` artifacts will not exist: mark those rows N\u002FA in the validation provenance rather than fabricating them.\n\n| Swarm verifier \u002F artifact | When to use | Purpose |\n|---|---|---|\n| `critic_drift_verifier` | obligation-vs-code, docs-vs-code, phase\u002Fgate changes, schema\u002Fconfig changes | detect drift between stated behavior and actual implementation |\n| `critic_hallucination_verifier` | external APIs, package claims, URLs, CLI flags, GitHub behavior, model\u002Ftool names | verify claims against source or mark as unverified |\n| `curator_phase` | before exploration and after synthesis | retrieve relevant lessons; write back confirmed true positives \u002F false positives |\n| `test_engineer` | confirmed\u002Fborderline correctness, security, state, schema, or config findings | propose or run falsification probes and regression tests |\n| `.swarm\u002Frepo-graph.json` | all nontrivial code changes | build impact cones and sibling-pattern checks |\n| `.swarm\u002Fevidence\u002F` | schema, phase, state, council, and guardrail changes | verify evidence compatibility and serialized provenance |\n| Tool-returned `.swarm\u002Fevidence\u002F` artifacts | after synthesis | record review quality only at paths actually returned by invoked evidence tools; never invent a metrics path |\n\nVerifier output is advisory until incorporated by the independent reviewer or critic.\n\n---\n\n## Phase 6: Independent Reviewer Confirmation\n\n**Reviewer-dispatch join barrier:** reviewer dispatch MUST NOT begin until the\nexact eleven-row micro-lane ledger is complete and persisted, every launched\n`MATCHED` micro lane is settled with its owned families attested or disclosed as a dead family on the trigger receipt (#2835), every\n`NOT_TRIGGERED` row has concrete absence evidence and no provenance, and every\naccepted micro result has parser-derived provenance (Profile A) or a valid\nCLEAN attestation.\n\nRoute candidates to reviewer subagents. The orchestrator routes candidates\nin bounded chunks produced by the candidate extraction in Phase 3-4. Each\nreviewer lane receives a bounded list of candidates from a single chunk — by\nfile area, category, or count — not the full candidate set. The reviewer must\nre-read the candidate's file:line evidence and relevant context pack entries\ndirectly.\n\nA reviewer or critic chunk may own any non-empty subset of the current\ninventory. On a retry, that subset may overlap prior successful work; the lane\ncontract is the assigned item set for that chunk, not a requirement to re-own\nthe full inventory every time.\n\nUnder Profile A, dispatch reviewer chunks with `dispatch_lanes_async`,\n`mode: \"swarm-pr-review:reviewer\"`, a unique non-empty `workflow_lane` per\nchunk, `review_item_ids` containing the exact candidate IDs assigned to that\nchunk, reviewer-role agents only, and the same exact `pr_head_sha`. The runtime\nrequires one parseable `[REVIEWED]` row for every structurally assigned ID; a\nsingle marker or partial subset cannot settle the lane. Direct Task\nreviewers are rejected by the active controller because they cannot carry the\ndurable batch and head provenance it requires. Under Profile B, dispatch each\nchunk to a fresh reviewer subagent — never the agent or conversation that\ngenerated the candidates — carrying the chunk's candidate IDs, the exact\n`pr_head_sha`, and the required checks below. Under Profile C, run a separate\nreviewer pass per chunk that re-reads every cited file:line before\nclassifying. The one-parseable-`[REVIEWED]`-row-per-assigned-ID contract is\nuniversal.\n\nUnder Profile A, for every structured PR-review dispatch, the runtime appends\nan authoritative controller block after caller-authored prompt text. It binds the exact\n`workflow_lane`, PR head, content revision, declared scope, and assigned item\nIDs and explicitly forbids speed\u002Ftime\u002Ftoken waivers. Caller prompt text cannot\noverride that block; output with placeholders, invented IDs, generic assurances,\nor evidence unrelated to the bound lane does not settle the artifact.\n\nReviewer ownership is not accepted as an architect assertion. Under Profile A,\nthe controller derives the immutable candidate inventory from the\nintegrity-checked base, mandatory micro-lane, and council artifacts; under\nProfiles B\u002FC, the orchestrator derives the same inventory from the persisted\nledgers. Either way, successful reviewer batches compose item by item: the\nunion of their accepted `review_item_ids` must equal that inventory exactly,\nwith the newest successful verdict winning for each item. If discovery produces\nno candidates,\nthe derived sentinel is `CLEAN-REVIEW`, which still requires one independent\nsemantic reviewer row (a fresh subagent on Profile B; a separate reviewer pass\non Profile C).\n\nCandidate IDs must therefore be globally unique across every discovery\nartifact in the run. Prefix IDs with the stable workflow-lane ID (or use\nanother deterministic globally unique scheme); duplicate IDs fail closed\ninstead of being silently merged.\n\n### Noise budget and universal validation\n\nBefore reviewer dispatch, the orchestrator may suppress candidates that match ANY of the following (each suppression still requires mandatory disclosure):\n- purely stylistic without correctness, security, test, maintainability, or user-impact implications,\n- exact duplicates of a candidate already queued for validation,\n- explorer-stated confidence=LOW with zero structural evidence (no file:line, no code path, no invariant reference).\n\nEvery suppressed candidate must appear in the final report under \"Suppressed Candidates\" with the reason. Suppression without disclosure is a hard rule violation.\n\n**All remaining candidates — regardless of severity — must be routed to independent reviewer validation.** Severity alone does not determine validation eligibility; it determines routing priority. A LOW-severity candidate with file:line evidence and a specific code path gets the same reviewer attention as a HIGH-severity candidate.\n\nCandidates not routed to reviewers must be listed as UNVERIFIED with reason in the validation provenance. Do not silently drop them.\n\n### Reviewer required checks\n\nFor each candidate, the reviewer must determine:\n\n- exact file:line evidence,\n- whether the issue is introduced by this PR or pre-existing,\n- reachability from realistic execution paths,\n- whether caller guards, schema validation, middleware, framework defaults, feature flags, or state-machine constraints mitigate it,\n- whether tests cover the negative path,\n- whether sibling files or docs must change together,\n- whether the severity is justified,\n- the smallest falsification probe that would prove or disprove it.\n\n### Reviewer classifications\n\n| Classification | Meaning |\n|---|---|\n| `CONFIRMED` | Evidence is real, reachable or structurally proven, and introduced or exposed by this PR |\n| `DISPROVED` | Candidate claim is incorrect, unreachable, mitigated, or based on a misunderstanding |\n| `UNVERIFIED` | Available evidence is insufficient to determine validity |\n| `PRE_EXISTING` | Issue exists on the base branch and is not materially worsened by this PR |\n\n### Evidence classifications\n\n| Type | Definition |\n|---|---|\n| `STRUCTURALLY_PROVEN` | File:line evidence directly demonstrates the bug or violated invariant |\n| `EXECUTION_PROVEN` | A test, trace, reproduction, or command demonstrates failure |\n| `STATIC_TRACE_PROVEN` | Static analysis plus reviewed path\u002Fcontext demonstrates reachability |\n| `PLAUSIBLE_BUT_UNVERIFIED` | Pattern suggests risk, but reachability or mitigation is unresolved |\n\nReviewer output format:\n\n```text\n[REVIEWED] | item_id | classification | evidence_type | severity | introduced_by_pr | file:line | rationale | probe | reviewer_notes | risk_impact | risk_tags\n```\n\nCLEAN-REVIEW sentinel and DISPROVED\u002FPRE_EXISTING row details: see\n`references\u002Fparser-dry-run.md`.\n\nEvery reviewer response must end with one parseable `[REVIEWED]` row per\nassigned candidate. A malformed `[REVIEWED]` row is not a verdict: re-dispatch\nwith the exact contract (max 2), then mark the reviewer dimension BLOCKED if no\nvalid row returns.\n\nAfter reviewer lanes settle, persist the post-reviewer finding ledger before\ncritic routing or synthesis. The artifact must preserve `CONFIRMED`,\n`DISPROVED`, `PRE_EXISTING`, and still-`PENDING` records with reviewer IDs and\nnext actions.\n\nCounterbalanced reviewer passes (#2906): when the candidate inventory holds more\nthan one item, dispatch the reviewer phase as two batches over the same inventory;\nthe controller alternates presentation order A (canonical) \u002F B (reversed), stamps\n`presentation_order` on each batch receipt, and marks each merged verdict\n`order_agreement` (agree\u002Fdisagree\u002Fsingle); unstable items are auto-flagged to the\ncritic and the report marks and counts them. Detail: references\u002Fcounterbalancing.md.\n\n---\n\n## Phase 7: Falsification Probe Requirement\n\nEach confirmed nontrivial finding must include at least one falsification artifact:\n\n- runnable failing command,\n- proposed regression test,\n- mutation that current tests fail to kill,\n- static-analysis trace,\n- minimal execution path,\n- exact reason no runtime probe is available.\n\nNontrivial means any finding that affects correctness, security, state transitions, write authority, git safety, config, schema\u002Fevidence integrity, model\u002Ftool permissions, external fetches, persistence, or user-visible behavior.\n\nA finding may still be reported without a runnable command if it is structurally proven, but the report must state why a runtime probe was not available.\n\n---\n\n## Phase 8: Critic Challenge\n\nRoute reviewer-confirmed CRITICAL and HIGH findings to a critic always. Route a MEDIUM finding only when its typed risk metadata says so (issue #2383): `risk_impact: \"HIGH_IMPACT\"`, or any `risk_tags` entry (`SECURITY`, `AUTH_PERMISSIONS`, `STATE_INTEGRITY`, `WRITE_PATH`, `EVIDENCE_INTEGRITY`, `GIT`, `CONFIGURATION`). An ordinary MEDIUM (`risk_impact: \"ORDINARY\"`, no tags) is NOT critic-routed. `risk_impact: \"UNKNOWN\"` always routes to critic — never guess impact you could not assess, and never let file paths, dimension names, or prose override the typed `risk_impact`\u002F`risk_tags` the reviewer row carries.\n\nThe controller derives critic ownership from the typed reviewer rows through the one shared production predicate; every newly written CONFIRMED finding must supply `risk_impact` and `risk_tags` (the write boundary rejects a CONFIRMED record without them, and unknown tag values fail the row). Completion is blocked until that exact derived inventory has valid critic rows — unless an admitted N-of-M verdict settlement (issue #3101) discloses a liveness-dead critic lane, whose receipt-backed CRITIC_UNAVAILABLE rows count as terminal settlements.\n\nReviewer and critic settlement MUST compose successful verdicts item by item\nacross complementary partial batches. The newest successful claim wins each\nitem; malformed or stale batches contribute nothing without erasing healthy\nsibling claims. Collection MUST validate exact lane ownership atomically, and\ncritic claims MUST bind to the exact reviewer row for their item. Settlement is\nitem completeness, not lane completeness. Follow the full retry, legacy,\nbinding, and diagnostic contract in\n[`references\u002Fverdict-settlement-contract.md`](references\u002Fverdict-settlement-contract.md).\n\nUnder Profile A, dispatch critic chunks with `dispatch_lanes_async`,\n`mode: \"swarm-pr-review:critic\"`, a unique non-empty `workflow_lane` per\nchunk, `review_item_ids` containing the exact finding IDs assigned to that\nchunk, critic-role agents only, and the same exact `pr_head_sha`. The runtime\nrequires one parseable `[CRITIC]` row for every structurally assigned ID and\nrequires the reviewer phase to have settled — every item in the current\ninventory holding a successful reviewer verdict, composed across batches —\nbefore a critic wave.\nUnder Profile B, dispatch each critic chunk to a fresh subagent that was\nneither the explorer nor the reviewer for those findings; under Profile C, run\na separate critic pass. The one-parseable-`[CRITIC]`-row-per-assigned-ID\ncontract and the reviewer-before-critic ordering are universal.\n\nThe critic must challenge:\n\n- severity inflation,\n- weak or incomplete evidence,\n- missing mitigating context,\n- false reachability assumptions,\n- framework or middleware defaults,\n- schema validation gates,\n- state-machine constraints,\n- feature flags or dead code,\n- pre-existing status,\n- non-actionable or unsafe fix recommendations,\n- sibling-file gaps,\n- whether multiple comments should be grouped into one root cause.\n\nCritic output format:\n\n```text\n[CRITIC] | item_id | status | severity | rationale | required_change\n```\n\n## Verdict row contract\n\nThe `[CRITIC]` row in the format above is **mandatory contract**, not advisory output. A critic response that does not end with that exact row format is treated as a planning preamble, not a verdict, and must be re-dispatched. Do not proceed past Phase 8 join barrier until each dispatched critic lane has produced a parseable `[CRITIC]` row.\n\n**Re-dispatch trigger:** when a critic lane response is missing the verdict row, the orchestrator must automatically re-dispatch that lane with the explicit instruction: \"Your final line MUST be exactly the Phase 8 contract row: `[CRITIC] | item_id | status | severity | rationale | required_change`. Use only enum values from `references\u002Ffindings-persistence-contract.md`. A response without that exact row will be treated as a planning message and re-dispatched.\" Do not synthesize findings from the planning preamble; only from the re-dispatched verdict.\n\n`NEEDS_MORE_EVIDENCE` is deliberately non-terminal and never satisfies critic\nsettlement. Re-dispatch a narrower critic\u002Fprobe lane or report the dimension\nBLOCKED. Terminal critic rows are cross-field checked: `DISPROVED` requires\n`NONE`, `UPHELD` requires CRITICAL\u002FHIGH\u002FMEDIUM, and `DOWNGRADED` cannot remain\nCRITICAL.\n\n**COVERAGE GATE alignment:** Critic lane failures apply the COVERAGE GATE (Phase 3) — under Profile A via `dispatch_lanes_async` with `mode: \"swarm-pr-review:critic\"` and the same exact `pr_head_sha`; under Profiles B\u002FC via a fresh critic subagent or pass. Do NOT mark findings UNVERIFIED or continue past the gap. The orchestrator NEVER fabricates a critic verdict by parsing prose, by tolerating a planning preamble, by presenting partial findings as complete beyond the truthful N-of-6 settlement, or by silently accepting reduced coverage.\n\nRefuted findings become `DISPROVED` or `ADVISORY`, depending on critic rationale. Downgrades must be listed in the final validation provenance.\n\nAfter critic lanes settle, persist the post-critic finding ledger before final\nsynthesis. This artifact is the source of truth for resumed reporting and for\nany later `swarm-pr-feedback` handoff.\n\n---\n\n## Runtime-Aware False-Positive Guard Checklist\n\nBefore confirming any finding, the reviewer and critic must check all that apply:\n\n- [ ] Schema validation gate: does schema validation reject malformed input before the flagged line?\n- [ ] Middleware interception: does middleware handle the request or command before the flagged path?\n- [ ] Framework default mitigation: does the framework inherently prevent this class of issue?\n- [ ] Caller context correctness: who invokes this code, and can untrusted input reach it?\n- [ ] Execution reachability: is the path reachable, or behind a feature flag, dead branch, build-only path, or commented-out code?\n- [ ] State-machine constraints: do ordering rules, locks, mutexes, phase gates, or transition guards prevent the state?\n- [ ] Permission boundary: does role\u002Ftool mapping prevent the operation?\n- [ ] Data lifetime: is the flagged state persisted, serialized, logged, or only transient?\n- [ ] Cross-platform behavior: does Windows\u002FmacOS\u002FLinux path or shell behavior change the result?\n- [ ] Test environment mismatch: is the finding only true under a mock or fixture that cannot occur in production?\n\nIf a mitigation applies and was not accounted for, downgrade to `ADVISORY`, `UNVERIFIED`, or `DISPROVED`.\n\n---\n\n## Phase 9: Synthesis, Grouping, and Noise Budget\n\nBefore final output:\n\n- group duplicate candidates by root cause,\n- report one finding per root cause,\n- attach all affected file:line references under that finding,\n- separate ship blockers from advisory notes,\n- suppress pure style\u002Fnit findings unless they indicate correctness, security, test, maintainability, or user-impact risk,\n- distinguish PR-introduced from pre-existing,\n- distinguish confirmed from plausible-but-unverified,\n- include disproved agent\u002Ftool claims,\n- keep final comments actionable.\n\n### Finding ID format\n\n```text\nF-001 | severity | category | root cause | affected file:line refs | reviewer | critic status\n```\n\n### Suggested final grouping\n\n1. Ship blockers,\n2. Important non-blockers,\n3. Test \u002F coverage gaps,\n4. Pre-existing issues,\n5. Unverified plausible risks,\n6. Disproved candidates \u002F false positives,\n7. Clean lane summary.\n\n---\n\n## Phase 10: Metrics and Knowledge Writeback\n\nAt the end of the review, include review quality metrics in the final report's\nvalidation provenance. Persist them only through an invoked evidence tool and\nrecord the exact `.swarm\u002Fevidence\u002F` path returned by that tool; if no invoked\ntool supports metrics (including all of Profiles B\u002FC), state `NOT PERSISTED —\nno metrics evidence writer` and keep the metrics block in the final report and\nsession ledger rather than naming a nonexistent command or path.\n\nRecord:\n\n- raw candidates by base lane,\n- raw candidates by micro-lane,\n- deterministic tool candidates,\n- reviewer-confirmed findings,\n- reviewer-disproved findings,\n- reviewer-unverified findings,\n- critic-upheld findings,\n- critic-downgraded findings,\n- critic-disproved findings,\n- final reported findings,\n- suppressed non-actionable candidates,\n- recurring false-positive patterns,\n- commands or probes used,\n- token\u002Ftime cost if available,\n- accepted\u002Ffixed findings when known.\n\nKnowledge writeback rules:\n\n- Write back only validated true positives or validated false-positive patterns.\n- Include file patterns, invariant, evidence, and why it was confirmed\u002Fdisproved.\n- Mark repo-specific lessons as project-tier unless there is strong evidence they generalize.\n- Never promote quarantined or unvalidated knowledge to hive-tier.\n- Never store secrets, private tokens, or raw sensitive logs.\n\n---\n\n## Phase 11: Post-Fix Re-verification\n\nWhen the PR author pushes fixes after a review, perform a targeted re-verification before updating the verdict.\n\n### Re-verification scope\n\nOnly re-verify findings the author claims to have fixed. Do not re-run the full review pipeline.\n\n### Re-verification steps\n\n1. For each finding the author claims fixed:\n   a. Read the changed file(s) from the updated branch at the specific lines referenced in the original finding.\n   b. Verify the fix addresses the root cause, not just the symptom.\n   c. Check that the fix does not introduce a new issue in the same area.\n2. Run CI checks on the updated branch to confirm no regressions.\n3. For findings the author did not address, carry forward the original finding with unchanged status.\n\n### Re-verification output\n\n```\n[REVERIFIED] | finding_id | FIXED \u002F PARTIALLY_FIXED \u002F NOT_FIXED \u002F NEW_ISSUE | evidence | updated_severity\n```\n\n- `FIXED`: the root cause is resolved and no new issue introduced.\n- `PARTIALLY_FIXED`: the root cause is partially addressed or a residual concern remains.\n- `NOT_FIXED`: the root cause persists unchanged.\n- `NEW_ISSUE`: the fix introduced a new problem at the same location.\n\nUpdate the verdict only after re-verifying all previously blocking findings.\n\n---\n\nFor the full parser-based candidate extraction dry-run example, read `references\u002Fparser-dry-run.md`.\n\n---\n\n# Council Mode Workflow\n\nCouncil mode is opt-in only and adversarial.\n\nWhen triggered:\n\n1. Build the same context pack as default mode.\n2. After the default base-dimension and risk-family coverage is complete, launch all supplementary council agents. Under Profile A, use one `dispatch_lanes_async` call with `mode: \"swarm-pr-review:council\"`, the same exact `pr_head_sha`, and one unique `workflow_lane` per council member; continue independent context preparation while they run, polling with `collect_lane_results` (without `wait`) to process settled agents incrementally, and use `wait: true` only when no independent work remains. All agents must be settled and their candidates added to the ledger before reviewer classification; under Profile A the runtime enforces this join barrier, and blocking, sequential, or direct-Task fallback is not equivalent to the structured council dispatch — bypassing the active controller is `BLOCKED`. Under Profile B, dispatch council members as parallel subagents with the same marker contract and settle them all before reviewer classification; under Profile C, run each council lens as a separate sequential pass.\n3. Each council agent assumes all work is wrong until code evidence proves otherwise.\n4. Each agent hunts within its lane only.\n5. Council uses the micro-lane row family: `[CANDIDATE] | candidate_id | micro_lane | severity | category | file:line | claim | invariant_violated | evidence_summary | confidence | risk_impact | risk_tags`. Emit one row per `EVIDENCE_FOUND` or `SUSPICIOUS` claim, or a fully populated `[CLEAN] | micro_lane | coverage_scope | evidence` row when no candidate survives. Put the exact council `workflow_lane` value in the `micro_lane` data field. Council prose without one of those markers does not settle the lane.\n6. Agents must not return `CONFIRMED`, `DISPROVED`, or final severity; candidate severity remains provisional until reviewer classification.\n7. The independent reviewer then classifies every council candidate as `CONFIRMED`, `DISPROVED`, `UNVERIFIED`, or `PRE_EXISTING`.\n8. Apply critic challenge to reviewer-confirmed HIGH\u002FCRITICAL or borderline findings.\n9. Final synthesis distinguishes real blockers, real low-severity issues, accepted caveats, disproved council claims, and follow-up quality work.\n\nDefault council lanes:\n\n- correctness and edge cases,\n- security and trust boundaries,\n- dependency and deployment safety,\n- docs and intent-vs-actual,\n- tests and falsifiability,\n- performance and architecture when risk justifies it.\n\nCouncil prompt requirements:\n\n- branch and commit range,\n- context pack summary,\n- files owned by that lane,\n- relevant impact cone,\n- explicit checklist,\n- strict output cap,\n- `EVIDENCE_FOUND \u002F SUSPICIOUS \u002F CLEAN` only,\n- file:line evidence required for `EVIDENCE_FOUND`.\n\nCouncil findings are supplementary, not authoritative overrides. Do not adopt council severities or claims without independent validation.\n\n---\n\n# Merge Recommendation Table\n\n| Verdict | Condition | `report_verdict` |\n|---|---|---|\n| `APPROVE` | zero unresolved CRITICAL findings, zero unresolved HIGH findings, all blocking obligations MET, no required validation phase failed | `APPROVE` -> APPROVE |\n| `APPROVE_WITH_NOTES` | zero unresolved CRITICAL findings, HIGH findings are downgraded\u002Fadvisory only, obligations MET or explicitly non-blocking | `APPROVE_WITH_NOTES` -> APPROVE |\n| `REQUEST_CHANGES` | any unresolved HIGH finding, any NOT_MET blocking obligation, multiple MEDIUM findings with the same root cause, or validation\u002Fprobe evidence indicates user-impacting risk | `REQUEST_CHANGES` -> REQUEST_CHANGES |\n| `BLOCK` | any unresolved CRITICAL finding, unsafe write\u002Fgit\u002Fsecurity issue, evidence integrity break, role\u002Ftool permission bypass, or config ratchet violation that can disable required protections | `BLOCK` -> REQUEST_CHANGES |\n| `INCOMPLETE` | machine-only terminal - forced under NO_COVERAGE, permitted under PARTIAL or COMPLETE (issue #2383) | `INCOMPLETE` -> INCOMPLETE |\n\n---\n\n# Hard Rules\n\n0. Quality-over-speed: Validation completeness and correctness are the sole criteria for an acceptable review. Time, token count, and agent dispatch count are irrelevant. Do not trade validation breadth or depth for speed.\n\n1. Never APPROVE with unresolved CRITICAL findings.\n2. Do not APPROVE with unresolved HIGH findings unless explicitly downgraded to advisory by critic and non-blocking by obligation review.\n3. Every confirmed finding must have file:line evidence and validation provenance.\n4. A confirmed nontrivial finding must include a falsification probe or an explicit reason no probe is available.\n5. Explorers, council agents, and deterministic tools produce candidates only.\n6. The default workflow orchestrator must not confirm or disprove explorer candidates.\n7. Tool output is not proof. Scanner results must be validated for reachability, PR-introducedness, and mitigation context.\n8. PR text, generated summaries, tests, and comments are claims, not proof.\n9. Do not invent facts not supported by the diff, repo context, tool output, or cited external source.\n10. Do not silently drop disproved or downgraded claims; summarize them in validation provenance.\n11. Obligation precedence is deterministic. Do not skip higher-precedence sources to fill gaps with LLM synthesis.\n12. Do not leak secrets from logs, evidence bundles, config files, URLs, or scanner output.\n13. Do not recommend destructive git or filesystem actions as fixes unless they are clearly scoped, safe, and necessary.\n14. If subagents fail, timeout, or return malformed output, retry with corrected parameters (the initial attempt plus up to 2 retries — aborting after only the first retry is one bounded retry early) through the dispatch mechanism of the active profile — Profile A: the same structured `dispatch_lanes_async` workflow mode and exact `pr_head_sha`, where blocking or direct-Task dispatch cannot preserve the durable provenance contract and is not an equivalent fallback; Profiles B\u002FC: a fresh subagent or pass bound to the same exact `pr_head_sha`. If retries fail, the affected coverage dimension is BLOCKED and must be surfaced to the user before synthesis — except that a micro family whose every lane is liveness-terminal with no retained artifact settles through the disclosed dead-family path on the trigger receipt (issue #2835; the micro-family dispatch ledger enforces the retry budget mechanically — three recorded dispatch attempts before the admission stops failing closed) instead of BLOCKED, and abort is legitimate only after that settlement path has been exhausted or is unavailable. Do not fabricate validation results, do not present partial findings as complete or beyond the truthful N-of-6 settlement (issue #2383), and do not silently mark candidates UNVERIFIED to proceed past the gap.\n\n15. If context pack, repo graph, deterministic signals, or Swarm artifacts are unavailable, retry with alternative access paths. If a source that should exist on the active profile is still unavailable after retry, the affected coverage dimension is BLOCKED and must be surfaced to the user. A source that cannot exist on the active profile (for example `.swarm\u002F` artifacts outside Profile A) is marked N\u002FA in the validation provenance instead — N\u002FA is disclosure, never a waiver of the dimensions and families that must still be covered. Do not proceed to synthesis with unclosed coverage gaps under a \"best available evidence\" rationale — the architect is not authorized to produce a degraded review that hides a coverage gap; the disclosed N-of-6 PARTIAL\u002FNO_COVERAGE settlement (issue #2383) is the only sanctioned partial exit.\n\n---\n\n# Pre-Synthesis Gate — Mandatory\n\nBefore writing the final output, print this checklist with filled values. Every blank field means the final output is invalid.\n\n```text\n[VALIDATION] scope selected: ___\n[VALIDATION] capability profile (A\u002FB\u002FC) and depth tier (S\u002FM\u002FL): ___ \u002F ___\n[VALIDATION] context pack built: YES\u002FNO — ___\n[VALIDATION] obligation count: ___\n[VALIDATION] repo graph \u002F impact cone source: ___\n[VALIDATION] deterministic signals ingested: ___\n[VALIDATION] lane dispatch mechanism: controller \u002F native subagents \u002F sequential passes — ___\n[VALIDATION] terminal coverage: COMPLETE (6\u002F6) OR PARTIAL (___\u002F6 + unresolved dimensions settled) OR NO_COVERAGE (0\u002F6) (issue #2383; lanes dispatched: ___)\n[VALIDATION] base explorer lanes returned: ___ \u002F ___\n[VALIDATION] micro risk families evaluated and attested: ___ \u002F 11 OR BLOCKED — \u003Cmissing rows> (micro lanes dispatched: ___)\n[VALIDATION] Swarm verifier routing used: ___\n[VALIDATION] raw candidates: ___\n[VALIDATION] tool candidates: ___\n[VALIDATION] reviewer lanes dispatched: ___\n[VALIDATION] reviewer lanes returned with parseable `[REVIEWED]` rows: ___ \u002F ___\n[VALIDATION] findings confirmed by reviewer: ___\n[VALIDATION] findings rejected by reviewer as false positive: ___\n[VALIDATION] findings marked PRE_EXISTING: ___\n[VALIDATION] findings left UNVERIFIED: ___\n[VALIDATION] findings escalated to critic: ___\n[VALIDATION] critic dispatched: ___ OR \"SKIPPED — no typed critic-routed finding (CRITICAL\u002FHIGH, MEDIUM+HIGH_IMPACT, MEDIUM+risk_tags, or UNKNOWN)\"\n[VALIDATION] critic returned: ___ OR \"N\u002FA\"\n[VALIDATION] findings upheld by critic: ___\n[VALIDATION] findings downgraded by critic: ___\n[VALIDATION] findings disproved by critic: ___\n[VALIDATION] falsification probes included: ___\n[VALIDATION] grouped root-cause findings: ___\n[VALIDATION] metrics \u002F knowledge writeback: ___\n[VALIDATION] all explorers verified to diff against PR branch, not HEAD: YES\u002FNO\n[VALIDATION] noise-filter suppressed candidates: ___ (count, each with reason in final report)\n[VALIDATION] all non-suppressed candidates routed to reviewer: YES\u002FNO\n```\n\nIf any reviewer lane lacks a parseable `[REVIEWED]` row after bounded\nre-dispatch, the reviewer dimension is BLOCKED. Do not infer or silently\ndowngrade a verdict.\n\n**COVERAGE GATE CONDITION:** If ANY validation dimension shows incomplete coverage that was not settled through the truthful N-of-6 terminal settlement (issue #2383) — lanes that failed and were not closed by retry or verified equivalent alternative, CI that did not run, tools that were unavailable after retry — the Pre-Synthesis Gate FAILS — apply the COVERAGE GATE (Phase 3). Do not proceed to final output. Surface unclosed gaps with exact failing dimensions and retry\u002Fequivalence evidence.\n\n---\n\n# Final Output Format\n\nProduce the final review in this order:\n\n## PR intent\n\nSummarize the obligations and user-visible intent.\n\n## Implementation summary\n\nSummarize what changed, including major files, public APIs, schemas, configs, tests, and Swarm artifacts.\n\n## Intended vs actual mapping\n\n| Obligation | Source | Actual evidence | Status | Linked finding |\n|---|---|---|---|---|\n\nUse `MET`, `PARTIALLY_MET`, `NOT_MET`, or `UNVERIFIABLE`.\n\n## Validation provenance\n\nInclude:\n\n- context pack limitations,\n- explorer lanes launched and returned,\n- micro-lanes triggered,\n- deterministic signals ingested,\n- reviewer identity \u002F role for each finding,\n- critic result for each escalated finding,\n- findings DISPROVED by reviewer with reason,\n- findings DOWNGRADED by critic with reason,\n- findings left UNVERIFIED with reason.\n\nIf zero findings, explicitly state:\n\n```text\nNo confirmed findings — all validated lanes CLEAN.\n```\n\nThen provide a lane-by-lane clean summary.\n\n## Confirmed findings\n\nFor each finding:\n\n```text\nF-001 — Severity — Category — Root cause\nFiles: path:line, path:line\nStatus: CONFIRMED \u002F critic status\nEvidence type: STRUCTURALLY_PROVEN \u002F EXECUTION_PROVEN \u002F STATIC_TRACE_PROVEN\nWhy it matters:\nValidation:\nFalsification probe:\nSuggested fix:\n```\n\n## Pre-existing findings\n\nList separately from PR-introduced findings.\n\n## Unverified but plausible risks\n\nOnly include if useful and clearly labeled as unverified.\n\n## Test \u002F coverage gaps\n\nFocus on missing tests that would catch real risks, not generic coverage requests.\n\n## Disproved candidates and false positives\n\nList concise reasons for notable false positives from explorers, tools, council agents, or reviewers.\n\n## Verdict\n\nUse one display verdict; the value after `->` is its exact `complete_pr_workflow`\n`report_verdict` (#2494 vocabulary bridge; severity\u002Faction policy owned by #2491):\n\n- `APPROVE` -> APPROVE\n- `APPROVE_WITH_NOTES` -> APPROVE (notes stay in the report body)\n- `REQUEST_CHANGES` -> REQUEST_CHANGES\n- `BLOCK` -> REQUEST_CHANGES\n\n## Merge recommendation\n\nExplain the recommendation in one short paragraph and list required actions before merge if applicable.\n\n## Feedback handoff\n\nWhen the review produced actionable validated findings or operational blockers,\ncall `write_pr_review_artifact` with `kind: \"handoff\"` (Profile A). The controller writes\n`.swarm\u002Fpr-review\u002F\u003Crun_id>\u002Ffeedback-handoff.json` only when its finding IDs\nexactly match the latest confirmed `handoff_to_feedback` records. On Profiles\nB\u002FC, write the same handoff content to the session\u002Ftask workspace path\ndescribed in \"Handoff To PR Feedback\" and reference that path in the\ncontinuation prompt. Include:\n\n- the handoff artifact path,\n- the preserved finding IDs and provenance that `swarm-pr-feedback` must carry\n  forward,\n- and an explicit question asking whether to continue into\n  `swarm-pr-feedback`.\n\nUse this exact continuation prompt format, substituting the exact path from\nwhichever profile applies (`.swarm\u002Fpr-review\u002F\u003Crun_id>\u002Ffeedback-handoff.json`\nunder Profile A, or the session\u002Ftask workspace path under Profiles B\u002FC — never\nmix the two):\n\n```text\n\u002Fswarm pr-feedback \u003CPR_URL> continue from \u003Chandoff_artifact_path>\n```\n\nWriting the validated handoff durably records one consent offer bound to the exact workflow instance, handoff digest, PR head\u002FURL, and actionable finding set; the first exact continuation confirms it and transitions modes. Internal creation never auto-routes, and malformed, non-actionable, or detached records cannot start PR_FEEDBACK.\n\n---\n\nFor reviewer, critic, and explorer prompt templates, read `references\u002Fprompt-templates.md`.\n\nUnder Profile A, after metrics and durable review artifacts are complete, but\nbefore emitting the user-facing final report, call `complete_pr_workflow` with\nmode `PR_REVIEW`, the same exact\n`pr_head_sha`, and the terminal `report_verdict` the coverage kind allows (issue #2383). The tool refuses to clear the session gate while required base,\ntrigger, declared reviewer\u002Fcritic, or open-lane obligations remain incomplete.\nWhile the gate remains active, the runtime prepends a workflow-active banner\nto the first substantive text part of each architect message (the model's text\nis preserved below the banner; later parts of the same message, and blank\nparts, are left untouched) and re-wakes an idle parent session. A\nuser interruption pauses every automatic wake path until a later explicit user\nturn settles; the durable gate remains available to continue or abort. Only\nemit the final report after the completion tool confirms that the gate cleared.\nIf it reports `checkout_restore_required`, call\n`prepare_pr_workflow_checkout` with `operation: \"restore\"` before returning to\nthe user. When `checkout_restore_receipts` lists multiple entries, one restore\ncall reapplies all receipts that share the recorded destination; an optional\nlisted `stash_oid` is an exact inventory assertion, not a selector that leaves\nthe other receipts pending. Successfully applied stashes remain in Git as\nexplicit safety backups and are listed in `retained_stash_oids`; the controller\nnever drops a mutable `stash@{n}` selector. Restoration is\nconservative: a dirty\u002Fconflicted checkout, mixed destinations, another active\nPR session, a missing stash, or an invalid recovery receipt returns a\nmanual-recovery diagnostic without resetting or dropping preserved state.\nLegacy receipts derive the exact original commit from the stash and restore a\nuniquely matching local branch when one exists (otherwise detached).\n\nUnder Profiles B\u002FC, no mechanical response gate exists: the Pre-Synthesis Gate\nchecklist is the completion gate. Emit the final report only after every line\nis filled, every dimension and family attested, and every BLOCKED item surfaced.\n\n## Aborting an unrecoverable review (Profile A)\n\nThe mechanical gate can leave the session stuck if the PR head cannot be\nfetched or checked out — for example when a compound `git fetch … && git\ncheckout …` is repeatedly rejected as read-only shell syntax (the runtime\nrequires each git intake command to be a single standalone command), when\nthe PR ref is missing, or when the working tree is on the wrong branch and\nthe merge-base bind can never verify. In that state the response gate\nsuspends further auto-resumes for either of two independent reasons: a\nsmall number of consecutive unproductive wakes (the durable gate `revision`\ndid not advance), or the total wake ceiling being reached (tier-scaled\ndefaults S=12 \u002F M=54 \u002F L=102, overridable via the `totalWakeCeiling`\noption, and in-memory\u002Fper-process so the count resets on plugin reload and\nwhen the durable gate clears — but NOT across the PR_REVIEW → PR_FEEDBACK\nhandoff, which keeps accumulating). Either suspension appends a\n`pr_workflow_wake_suspended` record to `.swarm\u002Fevents.jsonl` naming the\nreason, both counters, the tier, and the ceiling in force — read that first\nwhen diagnosing why a review stopped resuming. Either way, the only exits\nare:\n\n1. **Diagnose and retry the canonical standalone sequence.** Run\n   `git fetch origin refs\u002Fpull\u002F\u003CN>\u002Fhead`, verify with\n   `git rev-parse --verify \u003Cfull_pr_head_sha>^0` and\n   `git cat-file -t \u003Cfull_pr_head_sha>` (which must print `commit`), then run\n   `git switch --detach \u003Cfull_pr_head_sha>`. Do not use `--track FETCH_HEAD`.\n   Confirm `git rev-parse HEAD` equals the authoritative PR head, then recompute the exact\n   merge base with `git merge-base -- \u003Cbase_ref> \u003Cpr_head_sha>` (single\n   command) and retry the `swarm-pr-review:base` dispatch with the exact\n   `pr_head_sha`, `base_sha`, and `base_ref`.\n2. **Call `abort_pr_workflow`** with `mode: \"PR_REVIEW\"`, `kind: \"recovery\"`,\n   and a one-line `reason` describing the blocker. The tool clears the durable gate state\n   and stops the auto-resume loop. It refuses only while PR workflow lanes are still LIVE (a recent `updatedAt`); collect those with `collect_lane_results` first.\n   Lanes idle past the 30-minute staleness horizon settle as presumed-stale instead of blocking, disclosed as `presumed_stale_lanes` on the response and in `.swarm\u002Fevents.jsonl`; a schema-invalid (but JSON-parseable) gate state no longer defeats abort either. See `references\u002Flane-output-recoverability.md`.\n   It accepts both unbound and bound PR_REVIEW workflows so an unrecoverable bind\u002Fcheckout blocker cannot strand the gate. Settled discovery or validation\n   lanes with incomplete coverage use the truthful N-of-6 settlement path instead\n   of aborting. An audit event is appended to `.swarm\u002Fevents.jsonl`. After a legitimate abort the run's validated findings stay exportable: call\n   `export_pr_review_partial_results` (`run_id` + `pr_head_sha`) for a partial, non-authoritative salvage artifact — never a submission, never consent.\n   When the tool reports `checkout_restore_required`, immediately call `prepare_pr_workflow_checkout` with `operation: \"restore\"`; do not leave the\n   user detached from their original checkout with a hidden preserved stash.\n3. **Ask the user to run `\u002Fswarm abort-pr-workflow`** (a human-only\n   restricted command; the agent cannot invoke it via `swarm_command`).\n   This is the recovery path when the wake budget has suspended and the\n   architect cannot make further tool progress.\n\nA second, unrelated stranding class is **trigger-ledger drift**. This is not a\nfetch\u002Fcheckout problem: it means a later micro-lane explicitly supplied a\n`trigger_evaluation` that disagrees with the canonical ledger frozen by the\nfirst micro dispatch. A same-session retry may instead omit that argument and\nreuse the frozen ledger. When a later dispatch does supply a copy, the run\nfails closed in two places, with different strictness — at ledger bind time\n`bindPrReviewTriggerLedger` rejects a trigger_evaluation whose frozen-row digest\n(`trigger_id`, `result`, and `evidence` together) differs from the first\ndispatch's, and at receipt finalize time `write_pr_review_trigger_eval` rejects\nrows whose per-family `result` (classification) differs from the frozen ledger.\nThe finalize gate is deliberately narrower than the bind gate: evidence may be\nomitted or reworded at the receipt, but classifications must still agree. If a\nlater dispatch genuinely cannot converge with the frozen ledger, the exits are\nthe abort paths listed above (`abort_pr_workflow` or `\u002Fswarm abort-pr-workflow`),\nor re-dispatching the disagreeing lane so its trigger_evaluation converges with\nthe frozen ledger before re-binding.\n\nAbort is a recovery tool, not a coverage shortcut. Use it only when the\nbind\u002Fcheckout path is genuinely unreachable; never use it to skip a coverage\nobligation that is still recoverable, merely expensive, or inconvenient. When\nlanes have settled short of full coverage, the terminal N-of-6 settlement (issue\n#2383) is the truthful exit — not abort. For a publication-armed workflow whose exact\npublication cannot proceed, `abort_pr_workflow` with `kind: \"armed_recovery\"`\n(plus the armed recovery identity fields from `pr_workflow_status`) is the\naudited escape: it settles lanes, invalidates the staged publication\nauthorization, preserves validated work, and leaves a recoverable terminal\nstate; exact approved publication via `complete_pr_workflow` remains available\nand preferred whenever it can proceed.\n\nOn Profiles B\u002FC there is no durable gate or auto-resume loop to clear: if the\nhead bind is genuinely unreachable or bounded lane recovery is exhausted,\nreport the blocker to the user and stop.\n\n## Contract addendum (2026-10-12)\n\n- **Candidate rows are defect claims only.** Never emit verification notes,\n  confirmations, or coverage observations as CANDIDATE rows, and no\n  INFO-severity candidates — confirmations belong in the lane's\n  attestation\u002FCLEAN row. A misattributed or confirmatory candidate inflates\n  reviewer adjudication for zero signal.\n",{"name":5,"audience":23,"description":7,"swarm-contract-digest":24,"disable-model-invocation":25},"swarm-plugin","103ae1c77229",true,"main","e7e0e0cd0150a86494a874e5a9b4f70fdb93256a","skills\u002Fswarm-pr-review",2,"https:\u002F\u002Fgithub.com\u002Fzaxbysauce\u002Fzmem","https:\u002F\u002Fgithub.com\u002Fzaxbysauce","2026-11-15 01:44:13",{"source":8,"skillName":5,"commands":34,"prompt":44,"zipAvailable":25},[35,38,41],{"tool":36,"command":37},"npx","npx skills add zaxbysauce\u002Fzmem --skill swarm-pr-review",{"tool":39,"command":40},"bunx","bunx skills add zaxbysauce\u002Fzmem --skill swarm-pr-review",{"tool":42,"command":43},"pnpm","pnpm dlx skills add zaxbysauce\u002Fzmem --skill swarm-pr-review","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fzaxbysauce\u002Fzmem\u002Fblob\u002Fmain\u002Fskills\u002Fswarm-pr-review\u002FSKILL.md",[46,52,56,60,64,68,72],{"path":47,"resourceType":48,"resourceTypeDesc":49,"sizeBytes":50,"sourceHtmlUrl":51},"references\u002Fcounterbalancing.md","REFERENCE","参考文档",4000,"https:\u002F\u002Fgithub.com\u002Fzaxbysauce\u002Fzmem\u002Fblob\u002Fmain\u002Fskills\u002Fswarm-pr-review\u002Freferences\u002Fcounterbalancing.md",{"path":53,"resourceType":48,"resourceTypeDesc":49,"sizeBytes":54,"sourceHtmlUrl":55},"references\u002Ffindings-persistence-contract.md",15975,"https:\u002F\u002Fgithub.com\u002Fzaxbysauce\u002Fzmem\u002Fblob\u002Fmain\u002Fskills\u002Fswarm-pr-review\u002Freferences\u002Ffindings-persistence-contract.md",{"path":57,"resourceType":48,"resourceTypeDesc":49,"sizeBytes":58,"sourceHtmlUrl":59},"references\u002Flane-output-recoverability.md",23158,"https:\u002F\u002Fgithub.com\u002Fzaxbysauce\u002Fzmem\u002Fblob\u002Fmain\u002Fskills\u002Fswarm-pr-review\u002Freferences\u002Flane-output-recoverability.md",{"path":61,"resourceType":48,"resourceTypeDesc":49,"sizeBytes":62,"sourceHtmlUrl":63},"references\u002Fparallel-work-example.md",860,"https:\u002F\u002Fgithub.com\u002Fzaxbysauce\u002Fzmem\u002Fblob\u002Fmain\u002Fskills\u002Fswarm-pr-review\u002Freferences\u002Fparallel-work-example.md",{"path":65,"resourceType":48,"resourceTypeDesc":49,"sizeBytes":66,"sourceHtmlUrl":67},"references\u002Fparser-dry-run.md",11439,"https:\u002F\u002Fgithub.com\u002Fzaxbysauce\u002Fzmem\u002Fblob\u002Fmain\u002Fskills\u002Fswarm-pr-review\u002Freferences\u002Fparser-dry-run.md",{"path":69,"resourceType":48,"resourceTypeDesc":49,"sizeBytes":70,"sourceHtmlUrl":71},"references\u002Fprompt-templates.md",7778,"https:\u002F\u002Fgithub.com\u002Fzaxbysauce\u002Fzmem\u002Fblob\u002Fmain\u002Fskills\u002Fswarm-pr-review\u002Freferences\u002Fprompt-templates.md",{"path":73,"resourceType":48,"resourceTypeDesc":49,"sizeBytes":74,"sourceHtmlUrl":75},"references\u002Fverdict-settlement-contract.md",3552,"https:\u002F\u002Fgithub.com\u002Fzaxbysauce\u002Fzmem\u002Fblob\u002Fmain\u002Fskills\u002Fswarm-pr-review\u002Freferences\u002Fverdict-settlement-contract.md",[77,83,88,93,98,105],{"skillNo":78,"name":79,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":80,"categories":81,"keywords":82,"publishedAt":18},"01M78CEQCEHS30WN0456HFVZZZ","memory","https:\u002F\u002Fgithub.com\u002Fzaxbysauce\u002Fzmem\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fhosts\u002Fexpected\u002Fcache\u002Fzcode\u002Fskills\u002Fmemory\u002FSKILL.md",[],[],{"skillNo":84,"name":79,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":85,"categories":86,"keywords":87,"publishedAt":18},"01M78CEPF4DNY1QASCA42AJ0FF","https:\u002F\u002Fgithub.com\u002Fzaxbysauce\u002Fzmem\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fhosts\u002Fexpected\u002Fcache\u002Fcodex\u002Fskills\u002Fmemory\u002FSKILL.md",[],[],{"skillNo":89,"name":79,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":90,"categories":91,"keywords":92,"publishedAt":18},"01M78CENGZKX5GMJMJS0BRHJZX","https:\u002F\u002Fgithub.com\u002Fzaxbysauce\u002Fzmem\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fhosts\u002Fexpected\u002Fcache\u002Fclaude\u002Fskills\u002Fmemory\u002FSKILL.md",[],[],{"skillNo":94,"name":79,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":95,"categories":96,"keywords":97,"publishedAt":18},"01M78CEMHW23T1R9DACHBWX9PE","https:\u002F\u002Fgithub.com\u002Fzaxbysauce\u002Fzmem\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fhosts\u002Fcheckout\u002Fskills\u002Fmemory\u002FSKILL.md",[],[],{"skillNo":99,"name":100,"nameZh":6,"description":101,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":102,"categories":103,"keywords":104,"publishedAt":18},"01M78CE2AZC8SR86K5574A6W8P","swarm-pr-feedback","Ingest and resolve known pull request feedback with skeptical source verification. Use when addressing pasted PR feedback, GitHub review comments or threads, requested changes, CI\u002Fcheck failures, merge conflicts, stale PR branches, or PR follow-up work that must close all known issues without dropping findings. Supports multi-round bot reviews when the repo uses an auto-review bot that posts a new review after every push, via the iterative pattern documented in the body. Stage A (structural pre-checks) and Stage B (reviewer + test_engineer) gates and the reviewer + critic closeout gate are MANDATORY for any change made as part of this process.","https:\u002F\u002Fgithub.com\u002Fzaxbysauce\u002Fzmem\u002Fblob\u002Fmain\u002Fskills\u002Fswarm-pr-feedback\u002FSKILL.md",[],[],{"skillNo":106,"name":79,"nameZh":6,"description":107,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":108,"categories":109,"keywords":110,"publishedAt":18},"01M78CDGADXPR9WBQ05C10EJSW","ZMem — ZCode multi-tier memory system. Provides cross-session recall, capture, and management of lessons, facts, conventions, and preferences. Use when you need to recall prior knowledge before a non-trivial task, capture a lesson at task end, or manage the memory store. Tier 0 (core.md\u002FAGENTS.md) is auto-injected by the SessionStart hook; this skill operates Tier 2 (semantic store).","https:\u002F\u002Fgithub.com\u002Fzaxbysauce\u002Fzmem\u002Fblob\u002Fmain\u002Fskills\u002Fmemory\u002FSKILL.md",[],[]]