@juicesharp/rpiv-pi 0.11.0 → 0.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juicesharp/rpiv-pi",
3
- "version": "0.11.0",
3
+ "version": "0.11.2",
4
4
  "description": "Skill-based development workflow for Pi Agent — discover, research, design, plan, implement, validate",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -1,115 +1,111 @@
1
1
  ---
2
2
  name: code-review
3
- description: Three-pass parallel reviewer (quality, security, dependencies) with conditional advisor adjudication. Produces review documents in thoughts/shared/reviews/. Use when changes are ready for review.
4
- argument-hint: [scope]
3
+ description: "Three-wave parallel reviewer with file-oriented reasoning (quality, security, dependencies) and conditional advisor adjudication. File-centric framing: U30 diffs inline full-function context, Discovery Map uses semantic file summaries, and lens prompts read files as coherent units. Produces review documents in thoughts/shared/reviews/. Use when changes are ready for review."
4
+ argument-hint: "[scope]"
5
5
  ---
6
6
 
7
- ## Scope Source
8
-
9
- If the user has not specified what to review, ask them before proceeding. Scope is one of: `commit` (latest commit), `staged`, `working`, a commit hash or `A..B` range, or a PR branch name. Their input will appear as a follow-up paragraph after this skill body.
10
-
11
7
  # Code Review
12
8
 
13
- You are tasked with reviewing changes across three parallel lenses — **Quality**, **Security**, **Dependencies** — and synthesising their findings with optional stronger-model adjudication into an actionable `thoughts/shared/reviews/` artifact.
9
+ Scope: $ARGUMENTS
10
+
11
+ Review changes across **Quality**, **Security**, **Dependencies** lenses with optional advisor adjudication. Valid scopes: `commit` | `staged` | `working` | hash | `A..B` | PR branch. **If Scope above is empty, ask the user before proceeding.**
14
12
 
15
13
  **How it works**:
16
- - Resolve scope and assemble the diff (Step 1)
17
- - Phase-1 Discovery Map (Step 2 one agent + orchestrator-side git work)
18
- - Phase-2 three-lens review + precedents + conditional CVE lookup (Step 3 — parallel agents)
19
- - Cross-Finding Interaction Sweep (Step 4 — one synthesis agent over Phase-2 evidence, gated)
20
- - Reconcile findings via advisor (if present) or inline dimension-sweep (Step 5)
21
- - Grounded-questions developer checkpoint (Step 6)
22
- - Write the review artifact (Step 7)
23
- - Present and handle follow-ups (Steps 8–9)
14
+ - Step 1 resolve scope, read diff (with `-U30` context), derive flags, build semantic file map
15
+ - Step 2 — dispatch Wave-1: integration + precedents + (deps/CVE) + (peer-mirror); integration & peer-mirror gate Wave-2, precedents gates Step 5
16
+ - Step 3 dispatch Wave-2: Quality + Security lenses, file-oriented
17
+ - Step 4 — dispatch Wave-3: Predicate-Trace + Interaction Sweep + Gap-Finder, all gated
18
+ - Step 5 — reconcile via advisor or inline dimension-sweep (blocks on precedents)
19
+ - Step 6 — verify findings: re-read each cited file:line; drop/demote unverified
20
+ - Step 7 write artifact
21
+ - Steps 8–9 — present and handle follow-ups
22
+
23
+ **File-orientation contract**: agents reason about *files* as coherent units. Hunks are evidence *within* a file's analysis, never the unit of analysis. The `-U30` patch (Step 1) inlines function-level context so agents rarely need extra `Read` calls.
24
+
25
+ Every Wave-2 agent prompt contains EXACTLY: (a) `Known Context:` followed by the Discovery Map verbatim, and (b) the literal string `/tmp/code-review-patch.diff` as the patch path. Nothing else from Wave-1 outputs — NOT the raw integration-scanner dump, NOT precedent-locator output, NOT Dependencies/CVE output. See "Wave-2 context isolation" in Step 3 for the failure mode when this is violated. Wave-1 agents that do not consume the Discovery Map (precedents, dependencies, CVE) get `ChangedFiles` / manifest-diff only.
24
26
 
25
27
  ## Step 1: Resolve Scope and Assemble the Diff
26
28
 
