Skip to content

feat(review): add confidence annotation to review verdicts - #396

Open
Benkapner wants to merge 2 commits into
fullsend-ai:mainfrom
Benkapner:feat/review-confidence-annotation
Open

feat(review): add confidence annotation to review verdicts#396
Benkapner wants to merge 2 commits into
fullsend-ai:mainfrom
Benkapner:feat/review-confidence-annotation

Conversation

@Benkapner

@Benkapner Benkapner commented Jul 23, 2026

Copy link
Copy Markdown

Summary

Adds a confidence level (high/medium/low) to the review agent's structured output. This is the minimal first step toward graduated approval, emitting the data without changing any routing or auto-merge behavior.

Ported from fullsend-ai/fullsend#5515 per rh-hemartin's feedback that agents have moved to this repo.

What changes

  • pr-review skill (step 6g): new step after verdict determination that derives confidence from sub-agent agreement, challenger removal rate, and verdict threshold proximity
  • review-result schema: adds an optional confidence field (high/medium/low)

Confidence derivation

Level When
high all sub-agents agreed, challenger removed 0-1 findings, verdict not near threshold
medium challenger removed >1 finding, OR sub-agents disagreed on severity, OR verdict is one finding from flipping
low severe sub-agent disagreement, OR challenger failed (fallback set used), OR ambiguous change scope

What does NOT change

  • Dispatch logic, label behavior, verdict thresholds, auto-merge rules
  • The field is optional in the schema; omitting it is valid

Related

Checklist

  • PR title follows Conventional Commits
  • Commits are signed off (DCO)

@Benkapner
Benkapner requested a review from a team as a code owner July 23, 2026 11:59
@github-actions

Copy link
Copy Markdown

Functional tests did not run

Functional tests run automatically for org/repo members and collaborators on pull requests.

For other contributors, a maintainer must add the ok-to-test label after the latest push.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add confidence annotation to review verdict output

✨ Enhancement 📝 Documentation 🕐 10-20 Minutes

Grey Divider

AI Description

• Add optional confidence (high/medium/low) to structured review results.
• Document how confidence is derived from sub-agent agreement, challenger removals, and threshold
 proximity.
• Keep verdict/routing/auto-merge behavior unchanged; confidence is informational only.
Diagram

