Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/edda

crates/storage-git-gix/parked-gix-2/gunnar-wire-gix/tests/pack_copy.rs

//! `P-001` on the serve path: the pack is copied, not re-deflated.
//!
//! # Why none of these assertions is "the clone succeeded"
//!
//! Both emitters produce a correct, complete, stock-git-readable pack of the
//! same objects. A test that cloned and checked the result would pass against
//! the re-deflating writer this replaces, which is exactly how gunnar came to
//! ship an 18.34× bandwidth gap against `git 2.53.0` with a green suite. So
//! what is asserted here is **applied output**:
//!
//! * `objects_copied_from_pack` against `objects_recompressed`, which the serve
//!   path now reports for the same reason `RepackOutcome` does: a byte count
//!   and a wall clock cannot tell a pack-copy from a re-deflate,
//! * the **bytes**, against the whole-object pack of the *same object set*,
//!   produced by the same code path on the same fixture,
//! * `git verify-pack`'s own count of resolved delta chains, which is stock
//!   git's opinion rather than gunnar's of whether a delta reached the wire,
//! * `git index-pack --strict`, which is what git itself runs on a pack it is
//!   handed, so the delta chains are resolved and every object id re-derived by
//!   the other implementation.
//!
//! # The identity-value trap, and how the fixture avoids it
//!
//! A fixture of unique random blobs deltas to nothing, so a working pack-copy
//! would look broken and a broken one would look fine (`P-001`, `S-003`, and
//! the head-to-head in `stinky.md` `S-044`, whose own note says the eleven
//! gunnar-against-gunnar arms flatter gunnar for exactly this reason). The
//! fixture here is **churn**: one file rewritten a couple of lines at a time
//! across many commits, which is what a real repository looks like and what
//! git's delta encoder is for.
//!
//! # And why stock `git` builds it
//!
//! gitoxide has **no delta encoder at all** (`P-009`), so gunnar cannot make
//! the deltas this reuses and neither can its own repack. They come from the
//! pushing client, and the pushing client is stock git. A fixture packed by
//! gunnar would contain no deltas to copy and every assertion below would be
//! vacuous.

use std::path::{Path, PathBuf};
use std::process::Command;

use gix_hash::{Kind, ObjectId};
use gunnar_store::fs::FsStore;
use gunnar_store::{NoPackCopy, ObjectStore, MULTI_PACK_INDEX_THRESHOLD};
use gunnar_wire::upload_pack::FetchRequest;
use gunnar_wire::UploadPack;

mod common;

use common::{index_and_count, Fixture, Response};

// ── the fixture ─────────────────────────────────────────────────────────────

/// How many commits of churn. Small enough that the whole fixture is a few
/// megabytes and the test runs in about a second, large enough that git's
/// delta window (10 by default) has something to find.
const COMMITS: usize = 48;

/// Lines in the churned file. 400 × ~48 bytes ≈ 19 KiB per revision, so the
/// whole fixture is bounded at roughly `COMMITS × 19 KiB` ≈ 900 KiB of raw
/// blob content, deliberately capped: a degenerate size crossed with a large
/// input is how a test in this tree took a 499 GB box down.
const LINES: usize = 400;

/// How many files each commit rewrites in [`Churn::build_with`]. Three of
/// sixty means any given file is revisited about every twenty commits, so a
/// fetch of the last eight sees new revisions of files whose previous
/// revision is well behind the cut.
const TOUCHED_PER_COMMIT: usize = 3;

/// Files in the `S-003` fixture. See [`Churn::build_with`].
const WIDE_FILES: usize = 60;

/// Pushes in the multi-pack fixture, and therefore packs in it. See
/// [`Churn::build_pushed`].
///
/// **Twelve, and it is a floor rather than a preference.** The defect this
/// fixture exists for needs one object to be stored *twice* — whole in the pack
/// whose push introduced its dependant, and as a delta in the pack whose push
/// introduced it — which is what `index-pack --fix-thin` leaves behind when two
/// pushes overlap. MEASURED on this fixture, oden 2026-08-05, `gitoxide`'s
/// verdict on the pack served for a `HEAD~8` cut:
///
/// ```text
///   packs      2    3    6    12   24
///   verdict   ok   ok   ok  FAIL  FAIL
/// ```
///
/// At six packs the cut has to move to `HEAD~12` before it fires. Twelve is the
/// smallest round count that fires at the same `HEAD~8` cut every other arm in
/// this file uses, so the arms differ in the fixture's *layout* and in nothing
/// else.
const PUSH_ROUNDS: usize = 12;

/// A bare repository whose pack **stock git** built, with real delta chains in
/// it.
struct Churn {
    _dir: tempfile::TempDir,
    root: PathBuf,
    origin: PathBuf,
    /// A `Cell`, because [`Churn::push_more`] moves the origin's `HEAD` after
    /// construction and every arm that wants the tip must see the move. A plain
    /// field would leave a post-gc fixture serving the pre-gc tip, which is a
    /// clone of the wrong history that passes every count.
    head: std::cell::Cell<ObjectId>,
}

/// How the bare fixture repository is assembled. See [`Churn::build_pushed`].
#[derive(Clone, Copy)]
enum Layout {
    /// One `git repack -adf` pack, which is a repository somebody has `gc`'d.
    OnePack,
    /// One pack per push and no repack, which is every repository that has been
    /// pushed to since its last `gc`.
    PushedRounds(usize),
    /// The first `rounds` of `of` history slices, and no more: a repository
    /// that is mid-way through being filled, so a caller can fold it and
    /// measure the **same object set** before and after. See
    /// [`Churn::build_partial`].
    PushedRoundsOf { rounds: usize, of: usize },
}

impl Churn {
    fn build() -> Self {
        Self::build_with(1)
    }

    /// The same churn spread over `files` files, `TOUCHED_PER_COMMIT` of them
    /// rewritten per commit in rotation.
    ///
    /// `files == 1` is the original fixture and what every `P-001` arm below
    /// uses. A **wider** fixture is what `S-003` needs, and the difference is
    /// not cosmetic: with one file, blob *n* deltas against blob *n-1*, so a
    /// fetch of the last few commits carries almost every base it needs and
    /// the defect is invisible — MEASURED on this very fixture, 23 of 24
    /// objects copied. With sixty files touched three at a time, a file
    /// rewritten inside the fetch window was last written ~20 commits before
    /// it, which is on the far side of the negotiation cut. That is what a
    /// real repository looks like to a fetch, and it is the only shape in
    /// which this measures anything.
    fn build_with(files: usize) -> Self {
        Self::build_layout(files, Layout::OnePack)
    }

    /// The same churn, but the bare repository is built by **pushing** in
    /// `rounds` slices and is never repacked — so it ends with `rounds` packs
    /// and no `.bitmap`.
    ///
    /// That is not a variation for its own sake. It is the *only* shape in
    /// which two objects of one transfer can sit in different source packs,
    /// which is when `gix_pack`'s copier cannot re-point a delta at its base
    /// inside the pack it is writing and names it by object id instead. A
    /// single-pack fixture cannot produce that entry at all, which is why every
    /// arm above passed while `gunnar.year` was failing on it — and it is also
    /// the *production* shape, because a repository grows a pack per push and
    /// only `gc` collapses them.
    fn build_pushed(files: usize, rounds: usize) -> Self {
        Self::build_layout(files, Layout::PushedRounds(rounds))
    }

    /// The pushed fixture, stopped **before** the `gc`, so a caller can measure
    /// it, fold it with [`Churn::gunnar_gc`] and measure the same object set
    /// again.
    ///
    /// A before/after on one repository, rather than two fixtures compared: the
    /// commits carry real timestamps, so two builds have different object ids
    /// and git's delta window makes different choices, and a cross-fixture
    /// comparison of copy counts would be reading that noise as a result.
    fn build_partial(files: usize, rounds: usize, of: usize) -> Self {
        Self::build_layout(files, Layout::PushedRoundsOf { rounds, of })
    }

    /// Run gunnar's own `gc` over this fixture, in place.
    fn gunnar_gc(&self) -> gunnar_store::RepackOutcome {
        let store = gunnar_store::fs::FsStore::open_or_init(&self.origin, Kind::Sha1)
            .expect("open the fixture for gunnar's own gc");
        store
            .repack(&gunnar_store::RepackOptions::new())
            .expect("gunnar gc")
    }

    /// Push history slices `from+1..=to` of `of`, one pack each.
    fn push_more(&self, from: usize, to: usize, of: usize) {
        push_slices(&self.root.join("seed"), &self.origin, from, to, of);
        self.head_moved();
    }

    /// Re-read `HEAD` after the origin has been pushed to, and remember it.
    fn head_moved(&self) -> ObjectId {
        let head = ObjectId::from_hex(git(&self.origin, &["rev-parse", "HEAD"]).as_bytes())
            .expect("the head is an object id");
        self.head.set(head);
        head
    }

    fn build_layout(files: usize, layout: Layout) -> Self {
        let dir = tempfile::tempdir().expect("a temporary directory");
        let root = dir.path().to_path_buf();
        let work = root.join("seed");
        std::fs::create_dir_all(&work).expect("the work tree");

        git(&root, &["init", "-q", "-b", "main", work.to_str().unwrap()]);
        git(&work, &["config", "user.email", "bench@gunnar.invalid"]);
        git(&work, &["config", "user.name", "gunnar bench"]);

        let mut content: Vec<Vec<String>> = (0..files)
            .map(|f| {
                (0..LINES)
                    .map(|i| format!("line {i:04} of file {f:03}, original text"))
                    .collect()
            })
            .collect();
        for revision in 0..COMMITS {
            for slot in 0..TOUCHED_PER_COMMIT.min(files) {
                let f = (revision * TOUCHED_PER_COMMIT + slot) % files;
                // ~2% of the lines rewritten: a diff, not a rewrite. A whole
                // new file every commit would delta to nothing and make a
                // working encoder look broken.
                for step in 0..LINES / 50 {
                    let index = (revision * 7 + step * 53) % LINES;
                    content[f][index] = format!("line {index:04} rewritten at revision {revision}");
                }
                let name = if files == 1 {
                    "churn.txt".to_owned()
                } else {
                    format!("churn-{f:03}.txt")
                };
                std::fs::write(work.join(&name), content[f].join("\n")).expect("write the file");
                git(&work, &["add", &name]);
            }
            git(
                &work,
                &["commit", "-q", "-m", &format!("revision {revision}")],
            );
        }

        let origin = root.join("origin.git");
        match layout {
            Layout::OnePack => {
                git(
                    &root,
                    &[
                        "clone",
                        "-q",
                        "--bare",
                        work.to_str().unwrap(),
                        origin.to_str().unwrap(),
                    ],
                );
                // `-a -d -f`: one pack, no loose objects, and **recompute the
                // deltas from scratch** rather than reuse whatever the clone
                // happened to produce. This is the step that puts the delta
                // chains gunnar is about to copy into the fixture, so it is not
                // tidying.
                git(&origin, &["repack", "-adf", "-q"]);
            }
            Layout::PushedRounds(rounds) => {
                assert!(rounds >= 2, "one round is one pack, which is `OnePack`");
                init_pushed_origin(&root, &origin);
                push_slices(&work, &origin, 0, rounds, rounds);
                // Deliberately no `repack`, no `gc`, no `--prune`. See
                // [`Churn::build_pushed`]: the packs ARE the fixture.
                assert_eq!(
                    pack_count(&origin),
                    rounds,
                    "{rounds} push(es) left {} pack(s). A one-pack fixture cannot \
                     produce a cross-pack delta and every arm built on this one would be \
                     measuring the single-pack case twice",
                    pack_count(&origin)
                );
                assert!(
                    !has_bitmap(&origin),
                    "the pushed fixture grew a .bitmap, so the bitmap path would answer \
                     and the walk path — the subject — would never run"
                );
            }
            Layout::PushedRoundsOf { rounds, of } => {
                assert!(rounds >= 2 && rounds < of);
                init_pushed_origin(&root, &origin);
                push_slices(&work, &origin, 0, rounds, of);
                assert_eq!(pack_count(&origin), rounds);
                assert!(!has_bitmap(&origin));
            }
        }

        let head = ObjectId::from_hex(git(&origin, &["rev-parse", "HEAD"]).as_bytes())
            .expect("the head is an object id");
        Churn {
            _dir: dir,
            root,
            origin,
            head: std::cell::Cell::new(head),
        }
    }

