Skip to content

Commit 1f1a064

Browse files
Shahinyanmclaude
andcommitted
fix(tests): eliminate WSL project_hash collision + Windows async timing flakes (0.21.1)
Root cause for all three project_hash tests: TempDirs with no `.git` marker resolved `project_root` upward to a shared ancestor's `.git` — collapsing both to the same hash on hosts where /tmp sits under a git repo (WSL). Fix: give each TempDir its own `.git` directory so it is its own root. The async timing test (`ingest_hook_returns_fast_in_async_mode`) used a 2s threshold that was too tight for cold-start Windows CI runners (+AV); the pre-fix regression was 5-30s so 5s still distinguishes real and tolerates slow runners. Applied to: project_hash.rs (1), cli.rs migrate_project (2), main.rs resolve_project_paths (1), cli.rs async timing (1). All 459 workspace tests now pass locally with 0 failures. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent cf1c011 commit 1f1a064

7 files changed

Lines changed: 24 additions & 6 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ members = [
77
]
88

99
[workspace.package]
10-
version = "0.21.0"
10+
version = "0.21.1"
1111
edition = "2021"
1212
rust-version = "1.88"
1313
license = "MIT"

crates/tj-cli/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ default = ["embed"]
2323
embed = ["tj-core/embed"]
2424

2525
[dependencies]
26-
tj-core = { package = "task-journal-core", version = "0.21.0", path = "../tj-core", default-features = false }
26+
tj-core = { package = "task-journal-core", version = "0.21.1", path = "../tj-core", default-features = false }
2727
anyhow = { workspace = true }
2828
clap = { workspace = true }
2929
tracing = { workspace = true }

crates/tj-cli/tests/cli.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,10 @@ fn migrate_project_round_trips_data_to_new_path() {
455455
let xdg = assert_fs::TempDir::new().unwrap();
456456
let proj_a = assert_fs::TempDir::new().unwrap();
457457
let proj_b = assert_fs::TempDir::new().unwrap();
458+
// Distinct project roots so each hashes to itself, not to a shared ancestor
459+
// carrying a `.git` (which collapses both to one hash on some hosts, WSL).
460+
std::fs::create_dir(proj_a.path().join(".git")).unwrap();
461+
std::fs::create_dir(proj_b.path().join(".git")).unwrap();
458462

459463
// Create a task with the cwd = proj_a.
460464
let task_id = String::from_utf8(
@@ -503,6 +507,10 @@ fn migrate_project_refuses_overwrite_without_force() {
503507
let xdg = assert_fs::TempDir::new().unwrap();
504508
let proj_a = assert_fs::TempDir::new().unwrap();
505509
let proj_b = assert_fs::TempDir::new().unwrap();
510+
// Distinct project roots so each hashes to itself, not a shared `.git`
511+
// ancestor (which collapses both to one hash on some hosts, e.g. WSL).
512+
std::fs::create_dir(proj_a.path().join(".git")).unwrap();
513+
std::fs::create_dir(proj_b.path().join(".git")).unwrap();
506514

507515
// Both projects have data: create a task in each.
508516
for proj in [&proj_a, &proj_b] {
@@ -2379,8 +2387,8 @@ fn ingest_hook_returns_fast_in_async_mode() {
23792387
// this took 5-30s. Post-fix, expect well under 1s; assert <2s
23802388
// so flaky CI doesn't fail us.
23812389
assert!(
2382-
elapsed < std::time::Duration::from_millis(2000),
2383-
"ingest-hook must return in <2s in async mode, took {elapsed:?}"
2390+
elapsed < std::time::Duration::from_secs(5),
2391+
"ingest-hook must return in <5s in async mode (the pre-fix regression was 5-30s); took {elapsed:?}"
23842392
);
23852393

23862394
// A v2 pending entry must have been written. We don't assert

crates/tj-core/src/project_hash.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ mod tests {
6262
fn different_paths_yield_different_hashes() {
6363
let d1 = TempDir::new().unwrap();
6464
let d2 = TempDir::new().unwrap();
65+
// Make each temp dir its own project root, so the hash is of the temp
66+
// dir itself — not of a shared ancestor that happens to carry a `.git`
67+
// (which collapses both to one hash on some machines, e.g. WSL /tmp).
68+
std::fs::create_dir(d1.path().join(".git")).unwrap();
69+
std::fs::create_dir(d2.path().join(".git")).unwrap();
6570
let a = from_path(d1.path()).unwrap();
6671
let b = from_path(d2.path()).unwrap();
6772
assert_ne!(a, b);

crates/tj-mcp/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ path = "src/main.rs"
1717

1818
[dependencies]
1919
# Lean: the MCP server doesn't embed yet, so it skips the model2vec backend.
20-
tj-core = { package = "task-journal-core", version = "0.21.0", path = "../tj-core", default-features = false }
20+
tj-core = { package = "task-journal-core", version = "0.21.1", path = "../tj-core", default-features = false }
2121
anyhow = { workspace = true }
2222
tokio = { workspace = true }
2323
tracing = { workspace = true }

crates/tj-mcp/src/main.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -873,6 +873,11 @@ mod tests {
873873
let b = tmp.path().join("beta");
874874
std::fs::create_dir_all(&a).unwrap();
875875
std::fs::create_dir_all(&b).unwrap();
876+
// Make each its own project root, so they don't both resolve up to the
877+
// shared `tmp` ancestor (or a `.git` above it, which collapses the two
878+
// hashes on some hosts, e.g. WSL /tmp).
879+
std::fs::create_dir(a.join(".git")).unwrap();
880+
std::fs::create_dir(b.join(".git")).unwrap();
876881

877882
let (hash_a, _, _) = resolve_project_paths(&a).unwrap();
878883
let (hash_b, _, _) = resolve_project_paths(&b).unwrap();

plugin/.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "task-journal",
3-
"version": "0.21.0",
3+
"version": "0.21.1",
44
"description": "Append-only journal of AI-coding task reasoning chains: hypotheses, decisions, rejections, evidence. Renders compact resume packs so an agent can pick up a 2-week-old task with full context.",
55
"author": {
66
"name": "Mher Shahinyan"

0 commit comments

Comments
 (0)