graph TD
  A["Review Agent"] --> B["pr-review skill"] --> C["Verdict"] --> D["Confidence derivation"] --> E["review-result JSON"] --> F["Schema validation"]
  F --> G["Downstream consumers"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Numeric confidence score (0-1) with mapped buckets
  • ➕ More expressive than a 3-level enum; supports future thresholding/automation without schema changes
  • ➕ Easier to track drift over time (metrics/alerts)
  • ➖ Harder for humans to interpret consistently without guidance
  • ➖ Creates pressure to treat it as a decision signal earlier than intended
2. Compute confidence in the consumer/UI layer (not in agent output)
  • ➕ Avoids expanding the core review-result contract
  • ➕ Allows different consumers to apply different heuristics without coordination
  • ➖ Confidence would be inconsistent across consumers
  • ➖ Consumers often lack internal signals (sub-agent agreement, challenger fallback) that the agent has

Recommendation: The PR’s approach (agent-derived, 3-level informational enum) is the best minimal step: it standardizes the annotation at the source while keeping behavior unchanged. A numeric score is a good follow-on once the team is ready to operationalize confidence, but the current enum keeps the contract simple and human-friendly for early rollout.

Files changed (2) +31 / -0

Documentation (1) +26 / -0
SKILL.mdDocument step 6g confidence derivation after verdict +26/-0

Document step 6g confidence derivation after verdict

• Adds a new documented step (6g) describing how to derive a confidence level after verdict determination. Clarifies that confidence is informational only and should be included as an optional top-level field in the review result JSON.

skills/pr-review/SKILL.md

Other (1) +5 / -0
review-result.schema.jsonAdd optional confidence field to review-result schema +5/-0

Add optional confidence field to review-result schema

• Extends the review-result JSON schema with an optional top-level 'confidence' field. Restricts values to 'high', 'medium', or 'low' and documents how it should be interpreted.

schemas/review-result.schema.json

@rh-hemartin

Copy link
Copy Markdown
Member

I added "Closes fullsend-ai/fullsend#5514" to the PR body.

@qodo-code-review

qodo-code-review Bot commented Jul 23, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (1)

Grey Divider


Action required

1. confidence schema lacks tests ✗ Dismissed 📜 Skill insight ▣ Testability
Description
The PR introduces a new top-level confidence field (with an enum) in the review result schema but
does not add/adjust tests to constrain and validate the new accepted values. This risks regressions
where invalid confidence values slip through or the new field is unexercised by the
schema-validation test suite.
Code

schemas/review-result.schema.json[R30-34]

+    "confidence": {
+      "type": "string",
+      "enum": ["high", "medium", "low"],
+      "description": "How confident the review agent is in its verdict. Derived from sub-agent agreement, challenger removals, and verdict threshold proximity."
    }
Relevance

●● Moderate

No close precedent found for schema-field additions requiring new validation tests in this repo.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 1538339 requires that behavioral changes be accompanied by test changes. The diff
adds a new schema field (confidence) while the schema validation tests for the review schema do
not include any cases that exercise this new field.

schemas/review-result.schema.json[30-34]
scripts/validate-output-schema-test.sh[153-178]
Skill: code-implementation

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The review result schema now permits a new top-level `confidence` field with enum values, but there are no test fixtures asserting that valid values pass and invalid values fail.

## Issue Context
`scripts/validate-output-schema-test.sh` already tests the review schema with a couple of fixtures, but none include `confidence`, so the new contract is not constrained by tests.

## Fix Focus Areas
- scripts/validate-output-schema-test.sh[153-178]
- schemas/review-result.schema.json[30-34]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Protected skills/pr-review modified 📜 Skill insight § Compliance
Description
This PR modifies skills/pr-review/SKILL.md, which is a protected governance/infrastructure path
and must not be auto-approved. A human review is required to avoid governance/control-plane changes
being merged solely via automation.
Code

skills/pr-review/SKILL.md[R957-982]

+#### 6g. Determine confidence level
+
+After the verdict is set, derive a confidence level based on the signals
+available from the sub-agent and challenger passes. Confidence does not
+change the verdict or any routing behavior. It is an informational
+annotation for humans reviewing the agent's output.
+
+**Confidence levels:**
+
+- **high:** all sub-agents agreed on severity for every finding, the
+  challenger removed zero or one findings, and the verdict was not close
+  to a threshold boundary (e.g., no medium findings when the verdict is
+  approve)
+- **medium:** the challenger removed more than one finding (initial
+  disagreement that was resolved), OR sub-agents flagged the same code
+  with different severities, OR the verdict is one finding away from
+  flipping (e.g., one medium finding on an approve verdict)
+- **low:** significant sub-agent disagreement (same code flagged at
+  severities two or more levels apart), OR the challenger failed and
+  the pre-challenger set was used, OR the change scope is ambiguous
+  (e.g., large refactoring PR where correctness is hard to verify)
+
+Include the confidence level in the review result JSON as a top-level
+`confidence` field. This field is optional in the schema; omitting it
+is acceptable if you cannot determine it.
+
Relevance

●● Moderate

No matching historical suggestion found establishing “skills/ change must block auto-approval”;
likely depends on process.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 1538392 requires raising a finding whenever protected paths (including skills/)
are modified to ensure the PR is not auto-approved. The diff adds a new section in
skills/pr-review/SKILL.md, which is within the protected skills/ directory.

skills/pr-review/SKILL.md[957-982]
Skill: pr-review



Remediation recommended

3. Prompt blocks confidence field ✗ Dismissed 🐞 Bug ≡ Correctness
Description
The PR teaches the pr-review skill to emit a top-level confidence field, but the main review
agent prompt still instructs the agent to only emit fields listed in its top-level output
table—which does not include confidence. This conflicting guidance will likely cause the agent to
omit confidence, undermining the intended feature even though the schema allows it.
Code

skills/pr-review/SKILL.md[R979-981]

+Include the confidence level in the review result JSON as a top-level
+`confidence` field. This field is optional in the schema; omitting it
+is acceptable if you cannot determine it.
Relevance

●● Moderate

No close precedent found for prompt/output-contract mismatches suppressing newly-added optional
schema fields.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The schema and skill now allow/encourage emitting confidence, but the agent’s primary prompt still
says to emit only the fields in its table and that table does not include confidence, so the
prompt contract is internally inconsistent and likely suppresses the new field.

schemas/review-result.schema.json[6-35]
skills/pr-review/SKILL.md[957-981]
agents/review.md[230-250]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The PR adds an optional `confidence` field to `review-result.schema.json` and instructs the `pr-review` skill to output it, but `agents/review.md` (the primary agent prompt) still says to emit only the fields listed in its table and the table omits `confidence`. This conflicting contract makes it unlikely the field will be emitted in practice.

## Issue Context
- The harness uses `agents/review.md` as the agent prompt (`harness/review.yaml`).
- `agents/review.md` explicitly warns that the schema is strict and to only include fields listed below.
- The schema was updated to include `confidence`, so `agents/review.md` should be updated to match.

## Fix Focus Areas
- agents/review.md[230-260]
- skills/pr-review/SKILL.md[957-981]
- schemas/review-result.schema.json[6-35]

## Suggested changes
1. Add `confidence` to the `agents/review.md` “Top-level object” field table as optional, with allowed values `high|medium|low`.
2. Update any JSON/jq examples in `agents/review.md` to show `confidence` as optional (or add a short note that it may be included).
3. Keep wording consistent: `confidence` is informational and must not affect the `action`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

4. Invalid threshold proximity example ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
The new confidence guidance cites an example of “one medium finding on an approve verdict,” but the
same skill’s outcome rules say one medium finding should result in a comment-only outcome. This
inconsistency can lead to confusing or inconsistent confidence annotations.
Code

skills/pr-review/SKILL.md[R970-973]

+- **medium:** the challenger removed more than one finding (initial
+  disagreement that was resolved), OR sub-agents flagged the same code
+  with different severities, OR the verdict is one finding away from
+  flipping (e.g., one medium finding on an approve verdict)
Relevance

●●● Strong

Trivial doc consistency fix; similar style/clarity adjustments in pr-review docs were accepted.

PR-#172

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
6f’s rules define that one medium finding produces comment-only, yet 6g uses “one medium on approve”
as the boundary example, so the guidance is self-contradictory.

skills/pr-review/SKILL.md[939-947]
skills/pr-review/SKILL.md[966-973]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Section 6g’s examples for “verdict threshold proximity” conflict with section 6f’s verdict rules (approve should not coexist with a medium finding per the described policy).

## Issue Context
- 6f defines the outcome thresholds.
- 6g should use examples that are actually reachable under 6f, otherwise confidence becomes confusing/unstable across runs.

## Fix Focus Areas
- skills/pr-review/SKILL.md[937-977]

## Suggested changes
- Replace the “one medium finding on an approve verdict” example with a reachable boundary case (e.g., "comment verdict with exactly one medium finding" being close to flipping if another medium appears; or "request-changes with exactly two mediums" being close to flipping if one is downgraded/removed).
- Optionally clarify whether “threshold proximity” refers to (a) post-challenger final set only, or (b) how easily the verdict would flip under small adjudication changes.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 55 rules
✅ Skills: 4 invoked
  code-review
  code-implementation
  pr-review
  docs-review

Grey Divider

Tip of the day
💡 Did you know, you can commit Qodo's fix in one click with committable suggestions (GitHub & GitLab)

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread skills/pr-review/SKILL.md
Comment on lines +957 to +982
#### 6g. Determine confidence level

After the verdict is set, derive a confidence level based on the signals
available from the sub-agent and challenger passes. Confidence does not
change the verdict or any routing behavior. It is an informational
annotation for humans reviewing the agent's output.

**Confidence levels:**

- **high:** all sub-agents agreed on severity for every finding, the
challenger removed zero or one findings, and the verdict was not close
to a threshold boundary (e.g., no medium findings when the verdict is
approve)
- **medium:** the challenger removed more than one finding (initial
disagreement that was resolved), OR sub-agents flagged the same code
with different severities, OR the verdict is one finding away from
flipping (e.g., one medium finding on an approve verdict)
- **low:** significant sub-agent disagreement (same code flagged at
severities two or more levels apart), OR the challenger failed and
the pre-challenger set was used, OR the change scope is ambiguous
(e.g., large refactoring PR where correctness is hard to verify)

Include the confidence level in the review result JSON as a top-level
`confidence` field. This field is optional in the schema; omitting it
is acceptable if you cannot determine it.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Protected skills/pr-review modified 📜 Skill insight § Compliance

This PR modifies skills/pr-review/SKILL.md, which is a protected governance/infrastructure path
and must not be auto-approved. A human review is required to avoid governance/control-plane changes
being merged solely via automation.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

acknowledged, this needs human review by a codeowner.

Comment thread schemas/review-result.schema.json Outdated
Comment thread skills/pr-review/SKILL.md Outdated
Comment thread skills/pr-review/SKILL.md Outdated
@ben-alkov

Copy link
Copy Markdown
Member

/fs-review

@fullsend-ai-review

fullsend-ai-review Bot commented Jul 24, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 8:15 PM UTC · Completed 8:31 PM UTC
Commit: c70786a · View workflow run →

@fullsend-ai-review

Copy link
Copy Markdown

Review

Findings

Medium

  • [consumer-completeness] agents/review.md:238 — The top-level fields table in agents/review.md exhaustively lists every allowed field in the review result schema and is preceded by the directive: "Only include fields listed below — the schema is strict (additionalProperties: false) and will reject unknown fields." The new confidence field was added to schemas/review-result.schema.json and described in step 6g of skills/pr-review/SKILL.md, but agents/review.md was not updated to include it in this table. Because the agent definition explicitly tells the review agent to only emit fields from that table, the agent will never produce confidence — the instruction and schema are out of sync. The jq examples (lines 278–346) also omit confidence.
    Remediation: Add a confidence row (type: string, always required: no) to the top-level fields table in agents/review.md, and add a jq example demonstrating the optional field.

  • [protected-path] skills/pr-review/SKILL.md — This PR modifies skills/pr-review/SKILL.md, which is under the protected skills/ path. The PR provides sufficient context via the linked external issue (feat(review): add confidence annotation to review verdicts fullsend#5514) and a detailed description explaining the rationale. Human approval is always required for protected-path changes, regardless of context.

Low

  • [consumer-completeness] skills/pr-review/SKILL.md — Step 7 ("Produce the review result") documents required fields per action but does not mention the optional confidence field. Step 6g already instructs the agent to include it, so a reader following the procedure would know, but a cross-reference in step 7 would improve clarity.

  • [schema-inconsistency] schemas/review-result.schema.json:29 — The new confidence field uses a string enum (high/medium/low), while prioritize-result.schema.json and scribe-result.schema.json define confidence as a numeric field (0–1 range). The semantics differ — review confidence reflects sub-agent agreement and verdict stability, not a continuous probability — so the different representation is defensible, but documenting the rationale would prevent future confusion.


Labels: PR modifies review agent schema and skill definition

@fullsend-ai-review fullsend-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the review comment for full details.

},
"label_actions": {
"$ref": "#/$defs/label_actions"
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[low] schema-inconsistency

The new confidence field uses a string enum (high/medium/low), while prioritize-result.schema.json and scribe-result.schema.json define confidence as a numeric field (0-1 range). The semantics differ — review confidence reflects sub-agent agreement and verdict stability, not a continuous probability — so the different representation is defensible, but documenting the rationale would prevent future confusion.

Suggested fix: Document why review confidence semantics differ from prioritize/scribe confidence and warrant a different type.

ben-alkov
ben-alkov previously approved these changes Jul 24, 2026

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One more finding on step 6g's confidence logic — this one references code outside this PR's diff (skills/pr-review/SKILL.md:655, in step 6b), so it can't be attached as an inline comment there:

[MEDIUM] skills/pr-review/SKILL.md:655 — 6g's "different severities" medium-confidence trigger can never fire, because 6b already discards that exact signal

Step 6g's "medium" trigger #2 is "sub-agents flagged the same code with different severities." But step 6b, which runs earlier in the same synthesis pipeline, merges any two findings sharing category and location and instructs (line 655): "Keep the higher severity" — with no instruction to record that the inputs disagreed. By the time 6g runs, the one case where this signal is structurally detectable (two sub-agents, same category, same location, different severities) has already been silently collapsed into a single finding at the higher severity; the fact of disagreement is gone. As written, this specific 6g trigger has no data left to act on.

Separately, 6c deliberately keeps different-category findings on the same code as distinct entries (e.g., a correctness finding and a security finding on the same line) — normal, expected output, not disagreement — but 6g's phrasing doesn't distinguish this from genuine same-category severity disagreement, risking the trigger being misapplied to routine multi-dimension findings.

Suggestion: add an instruction to 6b to carry forward a disagreement marker (e.g., the discarded severity, or a count) when merging same-category/same-location findings, for 6g to consume. Clarify in 6g that the "different severities" trigger applies only to such same-category merges, not to 6c's intentionally distinct cross-category findings.

Comment thread skills/pr-review/SKILL.md
Use `reject` only when no amount of code-level iteration will make
the PR mergeable.

#### 6g. Determine confidence level

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM] Hardcoded numeric confidence thresholds go beyond what was asked for and aren't validated

Step 6g hardcodes absolute-count cutoffs: challenger removed "zero or one" findings = high vs. "more than one" = medium; severities "two or more levels apart" = low vs. any lesser gap = medium. These use counts rather than rates — a 1-finding PR where the challenger removes it (100% disagreement) buckets the same as a 20-finding PR where 1 of 20 is removed (5% disagreement), while a 20-finding PR where 2 of 20 are removed (10%) buckets into "medium."

The originating issue, fullsend-ai/fullsend#5514, proposes only qualitative bands ("high: ... no challenger overrides"; "medium: sub-agents disagreed ... challenger removed some but not all"; "low: significant sub-agent disagreement") — no 0-vs-1 count or two-level severity-gap numbers appear anywhere in it. Those specific cutoffs were introduced in this PR.

The linked problem doc (docs/problems/graduated-approval-policy.md) states directly, under "What we do not yet know": "Evidence for thresholds ... The thresholds need to be derived from observed outcomes, not guessed," and its "Path forward" section prescribes writing eval cases and demonstrating improvement before proposing thresholds. eval/review/cases/ in this repo currently contains only a .gitkeep — no eval cases exist to justify these numbers, despite eval/run-functional.sh already providing a harness to exercise them.

There's also direct precedent in this same problem area: fullsend-ai/fullsend#2255 documents a human reviewer closing fullsend-ai/fullsend#2012 specifically because it "was fundamentally a solution proposal (numeric scoring system, 5-tier routing table, three implementation approaches) filed as a problem doc."

Suggestion: walk the thresholds back to the qualitative language #5514 actually proposed (flagging any numeric boundary as a provisional heuristic pending calibration), or add eval cases under eval/review/cases/ exercising the 0/1/2+ boundaries and cite them as justification, per the problem doc's own prescribed path.

Comment thread skills/pr-review/SKILL.md Outdated
the pre-challenger set was used, OR the change scope is ambiguous
(e.g., large refactoring PR where correctness is hard to verify)

Include the confidence level in the review result JSON as a top-level

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM] Confidence has no consumer: not in the review body template, not in post-review.sh, not in interactive mode