    /// Serve one clone of this repository and hand back what came out.
    ///
    /// One serve function for every arm below, so that two arms being compared
    /// differ in exactly the one thing named in the call and nothing else: same
    /// object selection, same request, same `fetch`.
    ///
    /// * `ofs_delta` is the **client's own capability**. Since 2026-08-03 it
    ///   decides how a copied delta *names its base* — by distance backwards
    ///   (`OBJ_OFS_DELTA`) or by object id (`OBJ_REF_DELTA`) — and no longer
    ///   whether copying happens at all.
    /// * `pack_copy` is **gunnar's own seam**, [`NoPackCopy`]. `false` is the
    ///   pre-`P-001` server: same store, same walk, `write_pack` instead of
    ///   `write_pack_copy`.
    fn clone_through_gunnar(&self, ofs_delta: bool, pack_copy: bool) -> (Vec<u8>, Counts) {
        let store = FsStore::open_or_init(&self.origin, Kind::Sha1).expect("open the fixture");
        let objects = store.objects();
        let refs = store.refs();
        // The fixture guard, and not a formality: on a store with no packs
        // every arm here would be the fallback, `recompressed == 0` would be
        // unreachable, and the whole comparison would be a re-deflate measured
        // against itself. `P-001`'s own bench shipped in exactly that state.
        assert!(
            objects.packed().is_some(),
            "the fs backend reports no pack-resident view of a repository `git repack -adf` \
             just packed, so this whole test would be measuring the fallback twice"
        );
        let request = FetchRequest {
            wants: vec![self.head.get()],
            done: true,
            thin_pack: true,
            ofs_delta,
            ..Default::default()
        };
        let mut out = Vec::new();
        // The two branches differ only in what `packed()` answers. Everything
        // downstream — the request, the walk, the writer's options — is shared.
        let outcome = if pack_copy {
            UploadPack::new(&objects, &refs).fetch(&request, &mut out)
        } else {
            let blind = NoPackCopy(&objects);
            assert!(
                blind.packed().is_none(),
                "the control arm still reports a pack-resident view, so it is not a control"
            );
            UploadPack::new(&blind, &refs).fetch(&request, &mut out)
        }
        .expect("serve the clone");
        // Band 1 and nowhere else: the band byte is stripped here, so a valid
        // pack coming out of this has already proven the framing was right.
        let pack = Response::parse(&out).band(1);
        (
            pack,
            Counts {
                sent: outcome.objects_sent,
                copied: outcome.objects_copied_from_pack,
                recompressed: outcome.objects_recompressed,
                declined: outcome.closure_bases_declined,
            },
        )
    }

    /// The `n`th ancestor of the tip, as a `have` a real client would send.
    fn ancestor(&self, n: usize) -> ObjectId {
        git(&self.origin, &["rev-parse", &format!("HEAD~{n}")])
            .parse()
            .expect("an ancestor is an object id")
    }

    /// A **real client**: a repository holding exactly `at` and its ancestry,
    /// and nothing newer.
    ///
    /// A fetch pack cannot be judged standing on its own. Its commits name
    /// parents that live on the client's side of the negotiation cut, so
    /// `git index-pack --strict` — which verifies connectivity — refuses it,
    /// and refuses it identically whether the pack is thin, whole, correct or
    /// wrong. That is not a fixture detail: it is the reason this helper
    /// exists. The judge has to be a client that holds the bases, which is the
    /// only place a `--fix-thin` completion can even be attempted, and it is
    /// what a real `git fetch` does with the bytes.
    fn client_at(&self, at: ObjectId) -> PathBuf {
        let client = self.root.join(format!("client-{at}.git"));
        git(
            &self.root,
            &[
                "clone",
                "-q",
                "--bare",
                self.origin.to_str().unwrap(),
                client.to_str().unwrap(),
            ],
        );
        // Rewind to the cut and drop everything newer, so the client genuinely
        // lacks what the fetch is about to bring. Without the prune it would
        // hold the whole history and `--fix-thin` would have nothing to fix.
        git(&client, &["update-ref", "refs/heads/main", &at.to_string()]);
        git(&client, &["symbolic-ref", "HEAD", "refs/heads/main"]);
        git(&client, &["reflog", "expire", "--all", "--expire=now"]);
        git(&client, &["gc", "-q", "--prune=now"]);
        assert!(
            Command::new("git")
                .current_dir(&client)
                .args(["cat-file", "-e", &format!("{}^{{commit}}", self.head.get())])
                .status()
                .expect("probe the client")
                .code()
                != Some(0),
            "the client still holds the tip the fetch is supposed to deliver, so \
             `--fix-thin` would be resolving bases against objects a real client \
             at this cut would not have"
        );
        client
    }

    /// Serve one **negotiated fetch**: the client already holds `haves` and its
    /// whole ancestry, and asks for the tip.
    ///
    /// The difference from [`Churn::clone_through_gunnar`] is the only thing
    /// that matters here, and it is one field: a non-empty `haves`. A clone's
    /// selection is the whole history, so every delta's base travels with it;
    /// a fetch's selection is a suffix, so the bases the pushing client's git
    /// deltified against are on the *other* side of the cut. What the server
    /// does with those is what this measures.
    fn fetch_through_gunnar(&self, haves: &[ObjectId]) -> (Vec<u8>, Counts) {
        self.fetch_asking(haves, true)
    }

    /// The same, with the client's `thin-pack` capability under the caller's
    /// control. `false` is a client that never asked for one.
    fn fetch_asking(&self, haves: &[ObjectId], thin_pack: bool) -> (Vec<u8>, Counts) {
        self.fetch_asking_full(haves, thin_pack, true)
    }

    /// The same, with both capabilities under the caller's control.
    fn fetch_asking_full(
        &self,
        haves: &[ObjectId],
        thin_pack: bool,
        ofs_delta: bool,
    ) -> (Vec<u8>, Counts) {
        let store = FsStore::open_or_init(&self.origin, Kind::Sha1).expect("open the fixture");
        let objects = store.objects();
        let refs = store.refs();
        assert!(
            objects.packed().is_some(),
            "the fs backend reports no pack-resident view of a repository `git repack -adf` \
             just packed, so this whole test would be measuring the fallback twice"
        );
        let request = FetchRequest {
            wants: vec![self.head.get()],
            haves: haves.to_vec(),
            done: true,
            thin_pack,
            ofs_delta,
            ..Default::default()
        };
        let mut out = Vec::new();
        let outcome = UploadPack::new(&objects, &refs)
            .fetch(&request, &mut out)
            .expect("serve the fetch");
        assert!(
            outcome.objects_sent > 0,
            "the negotiation left nothing to send, so there is no fetch to measure"
        );
        (
            Response::parse(&out).band(1),
            Counts {
                sent: outcome.objects_sent,
                copied: outcome.objects_copied_from_pack,
                recompressed: outcome.objects_recompressed,
                declined: outcome.closure_bases_declined,
            },
        )
    }
}

#[derive(Debug)]
struct Counts {
    sent: u32,
    copied: usize,
    recompressed: usize,
    /// See [`gunnar_pack::WriteOutcome::closure_bases_declined`].
    declined: usize,
}

/// A bare origin that keeps every push as its own pack.
///
/// A small push is unpacked into loose objects by default
/// (`transfer.unpackLimit`, 100), and loose objects have no delta to copy at
/// all. gunnar's own receive-pack always writes a pack, so this is what makes a
/// fixture the production shape rather than a git-only artefact.
///
/// One writer for both pushed layouts (LAW 5): a second copy that forgot the
/// `unpackLimit` line would build a fixture with no packs in it and every arm
/// standing on it would measure the loose-object fallback while claiming to
/// measure pack copy.
fn init_pushed_origin(root: &Path, origin: &Path) {
    git(
        root,
        &[
            "init",
            "-q",
            "-b",
            "main",
            "--bare",
            origin.to_str().unwrap(),
        ],
    );
    git(origin, &["config", "transfer.unpackLimit", "1"]);
}

/// Push history slices `from..to` of `total`, one push — and so one pack —
/// each.
fn push_slices(work: &Path, origin: &Path, from: usize, to: usize, total: usize) {
    for r in from + 1..=to {
        let behind = COMMITS - COMMITS * r / total;
        git(
            work,
            &[
                "push",
                "-q",
                origin.to_str().unwrap(),
                &format!("+HEAD~{behind}:refs/heads/main"),
            ],
        );
    }
}

fn pack_dir_entries(origin: &Path) -> Vec<PathBuf> {
    std::fs::read_dir(origin.join("objects").join("pack"))
        .expect("the pack directory")
        .filter_map(|e| e.ok())
        .map(|e| e.path())
        .collect()
}

fn pack_count(origin: &Path) -> usize {
    pack_dir_entries(origin)
        .iter()
        .filter(|p| p.extension().is_some_and(|x| x == "pack"))
        .count()
}

fn has_bitmap(origin: &Path) -> bool {
    pack_dir_entries(origin)
        .iter()
        .any(|p| p.extension().is_some_and(|x| x == "bitmap"))
}

fn git(cwd: &Path, args: &[&str]) -> String {
    let out = Command::new("git")
        .current_dir(cwd)
        .args(args)
        .output()
        .unwrap_or_else(|err| panic!("running `git {args:?}`: {err}"));
    assert!(
        out.status.success(),
        "git {args:?} failed:\n{}",
        String::from_utf8_lossy(&out.stderr)
    );
    String::from_utf8_lossy(&out.stdout).trim().to_owned()
}

/// What **stock git** says is inside a pack gunnar served.
#[derive(Debug)]
struct StockGit {
    /// Delta entries, counted from `verify-pack`'s own chain-length histogram
    /// after it resolved them.
    deltas: usize,
    /// `OBJ_OFS_DELTA` entries — a base named by distance backwards, which a
    /// client that did not advertise `ofs-delta` cannot decode.
    ofs_deltas: usize,
    /// `OBJ_REF_DELTA` entries — a base named by object id, which needs no
    /// capability and is the older of the two forms.
    ref_deltas: usize,
}

