Everything in gunnar that is not finished — one ranked, verified inventory
Class:
reasoning. Findings, not fixes. Taken 2026-08-05 againstorigin/masterat491faf9, then re-checked at the tipbcf7f11— the one commit between them touchesbench/examples/fetkaos/mod.rsalone (43 insertions) and no row here, and everyfile:linebelow was re-read atbcf7f11. Every entry was verified against the code or the filesystem, never quoted from a comment. Where a claim could not be settled, it says so.Position or hole is the distinction that matters. A position is a thing gunnar does not do and has written down why. A hole is a thing gunnar does not do and nobody wrote down.
push-optionsis a hole.object-infois a position.
0. What the two methods actually yielded, honestly
Method 1 — sweeping gunnar's own source for admissions — found almost nothing, and that is a real result. Over 367 Rust files: 3 TODO/FIXME markers, and all three are quotations of gitoxide's TODOs, not gunnar's. Zero todo!(), zero unimplemented!() outside a doctest ellipsis and a read-only test fixture. Zero cfg(FALSE). Sixteen SKIPPED: sites, and fourteen of them are env-var-driven bench arms that are supposed to be opt-in; xtask ci's preflight refuses to run the suite at all when the interop tools are missing, precisely so a SKIPPED: can never become a green. The discipline is genuine and grepping for despair does not find this product's gaps.
Method 2 — diffing against git's own advertisement — is where the yield was, and it produced the single worst finding in this document (§1.1): a capability gunnar advertises on the wire, parses off the wire, and then discards.
Method 3 — things that exist but nothing reaches — produced the second (§3.1): a fail-open probe that is firing right now in every one of today's lane worktrees and costing each of them 40 tests.
And a result that should be said as plainly as the failures. Every guard in xtask/ was checked for whether it can report red, and they are the strongest part of this repository. xtask/src/guard.rs reads resolved cargo tree output rather than manifests (:639), propagates a failed resolve with ? (:975) so a broken command cannot read as "no forbidden crate", and closes the empty-graph trap (Rule::VacuousGraph, :96), the phantom-rule trap (check_rule_names_can_fire, :927) and the stale-exception trap (StaleDeviation). cycle_svg.rs's citation guard opens the cited file, indexes the cited line and asserts the anchor token is on that line (:1678), with a census asserting opened + foreign == all().len() and foreign > 0 so the foreign branch cannot go dead. vendor_patch.rs applies its contains() markers to code_only(&src) and has a dedicated test (:326) proving a marker surviving only in a comment does not count — the exact hollow-guard shape found elsewhere today. version_matches_tag.rs:122 asserts !tags.is_empty(). Three separate sweeps found no contains() guard satisfiable by a comment. I did not find a blind guard in xtask. The gaps below are places with no guard, not places with a fake one.
1. RELEASE-BLOCKING
1.1 push-options is advertised, parsed, and dropped on the floor · HOLE
Where: advertised crates/gunnar-wire/src/caps.rs:245 · parsed crates/gunnar-wire/src/receive_pack.rs:384 · carried receive_pack.rs:248 · consumed nowhere.
What proves it. grep push_options across all shipped (non-test) server code returns exactly one consumer:
crates/gunnar-cli/src/server/transport.rs:704
push_options = outcome.push_options.len(),
a count, in a log line. The values are never read. And the one component that could act on them is structurally blind: PushFacts (receive_pack.rs:100–118) has three fields — objects, new_objects, pack_bytes — and no options field, so PushGate::check cannot see them even in principle.
So git push -o ci.skip=true -o reviewer=alice succeeds, gunnar reads both strings off the wire, logs 2, and throws them away. This is the one place gunnar makes a promise on the wire it does not keep.
Why it is a hole and not a position. .nornir/wire-design.md:169 and .nornir/TOTAL-PROMPT.md:1265 both say only "read the push-options section". Neither says "and ignore them". Nobody decided this; it just stops.
Cost to close: small. One push_options: &'a [String] field on PushFacts, threaded from receive_pack.rs:459 into the apply call at :453, plus a red-first gate test. Half a day. Or one sentence of written position — but then the honest move is to stop advertising it.
Blocks release: yes, on the cheap end. Either wire it or write it down.
RESOLVED 2026-08-05 (blocker-five lane) — wired, not written down.
PushFacts::push_optionsandPushContext::push_optionsexist;gunnar_policy::PushOptionsGaterefuses onallowed/requiredpatterns;PolicyGateinserver/transport.rspasses them through.PushContext's field isOption<&[String]>so an unwired caller is refused, not treated as "the client sent none". Proven against stockgit push -oover real SSH (gunnar-cli/tests/push_facts.rs) and at the wire (gunnar-wire/tests/protocol.rs), both seen red by unwiring each seam.
1.2 The capability audit's own safety claim is false for exactly the list that contains the bug · HOLE in a guard
.nornir/protocol-capability-audit.md:15–19 says the advertisement is generated from one table that also generates the parser, so "'advertised but not honoured' is not something this codebase can express."
Verified false. That table generates only the v2 fetch= and ls-refs= argument lists. The entire v0 list is a hardcoded vec![] (crates/gunnar-wire/src/caps.rs:216–232) and the entire receive-pack list is another (caps.rs:238–249). push-options is a literal string in the second one. The audit's guarantee does not cover the list its own §2 got wrong.
Cost to close: the doc sentence is a two-minute fix and should happen today. Extending the generation to the v0 and receive-pack lists is a day and is the real fix. Blocks release: the doc sentence, yes — it is the sentence a reader uses to decide they need not check.
RESOLVED 2026-08-05 (blocker-five lane) — the real fix, not just the sentence.
caps::ADVERTISEDnames all three surfaces;caps::advertiseis the only thing that renders one; bothvec![]s are gone, and so is the fourth hand-written list nobody had counted — the v2 capability names inupload_pack.rs::write_capability_advertisement, in a different file from the other three. Every row carries aHonouredvalue: afileplus a substring of the line of code that reads it, or a sentence-length argument for why there is nothing to read it (three rows:agent,quiet,server-option).gunnar-wire/tests/advertisement.rswalks every row on every surface and strips comments before looking, becausecontains("push-options")is otherwise satisfied by the paragraph explaining push-options two lines above the call. Seen red three ways: a broken consumer, a capability nobody reads, and a literal pushed onto the rendered list beside the table. The audit's §0 sentence is corrected and says what was actually true.
1.3 The front page names a version this tree cannot produce · drift
README.md:50 (and its source .nornir/README.md:48): "Every line below was run end to end on oden, 2026-08-05, against gunnar 0.1.0 (v1.1-3-g3cfbf17)."
Measured: Cargo.toml:100 → version = "1.1.0"; git describe --tags --abbrev=7 origin/master → v1.1-29-gbcf7f11. The binary prints gunnar 1.1.0 (v1.1-29-g…). 0.1.0 is unreachable.
The same stale string is in crates/gunnar-cli/src/lib.rs:174, present tense and therefore false: "SshConfig::default() produces SSH-2.0-gunnar_0.1.0". It now produces SSH-2.0-gunnar_1.1.0.
18 sites carry 0.1.0. Most are dated historical measurements or synthetic test fixtures and are fine. The ones that are present-tense claims about this tree are README.md:50, .nornir/README.md:48, crates/gunnar-cli/src/lib.rs:174 and bench/examples/forge/mod.rs:3347 (see §2.1).
Cost: minutes. Blocks release: yes — it is the first version string a reader sees on a repo shipping today.
RESOLVED 2026-08-05 (blocker-five lane).
.nornir/README.mdnow saysgunnar 1.1.0; the rootREADME.mdis regenerated from it.xtask/tests/readme_version.rsscans both forgunnar <semver>literals against[workspace.package] version, asserts a non-zero census so deleting the sentence cannot turn the guard off, and asserts the root is the source verbatim.xtask::release_versionis now the one reader of the workspace version, shared withversion_matches_tag.rs(LAW 5). Seen red against the exact byte sequence that shipped. (crates/gunnar-cli/src/lib.rs:174andbench/examples/forge/mod.rs:3347are NOT fixed by this lane — they are prose in other lanes' files.)
1.4 Incoming objects are never content-checked, and land before the gate · HOLE, silent
Where: crates/gunnar-wire/src/receive_pack.rs. Zero hits for fsck, validate or quarantine in the whole receive path. The module's own header gives the order: PACK → index → connectivity → policy gate → ref transaction. Objects are in the ODB before PushGate runs.
Stock git receive-pack has transfer.fsckObjects and a quarantine directory for exactly this. gunnar's outgoing packs are fsck'd — but only in tests (crates/gunnar-pack/src/copy.rs:1020). Incoming ones are not checked at all, so a malformed tree or commit is storable.
Honest sizing, not alarm. WantPolicy::ReachableFromRefs is the default (crates/gunnar-wire/src/upload_pack.rs:96), so objects from a rejected push are not fetchable — this is a disk-space and integrity problem, not a disclosure one. And connectivity is verified before any ref moves, which is the harder half.
Cost: medium for real fsck; small for a written position, which is what is actually missing. Blocks release: the written position, yes. Shipping a forge that accepts unvalidated object bytes is a defensible choice; shipping one where nobody wrote down that it does is not.
RESOLVED 2026-08-05 (blocker-five lane) — written position, MEASURED.
.nornir/receive-quarantine-position.md. The measurement, not the inference: a refused push leaves 3 of 3 objects and 7 781 pack bytes on the server whilerefs/heads/mainnever appears —gunnar-cli/tests/push_facts.rs::a_refused_push_leaves_its_objects_in_the_object_database, stockgit pushover real SSH. That test pins the CURRENT behaviour on purpose: it goes red the day quarantine lands, and names the document. Not implemented: quarantine needs a two-phasePackIngestacross the seamgunnar-wiredeliberately does not own, and the appliance path has nowhere to stage into. fsck is the cheaper half and is ranked first in the document.
1.5 The audit and the CI decision record both describe, in the present tense, a file deleted two days ago · stale, and it is the honesty mechanism that is stale
.nornir/stinky.md S-033 is one of the six IN-PROGRESS entries — i.e. it is on the open list — and it reports a measurement:
"
.github/workflows/ci.ymlparses.python3 -c "import yaml; print(yaml.safe_load(open('.github/workflows/ci.yml')))"yields adictwith keysname,True…,permissions,concurrency,env,jobs. The fullwidth#placeholder is gone." "The file now opens with a banner reading⚠ THIS WORKFLOW HAS NEVER RUN."
.nornir/ci-options.md:271 restates it: ".github/workflows/ci.yml exists, is valid YAML, defines five jobs" — and §4 of that document is an entire settled decision about the file, including "One real defect was found and fixed in that file."
There is no .github/ directory. ls, git ls-files and a full-tree find all return nothing.
It is stale, not fabricated, and the difference matters. The file was real: added at b07ca38, edited at acbcd1b and at 7f9d37b ("Say plainly that the CI workflow has never run"), and deleted at e50b962, 2026-08-03 — "Read the README, PLAN and the dependency arguments back out loud". The measurement was true when it was taken. The file was then removed and neither record noticed, so today the audit carries a quoted python invocation against a path that does not exist.
This is the sharpest instance of the thing Rickard is complaining about: the mechanism that exists to stop him being told a thing is done is itself asserting a measurement of something that is gone. It also fully explains §3.7 — the reason nobody noticed there is no CI is that two records say there is.
RESOLVED 2026-08-05 (blocker-five lane). Both records corrected, and the second half — what CI does gunnar actually have — decided rather than left open:
cargo xtask ci, typed by a human, no hosted CI, none added. Written up in.nornir/ci-options.md("The decision") andstinky.mdS-033, which is now WONTFIX rather than an open entry quoting a deleted file. The trap underneath it (§3.1) is fixed too.
Cost: minutes to correct both records. Blocks release: yes — an audit entry that cites a deleted file is worse than no entry, because it is load-bearing for a reader deciding what is covered.
2. CORRECTNESS / MEASUREMENT INTEGRITY
2.1 The gitea/Forgejo headline table can still be measured on a stale binary, and the guard that would catch it is already a dependency · HOLE, LAW 5 + LAW 2
Where: bench/examples/forge/mod.rs:3293 (gunnar_binary) and :3350 (gunnar_binary_identity).
gunnar_binary() refuses absence — it demands CARGO_TARGET_DIR be set and the file exist — but never staleness. It does not compare the binary's mtime against crates/. gunnar_binary_identity() then records version, size and mtime on the row. The function's own doc comment says the suite fell into this hole on 2026-08-04 and measured a ten-hour-old build while reporting the tree it was launched from.
The guard exists, in this repo, and bench/ already depends on it. installtest/src/container.rs:217 locate_binary_for_measurement does exactly the mtime comparison and refuses (:265–276), treats an unanswerable question as a no (:257), and even reads GUNNAR_BENCH_BINARY — it was written to serve the bench. bench/Cargo.toml:83 declares gunnar-installtest = { path = "../installtest" }. But bench/examples/forge/mod.rs never calls it; only bench/examples/nornir-bench.rs:5630 does.
Naming a directory is not naming a build: a ~/.cache/nornir-bench-target from yesterday satisfies gunnar_binary() exactly as well as one from a minute ago. The README's front-page comparison table is generated from this harness.
Cost: small — call the existing function. Blocks release: no, but it is the number the release is being sold on.
2.2 The bakeoff corpus is an unpinned, uninvalidated mirror of a live checkout · HOLE
bench/examples/forge/mod.rs:3094 — the real-repository fixture defaults to /home/rickard/git/<repo>, repo defaulting to nornir (forge/mod.rs:3070) — a checkout being committed to by other lanes all day. It is mirrored through cached_repo (bench/examples/nornir-bench.rs:801), whose cache is keyed on name alone, marked complete with .gunnar-bench-complete, and never invalidated.
So the corpus is whatever nornir was at on the first run, forever; nothing in the repo or on the reported row says which commit that is. Deleting the cache silently re-corpuses the benchmark against a different nornir.
The README's conditions line records host, cores, rounds, loadavg and cgroup limits — it does not record the corpus commit. Cost: small (record the source HEAD on the row; ideally key the cache on it). Blocks release: no.
2.3 bifrost, the repository with the corrupt pack, is still in both corpus lists · HOLE
I got this wrong on the first pass and the correction is the finding. Two gunnar-znippy tests build their entire corpus by mirroring 19 named checkouts out of /home/rickard/git, and bifrost is entry 18 of 19 in both:
crates/gunnar-znippy/tests/refs_overlay_after_a_push.rs:79(list at:61–80, root at:111,GUNNAR_REFS_REAL_SRCdefault/home/rickard/git)crates/gunnar-znippy/tests/refs_from_archive.rs:70(list at:53–72, root at:76)
What was fixed was only the fixture, not the corpus. refs_overlay_after_a_push.rs:85–107 documents the bifrost incident at length — gunnar was right to refuse that push, the fixture was wrong — and the fix moved FIXTURE_REPO to funnel-core (:107). The 19-member corpus loop is untouched: it still clones bifrost, still lands on eprintln!("skipping {name}: mirror push failed: …") (refs_from_archive.rs:167, refs_overlay_after_a_push.rs:208), and the floor that guards the loop is
crates/gunnar-znippy/tests/refs_from_archive.rs:286
assert!(checked >= 12, "only {checked} of the 19 members were checked …");
so seven of nineteen members may silently drop out and the test still passes, with the reason only on stderr, which cargo test swallows unless --nocapture. The verdict of both tests is a function of nineteen unrelated checkouts staying healthy in a tree that seven lanes are writing to.
The floor is real work and stops the vacuous case, which is why this is a correctness item and not a release blocker. But bifrost is a known-corrupt member sitting inside the tolerance.
A third site is worse and simpler: crates/gunnar-coldtier/bench/examples/generation-chain.rs:198 hard-codes PathBuf::from("/home/rickard/git").join(repo) with no env override at all, and skips missing repos with eprintln! + continue → an empty CSV that looks like a clean run.
Cost: small — drop bifrost from both lists (or fsck each source before mirroring it), raise the floor to 19 or make a dropout fatal, and give generation-chain.rs the env var its two siblings have. Blocks release: no.
2.4 S-043 — Policy.* has no store, and the appliance therefore protects nothing · written, open, real
Verified still true at 491faf9: all five methods at crates/gunnar-cli/src/server/control_plane.rs:829–857 return ControlError::Unimplemented(PROTECTION_GAP); gunnar-policy reads gunnar-policy.json from beside each repository on disk (crates/gunnar-policy/src/config.rs).
This is not a hole — .nornir/stinky.md S-043 states it in full, including the part that matters: on the OS-less appliance there is no filesystem to put that file on, so branch protection silently does not exist there. The refusal shape is right (explicit Unimplemented, never an empty success). It is the largest open correctness entry, spans four crates, and is correctly ranked as its own piece of work. Blocks release: no, provided the appliance's protection gap is said out loud in the release notes.
2.5 Silent holes the docs never mention (each needs one sentence, not code)
Verified absent, and absent silently — no position anywhere in tree:
refs/namespaces/(GIT_NAMESPACE) — zero hits. Two false friends make this easy to mis-read as present: gunnar's ownNamespace(cli.rs:77) is org/repo tenancy, andGIT_NAMESPACEincrates/gunnar-policy/src/signature.rs:53is the sshsig namespace.- alternates — appears only as a dumb-path refusal (
crates/gunnar-http/src/route.rs:63) and a test asserting a clone makes none. No object dedup between forks. proc-receive— zero hits; Gerrit-style ref rewriting has no equivalent.session-id— zero hits. Cheap; nothing depends on it.- shallow lines on the push path —
receive_pack.rs:504–507drops clientshallowlines with acontinue("They are not commands"), whileconnectivity.rs:158walks the full closure. INFERRED, not measured: pushing from a shallow clone into a repo lacking the graft parents should fail as a missing object. The dropped lines are exactly the data needed to decide correctly. This one deserves a measurement before it is ranked.
git-upload-archive is the counter-example and the good shape: also absent, but cleanly refused and tested (crates/gunnar-wire/tests/real_git_surface.rs:1245, crates/gunnar-ssh/tests/command_parsing.rs:325) — a position, not a hole.
2.6 Five real-corpus tests are permanently green because nothing in the repository arms them · HOLE
Each is let Ok(v) = env::var(..) else { eprintln!("SKIPPED: …"); return; } — to cargo test that is a pass with zero assertions executed. The env var is set by nothing in the tree: no xtask step, no manifest, no script.
| test | variable |
crates/gunnar-store/tests/repack_writes_a_bitmap.rs:460 |
GUNNAR_BITMAP_REAL_REPOS |
crates/gunnar-wire/tests/bitmap_cost.rs:282 |
GUNNAR_BITMAP_REAL_REPOS |
crates/gunnar-wire/src/bitmap.rs:1053 |
GUNNAR_BITMAP_REAL_REPOS |
crates/gunnar-store/tests/repack_recomputes_deltas.rs:767 |
GUNNAR_REAL_REPOS |
crates/gunnar-znippy/tests/cold_tier_wired.rs:657 |
GUNNAR_COLD_TIER_REAL_REPO |
xtask ci's preflight closes exactly this class for the tool case — it refuses to run at all rather than let an interop test print SKIPPED: and pass (xtask/src/main.rs:678–686). There is no equivalent for the corpus case, and the bitmap arms are the ones that would tell you whether the bitmap reader actually pays.
Cost: small — extend preflight to the corpus variables, or set them in ci. Blocks release: no.
2.7 repack_recomputes_deltas.rs compiles only by cross-crate feature unification · latent
crates/gunnar-store/tests/repack_recomputes_deltas.rs:1 is #![cfg(all(feature = "fs", feature = "repack-delta"))]. xtask ci passes gunnar-store/fs but not gunnar-store/repack-delta (xtask/src/main.rs:874). It compiles today only because crates/gunnar-cli/Cargo.toml:71 lists "gunnar-store/repack-delta" inside the default server feature and --workspace unifies them.
Under cargo test -p gunnar-store --features fs the file compiles to nothing and reports nothing. crates/gunnar-wire/Cargo.toml:57–63 documents this exact trap in the other direction — "a crate whose own tests only pass when a sibling happens to be in the same build is not tested" — so the rule exists and was applied to gunnar-wire and not to gunnar-store. Cost: one word in the ci feature list. Blocks release: no.
2.8 S-050's own defect class is live in the README's picture, in the half the new guard cannot see · HOLE in a guard
S-050 (stinky.md:4264, DONE) is about diagram citations that point at closing braces. 491faf9 closed it by adding an anchor to Evidence — the cited line must contain a named token (xtask/src/cycle_svg.rs:55,67).
The guard only sees Evidence::at(…).naming(…). It does not see the hard-coded prose in the note: strings — and those are rendered into the committed SVG. Verified by opening each cited line:
| generator | cites | the line actually reads |
xtask/src/cycle_svg.rs:328 |
gunnar-coldtier/src/lib.rs:186 |
} |
xtask/src/cycle_svg.rs:345 |
upload_pack.rs:1256 |
} |
xtask/src/cycle_svg.rs:380 |
serve.rs:387 |
} |
xtask/src/cycle_svg.rs:202,380,1399 |
stores.rs:279 |
&self, |
xtask/src/cycle_svg.rs:1974 |
receive_pack.rs:595 |
} |
Four of the five are in the shipped picture: grep of assets/gunnar-znippy-cycle.svg finds lib.rs:186, upload_pack.rs:1256 and serve.rs:387 once each and stores.rs:279 three times. That SVG is embedded in README.md. (receive_pack.rs:595 is in the generator but not in the current SVG.) For the coldtier one the anchored Evidence for the same fact points at lib.rs:612 (refs_reserved_builder) — so the correct line is known, twenty lines away, in the same file.
Every anchored citation resolves — I checked them, and the anchor guard is good work. The finding is that it was declared DONE while covering one of the two ways a citation gets into the diagram. Cost: small — route the note: prose through Evidence too, which is LAW 5 anyway. Blocks release: no.
2.9 P-026 corrected P-001's headline; P-001's own Status line still carries the wrong number · DRIFTED
P-026 (performance-design.md:2910, FIXED, severity blocker) exists solely to say that P-001's famous 18.336× bytes / 219.963× CPU is a synthetic fixture's, that on 19 real repositories it is 3.4× the bytes and 18× the CPU, and — its own words, :2919 — that the wrong figure "is quoted in six places in this tree and was quoted to Rickard repeatedly on 2026-08-04."
The correction landed in exactly one file. crates/gunnar-store/src/object.rs:152 says 3.4×. It is the only place in the tree that does.
P-026's Status promises only "the doc comment everyone reads it from is corrected", so P-026 is narrowly honest and I am not calling it false. The problem is what it left standing twenty lines above itself, in the same file:
performance-design.md:309 P-001 — Status: **DONE 2026-08-03** … **18.3× fewer bytes**
The old figure survives across 10 files (39 raw occurrences, not all of them headline uses — I did not classify each one, and some are legitimately about the synthetic fixture). This is the number a release announcement would quote, off the Status line of the entry it belongs to. Cost: minutes. Blocks release: no, but fix it before anything is written for publication.
3. OPERABILITY / COVERAGE
3.1 cargo xtask ci run from any lane worktree silently drops the entire cold-tier suite · HOLE in the harness
This is the live instance of the defect class that has bitten all day, and seven lanes are sitting in it right now.
xtask/src/main.rs:745 resolves the znippy checkout by joining crates/gunnar-coldtier with the path = "../../../znippy/..." out of its own manifest — i.e. <parent-of-the-checkout>/znippy. From /home/rickard/git/gunnar that is /home/rickard/git/znippy, which exists. From a lane worktree such as /home/rickard/scratch/cargo/<lane>/gunnar it is /home/rickard/scratch/cargo/<lane>/znippy, which does not.
Measured, in my own worktree: /home/rickard/git/znippy/plugins/native/znippy-plugin-git/Cargo.toml exists; /home/rickard/scratch/cargo/unfinished/znippy/... does not. So znippy_checkout_present() returns false and run_znippy_tests returns true (main.rs:733–757), and the same location dependency fails the coldtier detached step.
To the harness's very great credit this is fail-open by design and it says so loudly — it prints NOT RUN, then names by file the three suites it did not cover, and the probe is asserted in both directions after it was wrong for a day. That is the right shape. The finding is not that the probe is blind; it is that the probe's answer is a function of where the worktree lives, and every lane lives where the answer is no. Any xtask ci green quoted from a lane worktree — including "1331 passes / 0 failures" — excludes cold_tier_wired.rs, refs_from_archive.rs and refs_overlay_after_a_push.rs, the only assertions that the cold tier is reached at all.
What it costs, counted: 40 tests / 4 450 lines in two crates the root Cargo.toml:79–93 excludes and that -p <name> cannot match either, because both carry [workspace] tables of their own (crates/gunnar-coldtier/Cargo.toml:52, crates/gunnar-znippy/Cargo.toml:60):
| file | tests | lines |
crates/gunnar-znippy/tests/cold_tier_wired.rs |
9 | 1 273 |
crates/gunnar-znippy/tests/refs_from_archive.rs |
1 | 295 |
crates/gunnar-znippy/tests/refs_overlay_after_a_push.rs |
4 | 908 |
crates/gunnar-coldtier/tests/*.rs (6 files) |
26 | 1 974 |
refs_overlay_after_a_push.rs is still referenced by exactly one line in the whole tree outside itself — xtask/src/main.rs:1020 — and that line is inside the NOT RUN message.
The three sibling detached steps fail loudly from a lane worktree (installtest, bench-compile, coldtier-bench-compile all hit unresolvable ../../edda, ../../draupnir, ../../tunnr, ../../../znippy paths), which is the correct behaviour and makes the silent one stand out.
Cost: small — resolve the sibling from a GUNNAR_ZNIPPY_ROOT env var or from git rev-parse --git-common-dir's parent rather than from the worktree's parent, so a worktree inherits the main checkout's neighbours. Blocks release: no, but it invalidates the provenance of every CI green taken from a lane today.
RESOLVED 2026-08-05 (blocker-five lane) — it REFUSES rather than inheriting.
xtask/src/main.rs::cold_tiersplits "absent" in two. No znippy anywhere is still a legitimateNOT RUNthat passes; absent beside a linked worktree whose main checkout has one isColdTier::OnlyInTheMainWorktreeand fails the step, naming the checkout to run in. Inheriting the main checkout's neighbour was rejected: cargo resolves the path dependency relative to the manifest, so the coldtier crate genuinely cannot be built from the worktree — a probe that answered "present" would hand the step to cargo and get a resolve error instead of a sentence. One probe, both steps (LAW 5). Seen red by revertingcold_tierto the old behaviour against a realgit worktree add.
3.2 cli.rs:35 tells every user "no smart-HTTP" while 1 636 lines of smart-HTTP ship in the tree · drift, position vs code
crates/gunnar-cli/src/cli.rs:35, in long_about — i.e. gunnar --help:
"Transport is SSH only: no smart-HTTP, no git://, and no git or ssh subprocess anywhere in the server."
Verified in tree at origin/master: crates/gunnar-http/ is 1 636 lines across five modules, is a workspace member (Cargo.toml:62), serves all four smart-HTTP URLs (crates/gunnar-http/src/lib.rs:15–29), has a live listener (crates/gunnar-cli/src/server/serve.rs:597–626, logging "gunnar smart-http listener: info/refs, git-upload-pack, git-receive-pack"), is resolved and size-asserted by the dependency guard on every run as the appliance+http profile (measured: 282 crates, 267 third-party), and its test suite is run by cargo xtask ci with --features …,gunnar-cli/http (xtask/src/main.rs:860, :875).
SSH-only is still the position for the shipped default build — http is not in default = ["server", "client"], so the sentence is true of the binary a user gets. But it is printed unconditionally by a binary that may have been compiled with the feature, and it reads as "gunnar does not have this" when what is meant is "this build does not enable this". Two more places restate the older, now-wrong form: xtask/src/guard.rs:342 ("§0's rule (no smart-HTTP …) is unaffected: gunnar registers no HTTP route" — route.rs registers four) and .nornir/ci-options.md:149.
The line worth keeping. The reason this is a position and not an inability is that the mechanism already spans two protocols: gRPC authenticates with an sshsig credential from the same §5 key table and the same ACL SSH uses (crates/gunnar-cli/src/cli.rs:176, D9 closed 2026-08-03). gunnar chose not to; it is not that gunnar could not.
Cost: minutes (three sentences). Blocks release: no, but it is user-facing help text that understates the product.
3.3 stock_clients.rs scopes itself against a premise that is false
crates/gunnar-ssh/tests/stock_clients.rs:15: "They do not prove that a clone works. gunnar-wire does not exist yet, so the transport behind the seam is a test double." crates/gunnar-wire/ exists and carries the whole protocol. The assertions themselves remain honest — they assert what was observed — but the stated reason for their narrowness is gone. Cost: minutes. Blocks: no.
3.4 README's audit counts are stale, in the flattering direction
Measured at 491faf9:
| README says | measured | |
stinky.md 51 entries |
51 | ✅ |
stinky.md 20 open |
18 open — see the named list below | ✗ overstates by 2 |
performance-design.md "is 18" |
22 entries (P-001…P-028, P-019…P-024 unused), 11 open (10 TODO + 1 PARTLY DONE) |
✗ matches neither reading |
The tally, named so it can be re-checked rather than re-argued. All 51 ### S- headings carry exactly one Status: line and the five buckets sum to 51: 31 DONE · 6 IN-PROGRESS · 12 TODO · 1 INVALID · 1 WONTFIX.
IN-PROGRESS(6): S-018, S-025, S-033, S-044, S-046, S-047TODO(12): S-003, S-013, S-014, S-016, S-020, S-031, S-034, S-035, S-036, S-043, S-048, S-049
18 open. A second sweep of this file independently reported 29 DONE / 14 TODO, i.e. 20 open, matching the README — that tally is wrong, and it is recorded here because it is the kind of near-miss that would otherwise have let the README line stand. Note also that S-033, one of the six open entries, is §1.5's: it is open work on a file that was deleted.
PLAN.md is staler still, and it drifts in the unflattering direction, which matters more. It dates itself 2026-08-03 and its status block says:
PLAN.md:18 audit 45 entries 7 done · 3 in progress · 35 open
PLAN.md:19 scale 18 entries all open (6 blockers)
Measured today: audit is 51 entries, 31 done, not 45/7. Scale is 22 entries, 11 done, not "18, all open" — P-001, P-007, P-008, P-009, P-012, P-025 and five more are closed with measurements attached.
So the one file nominated as the one live plan tells a reader that none of the performance work is finished on the day the thing ships, when half of it is. It also says "Tests: 517 workspace (last full green)" against the 1331 quoted today. PLAN.md:14 says "Status lives in those files, not here" — the header block is doing exactly what the file forbids.
And the forward plan is stale too, which is worse than the counts. PLAN.md's "Next, in dependency order" still lists as item 1:
repack()·S-006— "No cold tier ever forms; pushed packs accumulate without bound. Everything about znippy storage is downstream…"
S-006 is DONE in .nornir/stinky.md:486. crates/gunnar-store/src/repack.rs is 102 138 bytes of real code and gunnar gc is a live verb (crates/gunnar-cli/src/cli.rs:109). Item 3, "Delta reuse · P-001", is **DONE 2026-08-03**, landed at 6e65beb with 18.3× fewer bytes measured. Item 4, "Scale correctness · S-001, S-002, S-004, S-010" — all four DONE. Only item 2 (P-005, P-006, P-013, all TODO) is genuinely still next.
So three of the four items on the critical path of the one live plan are closed, and the plan says they are the next things to build. Anyone using PLAN.md to decide what shipped today would get it backwards.
Cost: minutes, and all five numbers plus the Next list should be generated from the two records rather than typed — they have now drifted twice. Blocks release: no, but it is the file someone will read to decide what shipped.
3.5 Doc claims that name a file which does not exist
Checked 334 distinct file paths cited in README.md, PLAN.md and .nornir/*.md against the filesystem. Almost all resolve; most apparent misses are deliberate references to other repos (gix-odb, znippy, korp-installer, nornir, skade) or to git's own t/perf/ scripts, which is correct usage. The genuine ones:
.nornir/appliance-design.md:100— "tests/zero_shell_guard.rswas the missing half, written as a separate file". That file does not exist; the check moved intoxtask/src/guard.rs:901andxtask/tests/guard.rs:401, both of which say so. The design record does not..nornir/appliance-design.md:312— "containers/Containerfile.bin-muslruns …", present tense.containers/is deleted from git;xtask/src/appliance.rs:330says "This used to".xtask/src/main.rs:136—cargo xtask --helpstill says "build every appliance container variant in containers/". The mechanism now materialises the Containerfile from.nornir/build-variants.toml(xtask/src/images.rs:29). User-facing help naming a deleted directory..nornir/design.md:557/.nornir/TOTAL-PROMPT.md:1752listgunnar-guide.md,gunnar-for-idiots.md,storage-design.md,grpc-guide.mdas "Planned:" — none exist. That is honest labelling, not a finding, and is recorded here only so nobody re-reports it.
Four more of the same shape, found by the same technique:
xtask/src/main.rs:19points a reader at.github/workflows/ci.yml— "see its header". There is no.github/directory.xtask/src/cycle_svg.rs:16namesxtask/tests/cycle_svg.rs. That file does not exist; the assertions live in the in-file#[cfg(test)]module (:1712,:1944) and do run, so the guard is armed and only the address is wrong.crates/gunnar-znippy/tests/cold_tier_wired.rs:842and:1047document the run command ascargo test -p gunnar-cli --features znippy --test cold_tier_wired.gunnar-clihas noznippyfeature any more and the file is not in that crate. Anyone following the instruction gets "no such feature" — on the file that §3.1 already shows is the least-run in the repo.vendor/gix-features/PATCH.md:179claims "xtask/src/vendor_patch.rsis run bycargo xtask ci".task_cinever calls it. It is reached — via its own#[cfg(test)]module under theteststep, and those tests read the live tree — so the claim is true by accident, not by design. Acireorganisation that drops theteststep silently disarms the guard that stops a publish shipping stockgix-features.
And six citations that name a real file at a line that is not there — of 165 fully-qualified in-repo citations opened, so ~3.6% rot, which is low but not zero and clusters on the most-quoted functions:
| record | cites | actually |
stinky.md:665, :820 |
crates/gunnar-cli/src/main.rs:41-44 |
the file is 17 lines |
stinky.md:3737, :3768 |
xtask/src/main.rs:227-273 = task_ci |
fn task_ci is at 803 |
ci-options.md:261 |
xtask/src/main.rs:140-177 = the tool check |
fn task_preflight is at 651; 140-177 is help text |
concurrency-design.md:92 |
copy.rs:374-384 = thread_limit: Some(1) |
it is at 1316 |
performance-design.md:1509 |
access.rs:276-297 |
the file is 214 lines |
stinky.md:2634 |
real_git_reads_what_we_wrote.rs:144-160 |
the file is 154 lines (the substance at 144-154 is right; the range overruns) |
The xtask/src/main.rs:227-273 one is worth naming twice: it is the citation S-033 uses (§1.5) to argue that cargo xtask ci is a complete gate. The argument is correct and the address is wrong.
Verified present and correct, since the negative is the point: all four assets/*.svg|webp, all three docs/*.pdf, bench/Containerfile, release/docs-nornir.toml, and dwarves/crates/dwarves/tests/gunnar_appliance_iso.rs (the evidence .nornir/real-metal-checklist.md:17 cites, in the dwarves repo).
3.6 Code nothing reaches
gunnar_policy::ancestry::reachable_from—crates/gunnar-policy/src/ancestry.rs:184. 44 lines of graph walk. A workspace-widegrep -rw reachable_fromovercrates/,xtask/,bench/andinstalltest/returns only the definition — while its own doc comment says "Used by tests and by callers that want the closure rather than a yes/no." The two siblings in the same file (is_descendant_of,introduced_commits) are genuinely used. Delete it or use it.gunnar-wire/stages(30stage::call sites) andoidprobe(23oidprobe::bumpcall sites) are compiled by exactly one place each —bench/Cargo.toml:190and:77— andxtask/src/main.rs:787says so out loud ("bench/is the ONLY place …"). From a lane worktreebench/cannot resolve at all (§3.1), so in practice nothing compiles them there. In/home/rickard/git/gunnarthey compile with--no-run, i.e. they are never executed. That is a deliberate, written position on coverage; it is worth knowing it is compile-only.crates/gunnar-znippy/Cargo.toml:81declareshttp = ["gunnar-cli/http"].run_znippy_tests(xtask/src/main.rs:1024) passes no--features. Nothing anywhere enables it.xtask/src/images.rs(1 479 lines) andxtask/src/appliance.rs(1 210 lines) have no tests of any kind — no in-file#[cfg(test)], noxtask/tests/{images,appliance}.rs— and both commands are explicitly excluded fromci(xtask/src/main.rs:443,:231). ~2 690 lines of the tooling that builds the ISO and the containers, with zero automated coverage. This is the soil the ISOBUILT-with-zero-artifacts defect grew in.
3.7 There is no automated CI at all, and that is what makes §3.1 matter · HOLE
Measured: no .github/, no .gitlab-ci.yml, no Woodpecker/Drone/Forgejo config, no *.yml/*.yaml anywhere in the top three levels of the tree, and .git/hooks/ contains nothing but the stock .sample files — not even the pre-commit that release/docs-nornir.toml:23 describes as "what a pre-commit should run".
So every green this repository has ever reported is a human or an agent running cargo xtask ci by hand, on oden. xtask/src/main.rs:19 points a reader at .github/workflows/ci.yml, "see its header".
§1.5 is why nobody noticed. That file existed until e50b962 on 2026-08-03, and two records — stinky.md S-033 and ci-options.md §4 — still describe it as present and parsing. Anyone asking "does gunnar have CI?" and consulting the audit gets yes, a workflow that is deliberately dormant, which is a reasonable-sounding answer and is wrong. The three citations (xtask/src/main.rs:19, S-033, ci-options.md:271) agree with each other and none of them agrees with the filesystem.
On its own that is a defensible position for a single-machine project. Combined with §3.1 it is not: the suite's coverage depends on which directory the human happened to be standing in, there is no second opinion, and nothing anywhere records where a quoted green was taken. That is exactly how "1331 passes / 0 failures" can be true and still not mean what a reader takes it to mean.
Cost: the honest cheap fix is not a CI server — it is making xtask ci print, in its final summary, the absolute path it ran in and the list of steps that did not run, so a quoted green carries its own provenance. An hour. Blocks release: no.
3.8 The two headline claims are TRUE — measured, not taken on trust
"No shell, no git or ssh subprocess" (README.md:16) holds. Swept every src/ in the server graph — gunnar-wire, gunnar-ssh, gunnar-store, gunnar-core, gunnar-pack, gunnar-policy, gunnar-grpc, gunnar-http, gunnar-proto, gunnar-lfs, gunnar-bitmap, gunnar-delta, gunnar-pktline, gunnar-sendpack, gunnar-stage — for Command::new, std::process::Command, fork and execve. Five hits. All five are inside #[cfg(test)] modules, checked individually: gunnar-wire/src/bitmap.rs:592 and :1068 (test mod opens at :565), gunnar-store/src/arrow_log.rs:2875 and :2918 (:2489), gunnar-cli/src/server/pid1.rs:751 (:538). Zero in shipped code.
The dependency guard — run in a clean worktree:
cargo xtask guard run in a clean worktree at 491faf9:
size appliance 281 crates (267 third-party)
dependency guard: PASS (7 tracked deviation(s), 0 violations)
pack-pipeline guard: PASS (0 undeclared call sites)
Exactly what README.md claims. Recorded because "verify the claim" has to include the ones that hold.
4. CLEANUP
-
containers/— five untracked files, not gitignored. Deleted from git on 2026-08-03 (.nornir/build-variants.toml:12) but still on disk in/home/rickard/git/gunnar(.containerignore+ four Containerfiles, 12 906 B). Not in.gitignore, so one carelessgit addresurrects them.git statushas shown?? containers/all day. -
crates/gunnar-cli/Cargo.toml:48— "The znippy cold tier of §4 is not built yet", justifyinggunnar-store/fs.crates/gunnar-znippyandcrates/gunnar-coldtierboth exist with a wired cold tier and three test files. The conclusion (fsis what an appliance runs on) is still right; the reason given for it is stale. -
crates/gunnar-cli/src/lib.rs:181quotes the appliance banner as"SSH-2.0-gunnar_0.1.0"while.nornir/real-metal-checklist.md:41shows the same run (5.911152673s) printed"SSH-2.0-gunnar_0.1.0 v1.0-4-g008d74b-modified". The doc comment truncated away the build ref — the exact thing the doc comment exists to argue for — and then says two ISOs are indistinguishable over the wire. -
.iso-out/gunnar-appliance-iso.isoexists at 29 214 720 B, dated 2026-08-03. The record naming29 456 384 Bdescribes a different build. The ISO lane owns theBUILT-with-zero-artifacts defect; this is only the note that the artifact currently on disk is neither today's nor the documented one. -
.nornir/docs.tomlis config nothing in gunnar reads, naming three PDFs that do not exist. It declares[book.manual] out = "docs/manual.pdf",[book.idiot_guide] out = "docs/idiot_guide.pdf"and[book.unsorted] out = "docs/unsorted.pdf".ls docs/returnsREADME.pdf,gunnar-manual.pdf,gunnar-record.pdf— none of the three.xtask/src/docsbook.rshardcodes its two outputs at:137and:166and never opensdocs.toml(zero hits for the filename in all ofxtask/). The file is read only by the externalnornir docs book, whichrelease/docs-nornir.toml:28says in as many words not to run because it hangs. And[book.idiot_guide]routes theidiotclass, whose only sources in the tree are_TEMPLATE-for-idiots.mdand_TEMPLATES.md— the templates themselves. This is the ISO defect's shape exactly: a record naming an artifact, and nobody looked for the file. -
Cargo.toml:29–33says ofgunnar-bitmap: "the consumer edge gets added when a lane measures the win, not before." False —crates/gunnar-wire/Cargo.toml:23andcrates/gunnar-store/Cargo.toml:81both depend on it unconditionally today.
Checked and clean, so nobody re-runs it: zero rayon (LAW 3); zero WebGL (LAW 4, not applicable); no #[ignore] without a stated reason except crates/gunnar-znippy/tests/cold_tier_wired.rs:864 and :1069, both env-driven bench arms whose headers explain themselves; xtask ci's preflight (main.rs:651) checks output, not exit code and fails the run rather than letting an interop test print SKIPPED: and pass.
5. What I could not determine
- Whether the dropped
shallowlines on the push path (§2.5) actually break a push from a shallow clone. It needs a running server and a real shallow fixture; the code reading says it should, and I will not rank it above an inference. - Whether
git fetch --server-optionsurvivesPeerCapabilities::parse(&capability_lines.join(" "))(crates/gunnar-wire/src/upload_pack.rs:651), which joins on a space and then splits on a space. A value containing a space would shred into phantom capabilities. Not measured. - The provenance of the "1331 passes / 0 failures at
491faf9" figure — whether it was taken in/home/rickard/git/gunnaror in a lane worktree. §3.1 makes those two different suites, and nothing on the number says which it was. A second run of the same command in a lane worktree measured 157 targets, 1250 passed, 0 failed, 6 ignored — 81 short, which is the size of what §3.1 drops. Neither number is wrong; they are different suites, and only one of them says so. - Everything whose evidence lives in a sibling repository.
znippy,znippy-zoomies,dwarves,draupnir,tunnrare all absent beside a lane worktree, socargo metadatafails outright forinstalltest/,bench/andcrates/gunnar-coldtier/there. That leaves all four ofPLAN.md's cold-tier## DONE:sections unverified from a lane — the byte-identity constant, the 3.96×/5.26× tables, the 19-repository corpus,encode_delta_against,MAX_GENERATION_CHAIN. The gunnar-side halves exist as files (crates/gunnar-coldtier/tests/history.rs:153,206,crates/gunnar-znippy/tests/cold_tier_wired.rs:108); none of them has been seen to pass or fail in such a tree. Onlycrates/gunnar-coldtieris guarded with aNOT RUNmessage (§3.1);installtestand the two bench trees fail as ordinary test failures, which reads as a broken repository rather than a missing neighbour. - I opened 165 of roughly 507
file:linecitations — the fully-qualified in-repo ones — plus every SVG-generator citation. The remaining ~340 are bare basenames or point into external crates and were checked only for basename resolution, not content. Six of the 165 were stale ranges, listed in §3.5. - I did not run the interop, ISO, bench or pressure suites, or
cargo xtask ciend to end.