Step 6g calls confidence "an informational annotation for humans reviewing the agent's output," but nothing renders it. Section 7's body template is restricted to the hidden SHA comment plus findings sections ("No summary section," "No footer ... do not repeat the outcome or include boilerplate") with no slot for confidence.

scripts/post-review.sh reads .action, .label_actions, .label_actions.reason, and .label_actions.actions[], but has no reference to .confidence anywhere. In interactive mode (no $FULLSEND_OUTPUT_DIR), no JSON artifact is written at all, so the computed value has no destination there either.

This repo already has a wired-up precedent for the same pattern: scripts/post-prioritize.sh reads .confidence via jq and writes it into the posted comment's RICE table and a tracked field. This PR doesn't follow that precedent.

Separately, the originating issue (fullsend-ai/fullsend#5514) lists three deliverables, the third being "Post-script PR comment: display confidence alongside the verdict." This PR implements only the first two, and the description doesn't flag the third as deferred.

(This is distinct from the existing LOW "consumer-completeness" finding already posted on this PR, which asks only for a cross-reference to confidence inside step 7's own documentation — it doesn't note that post-review.sh never reads the field, or that interactive mode has no destination for it at all.)

Suggestion: wire .confidence into scripts/post-review.sh and/or the body template so it actually reaches a human, following the post-prioritize.sh precedent, or state explicitly in the PR description that display is deferred to a tracked follow-up — and handle interactive mode so the computed value isn't silently discarded there too.

Comment thread skills/pr-review/SKILL.md Outdated

**Confidence levels:**

- **high:** all sub-agents agreed on severity for every finding, the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM] "All sub-agents agreed" is vacuously true whenever findings don't overlap — the normal case

The "high" bullet requires "all sub-agents agreed on severity for every finding." Per the synthesis pipeline, each dispatched sub-agent runs in full context isolation (no sub-agent sees findings from other dimensions), and 6a/6b only compare severities when two findings land in the same file within 5 lines of each other and share a category. Per the dispatch table, the normal case is non-overlapping fan-out — e.g., a "bug fix in auth middleware" change dispatches correctness, security, style-conventions, and intent-coherence sub-agents, each typically flagging distinct concerns.

When sub-agents report entirely non-overlapping findings (the common case), there's nothing to compare, so "all agreed" holds vacuously no matter how many independent issues were found. A PR where 4 sub-agents each surface one distinct, non-overlapping low-severity finding qualifies for the same "high" label as a PR where sub-agents actually examined the same code and converged on it — conflating "no detected conflict" with "actively corroborated."

Suggestion: require some minimum location overlap before "high" can be claimed on agreement grounds, or explicitly document that this criterion only asserts the absence of detected conflicts rather than independent corroboration.

Comment thread skills/pr-review/SKILL.md Outdated

- **high:** all sub-agents agreed on severity for every finding, the
challenger removed zero or one findings, and the verdict was not close
to a threshold boundary (e.g., no medium findings when the verdict is

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM] The "high" bullet's threshold-boundary example is tautological — the same bug already fixed in the adjacent "medium" bullet wasn't fixed here

The parenthetical "(e.g., no medium findings when the verdict is approve)" is vacuously true for every approve verdict: per 6f, approve is only reached via "no findings" or "low/info findings only (no medium+)," so an approve verdict can never have a medium finding regardless of how borderline anything was. The example can never disqualify a case from "high," so it provides no actual discriminating signal.

The exact same defect existed in the adjacent "medium" bullet ("one medium finding on an approve verdict" — an impossible combination under 6f). qodo-code-review flagged that specific phrase earlier in this PR's review, and it was fixed in commit c70786a ("changed 'approve verdict' to 'comment-only verdict' to match step 6f") — the line below now correctly reads "one medium finding on a comment-only verdict." That fix only addressed the medium bullet's text; the high bullet's separate, analogous tautology here was left unchanged.

Suggestion: replace the parenthetical with a reachable boundary case (e.g., zero findings vs. several low/info findings a sub-agent nearly classified as medium), or drop the example since 6f already guarantees zero medium+ findings on any approve verdict.

@ben-alkov
ben-alkov force-pushed the feat/review-confidence-annotation branch from c70786a to b835553 Compare July 29, 2026 21:21
@ben-alkov
ben-alkov self-requested a review July 29, 2026 21:21

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review-only pass on step 6g's confidence rubric and the schema change. 4 findings below (1 high, 3 medium); none overlap with the review comments already posted on this PR.

Comment thread skills/pr-review/SKILL.md Outdated
**Confidence levels:**

- **high:** all sub-agents agreed on severity for every finding, the
challenger removed zero or one findings, and the verdict was not close

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[HIGH] No precedence rule when confidence-band criteria overlap (challenger-failure vs. full-agreement, and medium vs. low severity-gap)

Step 6g's three confidence bands are independent OR/AND lists with no stated evaluation order, and two concrete collisions exist in the current text (verified on head b835553):

  1. High requires "the challenger removed zero or one findings." Per step 6d (lines 915-925, unchanged by this PR), when the challenger sub-agent fails, the orchestrator falls back to the pre-challenger set and records an info-level sub-agent-failure finding — but the effective "removed count" signal is also zero, making a failed challenger pass indistinguishable from one that ran and agreed with everything. Low separately lists "the challenger failed and the pre-challenger set was used" (line 1149) as its own trigger, but nothing in 6g instructs checking for that condition before evaluating high's removed-count criterion, so a failed challenger pass risks being read as maximum confidence instead of the low confidence intended.
  2. Medium's "sub-agents flagged the same code with different severities" (lines 1145-1146) is a strict superset of low's "severities two or more levels apart" (lines 1148-1149) — every case satisfying low's condition also satisfies medium's, with no tie-break stated for which wins.

Suggestion: state an explicit evaluation order, e.g., "check low's triggers first (including the step 6d sub-agent-failure marker); if none apply, check medium; otherwise high," and narrow medium's severity-difference clause to exclude gaps of two or more levels so it doesn't overlap with low's condition.

Comment thread skills/pr-review/SKILL.md Outdated
approve)
- **medium:** the challenger removed more than one finding (initial
disagreement that was resolved), OR sub-agents flagged the same code
with different severities, OR the verdict is one finding away from

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM] comment-only verdicts are structurally incapable of ever reaching high confidence

Verified on head b835553: step 6f (line 1119) defines comment-only as exactly "one medium finding (but no critical/high)" — every comment-only verdict has precisely one medium finding by construction. Step 6g's medium band cites "one medium finding on a comment-only verdict" (line 1147) as its illustrative example of "the verdict is one finding away from flipping." Since this is true of every single comment-only verdict without exception, it is unconditionally satisfied whenever the outcome is comment-only.

High's third requirement is that "the verdict was not close to a threshold boundary" (lines 1141-1142) — but the only description of what counts as "close to a boundary" is the same condition medium's example describes, which every comment-only verdict trivially meets. The practical consequence: no comment-only verdict can ever be labeled "high" confidence, no matter how unanimous the sub-agents were and how little the challenger changed, because the class of comment-only verdicts is definitionally always "one finding from flipping."

This is a distinct, deeper defect from the already-posted note that the high bullet's own approve-verdict example is vacuous — this is about an entire verdict category being capped, not about one example being uninformative.

Suggestion: either explicitly document that comment-only caps out at medium confidence (if intentional), or add an exception allowing high when the single medium finding was unanimous across sub-agents and survived the challenger unchanged.

Comment thread skills/pr-review/SKILL.md
Use `reject` only when no amount of code-level iteration will make
the PR mergeable.

#### 6g. Determine confidence level

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM] Confidence rubric gives no guidance for the reject verdict, the most subjective and highest-stakes case

Verified on head b835553: step 6f's reject clause (lines 1126-1129) fires on a subjective architectural judgment ("the approach is fundamentally wrong... no amount of code-level iteration will make the PR mergeable"), not on a tally of finding severities. All three bands in step 6g (lines 1140-1151), however, are defined purely in terms of per-finding signals: sub-agent severity agreement, challenger removal counts, and proximity to the approve/comment-only/request-changes thresholds. None of these naturally describe confidence in a reject call. Mechanically applying the stated rules, a reject verdict whose underlying findings all happened to have agreed severities and zero challenger removals would score "high" — even though what's actually contestable about a reject call is the architectural judgment itself, not the findings' severities.

Suggestion: add an explicit rule for reject, e.g., default it to "medium" unless the rejection rationale itself (not just finding severities) was independently corroborated by multiple sub-agents, or state that confidence for reject should reflect agreement on the architectural judgment rather than on finding tallies.

Comment thread schemas/review-result.schema.json Outdated
"label_actions": {
"$ref": "#/$defs/label_actions"
},
"confidence": {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM] Schema does not forbid confidence alongside action: "failure", allowing a self-contradictory result

Verified on head b835553: the confidence property (line 30) has no allOf conditional restricting it. The schema's allOf block already has a targeted conditional for action == "failure" (line 54) requiring only ["reason"], and a separate targeted conditional for approve+protected-path exclusion (lines 57-75) — establishing the pattern for this kind of restriction — but no equivalent guard excludes confidence from a failure result. Step 6g frames confidence as derived "after the verdict is set" (line 1133), presupposing a completed review, while action: "failure" represents the opposite (SKILL.md's failure-output guidance states the PR was not reviewed at all). As written, a result like {"action":"failure","reason":"tool-failure","confidence":"high"} currently validates against the schema, which is incoherent — "high confidence" in a verdict that was never reached.

Suggestion: add an allOf entry mirroring the existing pattern: {"if": {"properties": {"action": {"const": "failure"}}, "required": ["action"]}, "then": {"not": {"required": ["confidence"]}}}.

@Benkapner

Copy link
Copy Markdown
Author

On precedence collisions i agree as the bands need explicit evaluation order. ill add "check low triggers first if none apply, check medium otherwise high" in the next push, what do you think?

On comment-only capped - this is actually intentional. A comment-only verdict is by definition close to a threshold boundary (one more medium finding would flip to request-changes). ill document this explicitly rather than leaving it implicit.

on reject having no confidence guidance: not sure, i mean, its fair.. reject is a qualitative judgment call.. what do you say about default reject to "medium" confidence, because rejection is inherently a judgment call and only bump to "high" if multiple sub-agents independently said something like "this approach is fundamentally flawed" (not just "i found a bug"). That way the human reviewer sees "reject (medium confidence)" and knows to look carefully at whether reject is warranted vs. just requesting changes. @ben-alkov @waynesun09 @rh-hemartin

On schema allowing confidence with action: "failure": will add the allOf conditional to exclude confidence from failure results, matching the existing pattern.

@Benkapner
Benkapner requested a review from waynesun09 August 4, 2026 04:20
@Benkapner
Benkapner force-pushed the feat/review-confidence-annotation branch from b835553 to 261f903 Compare August 26, 2026 10:55
@Benkapner

Copy link
Copy Markdown
Author

@waynesun09 thanks for the detailed review. I rebased the branch onto current main and reworked the confidence rubric to address every point. Force-pushed as 261f903.

Here is how each finding maps to the change (the rubric now lives in skills/pr-review/SKILL.md step 6g; the summary table in the PR description above is superseded by that section):

  1. No precedence rule when bands overlap. 6g now states an explicit evaluation order: evaluate low, then medium, then high, assigning the first (most cautious) band whose condition holds and never promoting once a lower band matches. Overlaps resolve deterministically toward the more conservative band.

  2. "Different severities" medium trigger could never fire (6b collapses to the higher severity). 6b now records the severity disagreement and the size of the gap in the synthesis notes before merging to the higher severity, and 6g reads those notes. The trigger is scoped to same-category 6b merges only (a one-level gap is medium, a two-or-more-level gap is low), not to the distinct-category findings preserved in 6c.

  3. Hardcoded numeric thresholds beyond scope. Bands are now qualitative. The only residual numeric distinction (one-level vs two-or-more-level severity gap) is explicitly marked a provisional heuristic, with a note that bands should ultimately be derived from observed outcomes per graduated-approval-policy.md.

  4. "All sub-agents agreed" is vacuously true when findings do not overlap. High now requires absence of detected conflict (no sub-agent-failure finding, no severity disagreement in any 6b merge, no reconciliation contradiction) plus corroboration: each finding driving the verdict must have been raised by more than one sub-agent or confirmed by the challenger. The text calls out that disjoint-scope sub-agents do not corroborate each other.

  5. High's threshold-boundary example was tautological. Dropped that example. High is now defined by the absence-of-conflict plus corroboration conditions above, not by a "no medium findings when approve" restatement.

  6. comment-only could never reach high. 6g documents that comment-only caps at medium unless the single driving medium finding was raised by more than one sub-agent AND survived the challenger unchanged.

  7. No guidance for the reject verdict. Added: reject reflects a judgment call on architecture or scope, so it defaults to medium, and only reaches high when the architectural objection is corroborated (raised independently by more than one sub-agent or confirmed by the challenger).

  8. Schema allowed confidence with action: failure. Added an allOf guard forbidding confidence when action is failure, and 6g plus the output docs say to omit it for failures.

Also in this revision, so the field actually reaches the PR: scripts/post-review.src.sh (and the regenerated post-review.sh) append a **Confidence:** <value> line to the review body for non-failure actions, agents/review.md documents the field, and scripts/post-review-test.sh covers the present and absent cases. make script-test for the post-review suite passes; the schema guard is verified against the JSON Schema validator.

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review-only pass at head 261f903 on the revised step 6g rubric, the 6b "synthesis notes" addition, and the new post-script annotation. 3 medium findings below; none overlaps an existing thread on this PR.

# Append confidence annotation to body (skips failure, which has no body)
# ---------------------------------------------------------------------------

CONFIDENCE=$(jq -r '.confidence // empty' "${RESULT_FILE}")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM] Confidence annotation is posted against a verdict the post-script already overrode

Verified at head 261f903. The new block reads .confidence and appends **Confidence:** <value> to the body, but by that point post-review.src.sh may already have replaced the agent's verdict, and the confidence value is never revisited.

Two confirmed override paths run BEFORE the confidence block:

  1. Severity filter: when filtering removes every finding, jq 'del(.findings) | .action = "comment"' rewrites request-changes/reject to comment. This runs before ACTION is read, so ACTION is already the rewritten value.
  2. Protected-path check: jq '.action = "comment" | .body = (.body + $notice)' rewrites approve to comment and appends a "human reviewer must approve" notice, setting DOWNGRADED=true. The script explicitly documents that the ACTION shell variable retains the original value here ("ACTION retains the original value for the entire script — not re-read after protected-path downgrade").

In both paths the confidence the agent computed for the original verdict is rendered verbatim under the new one. A protected-path downgrade will routinely post comment + **Confidence:** high — a combination the new rubric says is essentially unreachable (SKILL.md §6g caps comment-only at medium unless a narrow corroboration test passes). Per §6g confidence is a property of the action ("how strongly the evidence and sub-agent agreement support this action"), so after a downgrade the posted value describes an action that no longer exists.

This is not cosmetic: the PR's stated purpose is to emit this datum for downstream graduated-approval work, and the value is wrong precisely on the protected-path and all-findings-filtered paths — the paths where a human (and any future automation) most needs an accurate signal. Note that skills/pr-review/ is itself a protected path, so this scenario fires on this repo's own reviews of PRs like this one. Neither of the two added tests in post-review-test.sh covers a downgrade combined with confidence.

Suggestion: Re-read the action after the downgrade paths, or gate the annotation on a downgrade flag, and either drop confidence from the body when the post-script changed the verdict or scope it to the agent's original verdict, e.g. **Confidence:** high (agent verdict: approve — downgraded by protected-path check). Note that a flag-based fix must cover BOTH paths: DOWNGRADED exists only for the protected-path branch, while the severity-filter branch keeps original_action local to its own block. Add post-review-test.sh cases for approve+confidence+protected path and for request-changes+confidence fully filtered, asserting the resulting annotation.

Comment thread skills/pr-review/SKILL.md Outdated
Omit `confidence` entirely for the `failure` action.

**Evaluation order.** The bands below can overlap, so evaluate them in a
fixed order and assign the **first** band whose condition holds: low

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM] 6g's "first matching band wins, never promote" rule contradicts its own promotion clauses for reject and comment-only

Verified against the diff at head 261f903. §6g states an absolute precedence rule: "evaluate them in a fixed order and assign the first band whose condition holds: low first, then medium, then high. The most cautious matching band wins; never promote to a higher band once a lower one has matched."

But two of the Medium band's triggers are unconditional properties of the action, not evidence conditions:

  • "The action is comment-only. Medium is the ceiling for comment-only unless the single driving medium finding was raised by more than one sub-agent AND survived the challenger unchanged; only then may comment-only reach high."
  • "The action is reject. ... default to medium. Promote to high only when the architectural objection is corroborated ..."

