{"record":{"id":"7348e9c44e725709","repo":"rtk-ai/rtk","slug":"version-notes-must-stay-prose","errorCode":null,"errorMessage":"version notes must stay prose","messagePattern":"version notes must stay prose","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/cmds/git/diff_cmd.rs","lineNumber":6905,"sourceCode":"        );\n        // The intact series (with the block restored) still parses, bullets\n        // and separators included, and the signature is not counted.\n        let intact = series.replace(\n            \"\\n-p\\n+q\\n\",\n            \"\\ndiff --git a/y.txt b/y.txt\\n--- a/y.txt\\n+++ b/y.txt\\n@@ -1 +1 @@\\n-p\\n+q\\n\",\n        );\n        let out = condense_unified_diff_strict(&intact).expect(\"intact series must parse\");\n        assert!(out.contains(\"[file] y.txt (+1 -1)\"), \"got:\\n{out}\");\n        assert!(!out.contains(\"bullet\"), \"got:\\n{out}\");\n        // Version notes between `---` and the diffstat (the kernel / b4\n        // convention) are column-0 bullets past the separator; they must\n        // stay prose, which is why the tolerance ends at the diffstat and\n        // not at `---`.\n        let notes = intact.replace(\n            \"---\\n y.txt | 2 +-\",\n            \"---\\nChanges in v2:\\n- rebased\\n- dropped the hack\\n\\n y.txt | 2 +-\",\n        );\n        let out = condense_unified_diff_strict(&notes).expect(\"version notes must stay prose\");\n        assert!(out.contains(\"[file] y.txt (+1 -1)\"), \"got:\\n{out}\");\n        assert!(!out.contains(\"rebased\"), \"got:\\n{out}\");\n    }\n\n    #[test]\n    fn a_prose_table_is_not_a_diffstat() {\n        // A markdown table in the commit message is space-indented and holds\n        // a ` | `, but it is prose: the bullet after it must stay prose too,\n        // not read as a marked line past the diffstat.\n        let base = \"From fe6a6d0d8316535b5ac232f5d7cc6d227b187b9e Mon Sep 17 00:00:00 2001\\nSubject: [PATCH] one\\n\\n col | val\\n --- | ---\\n row | text\\n- a bullet after the table\\n---\\nSTAT\\n 1 file changed, 1 insertion(+), 1 deletion(-)\\n\\ndiff --git a/x.txt b/x.txt\\n--- a/x.txt\\n+++ b/x.txt\\n@@ -1 +1 @@\\n-a\\n+b\\n-- \\n2.54.0\\n\";\n        let out = condense_unified_diff_strict(&base.replace(\"STAT\", \" x.txt | 2 +-\"))\n            .expect(\"a table in the message must not force raw\");\n        assert!(out.contains(\"[file] x.txt (+1 -1)\"), \"got:\\n{out}\");\n        assert!(!out.contains(\"bullet\"), \"got:\\n{out}\");\n\n        // Every diffstat shape format-patch emits still ends the tolerance,\n        // so a marked line after one is still lost content. The bare count\n        // covers a pure rename or mode change, which stats as `0`.","sourceCodeStart":6887,"sourceCodeEnd":6923,"githubUrl":"https://github.com/rtk-ai/rtk/blob/0924356b4caba4989607227b7c8824d3d8098719/src/cmds/git/diff_cmd.rs#L6887-L6923","documentation":"Test panic from `.expect(\"version notes must stay prose\")`: `condense_unified_diff_strict` failed (or its output lost the file entry / leaked prose) on a format-patch whose commit message contains kernel-style version notes (`Changes in v2:` plus `- ` bullets) placed between the `---` separator and the diffstat. The contract is that these column-0 bullets remain prose and do not reset the bullet tolerance, so parsing must still succeed and `rebased` must be dropped with the rest of the prose.","triggerScenarios":"Passing a patch series where `---` is followed by `Changes in v2:` / `- rebased` / `- dropped the hack` before the ` y.txt | 2 +-` diffstat — any code path that counts those bullets as marked lines past the separator breaks the parse or leaks the text.","commonSituations":"Real git format-patch output from kernel/b4 workflows routinely carries version-change notes in exactly this position; changes to the strict parser's bullet-tolerance window break these inputs.","solutions":["Inspect the parser error by unwrapping with the message included, then check where tolerance for column-0 bullets ends (should be at the diffstat, not at `---`).","Ensure prose detected between `---` and the diffstat is dropped from output rather than re-emitted or forcing a raw fallback.","Add the failing series shape as a fixture so the b4 convention stays covered."],"exampleFix":"// before\nlet out = condense_unified_diff_strict(&notes).expect(\"version notes must stay prose\");\n// after\nlet out = condense_unified_diff_strict(&notes)\n    .unwrap_or_else(|e| panic!(\"version notes must stay prose: {e}\"));","handlingStrategy":"validation","validationCode":"// guard: version-note bullets must appear before the diffstat line\nassert!(notes.contains(\"---\\nChanges in v2:\") && notes.contains(\" y.txt | 2 +-\"));","typeGuard":null,"tryCatchPattern":"let out = condense_unified_diff_strict(&notes)\n    .unwrap_or_else(|e| panic!(\"version notes must stay prose: {e}\"));","preventionTips":["Pin the b4/kernel convention as a dedicated fixture","Unit-test the bullet-tolerance boundary separately from end-to-end parsing","Never treat column-0 bullets between --- and the diffstat as marked lines"],"tags":["rust","test-assertion","git-format-patch"],"backgroundTag":"internal-invariant-violation","analyzedSha":"0924356b4caba4989607227b7c8824d3d8098719","analyzedAt":"2026-09-19T19:25:29.612Z","contentChangedAt":"2026-09-19T19:25:29.612Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}