Document Review
Review requirements or plan documents through multi-persona analysis. Task packs are reviewed as derived, report-only execution inputs against their current source plan. Dispatches generic subagents seeded with skill-local reviewer prompt assets, applies safe_auto fixes only when the run-local mutation policy is markdown-write, and preserves the same structural/semantic review as report-only findings when mutation is unavailable or forbidden.
Workflow Contract Summary
- 输入: requirements、统一计划、legacy plan、task pack 或其他可读 spec artifact,及可选 roster/output/mutation 参数。
- 输出: 默认 report-only 的结构化文档 findings、coverage、改进建议与可选 JSON envelope;只有显式 apply 授权才可修改 Markdown。
- 硬出口: 文档不可读、flag 冲突、task-pack/source-plan 漂移、format/source owner 不明确,或 mutation authority 缺失时不得写入文档。
- 权威: 原文和 source refs 提供事实,persona/LLM 判断语义充分性;producer 拥有 derived artifact 修复,review 不继承 commit/landing authority。
- 消费者: 文档 owner、
spec-brainstorm、spec-plan、spec-write-tasks、spec-work与人工 reviewer。
Interactive mode rules
- Pre-load the platform question tool before any question fires. In Claude Code,
AskUserQuestionis deferred — callToolSearchwithselect:AskUserQuestiononce, eagerly, at the top of Interactive-mode work (before the routing question, walk-through, bulk-preview, and Phase 5 terminal question) rather than at the first question site. Other hosts don't need this preload. - The numbered-list fallback applies only when the harness genuinely lacks a blocking question tool (
ToolSearchno match, the call fails, or the mode doesn't expose it, e.g. Codex edit modes). A pending schema load is not a fallback trigger. In genuine-fallback cases present options as a numbered list and wait. Rendering a question as narrative text because the tool feels inconvenient, the model is mid-report, or the instruction was buried is a bug — a question that calls for a user decision must either fire the tool or fall back loudly, never slip past as prose.
Phase 0: Detect Mode
Check the skill arguments for flags and a document path. Tokens matching mode:*, mutation:*, output:*, roster:*, or depth:* are flags, not file paths — strip every recognized flag before resolving the remaining document path for Phase 1.
| Flag | Meaning |
|---|---|
mode:headless |
Headless delivery (no interactive routing) |
mutation:report-only |
Caller-requested zero-write review; valid for Markdown, HTML, and ambiguous/unwritable inputs |
mutation:apply-fixes |
Explicitly authorizes bounded reviewer-owned Markdown fixes for this run; does not authorize commit or landing |
output:json |
Render the existing structured envelope as one JSON object |
roster:lite / roster:standard / roster:full |
Reviewer budget profile (default standard) |
depth:full / depth:lite |
Aliases of roster:full / roster:lite |
If both roster: and depth: appear, roster: wins. If neither appears, profile = standard.
mutation: and output: tokens are exact-token contracts. Accept only mutation:report-only, mutation:apply-fixes, and output:json. A duplicate token, multiple mutation:* tokens, multiple output:* tokens, or any unsupported mutation:* / output:* value fails closed before document read or reviewer dispatch. Return Review failed: flag-conflict-or-unsupported with the conflicting token names; do not guess precedence and do not treat those tokens as a path.
Set run-local requested_mutation to report-only or apply-fixes only when the matching exact token is present; otherwise default-report-only. Set output_mode to json only when output:json is present; otherwise text. Output mode changes rendering only — it does not grant mutation, dispatch, producer, commit, or lifecycle authority.
Set run-local delivery_mode to headless when mode:headless is present, otherwise interactive. Headless changes delivery, not mutation authority: it never upgrades default-report-only to a write policy. Only an explicit requested_mutation: apply-fixes may resolve to markdown-write; under report-only, no document write occurs in either delivery mode. output_mode is a third orthogonal choice. Headless never uses blocking prompts or interactive routing and Phase 5 returns immediately with "Review complete". Invoke a producer-owned write review via Skill("spec-doc-review", "mode:headless mutation:apply-fixes docs/plans/my-plan.md"); omit the mutation token for ordinary report-only review. Interactive references are eligible only after Phase 1 resolves mutation_policy: markdown-write.
Phase 1: Get and Analyze Document
If a document path is provided: Read it, then proceed; if the read fails, apply the missing-document gate below. If no document is specified (interactive mode): Ask which document to review, or find the most recent in docs/brainstorms/ or docs/plans/. If no document is specified (headless mode): Output "Review failed: headless mode requires a document path. Re-invoke with: Skill("spec-doc-review", "mode:headless ")" without dispatching agents.
Missing-document gate — verify before any dispatch. Some persona reviewers lack shell access and cannot recover a path that only exists on an un-checked-out ref. Before Phase 2, confirm every resolved path is readable on disk (location doesn't matter — an absolute path outside the checkout or another worktree is valid). If any path is unreadable, do not dispatch personas: interactive — "Document(s) not found on disk: . If they only exist on another branch, check it out (or use a worktree) and re-invoke; otherwise correct the path(s)."; headless — "Review failed: document(s) not found on disk: . Check out the branch containing them (or pass paths to files on disk) and re-invoke."
Classify Document Type
Classify by reading its content shape, not its file path. Path is a tie-breaker hint, not the primary signal.
首先检查 task-pack identity:frontmatter 含 type: task-pack 时,type: task-pack → classify as task-pack。source_plan、source_plan_hash 与 Task Pack Contract shape 用于后续 deterministic intake,不是 classification 前置条件;malformed pack 也不能降级解释成普通 plan。task-pack 分类优先于 unified requirements/plan 与通用 content-shape 分类。
First check the unified artifact contract: artifact_contract: spec-unified-plan/v1 plus artifact_readiness: requirements-only -> classify as unified-requirements (review Product Contract only; absent Planning Contract/Units/Verification/DoD is expected). Same contract plus artifact_readiness: implementation-ready -> classify as unified-plan (review Product Contract and Planning Contract with different lenses, then Implementation Units/Verification/DoD for execution completeness). Invalid progress-like readiness values (active, in_progress, completed, done) are a document-contract finding, not an execution state to honor.
STOP. 当 classification 为 task-pack 时,立即读取 references/task-pack-review-lens.md,完成 deterministic intake、current source-plan read、task-pack-specific semantic lens 与 terminal-owner mapping;这些步骤必须在 persona selection/dispatch 前完成。
Resolve Mutation Policy
After reading and classifying the document, set exactly one run-local mutation_policy, independently from delivery_mode:
report-only—task-pack强制使用report-only,并记录mutation_reason: task-pack-derived-artifact。Task pack 由spec-write-tasks生成且 JSON contract / human-readable mirror 必须同源;reviewer 只能返回 producer fix candidates,不得直接 patch derived artifact。显式mutation:report-only不覆盖这个更具体的 mandatory reason。markdown-write— only whenrequested_mutation: apply-fixes, the document is confirmed writable Markdown, and no mandatory report-only reason applies. Recordmutation_reason: caller-requested-apply-fixes. Markdownsafe_auto, walkthrough Apply, bulk Apply, and Open Questions append paths remain available; commit and landing remain unauthorized.report-only— whenrequested_mutation: report-onlyand the document is confirmed writable Markdown. Recordmutation_reason: caller-requested-report-onlyand keep the file byte-preserving.report-only— whenrequested_mutation: default-report-onlyand the document is confirmed writable Markdown. Recordmutation_reason: default-review-report-only; ordinary review never acquires write authority from file format or host capability.report-only— mandatory for HTML content or a.htmlartifact. Run the same reviewer roster, schema validation, confidence gate, deduplication, severity routing, Coverage, and limitations reporting, but do not invoke any document mutation path.report-only— also mandatory when the document is confirmed Markdown but the platform cannot write it. Recordmutation_reason: write-unavailable; keep the full review and finding envelope, but do not imply that Markdown mutation was attempted.- If extension, declared format, and content shape conflict, or the format remains ambiguous, fail closed to
report-onlyand recordmutation_reason: format-conflict-or-ambiguousin the envelope. Never guess Markdown write eligibility from the path alone.
For ordinary HTML use mutation_reason: html-artifact. A report-only request is valid in both headless and interactive delivery; interactive delivery still returns the structured report-only envelope and does not offer a mutation walkthrough.
Existing mandatory reasons retain their diagnostic meaning: task packs remain task-pack-derived-artifact, HTML remains html-artifact, write-unavailable Markdown remains write-unavailable, and format conflict/ambiguity remains format-conflict-or-ambiguous even when the caller requested apply. caller-requested-apply-fixes applies only to otherwise writable, unambiguous Markdown that is not a task pack. Without mutation:apply-fixes, ordinary writable Markdown resolves to report-only; delivery mode, JSON output, file writability, or permission settings cannot supply missing mutation authority.
Core classification rules (apply these first):
task-pack: Frontmattertype: task-pack; derived metadata such asgenerated_by: spec-write-tasks、mode: derived、source_plan、source_plan_hash; headingsTask Pack Contract、Execution Waves、Task Cards。Task-pack identity 优先,不因正文含 U-ID、files 或 verification 而归类成plan。requirements: Frontmatter fields likeactors:,flows:,acceptance_examples:; headings likeAcceptance Examples,Actors,Key Flows; IDs likeR1,A1,F1,AE1; prose focused on user/business problem and scope. No implementation units, per-unit file lists, or test scenarios.plan: Frontmatter fields liketype: feat|fix|refactor,origin:,product_contract_source:; headings likeImplementation Units,Key Technical Decisions,Risks & Dependencies; IDs likeU1,U2; per-unitGoal,Files,Approach,Test scenarios,Verification; repo-relative paths.- Tie-breaker: Content shape is authoritative over path. Mixed/sparse signals → fall back to path:
docs/brainstorms/→requirements,docs/plans/→plan. Neither applies → default torequirements(more conservative).
STOP. If classification is genuinely ambiguous after applying the core rules above, read references/document-classification-signals.md for the full signal lists before proceeding to persona selection.
Pass the classification result to each persona via the {document_type} slot in the subagent template.
Select Conditional Personas
Analyze the document to determine which conditional personas to activate. Use the quick-reference table first; if unresolved, read the full activation matrix.
Activation quick-reference (apply these signals first):
| Persona | Activate when the document... |
|---|---|
| product-lens | Stakes a challengeable claim about what to build and why, OR carries strategic weight beyond the immediate problem |
| design-lens | References UI/UX, frontend components, user flows, wireframes, interaction descriptions, responsive behavior, or accessibility |
| security-lens | Mentions auth/authorization, login flows, API endpoints, PII, payments, tokens, credentials, encryption, or third-party trust boundaries |
| scope-guardian | Has multiple priority tiers (P0/P1/P2), >8 requirements/units, stretch goals, or scope-goal misalignment signals |
| adversarial | Touches high-stakes domains (auth/payments/data migrations/external integrations), proposes new abstractions/architectural patterns, is a greenfield plan with no validated upstream, OR has explicit alternatives sections. Do NOT activate on routine plans with validated upstream Product Contract |
STOP. If the quick-reference table does not resolve whether to activate a conditional persona for this document, read references/persona-activation-matrix.md before finalizing the reviewer list.
Apply Roster Budget (profile)
The quick-reference table produces a candidate set. Apply the profile budget before Phase 2 dispatch — never merge personas, only skip candidates that exceed budget.
| Profile | Always-on | Conditional budget | Typical N |
|---|---|---|---|
lite |
coherence + feasibility | 0 conditional | 2 |
standard (default) |
coherence + feasibility | at most 1 conditional | ≤3 |
full |
coherence + feasibility | all candidates that qualify | 2–7 |
Selecting the single conditional under standard (first match wins when multiple qualify): 1. security-lens — auth/API/PII/payments/credentials/trust boundaries; 2. adversarial — high-stakes domain, new abstractions, greenfield without validated upstream, explicit alternatives; 3. design-lens — UI/UX/frontend/interaction; 4. product-lens — challengeable product/strategy claims; 5. scope-guardian — multi-priority / large unit count / stretch goals.
Record skipped candidates for the cost-shape line (skipped_conditional=… reason=budget). Under lite, skip all conditionals (reason=lite); under full, keep the full set (no budget skip). Escape hatch: user may name personas explicitly (e.g. "also run adversarial") — honor explicit names even under standard/lite, and note override=user on cost-shape.
Emit cost-shape (advisory, required)
After the reviewer list is fixed and before any dispatch, prepare exactly one advisory line (do not block on it). For ordinary text output, print it as shown below. When output_mode: json, do not print this line or any other user-visible prose outside the final JSON object; retain the same cost-shape facts inside the envelope's structured coverage metadata instead:
cost-shape: profile={lite|standard|full} N={count} personas=[{comma-separated short names}] skipped_conditional=[{name:reason},…] doc_bytes={utf8_bytes_or_unknown} slices={unified|full|mixed} isolation={min|degraded_inherited}
doc_bytes is the on-disk byte length when known, else unknown. slices is unified if every leaf gets a section slice, full if every leaf gets the full document, mixed otherwise. Task-pack review normally uses mixed: full task pack + focused current source-plan sections + compact deterministic receipt. isolation is set in Phase 2 Dispatch below. This line is advisory measurement, not a hard gate.
Phase 2: Announce and Dispatch Personas
For ordinary text output, tell the user which personas will review and why (justify conditionals), including the cost-shape: line from Phase 1 in the same announcement block. When output_mode: json, suppress this announcement and every other object-external status/terminal line; record selected/skipped personas, cost shape, isolation, and reviewer outcomes in the final JSON coverage and limitations fields. JSON mode's machine-readable single-object contract overrides the normal announcement requirement.
Build agent list. Always include coherence-reviewer and feasibility-reviewer. Add budget-filtered conditional personas only (product-lens-reviewer, design-lens-reviewer, security-lens-reviewer, scope-guardian-reviewer, adversarial-document-reviewer) — do not re-expand to "all conditionals that could match" after budget filtering unless profile=full or user override.
Dispatch
Before reviewer dispatch, record worker_dispatch_authorization, capability_probe, worker_dispatch_capability, worker_context_isolation, worker_model_override, and worker_bounded_parallelism, then normalize the result as worker_dispatch_outcome.
Dispatch authorization gate. A direct invocation of spec-doc-review authorizes this document-review workflow, not worker dispatch. Dispatch only when the user or an upstream handoff explicitly authorized subagents, personas, delegated review, or parallel-agent work for this run. Missing authorization forbids schema discovery and fixes capability_probe: not_applicable + worker_dispatch_capability: unknown; record dispatch_authorization_missing, set isolation=degraded_inherited, and apply the same selected persona prompt assets inline or serially. Only after authorization may current-session registry/schema be inspected as provider_untrusted evidence: confirmed absence records subagent_capability_missing; unavailable/incomplete/ambiguous discovery records worker_capability_unproven. Do not claim independent persona coverage or context isolation. This dispatch fallback is orthogonal to mutation_policy: only explicit mutation:apply-fixes can enable Markdown writes; HTML and all ordinary reviews remain non-mutating.
When the semantic probe yields one eligible generic worker candidate, dispatch bounded reviewer packets with bounded parallelism only when live facts support it; otherwise serialize and record parallelism_unproven_serialized. Permission settings govern whether a call may execute; they are not dispatch authorization. Respect the active-worker limit: queue selected reviewers, dispatch as many as accepted, fill freed slots as reviewers complete. Treat capacity-limit errors as backpressure, not failure — leave the reviewer queued and retry after a slot frees; record dispatch_backpressure_exhausted only after the bounded retry policy is exhausted, and worker_dispatch_failed after an accepted dispatch fails or for a non-capacity reason.
Context isolation (required intent): each reviewer prompt is self-contained (persona + schema + document slice + primer). Prefer minimum parent-context inheritance when worker_context_isolation: isolated. Do not rely on the worker inheriting the orchestrator's full skill text or chat history — if isolation is inherited or unknown, set isolation=degraded_inherited on the cost-shape line and proceed only where independent isolation is preferred rather than required; never claim isolation that did not happen.
For each selected reviewer, read the matching skill-local prompt asset at references/personas/<reviewer-name>.md and pass its full content as {persona_file}. Do not dispatch standalone agents by type/name or rely on platform-level custom-agent registration.
Model tiering (omit override if the platform has no known tier; inherit parent model otherwise): coherence gets the cheapest capable tier; design-lens/scope-guardian get the platform mid-tier; security-lens-reviewer, feasibility-reviewer, product-lens-reviewer, adversarial-document-reviewer: inherit the parent model (or a high-capability review tier if established).
Each subagent's prompt fills these template variables: {persona_file} — full content of the selected persona asset; {schema} — the findings schema below; {document_type} — the Phase 1 classification; {document_path} — the document path; {origin_path} — upstream provenance (prefer origin: frontmatter, else product_contract_source:<value>, else none; product-lens/adversarial/scope-guardian read this slot rather than re-parsing frontmatter); {document_content} — metadata, Goal Capsule, and the reviewer-specific section slice (unified artifacts: product-lens/adversarial/scope get Product Contract, feasibility/coherence also get Planning Contract and active Implementation Units/Verification/DoD when implementation-ready; task packs get the full task pack plus task-pack-review-lens.md, compact deterministic receipt, and focused current source-plan sections; legacy documents get the full document); {decision_primer} — cumulative prior-round decisions, or an empty block on round 1.
For legacy documents pass the full document (slices=full); for unified artifacts, default to section slices (slices=unified) and escalate to a broader slice only when a reviewer needs cross-section traceability the initial slice can't assess. For task-pack, set slices=mixed and wrap the four inputs separately as <task-pack-review-lens>、<deterministic-intake>、<task-pack> 与 <source-plan>,避免把 validator facts、derived tasks 与 canonical plan 混成同一 authority。Anti-waste rule: the orchestrator may read the full document once for classification and roster selection, but after slices are built do not also inject the full document into every leaf "for safety" — mark slices=mixed or full on cost-shape if a leaf must escalate.
When dispatch is explicitly authorized and at least one normal review lens is active, read references/cross-model-review.md and evaluate its independent external-data gates. If every gate passes, start exactly one report-only whole-document peer using references/personas/whole-doc-reviewer.md and the Skill-local adapter/runner lifecycle. The peer sweep reads the full document once; it does not multiply by persona and it never replaces the always-on reviewers. Missing authorization, receipt, data authority, redaction, allowlisted document ref, source identity, peer independence, or cleanup evidence means zero peer processes and no cross-model claim. A completed return may corroborate findings but never carries safe_auto or mutation authority.
Decision primer
On round 1, set {decision_primer} to <prior-decisions>Round 1 — no prior decisions.</prior-decisions>. On round 2+, accumulate prior-round decisions:
<prior-decisions>
Round 1 — applied (N entries):
- {section}: "{title}" ({reviewer}, {confidence})
Evidence: "{evidence_snippet}"
Round 1 — rejected (M entries):
- {section}: "{title}" — {one of: Skipped|Deferred to Open Questions|Acknowledged without applying} because {reason}
Evidence: "{evidence_snippet}"
Round 2 — applied (N entries): ...
</prior-decisions>
Each entry carries an Evidence: line because R29/R30 (references/synthesis-and-presentation.md) use an evidence-substring overlap check to match findings across rounds — without it, the orchestrator falls back to fingerprint-only matching, which re-surfaces rejected findings or over-suppresses. {evidence_snippet} is the finding's first evidence quote, truncated to ~120 characters at a word boundary with internal quotes escaped.
Accumulate across all rounds in the session. Skip, Defer, and Acknowledge all count as "rejected" for suppression purposes. Applied findings stay on the list so later rounds can verify fixes landed (R30). Cross-session persistence is out of scope — a new invocation starts fresh even if a prior session deferred findings into Open Questions.
Error handling: if a subagent fails or times out, proceed with completed findings and note the failure in Coverage — do not block the review on one reviewer. If both always-on reviewers (coherence and feasibility) return no valid result, attempt one equivalent inline review using their already-selected prompt assets and document slices. If that equivalent inline review also does not complete, set review_status: incomplete, record mandatory_review_coverage_missing, and suppress any clean verdict or execution handoff. Never describe partial roster coverage as complete. Dispatch limit: even at maximum (7 agents), use bounded parallel dispatch; queue and launch the remainder as active reviewers complete.
Phases 3-5: Synthesis, Presentation, and Next Action
Before rendering any finding, read references/rendering-floor.md. Its consequence-first wording, recommendation visibility, opaque-token budget, and trace-on-request rules apply to the structured envelope, batch report, walkthrough, bulk preview, and persisted Open Questions entry. Surface-specific layouts may differ, but none may weaken that shared decision floor.
After all dispatched agents return, read references/synthesis-and-presentation.md for the synthesis pipeline (validate, anchor-based gate, dedup, cross-persona promotion, contradiction resolution, auto-promotion, three-tier routing with FYI subsection), mutation-policy enforcement, structured envelope output, and the routing-question handoff.
Only when delivery_mode: interactive and mutation_policy: markdown-write, read references/walkthrough.md for the four-option routing question and per-finding walk-through. For the bulk-action preview used by best-judgment routing, Append-to-Open-Questions, and walk-through's "Auto-resolve with best judgment on the rest", read references/bulk-preview.md. Do not load either before agent dispatch completes, and never load them for report-only.
Included References
Task Pack Review Lens
仅当 Phase 1 分类为 task-pack 时读取 Task Pack Review Lens。
Subagent Template
@./references/subagent-template.md
Findings Schema
@./references/findings-schema.json
Selected reviewer prompt assets live under references/personas/. Read only the prompt files selected for the current review.