The clearest defect is a direct wording collision that survives any reading: the reject bullet literally says "Promote to high," while the ordering rule literally says "never promote to a higher band once a lower one has matched." Two literal-minded agents will band the same review differently.

Under the strict first-match reading, the Medium band matches by definition for every comment-only and every reject verdict, so the escape clauses in those same bullets are dead text and no reject or comment-only verdict can ever be assigned high. There is a more charitable parse — reading the condition as "comment-only AND NOT(corroborated)" — but the rubric never says which parse is intended, and that ambiguity is itself the problem in a document whose whole purpose is to make banding deterministic.

This matters because the author's revision comment lists these as separate fixes (item 1 = add evaluation order, item 6 = comment-only ceiling, item 7 = reject default), each added verbatim in response to a prior reviewer request. Item 1 silently undercuts the exceptions added by 6 and 7, so the fixes do not compose.

Suggestion: Separate band selection from band caps. Step 1: pick a band from the evidence conditions only (challenger failure, severity gaps, reconciliation, corroboration, missing context) using the low-then-medium-then-high order. Step 2: apply action-based ceilings (comment-only and reject cap at medium unless the stated corroboration test passes). Ceilings can then only lower a band, never collide with the first-match/never-promote rule, and the word "promote" disappears from the bullets.

Comment thread skills/pr-review/SKILL.md Outdated
- Preserve `actionable: true` if either finding had it
- If the merged findings disagreed on severity, record that disagreement
and the size of the gap (in severity levels) in your synthesis notes.
Merging to the higher severity discards the disagreement from the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM] 6g depends on "synthesis notes", an artifact that exists nowhere else in the skill or the output contract

Verified at head 261f903. The 6b addition instructs: "record that disagreement and the size of the gap (in severity levels) in your synthesis notes ... step 6g reads these notes when setting confidence."

The term is introduced by this PR and never defined. A repo-wide code search for "synthesis notes" returns zero occurrences, and a notes search scoped to skills/pr-review matches only unrelated GitLab API comment endpoints (/issues/<iid>/notes) — there is no note-taking artifact concept anywhere in the skill.

Nothing says where these notes live: a file under $FULLSEND_OUTPUT_DIR, in-context scratch text, or a field on the merged finding. They are not part of review-result.schema.json (the schema diff adds only confidence), so they are unobservable and untestable. Nothing states that they must be written before, or survive, the challenger pass in 6d/6e, or any context compaction between 6b and 6g.

The severity-gap machinery in §6g depends entirely on them — both the low band's "two or more levels" trigger and the medium band's "exactly one level" trigger read from this undefined store. This is the author's stated fix (revision item 2) for the earlier finding that the "different severities" trigger could never fire because 6b collapses to the higher severity. An agent holding 6b and 6g in one context may well carry the data forward in working memory, so the trigger is not strictly unimplementable — but the fix relocates the requirement into an undefined carrier rather than giving the data a defined home, which leaves the mechanism unverifiable and fragile.

Suggestion: Make the disagreement observable at the point 6g needs it: either keep the pre-merge severities on the merged finding (e.g. an internal merged_from: [{severity: low}, {severity: high}] note carried through 6c-6f), or define "synthesis notes" concretely in 6b — what file or section, what fields, and that it must be written before the challenger pass. Otherwise drop the severity-gap triggers from 6g until there is a defined carrier.

Benkapner and others added 2 commits September 9, 2026 14:58
Add an optional `confidence` field (high/medium/low) to the review
result, letting the review agent signal how strongly the evidence and
sub-agent agreement support its verdict. This is a minimal step toward
graduated approval: the value is advisory and does not change the action.

Addresses the review feedback on the prior confidence proposal:

- Precedence: confidence bands are evaluated low, then medium, then high,
  with the first (most cautious) matching band winning, so overlapping
  conditions resolve deterministically.
- Bands are qualitative, not numeric; the residual severity-gap splits
  are marked provisional pending eval-case calibration.
- 6b merges now record severity disagreement in synthesis notes so the
  medium "sub-agents disagreed" trigger can actually fire (merging to the
  higher severity previously discarded it).
- High requires absence of detected conflict plus corroboration of the
  driving findings, not the vacuous "all agreed" when scopes are disjoint.
- comment-only caps at medium unless the single driving finding was
  corroborated and survived the challenger; reject defaults to medium.
- Dropped the tautological high boundary example.
- Schema forbids `confidence` when action is `failure`.

The post-review script appends a "Confidence:" annotation to the body for
non-failure actions; agents/review.md documents the field.

Signed-off-by: Benjamin Kapner <bkapner@redhat.com>
Post-review can rewrite the action (severity filter, protected-path)
before the confidence line is appended. Name the agent's original
verdict when that happens. Split 6g into evidence-band then action
ceilings, and carry 6b severity disagreement as merged_from instead
of undefined synthesis notes.

Signed-off-by: Benjamin Kapner <bkapner@redhat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@Benkapner
Benkapner force-pushed the feat/review-confidence-annotation branch from 261f903 to 392d2a1 Compare September 9, 2026 12:02
@Benkapner
Benkapner requested a review from waynesun09 September 9, 2026 13:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(review): add confidence annotation to review verdicts

4 participants