/// Hand `pack` to **stock git** and report what it finds.
///
/// `index-pack --strict` is what git runs on a pack it receives: it resolves
/// every delta chain, re-derives every object id and refuses a pack whose
/// objects do not connect. If gunnar's `ofs-delta` base distances were wrong by
/// one byte this is what would say so, and nothing gunnar can check about its
/// own bytes would. It is also the entire safety argument for emitting an
/// `OBJ_REF_DELTA` whose base lies inside the same pack, which `gix-pack`'s own
/// comment calls "a discontinued practice": discontinued is not invalid, and
/// this is the third party whose acceptance is the claim.
///
/// **And it is not the only third party, which cost a fetch on 2026-08-05.**
/// The sentence above is true of a *self-contained* pack and was read as
/// covering a **thin** one, where the same entry means something else: in a
/// thin pack an `OBJ_REF_DELTA` is a claim about what the receiver already
/// holds, and gitoxide enforces exactly that while stock git does not. So the
/// arm that can see the difference is
/// [`a_thin_pack_names_no_base_the_receiver_does_not_already_hold`], which asks
/// both, and the two judges are kept side by side rather than one standing in
/// for the other.
fn stock_git_reads(root: &Path, pack: &[u8], name: &str) -> StockGit {
    let dir = root.join(name);
    std::fs::create_dir_all(&dir).expect("a directory for the pack");
    let pack_path = dir.join("copy.pack");
    std::fs::write(&pack_path, pack).expect("write the pack out");
    git(
        &dir,
        &[
            "index-pack",
            "--strict",
            "-o",
            "copy.idx",
            pack_path.to_str().unwrap(),
        ],
    );
    let listing = git(&dir, &["verify-pack", "-v", "copy.idx"]);

    // `verify-pack -v` ends with a histogram: `non delta: N objects`, then one
    // `chain length = D: M objects` line per delta depth present. Summing those
    // is git's own count of how many entries in this pack are deltas, taken
    // after it resolved them. Reading the per-object lines instead would mean
    // re-deciding what a delta looks like, which is the thing being checked.
    let deltas = listing
        .lines()
        .filter_map(|line| line.trim().strip_prefix("chain length = "))
        .filter_map(|rest| rest.split(": ").nth(1))
        .filter_map(|rest| rest.split_whitespace().next())
        .filter_map(|count| count.parse::<usize>().ok())
        .sum();

    // The delta **form** is a thing `verify-pack` does not print: its per-object
    // lines carry the *object* type (`blob`, `tree`, `commit`) and mark a delta
    // by appending `<depth> <base-oid>`, identically for both forms. So the form
    // is read where the format records it — the high nibble of the first byte of
    // the entry, `6` for `OBJ_OFS_DELTA` and `7` for `OBJ_REF_DELTA` — at the
    // offsets **git** printed. Nothing of gunnar's decides where an entry starts
    // or whether it is a delta; the only thing read here is one byte at each of
    // git's own offsets.
    //
    // (`gunnar-pack/tests/ofs_delta_off.rs` asserts the same nibble one layer
    // down, over `write_pack_copy` called directly. What is being checked here
    // is the layer that one cannot see: that `upload_pack` passes the client's
    // capability down to the emitter at all.)
    let mut ofs_deltas = 0;
    let mut ref_deltas = 0;
    for line in listing.lines() {
        // `<oid> <type> <size> <size-in-pack> <offset>`, plus `<depth> <base-oid>`
        // when it is a delta. Histogram lines carry no oid in column one.
        let fields: Vec<&str> = line.split_whitespace().collect();
        let Some(first) = fields.first() else {
            continue;
        };
        if first.len() < 40 || !first.bytes().all(|b| b.is_ascii_hexdigit()) {
            continue;
        }
        if fields.len() < 7 {
            continue;
        }
        let offset: usize = fields[4].parse().expect("git printed a pack offset");
        match (pack[offset] >> 4) & 0b111 {
            6 => ofs_deltas += 1,
            7 => ref_deltas += 1,
            other => panic!("git called offset {offset} a delta, but its type nibble is {other}"),
        }
    }
    assert_eq!(
        ofs_deltas + ref_deltas,
        deltas,
        "git's chain-length histogram counted {deltas} deltas but only \
         {ofs_deltas} + {ref_deltas} entries parsed as one, so the two readings \
         of the same pack disagree and neither can be trusted"
    );

    StockGit {
        deltas,
        ofs_deltas,
        ref_deltas,
    }
}

// ── the cases ───────────────────────────────────────────────────────────────

/// The headline: a clone of a packed repository is **copied**, and the wire
/// bytes say so.
///
/// # What the control arm is, and why it changed
///
/// Until 2026-08-03 the control was `ofs_delta: false`, because the serve path
/// gated copying on that capability and a client without it got the pre-`P-001`
/// server. That gate is gone — `OBJ_REF_DELTA` needs no capability, so such a
/// client now gets the copied entries too — and with it went the control: both
/// capability arms copy, and an assertion that the `false` arm recompresses
/// everything is now an assertion that the fix is absent.
///
/// So the control is [`NoPackCopy`], gunnar's own seam, which is what the
/// capability was only ever standing in for. It is a **better** control than the
/// capability ever was: it cuts `write_pack_copy` out of the path entirely
/// rather than changing how a copied entry names its base.
#[test]
fn a_clone_of_a_packed_repository_copies_entries_instead_of_recompressing_them() {
    let churn = Churn::build();
    let (copied_pack, copied) = churn.clone_through_gunnar(true, true);
    let (whole_pack, whole) = churn.clone_through_gunnar(true, false);

    // ── 1. the provenance the serve path now reports ────────────────────────
    assert_eq!(
        copied.recompressed, 0,
        "a clone of a fully packed repository deflated {} of its {} objects from \
         scratch; every one of them was already sitting deflated in the pack \
         (P-001). Counts: {copied:?}",
        copied.recompressed, copied.sent
    );
    assert_eq!(
        copied.copied, copied.sent as usize,
        "the serve path reports {} of {} objects copied. Anything less means \
         entries are being decoded and re-deflated on a repository where none \
         needs to be: {copied:?}",
        copied.copied, copied.sent
    );
    // The other arm is what the whole tree did before P-001, and it is here so
    // that "copied == sent" above is a statement about this change rather than
    // about an assertion that can only ever come out one way.
    assert_eq!(
        (whole.copied, whole.recompressed),
        (0, whole.sent as usize),
        "the pack-copy-off control is meant to be the OLD behaviour: every \
         object deflated from scratch, nothing copied. If it copied anything, \
         `NoPackCopy` is not cutting the seam and every count above is measuring \
         the same emitter twice: {whole:?}"
    );

    // ── 2. the same objects, both ways ──────────────────────────────────────
    assert_eq!(
        copied.sent, whole.sent,
        "the two arms packed different object sets, so their sizes are not \
         comparable"
    );
    assert_eq!(index_and_count(&copied_pack, Kind::Sha1), copied.sent);
    assert_eq!(index_and_count(&whole_pack, Kind::Sha1), whole.sent);

    // ── 3. the bytes, which are the point ───────────────────────────────────
    //
    // MEASURED on this fixture, oden 2026-08-03: 144 objects, 17 696 B copied
    // against 81 580 B with the seam cut, so **4.61×**. The absolute figures
    // move a few percent between runs and the ratio barely does: the fixture
    // commits carry real timestamps, so its object ids differ every run and
    // git's delta window makes slightly different choices (17 696 / 17 722 /
    // 19 155 B copied over three runs, 4.26× to 4.61×). Quote the ratio.
    //
    // The floor is 3× rather than 4.6× because this is a guard and not the
    // measurement (the measurement is the head-to-head against stock git), but
    // it is far outside anything a re-deflate can reach, which is the whole
    // assertion. Seen RED with the seam left uncut: both arms then run the same
    // emitter and the ratio is 1.00×, which is what this line and not the count
    // above it is here to catch — checked with that count neutralised, because a
    // guard standing behind another guard that always fires first is not a
    // guard.
    let ratio = whole_pack.len() as f64 / copied_pack.len() as f64;
    // Printed as well as asserted: the threshold below is a floor chosen to be
    // unreachable by a re-deflate, and the actual figure is what tells a reader
    // whether the fixture still has anything left to delta. `cargo test --
    // --nocapture` shows it.
    eprintln!(
        "pack_copy: {} objects, copied {} B vs whole-object {} B = {ratio:.2}x smaller",
        copied.sent,
        copied_pack.len(),
        whole_pack.len(),
    );
    assert!(
        ratio > 3.0,
        "the copied pack is {} bytes against the whole-object pack's {}, only \
         {ratio:.2}× smaller. Delta reuse is not happening, whatever the object \
         counts say",
        copied_pack.len(),
        whole_pack.len()
    );

    // ── 4. stock git's opinion of those bytes ───────────────────────────────
    let copied = stock_git_reads(&churn.root, &copied_pack, "verify-copied");
    let whole = stock_git_reads(&churn.root, &whole_pack, "verify-whole");
    assert!(
        copied.deltas > 0,
        "`git verify-pack` resolved no delta chains in the copied pack, so the \
         size win above came from somewhere other than delta reuse: {copied:?}"
    );
    assert_eq!(
        whole.deltas, 0,
        "the pack-copy-off control emitted {} deltas. gitoxide has no delta \
         encoder at all (P-009), so a delta in that pack is not a better \
         fallback, it is evidence the control is still copying: {whole:?}",
        whole.deltas
    );
    // A client that *did* advertise the capability should be paying the cheap
    // form: base by distance backwards, not 20 bytes of object id per entry.
    assert_eq!(
        copied.ref_deltas, 0,
        "an ofs-delta-capable client was sent {} ref-deltas, each one paying a \
         full object id where a 1-3 byte varint would do: {copied:?}",
        copied.ref_deltas
    );
}

/// A client that never advertised `ofs-delta` must not be sent one — and must
/// still get `P-001`.
///
/// Not a hypothetical politeness: an `OBJ_OFS_DELTA` entry to a client in that
/// mode is a pack it cannot decode.
///
/// Until 2026-08-03 that was honoured by not copying for such a client at all,
/// which handed it the whole of the pre-`P-001` server — MEASURED at **18.3×
/// the wire bytes and 13.0× the server CPU** for a capability that has nothing
/// to do with whether an entry may be copied. `OBJ_REF_DELTA` is the older of
/// the two forms and needs no capability, so the delta bytes survive in full and
/// only the base's *name* changes. Both halves are asserted here, because
/// either one alone is satisfiable by throwing the other away:
///
/// * **no `OBJ_OFS_DELTA` reaches this client** — the readability half, read
///   from the type nibble at stock git's own offsets, and
/// * **the entries were copied, deltas and all** — the `P-001` half, which is
///   what the old gate silently cost.
///
/// The layer under this one — `write_pack_copy` called directly, both forms,
/// byte-identical delta payloads — is `gunnar-pack/tests/ofs_delta_off.rs`. What
/// only this test can see is whether `upload_pack` hands the capability down.
#[test]
fn a_client_without_ofs_delta_gets_a_pack_it_can_read() {
    let churn = Churn::build();
    let (pack, counts) = churn.clone_through_gunnar(false, true);

    // ── the P-001 half ──────────────────────────────────────────────────────
    assert_eq!(
        counts.recompressed, 0,
        "a client without ofs-delta had {} of its {} objects inflated and \
         deflated again. The capability decides how a copied delta names its \
         base, not whether copying happens: {counts:?}",
        counts.recompressed, counts.sent
    );
    assert_eq!(
        counts.copied, counts.sent as usize,
        "only {} of {} entries were copied for a client without ofs-delta: {counts:?}",
        counts.copied, counts.sent
    );

    // ── the readability half, in stock git's words ──────────────────────────
    let seen = stock_git_reads(&churn.root, &pack, "verify-fallback");
    assert_eq!(
        seen.ofs_deltas, 0,
        "a client that never advertised ofs-delta was sent {} OBJ_OFS_DELTA \
         entries it cannot decode: {seen:?}",
        seen.ofs_deltas
    );
    assert!(
        seen.ref_deltas > 0,
        "not one delta reached this client. Either the copy path fell back to \
         re-deflating everything — which is the 18.3x regression this test \
         exists for — or the fixture has no deltas to copy: {seen:?}"
    );
}