27
- 1. **Parse the scope argument** (follow-up paragraph or the skill's argument):
28
- - `commit` → `git diff HEAD~1 HEAD`
29
- - `staged` `git diff --cached`
30
- - `working` → `git diff`
31
- - Commit hash `abc1234` → `git show abc1234`
32
- - Range `A..B` → `git diff A..B`
33
- - PR branch name → `git diff $(git merge-base main HEAD)..HEAD` (or the branch vs its base)
29
+ 1. **Interpret the Scope line** (from the header) and identify `OLDEST` + `NEWEST` commits (user-inclusive endpoints):
30
+ - `commit` → `OLDEST=NEWEST=HEAD`
31
+ - `staged` / `working` no commits; see working-tree branch below
32
+ - Single hash `h` → `OLDEST=NEWEST=h`
33
+ - Range `A..B` → verify A is ancestor of B (`git merge-base --is-ancestor A B`; swap if reversed); `OLDEST=A`, `NEWEST=B`
34
+ - Commit list (`h1,h2,h3` or whitespace-separated) find endpoints via `git rev-list --topo-order`; `OLDEST` = farthest-from-HEAD, `NEWEST` = nearest. Reject if not on a single linear ancestry (ask user to clarify).
35
+ - PR branch name → `OLDEST=$(git merge-base main HEAD)`, `NEWEST=HEAD` note: `OLDEST` is already the parent-of-first-PR-commit, so skip the `BASE` computation below and use `BASE=OLDEST` directly.
36
+
37
+ 2. **Compute the range once**: `BASE=$(git rev-parse "$OLDEST^")`, `TIP=$NEWEST`, `RANGE="$BASE..$TIP"`. This gives a range that INCLUDES `OLDEST`'s own changes (standard `A..B` excludes `A`). Every subsequent git command uses `$RANGE` — do NOT inline a `^` character in templates; orchestrators sometimes drop it.
34
38
 
35
- 2. **Read the full diff FIRST** (orchestrator-side, before any agent dispatch):
36
- - `git diff --name-only [scope]` → `ChangedFiles` list
37
- - `git diff --stat [scope]` → size summary
38
- - `git diff -U0 [scope]` → hunk ranges for Phase-2 prompts (inline, don't dump to user)
39
- - `git log -1 --format="%s%n%n%b" [scope-ref]` → commit-message context when applicable
39
+ 3. **Assemble the UNION of changes** (not the net endpoint-diff so reverted intermediate work stays visible). Save the patch to a tempfile once with generous context; do NOT re-run `git log --patch` to slice windows later:
40
+ - `git log "$RANGE" --name-only --pretty=format: | sort -u` → `ChangedFiles`
41
+ - `git log "$RANGE" --stat --reverse` → per-commit size summary
42
+ - `git log "$RANGE" --patch --reverse --no-merges -U30 > /tmp/code-review-patch.diff` → union patches with **30 lines of surrounding context per hunk** (function-level context inline)
43
+ - `git log "$RANGE" --reverse --format="%H %s%n%n%b%n---"` → commit-message context
44
+ - **Working-tree branch** (`staged` / `working`, no `$RANGE`): `git diff --cached --name-only` / `git diff --name-only`; `git diff --cached --stat` / `git diff --stat`; `git diff --cached -U30` / `git diff -U30`. Commit-message context is N/A.
45
+ - **Patch-size fallback**: `-U30` produces ~2–3× the size of `-U0`. If the resulting patch exceeds ~1MB, drop to `-U10` for this run; never use `-U0` — it defeats the skill's design.
40
46
 
41
47
  3. **Bail-out**: if `ChangedFiles` is empty, print `No changes in scope [scope]. Exiting.` and STOP. Do not write an artifact.
42
48
 
43
49
  4. **Derive flags** (orchestrator-side, used in later steps):
44
- - `ManifestChanged` = ChangedFiles contains any path matching dependency manifests across common ecosystems:
45
- `package.json`, `package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`,
46
- `pyproject.toml`, `poetry.lock`, `uv.lock`, `Pipfile`, `Pipfile.lock`, `requirements*.txt`,
47
- `*.csproj`, `Directory.Packages.props`, `packages.lock.json`, `global.json`,
48
- `go.mod`, `go.sum`,
49
- `Cargo.toml`, `Cargo.lock`,
50
- `Gemfile`, `Gemfile.lock`, `*.gemspec`,
51
- `pom.xml`, `build.gradle`, `build.gradle.kts`, `gradle/libs.versions.toml`,
52
- `composer.json`, `composer.lock`,
53
- `Package.swift`, `Package.resolved`, `Podfile.lock`,
54
- `mix.exs`, `mix.lock`, `pubspec.yaml`, `pubspec.lock`,
55
- `.terraform.lock.hcl`, `Dockerfile*`,
56
- OR a `peerDependencies`/`dependencyManagement`/central-versions block was touched.
50
+ - `ManifestChanged` = ChangedFiles intersects any dependency manifest or lockfile (e.g. `package.json`/lockfile, `Cargo.toml`/`Cargo.lock`, `go.mod`/`go.sum`, `pyproject.toml`/`requirements*.txt`/`poetry.lock`, `Gemfile*`, `*.csproj`, `pom.xml`/`build.gradle*`, `composer.json`, …) OR a peer/optional/dev-dependency field was touched.
57
51
  - `LockstepSelfReview` = repository root contains `scripts/sync-versions.js` AND every `packages/*/package.json` shares the same `version:` AND the diff touches `packages/*/package.json`.
52
+ - `HasGatingPredicate` = diff adds or modifies a **status/enum-comparison predicate** (`Status == X`, `Status is X or Y`, `X.Contains(Status)`, pattern-match on a discriminator) OR introduces a new value into an enum referenced by existing gating predicates. NOT merely the presence of `if (!x) return`.
58
53
  - `ReviewType` = one of `commit | pr | staged | working`.
59
- - `WorkflowRiskSignals` run each of the five commands below. For each, set its signal to `yes` if the command produces any output, else `no`. Treat empty output as `no` `grep`'s non-zero no-match exit is not an error. Record all five plus the `workflow_risk_gate` aggregate on the Discovery Map. The Step 4 gate reads these booleans.
54
+ - `PeerPairs` = `(new_file, peer_file)` tuples. `new_file` is in `git log "$RANGE" --diff-filter=A --name-only` (working-tree: `git diff --diff-filter=A --name-only [--cached]`). `peer_file` exists at HEAD (`git ls-tree HEAD`) and matches one heuristic:
55
+ - **Stem similarity ≥ 60%** of the longer stem (e.g. `PhysicalProductSubscription` ↔ `Subscription`).
56
+ - **Interface/impl pair**: `I<Name>` ↔ `<Name>`, `<Name>` ↔ `<Name>.impl`, `<Name>{Abstract,Base,Protocol}` ↔ `<Name>`.
57
+ - **Shared suffix** from `{Handler, Service, Repository, Aggregate, Reducer, Controller, Resolver, Command, Query, Job, Processor, Strategy, Policy, Event, Listener, Subscriber, Publisher, Exception, Eligibility, Ability, QueryParam, Specification, Factory, Builder}`.
58
+
59
+ Drop a pair only when the peer doesn't exist at HEAD, no heuristic matches, or both files were added in this diff. Empty list ⇒ skip the peer-mirror agent. Co-modified peers are KEPT — the agent Reads them at HEAD (post-diff tree state), so any invariant present at HEAD counts as peer evidence regardless of whether the peer was edited in this diff.
60
+
61
+ ## Step 2: Dispatch Wave-1 — Integration + Precedents + Deps/CVE + Peer-Mirror
60
62
 
61
- Group 1 External I/O and persistence writes:
62
- ```
63
- git diff -U0 [scope] | grep -nE '(fetch\(|axios\.|http\.(Get|Post|Put|Delete|Patch)|requests\.(get|post|put|delete|patch)|HttpClient\b|URLSession\b|reqwest::|net/http|fs\.(readFile|writeFile)|File\.(Open|Read|Write)|Process\.Start|subprocess\.|exec\.Command|child_process|\.save\(|\.update\(|\.delete\(|INSERT\s+INTO|UPDATE\s+\w+\s+SET|DELETE\s+FROM)' | head -20
64
- ```
65
- → `external_io_or_write = yes` if any match, else `no`.
63
+ Spawn ALL of the following in parallel at T=0 in a **single message with multiple Agent tool calls**. Do NOT wait for integration-scanner before dispatching precedents / dependencies / CVE — they do not consume Discovery-Map output, only `ChangedFiles` and the manifest diff (both orchestrator-produced in Step 1).
66
64
 
67
- Group 2 Retry/schedule/concurrency primitives:
68
- ```
69
- git diff -U0 [scope] | grep -nE '(\bretry\b|\bbackoff\b|\bBackOff\b|maxAttempts|\battempt(s)?\s*[<>=]=?\s*\d|\bschedule\(|\bcron\b|\bdebounce\(|\bthrottle\(|setTimeout\(|setInterval\(|\bMutex\b|\bRwLock\b|\bSemaphore\b|atomic\.|Atomic(Int|Long|Ref|Bool)\b|Interlocked\.|\bsynchronized\s*\(|\bvolatile\b)' | head -20
70
- ```
71
- → `retry_schedule_concurrency = yes` if any match, else `no`.
65
+ **AgentIntegration map:**
66
+ - subagent_type: `integration-scanner`
67
+ - Prompt: "Map inbound references, outbound dependencies, and infrastructure wiring for the following changed files: [ChangedFiles, one per line]. Flag any auth-boundary crossings (middleware, guards, interceptors, authorize-style decorators) and config/DI/event registration touching these paths. Do NOT analyse code quality — connections only, in your standard output format."
72
68
 
73
- Group 3 — Exported/public surface:
74
- ```
75
- git diff -U0 [scope] | grep -nE '(^[\+\-].*(export\s+(default\s+)?(function|class|const|interface|type)\s|\bpublic\s+(class|interface|struct|record|static)\s|pub\s+(fn|struct|trait|enum)\s)|@(Get|Post|Put|Delete|Patch)Mapping|app\.(get|post|put|delete|patch)\(|@app\.route|@api_view)' | head -20
76
- ```
77
- → `exported_public_surface = yes` if any match, else `no`.
69
+ **Agent — Precedents** (always): use the `precedent-locator` prompt defined in Step 3 below dispatch it here, not in Wave-2. Input it needs: `ChangedFiles` only.
78
70
 
79
- Group 4Schema/contract file paths:
80
- ```
81
- git diff --name-only [scope] | grep -E '(^|/)(migrations/|alembic/|db/migrate/)|\.(sql|proto|graphql[s]?|avsc)$|(^|/)(openapi|swagger).*\.ya?ml$|(^|/)prisma/schema\.prisma$'
82
- ```
83
- → `schema_contract_path = yes` if any match, else `no`.
71
+ **Agent Dependencies** (only when `ManifestChanged`): use the `codebase-analyzer` Dependencies prompt defined in Step 3 below dispatch here. Input it needs: touched manifest paths + `LockstepSelfReview` flag.
84
72
 
85
- Group 5 Auth-boundary (two-stage, finalized in Step 2):
86
- ```
87
- git diff -U0 [scope] | grep -nE '(middleware\b|interceptor\b|\bguard\b|@?[Aa]uthoriz|requires_auth|before_action\s+:authenticate|@PreAuthorize|@login_required|permission_classes)' | head -20
88
- ```
89
- → In Step 1, set a preliminary `auth_boundary_body` from this command's output only. In Step 2 (Discovery Map synthesis), OR that preliminary value with any auth-boundary crossings reported by the integration-scanner, and record the final `auth_boundary_body` on the Discovery Map.
73
+ **AgentCVE / advisory** (only when `ManifestChanged`): use the `web-search-researcher` prompt defined in Step 3 below — dispatch here. Input it needs: parsed `name@version` list from the manifest diff (orchestrator extracts and hands over directly).
90
74
 
91
- Set `workflow_risk_gate = yes` if ANY of the five group booleans is `yes`, else `no`.
75
+ **Agent — Peer-Mirror** (only when `len(PeerPairs) > 0`): `subagent_type: codebase-analyzer`. Input: the `PeerPairs` list verbatim, nothing else — no Discovery Map (it isn't built yet and the agent doesn't need it), no patch path (the work is peer-vs-new entity comparison, not diff analysis). Prompt:
76
+ ```
77
+ Peer-mirror check.
78
+
79
+ PeerPairs (orchestrator-computed):
80
+ [list of (new_file, peer_file) tuples]
92
81
 
93
- Do NOT extend these commands with: bare `dispatch(`, `emit(`, `publish(`, `enqueue(`, `produce(`, `async`, `await`, `go func`, bare `Lock`, `channel`, `select {`, or generic `export` without symbol-kind. Those patterns may appear in the Step 4 sweep prompt's prose but MUST NOT drive the gate.
82
+ For each pair, Read BOTH files in full. Enumerate the peer's PUBLIC surface as rows:
83
+ - every public method / exported function
84
+ - every domain event / notification / message fired (language-agnostic: method calls named `fire*`, `emit*`, `publish*`, `dispatch*`, `raise*`, `notify*`, `AddDomainEvent`, or idiomatic equivalents)
85
+ - every state transition (name + precondition guard + side-effects)
86
+ - every constructor-injected / DI-supplied collaborator
87
+ - every persisted field / column / serialised property
88
+ - every registration this file contributes to a switch/map/table/route/handler registry elsewhere (match by type name appearing in a `switch`/`match`/`when`/dispatch table)
94
89
 
95
- ## Step 2: Phase-1 Discovery Map
90
+ For each row, check the new file. Emit ONE row per peer invariant:
96
91
 
97
- 1. **Spawn Phase-1 agents in parallel** using the Agent tool:
92
+ peer_site (file:line `<verbatim line>`) | new_site (file:line `<verbatim line>` OR `<absent>`) | status | one-sentence delta
98
93
 
99
- - Use **integration-scanner** to map inbound references, outbound dependencies, infrastructure wiring, and auth-boundary crossings for `ChangedFiles`.
94
+ status {Mirrored, Missing, Diverged, Intentionally-absent}.
100
95
 
101
- Agent prompt:
102
- > Map inbound references, outbound dependencies, and infrastructure wiring for the following changed files: [ChangedFiles, one per line]. Flag any auth-boundary crossings (middleware, guards, interceptors, authorize-style decorators) and config/DI/event registration touching these paths. Do NOT analyse code quality — connections only, in your standard output format.
96
+ "Intentionally-absent" requires an explicit cite — a comment in the new file, a commit-message line mentioning the omission, or a type-system constraint that makes the invariant inapplicable (e.g. the peer's `Trial*` methods are absent because the new entity's type says it doesn't support trials). Suspicion is not sufficient; when in doubt, emit Missing.
97
+
98
+ Output format: markdown table per pair, heading `### Peer pair: <new_file> ↔ <peer_file>`. No prose outside the tables. No severity. No recommendations. Citation contract applies to every cell.
99
+ ```
103
100
 
104
- 2. **While the agent runs, the orchestrator produces Discovery Map facts inline** from Step 1's data:
105
- - `ChangedFiles`, `ManifestChanged`, `LockstepSelfReview`, `ReviewType`
106
- - Hunk ranges per file (from `git diff -U0`)
107
- - Commit-message context (if applicable)
108
- - Run the five `WorkflowRiskSignals` commands (Step 1) and record yes/no per group plus the `workflow_risk_gate` aggregate
101
+ While these agents run, the orchestrator produces the rest of the Discovery Map inline from Step 1's data:
102
+ - `ChangedFiles`, `ManifestChanged`, `LockstepSelfReview`, `ReviewType`
103
+ - **Semantic file map** (per file: `path (+A -B)` + role tag + top-level symbol names touched; see format and rules below)
104
+ - Commit-message context (if applicable)
109
105
 
110
- 3. **Wait for ALL agents to complete** before proceeding.
106
+ **Wait for `integration-scanner` AND the peer-mirror agent (when dispatched)** before dispatching Wave-2. Wave-2 agents consume both via the Discovery Map (auth-boundary crossings, inbound refs, peer-mirror Missing/Diverged rows). Precedents / Dependencies / CVE continue running in the background; **Precedents MUST be awaited before Step 5 begins** (Reconciliation reads its follow-up-within-30-days counts to weight severity; see Step 5). Dependencies / CVE also merge in at Step 5 but may arrive later in the wait barrier.
111
107
 
112
- 4. **Synthesize the Discovery Map** — a compact text block that Phase-2 agents receive verbatim as `Known Context`. Finalize `auth_boundary_body` by OR-ing the preliminary Step 1 body-match result with any auth-boundary crossings reported by the integration-scanner, then recompute `workflow_risk_gate`.
108
+ **Synthesize the Discovery Map** — a compact block that Wave-2 agents receive verbatim as `Known Context`. Each file line carries a *role tag* and a *symbols-touched hint*; files are clustered by shared directory prefix so agents orient without re-reading the patch.
113
109
 
114
110
  ```
115
111
  ## Discovery Map
@@ -117,245 +113,303 @@ You are tasked with reviewing changes across three parallel lenses — **Quality
117
113
  Review type: [ReviewType]
118
114
  Scope: [scope argument]
119
115
  Commit/range: [git ref]
120
- Changed files ([N]):
121
- path/a.ts (+A -B)
122
- path/b.ts (+A -B)
123
- Hunks:
124
- path/a.ts: L10-23, L45-60
125
- path/b.ts: L5-8
126
116
  Manifest changed: [yes|no]
127
117
  Lockstep self-review: [yes|no]
128
- Workflow risk signals:
129
- external_io_or_write: [yes|no]
130
- retry_schedule_concurrency: [yes|no]
131
- exported_public_surface: [yes|no]
132
- schema_contract_path: [yes|no]
133
- auth_boundary_body: [yes|no]
134
- workflow_risk_gate: [yes|no]
135
- Auth-boundary crossings: [from integration-scanner output, file:line]
136
- Inbound refs: [from integration-scanner output]
137
- Outbound deps: [from integration-scanner output]
138
- Wiring/config: [from integration-scanner output]
118
+
119
+ Changed files ([N]):
120
+
121
+ ## [cluster — shared directory prefix]
122
+ path/file.ext (+A -B) [role-tag] — top 1–3 symbols touched
123
+ ...
124
+
125
+ Auth-boundary crossings: [integration-scanner, file:line]
126
+ Inbound refs (files with ≥3 consumers): [integration-scanner]
127
+ Outbound deps: [integration-scanner]
128
+ Wiring/config: [integration-scanner]
129
+ Peer mirrors: [peer-mirror agent output verbatim — Missing/Diverged rows only; Mirrored and Intentionally-absent rows are summarised as counts]
139
130
  ```
140
131
 
141
- ## Step 3: Phase-2 Three-Lens Review
132
+ **Clustering**: group files by longest shared directory prefix yielding clusters of 2+ files; singletons form their own cluster labelled with the filename. Emerges from the repo — no framework assumptions.
133
+
134
+ **Role-tag** (one tag per file, first match wins):
135
+ 1. `[boundary]` — in integration-scanner's auth-boundary output
136
+ 2. `[persistence]` — path contains `migration`/`schema`/`repository`/`dao`/`model`, or matches an ORM/migration convention visible in the repo
137
+ 3. `[test]` — path contains `/test`/`/spec`/`__tests__`, or filename ends in a test suffix (`.test.*`, `.spec.*`, `_test.*`, `Test.*`)
138
+ 4. `[config]` — in integration-scanner's wiring/config output, or is a manifest/lockfile/settings file
139
+ 5. `[hub]` — in integration-scanner's inbound-refs with ≥3 consumers
140
+ 6. `[code]` — default
141
+
142
+ **Symbols-touched hint**: extract top 1–3 top-level definitions from the diff's `+` lines using a heuristic appropriate to the file's language (class/function/def/fn/struct/trait/interface/type/export). Cap at ~80 chars. Leave blank if ambiguous — orientation, not completeness.
143
+
144
+ ## Step 3: Dispatch Wave-2 — Quality + Security Lenses
145
+
146
+ Spawn Quality + Security in parallel using the Agent tool. Each receives the `## Discovery Map` block inline as `Known Context` above its task, and a pointer to `/tmp/code-review-patch.diff` for the diff itself. Precedents / Dependencies / CVE are already running from Wave-1 — do NOT re-dispatch them here; the prompts below document what those Wave-1 agents received, they are not re-issued.
147
+
148
+ **Wave-2 context isolation (LOAD-BEARING — violations cause silent quality collapse)**: Each Wave-2 agent receives EXACTLY two things, nothing else: (1) the Discovery Map (digested form) and (2) the literal path string `/tmp/code-review-patch.diff`.
149
+
150
+ **DO NOT paste into Wave-2 prompts**, under any circumstance, even if the orchestrator has already received them:
151
+ - raw integration-scanner output (the Discovery Map already summarises its auth/ref/wiring findings)
152
+ - precedent-locator output
153
+ - Dependencies lens output
154
+ - CVE lens output
155
+ - any prior Wave-2 or Wave-3 output from earlier runs in the same Pi session
156
+
157
+ **Why this is load-bearing**: summary context induces *narrativisation* — the agent treats the preamble as "the orchestrator already framed the findings, I just classify them" instead of independently reading the patch file. Observed failure signatures when this is violated: Quality drops from ~40 tool calls / 3M tokens / 500s to ~5-15 tool calls / 300k tokens / 100-200s, and returns hallucinated findings (invented statuses, mis-cited line numbers, claims that files are "missing from patch" when they are in fact present).
142
158
 
143
- 1. **Spawn Phase-2 agents in parallel** using the Agent tool. Each receives the `## Discovery Map` block inline as `Known Context` above its task.
159
+ **Self-check before dispatching Wave-2**: read your outgoing Agent prompt. If it contains any content from Wave-1 agent RESULTS beyond the Discovery Map you synthesised, strip it. The Discovery Map is the contract; raw outputs are reconciliation-only.
144
160
 
145
- **Always spawn:**
161
+ **Citation contract** (applies to every Wave-2+ agent, every step): every `file:line` citation MUST be accompanied by the literal line text in backticks — format `file:line — \`<verbatim line>\` — <note>`. Omit findings whose lines you cannot quote verbatim.
146
162
 
147
- **Quality lens:**
148
- - subagent_type: `codebase-analyzer`
149
- - Prompt:
163
+ **Quality lens** (`codebase-analyzer`) — **file-oriented**:
150
164
  ```
151
- Known Context:
152
- [paste Discovery Map verbatim]
165
+ Analyse changes file by file. For each file in ChangedFiles, read its diff region in `/tmp/code-review-patch.diff` (patch has `-U30` — full function context is already inline; rarely need an extra Read call), form a mental model of what the file does and what the diff changes about it, then apply the 13 surfaces below to the file as a whole. Cite `file:line` with verbatim line text (citation contract) for every finding. Omit findings not traceable to a diff-touched change. No severity.
153
166
 
154
- Task: Trace data flow through each changed hunk. For every hunk, enumerate `file:line` observations in these buckets do NOT classify severity, the orchestrator does:
155
- 1. Logic-bug risks: missing validation, dropped error paths, off-by-one, null/undefined misses, incorrect branch ordering, forgotten return/await, state mutations without guards.
156
- 2. Pattern divergence: where the hunk deviates from the surrounding file's existing style/structure (cite the nearby line the hunk broke from).
157
- 3. Blast radius: any inbound reference in the Discovery Map that the hunk's behavior change could affect (`consumer.ext:line` + what changes for it).
158
- 4. Test coverage gaps: any risk-bearing behavior the hunk introduces that has no adjacent test reference.
159
- 5. Cross-component consistency (1-hop only): when a hunk touches external I/O, state mutation outside local scope, retry/schedule/concurrency primitives, an exported/public symbol, a schema/contract file, or an auth boundary, compare its behavioral shape against the nearest established analogue reachable within ONE hop via the Discovery Map's inbound/outbound lists. "Behavioral shape" = what the code does, not what it is named (retry policy, I/O ordering and failure handling, input validation depth, concurrency protection, public-API signature and error channel, auth-check placement, observability symmetry, external-contract conformance). Prefer analogues already surfaced by the Discovery Map (inbound/outbound refs, wiring/config entries) or located in the same feature area (same or adjacent directory). Do NOT search broadly across the codebase. Each finding MUST cite both `hunk_file:line` AND `analogue_file:line`. If no 1-hop analogue is evident from the Discovery Map or the same feature area, omit this bucket for that hunk — do not speculate. Evidence only — no fix proposals.
167
+ **File order strategy**: prioritise by role tag `[boundary]` files first (security-sensitive), then `[persistence]` (durable-state surfaces), then `[hub]` (blast-radius amplifiers), then `[code]`, then `[config]`, then `[test]` last. Within the same tag, prioritise files with the largest diffs.
160
168
 
161
- Return evidence only. No recommendations.
169
+ **Per file**, write a short section (`### file/path.ext`) containing only the surfaces that APPLY to that file's changes. Use sub-headings for grouped evidence. A surface may be flagged across multiple files — report the evidence where it lives, and rely on cross-layer surfaces (8, 9) to tie them together.
170
+
171
+ **Surfaces** — each surface's mechanical trigger decides whether it APPLIES to a given file's changes. Walk every applicable trigger:
172
+
173
+ 1. **Logic & flow** (always, per file with new/modified code) — validation, error paths, off-by-one, null misses, branch ordering, return/await, unguarded mutation.
174
+ 2. **Pattern coherence** (≥2 similar constructs within a file, or ≥2 files in the same cluster) — cite nearby line broken from.
175
+ 3. **Blast radius** (Discovery Map lists inbound refs to this file, OR this file is flagged as a hub) — `consumer:line` + what changes for each inbound ref.
176
+ 4. **Test coverage gaps** (always, checked once across the whole changeset) — for each risk-bearing function/method added/changed, check whether any `[test]`-tagged file in ChangedFiles contains a corresponding test. Flag risk-bearing behavior with no adjacent test.
177
+ 5. **Predicate-set coherence** (`HasGatingPredicate`) — ≥2 conditionals on the same enum/type across the changeset. Tabulate `predicate file:line | accepted | rejected`. Flag mismatches. Surface 5 output MUST use heading `### Predicate-set coherence` at review-scope level (not nested inside a per-file section) — downstream step consumes it verbatim.
178
+ 6. **Registration coverage** (changeset adds discriminator value / enum variant / handler key / route / event type / strategy entry) — every dispatch/registry/switch across ChangedFiles that must enumerate it. Cite each registration site + each enumeration site. Flag gaps.
179
+ 7. **Query/write symmetry** (changeset adds setter/linker, shape change, or new persisted field) — trace BOTH creation and renewal/update paths; cite the setter file:line AND the reader file:line.
180
+ 8. **Cross-layer drift** (same entity/enum/key appears in ≥2 files in different clusters or role tags — e.g. model ↔ DTO ↔ schema ↔ registry ↔ presentation) — open each file, tabulate presence, flag asymmetry. When the entity is a **key fanned out across parallel tables** (locale maps, theme maps, strategy registries, handler/command tables, feature-flag tables), every table must carry the added key and none must retain a removed/renamed one — flag orphaned references and missing entries.
181
+ 9. **Peer-member consistency** (a file gains a new method/hook/case/handler in a set of peers — class methods, hook siblings, reducer cases, handler registrations, CLI subcommands) — tabulate the invariants the peers share (state mutation, emitted event/signal, precondition guard, bookkeeping counter, teardown symmetry); flag omissions in the new member.
182
+ 10. **Durable-state hygiene** (file is a schema migration, repository/DAO, file-backed config, KV/cache, serialized artifact, or adds a new persisted field) — trace the forward-write AND the reverse/rollback path; flag irreversible or data-losing rollback, missing lookup affordance for a new query field (index, key, sorted structure), iteration over an unbounded/mutable source without a stable cursor, and new invariants at the storage layer not mirrored by the in-memory validator.
183
+ 11. **Shared-state acquisition** (file introduces async handler, event listener, singleton init, queue consumer, file-lock region, or global cache mutation) — trace acquire/release around every mutation; flag unguarded check-then-act across an `await`/callback/IPC boundary, stale reads while another writer is in flight, non-commutative acquire order between distinct state slots, and replay/retry paths that lack an idempotency key.
184
+ 12. **Multi-step commitment** (file issues ≥2 writes that must all succeed or all be undone — DB transaction, cross-table mutation, multi-file write, filesystem+network pair, multi-API orchestration, compensating-action chain) — trace the commit boundary; flag missing undo/compensation on partial failure, retry paths that re-apply non-idempotent steps, and divergence between two stores that must agree without a coordinating primitive.
185
+ 13. **Error handling & idempotency** (file adds a failure-response construct — retry loop, catch/except block, error boundary, fallback branch, circuit breaker, timeout, resumable step) — trace the error-propagation path; flag swallowed errors, retry without an idempotency key, fallback that silently degrades observable behavior, unjustified timeout values.
186
+
187
+ **Economising Reads**: issue a `Read` only when (a) you need a file NOT in ChangedFiles (hub, peer, test), or (b) the changed function is longer than the `-U30` window can show. Never re-Read a file just to re-orient — that's what the symbols-touched hint is for.
162
188
  ```
163
189
 
164
- **Security lens:**
165
- - subagent_type: `codebase-analyzer`
166
- - Prompt:
190
+ **Security lens** (`codebase-analyzer`) — **file-oriented**:
167
191
  ```
168
- Known Context:
169
- [paste Discovery Map verbatim]
170
-
171
- Task: Grep each changed hunk for the following sink patterns and list every match with `file:line` + surrounding 3 lines. Cross-reference the Discovery Map's Auth-boundary crossings.
172
- For each hit, additionally return `confidence: N/10` reflecting how certain you are that a user-controlled input can reach this sink under current deployment. Do NOT report hits with confidence < 8.
173
- - Command execution: `exec(`, `execSync(`, `execFile(`, `child_process`, `spawn(`
174
- - Dynamic evaluation: `eval(`, `new Function(`
175
- - SQL template-interpolation: multi-line `` `SELECT ... ${ ``, `` `INSERT ... ${ ``, `` `UPDATE ... ${ ``, `` `DELETE ... ${ ``
176
- - XSS sinks: `innerHTML =`, `dangerouslySetInnerHTML`, `document.write(`
177
- - Path traversal: string concatenation into `fs.readFile`, `fs.writeFile`, `path.join` with user input
178
- - SSRF: `fetch(`, `http.request(`, `axios(`, `got(` where HOST or PROTOCOL (not just path) is user-controlled
179
- - Secrets in diff: `api_key`, `secret`, `password`, `BEGIN PRIVATE KEY`, `.env` content literal
180
- - Missing auth guard: auth-boundary crossings (from Discovery Map) reaching a traced sink without an upstream guard
181
-
182
- Hard exclusionsdo NOT report:
183
- - DOS / resource exhaustion / rate limiting / memory or CPU exhaustion
184
- - Missing hardening in isolation (no traced sink), lack of audit logs
185
- - Theoretical race conditions / timing attacks without a concrete reproducer
186
- - Log spoofing, prototype pollution, tabnabbing, open redirects, XS-Leaks, regex DOS, regex injection
187
- - Client-side-only authn/authz gaps (server is the authority)
188
- - XSS in React/Angular/tsx files unless via `dangerouslySetInnerHTML`, `bypassSecurityTrustHtml`, or equivalent
189
- - Findings whose sole source is an environment variable, CLI flag, or UUID (trusted in our threat model)
190
- - Findings in test-only files or `.ipynb` notebooks without a concrete untrusted-input path
191
- - Outdated-dependency CVEs (handled by the dependencies/CVE lens)
192
-
193
- For each hit, name the pattern and quote the line. Return evidence only. No CVE lookups — that is a separate agent.
192
+ Analyse each changed file as a whole, looking for sinks in the classes below. For each file, grep the file's diff region in `/tmp/code-review-patch.diff` (patch has `-U30` — sink context is inline) for the sink patterns, and for each hit provide the verbatim line (citation contract) plus 2 surrounding lines and `confidence: N/10` that user-controlled input can reach the sink under current deployment. Drop hits with confidence < 8. Cross-reference Discovery Map auth-boundary crossings and inbound refs — a sink in a file reached from an auth-boundary file is in scope even if the sink file itself doesn't cross the boundary.
193
+
194
+ **File order strategy**: `[boundary]` files first (direct source→sink exposure); then `[persistence]` (query injection, unsafe deserialization); then `[code]` (command exec, SSRF, explicit-trust rendering); then `[hub]` / `[config]`; skip `[test]` unless a test helper touches a sink.
195
+
196
+ IN-SCOPE RULE: only report findings whose sink line is inside a changed file's diff region (add/modify/adjacent-context rewrite). Pre-existing sinks in files the diff did not change are out of scope, UNLESS the diff changes how data flows TO the sink (e.g. new user-controlled source routed to an untouched sink) then cite both locations. When in doubt, trace data flow from Discovery Map boundary crossings through the changed files.
197
+
198
+ Sink classes match the concept in whatever language the diff uses:
199
+ - **Command execution** shell/process spawn w/ user input (e.g. `exec`, `subprocess.run(shell=True)`, `Runtime.exec`, …).
200
+ - **Dynamic code / unsafe deserialization** — `eval` / dynamic-function constructors; deserializers that can execute code (e.g. `pickle.loads`, `yaml.load` w/o safe loader, `ObjectInputStream`, `BinaryFormatter`, …).
201
+ - **Query injection** user input concatenated or interpolated into a query string interpreted by an external engine (SQL, NoSQL operators, LDAP filters, XPath, GraphQL constructed as string). Parameterized/prepared queries and typed query builders are safe.
202
+ - **Explicit-trust rendering** — user input emitted into a channel that will interpret it as code/markup rather than data. In-scope only when the framework's explicit-trust API is invoked (`dangerouslySetInnerHTML`, `bypassSecurityTrustHtml`, `v-html`, `template.HTML`, `mark_safe`, `html_safe`, triple-stache, raw-HTML markdown, …), plain `innerHTML =` / `document.write(` in vanilla/server-rendered code, or equivalent passthroughs in non-HTML renderers (unescaped ANSI-escape emission to a TTY, unquoted shell-prompt interpolation, template-engine raw blocks).
203
+ - **Path traversal** user-controlled components into file-system APIs without normalization/allowlist.
204
+ - **SSRF** outbound HTTP/TCP with user-controlled host OR protocol (not just path).
205
+ - **Secrets in diff** — literal credentials, API keys, PEM blocks, connection strings w/ embedded passwords, `.env` content.
206
+ - **Missing trust-boundary check** a traced sink reached from a Discovery-Map boundary crossing (HTTP handler, RPC endpoint, IPC message, CLI flag that flows to a privileged operation, webhook receiver) without an upstream authorization/validation step (middleware, guard, attribute/decorator, allowlist check, signature verification).
207
+
208
+ Do NOT report: DOS/resource exhaustion/rate-limiting, missing hardening without a traced sink, theoretical races/timing without reproducer, log spoofing/prototype pollution/tabnabbing/open redirects/XS-Leaks/regex DOS, client-side-only authn/authz (server is the authority), findings sourced only from env var / CLI flag / UUID, test-only or notebook files without a concrete untrusted-input path, outdated-dependency CVEs (CVE lens handles).
209
+
210
+ Name the sink class and the matched idiom. Evidence only. No CVE lookups.
194
211
  ```
195
212
 
196
- **Dependencies lens:**
197
- - subagent_type: `codebase-analyzer`
198
- - Prompt (only when `ManifestChanged` is true; otherwise SKIP this lens and omit the `### Dependencies` H3 block from the artifact):
213
+ **Dependencies lens** (`codebase-analyzer`, only when `ManifestChanged`; otherwise SKIP and omit `### Dependencies` in artifact):
199
214
  ```
200
- Known Context:
201
- [paste Discovery Map verbatim]
202
- Lockstep self-review: [LockstepSelfReview yes|no]
203
-
204
- Task: For each dependency-manifest file in the diff, infer its ecosystem primarily from the canonical manifest filename and nearby syntax in the diff (npm/yarn/pnpm, pip/poetry/uv, NuGet/MSBuild, Go modules, Cargo, Gem/Bundler, Maven/Gradle, Composer, SwiftPM/CocoaPods, Mix, Pub, Terraform lock, Docker base-image pins). If the ecosystem is ambiguous (e.g., `pyproject.toml` that could be Poetry, PEP-621, Hatch, or uv; `global.json` that may be SDK-only vs. tool-manifest; `Dockerfile` with multi-stage base-image pins), STATE the ambiguity explicitly rather than guessing — list the file with a "`ecosystem: ambiguous (<candidates>)`" marker and proceed conservatively.
205
-
206
- Then list:
207
- 1. Added dependencies: `ecosystem:name@version` with `file:line`.
208
- 2. Bumped dependencies: `ecosystem:name: old -> new` with `file:line`.
209
- 3. Removed dependencies.
210
- 4. Pin-strength changes (exact ↔ range, floating ↔ pinned).
211
- 5. Peer/centrally-managed version changes (`peerDependencies`, `dependencyManagement`, `Directory.Packages.props`, Gradle version catalogs).
212
- 6. Transitive-only drift (lockfile-only moves).
213
- 7. Runtime/SDK/toolchain pin changes (`engines`, `global.json` SDK, `go.mod` toolchain, `rust-toolchain.toml`, `.nvmrc`, `.python-version`) — list as architectural notes.
214
- 8. When Lockstep self-review is `yes`: flag only intra-monorepo version drift where a sibling pin diverges from the lockstep `version:` governed by `scripts/sync-versions.js`. Treat `"*"` peer pins as intentional.
215
- 9. When Lockstep self-review is `no`: flag version-conflicts between a direct dep and its lockfile resolution.
216
-
217
- Return evidence only. No CVE lookups — that is a separate agent.
215
+ Lockstep self-review: [yes|no]
216
+
217
+ Identify the ecosystem from touched manifests (npm, Cargo, Go modules, PyPI/Poetry, Bundler, NuGet, Maven/Gradle, …). Parse the changed manifest(s) and list:
218
+ 1. Added deps: `name@version` with `file:line`.
219
+ 2. Bumped deps: `name: old -> new` with `file:line`.
220
+ 3. Removed deps.
221
+ 4. Peer / optional / dev-scope changes (whatever the ecosystem calls them).
222
+ 5. License field changes in manifest or lockfile.
223
+ 6. Lockstep=yes: flag only intra-monorepo drift where a sibling pin diverges from the lockstep version. Treat wildcard peer pins as intentional.
224
+ 7. Lockstep=no: flag version conflicts between direct dep and lockfile resolution.
225
+
226
+ Evidence only. No CVE lookups.
218
227
  ```
219
228
 
220
- **Precedents lens:**
221
- - subagent_type: `precedent-locator`
222
- - Prompt:
229
+ **Precedents lens** (`precedent-locator`):
223
230
  ```
224
- Planned change: code review of [scope]. Changed files: [ChangedFiles].
225
- Find the most similar past changes that touched these files or files nearby. For each precedent, report the commit hash, blast radius, any follow-up fixes within 30 days, and the one-sentence takeaway. Distil composite lessons across all precedents.
231
+ Code review of [scope]. Changed files: [ChangedFiles].
232
+ Find similar past changes touching these files or nearby. Per precedent: commit hash, blast radius, follow-up fixes within 30 days, one-sentence takeaway. Distil composite lessons.
226
233
  ```
227
234
 
228
- **Conditional spawn** (only when `ManifestChanged` is true):
235
+ **CVE/advisory lens** (`web-search-researcher`, only when `ManifestChanged`):
236
+ ```
237
+ Look up CVEs / GitHub Advisories / OSS Index entries for the target versions. Return LINKS. Per vulnerability: severity (Critical/High/Moderate/Low), affected range, whether bumped-to version is fixed.
229
238
 
230
- **CVE/advisory lens:**
231
- - subagent_type: `web-search-researcher`
232
- - Prompt:
239
+ Dependencies:
240
+ [name@version per line — orchestrator-extracted]
233
241
  ```
234
- For each of the following dependency changes, look up known CVEs / GitHub Advisories / OSS Index entries in the target version. If a vulnerability exists, summarize severity (Critical / High / Moderate / Low), affected version range, and whether the bumped-to version is fixed.
235
242
 
236
- Dependencies to check (format each as `ecosystem:name@version` so the advisory lookup hits the right database; common ecosystems: npm, pypi, nuget, go, crates, rubygems, maven, composer, swift, hex, pub, terraform, oci-image):
237
- [name@version or ecosystem:name@version, one per line — extracted by orchestrator from the diff]
243
+ **Wait for Quality + Security to complete** before proceeding. Precedents / Dependencies / CVE from Wave-1 may still be running; gather them before Step 5, not before Step 4.
244
+
245
+ ## Step 4: Dispatch Wave-3 — Predicate-Trace + Interaction Sweep + Gap-Finder
246
+
247
+ Once Wave-2 (Quality + Security) completes, dispatch all three gated agents below **in a single message with multiple Agent tool calls**. They do NOT consume each other's output:
248
+
249
+ - **Interaction Sweep (4b)** receives Quality's `Predicate-set coherence` table directly as its predicate-row source. Quality's table already flags mismatches — Predicate-Trace (4a) only *elaborates* them through consumers. Interaction Sweep's categories 1–6 don't need 4a at all; categories 7–9 (stranded-state, false-promise, co-tenant filter gap) operate on the same rows 4a would trace.
250
+ - **Gap-Finder (4c)** is explicitly a coverage-check against lens findings. The skill's rule *"Do NOT re-analyse what lenses already found"* (Step 4c body below) means it deliberately ignores 4a/4b output — running it in parallel preserves intent.
251
+ - If Predicate-Trace (4a) surfaces a row that was not visible in Quality's table, append it via a Step 9 follow-up — cheaper than a serial gate.
238
252
 
239
- Query GHSA / OSV.dev / ecosystem-specific databases (RustSec, Trivy for images) as appropriate. Return LINKS alongside findings.
253
+ ### Step 4a: Predicate-Trace
254
+
255
+ **Gate**: SKIP this sub-step (do not dispatch 4a) unless `HasGatingPredicate` is true AND the Quality lens returned ≥2 rows in its `Predicate-set coherence` table referencing the same enum/type. If skipped, 4b and 4c still dispatch.
256
+
257
+ Otherwise spawn ONE `codebase-analyzer` in parallel with 4b and 4c:
240
258
  ```
259
+ Coherence rows (Quality — Predicate-set coherence): [paste verbatim]
260
+ Gating predicates in diff: [`file:line` list]
241
261
 
242
- 2. **Wait for ALL agents to complete** before proceeding.
262
+ Per predicate, return: `predicate file:line | inputs | promise (what TRUE/matching branch implies) | consumer file:line | consumer filter | fulfils? | gap`.
243
263
 
244
- ## Step 4: Cross-Finding Interaction Sweep
264
+ Flag:
265
+ - *False promise* — matching branch depends on a consumer/filter elsewhere that excludes this entity's source/type/state.
266
+ - *Stranded state* — entity reaches state X via one conditional, but every conditional that operates on this entity elsewhere excludes X (no exit path).
267
+
268
+ Evidence only. Citation contract applies.
269
+ ```
245
270
 
246
- 1. **Evaluate the gate**. SKIP this step (go directly to Step 5) only when ALL of the following are true:
247
- - `len(ChangedFiles) < 2`, AND
248
- - Quality lens returned fewer than 4 total observations across all hunks, AND
249
- - `workflow_risk_gate` on the Discovery Map is `no`, AND
250
- - `precedent-locator` did not return any follow-up fix within 30 days for files in `ChangedFiles`.
271
+ Do NOT wait 4b (Interaction Sweep) and 4c (Gap-Finder) dispatch in the same message as 4a.
251
272
 
252
- 2. **Spawn the interaction-sweep agent** using the Agent tool:
273
+ ### Step 4b: Interaction Sweep
253
274
 
254
- - Use **codebase-analyzer** to perform a cross-finding interaction sweep over Phase-2 evidence.
275
+ **Gate**: SKIP this sub-step (do not dispatch 4b) when EITHER `len(ChangedFiles) < 2` OR the Quality lens returned fewer than 4 total observations across all files. Emergent interactions need surface area; tiny diffs cannot structurally produce them.
255
276
 
256
- Agent prompt:
277
+ Otherwise spawn ONE `codebase-analyzer` in parallel with 4a and 4c:
257
278
  ```
258
- Known Context:
259
- [paste Discovery Map verbatim]
279
+ Quality Evidence: [verbatim]
280
+ Security Evidence: [verbatim]
281
+ Predicate-set coherence rows (verbatim from Quality's table — full Step 4a output is NOT required and is NOT awaited): [verbatim | "not applicable"]
282
+ Precedents: [verbatim if Wave-1 finished; else "deferred to Step 5"]
283
+
284
+ Group evidence by shared entity, state machine, workflow, data flow path, API boundary, background process, or producer-consumer contract.
285
+
286
+ Per group, check for emergent defects:
287
+ 1. contradictory assumptions between components/layers,
288
+ 2. unreachable, stuck, or non-terminal states,
289
+ 3. retry/reprocess mechanisms made inert by another behavior,
290
+ 4. duplicate-processing / idempotency gaps from ordering or missing guards,
291
+ 5. guards in one layer invalidating transitions in another,
292
+ 6. one finding masking, amplifying, or permanently triggering another,
293
+ 7. stranded state — state X reachable via one conditional but every conditional operating on this entity elsewhere excludes X,
294
+ 8. false-promise predicate — matching branch's consumer excludes this entity's source/type/state,
295
+ 9. co-tenant filter gap — shared discriminator filter where a new or terminal value the diff touches falls through every consumer's filter.
296
+
297
+ Return only findings with ≥2 concrete `file:line` facts from different files/components, each quoted verbatim per the citation contract. No recommendations. No single-location repeats.
298
+
299
+ For findings involving ordering/races/concurrency across processes or handlers, name the ordering primitive that would prevent the race (distributed lock, exclusive-key wrapper, ordered partition, transaction, idempotency key, etc.) and explain why it does NOT apply here. Drop the finding if the primitive exists in the diff or nearby and your argument against it is speculative.
300
+ ```
301
+
302
+ Do NOT wait — 4c (Gap-Finder) dispatches in the same message.
260
303
 
261
- Quality Evidence:
262
- [paste Quality lens output verbatim]
304
+ ### Step 4c: Gap-Finder
263
305
 
264
- Security Evidence:
265
- [paste Security lens output verbatim]
306
+ **Gate**: SKIP this sub-step (do not dispatch 4c) when `len(ChangedFiles) < 2`. Tiny diffs cannot structurally have coverage gaps.
307
+
308
+ Otherwise spawn ONE `codebase-analyzer` in parallel with 4a and 4b. The prompt intentionally omits 4a/4b output (they are not awaited); Gap-Finder's job is to find FILES (or specific risk-bearing regions within them) no LENS covered, not to audit 4a/4b. Scope is deliberately limited to risk-bearing file roles with non-trivial deltas — the 5-finding cap makes a full walk wasteful:
309
+ ```
310
+ All lens findings so far:
311
+ Quality Evidence: [verbatim]
312
+ Security Evidence: [verbatim | "not applicable"]
266
313
 
267
- Precedents:
268
- [paste precedents output verbatim]
314
+ Diff patch: Read `/tmp/code-review-patch.diff` (already assembled with `-U30`, so full function context is inline).
315
+ Discovery Map: [verbatim]
269
316
 
270
- Task: Perform a cross-finding interaction sweep. Group the evidence by shared entity, state machine, workflow, data flow path, API boundary, background process, or producer-consumer contract.
317
+ **In-scope files only**: restrict the walk to files tagged `[boundary]`, `[persistence]`, `[code]`, or `[hub]` AND whose diff delta is ≥ 5 lines (added + removed). SKIP all `[test]` and `[config]` files, and skip files with tiny deltas. These categories almost never produce gap findings under the 5-finding cap, and walking them consumes the bulk of Gap-Finder's runtime without improving recall.
271
318
 
272
- For each group, check whether multiple local observations combine into an emergent defect. The sweep checks two tiers of defect classes abstract cross-stack classes first, then the original local-composition checks:
319
+ Task: Walk the in-scope files. For each file, check whether ANY existing finding above already covers its risk-bearing behaviors. A file's behavior is "risk-bearing" if the diff introduces: state mutations, I/O operations (DB/network/file), error paths, conditional logic on mutable state, concurrent/shared-state access, or a public API surface change.
273
320
 
274
- Abstract cross-stack defect classes (check these first):
275
- A1. Dual-write divergence: two sinks that must stay consistent were updated asymmetrically, or one was updated and the other was not. Covers write/read models, cache/source-of-truth, replica/primary, index/source, client-optimistic/server-authoritative, migration/ORM model.
276
- A2. Invariant-enforcement gap: a check enforced on one call path is bypassed on a sibling path. Covers auth scoping, tenant/account/workspace scoping, input validation, rate limiting, ACL, quota, feature flag.
277
- A3. Coupled-lifecycle mismatch: two artifacts that must evolve together and only one did. Covers API schema ↔ client, protobuf ↔ codegen ↔ consumer, migration ↔ model, IaC ↔ app config, event schema ↔ consumer.
321
+ Flag files whose risk-bearing behavior has NO corresponding finding. For each flagged file:
322
+ - Quote the specific `file:line` range and verbatim code per the citation contract
323
+ - State what risk-bearing behavior it contains (method name, behavior class)
324
+ - Explain why no existing finding covers it (1 sentence)
278
325
 
279
- Original local-composition checks:
280
- L1. Contradictory assumptions between components or layers.
281
- L2. Unreachable, stuck, or non-terminal states.
282
- L3. Retry/reprocess mechanisms made inert by another behavior.
283
- L4. Duplicate-processing or idempotency gaps from ordering or missing guards.
284
- L5. Guards in one layer invalidating transitions in another.
285
- L6. One finding masking, amplifying, or permanently triggering another.
326
+ Do NOT re-analyse what lenses already found — only flag GAPS in coverage. Maximum 5 gap findings total across the changeset. Stop walking once 5 gaps are flagged. Citation contract applies.
286
327
 
287
- Return only interaction findings backed by explicit evidence from at least two concrete file:line locations from different files or different components. No recommendations. Do not repeat single-location findings.
328
+ File order: follow role-tag priority (`[boundary]` `[persistence]` `[hub]` `[code]`).
288
329
  ```
289
330
 
290
- 3. **Wait for the interaction-sweep agent to complete** before proceeding.
331
+ **Wait for ALL of 4a / 4b / 4c AND the Precedents agent from Wave-1 to complete** before proceeding to Step 5 (Reconciliation). Precedents is a **hard gate** — severity weighting in Step 5 reads its follow-up-within-30-days counts. Dependencies / CVE (when dispatched) also merge in here but are not individually hard-gated; wait for them too unless they clearly exceed the review SLA, in which case omit `## Dependencies` and note it in the artifact.
291
332
 
292
333
  ## Step 5: Reconcile Findings
293
334
 
294
- 1. **Compile evidence** from every lens and the interaction sweep (when it ran):
295
- - Quality evidence → classify each `file:line` observation into severity:
296
- - 🔴 Critical: traced flow contradiction (dropped error path, missing validation on a known sink, null-deref).
297
- - 🟡 Important: blast-radius × complexity-delta (hot path + new allocation, visible ABI change without migration).
298
- - 🔵 Suggestion: pattern divergence with a concrete nearby template.
299
- - 💭 Discussion: composite-lesson architecture concerns.
300
- - Bucket-5 (cross-component consistency) findings default to 🔵 when the divergence is structural only. Promote to 🟡 when the hunk touches I/O, an exported/public surface, a schema/contract, or an auth boundary, OR when the Discovery Map lists a concrete inbound consumer whose behavior changes. 🔴 promotion must come through the interaction sweep's defect classes, not the Quality lens alone.
301
- - Security evidence classify:
302
- - 🔴 sink hit with a CONCRETE user-reachable source→sink path traced through Discovery Map auth-boundary crossings. Reject any hit lacking an explicit trace.
303
- - 🟡 crypto-only concrete issues: weak hash in an auth/integrity role (MD5/SHA1), non-constant-time compare on secrets, hardcoded key material in diff. Do NOT use 🟡 for "missing hardening".
304
- - 🔵 pattern divergence from a secure example in the SAME file (cite the nearby secure `file:line`).
305
- - 💭 architectural question.
306
- - Dependencies evidence classify:
307
- - 🔴 Known-exploitable CVE in a touched dep (Critical/High per advisory DB) OR lockstep-contract violation (would trip `scripts/sync-versions.js`).
308
- - 🟡 Moderate CVE, outdated major with a migration path, license incompatibility with the project license.
309
- - 🔵 Minor/transitive drift.
310
- - 💭 Architectural dep question.
311
- - Interaction-sweep evidence → classify (🔴/🟡 only; no 💭 tier — the sweep must produce concrete emergent defects, not speculation):
312
- - 🔴 Critical: concrete emergent failure across 2+ `file:line` facts from different files/components (stranded state, duplicate-processing path, inert retry, producer/consumer contradiction).
313
- - 🟡 Important: concrete multi-component mismatch with bounded blast radius or an existing mitigation.
314
- - Precedents → compile into a separate `## Precedents & Lessons` section orthogonal to per-lens findings. Composite lessons go at the bottom of that section.
335
+ **Barrier**: Step 5 MUST NOT begin until the Precedents agent has returned. Severity weighting depends on historical follow-up counts; starting reconciliation without them produces mis-weighted severities that the verification pass (Step 6) cannot correct.
336
+
337
+ **Resolution integrity check** (load-bearing): when Precedents returns a commit that claims to resolve or supersede a current finding, run `git merge-base --is-ancestor <precedent-hash> <TIP>` before accepting the resolution.
338
+ - Ancestor: the precedent IS in the reviewed branch; mark the finding `resolved-by: <hash>` and demote its severity to 💭 (kept for context).
339
+ - Not ancestor: the precedent is on a different branch / not merged; treat it as **context only**. Do NOT mark the finding resolved; annotate the precedent's row in `## Precedents` third column `NOT ancestor of [TIP] (context only)`.
340
+ - Orchestrator unable to run git (e.g., `staged` / `working` scope with no commit): skip the check and annotate `resolution: unverified`.
341
+
342
+ 1. **Compile and classify evidence** per lens:
343
+ - **Quality** — 🔴 traced flow contradiction (dropped error path, missing validation on a sink, null-deref); 🟡 blast-radius × complexity-delta (hot path + new allocation, ABI change without migration); 🔵 pattern divergence with nearby template; 💭 composite-lesson architecture concern.
344
+ - **Security** — 🔴 concrete user-reachable source→sink trace via Discovery Map auth-boundary (reject hits without explicit trace); 🟡 concrete crypto issue (weak hash in auth/integrity role, non-constant-time compare, hardcoded key material); 🔵 divergence from a secure example in the same file; 💭 architectural question.
345
+ - **Dependencies** 🔴 Critical/High CVE in touched dep OR lockstep-contract violation; 🟡 Moderate CVE, outdated major with migration path, license incompatibility; 🔵 minor/transitive drift; 💭 architectural dep question.
346
+ - **Interaction-sweep** — 🔴/🟡 only (no 💭): 🔴 concrete emergent failure across ≥2 files/components; 🟡 multi-component mismatch with bounded blast radius or existing mitigation. **Promotion rule**: when ≥2 lens findings share the same entity/flow and combine into an emergent failure, the aggregate is 🔴 even if each constituent was 🟡/🔵. The interaction IS the defect — don't leave constituents at their original severity and skip the cross-finding bullet.
347
+ - **Gap-finder** 🟡 uncovered risk-bearing region in a changed file with no lens coverage; 🔵 low-impact gap (style-only or defensive-only region missed). No 🔴 (gap findings are uncertain by nature).
348
+ - **Peer-mirror** — treat every Missing/Diverged row as a finding. Base severity 🔵. **Bump to 🟡** when the missing invariant is a domain-event emission, a precondition guard on a state-mutating method, or a persisted-field invariant. **Bump to 🔴** when the missing invariant intersects a dispatch site the diff touches (switch/map/table/registry enumerating the peer's type alongside the new type — detectable from integration-scanner's `Wiring/config` output and the Discovery Map's `[config]`/`[hub]` files). Rationale: a missing mirror on a dispatched invariant is a silent-stranded-state cascade constituent; on a non-dispatched invariant it is a style issue. Record every peer-mirror bump in `## Reconciliation Notes`.
349
+ - **Precedents** compile into `## Precedents` (table: `hash | subject | 30d-follow-ups | note`), composite lessons below. **Severity weighting**: for each current finding, count precedent commits touching the same symbol/file that had ≥1 follow-up fix within 30 days. If count ≥ 2, bump the finding one severity tier (🔵→🟡, 🟡→🔴); cap at 🔴. Record the bump by annotating the finding's title line `[precedent-weighted]` — do NOT emit a separate reconciliation section.
315
350
 
316
351
  2. **Probe advisor availability** — attempt a probe by checking whether `advisor` is in the active tool set (main-thread visibility). If yes, proceed to advisor path; otherwise take the inline path.
317
352
 
318
353
  3. **Advisor path** (when advisor is active):
319
354
  - Print a main-thread `## Pre-Adjudication Findings` block first — the advisor reads `getBranch()`, so evidence must be flushed before the call.
320
- - Call `advisor()` (zero-param). If it returns usable prose, paste it verbatim into `## Advisor Adjudication` and skip the inline path. Otherwise fall through.
355
+ - Call `advisor()` (zero-param). If it returns usable prose, paste it verbatim as a blockquote at the top of `## Recommendation` and skip the inline path. Otherwise fall through.
321
356
 
322
357
  4. **Inline path** (advisor unavailable or errored):
323
358
  - Run a dimension-sweep modeled on `skills/design/SKILL.md:83-116`: Data model / API surface / Integration / Scope / Verification / Performance.
324
359
  - For every finding, ask: does another finding contradict this severity given the Discovery Map? If yes, note the tension.
325
- - Produce a short `## Reconciliation Notes` block inside the artifact capturing any severity moves and the rationale.
360
+ - Record every severity move as a title-line annotation on the affected finding (`[precedent-weighted]`, `[cascade: <kind>]`, `[subsumed-by <ID>]`). No standalone reconciliation section.
326
361
 
327
362
  5. **Emit the reconciled severity map** — authoritative severity per finding, carrying the advisor's guidance when present. Keep the per-pass grouping (do NOT tag each finding with its originating lens in prose; the H2 it sits under is the tag).
328
- - Interaction findings live in their own `### Cross-Finding Interactions` H3 under `## Issues Found`, not folded into per-lens H3s.
329
- - When an interaction finding subsumes multiple local findings, keep the local findings if still actionable, but lead with the interaction finding and explain the relationship in `## Reconciliation Notes`.
363
+ - Interaction findings carry `I<n>` IDs and appear under the severity H2 that matches their final tier (`## 🔴 Critical`, `## 🟡 Important`). The old `### Cross-Finding Interactions` sub-heading is retired severity is the top-level grouping.
364
+ - When an interaction finding subsumes a local finding at the root-cause level, keep the local finding only if its evidence is independently actionable; annotate the local finding's title line `[subsumed-by I<n>]`.
365
+ - Distinct structural defects MUST remain distinct findings even when related. Specifically: a *stranded state* (entity reaches X, no exit path) and a *false-promise predicate* (TRUE branch promises unreachable behavior) are separate defects even when they arise in the same subsystem — do NOT collapse them. Collapse only when the narrative, fix, and evidence locations are identical.
366
+ - **Cascade detection** (load-bearing): before emitting severities, scan findings for these triples and emit a 🔴 Cross-Finding bullet if any fires —
367
+ • *{entity reaches state X} + {no event on that transition} + {consumer filter excludes X}* = **silent stranded state**
368
+ • *{check-then-act on shared resource} + {no ordering primitive} + {retry/replay path}* = **duplicate-processing cascade**
369
+ • *{spec A accepts Y} + {spec B rejects Y} + {workflow depends on both}* = **contradictory-predicate deadlock**
370
+ Also check `thoughts/shared/reviews/*.md` and Precedents: if a prior review names a cascade whose constituents appear in current findings, cite it and assert reproduction. Missed cascades are the biggest historical quality regression; prefer false positives here.
330
371
 
331
- ## Step 6: Developer Checkpoint
372
+ ## Step 6: Verify Findings
332
373
 
333
- Use the grounded-questions-one-at-a-time pattern. Every question must reference real findings with `file:line` evidence and pull a DECISION from the developer.
374
+ Before writing the artifact, spawn ONE `codebase-analyzer` whose sole job is to ground every reconciled finding in the actual code at its cited `file:line`. This catches two classes of error the lenses cannot self-detect: (a) *confident assertions* the agent never opened a file to confirm, and (b) *rationalisations* ("intentional-by-design", "pre-existing", "not a real deadlock") that contradict what the code does. Lens agents reason from the patch; the verifier reasons from the file.
334
375
 
335
- **Present a compiled scan first** (under 20 lines):
376
+ **Dispatch** after Step 5's reconciled severity map is final, before Step 7 writes anything:
336
377
 
337
- ```
338
- Review: [scope]
339
- Files: [N]
340
- Quality: [C🔴/I🟡/S🔵/D💭]
341
- Security: [C/I/S/D]
342
- Dependencies: [C/I/S/D | not-applicable]
343
- Precedents: [N composite lessons, top: "[one-line]"]
344
- Advisor: [adjudicated | inline]
345
- ```
378
+ ```
379
+ Verify each finding below against the actual repository state. You have Read access to the whole tree.
380
+
381
+ Findings (verbatim from Step 5):
382
+ [paste the full reconciled severity map — each finding with its file:line citation, verbatim line quote per the citation contract, and severity tier]
383
+
384
+ For EACH finding:
385
+ 1. Open the cited file at the cited line using Read. Confirm the verbatim quote appears at that line.
386
+ 2. If the finding makes a claim about behavior reachable elsewhere (consumer filters, dispatch registrations, peer aggregates, upstream guards, downstream sinks), Read those referenced files too. Do NOT trust the patch-only view.
387
+ 3. If the finding claims a state is "stranded" / a predicate is "false-promise" / a precondition is "missing" — construct a concrete 2–3 line reproducer trace: "caller at A:L invokes B:L with entity in state X; guard at C:L rejects; exit path would require D which the code does not provide." If you cannot construct it, the finding is Weakened.
388
+ 4. If the finding was marked `resolved-by: <hash>` in Step 5, Read the resolving commit's changes on the reviewed branch (via `git show <hash> -- <file>`) and confirm the resolution is actually present at TIP.
389
+
390
+ Return ONE tag per finding — output format:
346
391
 
347
- Wait for the developer's response. Then ask **one question at a time**, waiting for each answer.
392
+ FINDING <id> | <tag> | <one-sentence justification citing a file:line>
393
+
394
+ Tags:
395
+ - Verified — quote matches, claim is reproducible against the actual code, no contradiction found
396
+ - Weakened — claim is partially true but narrower than stated (severity should drop one tier), OR it relies on a consumer-side assumption that the actual consumer does not make
397
+ - Falsified — quote does not match, OR the claimed behavior is contradicted by code the lens did not read (peer site, upstream guard, existing handler, resolution already applied)
398
+
399
+ Be explicit about contradictions. If finding A says "intentional by design" and finding B says "stranded state" about the same entity, mark the one whose claim the code does NOT support as Falsified and cite the contradicting line.
400
+
401
+ Citation contract applies to every justification. No recommendations. No new findings.
402
+ ```
348
403
 
349
- **Question patterns:**
404
+ **Apply the tags**:
405
+ - **Falsified** findings — remove from the artifact entirely. Their ID is retired (never reused); the retirement is counted in the frontmatter `verification` string (`F` dropped) and nowhere else.
406
+ - **Weakened** findings — demote one severity tier (🔴→🟡, 🟡→🔵, 🔵→💭). Rewrite the finding's evidence line to reflect the narrower claim.
407
+ - **Verified** findings — carry through unchanged to Step 7.
408
+ - **Edge case**: if a 🔴 Cross-Finding Interaction bullet relies on constituents that are now Falsified or Weakened, re-evaluate the interaction. Drop the interaction if it no longer stands on ≥2 Verified constituents from different files.
350
409
 
351
- - **Severity dispute**: Only ask when the advisor re-ranked a finding or when inline reconciliation surfaced a contradiction. Use `ask_user_question` — Options: "Keep [original severity] (Recommended)" / "Downgrade" / "Escalate" with `file:line` evidence in the description.
352
- - **Scope ambiguity**: "❓ Question: finding at `file:line` lies in a test helper — does the team count test-only issues? Include in artifact or not?"
353
- - **False-positive confirmation**: Only ask when a security/dep finding hinges on context the orchestrator cannot see (e.g., `exec()` with a variable that the developer might know is constant).
410
+ **Gate**: if verification removes / demotes ALL 🔴 findings AND there are no remaining 🟡 findings, set `status: approved` in the artifact frontmatter. Otherwise `status: needs_changes` (or `requesting_changes` for verified 🔴 > 3).
354
411
 
355
- **Critical rules:**
356
- - Ask ONE question at a time. Wait before asking the next.
357
- - Lead with the most load-bearing finding.
358
- - Skip the checkpoint entirely if no disputes surfaced and the developer set `status: approved` in the scan response.
412
+ **Do not skip this step** — it is the only mechanism that stops confident-but-unread lens assertions from reaching the artifact.
359
413
 
360
414
  ## Step 7: Write the Review Document
361
415
 
@@ -365,167 +419,78 @@ Wait for the developer's response. Then ask **one question at a time**, waiting
365
419
  - Branch + commit: from git-context injected at session start, or `git branch --show-current` / `git rev-parse --short HEAD` (fallback: `no-branch` / `no-commit`).
366
420
  - Reviewer: user from injected git-context (fallback: `unknown`).
367
421
 
368
- 2. **Write the artifact** using the Write tool (no Edit — this skill writes once per run):
422
+ 2. **Write the artifact** using the Write tool (no Edit — this skill writes once per run).
369
423
 
370
- ```markdown
371
- ---
372
- date: [ISO 8601 with timezone]
373
- reviewer: [User]
374
- repository: [Repo name]
375
- branch: [Branch]
376
- commit: [Short hash]
377
- review_type: [commit|pr|staged|working]
378
- scope: "[What was reviewed]"
379
- critical_issues: [Count across all lenses]
380
- important_issues: [Count]
381
- suggestions: [Count]
382
- status: [approved|needs_changes|requesting_changes]
383
- tags: [code-review, relevant-components]
384
- last_updated: [YYYY-MM-DD]
385
- last_updated_by: [User]
386
- files_changed: [N]
387
- advisor_used: [true|false]
388
- interaction_sweep: [run|skipped-by-gate]
389
- workflow_risk_gate: [yes|no]
390
- ---
424
+ **Finding IDs**: lens-prefix + ordinal, stable across severity moves. `I` = interaction, `Q` = quality, `S` = security, `G` = gap. Ordinals never renumber — if a finding is dropped by Step 6, its ID is retired, not reused.
391
425
 
392
- # Code Review: [Scope Description]
393
-
394
- **Date**: [full ISO date]
395
- **Reviewer**: [User]
396
- **Repository**: [Repo]
397
- **Branch**: [Branch]
398
- **Commit**: [Short hash]
399
-
400
- ## Review Summary
401
- [3–5 sentences: overall verdict, highest-severity finding per lens, advisor outcome.]
402
-
403
- ## Issues Found
404
-
405
- ### Cross-Finding Interactions
406
- (Omit this H3 block entirely when the interaction sweep was skipped per the Step 4 gate, OR when the sweep returned no findings. Only 🔴/🟡 tiers — no 💭.)
407
- #### 🔴 Critical
408
- - `file:line` + `file:line` (≥ 2 distinct locations) — [emergent defect narrative: which local facts combine, and how the failure path is reached]
409
- #### 🟡 Important
410
- - `file:line` + `file:line` — [multi-component mismatch + blast radius or existing mitigation]
411
-
412
- ### Quality
413
- #### 🔴 Critical
414
- - `file:line` — [evidence + one-sentence fix pointer]
415
- #### 🟡 Important
416
- - `file:line` — [evidence + fix pointer]
417
- #### 🔵 Suggestions
418
- - `file:line` — [nearby template reference + suggested alignment]
419
- #### 💭 Discussion
420
- - `file:line` — [open question or trade-off]
421
-
422
- ### Security
423
- #### 🔴 Critical
424
- - `file:line` — [sink quoted + exploitability rationale referencing auth-boundary from Discovery Map]
425
- #### 🟡 Important
426
- - `file:line` — [missing hardening + secure precedent]
427
- #### 🔵 Suggestions
428
- - `file:line` — [pattern divergence from secure example]
429
- #### 💭 Discussion
430
- - `file:line` — [architectural question]
431
-
432
- ### Dependencies
433
- (Omit this H3 block entirely when the Dependencies lens was skipped — i.e., `ManifestChanged` was false.)
434
- #### 🔴 Critical
435
- - `dep@ver` (`package.json:line`) — [CVE id + link + affected-range + fix version]
436
- #### 🟡 Important
437
- - `dep@ver` — [moderate CVE / license / lockstep note with link]
438
- #### 🔵 Suggestions
439
- - `dep@ver` — [minor/transitive drift]
440
- #### 💭 Discussion
441
- - `dep@ver` — [architectural dep question]
442
-
443
- ## Precedents & Lessons
444
- - `commit hash` — [precedent + one-sentence takeaway]
445
- - Composite lessons (most-recurring first):
446
- 1. [lesson 1]
447
- 2. [lesson 2]
448
-
449
- ## Pattern Analysis
450
- [How changes align with or diverge from existing patterns in the changed files. Cite `file:line` of the nearest established pattern.]
451
-
452
- ## Impact Assessment
453
- [Files and inbound refs affected per the Discovery Map. Enumerate each affected consumer with `file:line` and what changes for it.]
454
-
455
- ## Historical Context
456
- [Links to thoughts/ docs referenced by precedent-locator; one line each, no summaries.]
457
-
458
- ## Advisor Adjudication
459
- (Omit this H2 entirely when the advisor did not run — its presence IS the signal that adjudication occurred.)
460
- [Advisor model prose pasted VERBATIM. Do not edit or paraphrase.]
461
-
462
- ## Reconciliation Notes
463
- (Include only when the inline path ran, OR when developer dispute in Step 5 moved a severity.)
464
- [Short prose: which findings shifted severity and why.]
465
-
466
- ## Recommendation
467
- [Clear verdict: Approved / Needs Changes / Requesting Changes. Cite the top 1–3 items that drove the verdict with `file:line`.]
468
- ```
426
+ **Title-line annotations** (appear in square brackets on the finding's title line, point-of-demand for reconciliation facts):
427
+ - `[precedent-weighted]` — severity bumped by Step 5's precedent follow-up weighting.
428
+ - `[cascade: <kind>]` — severity set by Step 5's cascade-detection triple (`stranded-state`, `duplicate-processing`, `contradictory-predicate-deadlock`).
429
+ - `[subsumed-by <ID>]` — root-cause subsumed by another finding but kept because its specific evidence is independently actionable.
430
+
431
+ **Section-omission rules**: omit entirely (no empty placeholders) when —
432
+ - `## 💭 Discussion` — no 💭 findings.
433
+ - `## Pattern Analysis` — no peer-mirror pair existed for this diff.
434
+ - `## Impact` — integration-scanner returned no inbound refs to changed files.
435
+ - `## Precedents` precedent-locator returned no precedents.
436
+
437
+ **What is NOT emitted to the artifact**: verification outcomes in prose (frontmatter `verification` string is the only channel), advisor availability / dispatch path / tool failures (skill trace, not review content), `last_updated` / `last_updated_by` (git mtime + git author carry this for a write-once artifact).
438
+
439
+ **Advisor prose**, when advisor ran, is pasted verbatim as a blockquote at the top of `## Recommendation`, not as a standalone section.
440
+
441
+ **Template shape**: Read the full template at `templates/review.md` (house pattern per `.rpiv/guidance/skills/architecture.md:66` — `templates/` subfolder, runtime-read, never inlined). At emission time: Read `templates/review.md`, fill every `[placeholder]` with reconciled-and-verified values from Steps 5 and 6, apply the section-omission rules above (delete the whole section AND its trailing separator line when its input is empty), strip the leading `<!-- -->` comment, and Write the result to the target path.
469
442
 
470
- ## Step 8: Present and Chain
443
+ ## Step 8: Present Summary
471
444
 
472
445
  ```
473
446
  Review written to:
474
447
  `thoughts/shared/reviews/[filename].md`
475
448
 
476
- [C] critical, [I] important, [S] suggestions across [Q] quality, [Se] security, [D] dependency issues.
477
- Advisor: [adjudicated | inline]
478
- Status: [verdict]
449
+ Severity: [C] critical · [I] important · [S] suggestions
450
+ Lenses: [Q] quality · [Se] security · [D] dependencies
451
+ Verification: [V] verified · [W] weakened · [F] falsified (dropped)
452
+ Advisor: [adjudicated | inline]
453
+ Status: [approved | needs_changes | requesting_changes]
479
454
 
480
455
  Top items:
481
- 1. `file:line` — [headline]
482
- 2. `file:line` — [headline]
483
- 3. `file:line` — [headline]
456
+ 1. [ID] — `file:line` — [headline]
457
+ 2. [ID] — `file:line` — [headline]
458
+ 3. [ID] — `file:line` — [headline]
484
459
 
485
- Ask follow-ups, or run `/skill:revise` to address the findings.
460
+ Ask follow-ups.
486
461
  ```
487
462
 
488
463
  ## Step 9: Handle Follow-ups
489
464
 
490
- - If the user asks for deeper analysis of a specific finding, spawn a targeted `codebase-analyzer` on that area (1 agent max) and append a `## Follow-up [timestamp]` section using the Edit tool.
491
- - Update frontmatter: `last_updated`, `last_updated_by`, and `last_updated_note: "Appended follow-up on [area]"`.
492
- - Never rewrite prior findings; only append.
465
+ - If the user asks for deeper analysis of a specific finding, spawn a targeted `codebase-analyzer` on that area (1 agent max) and append a `## Follow-up [ISO 8601 timestamp]` section using the Edit tool. The section heading's timestamp is the append-time record — no frontmatter update needed.
466
+ - Never rewrite prior findings; only append. Retired IDs (Falsified in Step 6) stay retired; follow-ups introduce new IDs with the same lens-prefix scheme (next ordinal).
493
467
 
494
468
  ## Important Notes
495
469
 
496
- - **No tool-permission widening**: `allowed-tools` is intentionally omitted — the skill inherits `Agent`, `ask_user_question`, `advisor`, `Write`, `web_search`, `todo` per `.rpiv/guidance/skills/architecture.md:40`. Do NOT re-add the line.
497
- - **Always use parallel Agent tool calls** in Phase-2 to maximise efficiency.
498
- - **Always read the full diff FIRST** (Step 1) before spawning any Phase-1 or Phase-2 agent.
499
- - **Always pass the Discovery Map inline** as `Known Context` to every Phase-2 agent agents are `isolated: true` and cannot see sibling transcripts.
500
- - **Security-lens precision stance**: prefer false negatives over false positives. Security evidence must carry `confidence ≥ 8` and 🔴 requires an explicit source→sink trace. Missing hardening without a traced sink is NOT a finding. Keep the Security-lens exclusion list in sync with the reference FP-filter precedents.
501
- - **Critical ordering**: Follow the numbered steps exactly.
502
- - ALWAYS resolve scope and bail on empty diff (Step 1) before Phase-1.
503
- - ALWAYS wait for Phase-1 completion before Phase-2 dispatch.
504
- - ALWAYS wait for ALL Phase-2 agents to complete before the interaction sweep (Step 4).
505
- - ALWAYS run the Cross-Finding Interaction Sweep (Step 4) after ALL Phase-2 agents complete and BEFORE severity classification in Step 5, UNLESS the Step 4 gate skipped it.
506
- - NEVER emit an interaction finding unless it cites at least two concrete `file:line` facts from different files/components.
507
- - ALWAYS wait for the interaction sweep (when it ran) to complete before reconciliation (Step 5).
508
- - ALWAYS probe advisor availability before calling `advisor()` (strip-when-unconfigured at `packages/rpiv-advisor/advisor.ts:463-472`).
509
- - ALWAYS emit the `## Pre-Adjudication Findings` block to the main branch BEFORE calling `advisor()` the advisor reads `getBranch()` (main-thread-only at `packages/rpiv-advisor/advisor.ts:336`) and will not see evidence you did not flush.
510
- - ALWAYS preserve the severity taxonomy emoji + naming (🔴 Critical / 🟡 Important / 🔵 Suggestions / 💭 Discussion) and the existing frontmatter keys verbatim — discovery agents `thoughts-locator` and `thoughts-analyzer` grep these.
511
- - NEVER call `advisor()` from inside a sub-agent — its branch is invisible to the advisor.
512
- - NEVER parse advisor prose mechanically — paste verbatim into `## Advisor Adjudication`.
513
- - NEVER add a new bundled agent to support this skill zero-new-agents contract per `packages/rpiv-pi/extensions/rpiv-core/agents.ts:148-268` sync cost.
514
- - **Severity classification**:
515
- - Evidence from agents justifies each issue's severity.
516
- - Every finding carries a `file:line`.
517
- - Correct-pattern examples cited where available.
518
- - Fixes are concrete (pointer, not vague).
519
- - **Agent roles (for this skill)**:
520
- - `integration-scanner` (Phase-1): inbound refs, outbound deps, auth-boundary crossings.
521
- - `codebase-analyzer` × 3 (Phase-2): one per lens evidence-only, no recommendations (honors the guardrail at `packages/rpiv-pi/agents/codebase-analyzer.md:113-119`).
522
- - `codebase-analyzer` × 1 (Step 4, gated): cross-finding interaction sweep emergent defects only, evidence-backed across multiple locations, no recommendations.
523
- - `precedent-locator` (Phase-2, always): git history + thoughts/ for lessons.
524
- - `web-search-researcher` (Phase-2, conditional on `ManifestChanged`): CVE / GitHub Advisory / OSS Index lookups with LINKS.
525
- - **File reading**: read the diff FULLY (no limit/offset) via `git` commands before spawning agents. Let agents read their scoped targets; the orchestrator does not need to read source files for non-risk findings.
526
- - **Framework-agnostic defaults**:
527
- - The Quality-lens bucket-5, the Step 4 gate, and the interaction-sweep defect classes are phrased in universal behavioral terms (I/O, state mutation, concurrency, public surface, schema/contract, auth) rather than framework names. Do NOT add framework-specific vocabulary to these prompts. If a stack needs more specificity, open a separate RFC.
528
- - Bucket-5 scope cap: capped at 1 hop via Discovery Map inbound/outbound lists AND limited to same-feature-area analogues. Agents must NOT traverse beyond directly connected files or search broadly across the codebase. Preserves evidence-only discipline at `packages/rpiv-pi/agents/codebase-analyzer.md:113-119`.
529
- - Dependencies lens is ecosystem-neutral: the lens prompt infers ecosystem from filename and nearby syntax; ambiguous cases (e.g., `pyproject.toml`, `global.json`, `Dockerfile`) must be stated explicitly, not guessed. Adding a new ecosystem means extending `ManifestChanged` (Step 1) and optionally the ecosystem hint in the CVE lens prompt.
530
- - **Workflow risk signals**: ALWAYS run the five `WorkflowRiskSignals` commands (Step 1) and record their yes/no results on the Discovery Map. NEVER approximate the patterns by eye — the Step 4 gate reads the recorded booleans.
531
- - CC auto-loads CLAUDE.md files when agents read files in a directory — no need to scan for them explicitly.
470
+ - **Frontmatter**: `allowed-tools` is intentionally omitted — the skill inherits `Agent`, `ask_user_question`, `advisor`, `Write`, `web_search`, `todo` per `.rpiv/guidance/skills/architecture.md:40`. Do NOT re-add the line.
471
+ - **Security-lens precision stance**: prefer false negatives. Evidence must carry `confidence ≥ 8`; 🔴 requires an explicit source→sink trace. Missing hardening without a traced sink is NOT a finding.
472
+ - **Load-bearing ordering**:
473
+ - Wave-1 fans out at T=0 — integration-scanner, Precedents, (when `ManifestChanged`) Dependencies + CVE, and (when `len(PeerPairs) > 0`) the peer-mirror agent dispatch in a single multi-Agent message. integration-scanner AND peer-mirror gate Wave-2 (both feed the Discovery Map Wave-2 consumes); **Precedents is a hard gate on Step 5** (its follow-up-within-30-days counts drive severity weighting; reconciling without them produces mis-weighted severities the verification pass cannot correct); Dependencies + CVE soft-gate Step 5.
474
+ - Step 4a (Predicate-Trace), 4b (Interaction Sweep), 4c (Gap-Finder) dispatch in parallel once Wave-2 completes. Interaction Sweep (4b) receives Quality's `Predicate-set coherence` table as its predicate-row source, not 4a's output.
475
+ - When Quality's `Predicate-set coherence` surface returns ≥2 rows with mismatched values on the same enum/type, the 4b sweep MUST evaluate categories 7–9 against those rows.
476
+ - **File orientation is load-bearing**: patches MUST use `-U30` (or `-U10` fallback for >1MB patches), never `-U0`. The Discovery Map's semantic file map (clusters + role tags + symbols-touched hint) is the orientation primitive, not per-hunk line ranges. Lens prompts organise findings per file (`### file/path.ext`), not per hunk. Agents SHOULD NOT issue extra `Read` calls for files already represented in the patch unless specifically needed for a cross-file trace.
477
+ - **Wave-2 context isolation**: Quality and Security prompts MUST NOT include Wave-1 background-agent output (precedent-locator, Dependencies, CVE) even when those agents have finished before Wave-2 dispatches. Summary context from those agents causes the lens agents to narrativise instead of independently analyse the diff — the observed failure mode is a ~5× speedup coupled with hallucinated findings and mis-cited line numbers. Pass only Discovery Map + patch file path.
478
+ - ALWAYS emit `## Pre-Adjudication Findings` to the main branch BEFORE calling `advisor()` — advisor reads `getBranch()` (main-thread-only, `packages/rpiv-advisor/advisor.ts:336`).
479
+ - ALWAYS probe advisor availability before calling it (strip-when-unconfigured at `packages/rpiv-advisor/advisor.ts:463-472`).
480
+ - NEVER call `advisor()` from a sub-agent (branch invisible to advisor).
481
+ - NEVER parse advisor prose paste verbatim as a blockquote at the top of `## Recommendation`.
482
+ - ALWAYS wait for 4a / 4b / 4c AND the Precedents agent to complete before Step 5 — Wave-3's hard barrier. Dependencies + CVE wait here too when running, but are not individually hard-gated.
483
+ - ALWAYS run Step 6 (verification pass) between reconciliation and artifact write. It is the only mechanism that catches lens agents asserting claims they never opened a file to confirm, and the only mechanism that validates `resolved-by` annotations against the actual branch via `git merge-base --is-ancestor`. Skipping Step 6 silently re-admits the failure mode this skill was designed to prevent.
484
+ - PRESERVE severity emoji/naming and frontmatter keys verbatim — `thoughts-locator` / `thoughts-analyzer` grep these.
485
+ - NEVER add a new bundled agent — zero-new-agents contract (`packages/rpiv-pi/extensions/rpiv-core/agents.ts:148-268`).
486
+ - **Agent roles**:
487
+ - `integration-scanner` (Wave-1)inbound/outbound refs, auth-boundary crossings.
488
+ - `precedent-locator` (Wave-1) — git history + thoughts/.
489
+ - `codebase-analyzer` ×1 (Wave-1, `ManifestChanged`) dependencies parse.
490
+ - `web-search-researcher` (Wave-1, `ManifestChanged`) CVE/advisory lookups with LINKS.
491
+ - `codebase-analyzer` ×1 (Wave-1, gated on `len(PeerPairs) > 0`) — peer-mirror check; tabulates peer's public surface against the newly-added file, tags each row Mirrored/Missing/Diverged/Intentionally-absent.
492
+ - `codebase-analyzer` ×2 (Wave-2) — Quality, Security.
493
+ - `codebase-analyzer` ×1 (Step 4a, gated) — predicate-trace.
494
+ - `codebase-analyzer` ×1 (Step 4b, gated) interaction sweep.
495
+ - `codebase-analyzer` ×1 (Step 4c, gated)gap-finder (coverage verification).
496
+ - `codebase-analyzer` ×1 (Step 6, always) — verification pass (grounds every reconciled finding at its cited file:line; tags Verified / Weakened / Falsified; Falsified dropped, Weakened demoted one tier).
@@ -0,0 +1,102 @@
1
+ <!-- Emitted by code-review SKILL.md Step 7. Placeholders in [brackets] are filled at emission; section-omission rules live inline in SKILL.md. -->
2
+ ---
3
+ template_version: 1
4
+ date: [ISO 8601 w/ tz]
5
+ reviewer: [User]
6
+ repository: [Repo]
7
+ branch: [Branch]
8
+ commit: [Short hash]
9
+ review_type: [commit | pr | staged | working]
10
+ scope: "[What was reviewed]"
11
+ status: [approved | needs_changes | requesting_changes]
12
+ counts: "[C]🔴 · [I]🟡 · [S]🔵"
13
+ verification: "[V] verified · [W] weakened · [F] dropped"
14
+ tags: [code-review, relevant-components]
15
+ ---
16
+
17
+ # Code Review — [Scope] ([commit])
18
+
19
+ Status: **[status]** · [C]🔴 · [I]🟡 · [S]🔵 · verification: [V]✓ [W]− [F]✗
20
+
21
+ Top blockers:
22
+ 1. [ID] — [one-line headline]
23
+ 2. [ID] — [one-line headline]
24
+
25
+ ───────────────────────────────────────────────────────────────────
26
+
27
+ ## Legend
28
+ 🔴 fix before merge · 🟡 fix soon · 🔵 nice to have · 💭 discuss
29
+ IDs: I=interaction Q=quality S=security G=gap
30
+ verification: ✓ verified − weakened (demoted) ✗ falsified (dropped)
31
+ annotations: [precedent-weighted] [cascade: <kind>] [subsumed-by <ID>]
32
+
33
+ ───────────────────────────────────────────────────────────────────
34
+
35
+ ## 🔴 Critical
36
+
37
+ 🔴 [ID] [annotation?] [short headline]
38
+ - where file:line
39
+ - code `<verbatim line from the file>`
40
+ - why [1–2 lines: mechanism, not symptom]
41
+ - fix [one sentence, imperative]
42
+ - alt [optional: alternative fix]
43
+
44
+ (one block per 🔴 finding; interaction findings may add a `peer` or `cites` line listing the ≥2 file:line facts)
45
+
46
+ ───────────────────────────────────────────────────────────────────
47
+
48
+ ## 🟡 Important
49
+
50
+ 🟡 [ID] [annotation?] [short headline]
51
+ - where file:line
52
+ - code `<verbatim line>`
53
+ - why [mechanism]
54
+ - fix [action]
55
+
56
+ ───────────────────────────────────────────────────────────────────
57
+
58
+ ## 🔵 Suggestions
59
+
60
+ 🔵 [ID] [short headline]
61
+ - where file:line
62
+ - fix [action]
63
+
64
+ ───────────────────────────────────────────────────────────────────
65
+
66
+ ## 💭 Discussion
67
+
68
+ 💭 [ID] [question / architectural concern]
69
+ - where file:line
70
+ - why [what the reviewer wants the author to consider]
71
+
72
+ ───────────────────────────────────────────────────────────────────
73
+
74
+ ## Pattern Analysis
75
+ Peer: `<peer file>` · Mirrored [M] · Missing [Mi] · Diverged [D] · Intentionally-absent [A]
76
+ Missing/Diverged rows drive: [finding IDs]
77
+
78
+ ───────────────────────────────────────────────────────────────────
79
+
80
+ ## Impact
81
+
82
+ consumer change findings
83
+ ──────────────────────────────── ────────────── ────────
84
+ [file:line] [change class] [IDs]
85
+
86
+ ───────────────────────────────────────────────────────────────────
87
+
88
+ ## Precedents
89
+ [hash] "[commit subject]" [30d follow-ups | NOT ancestor of [TIP] | note]
90
+
91
+ Recurring lessons (most → least):
92
+ 1. [composite lesson]
93
+ 2. ...
94
+
95
+ ───────────────────────────────────────────────────────────────────
96
+
97
+ ## Recommendation
98
+ > (advisor prose pasted verbatim here when advisor ran; omit the blockquote otherwise)
99
+
100
+ 1. [ID] [action, one sentence] | Alt: [alternative]
101
+ 2. [ID] [action]
102
+ 3. [ID] [action]
@@ -2,7 +2,6 @@
2
2
  name: revise
3
3
  description: Update existing implementation plans based on feedback. Makes surgical edits while preserving structure and quality. Use when plans need adjustments after review or during implementation.
4
4
  argument-hint: "[plan-path] [feedback]"
5
- allowed-tools: Edit, Read, Bash(git *), Glob, Grep, Agent
6
5
  ---
7
6
 
8
7
  # Iterate Implementation Plan
@@ -15,16 +14,30 @@ When this command is invoked:
15
14
 
16
15
  1. **Parse the input to identify**:
17
16
  - Plan file path (e.g., `thoughts/shared/plans/2025-10-16_09-00-00_feature.md`)
17
+ - Whether the user accidentally provided a review artifact path instead (e.g., `thoughts/shared/reviews/2025-10-16_10-00-00_feature.md`)
18
18
  - Requested changes/feedback
19
19
 
20
20
  2. **Handle different input scenarios**:
21
21
 
22
+ **If a REVIEW artifact path is provided**:
23
+ ```
24
+ `revise` updates implementation plans, not review artifacts.
25
+
26
+ If you want to act on code-review findings, provide the target plan path plus the changes to make.
27
+
28
+ Example:
29
+ `/skill:revise thoughts/shared/plans/2025-10-16_09-00-00_feature.md "Address the findings from thoughts/shared/reviews/2025-10-16_10-00-00_feature.md by tightening validation in Phase 2 and expanding success criteria."`
30
+ ```
31
+ Wait for user input.
32
+
22
33
  **If NO plan file provided**:
23
34
  ```
24
35
  I'll help you iterate on an existing implementation plan.
25
36
 
26
37
  Which plan would you like to update? Please provide the path to the plan file (e.g., `thoughts/shared/plans/2025-10-16_09-00-00_feature.md`).
27
38
 
39
+ If you're coming from `/skill:code-review`, pass the relevant plan path and summarize which findings should change the plan.
40
+
28
41
  Tip: You can list recent plans with `ls -lt thoughts/shared/plans/ | head`
29
42
  ```
30
43
  Wait for user input, then re-check for feedback.
@@ -240,3 +253,11 @@ Assistant: I've found the plan. What changes would you like to make?
240
253
  User: Add more specific success criteria
241
254
  Assistant: [Proceeds with update]
242
255
  ```
256
+
257
+ **Scenario 4: User passes a review artifact instead of a plan**
258
+ ```
259
+ User: /skill:revise thoughts/shared/reviews/2025-10-16_10-00-00_feature.md
260
+ Assistant: `revise` updates implementation plans, not review artifacts. Please provide the target plan path plus the changes to make.
261
+ User: /skill:revise thoughts/shared/plans/2025-10-16_09-00-00_feature.md "Address the review findings by splitting Phase 2 and adding validation coverage"
262
+ Assistant: [Proceeds with update]
263
+ ```