Summary
A cluster of ~5 tests in crates/mold-server/src/execution_plan.rs fails non-deterministically on a fast local machine while passing in CI. The failing subset varies run to run — I have observed 2, 3, 4, and 5 failures from the same cluster within a single session, with no source change between runs:
cache_miss_identity_changes_when_artifact_metadata_changes
same_size_in_place_overwrite_changes_equivalence_content_identity
same_size_in_place_overwrite_with_restored_mtime_changes_content_identity
frozen_chain_model_uses_canonical_companions_and_ignores_changed_config
Root cause
artifact_metadata_identity derives identity from path + size + mtime. The fixtures overwrite a file with different content of identical size:
std::fs::write(&path, b"aaaa").unwrap();
let first_metadata = artifact_metadata_identity(&path, &path.metadata().unwrap());
// ...
std::fs::write(&path, b"bbbb").unwrap();
let second_metadata = artifact_metadata_identity(&path, &path.metadata().unwrap());
assert_ne!(
first_metadata, second_metadata,
"fixture must observe a new metadata identity"
);
Size is unchanged by construction, so the assertion rests entirely on the two writes landing in different filesystem mtime ticks. When they land in the same tick the identities are equal and the fixture's own precondition fails — before the test reaches the behaviour it means to check.
This is why it fails more on a fast machine: the two writes complete closer together. CI's slower runners and filesystem separate them, which is why main is green.
Why it matters beyond flakiness
The failing set drifts with machine load, so a local cargo test --workspace cannot distinguish "my change broke something" from "the box was busy". Every contributor running the documented CI-equivalent gate has to hold a mental list of which failures to ignore, and that list is not even stable. During recent LTX-2 milestone work this cost real time on several PRs, each time re-deriving that the failures were unrelated.
Suggested fix
Make the fixture control the clock instead of racing it — force a distinct mtime rather than hoping for one:
filetime::set_file_mtime(&path, FileTime::from_unix_time(t + 1, 0))?;
filetime is already in the dependency graph. Alternatively, assert on the content identity these tests actually care about and drop the metadata-identity precondition, which is an implementation detail of the cache rather than the property under test.
Either way the tests then verify the intended invariant deterministically, on any filesystem.
Reproduction
unshare -Urm --map-root-user sh -c 'mount -t tmpfs none /mnt; \
env -u MOLD_HOME -u MOLD_MODELS_DIR cargo test -p mold-ai-server --lib execution_plan:: 2>&1' \
| grep -E "^test .*FAILED|^test result"
Run it a few times under varying load; the failing subset changes.
Summary
A cluster of ~5 tests in
crates/mold-server/src/execution_plan.rsfails non-deterministically on a fast local machine while passing in CI. The failing subset varies run to run — I have observed 2, 3, 4, and 5 failures from the same cluster within a single session, with no source change between runs:cache_miss_identity_changes_when_artifact_metadata_changessame_size_in_place_overwrite_changes_equivalence_content_identitysame_size_in_place_overwrite_with_restored_mtime_changes_content_identityfrozen_chain_model_uses_canonical_companions_and_ignores_changed_configRoot cause
artifact_metadata_identityderives identity from path + size + mtime. The fixtures overwrite a file with different content of identical size:Size is unchanged by construction, so the assertion rests entirely on the two writes landing in different filesystem mtime ticks. When they land in the same tick the identities are equal and the fixture's own precondition fails — before the test reaches the behaviour it means to check.
This is why it fails more on a fast machine: the two writes complete closer together. CI's slower runners and filesystem separate them, which is why
mainis green.Why it matters beyond flakiness
The failing set drifts with machine load, so a local
cargo test --workspacecannot distinguish "my change broke something" from "the box was busy". Every contributor running the documented CI-equivalent gate has to hold a mental list of which failures to ignore, and that list is not even stable. During recent LTX-2 milestone work this cost real time on several PRs, each time re-deriving that the failures were unrelated.Suggested fix
Make the fixture control the clock instead of racing it — force a distinct mtime rather than hoping for one:
filetimeis already in the dependency graph. Alternatively, assert on the content identity these tests actually care about and drop the metadata-identity precondition, which is an implementation detail of the cache rather than the property under test.Either way the tests then verify the intended invariant deterministically, on any filesystem.
Reproduction
Run it a few times under varying load; the failing subset changes.