From a9544fa9594de7087c90d335b84047bcbca14134 Mon Sep 17 00:00:00 2001 From: Levi Neuwirth Date: Sun, 9 Aug 2026 22:34:19 +0200 Subject: [PATCH] docs: narrow the copy-detection claim to the fixture it was measured on The lane asserted that real git emits no 2 C record even under status.renames=copies, and a test MEASURED it. The measurement was real; the proposition drawn from it was too broad. git-status(1) documents C as "copied (if config option status.renames is set to copies)", so git does emit it. What the fixture establishes is narrower: with ITS copy source left unchanged, git reports 1 A. and emits no 2 C record. That is a fact about the fixture. It is still sufficient reason to craft the row through _deliver_status --- a weaker and true justification replacing a stronger false one --- so no behaviour changes and no test changes. The score-based runtime fix was never in question. Six sites narrowed, not the two that review cited: the framing bullet, the ledger bullet, the g6_4b doc comment, the premise comment, the assertion message, and the rename_and_copy_repo fixture doc. Each also records the retraction, so the old claim cannot be reconstructed from a stale copy that outlived the correction. What is deliberately NOT claimed anywhere: WHY an unchanged source is not offered as a copy candidate. There is a plausible mechanism and it was never established, and replacing one overreach with a smaller one is how this class of error survives. The root cause is worth recording: this claim entered the lane as a dispatch instruction stated as settled fact, and the implementing agent did exactly what it was asked --- measured one fixture. A measurement cannot be broader than its fixture, however carefully it is run. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai --- docs/active-work.md | 17 +++++--- docs/git-integration-framing.md | 20 ++++++--- tests/git_status_stage1_acceptance.rs | 60 ++++++++++++++++++--------- 3 files changed, 67 insertions(+), 30 deletions(-) diff --git a/docs/active-work.md b/docs/active-work.md index bdb398e..7362ab0 100644 --- a/docs/active-work.md +++ b/docs/active-work.md @@ -566,11 +566,18 @@ Linux stayed green. wider surface for no new fact. `g6_4b` asserts both prefixes, so the claim is checked rather than asserted here. -- **Parser-level coverage, stated plainly rather than implied.** Real - `git` emits no `2 C` record — the test MEASURES that, under - `-c status.renames=copies`, rather than recalling it — so the copy - ROW is supplied through `_deliver_status`, the seam `g6_2b`/`g6_17`/ - `g6_21` already use. Everything downstream is real: repository, +- **Parser-level coverage, stated plainly rather than implied.** The + copy ROW is supplied through `_deliver_status`, the seam + `g6_2b`/`g6_17`/`g6_21` already use. + + **Scope corrected in review round 5.** This entry claimed real `git` + emits no `2 C` record at all, measured under + `-c status.renames=copies`. **The measurement was real; the claim + drawn from it was too broad.** `git-status(1)` documents `C` as + "copied (if config option status.renames is set to `copies`)", so + git does emit it. What the test establishes is that **this fixture** + — whose copy source is unchanged — yields `1 A.`. That is enough to + justify crafting the row and nothing more. Everything downstream is real: repository, panel, `d` dispatch, spawned `git diff`, rendered buffer. Both crafted rows name paths that exist in the fixture, so each drives a real two-path diff. diff --git a/docs/git-integration-framing.md b/docs/git-integration-framing.md index b9c4d15..95c8e03 100644 --- a/docs/git-integration-framing.md +++ b/docs/git-integration-framing.md @@ -608,11 +608,21 @@ So, stated plainly rather than dressed up: `R.` against `C.`. Both classes are asserted, and so is the **argv**: the two-path `git diff HEAD -- ` is right for a copy and a rename alike, so a fix to what the user is *told* must not - reach what runs. **Parser-level, deliberately** — see the corpus - bullet above: real `git` emits no `2 C` record even under - `status.renames=copies`, so the copy ROW is supplied through - `_deliver_status` while the repository, the panel, the `d` dispatch - and the spawned diff around it are real. + reach what runs. **Parser-level, deliberately** — the copy ROW is + supplied through `_deliver_status` while the repository, the panel, + the `d` dispatch and the spawned diff around it are real. + + **The reason, narrowed after review.** This bullet used to say real + `git` emits no `2 C` record "even under `status.renames=copies`". + **That is too strong, and git's own documentation contradicts it** — + `git-status(1)` lists `C` as *"copied (if config option + status.renames is set to `copies`)"*. What the test measures is + narrower: **for its fixture, whose copy source is left unchanged**, + git reports `1 A.`. That is a fact about the fixture, and it is + sufficient reason to craft the row — a weaker and true justification + in place of a stronger false one. No mechanism is claimed for why an + unchanged source is not offered as a candidate; that was never + established. - **The untracked diff renders on exit 1**, not a failure row (Q#G-7a) — the case `--exit-code` semantics would otherwise break, and the one most likely to be "fixed" later by someone who reads exit 1 as an diff --git a/tests/git_status_stage1_acceptance.rs b/tests/git_status_stage1_acceptance.rs index 6a66706..f3e71ca 100644 --- a/tests/git_status_stage1_acceptance.rs +++ b/tests/git_status_stage1_acceptance.rs @@ -205,10 +205,11 @@ fn mixed_repo(root: &Path) { /// staged `copy_dst.txt`. /// /// Both are real on disk, and that is what the copy fixture is FOR: -/// real `git` classifies the copy as an ordinary `1 A.` add (see -/// `g6_4b`), so the `2 C.` row has to be supplied — but because both of -/// its paths exist here, the two-path diff that row drives is a real -/// invocation rendering a real patch. +/// **with this fixture's source left unchanged**, git classifies the +/// copy as an ordinary `1 A.` add (measured in `g6_4b`; not a claim +/// about git in general), so the `2 C.` row has to be supplied — but +/// because both of its paths exist here, the two-path diff that row +/// drives is a real invocation rendering a real patch. fn rename_and_copy_repo(root: &Path) { init_repo(root); write(root, "Cargo.toml", "[package]\nname = \"fixture\"\n"); @@ -943,16 +944,28 @@ fn refocus_panel(s: &mut EditorState) { /// A **copy** row's diff header says *copied*, a **rename** row's says /// *renamed*, and both run the SAME two-path invocation. /// -/// **This is a parser/presentation test, not end-to-end copy coverage, -/// and no test here could be.** Porcelain v2 folds renames and copies -/// into one `2` record whose `` field leads with `R` or `C`, but -/// real `git` will not emit a `2 C` record for a plain copy — not even -/// under `status.renames=copies`, which the premise below MEASURES -/// rather than recalls. The framing scopes "copied" to the parser level -/// for exactly that reason (§6's witness corpus), so the copy ROW is -/// supplied as payload bytes through `_deliver_status` — the seam -/// `g6_2b`, `g6_17` and `g6_21` already use for rows no fixture can -/// produce. +/// **This is a parser/presentation test, not end-to-end copy coverage.** +/// Porcelain v2 folds renames and copies into one `2` record whose +/// `` field leads with `R` or `C`. +/// +/// **Scope of the premise, narrowed after review.** An earlier version +/// of this comment said real `git` "will not emit a `2 C` record — not +/// even under `status.renames=copies`". **That is too strong and git's +/// own documentation contradicts it**: `git-status(1)` lists `C` as +/// "copied (if config option status.renames is set to `copies`)". +/// +/// What the premise below actually MEASURES is narrower and is all it +/// claims: **for THIS fixture — a copy whose source is left unchanged — +/// git reports `1 A.` and emits no `2 C` record**, under +/// `-c status.renames=copies`. It is measured rather than recalled, but +/// it is a fact about this fixture, not about `git` in general. No +/// mechanism is asserted here for *why* an unchanged source is not +/// offered as a copy candidate; that was not established. +/// +/// So the copy ROW is supplied as payload bytes through +/// `_deliver_status` — the seam `g6_2b`, `g6_17` and `g6_21` already use +/// — because this fixture cannot produce one, which is a weaker and +/// true reason than the one first given. /// /// Everything downstream of the row is real: the repository, the panel, /// the `d` dispatch, the spawned `git diff`, and the rendered buffer. @@ -973,10 +986,15 @@ fn g6_4b_a_copy_says_copied_and_a_rename_says_renamed() { let mut s = editor(); open_panel(&mut s, &root, "copy_src.txt"); - // The premise, measured: even asked for copy detection explicitly, - // real `git` reports the copy as `1 A.` and emits no `2 C` record. - // Pinned here so a future reader can see WHY the row below is - // crafted, instead of taking it on trust. + // The premise, measured — and note what it does and does not say. + // For THIS fixture, whose copy source is left unchanged, git reports + // `1 A.` and emits no `2 C` record even when asked for copy + // detection explicitly. That is a fact about this fixture. `git` + // DOES emit `C` in general — `git-status(1)` documents it as + // "copied (if config option status.renames is set to `copies`)" — + // so this assertion must not be read as proving otherwise. + // Pinned so a future reader can see WHY the row below is crafted, + // instead of taking it on trust. let raw = git( &root, &[ @@ -991,8 +1009,10 @@ fn g6_4b_a_copy_says_copied_and_a_rename_says_renamed() { ); assert!( !raw.contains("2 C"), - "fixture premise: real git emits no `2 C` record for a plain copy, \ - even under status.renames=copies; it emitted:\n{raw:?}" + "fixture premise: for THIS fixture (copy source unchanged), git \ + emits no `2 C` record even under status.renames=copies. This is \ + a claim about the fixture, not about git in general — git does \ + document `C` as copied under that setting. It emitted:\n{raw:?}" ); assert!( panel_text(&s).contains("A. copy_dst.txt"),