Skip to main content

Module silent_revert

Module silent_revert 

Source
Expand description

Falsification (c): how often does a landed merge remove work that neither side removed?

crate::safety::check answers that question for one merge. This module points it at a repository’s real merge history so the question can be answered with a number instead of an argument. The plan it serves, its kill criterion and the reasoning behind both live outside the repository; what matters here is that the criterion was fixed before the number was known, so a near-zero result is an answer and not a prompt to re-cut the measurement.

§What is compared, and to what

For a merge commit M with first parent T (the target branch, the side that was being merged onto) and second parent P (the proposal), with B = merge-base(T, P):

base     = B:<path>      what the author wrote against
target   = T:<path>      the state being merged onto
proposed = P:<path>      what the author wrote
result   = M:<path>      what actually landed

which is exactly crate::safety::check’s signature. A path missing from a tree reads as empty, so an added file compares as an addition and a deleted file as a removal, both of which the bag comparison already handles.

Only paths where M differs from T are examined. A path the merge left identical to the target has an empty landing delta and therefore always upholds, so scanning it would cost four blob reads to learn nothing.

§What a finding is worth, stated before any are counted

A violation here is evidence of a silent revert, not proof of a defect, and the honest reading is bounded on both sides:

  • False positives are expected and are the dominant noise. A merge whose conflicts a human resolved by hand is free to remove lines neither parent removed, and that is a correct resolution, not a silent revert. Automatic merges — a merge queue’s, --no-ff on a clean tree — are where a finding means what it says. The report keeps the two apart only as far as git lets it, which is not far; any non-zero count wants eyes on the individual findings before it is quoted at anybody.
  • False negatives dominate the other direction. The comparison is over line bags, so a merge that moves a line, or applies an edit at the wrong occurrence of a repeated line, is bag-neutral and passes. That is crate::safety’s stated positional blindness, inherited here whole.

So the count is a lower bound on a noisy signal. It is worth having anyway, for the same reason choir-queue’s corpus module is: it needs nothing but git — no CI history, no issue tracker, no human labelling — and an unmeasured rate cannot be argued with at all.

§Shape

Same split as choir-queue::corpus: parsing and scanning are pure functions over text, and every shell-out is a separate call, so the tests are hermetic and the expensive part is the caller’s problem.

§Examples

use choir_merge::silent_revert::{scan_merge, Blobs, ScanReport};

// The target added a line after the fork; the proposal touched a
// different one; the landed result dropped the target's line.
let blobs = Blobs {
    base: "a\n".into(),
    target: "a\nkeep\n".into(),
    proposed: "a\nb\n".into(),
    result: "a\nb\n".into(),
};
let mut report = ScanReport::default();
scan_merge("deadbeef", &[("src/x.rs".to_string(), blobs)], &mut report);

assert_eq!(report.findings.len(), 1);
assert_eq!(report.findings[0].reverted, vec!["keep".to_string()]);

Structs§

Blobs
The four texts crate::safety::check compares, for one path.
Finding
One path in one merge that removed or added lines neither side did.
MergeCommit
One merge commit, reduced to what the scan needs.
ScanReport
What one repository’s scan counted.

Constants§

MAX_BLOB_BYTES
Blobs larger than this are skipped rather than compared.
MERGE_LOG_FORMAT
The --format string parse_merges expects.

Functions§

changed_paths
Paths where to differs from from.
merge_base
git merge-base a b, or None when they share none.
merge_log
The merge commits on repo’s first-parent mainline, newest first.
parse_batch
Splits cat-file --batch output into count positional results.
parse_merges
Parses git log --merges MERGE_LOG_FORMAT output.
scan_merge
Applies the safety check to every path of one merge, counting into report.
scan_repo
Scans one repository’s merge history.