/// A store with no packs answers `None` and keeps working — the default on
/// [`ObjectStore::packed`] is a real answer, not a stub.
///
/// `MemObjectStore` is the case the appliance's non-`fs` build is, and a znippy
/// cold tier that stores inflated content per oid is the same shape (`P-005`).
#[test]
fn a_store_with_no_packs_falls_back_and_says_so() {
    let fixture = Fixture::build(Kind::Sha1);
    assert!(
        fixture.objects.packed().is_none(),
        "the in-memory store claims a pack-resident view it cannot have"
    );

    let upload = UploadPack::new(&fixture.objects, &fixture.refs);
    let request = FetchRequest {
        wants: vec![fixture.four],
        done: true,
        thin_pack: true,
        ofs_delta: true,
        ..Default::default()
    };
    let mut out = Vec::new();
    let outcome = upload.fetch(&request, &mut out).expect("serve the clone");
    assert!(outcome.objects_sent > 0);
    assert_eq!(
        outcome.objects_copied_from_pack, 0,
        "a store with no packs cannot have copied anything"
    );
    assert_eq!(
        outcome.objects_recompressed, outcome.objects_sent as usize,
        "every object had to be deflated, and the report must say so rather \
         than leave the fields at zero"
    );
    assert_eq!(
        index_and_count(&Response::parse(&out).band(1), Kind::Sha1),
        outcome.objects_sent
    );
}

/// **`S-003`: a negotiated fetch must keep the deltas a clone keeps.**
///
/// `P-001` is measured on a clone, where it copies 100% of the entries, and
/// that number hid this: a clone's object selection is the *whole* history, so
/// every `OBJ_OFS_DELTA`'s base is inside the transfer and
/// `PackCopyAndBaseObjects` can re-point it. A **fetch**'s selection is a
/// suffix of history, and the bases the pushing client's git chose live on the
/// other side of the negotiation cut. `gix_pack`'s `Entry::from_pack_entry`
/// then finds no base among `potential_bases`, returns `None` because
/// `allow_thin_pack` is false, and the caller inflates the whole delta chain
/// and re-deflates the object whole.
///
/// So the *same* object, in the *same* pack, is copied on a clone and
/// recompressed on a fetch. That is the whole of gunnar's 1.47x wire-byte loss
/// to gitea, and no clone-shaped test could ever see it.
///
/// What is asserted is applied output — `objects_copied_from_pack` against
/// `objects_recompressed`, and the delta count stock `git` finds in the bytes —
/// for the reason this file's own header gives: both shapes produce a valid,
/// complete, git-readable pack, so nothing about correctness can tell them
/// apart.
#[test]
fn a_negotiated_fetch_keeps_the_deltas_it_already_had() {
    let churn = Churn::build_with(WIDE_FILES);
    // `S003_DEPTH` re-runs this at another cut without editing it. The
    // relationship is worth knowing and is the reason 8 is the default: the
    // SHORTER the fetch, the worse the pre-fix server does, because a short
    // transfer carries fewer of its own bases. MEASURED on this fixture,
    // whole-pack over thin-pack: 4.95x at 8 commits, 5.52x at 24, 1.43x at 40.
    // A benchmark that fetches hundreds of commits is measuring the best case.
    let depth: usize = std::env::var("S003_DEPTH")
        .ok()
        .and_then(|v| v.parse().ok())
        .unwrap_or(8);
    let cut = churn.ancestor(depth);
    let haves = vec![cut];
    let (pack, counts) = churn.fetch_through_gunnar(&haves);

    // ── stock git is the judge, in the one place a fetch can be judged ──────
    let client = churn.client_at(cut);
    let (accepted, deltas) = client_accepts(&client, &pack);
    fsck(&client);
    // Not `==`. A **thin** pack names bases it does not carry, and
    // `--fix-thin` appends those completed bases to the index it writes, so
    // the client's pack is legitimately larger than the transfer. That
    // inequality is itself the applied output: a pack that carried every base
    // it referenced would come out exactly equal, which is what the pre-fix
    // server produced.
    assert!(
        accepted >= counts.sent,
        "stock git indexed {accepted} objects out of a fetch gunnar says carried {} \
         ({counts:?})",
        counts.sent
    );

    // ── and stock git is also the yardstick ─────────────────────────────────
    //
    // The same object set, packed by `git pack-objects` for the same cut, in
    // both forms it can take. `--thin` is what `git-upload-pack` sends a
    // client that advertised the capability — which this request did — and is
    // therefore the number gunnar is actually competing against. Without it is
    // what gunnar sends today.
    let thin = git_packs(&churn.origin, churn.head.get(), cut, true);
    let whole = git_packs(&churn.origin, churn.head.get(), cut, false);
    assert!(
        whole > thin,
        "stock git produced no smaller pack with --thin than without it ({whole} vs \
         {thin}), so this fixture has no cross-cut deltas and every ratio below \
         would be a comparison of a thing with itself"
    );

    eprintln!(
        "S-003: sent={} copied={} recompressed={} bytes={} deltas={} indexed={} | git thin={} whole={}",
        counts.sent,
        counts.copied,
        counts.recompressed,
        pack.len(),
        deltas,
        accepted,
        thin,
        whole
    );

    // The claim, in the unit the loss was reported in: **wire bytes**. A count
    // of copied entries cannot carry it, because the entries that matter are
    // exactly the ones being expanded, and 23-of-24 looks excellent while the
    // pack is twice the size it should be.
    let over = pack.len() as f64 / thin as f64;
    assert!(
        over <= 1.10,
        "gunnar served {} bytes where stock git's thin pack of the same objects is \
         {thin} ({over:.2}x). Those objects are pack-resident and already deltified; \
         {} of {} were re-deflated whole because their delta bases fall on the \
         client's side of the negotiation cut. That is `S-003`: {counts:?}",
        pack.len(),
        counts.recompressed,
        counts.sent
    );
}

/// `git pack-objects` over the same revision range, thin or whole.
///
/// This is the yardstick, and it is stock git's own answer rather than
/// gunnar's about what the transfer is worth compressing to.
fn git_packs(origin: &Path, head: ObjectId, cut: ObjectId, thin: bool) -> usize {
    use std::io::Write as _;
    let mut args = vec!["pack-objects", "--revs", "--stdout", "--delta-base-offset"];
    if thin {
        args.push("--thin");
    }
    let mut child = Command::new("git")
        .current_dir(origin)
        .args(&args)
        .stdin(std::process::Stdio::piped())
        .stdout(std::process::Stdio::piped())
        .stderr(std::process::Stdio::piped())
        .spawn()
        .expect("spawn pack-objects");
    write!(
        child.stdin.take().expect("pack-objects stdin"),
        "{head}\n^{cut}\n"
    )
    .expect("feed the revision range");
    let out = child.wait_with_output().expect("pack-objects");
    assert!(
        out.status.success(),
        "git pack-objects failed:\n{}",
        String::from_utf8_lossy(&out.stderr)
    );
    assert!(
        !out.stdout.is_empty(),
        "git pack-objects produced no bytes, so the yardstick is zero and every \
         ratio against it is meaningless"
    );
    out.stdout.len()
}

/// Hand `pack` to a **real client** that holds the bases, exactly as `git
/// fetch` does, and report what it accepted.
///
/// `--strict` re-derives every object id and verifies connectivity;
/// `--fix-thin` is what completes a thin pack against objects the receiver
/// already has. Together they are the whole correctness claim for anything
/// this test measures: a delta whose base the client lacks, or a base distance
/// wrong by one byte, dies here rather than on a customer's disk.
///
/// Returns `(objects, deltas)` as **stock git's** own index says, not as
/// gunnar reported them.
fn client_accepts(client: &Path, pack: &[u8]) -> (u32, usize) {
    use std::io::Write as _;
    let mut child = Command::new("git")
        .current_dir(client)
        .args(["index-pack", "--strict", "--fix-thin", "--stdin", "-v"])
        .stdin(std::process::Stdio::piped())
        .stdout(std::process::Stdio::piped())
        .stderr(std::process::Stdio::piped())
        .spawn()
        .expect("spawn index-pack");
    child
        .stdin
        .take()
        .expect("index-pack stdin")
        .write_all(pack)
        .expect("feed the pack");
    let out = child.wait_with_output().expect("index-pack");
    assert!(
        out.status.success(),
        "stock git REFUSED the pack gunnar served:\n{}",
        String::from_utf8_lossy(&out.stderr)
    );
    // `index-pack -v` answers `pack\t<sha>`; the id is the last field.
    let name = String::from_utf8_lossy(&out.stdout)
        .split_whitespace()
        .next_back()
        .unwrap_or_default()
        .to_owned();
    assert!(
        !name.is_empty(),
        "index-pack named no pack, so nothing can be counted"
    );
    let idx = client.join(format!("objects/pack/pack-{name}.idx"));
    let listed = git(client, &["verify-pack", "-v", idx.to_str().unwrap()]);

    // `verify-pack -v` prints one line per object:
    //   <oid> <type> <size> <size-in-pack> <offset>            — a base
    //   <oid> <type> <size> <size-in-pack> <offset> <depth> <base-oid>  — a delta
    // so the seventh field is present exactly on the deltas. The type filter
    // drops the trailing chain-length histogram, which is prose.
    let mut objects = 0u32;
    let mut deltas = 0usize;
    for line in listed.lines() {
        let fields: Vec<&str> = line.split_whitespace().collect();
        if !matches!(fields.get(1), Some(&("commit" | "tree" | "blob" | "tag"))) {
            continue;
        }
        objects += 1;
        if fields.len() >= 7 {
            deltas += 1;
        }
    }
    assert!(
        objects > 0,
        "verify-pack listed no objects at all, so both numbers below would be \
         zeroes that look exactly like a clean answer"
    );
    (objects, deltas)
}

/// `git fsck --full --strict` inside the client, after it took the pack.
fn fsck(client: &Path) {
    let out = Command::new("git")
        .current_dir(client)
        .args(["fsck", "--full", "--strict", "--no-progress"])
        .output()
        .expect("run fsck");
    assert!(
        out.status.success(),
        "the client's object store is broken after taking the pack:\n{}",
        String::from_utf8_lossy(&out.stderr)
    );
}

