basic BMAD setup
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
---
|
||||
name: bmad-code-review
|
||||
description: 'Review code changes with several independent reviewers in parallel, then triage and present the findings. Use when the user says "run code review" or "review this code"'
|
||||
---
|
||||
|
||||
Run the following command exactly once without changing the current working directory.
|
||||
|
||||
Replace `{project-root}` with the nearest folder containing `_bmad/`, from the working directory upward.
|
||||
Replace `{skill-root}` with the absolute path to this skill's directory.
|
||||
|
||||
If the invocation asks for a `quick` or `thorough` review, append `--set workflow.review=<value>` to the command.
|
||||
If the invocation asks for a `no-code` review, append `--set workflow.fixes=handoff` to the command.
|
||||
|
||||
If the invocation is clearly non-interactive -- it says not to ask questions, or a bot, a CI job or another workflow is running the review -- append `--set workflow.interactive=false`. When in doubt, don't.
|
||||
|
||||
```bash
|
||||
uv run --no-cache "{project-root}/_bmad/scripts/render_skill.py" --project-root "{project-root}" --skill "{skill-root}"
|
||||
```
|
||||
|
||||
- The command should print one line to stdout. `read and follow <rendered workflow.md>`: read that file and follow it. `HALT: <reason>`: report the reason and stop.
|
||||
- If the script does not exist, BMad is not set up in this project yet. Offer to set it up using `bmad` skill, then run the command again. If you do not have the `bmad` skill, offer to install it first.
|
||||
- On any other output or failure, including `uv` being unavailable, report the command output and stop. Do not run any workflow source directly.
|
||||
@@ -0,0 +1,3 @@
|
||||
[skill]
|
||||
bmod = "bmod-method"
|
||||
source = "github:bmad-code-org/BMAD-METHOD/skills"
|
||||
@@ -0,0 +1,152 @@
|
||||
# DO NOT EDIT -- overwritten on every update.
|
||||
#
|
||||
# Workflow customization surface for bmad-code-review. Mirrors the
|
||||
# agent customization shape under the [workflow] namespace.
|
||||
|
||||
[workflow]
|
||||
|
||||
# --- Configurable below. Overrides merge per BMad structural rules: ---
|
||||
# scalars: override wins • arrays (persistent_facts, activation_steps_*): append
|
||||
# arrays-of-tables with `code`/`id`: replace matching items, append new ones.
|
||||
|
||||
# Steps to run before the standard activation.
|
||||
# Overrides append. Use for pre-flight loads, compliance checks, etc.
|
||||
|
||||
activation_steps_prepend = []
|
||||
|
||||
# Steps to run after persistent facts load but before the workflow begins.
|
||||
# Overrides append. Use for context-heavy setup that should happen
|
||||
# once activation context is in place.
|
||||
|
||||
activation_steps_append = []
|
||||
|
||||
# Persistent facts the workflow keeps in mind for the whole run
|
||||
# (standards, compliance constraints, stylistic guardrails).
|
||||
# Distinct from the runtime memory sidecar — these are static context
|
||||
# loaded on activation. Overrides append.
|
||||
#
|
||||
# Each entry is either:
|
||||
# - a literal sentence, e.g. "All stories must include testable acceptance criteria."
|
||||
# - a file reference prefixed with `file:`, e.g. "file:{project-root}/docs/standards.md"
|
||||
# (glob patterns are supported; the file's contents are loaded and treated as facts).
|
||||
|
||||
persistent_facts = []
|
||||
|
||||
# Scalar: executed when the workflow reaches its final step,
|
||||
# after review findings are presented and recorded. Override wins.
|
||||
# Leave empty for no custom post-completion behavior.
|
||||
|
||||
on_complete = ""
|
||||
|
||||
# Review selection: "quick" runs quick_lenses, "thorough" runs thorough_lenses.
|
||||
|
||||
review = "thorough"
|
||||
|
||||
# Whether a human can answer during the run. Set false when nobody can (a
|
||||
# review bot, a CI job, another workflow): the review then never asks or
|
||||
# halts, and takes the default at every choice.
|
||||
|
||||
interactive = true
|
||||
# What to do with patch findings: "apply" fixes them in this session;
|
||||
# "handoff" (a no-code review) hands them to a coding agent instead.
|
||||
|
||||
fixes = "apply"
|
||||
|
||||
# What a no-code review writes for the coding agent instead of fixing the
|
||||
# patch findings. Override wins; empty uses the text in step 4.
|
||||
|
||||
handoff_format = ""
|
||||
|
||||
# How that reaches the caller. Override wins; empty shows it in this chat.
|
||||
|
||||
handoff_delivery = ""
|
||||
|
||||
# Review lenses for the review step, in two sets the review selection picks
|
||||
# between. `instruction` is the lens's whole execution recipe — subagents by
|
||||
# default, but an override may run anything (e.g. an external reviewer via
|
||||
# bash). {diff_file}, {claims_file}, {plan_file}, and {verbatim_intent} are
|
||||
# substituted at run time; the first three are paths, and {diff_file} is the
|
||||
# unified diff file the lens reads. `when` (optional) gates a lens; empty
|
||||
# `instruction` disables it.
|
||||
|
||||
[[workflow.quick_lenses]]
|
||||
id = "quick"
|
||||
name = "Quick"
|
||||
instruction = """
|
||||
Launch a context-free subagent with this prompt:
|
||||
|
||||
Read `{plan_file}` — the plan holding the acceptance criteria and intent; it is empty when there is none — and the files its frontmatter `context:` lists. Read the agent instruction files (`AGENTS.md`, `CLAUDE.md`, or equivalents) at the repository root and in the directories the diff touches; those are the rules. Then read the unified diff at `{diff_file}` — it is the change under review.
|
||||
|
||||
Report unmet acceptance criteria, broken rules, and bugs. Each finding: the location, what goes wrong, and evidence checked against the surrounding code. Output a Markdown list of findings only — no severity, priority, or ranking.
|
||||
|
||||
Review by inspection only. Do not modify code, run builds or tests, or invoke quality gates. Do not invoke any skill, and do not spawn subagents of your own — you are the reviewer. Return your findings as text in your final message; do not route them through any findings-reporting tool the host may offer.
|
||||
|
||||
"""
|
||||
|
||||
[[workflow.thorough_lenses]]
|
||||
id = "blind-hunter"
|
||||
name = "Blind Hunter"
|
||||
instruction = """
|
||||
Launch a context-free subagent with this prompt:
|
||||
|
||||
Conduct a review of CONTENT.
|
||||
Look for what's missing, not only what's wrong.
|
||||
Compute your finding floor N from the diff file's size: N = min(floor(sqrt(kB) + 1), 10), where kB is the file's size in kilobytes. State the arithmetic in one line, then find at least N issues to fix or improve.
|
||||
Output a Markdown list of findings only — no severity, priority, or ranking.
|
||||
If the content is empty, stop and say so.
|
||||
If you have zero findings, re-check and keep thinking; do not stop with an empty list.
|
||||
|
||||
CONTENT: the unified diff at `{diff_file}`. Read that file — it is the content under review.
|
||||
|
||||
Review by inspection only. Do not modify code, run builds or tests, or invoke quality gates. Do not invoke any skill, and do not spawn subagents of your own — you are the reviewer. Return your findings as text in your final message; do not route them through any findings-reporting tool the host may offer.
|
||||
|
||||
"""
|
||||
|
||||
[[workflow.thorough_lenses]]
|
||||
id = "edge-case-hunter"
|
||||
name = "Edge Case Hunter"
|
||||
instruction = """
|
||||
Launch a context-free subagent with this prompt:
|
||||
|
||||
Read `{skill-root}/review-prompts/edge-case-hunter.md` completely and follow it as your review instructions.
|
||||
|
||||
claims_file (leave unread until your instructions call for it): {claims_file}
|
||||
|
||||
Review content: the unified diff at `{diff_file}`. Read that file — it is the content under review.
|
||||
|
||||
Review by inspection only. Do not modify code, run builds or tests, or invoke quality gates. Do not invoke any skill, and do not spawn subagents of your own — you are the reviewer. If the instruction file is unreadable, report that exact failure and stop. Return your findings as text in your final message; do not route them through any findings-reporting tool the host may offer.
|
||||
|
||||
"""
|
||||
|
||||
[[workflow.thorough_lenses]]
|
||||
id = "verification-gap"
|
||||
name = "Verification Gap Reviewer"
|
||||
instruction = """
|
||||
Launch a context-free subagent with this prompt:
|
||||
|
||||
Read `{skill-root}/review-prompts/verification-gap.md` completely and follow it as your review instructions.
|
||||
|
||||
Review content: the unified diff at `{diff_file}`. Read that file — it is the content under review.
|
||||
|
||||
Review by inspection only. Do not modify code, run builds or tests, or invoke quality gates. Do not invoke any skill, and do not spawn subagents of your own — you are the reviewer. If the instruction file is unreadable, report that exact failure and stop. Return your findings as text in your final message; do not route them through any findings-reporting tool the host may offer.
|
||||
|
||||
"""
|
||||
|
||||
[[workflow.thorough_lenses]]
|
||||
id = "intent-alignment"
|
||||
name = "Intent Alignment Auditor"
|
||||
when = "an intent is available: the spec's intent section, or the user's or conversation's own words on what the change is for"
|
||||
instruction = """
|
||||
Launch a subagent with this prompt:
|
||||
|
||||
You are an intent-alignment auditor. You have no other context about how this change was produced. Here is the verbatim intent this work started from:
|
||||
|
||||
{verbatim_intent}
|
||||
|
||||
The diff is the unified diff at `{diff_file}`. Read that file — it is the change under review.
|
||||
|
||||
Your task is strictly descriptive — do not prescribe additional work. Report: (1) the defensible readings of the intent, enumerated; (2) which reading this diff implements; (3) where the readings and the diff diverge — specifically, which surface the intent's expectations live at versus which surface the diff's changes and its tests exercise.
|
||||
|
||||
Review by inspection only. Do not modify code, run builds or tests, or invoke quality gates. Do not invoke any skill, and do not spawn subagents of your own — you are the reviewer. Return your findings as text in your final message; do not route them through any findings-reporting tool the host may offer.
|
||||
|
||||
"""
|
||||
@@ -0,0 +1,14 @@
|
||||
# Claims Check
|
||||
|
||||
Final pass for the Edge Case Hunter — runs only when the message that launched you named a claims file. Read that file now, for the first time; the path tracing is finished and the claims cannot steer it retroactively.
|
||||
|
||||
The file holds the change's own narrative — commit messages and any stated description. The narrative is the author's testimony, not evidence: a claim repeated in a code comment is still the same claim, not confirmation. Extract each checkable claim — what the change does, what it preserves, ordering, arithmetic, and parity with existing code ("exactly as X does") — then try to falsify each one against the code you have already traced. Where your trace is not enough to decide, read the code that decides it: the compared-to function, the actual callee, the state the claim assumes.
|
||||
|
||||
Append one finding per falsified claim to the same JSON array, with the four standard fields plus:
|
||||
|
||||
- `kind`: `"claim"`
|
||||
- `confidence`: `"high"`, `"medium"`, or `"low"`
|
||||
|
||||
For a claim finding the standard fields read as: `location` = where the code contradicts the claim; `trigger_condition` = the claim, quoted or tightly paraphrased; `guard_snippet` = what the code actually does; `potential_consequence` = what goes wrong for someone who believed the claim.
|
||||
|
||||
Verified claims produce nothing. Add nothing if nothing is falsified.
|
||||
@@ -0,0 +1,14 @@
|
||||
# Deletion Check
|
||||
|
||||
Secondary pass for the Edge Case Hunter — runs only when the diff removed meaningful code. Subordinate to the edge-case pass; findings are usually few or none.
|
||||
|
||||
For each chunk of removed or replaced code (ignore pure renames and whitespace), ask: did it carry behavior or a contract that the change neither re-established nor intentionally retired? Add a finding for any resulting regression, orphaned reference, or newly-dead code. Skip anything already covered by your edge-case findings.
|
||||
|
||||
Append each finding to the same JSON array as the edge-case findings, with the four standard fields plus:
|
||||
|
||||
- `kind`: `"deletion"`
|
||||
- `confidence`: `"high"`, `"medium"`, or `"low"` — these are inferences; rate them
|
||||
|
||||
For a deletion finding the standard fields read as: `location` = the removed item; `trigger_condition` = the behavior or contract it enforced; `guard_snippet` = where or how to re-establish it; `potential_consequence` = the regression or orphan.
|
||||
|
||||
Add nothing if nothing qualifies.
|
||||
@@ -0,0 +1,112 @@
|
||||
# Edge Case Hunter Review
|
||||
|
||||
**Goal:** You are a pure path tracer. Never comment on whether code is good or bad; only list missing handling.
|
||||
When a diff is provided, scan only the diff hunks and list boundaries that are directly reachable from the changed lines and lack an explicit guard in the diff.
|
||||
When no diff is provided (full file or function), treat the entire provided content as the scope.
|
||||
Ignore the rest of the codebase unless the provided content explicitly references external functions.
|
||||
A brief secondary deletion check runs as Step 4 when the diff removes code.
|
||||
A claims check runs as Step 5 when the launch message names a claims file.
|
||||
|
||||
**Inputs:**
|
||||
- **content** — Content to review, or a path to read it from: diff, full file, or function
|
||||
- **also_consider** (optional) — Areas to keep in mind during review alongside normal edge-case analysis
|
||||
- **claims_file** (optional) — Path to the change's stated narrative. Do NOT read it before Step 5: the path tracing in Steps 2–3 must finish before the narrative is seen.
|
||||
|
||||
**MANDATORY: Execute steps in the Execution section IN EXACT ORDER. DO NOT skip steps or change the sequence. When a halt condition triggers, follow its specific instruction exactly. Each action within a step is a REQUIRED action to complete that step.**
|
||||
|
||||
**Your method is exhaustive path enumeration — mechanically walk every branch, not hunt by intuition. Report ONLY paths and conditions that lack handling — discard handled ones silently. Do NOT editorialize or add filler. Do not assign severity labels, rankings, or priority levels.**
|
||||
|
||||
|
||||
## EXECUTION
|
||||
|
||||
### Step 1: Receive Content
|
||||
|
||||
- Take the content to review from the parent message that launched you — inline, or by reading the file it points to (never from this instruction file)
|
||||
- If no content is supplied, or it is empty, unreadable, or cannot be decoded as text, return `[{"location":"N/A","trigger_condition":"Input empty or undecodable","guard_snippet":"Provide valid content to review","potential_consequence":"Review skipped — no analysis performed"}]` and stop
|
||||
- Identify content type (diff, full file, or function) to determine scope rules
|
||||
|
||||
### Step 2: Exhaustive Path Analysis
|
||||
|
||||
**Walk every branching path and boundary condition within scope — report only unhandled ones.**
|
||||
|
||||
- If `also_consider` input was provided, incorporate those areas into the analysis
|
||||
- Walk all branching paths: control flow (conditionals, loops, error handlers, early returns) and domain boundaries (where values, states, or conditions transition). Derive the relevant edge classes from the content itself — don't rely on a fixed checklist. Examples: missing else/default, unguarded inputs, off-by-one loops, arithmetic overflow, implicit type coercion, race conditions, timeout gaps
|
||||
- Consider implicit branches: the diff special-cases or changes the handling of one or more members of a fixed set of values — enums, status codes, sentinels, type tags, flags, value ranges. The rest of the set is implicit branches (e.g. the diff changes the `RED` and `YELLOW` cases of a `RED`/`YELLOW`/`GREEN` enum; `GREEN` is the implicit branch)
|
||||
- Consider handle lifetime: when the changed code re-checks, re-fetches, or re-validates something it already held — a handle, index, id, pointer — the re-check exists because an intervening call can invalidate it. Identify that call, what it does to the thing held, and what the changed code silently skips when the re-check fails
|
||||
- For each call site the diff adds or changes — in test files as well as production code — read the callee's declaration and check the call against it: argument count, order, types, and defaults. Report any mismatch
|
||||
- For each path: determine whether the content handles it
|
||||
- Collect only the unhandled paths as findings — discard handled ones silently
|
||||
|
||||
### Step 3: Validate Completeness
|
||||
|
||||
- Revisit every edge class from Step 2 — e.g., missing else/default, null/empty inputs, off-by-one loops, arithmetic overflow, implicit type coercion, race conditions, timeout gaps
|
||||
- Add any newly found unhandled paths to findings; discard confirmed-handled ones
|
||||
|
||||
### Step 4: Deletion Check
|
||||
|
||||
If the diff removed or replaced meaningful code (ignore pure renames and whitespace): load `references/deletion-check.md` and follow it.
|
||||
|
||||
### Step 5: Claims Check
|
||||
|
||||
If the launch message provided a `claims_file` path and the file exists and is non-empty: load `references/claims-check.md` and follow it.
|
||||
|
||||
### Step 6: Present Findings
|
||||
|
||||
Output all findings as a single JSON array following the Output Format specification exactly.
|
||||
|
||||
|
||||
## OUTPUT FORMAT
|
||||
|
||||
Return ONLY a valid JSON array of objects. Each edge-case finding contains exactly these four fields:
|
||||
|
||||
```json
|
||||
[{
|
||||
"location": "file:start-end (or file:line when single line, or file:hunk when exact line unavailable)",
|
||||
"trigger_condition": "one-line description (max 15 words)",
|
||||
"guard_snippet": "minimal code sketch that closes the gap (single-line escaped string, no raw newlines or unescaped quotes)",
|
||||
"potential_consequence": "what could actually go wrong (max 15 words)"
|
||||
}]
|
||||
```
|
||||
|
||||
No extra text, no explanations, no markdown wrapping. An empty array `[]` is valid when nothing is found. Deletion findings from Step 4 and claim findings from Step 5, if any, go in the same array with the extra fields defined in `references/deletion-check.md` and `references/claims-check.md`.
|
||||
|
||||
|
||||
## HALT CONDITIONS
|
||||
|
||||
- If no content is supplied, or it is empty, unreadable, or cannot be decoded as text, return `[{"location":"N/A","trigger_condition":"Input empty or undecodable","guard_snippet":"Provide valid content to review","potential_consequence":"Review skipped — no analysis performed"}]` and stop
|
||||
<reference path="references/deletion-check.md">
|
||||
# Deletion Check
|
||||
|
||||
Secondary pass for the Edge Case Hunter — runs only when the diff removed meaningful code. Subordinate to the edge-case pass; findings are usually few or none.
|
||||
|
||||
For each chunk of removed or replaced code (ignore pure renames and whitespace), ask: did it carry behavior or a contract that the change neither re-established nor intentionally retired? Add a finding for any resulting regression, orphaned reference, or newly-dead code. Skip anything already covered by your edge-case findings.
|
||||
|
||||
Append each finding to the same JSON array as the edge-case findings, with the four standard fields plus:
|
||||
|
||||
- `kind`: `"deletion"`
|
||||
- `confidence`: `"high"`, `"medium"`, or `"low"` — these are inferences; rate them
|
||||
|
||||
For a deletion finding the standard fields read as: `location` = the removed item; `trigger_condition` = the behavior or contract it enforced; `guard_snippet` = where or how to re-establish it; `potential_consequence` = the regression or orphan.
|
||||
|
||||
Add nothing if nothing qualifies.
|
||||
</reference>
|
||||
<reference path="references/claims-check.md">
|
||||
# Claims Check
|
||||
|
||||
Final pass for the Edge Case Hunter — runs only when the message that launched you named a claims file. Read that file now, for the first time; the path tracing is finished and the claims cannot steer it retroactively.
|
||||
|
||||
The file holds the change's own narrative — commit messages and any stated description. The narrative is the author's testimony, not evidence: a claim repeated in a code comment is still the same claim, not confirmation. Extract each checkable claim — what the change does, what it preserves, ordering, arithmetic, and parity with existing code ("exactly as X does") — then try to falsify each one against the code you have already traced. Where your trace is not enough to decide, read the code that decides it: the compared-to function, the actual callee, the state the claim assumes.
|
||||
|
||||
Append one finding per falsified claim to the same JSON array, with the four standard fields plus:
|
||||
|
||||
- `kind`: `"claim"`
|
||||
- `confidence`: `"high"`, `"medium"`, or `"low"`
|
||||
|
||||
For a claim finding the standard fields read as: `location` = where the code contradicts the claim; `trigger_condition` = the claim, quoted or tightly paraphrased; `guard_snippet` = what the code actually does; `potential_consequence` = what goes wrong for someone who believed the claim.
|
||||
|
||||
Verified claims produce nothing. Add nothing if nothing is falsified.
|
||||
</reference>
|
||||
|
||||
## CONTENT SOURCE
|
||||
|
||||
"Review content:" in the message that launched you gives the content itself or a path to read it from. Read the file when it is a path; either way that is the content under review, and this instruction file never is.
|
||||
@@ -0,0 +1,113 @@
|
||||
# Verification Gap Review
|
||||
|
||||
**Goal:** Find changed behavior that could break without reliable verification catching it. Ask one question — "if the behavior this change is supposed to produce broke where it's actually used, would verification fail?" Do not hunt for correctness bugs, but report genuine problems you notice while tracing verification.
|
||||
|
||||
The main verification gap shapes are:
|
||||
|
||||
1. **Regression gap:** the changed code regresses where it's used, and no test covering that use would fail.
|
||||
2. **Missing-adoption gap:** a place that should now use the new behavior doesn't; it handles the same case its own way, or not at all, and no test would flag the omission.
|
||||
3. **Broken-verification gap:** a test appears to cover the changed behavior, but would not actually protect it because it is skipped, flaky, not run in the normal verification path, or too weak to observe the regression.
|
||||
|
||||
## Evidence Rules
|
||||
|
||||
- Read a test before claiming what it covers, runs, asserts, or misses.
|
||||
- Before claiming no test exists, search the whole repo by the symbol under test and by import references; expected file locations are not enough.
|
||||
- Never assert what you did not verify. If a finding cannot be grounded, drop it.
|
||||
- In a finding, say what you actually checked — "none of the tests I read cover this" — and show how far you looked. Say a test doesn't exist anywhere only when the symbol/import-reference search actually shows that.
|
||||
- Do not assign severity, confidence, priority, or ranking.
|
||||
|
||||
## Review Sequence
|
||||
|
||||
### Step 1: Screen for behavioral change
|
||||
|
||||
Screen each part of the change separately. If a part is non-behavioral, skip it. Call a part non-behavioral only when the changed code does not alter return values, thrown errors, caller-visible side effects, or observable state (including iteration order and emitted messages). Once a part meets that test, move on; do not inspect callers or tests for extra confirmation.
|
||||
|
||||
Common non-behavioral examples: formatting, comments, whitespace; pure renames; trivial getters/setters and pass-throughs; type-only or compiler-enforced changes with no runtime effect; etc.
|
||||
|
||||
Only outcomes produced by deterministic code are worth automatically testing; tests are useless on static source text and brittle on LLM output. Skip those parts.
|
||||
|
||||
If every part is skipped, output the clean result (see Output Format).
|
||||
|
||||
### Step 2: Find the behavior that changed
|
||||
|
||||
Identify what behavior changed compared to the previous version: output, side effect, branch, error path, schema/event shape, config default, validation/authorization rule, external contract, etc. If the change affects more than one behavior, handle each separately.
|
||||
|
||||
Treat broad-impact changes as behavioral even when no single changed line looks important: dependency, toolchain, build/config, data-file, etc.
|
||||
|
||||
### Step 3: Trace where that behavior is used
|
||||
|
||||
Trace the changed behavior to the places that observe it. Start with direct callers and registered entry points (routes, commands, DI), contract consumers (schemas, events, APIs, database readers), and reverse-dependency info if already available.
|
||||
|
||||
Follow a path only while the changed behavior is reachable and unverified. Stop when a test at that boundary would fail, the consumer does not observe the changed behavior, or the next hop is guesswork (dynamic dispatch, reflection, outside-repo consumers, etc.). Prefer the nearest observable boundary, often one to three hops away, especially across contract, integration, or service edges. If there are more than five similar consumers, group obvious repeats and check representative paths; expand only when a consumer observes the behavior differently.
|
||||
|
||||
### Step 4: Qualify the consumer, then check its test
|
||||
|
||||
For each consumer, name the smallest realistic regression this consumer would observe: invert the branch, drop the default, omit the field, return the old error code, skip the integration call, etc. This is the Demonstration. If no such regression exists, drop the path; untested downstream code is not a finding.
|
||||
|
||||
A `Missing-adoption gap` qualifies not by the adoption failure alone but by a supersession signal: the change gives clear evidence the new behavior is meant to replace the local one — PR intent, naming or docs, a replaced sibling site, deleted duplicate logic, or a test defining the new rule — and the local site shares the same observable contract. Without a supersession signal and a shared observable contract, it is a refactor suggestion, not a verification-gap finding. Once both hold, check whether any test for that site would flag the non-adoption; missing coverage of the non-adoption is the gap itself, not a disqualifier.
|
||||
|
||||
Find and read the relevant test. Ask whether the Demonstration would make an assertion fail.
|
||||
|
||||
- If yes, the behavior is verified. No finding.
|
||||
- For a regression-style Demonstration: if no test runs the path, the test is skipped/flaky/not run normally, or the test runs the code without checking the changed result, report a `Regression gap` or `Broken-verification gap`.
|
||||
- For a qualifying Missing-adoption case: if none of the site tests you found assert it adopts the new behavior, report a `Missing-adoption gap`.
|
||||
|
||||
A test counts only if it runs normally and an assertion observes the changed output, branch, or contract. These do not count: no execution; source-text assertions that match a file's wording instead of running it; success/no-throw/snapshot-only checks; mock/log-call checks; human-only checks; tests that mock away the integration; e2e tests that pass through without checking the changed output; stale assertions or fixtures.
|
||||
|
||||
For example, `expect(x ?? DEFAULT).toBe(DEFAULT)` passes when `x` is missing.
|
||||
|
||||
Common patterns:
|
||||
|
||||
- **Caller-path gap** — helper test covers the branch, but caller values skip it.
|
||||
- **Contract drift** — payload/schema/event changes must be verified at the consumer.
|
||||
- **Migration compatibility** — tests only create new-format rows or fresh schemas.
|
||||
- **Phantom exception** — handled partial-failure path has no test.
|
||||
- **Missing-adoption gap** — sibling site should use the new rule/helper and does not.
|
||||
- **Removed verification** — deleted test or weakened assertion leaves behavior unpinned; removing a source-text assertion is not this, since it never counted.
|
||||
|
||||
### Step 5: Confirm each finding is real
|
||||
|
||||
Before writing a finding, re-open the specific tests or search results the finding relies on. Verify the Demonstration would not make any test you checked fail, or that the absence claim is backed by the symbol/import-reference search. Do not claim more than you verified; drop any finding you cannot ground.
|
||||
|
||||
Explain why the test misses the bug using what the test sets up and checks.
|
||||
|
||||
Do not report: compiler/type-checker-enforced cases; behavior already verified by an integration, contract, or e2e test; implementation-detail or mock-only tests; low coverage or a missing test file by itself; legacy untested code the change did not affect.
|
||||
|
||||
Report genuine problems you noticed while tracing verification, even if they are not verification gaps. Put them under `Other findings` in the output. This permits reporting what you already reached, not extra hunting. A claim that code misbehaves is a defect, not a gap — it goes under `Other findings` for standard triage, however you found it.
|
||||
|
||||
## OUTPUT FORMAT
|
||||
|
||||
Emit each verification-gap finding as one block. No general advice, no severity or confidence. Triage trusts a gap finding as filed and does not re-verify it, so each block must stand on its own evidence.
|
||||
|
||||
```markdown
|
||||
### <one-line title naming the gap>
|
||||
|
||||
- **Changed surface:** the exact behavior or contract that changed — `file:line`.
|
||||
- **Impacted consumer or site:** named concretely with `file:line` (e.g. "the `createInvoice` mutation used by the billing dashboard at `billing/dashboard.ts:88`," not "callers of this function").
|
||||
- **Existing test evidence:**
|
||||
- `Regression gap`: what the relevant test actually asserts, with `file:line`; or, if none, the symbol/import-reference searches run and their result.
|
||||
- `Missing-adoption gap`: tests for the impacted site, and whether any assert it adopts the new behavior.
|
||||
- `Broken-verification gap`: the apparent test or verification path, and why it does not count.
|
||||
- **Missing verification:** the precise assertion or check that's absent.
|
||||
- **Demonstration:**
|
||||
- `Regression gap` / `Broken-verification gap`: the concrete regression that would ship undetected, and why the tests you checked would not fail.
|
||||
- `Missing-adoption gap`: the case the site mishandles by not adopting the new behavior, and that none of the tests you read assert adoption.
|
||||
- **Consequence:** the concrete thing that ships wrong — a regression the checked evidence would not catch, or a site that should use the new behavior and doesn't.
|
||||
- **Disposition:** `patch` — name the test to add, fit to the repo's own way of verifying (don't impose a generic test pyramid) — or `defer` when the gap is real but not worth closing as part of this change, with one sentence of why.
|
||||
```
|
||||
|
||||
If you noticed genuine non-gap problems while tracing verification, append:
|
||||
|
||||
```markdown
|
||||
## Other findings
|
||||
|
||||
- <description only; no severity, confidence, priority, or ranking>
|
||||
```
|
||||
|
||||
When you find no verification gaps and no other findings, output exactly this single line, not an empty response:
|
||||
|
||||
`No verification gaps found.`
|
||||
|
||||
## CONTENT SOURCE
|
||||
|
||||
"Review content:" in the message that launched you gives the content itself or a path to read it from. Read the file when it is a path; either way that is the content under review, and this instruction file never is. If no content is supplied, or it is empty or unreadable, stop with exactly: `No verification gaps found.`
|
||||
@@ -0,0 +1,58 @@
|
||||
---
|
||||
diff_file: '' # set at runtime: path to the diff file
|
||||
claims_file: '' # set at runtime (path or empty)
|
||||
plan_file: '' # set at runtime (path or empty)
|
||||
review_mode: '' # set at runtime: full or no-plan
|
||||
---
|
||||
|
||||
# Step 1: Gather Context
|
||||
|
||||
## RULES
|
||||
|
||||
- The triggering prompt and the conversation before it name the review target — act on them; do not start from a blank slate.
|
||||
- Writing `{diff_file}` and the claims file is the only change this step may make. Otherwise it is read-only.
|
||||
{% if not workflow.interactive %}
|
||||
- No human can answer during this run: never ask and never HALT for input. Wherever an instruction below would ask, take the default it names instead; where it names none, stop and report what is missing.
|
||||
{% endif %}
|
||||
|
||||
## INSTRUCTIONS
|
||||
|
||||
1. **Find the review target.** Check in this order and stop at the first that identifies it:
|
||||
- **Request or recent conversation.** A PR (resolve via `gh pr view`; if that fails, ask for a SHA or branch), commit, branch, commit range, staged or uncommitted changes, a provided diff or file list, or a plan file. A plan sets `plan_file`; a non-empty frontmatter `baseline_revision` other than `NO_VCS` makes the diff source the **plan baseline** — otherwise say so and continue, since a plan without one does not identify the diff.
|
||||
- **The ticket tree.** Run `uv run {project-root}/_bmad/method/scripts/tickets.py --project-root {project-root} status`. On a non-zero exit, continue. Otherwise offer the `tickets` rows whose `state` is `review`, `<ref>` and `<title>` each, plus a choice of another target, and HALT for the user's pick. With none, or another target chosen, continue. For a picked ticket, run `tickets.py find <ref>` (same command form) and treat its `plan` as a plan file from the request.
|
||||
- **Current git state.** If HEAD is not on the default branch, confirm: "I see HEAD is `<short-sha>` on `<branch>` — do you want to review this branch's changes?" If confirmed, it is a branch diff against the default branch.
|
||||
- **Ask.** Go to instruction 2.
|
||||
|
||||
{% if not workflow.interactive %}
|
||||
Skip the ticket-tree offer, take the current branch's diff against the default branch without confirming, and if HEAD is on the default branch and nothing else identifies a target, stop and report that there is nothing identified to review.
|
||||
{% endif %}
|
||||
|
||||
2. HALT. Ask the user what to review: uncommitted changes, staged changes, a branch diff (which base), a commit range, or a provided diff or file list.
|
||||
|
||||
3. Write the diff to `{diff_file}`, a uniquely-named temp file outside the repository, so concurrent reviews cannot collide. A plan baseline diffs every change since `baseline_revision`, untracked files included. A branch diff runs from the merge-base (`<base>...HEAD`), so later commits on the base do not show up as reverted. For a file list, include untracked files. If the source does not resolve, HALT and ask for a valid one; if the diff is empty, HALT — there is nothing to review. The review lenses read that file; the diff text is never pasted into their prompts. Read `{diff_file}` yourself when you need the diff later in this workflow.
|
||||
|
||||
4. **Stage the claims file.** Collect the change's own narrative: for a plan baseline, branch diff, or commit range, the commit messages it covers (`git log <base>..<head>`, where a plan baseline's head is `HEAD`); for other sources, whatever description of the change the user or conversation supplied. Write it verbatim to another uniquely-named temp file outside the repository and set `claims_file` to its path, or `''` if there is none. Do not analyze or summarize it — it is input for one review lens, staged as a file so the other lenses never see it.
|
||||
|
||||
5. **Set the plan context.**
|
||||
- The request or conversation explicitly says there is no plan → `review_mode` = `no-plan`, `plan_file` = `''`. Do not ask.
|
||||
- `plan_file` is set → verify it is readable; `review_mode` = `full`.
|
||||
{% if workflow.interactive %}
|
||||
- Otherwise, ask for a plan file path, or to continue without one, and set `plan_file` and `review_mode` accordingly. Do not assume no-plan just because none was given.
|
||||
{% else %}
|
||||
- Otherwise → `review_mode` = `no-plan`, `plan_file` = `''`.
|
||||
{% endif %}
|
||||
|
||||
6. If `review_mode` = `full` and `{plan_file}`'s frontmatter has a `context` list, load each referenced doc and warn about any that cannot be found.
|
||||
|
||||
7. If `{diff_file}` exceeds about 3000 lines, warn the user and offer to chunk the review by file group. If they accept, agree on the first group, rebuild `{diff_file}` for it, and list the remaining groups for follow-up runs.
|
||||
|
||||
### CHECKPOINT
|
||||
|
||||
Present a summary before proceeding: diff stats (files changed, lines added/removed), `{review_mode}`, and loaded plan/context docs (if any).
|
||||
{% if workflow.interactive %}
|
||||
HALT and wait for user confirmation to proceed.
|
||||
{% endif %}
|
||||
|
||||
## NEXT
|
||||
|
||||
Read fully and follow `{{ rendered("step-02-review.md") }}`
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
failed_layers: '' # set at runtime: comma-separated list of lenses that failed or returned empty
|
||||
---
|
||||
|
||||
# Step 2: Review
|
||||
|
||||
## RULES
|
||||
|
||||
- All review subagents must run at the same model capability as the current session.
|
||||
- Run subagents synchronously: launch them together as blocking calls awaited in this turn — never backgrounded or detached, never ending the turn to await results.
|
||||
|
||||
## INSTRUCTIONS
|
||||
|
||||
1. The review lenses are listed below. For each lens:
|
||||
- `Run only when` present and not satisfied by the current context (`{review_mode}`, `{plan_file}`, `{verbatim_intent}`) → skip the lens and tell the user which lens was skipped and why.
|
||||
- otherwise → the lens is active.
|
||||
|
||||
2. Announce skipped lenses first, then launch every active lens before handling any lens's result. Try running all active lenses simultaneously: substitute the runtime placeholders (`{diff_file}`, `{claims_file}`, `{plan_file}`, `{verbatim_intent}`) into each lens's instruction. `{diff_file}`, `{claims_file}`, and `{plan_file}` are paths: substitute the absolute path and let the lens read the file — a launch prompt never carries diff text, and the child's working directory is not yours. `{verbatim_intent}` is the intent section of `{plan_file}` if it has one, else the user's or conversation's own words on what the change is for, substituted inline as text; a request to review something is not an intent. When an instruction launches a reviewer subagent, launch that child with the prompt text after placeholder substitution; do not load the reviewer instruction file yourself. For any other customized instruction, execute it as written. When running lenses as subagents, spawn every reviewer before reading or reacting to any of their output; begin collection only once all are launched.
|
||||
|
||||
{% if workflow.review == "quick" %}
|
||||
{{ workflow.quick_lenses }}
|
||||
{% else %}
|
||||
{{ workflow.thorough_lenses }}
|
||||
{% endif %}
|
||||
|
||||
3. If a lens's instruction requires subagents and none are available, for each such lens write that lens's child prompt beside `{plan_file}`, named after it with the lens id appended (in `{{ initiative_folder }}/` when there is no plan), with every file it points to — the diff, the claims, the reviewer instruction file — replaced inline by that file's contents, and every other line left exactly as written. That session shares no filesystem with this one, so its prompt has to stand alone; this is the only place you read a reviewer instruction file yourself. Then HALT. Ask the user to run each in a separate session (ideally a different LLM) and paste back the findings. When findings are pasted, treat them as those lenses' findings and resume from this point.
|
||||
|
||||
4. **Lens failure handling**: If any lens fails, times out, or returns empty results, append the lens's `name` to `failed_layers` (comma-separated) and proceed with findings from the remaining lenses.
|
||||
|
||||
5. Collect all findings from the completed lenses, keeping track of each finding's originating lens `id`.
|
||||
|
||||
## NEXT
|
||||
|
||||
Read fully and follow `{{ rendered("step-03-triage.md") }}`
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
---
|
||||
|
||||
# Step 3: Triage
|
||||
|
||||
## INSTRUCTIONS
|
||||
|
||||
1. **Normalize** findings from all layers into a unified list where each finding has:
|
||||
- `id` -- sequential integer
|
||||
- `source` -- the `id` of the layer that produced the finding (e.g., `blind-hunter`)
|
||||
- `title` -- one-line summary
|
||||
- `detail` -- full description
|
||||
- `location` -- file and line reference (if available)
|
||||
|
||||
2. Once every layer has reported -- and not before -- render a verdict on each finding, ahead of any deduplication or grouping. Disregard any severity a reviewing subagent assigned -- they lack the context to grade.
|
||||
|
||||
For each finding:
|
||||
- A gap finding from the verification-gap layer arrives pre-verified -- that layer's evidence rules made it read the tests and run the searches it cites, and triage trusts the claim as filed. Skip verification, render the verdict from the filed evidence, and weigh its filed disposition when routing. Its `Other findings` are verified like everything else.
|
||||
- **Verify the finding's claim.** At the cited file and line, does the bad outcome the reviewer describes actually occur? Read beyond the changed lines -- follow callers, guards upstream, etc -- until you can answer yes or no. A different finding about nearby code does not settle this one. Judge whether the problem is real, not whether the proposed fix is plausible. Code that loudly fails on a situation you never showed the program can reach is correct behavior, not a defect.
|
||||
- **Render exactly one verdict** from what verification established -- the verdict is the whole triage decision; there is no separate keep-or-dismiss.
|
||||
- `high` (intolerable), `medium` (tolerable), `low` (cosmetic or negligible) -- the bad outcome is real. Assign severity by how much it hurts end users or developers. For developer-only problems (inconsistent design, eroded invariants, duplicated sources of truth), name where it will cause trouble -- which caller will diverge, which rule will break. A vague "this is messy" with no named harm is not a severity grade; use `false` or `maybe-false` instead. When the harm is real but you cannot tell how bad, pick the higher grade.
|
||||
- `false` -- you checked, and the bad outcome does not happen at the cited location. Write what disproves this specific claim. A true fact about nearby code that does not disprove the claim does not count.
|
||||
- `maybe-false` -- you could not tell whether the bad outcome happens. Write what you would need to check to find out. Use this only when the diff and surrounding code leave the question open; when they are enough to decide, pick `high`, `medium`, `low`, or `false`.
|
||||
|
||||
- Every finding keeps its verdict and evidence (a sentence or two) for the summary; never drop, merge, or silently skip one.
|
||||
|
||||
Reject `false` findings on their refutation.
|
||||
|
||||
Reject `low` findings when it is unlikely that users or developers would meet the defect in everyday use (judged plainly -- no proof needed) and the fix is more than a direct correction or deletion -- adding guards, branches, parameters, or other complexity.
|
||||
|
||||
Reject any finding whose fix is to edit the plan under review.
|
||||
|
||||
All remaining findings continue to grouping.
|
||||
|
||||
3. **Group the survivors by shared root cause** -- two findings belong in one entry only when the same defect produced both. Same location alone is not a shared root cause, and neither is a shared fix. An entry carries every member's verified bad outcome in `detail` and the highest verdict among them (`high` > `medium` > `low` > `maybe-false`); set `source` to the contributing layers joined with `+` (e.g., `blind-hunter+edge-case-hunter`).
|
||||
|
||||
4. **Route** each entry into exactly one triage bucket. A group that includes verified `high`, `medium`, or `low` members routes by its highest such verdict -- not to defer just because a member is `maybe-false`.
|
||||
- **decision_needed** -- There is an ambiguous choice that requires human input. The code cannot be correctly patched without knowing the user's intent. Applies in every mode, with or without a plan, and whether or not a human can answer during this run -- the choice then falls to whoever reads the review. Record the options (each plausible fix, one line) and the one you recommend, with the reason.
|
||||
- **patch** -- Code issue that is fixable without human input. The correct fix is unambiguous, adds no public surface, and guards no state you did not demonstrate; otherwise `decision_needed`.
|
||||
- **defer** -- Pre-existing issue not caused by the current change, real but not actionable now; or an entry whose members are all `maybe-false` and the claim, if true, would be `medium` or `high` -- record that severity marked unverified, plus what would settle it (if it would only be `low`, reject it with the same note); or any entry whose fix edits agent-context files (CLAUDE.md, AGENTS.md, rules, other specs).
|
||||
|
||||
An entry this change caused, with a verified `high`, `medium`, or `low` member, is never `defer`, whatever its fix touches: it is `patch` or `decision_needed`. defer is only for what is not this change's problem.
|
||||
|
||||
5. If `failed_layers` is non-empty, report which layers failed before announcing results. If zero entries remain after rejections AND `failed_layers` is non-empty, warn the user that the review may be incomplete rather than announcing a clean review.
|
||||
|
||||
6. If zero entries remain after triage (all rejected or none raised): state "✅ Clean review — all layers passed." (Item 5 already warned if any review layers failed via `failed_layers`.)
|
||||
|
||||
## NEXT
|
||||
|
||||
Read fully and follow `{{ rendered("step-04-present.md") }}`
|
||||
@@ -0,0 +1,133 @@
|
||||
---
|
||||
deferred_work_file: '{{ initiative_folder }}/deferred-work.md'
|
||||
---
|
||||
|
||||
# Step 4: Present and Act
|
||||
|
||||
## RULES
|
||||
|
||||
- When `{plan_file}` is set, always write findings to it before offering action choices.
|
||||
- Never change a plan's `status`. The build leaves it at `built`; only the user marks a ticket done.
|
||||
{% if not workflow.interactive %}
|
||||
- No human can answer during this run: never ask and never HALT. The report text is the deliverable -- everything a reader must act on is in it, not only in files the run writes.
|
||||
{% endif %}
|
||||
|
||||
## INSTRUCTIONS
|
||||
|
||||
### 1. Clean review shortcut
|
||||
|
||||
If zero findings remain after triage (all rejected or none raised): state that. When `{plan_file}` is set, still write section 2's block, with the summary line and the `Rejected` appendix, so the run is recorded.
|
||||
{% if workflow.fixes == "handoff" %}
|
||||
Then proceed to section 5.
|
||||
{% elif workflow.interactive %}
|
||||
Then proceed to section 6 (Next steps).
|
||||
{% else %}
|
||||
Then end.
|
||||
{% endif %}
|
||||
|
||||
### 2. Write findings to the plan
|
||||
|
||||
If `{plan_file}` is set, append a block to its `## Code Review` section, creating that section at the end of the file when it is absent. The block opens with `### {date}` and the summary line from section 3, then the findings below, then the `Rejected` appendix. Write all findings in this order:
|
||||
|
||||
1. **`decision-needed`** findings (unchecked):
|
||||
`- [ ] [Review][Decision] <Title> — <Detail> Options: <each option, one line>. Recommended: <option> — <reason>.`
|
||||
|
||||
2. **`patch`** findings (unchecked):
|
||||
`- [ ] [Review][Patch] <Title> [<file>:<line>]`
|
||||
|
||||
3. **`defer`** findings (checked off, marked deferred):
|
||||
`- [x] [Review][Defer] <Title> [<file>:<line>] — deferred: <pre-existing, or for maybe-false the evidence that would settle it>`
|
||||
|
||||
Also append each `defer` finding to `{deferred_work_file}` under a heading `## Deferred from: code review ({date})`. If `plan_file` is set, include its basename in the heading (e.g., `code review of story-digest-delivery-plan (2026-03-18)`). One bullet per finding with description.
|
||||
|
||||
### 3. Present summary
|
||||
|
||||
Announce what was written:
|
||||
|
||||
> **Code review complete.** <D> `decision-needed`, <P> `patch`, <W> `defer`, <R> rejected.
|
||||
|
||||
The `Rejected` appendix is one line per rejected finding: `false` with its refutation, `low` with why it was not worth fixing. Without `plan_file`, it ends the chat listing.
|
||||
|
||||
{% if not workflow.interactive %}
|
||||
The listing is the review itself. List `decision-needed` entries first, then `patch`, then `defer`, then the `Rejected` appendix, highest severity first within each. Each `decision-needed` entry carries its options and the recommended one and is marked open -- nothing was decided. Each `patch` entry carries its location and the fix.
|
||||
{% endif %}
|
||||
|
||||
If `plan_file` is set, add: `Findings written to {plan_file}.`
|
||||
Otherwise add: `Findings are listed above. No plan was provided, so nothing was persisted.`
|
||||
|
||||
{% if workflow.interactive %}
|
||||
### 4. Resolve decision-needed findings
|
||||
|
||||
If `decision_needed` findings exist, present each one with its detail and the options available. The user must decide — the correct fix is ambiguous without their input. Walk through each finding (or batch related ones) and get the user's call. Once resolved, each becomes a `patch`, `defer`, or is rejected.
|
||||
|
||||
If the user chooses to defer, ask: Quick one-line reason for deferring this item? (helps future reviews): — then append that reason to both the finding's bullet in `{plan_file}` and the `{deferred_work_file}` entry.
|
||||
|
||||
**HALT** — I am waiting for your numbered choice. Reply with only the number. Do not proceed until you select an option.
|
||||
{% endif %}
|
||||
|
||||
### 5. Handle `patch` findings
|
||||
|
||||
{% if workflow.fixes == "handoff" %}
|
||||
{{ workflow.handoff_format | default("Write one Markdown block a coding agent can fix the findings from without redoing the review. Name the base it was compared to by full SHA, and the reviewed commit the same way, or say that the change is uncommitted on top of the base. Then, for each `patch` finding (including any resolved from `decision-needed`): what is wrong and how you know; the files or symbols it touches; what the fixed code should do, as an outcome, not a recipe; and how to check the fix, including anything that has to be run to confirm the defect. If there are no `patch` findings, say so. Then, under their own headings, list the `decision-needed` findings still unresolved and the `defer` findings, each with its reason, so the agent knows they are not its to fix.", true) }}
|
||||
|
||||
Nothing was run in this review, so never claim a fix works or a check passed.
|
||||
|
||||
{{ workflow.handoff_delivery | default("Show it in this chat.", true) }}
|
||||
{% elif workflow.interactive %}
|
||||
If `patch` findings exist (including any resolved from section 4), HALT. Ask the user:
|
||||
|
||||
If `plan_file` is set, present all three options:
|
||||
|
||||
> **How would you like to handle the `<P>` `patch` findings?**
|
||||
> 1. **Apply every patch** — fix all of them now, no per-finding confirmation. Defer and decision-needed items are not touched.
|
||||
> 2. **Leave as action items** — they are already in `{plan_file}`
|
||||
> 3. **Walk through each patch** — show details for each before deciding
|
||||
|
||||
If `plan_file` is **not** set, present only options 1 and 2 (omit "Leave as action items" — findings were not written to a file):
|
||||
|
||||
> **How would you like to handle the `<P>` `patch` findings?**
|
||||
> 1. **Apply every patch** — fix all of them now, no per-finding confirmation. Defer and decision-needed items are not touched.
|
||||
> 2. **Walk through each patch** — show details for each before deciding
|
||||
|
||||
**HALT** — I am waiting for your numbered choice. Reply with only the number. Do not proceed until you select an option.
|
||||
|
||||
- **Apply every patch**: Apply every patch finding without per-finding confirmation. Do not modify defer or decision-needed items. After all patches are applied, present a summary of changes made. If `plan_file` is set, check off the patch items in it (leave defer items as-is).
|
||||
- **Leave as action items** (only when `plan_file` is set): Done — findings are already written to `{plan_file}`.
|
||||
- **Walk through each patch**: Present each finding with full detail, diff context, and suggested fix. After walkthrough, re-offer the applicable options above.
|
||||
|
||||
**HALT** — I am waiting for your numbered choice. Do not proceed until you select an option.
|
||||
{% else %}
|
||||
Apply every `patch` finding without asking. Do not modify defer or decision-needed items. After all patches are applied, present a summary of changes made. If `plan_file` is set, check off the patch items in it (leave defer items as-is).
|
||||
{% endif %}
|
||||
|
||||
{% if workflow.interactive %}
|
||||
**✅ Code review actions complete**
|
||||
|
||||
- Decision-needed resolved: <D>
|
||||
- Patches handled: <P>
|
||||
- Deferred: <W>
|
||||
- Rejected: <R>
|
||||
|
||||
### 6. Next steps
|
||||
|
||||
Present the user with follow-up options:
|
||||
|
||||
{% if workflow.fixes == "handoff" %}
|
||||
> **What would you like to do next?**
|
||||
> 1. **Re-run code review** — address findings and review again
|
||||
> 2. **Done** — end the workflow
|
||||
{% else %}
|
||||
> **What would you like to do next?**
|
||||
> 1. **Build the next ticket** — run `bmad-build` to pick up the next ready ticket
|
||||
> 2. **Re-run code review** — address findings and review again
|
||||
> 3. **Done** — end the workflow
|
||||
{% endif %}
|
||||
|
||||
**HALT** — I am waiting for your choice. Do not proceed until the user selects an option.
|
||||
{% endif %}
|
||||
|
||||
## On Complete
|
||||
|
||||
If anything appears below, follow it as the final terminal instruction before exiting; otherwise exit normally.
|
||||
|
||||
{{ workflow.on_complete }}
|
||||
@@ -0,0 +1,44 @@
|
||||
{% if workflow.review not in ("quick", "thorough") %}
|
||||
{{ halt("workflow.review must be quick or thorough, not " ~ workflow.review) }}
|
||||
{% endif %}
|
||||
{% if workflow.interactive is not boolean %}
|
||||
{{ halt("workflow.interactive must be true or false, not " ~ workflow.interactive) }}
|
||||
{% endif %}
|
||||
{% if workflow.fixes not in ("apply", "handoff") %}
|
||||
{{ halt("workflow.fixes must be apply or handoff, not " ~ workflow.fixes) }}
|
||||
{% endif %}
|
||||
|
||||
# Code Review Workflow
|
||||
|
||||
Several independent reviewers hunt for defects in a code change; this workflow sends them the change, then verifies, triages, presents, and fixes what they found.
|
||||
|
||||
Subagents are an important part of this workflow. Use them wherever a step calls for them, if you can. If you need the user's permission to run them, ask once now for the whole run.
|
||||
|
||||
## Conventions
|
||||
|
||||
- When a step directs you to another file, read it fully and follow it. Load one step at a time, when it is reached.
|
||||
- A step that shows a menu or checkpoint halts there and waits for the user.
|
||||
{% if workflow.fixes == "handoff" %}
|
||||
|
||||
## No-code review
|
||||
|
||||
Review by inspection only. Do not modify code, run builds or tests, or invoke quality gates.
|
||||
{% endif %}
|
||||
|
||||
## On activation
|
||||
|
||||
Run each of these in order before step 1 (`_None._` means skip):
|
||||
|
||||
{{ workflow.activation_steps_prepend }}
|
||||
|
||||
Hold every entry below as fact for the whole run. Entries prefixed `file:` are paths or globs under `{project-root}` to read; the rest are facts verbatim (`_None._` means none):
|
||||
|
||||
{{ workflow.persistent_facts }}
|
||||
|
||||
Then run each of these in order (`_None._` means skip):
|
||||
|
||||
{{ workflow.activation_steps_append }}
|
||||
|
||||
## First step
|
||||
|
||||
Read fully and follow `{{ rendered("step-01-gather-context.md") }}`.
|
||||
Reference in New Issue
Block a user