Pre-flight Checklist
Bug Description
Native reviewer capture accepts facadeFinding.id as optional (json:"id,omitempty"), but candidate-causal admission requires repository-derived finding IDs before canonical lens-result processing assigns deterministic IDs to omitted values.
For a valid candidate-causal finding that omits id, the native pipeline can derive an empty candidate-causal ID from the decoded provider result, then canonicalize the same finding to R1-001, R2-001, R3-001, or R4-001. AdmitArtifact compares the pre-canonical verified ID set with the post-canonical expected ID set and rejects the result as out of scope:
reviewer artifact admission out_of_scope: candidate-causal findings are not proven by repository-derived changed-line evidence
The public decoder therefore permits a shape that native semantic admission cannot successfully process for candidate-causal findings.
This is distinct from intended proof-scope validation. AdmitArtifact correctly rejects proof_refs that cite repository paths outside the frozen changed_path_manifest; callers should keep candidate proof inside the frozen candidate rather than weaken that check.
Steps to Reproduce
- Start a negotiated native review with a frozen candidate containing one changed line and select any review lens.
- Obtain the provider-owned artifact subject, candidate diff, and changed-path manifest through capture preflight.
- Submit a reviewer result with completed provider-owned inspection and one candidate-causal
CRITICAL finding whose location and proof reference point to the changed candidate line.
- Omit only the finding
id; keep evidence_class: "deterministic" and causal_disposition: "introduced".
- Capture the result through
gentle-ai review capture-result.
- Observe that decoding succeeds because
facadeFinding.ID is optional, canonicalization assigns a deterministic lens ID, but candidate-causal ID verification no longer matches and admission rejects the result.
Expected Behavior
The native boundary should have one coherent ownership rule for finding IDs:
- Either require every non-empty finding ID during decode/admission before repository-derived candidate-causal verification, with the canonical selected-lens prefix and uniqueness checks; or
- Canonicalize deterministic IDs before deriving and comparing repository-owned candidate-causal ID sets, while preserving the exact canonical payload and all existing admission checks.
Missing IDs must not be silently accepted by the schema and then rejected only because canonicalization occurs after causal verification.
Actual Behavior
facadeFinding.ID uses omitempty, canonicalLensResult deterministically supplies a missing ID, and AdmitArtifact compares candidate-causal IDs against the canonicalized result. A schema-valid reviewer payload is therefore unreplayable even though its location and proof are fully inside the frozen candidate.
Environment
- Gentle AI:
1.49.1-0.20260722122850-8881b60b01c7
- Operating System: Linux
- Agent / Client: OpenCode
- Shell: bash
- Affected Area: native review capture and artifact admission
Source Evidence
internal/cli/review_facade.go: facadeFinding.ID string json:"id,omitempty".
internal/reviewtransaction/transaction.go: canonicalLensResult assigns <lens-prefix>-<index> when finding.ID == "".
internal/cli/review_artifact.go: repository-derived CandidateCausalFindingIDs are passed into admission.
internal/reviewtransaction/artifact_admission.go: admission canonicalizes the lens result, derives candidate-causal IDs from canonical findings, and compares them with the previously verified IDs.
Acceptance Criteria
- A focused test covers a candidate-causal finding with omitted
id and proves the chosen ownership rule deterministically.
- Native schema/decoder behavior and semantic admission agree about whether
id is required.
- Stable IDs remain bound to the selected lens and unique within the result.
- Candidate-causal changed-line verification remains fail-closed.
- Out-of-manifest locations, proof references, and evidence remain rejected.
- No adapter synthesizes hashes, strips evidence, or rewrites semantic findings to bypass native admission.
Related Issues
Pre-flight Checklist
Bug Description
Native reviewer capture accepts
facadeFinding.idas optional (json:"id,omitempty"), but candidate-causal admission requires repository-derived finding IDs before canonical lens-result processing assigns deterministic IDs to omitted values.For a valid candidate-causal finding that omits
id, the native pipeline can derive an empty candidate-causal ID from the decoded provider result, then canonicalize the same finding toR1-001,R2-001,R3-001, orR4-001.AdmitArtifactcompares the pre-canonical verified ID set with the post-canonical expected ID set and rejects the result as out of scope:The public decoder therefore permits a shape that native semantic admission cannot successfully process for candidate-causal findings.
This is distinct from intended proof-scope validation.
AdmitArtifactcorrectly rejectsproof_refsthat cite repository paths outside the frozenchanged_path_manifest; callers should keep candidate proof inside the frozen candidate rather than weaken that check.Steps to Reproduce
CRITICALfinding whose location and proof reference point to the changed candidate line.id; keepevidence_class: "deterministic"andcausal_disposition: "introduced".gentle-ai review capture-result.facadeFinding.IDis optional, canonicalization assigns a deterministic lens ID, but candidate-causal ID verification no longer matches and admission rejects the result.Expected Behavior
The native boundary should have one coherent ownership rule for finding IDs:
Missing IDs must not be silently accepted by the schema and then rejected only because canonicalization occurs after causal verification.
Actual Behavior
facadeFinding.IDusesomitempty,canonicalLensResultdeterministically supplies a missing ID, andAdmitArtifactcompares candidate-causal IDs against the canonicalized result. A schema-valid reviewer payload is therefore unreplayable even though its location and proof are fully inside the frozen candidate.Environment
1.49.1-0.20260722122850-8881b60b01c7Source Evidence
internal/cli/review_facade.go:facadeFinding.ID string json:"id,omitempty".internal/reviewtransaction/transaction.go:canonicalLensResultassigns<lens-prefix>-<index>whenfinding.ID == "".internal/cli/review_artifact.go: repository-derivedCandidateCausalFindingIDsare passed into admission.internal/reviewtransaction/artifact_admission.go: admission canonicalizes the lens result, derives candidate-causal IDs from canonical findings, and compares them with the previously verified IDs.Acceptance Criteria
idand proves the chosen ownership rule deterministically.idis required.Related Issues