/// **The `S-003` gate, and the proof the arm above can go red.**
///
/// A thin pack is only legal because the client asked for one. This drives the
/// same fixture, the same cut and the same walk with `thin-pack` withheld, and
/// two things must follow:
///
///  * the objects whose bases fall outside the cut are **expanded again** —
///    which is the pre-fix server, so this is the red the green arm is
///    measured against, produced by a supported request rather than by an env
///    switch that only tests exist to honour, and
///  * the pack is **self-contained**: `git index-pack --strict` accepts it
///    standing alone, with no repository to resolve bases against. That is the
///    property a client without the capability is entitled to, and it is not
///    implied by the first — a server that emitted thin deltas regardless
///    would still report objects expanded if it expanded some others.
#[test]
fn a_client_that_did_not_ask_for_a_thin_pack_gets_a_whole_one() {
    let churn = Churn::build_with(WIDE_FILES);
    let cut = churn.ancestor(8);

    let (asked, asked_counts) = churn.fetch_asking(&[cut], true);
    let (plain, plain_counts) = churn.fetch_asking(&[cut], false);

    // ── and the base closure must not have run ──────────────────────────────
    //
    // `write_pack_copy` may add a delta's unselected base to the pack instead of
    // expanding the delta, and on a **clone** that is worth −2.82% of the wire.
    // On a negotiated fetch it is the opposite: the base sits below the cut, so
    // it is an object the client already holds, and shipping it is the
    // duplication thin packs exist to avoid. MEASURED oden 2026-08-05 on this
    // fixture with the closure wrongly enabled here: **31 360 → 55 513 bytes,
    // +77%**, 57 bases added to recover 24 deltas.
    //
    // `upload_pack` therefore passes `base_closure: None` whenever the
    // negotiation found anything in common, and this is where that goes red —
    // as an object count, because a pack that gained 57 objects is not the pack
    // this test goes on to compare.
    assert_eq!(
        asked_counts.sent, plain_counts.sent,
        "the two requests selected different objects ({} thin, {} plain). If the plain \
         arm is the larger, the base closure ran on a NEGOTIATED fetch: it must be off \
         whenever `common` is non-empty, because an unselected base below the cut is an \
         object the client already has",
        asked_counts.sent, plain_counts.sent,
    );
    assert_eq!(
        asked_counts.recompressed, 0,
        "the thin arm expanded {} objects, so the comparison has no baseline",
        asked_counts.recompressed
    );
    assert!(
        plain_counts.recompressed > 0,
        "withholding `thin-pack` changed nothing: {plain_counts:?}. Either the \
         capability is not being honoured — in which case a client that cannot \
         complete a thin pack is being sent one — or the fixture has no deltas \
         crossing the cut and the green arm proves nothing"
    );
    assert!(
        plain.len() > asked.len(),
        "the whole-object pack ({} bytes) is no larger than the thin one ({} \
         bytes), so `S-003` is measuring nothing",
        plain.len(),
        asked.len()
    );

    // ── self-containment, asserted in both directions ───────────────────────
    //
    // `index-pack` with neither `--fix-thin` nor a repository behind it can
    // resolve a delta only against the pack's own objects, so it is exactly
    // the question "does this pack carry every base it names". The whole-object
    // pack must pass it and the thin one must **fail** it: asserting only the
    // first would be satisfied by a server that never made a thin pack at all,
    // which is the thing being disproved two assertions up.
    //
    // (`--strict` is deliberately not used here. It also verifies
    // connectivity, and a fetch pack's commits name parents that live on the
    // client's side of the cut, so it refuses both packs for a reason that has
    // nothing to do with deltas.)
    assert!(
        indexes_standalone(&churn.root, &plain, "whole"),
        "the pack sent to a client without `thin-pack` names a base it does not \
         carry, so that client cannot read it"
    );
    assert!(
        !indexes_standalone(&churn.root, &asked, "thin"),
        "the pack sent to a client that DID ask for `thin-pack` resolves standing \
         alone, so it is not thin and the byte win above came from somewhere else"
    );

    eprintln!(
        "S-003 gate: thin={} B ({} expanded) vs whole={} B ({} expanded), {} objects",
        asked.len(),
        asked_counts.recompressed,
        plain.len(),
        plain_counts.recompressed,
        asked_counts.sent
    );
}

/// Can stock git index this pack with no repository and no `--fix-thin`?
///
/// That is the definition of a pack being self-contained: every delta base it
/// names is inside it. Returns the verdict rather than asserting, because both
/// answers are load-bearing in different places.
fn indexes_standalone(root: &Path, pack: &[u8], name: &str) -> bool {
    let dir = root.join(format!("standalone-{name}"));
    std::fs::create_dir_all(&dir).expect("a directory for the pack");
    let path = dir.join("p.pack");
    std::fs::write(&path, pack).expect("write the pack out");
    let out = Command::new("git")
        .current_dir(&dir)
        .args(["index-pack", "-o", "p.idx", path.to_str().unwrap()])
        .output()
        .expect("run index-pack");
    out.status.success()
}

/// **Both delta forms in one pack: `thin-pack` without `ofs-delta`.**
///
/// The combination is not hypothetical — `OBJ_REF_DELTA` is the older form and
/// needs no capability — and it is the one place the two naming schemes meet.
/// A thin delta must name its base by object id because the base is not in the
/// pack to have a distance to; an *internal* delta, on this client, must ALSO
/// be named by object id, and by a different route through the emitter (gix's
/// `DeltaOid` for the first, this crate's own `written_ids` table for the
/// second). A pack that got either wrong is one stock git refuses.
#[test]
fn a_thin_fetch_to_a_client_without_ofs_delta_is_readable() {
    let churn = Churn::build_with(WIDE_FILES);
    let cut = churn.ancestor(8);
    let (pack, counts) = churn.fetch_asking_full(&[cut], true, false);

    assert_eq!(
        counts.recompressed, 0,
        "withholding ofs-delta cost this client the thin reuse as well: {counts:?}.          The two capabilities are independent — one decides how a base is NAMED,          the other whether a base outside the pack may be named at all"
    );

    // The `OBJ_OFS_DELTA` census is deliberately NOT taken here. It needs
    // `index-pack` on the pack standing alone, and a thin pack cannot be
    // indexed standing alone — the base is the point. That census is taken by
    // `a_client_without_ofs_delta_gets_a_pack_it_can_read`, over a clone,
    // which is self-contained and where the same emitter branch decides the
    // same thing. What is left to this arm is the half that one cannot see:
    // that the reuse survives when both capabilities differ from the default,
    // and that a real client at the cut can still complete the result.
    let client = churn.client_at(cut);
    let (accepted, deltas) = client_accepts(&client, &pack);
    fsck(&client);
    assert!(accepted >= counts.sent);
    assert!(deltas > 0, "the completed pack holds no deltas at all");
}

/// **The red the whole vouching mechanism did not have.**
///
/// `client_accepts` proves a served thin pack completes against the client it
/// was vouched for. On its own that is a green nobody has seen red: a voucher
/// that said *yes* to every base would produce a pack that also passes, against
/// that client, because that client happens to hold the bases. The assertion
/// only means something if the same pack is refused by a client that does not.
///
/// So the same bytes are handed to a client at the **root commit**, which holds
/// none of the history the bases live in. `git index-pack --strict --fix-thin`
/// must fail, and must fail *by naming unresolved deltas* rather than by any
/// other unhappiness — a non-zero exit alone would also be produced by a
/// corrupt pack, a missing directory or a mistyped flag, and this test would
/// then pass while proving nothing (`LAW 2`: check output, not exit code).
///
/// # What this pins, and what the measurement behind it says
///
/// A thin pack whose bases the receiver lacks is not a smaller answer, it is a
/// **failed fetch** — this is what that failure looks like. Any future
/// widening of `Selection::client_has` has to keep the arm above green and this
/// one red, and nothing else can tell a widening from a bug.
///
/// MEASURED oden 2026-08-04, `bench/examples/fetchbytes-probe.rs`, 46 negotiated
/// fetches over the 19 real `workspace_nordisk` repositories at three
/// divergence depths, every pack judged by `index-pack --strict`,
/// `fsck --full --strict` and `rev-list --objects` set equality against the
/// server:
///
/// | voucher | thin bases offered | refused | of those, held by the client |
/// |---|---:|---:|---:|
/// | bitmap (ships) | 1 193 | 604 | **0** |
/// | walk, `Exclusion::Edges` | 1 194 | 753 | **138** |
/// | walk, `Exclusion::Full` | 1 193 | 604 | **0** |
///
/// The refusal *rate* is 50.6% and every one of those refusals is **correct**:
/// the base is genuinely not in the receiving repository. The walk's 138 extra
/// refusals are the under-approximation `copy.rs` already names, they are worth
/// 857 939 bytes corpus-wide (1.44%), and the bitmap path does not have them.
/// There is no widening left to take that would not break this test.
#[test]
fn a_thin_pack_is_refused_by_a_client_that_lacks_its_bases() {
    let churn = Churn::build_with(WIDE_FILES);
    let cut = churn.ancestor(8);
    let (pack, counts) = churn.fetch_through_gunnar(&[cut]);
    assert!(
        counts.copied > 0,
        "nothing was copied, so this pack carries no delta whose base could be \
         missing and the refusal below would mean nothing ({counts:?})"
    );

    // The client the fetch was vouched for takes it. This is the green half,
    // and it is here rather than borrowed from the arm above so that the two
    // halves are the same bytes.
    let vouched_for = churn.client_at(cut);
    client_accepts(&vouched_for, &pack);
    fsck(&vouched_for);

    // A client at the root holds no revision any of those bases could be.
    //
    // ── `--fix-thin` WITHOUT `--strict`, and that is the whole test ─────────
    //
    // `--strict` also verifies **connectivity**, and a fetch of the last eight
    // commits references the cut commit, which this client does not have. So
    // `--strict` fails here on *any* pack, thin or whole, and a guard built on
    // it is measuring connectivity while claiming to measure vouching.
    //
    // Found by running the red rather than by reading the code: the first
    // version of this test used `--strict`, and re-pointing it at a
    // deliberately **non-thin** pack — one with no outside base to be missing —
    // left it passing. `--fix-thin` alone fails only on a delta whose base
    // cannot be found, which is the one thing being asserted.
    let root = churn.ancestor(COMMITS - 1);
    let stranger = churn.client_at(root);
    let out = {
        use std::io::Write as _;
        let mut child = Command::new("git")
            .current_dir(&stranger)
            .args(["index-pack", "--fix-thin", "--stdin", "-v"])
            .stdin(std::process::Stdio::piped())
            .stdout(std::process::Stdio::piped())
            .stderr(std::process::Stdio::piped())
            .spawn()
            .expect("spawn index-pack");
        child
            .stdin
            .take()
            .expect("index-pack stdin")
            .write_all(&pack)
            .expect("feed the pack");
        child.wait_with_output().expect("index-pack")
    };
    let stderr = String::from_utf8_lossy(&out.stderr).to_ascii_lowercase();
    assert!(
        !out.status.success(),
        "a client holding none of the bases COMPLETED the thin pack. Either this \
         fixture's deltas all point inside the transfer — in which case the arm \
         above is proving nothing about vouching — or `--fix-thin` resolved them \
         against objects this client should not have."
    );
    assert!(
        stderr.contains("unresolved delta"),
        "index-pack failed, but not by naming an unresolved delta. A non-zero \
         exit is also what a corrupt pack, a bad flag or a broken connectivity \
         check produces, and this assertion has already been hollow once for \
         exactly that reason:\n{stderr}"
    );
}

/// Hand `pack` to **gitoxide**, resolving thin bases against `client`.
///
/// This is `gunnar_pack::index_thin_pack`, which is
/// `gix_pack::Bundle::write_to_directory` — the same call `gunnar-client`'s
/// fetch ends in and the same call `receive-pack` ends in. It is a *second*
/// judge, not a cheaper spelling of `index-pack`: the two implementations
/// disagree about one thing, and that disagreement is the defect below.
fn gitoxide_reads(client: &Path, pack: &[u8]) -> Result<usize, String> {
    let store = FsStore::open_or_init(client, Kind::Sha1).expect("open the client");
    let objects = store.objects();
    let bases = gunnar_store::gix_adapter::GixObjects::new(&objects);
    let mut reader = std::io::BufReader::new(pack);
    match gunnar_pack::index_thin_pack(
        &mut reader,
        None,
        bases,
        &gunnar_pack::IndexOptions::new(Kind::Sha1),
        None,
    ) {
        Ok(indexed) => Ok(indexed.num_objects as usize),
        Err(err) => {
            // `Error::repo`'s lesson, one crate over: the top line here is
            // "failed to index the pack" and the object id that makes the
            // failure diagnosable is two `#[source]`s down.
            let mut chain = format!("{err}");
            let mut src: Option<&dyn std::error::Error> = std::error::Error::source(&err);
            while let Some(s) = src {
                chain.push_str(&format!(": {s}"));
                src = s.source();
            }
            Err(chain)
        }
    }
}

/// **A thin pack may only name a base the receiver already HOLDS.**
///
/// `Selection::client_has` used to vouch for the objects *being sent* as well,
/// on the argument that "naming a base inside the same pack is an
/// `OBJ_REF_DELTA` against an object in the same pack, which stock git
/// accepts". Stock git does accept it. **gitoxide does not**, and gitoxide is
/// what `gunnar-client` — and every other gitoxide-based client — resolves a
/// fetch with:
///
/// `gix_pack::data::input::LookupRefDeltaObjectsIter` treats every
/// `OBJ_REF_DELTA` in a thin pack as naming an object the *receiver* holds. It
/// looks the base up in the local object database and in the bases it has
/// already spliced in, and **nowhere else** — never inside the pack it is
/// reading. A base that is in the transfer but has not been spliced in is
/// `input::Error::NotFound`, and the fetch dies with
/// `The object <base> could not be decoded or wasn't found`.
///
/// So the two judges disagree, and a guard that asks only stock git cannot see
/// it. Reproduced first outside this suite, on a `gunnar.year` run: server
/// tree `1d062a8c` was written into the pack as a delta on a tree the client
/// held, the next entry was a delta on `1d062a8c` — and gitoxide refused the
/// whole pack while `git index-pack --strict --fix-thin` completed it.
///
/// Both judges are kept, and they are not redundant: stock git catches a wrong
/// base *distance* that gitoxide's splice would paper over, and gitoxide
/// catches this.
#[test]
fn a_thin_pack_names_no_base_the_receiver_does_not_already_hold() {
    let churn = Churn::build_pushed(WIDE_FILES, PUSH_ROUNDS);
    let cut = churn.ancestor(8);
    let (pack, counts) = churn.fetch_through_gunnar(&[cut]);
    assert!(
        counts.copied > 0,
        "nothing was copied, so this pack carries no delta whose base could be \
         named at all ({counts:?})"
    );
    let client = churn.client_at(cut);

    // **gitoxide first, and the order is load-bearing.** `client_accepts` runs
    // `index-pack --fix-thin` *into* the client, so after it the client holds
    // every object of the transfer and no thin base can be missing any more.
    // Seen for real: with the two calls the other way round this arm passed on
    // a pack `gunnar.year` was dying on. `index_thin_pack` with `None` for the
    // directory writes nothing, so it leaves the client as it found it.
    let gix_verdict = gitoxide_reads(&client, &pack);

    // Stock git's verdict, kept as the control: it passed before this defect
    // was fixed and it must still pass after, or the fix traded one receiver
    // for the other.
    client_accepts(&client, &pack);
    fsck(&client);

    match gix_verdict {
        Ok(n) => assert!(
            n as u32 >= counts.sent,
            "gitoxide indexed {n} object(s) out of a pack that carried {} \
             ({counts:?})",
            counts.sent
        ),
        Err(chain) => panic!(
            "the client the fetch was VOUCHED FOR cannot read the pack with \
             gitoxide, while stock git completed the same bytes.\n{chain}\n\
             A thin base is a promise about what the RECEIVER holds. An object \
             this transfer is carrying is not held until the pack has been \
             resolved, and gitoxide resolves thin bases before it resolves the \
             pack."
        ),
    }
}

/// How many pushes arrive after the `gc` in
/// [`the_pack_copy_guards_hold_after_gunnars_own_gc`].
///
/// # The floor, swept 2026-08-05 on oden
///
/// Not a taste. `sweep_gcd_after` runs the whole arm at 1, 2, 4 and 8 post-gc
/// pushes with [`GCD_ROUNDS`] before the fold, both judges on the cross-fold
/// fetch. MEASURED:
///
/// | after | packs | clone copied, pre-fold → post-fold | fetch copied | gitoxide |
/// |------:|------:|-----------------------------------:|-------------:|:---------|
/// |     1 |     2 |                    138/220 → 220/220 |     27 of 40 | accepts  |
/// |     2 |     3 |                    125/205 → 205/205 |     17 of 40 | accepts  |
/// |     4 |     5 |                    114/180 → 180/180 |     12 of 40 | accepts  |
/// |     8 |     9 |                    101/140 → 140/140 |     12 of 40 | accepts  |
///
/// Every value comes out clean, and every value puts objects in more than one
/// pack, which is the condition the arm exists for. What the sweep rules out is
/// the value **0**, a folded repository nobody has pushed to since: one pack,
/// nothing cross-pack, and an arm that would be [`Layout::OnePack`] under
/// another name.
///
/// 4 is kept because it is the smallest value that leaves more than one *new*
/// pack beside the consolidated one, so a delta whose base landed in a
/// different post-gc push is reachable and not only one reaching back into the
/// fold — and because the copied fraction of the cross-fold fetch has already
/// flattened by then (12 of 40 at both 4 and 8), so the larger sizes buy
/// nothing but time.
const GCD_AFTER: usize = 4;

/// Pushes before the `gc` in [`Churn::build_gcd`].
///
/// [`PUSH_ROUNDS`]'s twelve, so the pre-fold half of this fixture is the same
/// production shape every other pushed arm stands on and the only variable
/// against them is the `gc`.
const GCD_ROUNDS: usize = PUSH_ROUNDS;

/// **The pack-copy guards, re-run after gunnar's own `gc`.** They had only ever
/// run after a push.
///
/// Both 2026-08-05 sweeps named `gc` under load as unswept, and this is the
/// half of it that is not about concurrency. Three of that day's wrong answers
/// were about *which pack holds which object* — a base closure keying
/// membership by `(pack_id, pack_offset)` when a pack holds an object once, and
/// a multi-pack index giving one pack's object list holes so `PackExtents`
/// measured an entry across the hole. **A gc changes exactly that**, and no arm
/// in this file had ever served a repository gunnar had folded:
/// [`Layout::OnePack`] is stock `git repack -adf`, git's writer, not gunnar's.
///
/// # The comparison is within one repository, and it has to be
///
/// The first version of this test asserted `copied == sent` on a post-gc
/// fixture and failed at 197 of 240 — and that was the **test** being wrong,
/// not the code. MEASURED across four layouts on the same run: one pack copies
/// 240/240, twelve pushed packs copy 158/240, sixteen copy 155/240, and this
/// layout's five copy 197/240. A copy fraction below 1 is what a multi-pack
/// repository *is*; the fold moves it toward 1. So a floor on the fraction
/// would have been a number picked off one run, and a comparison against a
/// separately built pushed fixture would have compared two different object
/// graphs — the commits carry real timestamps, so every build has different ids
/// and git's delta window makes different choices.
///
/// What is asserted instead is the **same object set, before and after the same
/// fold**: build the fixture partly, clone it, fold it, clone it again. The
/// object set is identical by construction, so the two counts are comparable,
/// and the claim — a fold does not make copy worse — is one no run-to-run noise
/// can fake.
///
/// # Result: CLEAN, and what that is worth
///
/// Stated plainly (LAW 7). Copy survives the fold and improves across it, both
/// judges accept both packs, and nothing regressed. This arm found no defect;
/// what it removes is the possibility that one was there unlooked-at, and it is
/// the guard that fires if a future change to the fold breaks copy for everyone
/// who has ever run `gunnar gc`.
///
/// # Seen red
///
/// Three ways, each naming its own subject:
///
/// 1. **the fold removed** — `after.copied == after.sent` fires at 114 of 180,
///    which is the pre-fold number, proving the second clone is measured after
///    the fold and not before it.
/// 2. **`clone_through_gunnar(.., false)` for the post-fold arm** — the "not
///    worse" assertion fires with 0 copied against 114, proving both counts come
///    from the transfers named here and not from the fixture's own history.
/// 3. **`push_more` not re-reading `HEAD`** — the post-push half then serves
///    the pre-push tip, the negotiation cut is already the tip, and
///    `fetch_asking_full`'s own control fires with *"the negotiation left
///    nothing to send"*. That is why `Churn::head` is a `Cell`: a plain field
///    would leave a post-push fixture serving a history it has moved past.
#[test]
fn the_pack_copy_guards_hold_after_gunnars_own_gc() {
    // ── the same object set, before and after one fold ──────────────────────
    let churn = Churn::build_partial(WIDE_FILES, GCD_ROUNDS, GCD_ROUNDS + GCD_AFTER);
    let (before_pack, before) = churn.clone_through_gunnar(true, true);

    let folded = churn.gunnar_gc();
    assert!(
        folded.rewrote,
        "gunnar's gc found nothing to do on a {GCD_ROUNDS}-pack fixture, so nothing below          is measuring a fold: {folded:?}"
    );
    assert_eq!(
        pack_count(&churn.origin),
        1,
        "gunnar's gc left {} packs: {folded:?}",
        pack_count(&churn.origin)
    );

    let (after_pack, after) = churn.clone_through_gunnar(true, true);
    assert_eq!(
        after.sent, before.sent,
        "the fold changed how many objects a clone of the same history sends, {} to {}.          That is not a copy question, it is a lost or duplicated object",
        before.sent, after.sent
    );
    assert!(
        after.copied >= before.copied,
        "gunnar's own gc made pack copy WORSE on the same object set: {} of {} copied          before the fold, {} after. before={before:?} after={after:?}",
        before.copied,
        before.sent,
        after.copied
    );
    assert_eq!(
        after.copied, after.sent as usize,
        "a clone of a repository folded into ONE pack copied {} of {} objects. With a          single pack there is no cross-pack base and nothing left to decline: {after:?}",
        after.copied, after.sent
    );
    // Both packs are real packs stock git will take, and both still carry
    // deltas — a fold that flattened every chain would satisfy every count
    // above while sending far more bytes.
    for (label, pack, counts) in [
        ("pre-gc", &before_pack, &before),
        ("post-gc", &after_pack, &after),
    ] {
        assert_eq!(
            index_and_count(pack, Kind::Sha1),
            counts.sent,
            "stock git indexed a different number of objects than the {label} clone sent"
        );
        let read = stock_git_reads(&churn.root, pack, &format!("gcd-{label}"));
        assert!(
            read.deltas > 0,
            "`git verify-pack` resolved no delta chain in the {label} clone, so its size              is not coming from delta reuse: {read:?}"
        );
    }

    // ── then the pushes that arrive after the gc ────────────────────────────
    //
    // A folded repository nobody has pushed to since is the easy shape. This is
    // the one an operator actually has: the consolidated pack, `GCD_AFTER` new
    // ones beside it, and a `.bitmap` that is stale for everything after the
    // fold.
    assert!(
        has_bitmap(&churn.origin),
        "gunnar's gc wrote no .bitmap, so the stale-bitmap-plus-new-packs state this half          exists for is not present"
    );
    churn.push_more(GCD_ROUNDS, GCD_ROUNDS + GCD_AFTER, GCD_ROUNDS + GCD_AFTER);
    assert_eq!(
        pack_count(&churn.origin),
        1 + GCD_AFTER,
        "the post-gc pushes did not each land their own pack, so the consolidated pack is          not sitting alongside anything and no object can be in two packs"
    );

    // A negotiated fetch, because it is selection that produces a delta whose
    // base is not in the transfer. The cut is on the far side of the fold, so
    // the transfer spans the consolidated pack AND the new ones — the
    // `(pack_id, pack_offset)` condition, which a cut inside one pack cannot
    // produce.
    let cut = churn.ancestor(8);
    let (fetch_pack, fetched) = churn.fetch_through_gunnar(&[cut]);
    assert!(
        fetched.copied > 0,
        "a negotiated fetch across the fold copied nothing, so it carries no delta whose          base could be misnamed and this half is vacuous ({fetched:?})"
    );

    // Both judges. Stock git 2.53.0 is the judge on anything on the wire, and
    // gitoxide's `index_thin_pack` is the second because the two disagree: git
    // accepts a thin base that gitoxide refuses. See
    // `a_thin_pack_names_no_base_the_receiver_does_not_already_hold`.
    let client = churn.client_at(cut);
    // gitoxide first: `client_accepts` runs `index-pack --fix-thin` into the
    // client, after which no thin base can be missing any more.
    let gix = gitoxide_reads(&client, &fetch_pack);
    client_accepts(&client, &fetch_pack);
    fsck(&client);
    match gix {
        Ok(n) => assert!(
            n as u32 >= fetched.sent,
            "gitoxide indexed {n} of the {} objects a post-gc fetch carried ({fetched:?})",
            fetched.sent
        ),
        Err(chain) => panic!(
            "gitoxide cannot read a pack served across gunnar's own fold, while stock git              completed the same bytes.\n{chain}"
        ),
    }
    eprintln!(
        "post-gc: clone copied {}/{} before the fold and {}/{} after; \
         cross-fold fetch {} objects, {} copied",
        before.copied, before.sent, after.copied, after.sent, fetched.sent, fetched.copied
    );
}

