Skip to content

fix(tests): verify the fixture git template before handing it out - #978

Merged
wenzowski merged 2 commits into
mainfrom
claude/glacial-ci-regression-d9qtr3
Sep 18, 2026
Merged

wenzowski merged 2 commits into
mainfrom
claude/glacial-ci-regression-d9qtr3

Conversation

@wenzowski

Copy link
Copy Markdown
Contributor

DO-NOT-CLOSE CLOUD-1832

Why

The musl job on release PR #977 (run 35292062763) reddened with two fixtures failing in the same millisecond:

panicked at crates/batten/tests/it/common/mod.rs:684:
git ["add", "-A"] failed in …/target/x86_64-unknown-linux-musl/tmp/adjudicate-loadable:
fatal: not a git repository (or any of the parent directories): .git

Both call Fixture::…git().base_commit(). init_repo ran; git add -A then found no repository. Not a verdict failure and not a musl divergence — windows and macos ran the same suite green on the identical head, whose only delta from main is the version bump.

The unsound branch

git_init_template publishes by atomic rename and reads a failed rename as "another process published first; its copy is complete". That is the likely cause and not the only one — a staging/.git that was never created, a cross-device error, an interrupted publish all reach the same return, handing back a path nobody checked. init_repo then copies whatever is there into the fixture and checks nothing either, so the first thing to notice is a git add several calls later. A could-not-look wearing a result's clothes.

The change

  • The loser's branch requires the published path to be a complete template before returning it.
  • init_repo requires its copy to have produced a repository, naming the template when it did not.
  • is_template is the one predicate both rest on, and a_directory_is_a_template_only_when_it_carries_a_repositorys_own_files shows it discriminating: absent, empty, HEAD-only and config-only are refused; a repository this suite built is accepted. Shown able to fail — stubbing the predicate to true reds it on the absent case.

What this does not claim

Not reproduced locally. A full musl binary(it) run with the scratch root wiped first passed 3525/3525, and thirty consecutive cold-start races through the same path failed none. This closes a branch that is unsound on reading and is the only code that emits that message; it is not a race I can demonstrate on demand.

Poisoning the real published template would be the stronger end-to-end arm and is deliberately not taken: that path is shared by every test process under one CARGO_TARGET_TMPDIR, so such a case would red its concurrent siblings — the cross-process hazard this fix is about.

CI's musl job runs with a cold scratch root every time, because the musl- cache family is new; that is the condition under which the first wave of test processes all race to publish.

🤖 Generated with Claude Code

https://claude.ai/code/session_01F1kFtyX6Fr37ANwTjr7yEV


Generated by Claude Code

@coderabbitai

coderabbitai Bot commented Sep 18, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 49 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 221741ca-77d8-46bc-a000-1173aaf5e735

📥 Commits

Reviewing files that changed from the base of the PR and between 2f5507a and ed1eb11.

📒 Files selected for processing (2)
  • crates/batten/tests/it/common/mod.rs
  • crates/batten/tests/it/primitives.rs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@wenzowski
wenzowski marked this pull request as ready for review September 18, 2026 05:08
@wenzowski
wenzowski marked this pull request as draft September 18, 2026 05:10
@wenzowski
wenzowski force-pushed the claude/glacial-ci-regression-d9qtr3 branch from 9d21d85 to 54be583 Compare September 18, 2026 06:31
`git_init_template` publishes by atomic rename, and read a failed rename as
"another process published first; its copy is complete". That is the likely
cause and not the only one: a `staging/.git` that was never created, a
cross-device error, an interrupted publish all arrive at the same `return`,
handing back a path nobody checked. `init_repo` then copies whatever is
there into a fixture and checks nothing either, so the first thing to notice
is a `git add -A` several calls later reporting a directory that is not a
repository — a could-not-look wearing a result's clothes.

Both ends now assert. The loser's branch requires the published path to be a
complete template before returning it, and `init_repo` requires the copy to
have produced a repository, naming the template when it did not.

`is_template` is the one predicate both rest on, and
`a_directory_is_a_template_only_when_it_carries_a_repositorys_own_files`
is where it is shown to discriminate: absent, empty, HEAD-only and
config-only directories are all refused, and a repository this suite built
is accepted. Shown able to fail — with the predicate stubbed to `true` it
reds on the absent case.

NOT REPRODUCED LOCALLY, stated because it bounds what this claims. The
`musl` job on the v0.0.170 release PR reddened with exactly this message on
two fixtures in the same millisecond; a full musl `binary(it)` run with the
scratch root wiped first passed 3525/3525, and thirty consecutive cold-start
races through the same path failed none. So this closes a branch that is
unsound on reading and is the only code that emits that message, rather than
a race I can demonstrate.

Poisoning the real published template would be the stronger arm and is
deliberately not taken: that path is shared by every test process under one
`CARGO_TARGET_TMPDIR`, so the case would red its concurrent siblings — the
cross-process hazard this fix is about.

Refs: CLOUD-1832
…ilure

The first repair asserted on the branch where the publish rename fails and
the published path is not a complete template. CI then failed on exactly
that assertion, on a cold musl scratch root, in a case whose subject was
elsewhere: the diagnosis was confirmed and the suite was still red.

A missing template is a COST. `common` still knows how to fork the
repository the template stands for, so `git_init_template` now answers
`Option` and `init_repo` forks when the answer is `None` — one `git init`
per fixture for that process, which is the behaviour that predates the
template. The state that used to be only asserted is printed instead: the
rename's error, whether a staged `.git` existed, and what the published
path actually contains.

Both routes now build the repository through one named function, so the
identity the template bakes into its own config cannot drift out of the
fallback — a fixture reading it through `git::config_value` cannot tell
which route built its repository, and a test pins that.

Refs: CLOUD-1832
@wenzowski
wenzowski force-pushed the claude/glacial-ci-regression-d9qtr3 branch from 54be583 to ed1eb11 Compare September 18, 2026 10:49
@wenzowski
wenzowski marked this pull request as ready for review September 18, 2026 10:49
@wenzowski

Copy link
Copy Markdown
Contributor Author

/fast-forward

@wenzowski
wenzowski merged commit ed1eb11 into main Sep 18, 2026
26 checks passed
@wenzowski
wenzowski deleted the claude/glacial-ci-regression-d9qtr3 branch September 18, 2026 11:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant