{"record":{"id":"2c384bff1b46b09f","repo":"Hmbown/CodeWhale","slug":"review-receipt-does-not-cover-every-planned-pr-pass","errorCode":null,"errorMessage":"Review receipt does not cover every planned PR pass","messagePattern":"Review receipt does not cover every planned PR pass","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/tools/review.rs","lineNumber":1086,"sourceCode":"        unresolved_risk: ReviewReceiptRisk {\n            unresolved,\n            level: risk_level,\n            summary: risk_summary,\n        },\n        review_content_sha256: sha256_hex(review_content.as_bytes()),\n        coverage: None,\n    }\n}\n\npub(crate) fn attach_pr_review_coverage(\n    receipt: &mut ReviewReceipt,\n    coverage: ReviewReceiptCoverage,\n) -> anyhow::Result<()> {\n    anyhow::ensure!(\n        receipt.diff_fingerprint == coverage.manifest.diff_fingerprint,\n        \"Review receipt and PR coverage manifest fingerprints differ\"\n    );\n    anyhow::ensure!(\n        coverage.completed_passes.len() == coverage.manifest.passes.len()\n            && coverage\n                .completed_passes\n                .iter()\n                .enumerate()\n                .all(|(index, pass)| pass.number == index + 1),\n        \"Review receipt does not cover every planned PR pass\"\n    );\n    receipt.schema_version = PR_COVERAGE_RECEIPT_SCHEMA_VERSION;\n    receipt.coverage = Some(coverage);\n    Ok(())\n}\n\npub fn write_review_receipt(\n    receipt: &ReviewReceipt,\n    path_override: Option<&Path>,\n) -> anyhow::Result<PathBuf> {\n    let path = if let Some(path) = path_override {","sourceCodeStart":1068,"sourceCodeEnd":1104,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tools/review.rs#L1068-L1104","documentation":"`attach_pr_review_coverage` also ensures the coverage records every planned pass, with sequential numbering (pass at index i has number i+1). If any planned pass is missing from `completed_passes` or the numbering is off, the receipt would claim full coverage it does not have, so attaching is refused.","triggerScenarios":"Calling `attach_pr_review_coverage` when `completed_passes.len() != manifest.passes.len()`, or a completed pass's `number` does not equal its 1-based index (gaps, duplicates, or out-of-order pass records).","commonSituations":"A pass failed and was dropped from `completed_passes` instead of the whole review being rejected; pass records were collected concurrently and sorted/appended in the wrong order; a refactor changed pass numbering from 1-based to 0-based.","solutions":["Complete all planned passes and record them in order (number == index + 1) before attaching coverage","Sort/renumber `completed_passes` to match the manifest order if they were collected out of order","Reject the review run if any pass is missing rather than attaching partial coverage"],"exampleFix":"// before\ncompleted_passes.sort_by_key(|p| p.number);\nattach_pr_review_coverage(&mut receipt, coverage)?;\n// after\ncompleted_passes.sort_by_key(|p| p.number);\nanyhow::ensure!(completed_passes.iter().enumerate().all(|(i, p)| p.number == i + 1));\nattach_pr_review_coverage(&mut receipt, coverage)?;","handlingStrategy":"validation","validationCode":"let ok = coverage.completed_passes.len() == coverage.manifest.passes.len() && coverage.completed_passes.iter().enumerate().all(|(i, p)| p.number == i + 1); if !ok { return Err(anyhow!(\"coverage missing or misnumbered passes\")); }","typeGuard":null,"tryCatchPattern":"match attach_pr_review_coverage(&mut receipt, coverage) { Err(e) if e.to_string().contains(\"every planned PR pass\") => rerun_missing_passes_then_attach(), Err(e) => return Err(e), Ok(()) => {} }","preventionTips":["Record completed passes in manifest order as they finish","Keep pass numbering 1-based and derived from the manifest index","Fail the whole review when a pass fails instead of dropping it from coverage"],"tags":["review","coverage","invariant-violation","passes"],"backgroundTag":"internal-invariant-violation","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}