/// Stock git's verdict on the emitted pack: the index it writes, or the reason
/// it refused.
///
/// `index-pack --strict` is what `transfer.fsckObjects=true` runs on a pack a
/// client receives, and it is the judge that **refuses a pack carrying one
/// object twice**. gitoxide does not; see [`gitoxide_reads_standalone`]. The
/// two are kept side by side because each sees something the other does not,
/// and this is the direction that cost `gunnar.year` a clone.
fn stock_git_reads_standalone(dir: &Path, pack: &[u8]) -> Result<PathBuf, String> {
    std::fs::create_dir_all(dir).expect("a directory for the pack");
    let path = dir.join("p.pack");
    std::fs::write(&path, pack).expect("write the pack out");
    let out = Command::new("git")
        .current_dir(dir)
        .args([
            "index-pack",
            "--strict",
            "-o",
            "p.idx",
            path.to_str().unwrap(),
        ])
        .output()
        .expect("run index-pack");
    if !out.status.success() {
        return Err(String::from_utf8_lossy(&out.stderr).trim().to_owned());
    }
    Ok(dir.join("p.idx"))
}

/// Hand a **self-contained** pack to gitoxide, the second judge, and keep the
/// index it writes.
///
/// `index_pack` rather than `index_thin_pack`: a clone's pack names no base it
/// does not carry, so there is no receiver to resolve against and a failure
/// here is a failure of the bytes.
///
/// The index is written rather than discarded because gitoxide **accepts** a
/// pack that carries an object twice — MEASURED, it returned `Ok(241)` for a
/// 241-entry pack of 240 objects — so its index is the one listing of the
/// pack's entries that survives the defect and can be counted. See
/// [`census_of`].
fn gitoxide_reads_standalone(dir: &Path, pack: &[u8], kind: Kind) -> Result<u32, String> {
    std::fs::create_dir_all(dir).expect("a directory for the index");
    let mut cursor = std::io::Cursor::new(pack);
    gunnar_pack::index_pack(
        &mut cursor,
        Some(dir),
        &gunnar_pack::IndexOptions::new(kind),
        None,
    )
    .map(|indexed| indexed.num_objects)
    .map_err(|err| {
        let mut chain = format!("{err}");
        let mut src: Option<&dyn std::error::Error> = std::error::Error::source(&err);
        while let Some(s) = src {
            chain.push_str(&format!(": {s}"));
            src = s.source();
        }
        chain
    })
}

/// Every object id a **v2 pack index** names, in index order.
///
/// # Why this parses the format rather than shelling out
///
/// Because `git verify-pack -v` is the obvious way to list an index's entries
/// and it **cannot see the defect**: MEASURED oden 2026-08-05, handed an index
/// carrying one object twice it prints nothing and exits non-zero with
/// `fatal: The same object <id> appears twice in the pack`. So does `git
/// index-pack`. git refuses a duplicate at every entrance, which is right of
/// git and useless as an instrument — a census taken through it is an
/// assertion that can never fail, and this arm had one for an afternoon.
///
/// The v2 layout is fixed and small: the magic `\xfftOc`, the version, a
/// 256-entry fanout whose last cell is the object count, and then that many
/// raw hashes. Nothing here decides what an object is; it reads the count and
/// the names out of the one file that lists them.
fn index_object_ids(idx: &Path, kind: Kind) -> Vec<String> {
    let bytes = std::fs::read(idx).expect("read the pack index");
    assert!(
        bytes.starts_with(&[0xff, b't', b'O', b'c']),
        "{idx:?} is not a v2 pack index"
    );
    assert_eq!(
        u32::from_be_bytes(bytes[4..8].try_into().expect("the version")),
        2,
        "{idx:?} is not version 2"
    );
    let fanout_end = 8 + 256 * 4;
    let count = u32::from_be_bytes(
        bytes[fanout_end - 4..fanout_end]
            .try_into()
            .expect("the last fanout cell"),
    ) as usize;
    let width = kind.len_in_bytes();
    let names = &bytes[fanout_end..fanout_end + count * width];
    names
        .chunks_exact(width)
        .map(|id| id.iter().map(|b| format!("{b:02x}")).collect())
        .collect()
}

/// The one index file in `dir`.
fn sole_index(dir: &Path) -> PathBuf {
    let mut found: Vec<PathBuf> = std::fs::read_dir(dir)
        .expect("an index directory")
        .filter_map(|entry| entry.ok())
        .map(|entry| entry.path())
        .filter(|path| path.extension().is_some_and(|ext| ext == "idx"))
        .collect();
    assert_eq!(found.len(), 1, "expected exactly one .idx in {dir:?}");
    found.pop().expect("one index")
}

/// The object count the pack's own header declares, read out of the bytes.
///
/// The header is written before the first entry, from a count decided before
/// the generator runs. Comparing it against the entries stock git actually
/// found is what catches a writer that emitted a different number of objects
/// than it promised.
fn pack_header_objects(pack: &[u8]) -> u32 {
    assert!(pack.starts_with(b"PACK"), "not a packfile");
    u32::from_be_bytes(pack[8..12].try_into().expect("a pack header"))
}

/// Files in the fixture for [`a_clone_of_a_multi_pack_store_carries_no_object_twice`],
/// against [`WIDE_FILES`]'s sixty.
///
/// Sixteen, because the condition is a **property of git's delta search** and
/// not something the fixture can state directly: it needs one blob to be the
/// base of a delta *inside an early pack* and to be spliced into a later one as
/// well, which happens when a file is revised more than once inside a single
/// push round. At sixty files and forty-eight commits a file is touched about
/// every twenty commits, so it almost never is; at sixteen it is.
///
/// MEASURED oden 2026-08-05 at these sixteen files, the same clone at
/// `origin/master` (`8f79cd7`, the defect present) against this commit, and the
/// closure's own `closure_bases_declined`:
///
/// ```text
///   packs        2    3    4    5    6    8   12   15
///   before      ok   ok   ok FAIL FAIL FAIL FAIL FAIL
///   declined     0    0    0    4    8    5    3    7
/// ```
///
/// So **five packs is the floor** and [`PUSH_ROUNDS`]'s twelve is well inside
/// it. Four is not a smaller version of the defect, it is the absence of it,
/// and a fixture built at four packs would be a guard that could never fail.
///
/// # Fifteen was the ceiling, and the reason for it is closed
///
/// At **sixteen** packs `FsStore::open_or_init` writes a multi-pack index
/// (`gunnar_store::midx::MULTI_PACK_INDEX_THRESHOLD`), and from there
/// `write_pack_copy` emitted a pack **stock git and gitoxide both refused** —
/// `fatal: pack is corrupted (SHA1 mismatch)` — with `GUNNAR_BASE_CLOSURE=off`
/// as well as on, and with `NoPackCopy` clean on the same fixture. That was a
/// separate defect of the copy path under a multi-pack index and this arm's
/// fixture stayed below it so the two could not be confused for one another.
///
/// It was `P-025`'s entry-length table sizing an entry across an object the
/// index had attributed to the other pack, fixed in `0d10e17`. The ceiling is
/// gone and **it is now a case rather than a boundary**:
/// [`a_clone_of_a_store_with_a_multi_pack_index_is_not_corrupt`] is this same
/// fixture at `MULTI_PACK_INDEX_THRESHOLD` packs, where the index appears by
/// itself. This arm still sits at [`PUSH_ROUNDS`] so that it keeps measuring the
/// closure with the extent table **live** on every pack — above the threshold
/// the short-list packs decline their table and `closure_bases_declined` falls
/// to 0, which would make the canary below unreachable.
const DUP_FILES: usize = 16;

/// **A pack carries every object once, and a multi-pack store is where that
/// stops being automatic.**
///
/// `WriteOptions::base_closure` names a delta's unselected base and adds it to
/// the pack rather than exploding the delta. "Unselected" was decided by pack
/// **offset**, which is the right question for `Entry::from_pack_entry` and the
/// wrong one for the pack: on a multi-pack store one object id has two
/// locations, `location_by_oid` answers with one of them, and a delta in the
/// other pack names an offset the selection does not hold whose *object* it
/// does. The base was then added to a pack that already carried it, and stock
/// git refuses such a pack outright:
///
/// ```text
/// fatal: The same object 00d6fd78e6c2b91b311f54f5401b6ca5eb635f33 appears twice in the pack
/// fatal: fetch-pack: invalid index-pack output
/// ```
///
/// That is where `gunnar.year` died at week 12, on the quarterly clone.
///
/// # Why every existing arm was green while it happened
///
/// Because every fixture in this tree was built by `git clone --bare`, which
/// **repacks**. A repacked store holds each object once, one object has one
/// location, and the two questions above are the same question. The shape is
/// [`Churn::build_pushed`]'s — one pack per push, no `gc` — which is also the
/// production shape, and [`DUP_FILES`] carries the sweep that says how many
/// packs it takes.
///
/// # What is asserted, and why the count is not enough on its own
///
/// The **entries** of the emitted pack, from stock git's own `verify-pack -v`,
/// not the `.idx` and not a count gunnar reports about itself. A duplicated
/// object is two entries with one id, and it is invisible to `objects_sent`,
/// to `bytes_written` and to the pack's own header — all three were correct
/// while the pack was unreadable.
///
/// `closure_bases_declined` is the **canary**, and it is not decoration: it is
/// the number of times the closure was offered this exact case and turned it
/// down. Without it a fixture that drifted out of the shape would leave every
/// assertion below trivially true.
#[test]
fn a_clone_of_a_multi_pack_store_carries_no_object_twice() {
    let churn = Churn::build_pushed(DUP_FILES, PUSH_ROUNDS);
    let (pack, counts) = churn.clone_through_gunnar(true, true);
    assert!(
        counts.copied > 0,
        "nothing was copied out of a pack, so no delta base was named at all \
         and there is no closure to judge ({counts:?})"
    );

    let header = pack_header_objects(&pack);

    // **gitoxide first, and it is not the judge that catches this.** It indexes
    // a pack carrying an object twice without complaint, which is exactly what
    // makes its index usable as a census: it is a listing of the pack's
    // ENTRIES that survives the defect. Stock git's would not exist to read.
    let gix_dir = churn.root.join("gix-index");
    let gix = gitoxide_reads_standalone(&gix_dir, &pack, Kind::Sha1);
    let ids = match &gix {
        Ok(_) => index_object_ids(&sole_index(&gix_dir), Kind::Sha1),
        Err(chain) => panic!(
            "gitoxide could not index the clone pack:\n{chain}\n\
             the header declares {header} objects and the server reported \
             {counts:?}"
        ),
    };

    let mut seen = std::collections::HashSet::new();
    let duplicated: Vec<&String> = ids.iter().filter(|id| !seen.insert(*id)).collect();
    assert!(
        duplicated.is_empty(),
        "the clone pack carries {} object(s) twice — {duplicated:?} — out of \
         {} entries for {} distinct objects. An added delta base must never be \
         an object the pack already holds, by any route, including one reached \
         through a different pack than the walk selected from",
        duplicated.len(),
        ids.len(),
        seen.len(),
    );
    assert_eq!(
        ids.len(),
        header as usize,
        "the pack's header promised {header} objects and its index lists {} \
         entries",
        ids.len()
    );
    assert_eq!(
        gix.as_ref().ok().copied(),
        Some(header),
        "gitoxide's object count for the same bytes is {gix:?}, against a \
         header of {header}"
    );

    // Stock git, which is the receiver that refuses a duplicate and the one a
    // customer runs. It is asked after the census so that a duplicated object
    // is named by gunnar's own assertion first and confirmed by git's second,
    // rather than only appearing as somebody else's error string.
    let stock_dir = churn.root.join("stock-index");
    let stock_idx = match stock_git_reads_standalone(&stock_dir, &pack) {
        Ok(idx) => idx,
        Err(stderr) => panic!(
            "stock git refused the clone pack:\n{stderr}\n\
             gitoxide accepted the same bytes ({gix:?}); the header declares \
             {header} objects and the server reported {counts:?}"
        ),
    };
    assert_eq!(
        index_object_ids(&stock_idx, Kind::Sha1).len(),
        header as usize,
        "stock git's index of the pack names a different number of objects \
         than the pack's header declares"
    );

    // **The canary, and it runs last on purpose.** With the decline removed the
    // census above goes red first and names the duplicated object, which is the
    // diagnosis a reader wants. Reaching here means the pack was clean, and a
    // clean pack proves something only if the closure was offered the case at
    // all.
    assert!(
        counts.declined > 0,
        "the closure was never offered a base the pack already carried, so this \
         arm asserted nothing ({counts:?}). Either the fixture drifted out of \
         the shape — see `DUP_FILES` for the pack-count sweep — or the decline \
         it counts is gone"
    );

    // Every object the clone asked for arrived. A pack that dropped one is
    // duplicate-free for a reason nobody wants.
    let want: std::collections::HashSet<String> = git(
        &churn.origin,
        &["rev-list", "--objects", &churn.head.get().to_string()],
    )
    .lines()
    .filter_map(|line| line.split_whitespace().next().map(str::to_owned))
    .collect();
    for id in &want {
        assert!(seen.contains(id), "the clone pack is missing {id}");
    }
}

