Skip to content

bug(review): assess rejects already_reviewed passive delta when exact candidate is unconsumed #1954

Description

@MarsSall

Before submitting

  • I searched open and closed issues and did not find a report of this problem.
  • I reviewed this report and removed credentials, tokens, private paths, hostnames, and other sensitive data.

These checks were performed by the reporting agent. Searches included already_reviewed, "passive delta", "acknowledged_predecessor", and "consumed" "assess". Related #1175 concerns optional reason fields, and #654 concerns acknowledgement losing its committed selector; neither matches this reproduction.

Problem

The Shell assessment decoder rejects a native assessment after an acknowledged committed review is followed only by a passive ODD task note.

Native Gentle AI correctly reports review_due: false, review_due_reason: "already_reviewed", and candidate.consumed: false. The exact new candidate has not been consumed; its executable changes are covered by the acknowledged committed predecessor. A fresh inspection of the new range also stops with acknowledged_predecessor_passive_delta.

The facade instead returns risk: "unassessable" with schema-incompatible, losing the native medium risk and review eligibility evidence and falling back to high-risk-equivalent verification. No data loss or unsafe approval was observed.

The conflicting check remains present in current main and in the tested source commit: validateReviewDueConsistency in lib/review-risk-assessment.ts requires already_reviewed if and only if candidate.consumed === true:

const alreadyReviewed = reviewDueReason === REVIEW_DUE_REASON.ALREADY_REVIEWED;
if (alreadyReviewed !== (candidate.consumed === true)) {
  throw new TypeError("review assessment review_due_reason already_reviewed must be reported exactly when candidate.consumed is true");
}

This equivalence excludes the native acknowledged-predecessor passive-delta case. The exact candidate must remain unconsumed; accepting the assessment must not manufacture closure or delivery authority.

Steps to reproduce

  1. Use the beta versions below, with RDD enabled, in a disposable Git repository.
  2. Commit a baseline containing increment(value) returning value + 1 and a passing test for increment(1) == 2. Retain this commit as <base-commit>.
  3. Add double(value) returning value * 2, plus a test for double(3) == 6. Leave increment and its original test unchanged. Observe RED before adding double, then GREEN for both tests; commit this additive change.
  4. Run an ordinary committed-only native review against <base-commit> with the reliability lens through the facade. Complete the provider-issued capture and exact acknowledgement. In this reproduction the review approved and acknowledgement returned authority: "burned".
  5. Add and commit only odd/tasks/beta-note.md, containing a short passive note about the approved candidate. Do not change executable files or the original base selector.
  6. Call gentle_review with operation: "assess", the fixture workspaceRoot, and input: {"baseRef":"<base-commit>","committedOnly":true}.
  7. Compare with the read-only native command for the same committed range:
gentle-ai review assess --cwd=<fixture> --base-ref=<base-commit> --committed-only --json
  1. A fresh facade inspection of the new range with the same base selector returns the terminal stop acknowledged_predecessor_passive_delta. This is inspection of the new candidate, not a bound STATUS replay of the consumed lineage.

The fixture was removed after collecting the results. This was an actual approved committed review, not a mocked receipt or an acknowledgement of pending workspace changes.

Expected and actual behavior

Expected: accept the supported native acknowledged-predecessor assessment, preserve candidate.consumed: false, expose reviewDue: false and already_reviewed, and derive verification from the native risk tier without inventing exact-candidate closure.

Actual: the facade rejects the native envelope, returns risk and nativeRisk as unassessable, candidate: null, and applies its conservative high-risk fallback. The native command exits 0 with a usable medium-risk assessment, and fresh inspection recognizes the passive delta.

Suggested regression: decode this native envelope with already_reviewed, review_due: false, and candidate.consumed: false, while retaining malformed-envelope rejection and exact-candidate consumed/closure semantics.

gentle-pi version

4.0.0; tested source commit 12a69a36524d4f239aefc3db7a25bce99c9e1bf5. Native Gentle AI beta override: 4.0.1-0.20261008053821-b15198ba3876. This report concerns the beta pairing, not a claim about the bundled stable binary.

Pi version

1.1.0

Operating system

Linux

Relevant logs or error output (optional)

Native assessment (exit 0; base commit replaced with a public-safe placeholder):
{
  "schema": "gentle-ai.review-assessment/v1",
  "risk": "medium",
  "reasons": [{"code": "executable_change", "path": "calc.py"}],
  "changed_paths": 3,
  "changed_lines": 10,
  "candidate": {
    "kind": "base-diff",
    "base_ref": "<base-commit>",
    "consumed": false
  },
  "review_due": false,
  "review_due_reason": "already_reviewed"
}

Facade assessment excerpt:
"risk": "unassessable"
"nativeRisk": "unassessable"
"reasons": [{
  "code": "schema-incompatible",
  "detail": "native review assess failed; no sanitized stderr diagnostic is available."
}]
"candidate": null
"plan": {
  "writerSelfVerification": true,
  "structuralReadbackOnly": false,
  "independentVerifier": true,
  ...
}

Fresh inspection of the new range:
"next_transition": {
  "kind": "stop",
  "reason_code": "acknowledged_predecessor_passive_delta"
}

Activity

  1. Alan-TheGentleman commented on Oct 10, 2026

    @Alan-TheGentleman
    Collaborator

    Fixed in #1987 (merged as 3f86655).

    The Shell assessment decoder now accepts an already_reviewed predecessor whose exact candidate is explicitly unconsumed, without inferring closure for that candidate. Missing or contradictory consumed evidence is still rejected.

    Covered by:

    • decodeReviewAssessmentV1 accepts an already-reviewed predecessor without consuming the medium-risk candidate (#1954)
    • gentle_review assess: already-reviewed predecessor remains medium and never proves exact-candidate closure (#1954)
    • decodeReviewAssessmentV1 rejects already_reviewed with missing consumed evidence

    Thanks for the precise reproduction.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    status:approvedIssue approved by maintainer; PR may be opened

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions