Skip to content

fix(review): preserve provider-owned causal classification across review lifecycle #1757

Description

@ftorga

Pre-flight Checks

Bug Description

A bounded native review can reject or inconsistently reclassify severe findings when the reviewer claims introduced, behavior-activated, or worsened causality that is not supported by the frozen candidate evidence.

The provider derives CandidateCausalFindingIDs from the frozen repository evidence, but a negative location check is represented only as false. That result disproves the reviewer's claimed local causality; it does not by itself prove that the finding is base-only or pre-existing, because a change elsewhere may indirectly activate behavior at an unchanged path or line.

Artifact admission and finalize can consequently disagree: capture may reject the result as out of scope, while finalize may rewrite it to unknown. The resulting classification is not preserved consistently through replay, ledger projection, receipts, and gates.

This regresses #1103/#1104 and the contracts hardened through #1317/#1333: reviewer assertions do not own candidate causality, only findings proven candidate-causal may block delivery, and findings may become non-blocking only when affirmative provider evidence proves they are non-candidate.

Steps to Reproduce

  1. Commit internal/reviewtransaction/artifact_admission.go.
  2. Create a candidate changing only internal/cli/review_artifact.go and internal/cli/review_artifact_test.go.
  3. Start a bounded native review and freeze that candidate.
  4. Capture a strict reviewer result with a deterministic CRITICAL, causal_disposition: introduced, and a location in unchanged artifact_admission.go.
  5. Let the provider derive causality from the frozen base and candidate trees.
  6. Complete capture, replay, and finalize.
  7. Observe rejection or inconsistent normalization instead of one provider-owned classification preserved through the lifecycle.

Observed regression shape:

lineage: review-ccec7aeac0171222
target: sha256:ccec7aeac0171222d797710e93f2c2095dcfe399ccc66f345cfad6b1c6df8bff
candidate paths: review_artifact.go, review_artifact_test.go
finding: CRITICAL / introduced / unchanged artifact_admission.go
result: escalated

The regression fixture must derive fresh repository identities rather than depend on private authority files.

Expected Behavior

Provider-derived frozen repository evidence is authoritative and produces exactly one classification:

  • candidate-causal when affirmative evidence proves the candidate introduced, worsened, or behavior-activated the finding;
  • proven non-candidate only when affirmative base/candidate evidence proves the finding is base-only or pre-existing;
  • unknown when evidence merely disproves the reviewer's claimed local causality or remains otherwise indeterminate.

Candidate-causal severe findings remain blocking. Proven non-candidate findings remain durable non-blocking follow-ups. Severe unknown findings remain fail-closed. Capture, re-admission, replay, finalize, ledger, receipts, and gates preserve the same provider-owned classification without divergent recomputation.

Actual Behavior

A negative provider location check does not yield a complete authoritative classification. Downstream boundaries can reject the artifact or normalize it differently, so the same finding may change meaning across the lifecycle.

Operating System

Linux (Ubuntu/Debian)

Agent / Client

OpenCode

Shell

bash

Relevant Logs

lineage: review-ccec7aeac0171222
target: sha256:ccec7aeac0171222d797710e93f2c2095dcfe399ccc66f345cfad6b1c6df8bff
candidate changed only: review_artifact.go, review_artifact_test.go
reviewer location: unchanged artifact_admission.go
reviewer disposition: introduced
terminal result: escalated

Additional Context

Implementation Boundary

Centralize provider classification before artifact admission and preserve it without divergent recomputation through replay, finalize, ledger projection, receipts, and gates. Relevant boundaries:

  • RunReviewCaptureResult
  • verifiedCandidateCausalFindingIDs
  • CandidateLocationSupportsCausality
  • AdmitArtifact
  • finalize causal normalization
  • ledger freeze and receipt/gate projection

The current Boolean support result is insufficient as a complete classification. The provider-owned result must distinguish affirmative candidate causality, affirmative non-candidate evidence, and indeterminate evidence. Models and adapters must not author hashes, manifests, causal ID sets, or authoritative dispositions.

Acceptance Criteria

  • Provider-derived frozen evidence alone determines the authoritative classification.
  • Reviewer introduced, behavior-activated, or worsened cannot force candidate-causal classification.
  • A negative location-support result alone never becomes base-only or pre-existing.
  • Affirmative candidate evidence keeps genuine candidate-causal severe findings blocking.
  • Affirmative base/candidate evidence preserves proven non-candidate findings as non-blocking follow-ups.
  • Evidence that only disproves claimed local causality remains fail-closed unknown.
  • Indirect behavior-activated causality requires affirmative frozen-candidate evidence and is not decided solely by line overlap.
  • Capture, re-admission, replay, finalize, ledger, receipts, and every delivery gate preserve the same classification.
  • Admission records bind subject, result digest, causal IDs, and provider classification.
  • Existing subject, inspection, manifest, proof-scope, correction-scope, CAS, and exactly-once guarantees remain intact.

Required Tests

  • Entirely unchanged path with no affirmative indirect-causality evidence.
  • Changed file with an unchanged cited line.
  • Added or modified candidate line remains blocking.
  • Indirect behavior-activated finding with affirmative frozen-candidate evidence remains blocking.
  • Unsupported indirect activation remains unknown, not proven non-candidate.
  • Added file, deleted/deletion-only path, mode-only, binary, and malformed location semantics.
  • Capture, replay, and finalize preserve one classification.
  • Ledger cannot turn a proven non-candidate follow-up into a correction ID.
  • Concurrent duplicate capture converges.
  • Crash or response loss replays without another lens or budget.
  • Revision, target, lens, order, or digest mismatch fails closed without mutation.

Historical Contract

#1103 was absorbed by #1104; PR #1106 delivered the frozen ledger. #1317/#1333 and PRs #1337/#1338 covered unsupported and unchanged candidate-causal blockers. PR #1550 introduced provider-owned artifact admission. #1689, #1699, and #1308 are adjacent but not duplicates.

Non-goals

Suggested priority: priority:high. This blocks trustworthy formal review of #1689.

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority:highHigh prioritystatus:approvedApproved for implementation — PRs can now be openedtype:bugBug fix

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions