rtk-ai/rtk · warning
version notes must stay prose
Error message
version notes must stay prose
What it means
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.
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.
Example fix
// before
let out = condense_unified_diff_strict(¬es).expect("version notes must stay prose");
// after
let out = condense_unified_diff_strict(¬es)
.unwrap_or_else(|e| panic!("version notes must stay prose: {e}")); Defensive patterns
Strategy: validation
Validate before calling
// guard: version-note bullets must appear before the diffstat line
assert!(notes.contains("---\nChanges in v2:") && notes.contains(" y.txt | 2 +-")); Try / catch
let out = condense_unified_diff_strict(¬es)
.unwrap_or_else(|e| panic!("version notes must stay prose: {e}")); Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- a bodyless region of prose must not force raw
- a table in the message must not force raw
- f.txt entry
- intact series must parse
- fixture listed in CORPUS
AI-assisted analysis of rtk-ai/rtk@0924356b4c (2026-09-19).
Data as JSON: /api/errors/7348e9c44e725709.
Report an issue: GitHub.
Appendix: source
Thrown at src/cmds/git/diff_cmd.rs:6905
);
// The intact series (with the block restored) still parses, bullets
// and separators included, and the signature is not counted.
let intact = series.replace(
"\n-p\n+q\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",
);
let out = condense_unified_diff_strict(&intact).expect("intact series must parse");
assert!(out.contains("[file] y.txt (+1 -1)"), "got:\n{out}");
assert!(!out.contains("bullet"), "got:\n{out}");
// Version notes between `---` and the diffstat (the kernel / b4
// convention) are column-0 bullets past the separator; they must
// stay prose, which is why the tolerance ends at the diffstat and
// not at `---`.
let notes = intact.replace(
"---\n y.txt | 2 +-",
"---\nChanges in v2:\n- rebased\n- dropped the hack\n\n y.txt | 2 +-",
);
let out = condense_unified_diff_strict(¬es).expect("version notes must stay prose");
assert!(out.contains("[file] y.txt (+1 -1)"), "got:\n{out}");
assert!(!out.contains("rebased"), "got:\n{out}");
}
#[test]
fn a_prose_table_is_not_a_diffstat() {
// A markdown table in the commit message is space-indented and holds
// a ` | `, but it is prose: the bullet after it must stay prose too,
// not read as a marked line past the diffstat.
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";
let out = condense_unified_diff_strict(&base.replace("STAT", " x.txt | 2 +-"))
.expect("a table in the message must not force raw");
assert!(out.contains("[file] x.txt (+1 -1)"), "got:\n{out}");
assert!(!out.contains("bullet"), "got:\n{out}");
// Every diffstat shape format-patch emits still ends the tolerance,
// so a marked line after one is still lost content. The bare count
// covers a pure rename or mode change, which stats as `0`.View on GitHub (pinned to 0924356b4c)