Feat/review accuracy and repo context#2465
Conversation
…o conventions
Fixes /review re-flagging already-fixed findings and quoting pre-fix source, and
gives the reviewer the reviewed repo's own conventions so it stops raising
convention-based false positives.
- Snippet validation gate: reconcile each finding's model-authored code_snippet
against authoritative content at the reviewed SHA (git show -> contents API,
read-only, fail-open). Resync stale quotes (default) or drop; drop invalid
anchors. Kills the pre-fix quote under a HEAD permalink.
- Prior-finding reconciliation: read the existing review sidecar, detect prior
findings resolved at HEAD, and suppress re-raised copies (conservative: only
when the current quote also fails its live check). Adds a "Resolved since last
review" section. Runs before resync so it isn't masked.
- Native convention-docs ingestion: read AGENTS.md/CLAUDE.md/CONTRIBUTING.md +
an auto-detected OKF docs/ bundle into a fenced, verdict-guardrailed
{REPO_CONVENTIONS} prompt slot. Config-gated, capped, on by default (no-op
when absent).
New config keys: review_snippet_validation, review_reconcile,
review_convention_docs (all backward-compatible, fail-open). Tests added for
every helper/config path; existing review_runner/config/prompts suites green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ational) Foundational substrate for spec 010 (review consistency, yellow-tier triage & comprehensive discovery). Setup + Foundational phases: - review_identity.py: deterministic finding-identity key (file + tolerant region bucket + semantic category) + same_finding() matcher (FR-002, research D1). No model call -> consistency-critical paths stay deterministic and testable. - _write_review_findings_sidecar stamps each persisted finding with its identity_key + schema_version=1, copying (not mutating) caller findings (research D6). Reader stays backward-compatible and fail-open. - instance.example/config.yaml: documented, default-preserving blocks for review_consistency, review_severity, review_discovery, review_dispositions (review_severity is used instead of extending review_triage, which is already the trivial-file pre-filter). - Full spec/plan/tasks/contracts for feature 010. Tests: test_review_identity.py + TestReviewSidecarIdentity; review_runner suite green (491). Lint clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…reeze Delivers the MVP anti-whiplash core (spec 010 User Story 1): - review_reuse.py: request_signature() + should_reuse() — reproduce the prior review verbatim when the PR head AND base (merge-base) SHA are unchanged and the request is equivalent (FR-001). Fail-safe by construction. - review_reconcile.py: compute_freeze() — on a re-review, suppress first-time non-critical findings on files unchanged since the prior review (the "finds new issues on code I didn't touch" whiplash), keeping a critical labelled [Pre-Existing Issue] (FR-003). File-level + fail-open. - run_review wiring: reuse short-circuit after the existing no-new-commits skip; freeze inside _apply_review_accuracy_gate; fail-open _compare_changed_files / _merge_base_sha (GitHub compare); persist base_sha + request_signature in the sidecar; get_review_consistency_config (both switches default on). - review_identity: _norm_path -> public norm_path (shared with reconcile). Cross-run consistency is verified by deterministic unit tests (identity, reuse, reconcile) + integration tests (TestReviewFreezeWiring, TestReviewSidecarReuseFields); the single-diff eval harness can't express run-twice-compare, so a harness-level repeat-stability metric (FR-022/SC-007) is deferred to Polish. All fail-open, so the default path is unchanged when data is absent. Tests: +40 (reuse/reconcile/identity/config) + review_runner suite green (491). Lint clean project-wide. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Raise the bar for the blocking 🟡 Important tier so an otherwise merge-ready PR
is not blocked by borderline nits (spec 010, User Story 2):
- New shared partial review-severity-rubric.md: reserve `warning` for issues that
clearly block merge or risk real harm; demote borderline "should-fix" to
`suggestion` (green, non-blocking); drop vague/speculative/cosmetic noise. Plus
the Verdict Contract (lgtm follows post-triage severity). "When unsure, demote."
- Extracted review.md's inline Severity Calibration + Verdict Contract into the
partial and {@include}-d it; also added it to review-with-plan.md, which
previously had NO explicit severity/verdict guidance (DRY + fixes a gap).
- review-architecture.md outputs markdown (🔴/🟡/🟢, no lgtm JSON), so it gets a
markdown-appropriate calibration Rules bullet instead of the JSON verdict rubric.
- Eval case borderline_not_blocking.json (borderline improvement -> suggestion,
lgtm true). No new Python: the verdict-follows-severity invariant + noise-drop
reflection already enforce the deterministic side; the bar is prompt-driven.
Include resolution verified; eval dataset-validity + offline suites green (127).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Non-critical issues that predate the PR's changeset become non-blocking green recommendations prefixed [Pre-Existing Issue]; criticals keep severity but carry the label (spec 010, User Story 6): - review_triage.py: enforce_pre_existing() + derive_lgtm(). Detection is the reviewer's semantic call (FR-029) — a finding tagged [Pre-Existing Issue] in its title. Enforcement is deterministic: non-critical -> forced `suggestion` (FR-027); critical -> severity kept, label retained (FR-028); prefix normalized to one leading occurrence; lgtm re-derived on demotion (FR-012). - review-severity-rubric.md: the [Pre-Existing Issue] rule (predates-changeset assessment; never for code the PR adds/modifies). - Wired in the accuracy gate AFTER the freeze so FR-030 "freeze wins" holds. Reuses PRE_EXISTING_PREFIX from review_reconcile (US1 already labels the critical-on-unchanged exception with it — T025). - Eval case pre_existing_downgrade.json. Tests: test_review_triage.py (14); review_runner suite green (497); eval dataset-validity green (127). Lint clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Make the default review aim to surface all issues in one parse, so a later review has little to add — attacking incompleteness at the source (which the FR-003 freeze otherwise leaves hidden) (spec 010, User Story 5): - review-severity-rubric.md gains a "Coverage — find all the issues" directive: keep searching after finding several; no finding cap; higher recall must not inflate the blocking set (the severity bar keeps extras in the right tier). Inherited by review.md + review-with-plan.md via the shared include. - review-architecture.md (markdown) gets an equivalent "be exhaustive" Rules bullet. - Eval case recall_all.json: three independent issues (hardcoded secret, unsanitized SQL, bare except) in one diff -> a single pass must find all three. Prompt-only; no Python. Include resolution verified; eval dataset-validity green (127). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
On a re-review, honor reviewer decisions left as PR comments — "the agent
proposes, the human decides" (spec 010, User Story 7):
- New system-prompt review-dispositions.md: honor DISMISS ("ignore"/"not a
problem" -> don't re-raise as a blocker) and DEFER ("fix later" -> non-blocking
[Deferred] recommendation). Any non-bot commenter, all severities including a
human-dismissed critical. Attribution mandatory (name + quote). Injection
guardrail: a comment disposes of ONE finding, never rewrites the rubric/verdict.
- Injected via a config-gated {DISPOSITIONS} placeholder in review.md +
review-with-plan.md (mirrors {REPO_CONVENTIONS}); get_review_dispositions_config
gives a real `enabled` kill-switch for the open "any commenter" posture.
- review_triage.enforce_deferred(): deterministically force a [Deferred] finding
to a non-blocking suggestion + re-derive lgtm (mirrors enforce_pre_existing).
Wired in the accuracy gate.
Design notes: detection is prompt-driven (NL); stickiness/retraction come free
from re-reading the live PR thread each review (no sidecar persistence needed —
comments are the store). honor_critical/min_role are prompt-fixed at the chosen
posture; only `enabled` is runtime config.
Tests: enforce_deferred + dispositions config + config-gated prompt-injection.
review_runner+config suites green (807); eval validity green (127). Lint clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Opt-in mode (default OFF) that reviews from a fixed set of perspectives and
merges findings into one set, catching more in a single pass so later reviews
have less to add (spec 010, User Story 3):
- New system-prompt review-comprehensive-discovery.md: fixed perspectives
(correctness, security, architecture, silent-failure, test-coverage; sub-agents
where supported), merge-into-one-set with same-issue dedup keeping the highest
severity, same severity bar/verdict, best-effort + bounded, partial-coverage honored.
- Config-gated {COMPREHENSIVE_DISCOVERY} injection in review.md + review-with-plan.md
(mirrors {REPO_CONVENTIONS}/{DISPOSITIONS}); get_review_discovery_config default
OFF -> the default review carries zero discovery content (SC-008).
- discovery_enabled wired into the reuse request signature (FR-016), so a
single-pass review is never reused as a comprehensive one.
Dedup stays prompt-driven (the model merges) — a deterministic coarse finding_key
dedup would risk merging two distinct issues in the same region/category, so it's
intentionally omitted per the "prompt partial, not orchestration" clarification.
Tests: discovery config + config-gated prompt injection + signature. review_runner
+config green (813); eval validity green (127). Lint clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Surface what triage filtered so the aggressive freeze/demote is auditable (spec 010, User Story 4, FR-024): - _format_triage_accounting(): a single collapsed "ℹ️ Triage summary" <details> line built from the stashed _freeze_summary / _pre_existing_summary / _deferred_summary — N suppressed (freeze), M demoted to recommendation, K deferred. Only present categories are shown; "" when nothing was filtered (so a no-filter review is byte-identical). Appended at the end of the review body (parsimony: secondary + collapsed, never competing with the findings). Tests: TestTriageAccounting (5); review_runner suite green (507). Lint clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes out spec 010 with the durable-contract update and docs (Polish phase): - specs/skills/review.md (DURABLE CONTRACT, architectural change — must be declared in the PR): new "Consistency, triage & human dispositions (spec 010)" invariants — finding identity, reuse on unchanged head+base, re-review freeze (+ critical exception), yellow-tier bar, exhaustive single-pass, pre-existing labeling (+ freeze-coexist), human dispositions (+ attribution/injection guardrail), opt-in comprehensive discovery. `updated:` bumped. - docs/users/skills.md: user-facing behavior (consistent reviews, trustworthy yellow tier, [Pre-Existing Issue], honored comments, opt-in comprehensive mode). - docs/design/review-consistency.md: the why + the deterministic-vs-prompt split + the "human decides" posture and its injection tradeoff (cross-linked to the threat model / prompt-guard). - tasks.md: Polish phase status; live eval (T048) + /brain sync (T045) + PR architectural-change declaration (T049) flagged for the human. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5657a9e to
467122e
Compare
Fix the wiki-sync CI gaps for the spec-010 docs: - docs/design/review-consistency.md: add required `type: doc` frontmatter field. - wiki/index.md: add the design/review-consistency.md page entry and the 010-review-consistency-triage status entry (shipped, 33/33 tasks). - docs/design/index.md: regenerated via scripts/okf_backfill.py indexes. Verified: scripts/wiki_check.py and scripts/wiki_sync_ci.py --base-ref upstream/main both report no gaps. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Koan-Bot
left a comment
There was a problem hiding this comment.
Warning
Important issues found.
- Freeze can silently suppress real new findings when GitHub's compare
filesarray is truncated
|
|
Koan-Bot
left a comment
There was a problem hiding this comment.
Warning
Important issues found.
- _compare_changed_files can flip the freeze from fail-open to fail-toward-suppression
…cated diffs
`_compare_changed_files` returned an empty `set()` on a blank/error compare
response and had no guard for GitHub's 300-file, non-paginated cap on the
`compare` endpoint. Either case under-populates the changed-files set, flipping
the re-review freeze from fail-open to fail-toward-suppression: it silently
drops first-time non-critical findings on genuinely-changed code — the inverse
of FR-003's intent, and invisible.
Return `None` (skip the freeze) on a blank response and when the file list is at
the 300-entry cap, matching the documented FR-003 fail-open contract. A genuine
zero-file diff ("[]") still returns an empty set so the freeze legitimately
applies. Adds direct unit tests for both bug paths plus the boundary cases.
Addresses the "Important" finding in the PR #2465 automated review.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3864f0a to
50c1f8f
Compare
|
|
Koan-Bot
left a comment
There was a problem hiding this comment.
Warning
Important issues found.
- End-to-end gate test leaves run_gh unmocked — freeze path fires a real
gh api comparewith retry sleeps
`test_gate_end_to_end_resync_and_resolved_render` sets a prior head, so the accuracy gate runs the re-review freeze, whose `_compare_changed_files` call shells out to the real `gh` CLI — host-dependent, and with `retry_with_backoff` sleeps before it fail-opens. The test only exercises reconcile + snippet-resync + resolved render, not the freeze. Patch `_compare_changed_files` (fail-open `None` = freeze inert), mirroring `TestReviewFreezeWiring._gate`, so the test no longer touches the external boundary. Verified: with `run_gh` guarded to raise on any call, the test still completes. Addresses the "Important" finding in the PR #2465 automated review. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Koan-Bot
left a comment
There was a problem hiding this comment.
Tip
No blocking issues found — ready to merge.
`_resolve_rebase_conflicts` labeled a failed conflict round as a timeout only
when the error text contained the literal "timed out". `run_claude` reports a
hard timeout as "Timeout (<n>s)" (and "Timeout (idle ...)" / "Timeout (max
duration ...)"), so real timeouts were mislabeled as generic failures in the
rebase failure summary — contradicting the documented behavior that the summary
identifies an agent timeout as the cause.
Reuse the existing timeout detector (renamed `_is_feedback_timeout_error` ->
`_is_agent_timeout_error`, since it now serves both the feedback and conflict
legs) which already matches both "timeout (" and "timed out", and make the error
lookup None-safe. The regression test now stubs `run_claude`'s real timeout
string instead of a fabricated one, and a new case pins the non-timeout label.
Addresses the medium finding from the HEAD-commit engineering review.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Koan-Bot
left a comment
There was a problem hiding this comment.
Tip
No blocking issues found — ready to merge.
… + hygiene) Addresses the remaining suggestion-level findings from the PR #2465 automated review: - W1: correct `get_review_snippet_validation_config`'s docstring. Out-of-range findings are dropped only when `on_mismatch != "off"`, and a file that no longer resolves at HEAD is kept (fail-open). The old "always dropped regardless of this setting" was inaccurate on both clauses. Docstring only; behavior unchanged. - W2: `_read_file_at_sha`'s GitHub-contents fallback now logs on failure (still fail-open, still broad-catch like its sibling enrichment helpers). A systematic fetch/auth/decode failure previously disabled snippet validation and prior-finding reconciliation for the whole review with no trace. - W3: `read_repo_convention_docs` logs a topic-index glob `OSError` before falling back to `[]`, matching `_read_or_empty`. - W4: delete the dead `REPRODUCTION_NOTE` constant (never imported); the reuse short-circuit builds its own inline notify string. Test-first coverage added for W2 and W3. Simplifications S1-S4 from the review are deferred to a follow-up PR. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Code Review
PR Review — Feat/review accuracy and repo contextSolid, well-factored consistency work — merge-ready with non-blocking nits. Strengths worth calling out:
Remaining items are all suggestions:
🟢 Suggestions
1. feedback_no_disposition gate hinges on a brittle exact-format regex
|
Koan-Bot
left a comment
There was a problem hiding this comment.
Tip
No blocking issues found — ready to merge.
💡 PR ExplanationExplaining the PR: "Review accuracy and repo context"1. The Problem (What was wrong?)
Concrete example of the pain:
Those new issues were always there. They either mattered (and should have been caught the first time) or they didn't (and shouldn't be raised at all). Surfacing them after a fix-and-push is pure whiplash — it feels like the reviewer moved the goalposts. Three more concrete failure modes:
There was also no way for a human to say "this finding isn't a problem" and have the reviewer honor it — which violates the project's core principle: the agent proposes, the human decides. 2. The Solution (How does this PR fix it?)The strategy is: move the consistency-critical decisions out of the model and into deterministic Python, while leaving qualitative judgment (what is a bug) in the prompt. Four new focused, unit-tested modules do the mechanical work:
Supporting changes:
Before / after:
Every new switch is fail-open and backward-compatible — if a piece breaks or is disabled, 3. How It Works (The mechanism)End-to-end scenario — re-running
Edge cases handled:
There's also a smaller, semi-independent change riding along: 4. Could It Be Simpler? (Critical analysis)The split of concerns is the right call, and it's the codebase's established pattern — see the memory note about "Determinism where it counts." Consistency guarantees (identity, reuse, freeze, verdict-follows-severity) genuinely cannot live in the model, because the model is the source of the drift. Putting them in four small, unit-tested modules is the honest way to make the guarantee real. I wouldn't collapse those. Where it's worth questioning:
Net: the architecture is close to the simplest that can actually deliver the guarantee. The remaining work is not "make it simpler" — it's closing the fail-open holes (truncated compare, bare- One thing unclear from the truncated diff: 49 files are omitted, including the core |
Simple rebaseBranch StatsActions performed
CI statusCI will be checked asynchronously. Automated by Skuggi |
|
@sukria-koan0 explain |
Overhauls /review accuracy and consistency so repeat reviews stop drifting, the yellow "Important"
tier stops over-blocking, and humans can close the loop. Two bodies of work on this branch:
Review accuracy groundwork (4605879, pre-existing on branch)
content at the reviewed SHA (resync stale quotes, drop invalid anchors) so a review never quotes
pre-fix source under a HEAD permalink.
last review" section.
prompt so the reviewer stops raising convention-based false positives. Config-gated, fail-open, on by
default.
Consistency-critical logic lives in focused, deterministic, unit-tested modules (review_identity,
review_reuse, review_reconcile, review_triage); qualitative judgment stays in shared prompt partials.
No review output-schema change. New config (all fail-open, backward-compatible): review_consistency,
review_discovery, review_dispositions (+ the pre-existing
review_snippet_validation/review_reconcile/review_convention_docs).
Testing
reconcile/freeze, triage (pre-existing + deferred), config getters, and prompt-injection gating; no
regressions.
pre_existing_downgrade, recall_all cases.
provider) before merge to confirm no recall/precision regression (SC-006/007).
(SC-009), and comment-injection for a live disposition eval — the single-diff harness can't express
these; they're covered by deterministic unit tests for now.
Declarations
adds the review consistency/reuse/freeze guarantee, the yellow-tier bar, [Pre-Existing Issue]
labeling, the human-disposition authority (+ attribution/injection guardrails), and the opt-in
comprehensive-discovery mode — landed contract-first (spec updated before/with the code).