/// The parameter sweep behind [`GCD_AFTER`], run on demand.
///
/// `#[ignore]`d because it is a measurement rather than a guard, but it still
/// asserts the two things its own table rests on — that the fold makes the
/// clone wholly copyable and that each post-gc push lands its own pack — so it
/// cannot print nonsense and be believed.
#[test]
#[ignore = "a measurement, not a guard; run explicitly with --ignored"]
fn sweep_gcd_after() {
    for after in [1usize, 2, 4, 8] {
        let churn = Churn::build_partial(WIDE_FILES, GCD_ROUNDS, GCD_ROUNDS + after);
        let (_, before) = churn.clone_through_gunnar(true, true);
        churn.gunnar_gc();
        let (_, folded) = churn.clone_through_gunnar(true, true);
        churn.push_more(GCD_ROUNDS, GCD_ROUNDS + after, GCD_ROUNDS + after);
        let packs = pack_count(&churn.origin);
        let cut = churn.ancestor(8);
        let (pack, fetched) = churn.fetch_through_gunnar(&[cut]);
        let client = churn.client_at(cut);
        let gix = gitoxide_reads(&client, &pack).is_ok();
        client_accepts(&client, &pack);
        eprintln!(
            "after={after}  packs={packs}  clone {}/{} -> {}/{}  fetch sent={} copied={} gix_ok={gix}",
            before.copied, before.sent, folded.copied, folded.sent, fetched.sent, fetched.copied
        );
        assert_eq!(folded.copied, folded.sent as usize);
        assert_eq!(packs, 1 + after);
    }
}

/// **A whole clone off a store that grew a multi-pack index by itself, judged
/// by both receivers.**
///
/// The corpus shape this repository had no arm for, and the absence is why the
/// defect below lived from `fc2e0c3` (2026-08-04 20:54) to `0d10e17`
/// (2026-08-05 11:47). Every fixture that reached sixteen packs was either a
/// `git clone --bare` carve — which repacks, so one pack — or
/// `nornir-bench`'s `packed_fixture`, which writes `ids.chunks(per)` into
/// disjoint packs and never serves any of them. Disjoint packs and lookups
/// cannot express the defect: it needs one object in **two** packs and a
/// receiver looking at the served bytes.
///
/// # What it guards
///
/// `PackExtents` (`P-025`) sizes an entry as the distance to the next offset in
/// the same pack, which is exact only if it holds every offset that pack has. A
/// multi-pack index keeps one **deduplicated** oid table, so an object living in
/// two packs is recorded against exactly one of them and `gix-odb` builds the
/// other pack's list by filtering that table by pack — short by precisely the
/// objects the index attributed elsewhere. The entry before each hole is then
/// measured across it, the copied entry carries its neighbour's bytes as a tail,
/// and the receiver parses every entry the header promised and reads its trailer
/// from the wrong offset.
///
/// # Why this pack count and not a bigger round number
///
/// [`MULTI_PACK_INDEX_THRESHOLD`] exactly, because the index has to appear
/// **unasked** — nothing here writes one, and a fixture that called
/// `write_multi_pack_index` itself would guard the writer instead of the store's
/// own policy. Reading the constant rather than spelling `16` is what makes the
/// arm follow the policy if it moves.
///
/// Pack count is not the trigger and this arm does not claim it is. MEASURED
/// oden 2026-08-06 on this fixture, `write_pack_copy` with the completeness
/// check removed, stock git 2.53.0 as the receiver:
///
/// ```text
///   threshold 16   packs  2 ok ·  4 ok ·  8 ok · 13 ok · 15 ok · 16 FAIL · 17 FAIL · 20 FAIL
///   threshold  8   packs  2 ok ·  4 ok ·  8 FAIL · 12 FAIL · 16 FAIL
///   threshold  2   packs  2 FAIL ·  4 FAIL
/// ```
///
/// The cliff moves with the constant, to the pack. **Two packs is the floor** —
/// the fewest a multi-pack index can span — and the threshold only decides when
/// a store starts having the index that exposes it. The fixture already holds
/// 16 objects in two packs at two packs, so the duplicate is not what the cliff
/// tracks either. `crates/gunnar-pack/tests/pack_extents.rs` carries the
/// two-pack case with a hand-written index; this one carries the production
/// shape, where nobody asked for the index at all.
///
/// # Seen red
///
/// All three of its own conditions, oden 2026-08-06:
///
/// * with the completeness check removed from `PackedObjects::learn_pack`, on
///   stock git's own words — `fatal: pack is corrupted (SHA1 mismatch)`, 201 501
///   bytes served against 194 782 accepted on a green run, ≈6.7 kB of surplus.
///   The two figures are two builds of this fixture, which carries real
///   timestamps, so they are not the same repository to the byte;
///   `gunnar.multi_pack_serve` does the A/B inside one open store and measured
///   **+16 137** exactly, at sha256;
/// * with the fixture at 4 packs — *"opening a 16-pack store wrote no
///   multi-pack-index"*;
/// * with the fixture repacked to one pack — *"no object of the 240 in this
///   fixture lives in more than one pack"*.
///
/// The shape assertions stay green under the first, so that failure names the
/// defect and not the fixture.
#[test]
fn a_clone_of_a_store_with_a_multi_pack_index_is_not_corrupt() {
    let churn = Churn::build_pushed(DUP_FILES, MULTI_PACK_INDEX_THRESHOLD);

    // ── the shape, stated as numbers before gunnar opens anything ──────────
    //
    // Neither of these is a formality. Without an object in two packs the index
    // deduplicates nothing, no entry list has a hole, and every assertion below
    // is trivially true on a fixture that cannot fail.
    let (distinct, duplicated) = objects_by_pack_residency(&churn.origin);
    assert!(
        duplicated > 0,
        "no object of the {distinct} in this fixture lives in more than one \
         pack, so a multi-pack index has nothing to choose between and this arm \
         cannot see the defect it exists for"
    );
    assert!(
        !churn.origin.join("objects/pack/multi-pack-index").is_file(),
        "the fixture already had a multi-pack index before gunnar opened it, so \
         this arm would not be watching the store's own policy write one"
    );

    let (pack, counts) = churn.clone_through_gunnar(true, true);

    // The index appeared by itself, during the open inside the serve. If it did
    // not, everything below is the single-pack path measured again.
    assert!(
        churn.origin.join("objects/pack/multi-pack-index").is_file(),
        "opening a {MULTI_PACK_INDEX_THRESHOLD}-pack store wrote no \
         multi-pack-index, so this arm served the configuration it is not about"
    );
    assert!(
        counts.copied > 0,
        "nothing was copied out of a pack, so `write_pack_copy` never ran the \
         path this arm guards ({counts:?})"
    );

    // ── stock git, the receiver that names the defect ──────────────────────
    let stock_dir = churn.root.join("midx-stock");
    let stock_idx = match stock_git_reads_standalone(&stock_dir, &pack) {
        Ok(idx) => idx,
        Err(stderr) => panic!(
            "stock git refused a clone served off a {MULTI_PACK_INDEX_THRESHOLD}-pack \
             store with a multi-pack index over it:\n{stderr}\n\
             {duplicated} of {distinct} objects live in more than one pack, the \
             pack's header declares {} objects, it is {} bytes long and the \
             server reported {counts:?}",
            pack_header_objects(&pack),
            pack.len()
        ),
    };

    // ── gitoxide, the second decoder ───────────────────────────────────────
    //
    // The two refuse this defect with different words — `pack is corrupted
    // (SHA1 mismatch)` against a failed index — so a guard that asked only one
    // would be a guard against one implementation's parser.
    let gix_dir = churn.root.join("midx-gix");
    let gix = gitoxide_reads_standalone(&gix_dir, &pack, Kind::Sha1)
        .unwrap_or_else(|chain| panic!("gitoxide refused the same clone pack:\n{chain}"));

    // The header, both indices and the server's own count are one number, or
    // some entry went somewhere nobody is looking.
    let header = pack_header_objects(&pack);
    assert_eq!(
        index_object_ids(&stock_idx, Kind::Sha1).len(),
        header as usize,
        "stock git indexed a different number of objects than the pack's header \
         declares"
    );
    assert_eq!(gix, header, "gitoxide's count for the same bytes differs");
    assert_eq!(
        counts.sent, header,
        "the server reported sending {} objects into a pack whose header says \
         {header}",
        counts.sent
    );
}

/// `(distinct objects, how many of them live in more than one pack)`, read out
/// of the `.idx` files themselves.
///
/// First-party for the reason [`index_object_ids`] gives: `git verify-pack` and
/// `git index-pack` both refuse a duplicate at the door and print nothing, so a
/// census taken through either is an assertion that can never fail. This one
/// reads the v2 index format directly, which is also the only listing that
/// survives the defect it is measuring.
fn objects_by_pack_residency(origin: &Path) -> (usize, usize) {
    let mut per_id: std::collections::HashMap<String, usize> = std::collections::HashMap::new();
    let mut indices: Vec<PathBuf> = std::fs::read_dir(origin.join("objects/pack"))
        .expect("the fixture's pack directory")
        .filter_map(|entry| entry.ok())
        .map(|entry| entry.path())
        .filter(|path| path.extension().is_some_and(|ext| ext == "idx"))
        .collect();
    indices.sort();
    for idx in &indices {
        for id in index_object_ids(idx, Kind::Sha1) {
            *per_id.entry(id).or_default() += 1;
        }
    }
    let duplicated = per_id.values().filter(|count| **count > 1).count();
    (per_id.len(), duplicated)
}