{"record":{"id":"88bd1679b2481c59","repo":"rtk-ai/rtk","slug":"hg-export-must-parse","errorCode":null,"errorMessage":"hg export must parse","messagePattern":"hg export must parse","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmds/git/diff_cmd.rs","lineNumber":6735,"sourceCode":"            );\n            assert_eq!(\n                condense_unified_diff(fixture),\n                fixture,\n                \"{name}: not byte-exact\"\n            );\n        }\n    }\n\n    #[test]\n    fn hg_export_condenses_despite_its_prologue_and_diff_echo() {\n        // Real `hg export tip` (Mercurial 7.0.1): `# …` headers and the\n        // message at column 0, then a `diff -r <a> -r <b> <file>` echo before\n        // each header pair. The prose used to latch `dropped_prologue`, and\n        // the echo then turned it into a whole-stream raw fallback: 0%\n        // savings for a whole producer. The changeset header now opens a\n        // message region, like an mbox `From`.\n        let fixture = include_str!(\"../../../tests/fixtures/diff/hg_export_raw.txt\");\n        let out = condense_unified_diff_strict(fixture).expect(\"hg export must parse\");\n        assert!(out.contains(\"[file] f.txt (+1 -1)\"), \"got:\\n{out}\");\n        assert!(out.contains(\"[file] g.txt (+1 -0)\"), \"got:\\n{out}\");\n        assert!(!out.contains(\"bullet\"), \"message prose leaked:\\n{out}\");\n        // The message region ends at the first file header; the second\n        // echo arrives outside it and still marks the `diff -r` context, so\n        // an unread column-0 line after it forces raw as in any GNU stream.\n        let with_fact = format!(\"{fixture}Seulement dans b: h.txt\\n\");\n        assert!(condense_unified_diff_strict(&with_fact).is_none());\n    }\n\n    #[test]\n    fn no_newline_marker_stays_attached_to_the_line_it_describes() {\n        // Real `git diff` of two files: `f.txt` changes its first line while\n        // its unchanged last line lacks a newline (marker after a context\n        // line), and `g.txt` gains a trailing newline (marker after `-y`).\n        // The first marker used to land under `+A` and claim the ADDED line\n        // had no newline; it must be dropped. The second is the witness of\n        // a newline-only change and must stay right under `-y`.","sourceCodeStart":6717,"sourceCodeEnd":6753,"githubUrl":"https://github.com/rtk-ai/rtk/blob/0924356b4caba4989607227b7c8824d3d8098719/src/cmds/git/diff_cmd.rs#L6717-L6753","documentation":"`.expect(\"hg export must parse\")` panic: `condense_unified_diff_strict()` returned None on an `hg export` fixture. `hg export` emits a changeset header, a column-0 commit message, then a `diff -r <a> -r <b> <file>` echo before each header pair; the prose used to latch `dropped_prologue` and the echo forced a whole-stream raw fallback (0% savings for all `hg export` output). The fix under test: the changeset header opens a message region like an mbox `From`.","triggerScenarios":"Calling `condense_unified_diff_strict()` on tests/fixtures/diff/hg_export_raw.txt returns None, or returns output missing `[file] f.txt (+1 -1)` / `[file] g.txt (+1 -0)`, or leaking message prose (`bullet`).","commonSituations":"Running `rtk hg export`; changes to the message-region state machine shared with mbox handling; regressions where the second `diff -r` echo (outside the message region) re-triggers raw fallback on a later column-0 line.","solutions":["Re-apply/verify the rule: an `hg export` changeset header (`# HG changeset patch`) opens a message region that ends at the first file header.","Treat `diff -r ... <file>` echo lines as context markers, not unread noise, when they appear before a header pair.","Ensure after the first file header the second echo still marks `diff -r` context so genuinely unread column-0 lines later force raw (per the test's follow-up).","Regenerate the fixture if hg's export format changed in the recorded version."],"exampleFix":"// before\nif line.starts_with(\"diff -r \") { dropped_prologue = true; } // whole-stream raw\n// after\nif line.starts_with(\"# HG changeset patch\") { open_message_region(); }\nif line.starts_with(\"diff -r \") { mark_diff_context(); }","handlingStrategy":"validation","validationCode":"let out = condense_unified_diff_strict(&hg_export_fixture);\nassert!(out.as_deref().map_or(false, |o| o.contains(\"[file] f.txt (+1 -1)\") && o.contains(\"[file] g.txt (+1 -0)\") && !o.contains(\"bullet\")));","typeGuard":"fn parses_cleanly(diff: &str) -> bool {\n    crate::cmds::git::diff_cmd::condense_unified_diff_strict(diff)\n        .map_or(false, |o| !o.is_empty())\n}","tryCatchPattern":"let out = condense_unified_diff_strict(hg_export_output)\n    .unwrap_or_else(|| hg_export_output.to_string());","preventionTips":["Model producer prologues (mbox From, hg changeset) with one shared message-region mechanism; do not special-case per flag.","Treat producer echo lines (`diff -r ...`) as context, never as fatal unread noise.","Verify savings do not drop to 0% for a whole producer: 0% is the symptom of an over-eager raw fallback.","Add one fixture per producer echo format (hg export, hg log -p, format-patch)."],"tags":["rust","test-failure","diff-parsing","mercurial"],"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"}