crates/storage-git-gix/parked-gix-2/gunnar-wire-gix/tests/unnamed_policy.rs
//! **`deepen-since` meant something different on gunnar than in git, and said
//! nothing about it.**
//!
//! Every case here is a diff against stock `git` 2.53.0, driven through the
//! real client over the `ext::` helper, in the shape `second_sweep.rs`
//! established.
//!
//! # The class
//!
//! `caps::ADVERTISED` makes *"advertised and honoured by nothing"* impossible.
//! Its inverse — a behaviour the server applies that the wire never
//! declares — has now produced four wrong answers in this tree in one day, and
//! the two guards added to `tests/advertisement.rs`
//! (`every_capability_the_server_reads_is_one_it_advertises` and
//! `every_serving_policy_is_declared_somewhere`) close the two shapes that are
//! *visible in the source*: a capability read but never offered, and a `Config`
//! field enforced but never classified.
//!
//! This file is the third shape, and no census can catch it: gunnar advertises
//! `shallow`, which is a promise to accept all five deepening arguments — and
//! `deepen-since` was accepted and then **interpreted differently from git**.
//! The advertisement is a word, and the word has a meaning; a server may be
//! entirely honest about which words it speaks and still mean something else by
//! one of them. Only a differential against the definition can see that, which
//! is why every arm below runs the identical request against stock
//! `git-upload-pack` first.
//!
//! # What was wrong
//!
//! `deepen-since` is `rev-list --max-age=<since>` in git: a commit older than
//! the cutoff is not selected, and **being a tip does not exempt it**. gunnar's
//! walk seeded every `want` unconditionally and tested only *parents'* dates.
//! So a request whose tip predated the cutoff was answered with that tip.
//!
//! MEASURED oden 2026-08-05, git 2.53.0, three commits dated
//! `1700001000/2000/3000`, `--shallow-since=@1700009000`:
//!
//! | server | result |
//! |---|---|
//! | stock `git-upload-pack` | `fatal: no commits selected for shallow requests` |
//! | gunnar, before | a one-commit clone of a commit **older than the cutoff** |
//!
//! The client asked for history newer than a date and was handed history older
//! than it, marked shallow, exit 0, nothing in either log. A refusal that is
//! not a refusal but a different answer — the same shape as the `deepen-not`
//! defect next door in `second_sweep.rs`, and the reason both live under the
//! same heading.
//!
//! # Both halves of the fix were seen red, separately
//!
//! The fix is two lines apart in `shallow.rs::compute`, and each was reverted
//! on its own to check it carries weight:
//!
//! * without the **seed filter**, `since_past_every_commit` fails with *"gunnar
//! served a --shallow-since past every commit … `git rev-list` says
//! `1700005000 D`"* — commit `D`, dated `+5000`, against a cutoff of `+9000`;
//! * with the seed filter but without the **empty-selection refusal**, the same
//! case fails differently — *"gunnar refused, but not in git's words"*, with
//! `error: Could not read …` / `fatal: Failed to traverse parents of commit
//! …`. Cutting every want away and then serving the result is a **corrupt**
//! clone rather than a wrong one, which is why the refusal is not decoration
//! on top of the filter.
//!
//! Both v0 and v2 arms went red both times, and the fourth case
//! (`an_ordinary_since_…`) stayed green throughout — a seed filter that simply
//! cut everything would have taken it down.
#[path = "git_harness/mod.rs"]
mod git_harness;
use git_harness::*;
use gix_hash::Kind;
use gunnar_wire::ProtocolVersion;
fn main() {
serve_if_asked();
let cases: &[(&str, fn())] = &[
(
"CONTROL_stock_git_refuses_a_since_past_every_commit",
control_stock_git_since_past_every_commit,
),
(
"since_past_every_commit_is_refused_like_stock_git",
since_past_every_commit,
),
(
"since_past_every_commit_is_refused_on_v0_too",
since_past_every_commit_v0,
),
(
"an_ordinary_since_still_serves_and_matches_stock_git",
an_ordinary_since_matches,
),
(
"a_deepen_not_excluding_every_tip_is_refused_like_stock_git",
deepen_not_excluding_everything,
),
];
run_cases("unnamed_policy", cases, 5);
}
/// A cutoff later than every commit in `Scene::dated`, whose newest is
/// `DATED_BASE + 5000`.
fn past_everything() -> String {
format!("@{} +0000", DATED_BASE + 9000)
}
/// A cutoff between `B` (+2000) and `M` (+4000), so the request is ordinary:
/// something is selected and something is cut.
fn between() -> String {
format!("@{} +0000", DATED_BASE + 3500)
}
/// **The contract.** git does not serve a smaller answer when the date excludes
/// everything — it dies, by name.
///
/// Without this arm the two gunnar arms below would be asserting gunnar against
/// gunnar's own reading of the documentation, which is exactly how
/// `deepen-since` came to mean two things.
fn control_stock_git_since_past_every_commit() {
let scene = Scene::dated(Kind::Sha1);
let (ok, _, stderr) = Git::new()
.cwd(&scene.root)
.args(["clone", "-q", "--shallow-since"])
.arg(past_everything())
.arg(scene.local_url())
.arg(scene.root.join("stock-past").to_str().unwrap())
.run();
assert!(
!ok,
"stock git served a --shallow-since past every commit, so there is no contract here to \
hold gunnar to and both arms below would pass on anything"
);
assert!(
stderr.contains("no commits selected"),
"stock git refused for some other reason than the one under test:\n{stderr}"
);
// …and the same server serves an ordinary cutoff, so "it refuses" above is
// about the date and not about the fixture being unservable.
Git::new()
.cwd(&scene.root)
.args(["clone", "-q", "--shallow-since"])
.arg(between())
.arg(scene.local_url())
.arg(scene.root.join("stock-between").to_str().unwrap())
.ok();
}
/// gunnar served the tip anyway. Now it refuses, and the refusal reaches the
/// client.
fn since_past_every_commit() {
let scene = Scene::dated(Kind::Sha1);
let into = scene.root.join("gunnar-past");
let (ok, _, stderr) = scene
.client(ProtocolVersion::V2)
.args(["clone", "-q", "--shallow-since"])
.arg(past_everything())
.arg(scene.url())
.arg(into.to_str().unwrap())
.run();
assert!(
!ok,
"gunnar served a --shallow-since past every commit where stock git refuses. The client \
asked for commits newer than a date and got one older than it, marked shallow, exit 0 \
— a different answer wearing a success's clothes. `git rev-list` says {:?}",
std::fs::read_dir(&into)
.map(|_| git_in(&into).args(["log", "--format=%ct %s"]).ok())
.unwrap_or_else(|_| "no clone at all".to_owned())
);
assert!(
stderr.contains("no commits selected"),
"gunnar refused, but not in git's words, so a client cannot tell the two servers \
apart:\n{stderr}"
);
}
/// The same, on protocol v0. Three of today's four defects in this class were
/// green on v2 and broken on v0, so a v2-only arm is not evidence here.
fn since_past_every_commit_v0() {
let scene = Scene::dated(Kind::Sha1);
let (ok, _, stderr) = scene
.client(ProtocolVersion::V0)
.args(["clone", "-q", "--shallow-since"])
.arg(past_everything())
.arg(scene.url())
.arg(scene.root.join("gunnar-past-v0").to_str().unwrap())
.run();
assert!(
!ok,
"protocol v0 served a --shallow-since past every commit that v2 refuses. Every defect \
in this class so far has been green on v2 and broken on v0"
);
assert!(
stderr.contains("no commits selected"),
"v0 refused for a different reason than v2:\n{stderr}"
);
}
/// **The other direction, and it is what makes the two arms above mean
/// anything.** An ordinary cutoff must still be served, and served the way git
/// serves it — a seed filter that cut too much would satisfy every assertion
/// above while breaking `--shallow-since` outright.
fn an_ordinary_since_matches() {
let scene = Scene::dated(Kind::Sha1);
let mine = scene.root.join("gunnar-between");
let stock = scene.root.join("stock-between");
scene
.client(ProtocolVersion::V2)
.args(["clone", "-q", "--shallow-since"])
.arg(between())
.arg(scene.url())
.arg(mine.to_str().unwrap())
.ok();
Git::new()
.cwd(&scene.root)
.args(["clone", "-q", "--shallow-since"])
.arg(between())
.arg(scene.local_url())
.arg(stock.to_str().unwrap())
.ok();
let commits = |dir: &std::path::Path| -> usize {
git_in(dir)
.args(["rev-list", "--count", "HEAD"])
.ok()
.parse()
.unwrap()
};
let shallow = |dir: &std::path::Path| -> Vec<String> {
let mut lines: Vec<String> = std::fs::read_to_string(dir.join(".git").join("shallow"))
.unwrap_or_default()
.lines()
.map(str::to_owned)
.collect();
lines.sort();
lines
};
assert_eq!(
(commits(&mine), shallow(&mine)),
(commits(&stock), shallow(&stock)),
"gunnar and stock git disagree about an ordinary --shallow-since"
);
// Not vacuous: the cutoff really cuts, so "they agree" is not "they both
// sent the whole repository".
assert!(
commits(&mine) < 5 && !shallow(&mine).is_empty(),
"the cutoff between B and M selected everything ({} commits, {:?} cut points), so this \
arm compares two full clones and would agree however `since` were implemented",
commits(&mine),
shallow(&mine)
);
}
/// **The other way to select nothing, because the refusal names both.**
///
/// `compute`'s error says *"deepen-since and deepen-not between them exclude
/// every requested tip"*, and until this case that claim was half asserted:
/// only the date path had ever reached it. `--shallow-exclude=main` while
/// cloning `main` removes every want through the exclusion set instead.
///
/// MEASURED oden 2026-08-05: stock git 2.53.0 answers this with the identical
/// `fatal: no commits selected for shallow requests` and leaves no clone
/// behind, so the two paths really are one contract and not two.
fn deepen_not_excluding_everything() {
let scene = Scene::dated(Kind::Sha1);
let (stock_ok, _, stock_err) = Git::new()
.cwd(&scene.root)
.args(["clone", "-q", "--shallow-exclude=main"])
.arg(scene.local_url())
.arg(scene.root.join("stock-excl-all").to_str().unwrap())
.run();
assert!(
!stock_ok,
"stock git served a clone whose only branch was excluded, so there is no contract here"
);
assert!(
stock_err.contains("no commits selected"),
"stock git refused for another reason:\n{stock_err}"
);
for protocol in [ProtocolVersion::V0, ProtocolVersion::V2] {
let (ok, _, stderr) = scene
.client(protocol)
.args(["clone", "-q", "--shallow-exclude=main"])
.arg(scene.url())
.arg(
scene
.root
.join(format!("gunnar-excl-all-{protocol:?}"))
.to_str()
.unwrap(),
)
.run();
assert!(
!ok,
"{protocol:?}: gunnar served a clone whose only branch was excluded, where stock \
git refuses"
);
assert!(
stderr.contains("no commits selected"),
"{protocol:?}: gunnar refused, but not in git's words:\n{stderr}"
);
}
}