deep-review¶
Multi-lens evaluative review with preserved disagreement
Reads one artifact — a diff, design, plan, or document — through independent
charters and reports what will go wrong. Retrieval finds material,
verify settles whether a claim is true, and
corpus-review proves everything was read. This plugin
answers the remaining question: is this good?
deep-review declares dependencies: ["plan-execute", "verify"]. It reuses
plan-execute's cheap-worker fan-out to run lenses in
parallel, and routes every checkable finding to verify rather
than grading its own defects. verify already pulls the
retrieval spine.
Install¶
Components¶
| Component | What it is |
|---|---|
deep-review skill |
The frame → lenses → dispatch → adjudicate → route → report pipeline, the finding taxonomy, and the rules that keep a panel honest. |
review-lens subagent |
Reviews one artifact through one assigned charter and returns typed, cited findings plus its own coverage. Read-only and charter-scoped. |
/deep-review command |
Runs the panel end to end over an artifact. |
adjudicate-findings.py |
Validates the contract, merges corroboration, flags tradeoff candidates, and emits the review ledger. |
One worker parameterized by a charter, not one agent per persona. A fixed roster would hardcode which perspectives exist; a charter is data, so a domain lens (security, accessibility, privacy, cost) needs no new component.
Judgment is not verification¶
| Verification | Corpus review | Deep review | |
|---|---|---|---|
| Question | is this claim true? | did we read all of it? | is this good? |
| Output | a verdict per claim | a disposition per unit | a typed finding per concern |
| Evidence | file:line |
inspected units | the artifact plus its context |
| Disagreement | not applicable | not applicable | preserved as a tradeoff |
A DEFECT finding is a hypothesis, not a verdict. It becomes a claim for
verify; reporting it as confirmed before that verdict returns is
the overreach this plugin exists to prevent.
Why a panel needs machinery¶
An unstructured multi-perspective review degrades in three predictable ways:
- Volume as rigor — more findings read as more diligence, so reviewers pad.
- Manufactured disagreement — distinct personas invent distinct objections even when they agree, and one issue is counted three times.
- Preference laundering — a style opinion is phrased as a defect, and the author cannot tell what they are allowed to decline.
Each rule below blocks one of them.
Finding types¶
Every finding declares exactly one type, and the type decides how it is settled:
| Type | Meaning | Required fields | Settled by |
|---|---|---|---|
DEFECT |
a checkable assertion that the artifact is wrong | + Falsification |
verify |
RISK |
a conditional prediction | + Trigger |
triage: judgment, or runtime-evidence when the trigger is observable |
JUDGMENT |
a tradeoff with no fact of the matter | — | the author, who may decline |
QUESTION |
the reviewer lacks context | — | an answer, not a fix |
A DEFECT you cannot exhibit is a RISK; a RISK with no trigger is a
JUDGMENT. Adjudication enforces this by rejecting a report that omits the
required field, so "falsify or downgrade" is structural rather than advisory.
Default lenses¶
| Lens | Responsible for | Silent about |
|---|---|---|
adversarial |
making it fail: edge cases, error paths, concurrency, trust boundaries | style, structure, docs, design direction |
architect |
coherence with the existing system, coupling, precedent, evolution cost | bug hunting, runtime failure modes, tooling |
consumer |
the artifact in use: API shape, defaults, error messages, migration burden | internals, implementation quality, deployment |
operator |
day two: detectability, diagnosability, reversibility, on-call burden | elegance, API taste, code style |
The silent about column is load-bearing. Without an explicit non-scope, four lenses all file the same naming complaint and the panel becomes an echo.
Pipeline¶
flowchart LR
F[frame<br/>artifact + decision + stakes] --> L[select lenses<br/>charters + non-scope]
L --> D[dispatch<br/>independent workers]
D --> A[adjudicate<br/>merge + collide]
A --> R[route<br/>defects to verify]
R --> P[report<br/>findings + coverage]
ROOT="${CONTEXT_KIT_DEEP_REVIEW_ROOT:-plugins/deep-review}"
# frame.json declares artifact, decision, stakes, and expected_lenses;
# dispatch one review-lens worker per charter -> ./work/findings/<lens>.md
python3 "$ROOT/scripts/adjudicate-findings.py" \
--frame ./work/frame.json \
--findings-dir ./work/findings \
--out-dir ./work/report
# workers reply inline; if the reports are in context rather than on disk,
# write them verbatim into one file and pass that instead:
# --findings-file ./work/findings.md
Claude Code components may use CLAUDE_PLUGIN_ROOT as the plugin-root fallback.
Adjudication¶
Corroboration merges, never multiplies. Findings sharing a type, a citation, and a similar problem collapse into one entry carrying every lens that raised it and the highest severity any of them asserted. Counting agreement three times would destroy the exact signal independent lenses exist to produce.
That signal is only meaningful because no lens ever sees another's findings. A panel run with shared visibility produces agreement that means nothing.
Disagreement is preserved. Two lenses at one citation whose resolutions are dissimilar surface as a tradeoff candidate routed to whoever owns the decision. Every lens's own resolution is kept on the merged entry and conflict detection runs over those positions, so two lenses that agree on the problem but want opposite fixes still collide — merging a problem never merges away a fix. These are candidates, not proven contradictions — deciding whether two prose resolutions genuinely conflict is not a deterministic operation, and the script does not pretend otherwise. The value is surfacing the collision instead of letting a synthesizer quietly pick a winner.
No ledger means no guarantees
A synthesis written without running the adjudicator has unmerged corroboration, undetected resolution conflicts, and no coverage accounting — and its shape is identical to an adjudicated one. Label it an Unadjudicated synthesis and name what is missing. Skipping the step because a finding already looks decisive is exactly when the merge and conflict checks matter most.
A missing lens is not a clean lens
The frame's expected_lenses roster is required. A declared lens with no
report exits nonzero and appears under Degraded review. Without a
roster, a crashed worker is indistinguishable from one that found nothing —
and a failed operator lens would read as an operable artifact.
Reading the ledger honestly¶
- A clean ledger is not an approval. It reports what the declared lenses looked at; coverage gaps bound what silence means.
- Counts are not quality. Ten
notefindings and oneblockingfinding is not eleven problems. - A question-dominated lens judged nothing. When a lens returns only questions it reached no verdict — usually for want of access its charter needed. The ledger flags it so zero defects read as could not look.
- Unrouted defects are unfinished work. A
DEFECTthat has not been throughverifyis still a hypothesis.
Composition¶
verify— owns truth; everyDEFECTbecomes a claim there.plan-execute— cheap lens workers, strong synthesizer.runtime-evidence— settles an observableRISK.corpus-review— shard an oversized artifact first, then review the shards; coverage and judgment compose.memory— recalls settled constraints so the panel does not relitigate a closed tradeoff, and captures the ones this review closes.code-search— lenses need callers, precedent, and history beyond the diff.
Development¶
Hermetic: no network, no model, temporary directories only.