Skip to content

Fix snapshot filename collisions on case-insensitive filesystems#2

Merged
friggeri merged 1 commit intomainfrom
frg/fix-yaml-casing
Jan 14, 2026
Merged

Fix snapshot filename collisions on case-insensitive filesystems#2
friggeri merged 1 commit intomainfrom
frg/fix-yaml-casing

Conversation

@friggeri
Copy link
Copy Markdown
Collaborator

All SDK test harnesses now generate lowercase snapshot filenames to avoid collisions when checking out on macOS/Windows (case-insensitive filesystems).

  • Node.js: Added .toLowerCase() to filename generation
  • Go: Added strings.ToLower() to filename generation
  • .NET: Simplified to single regex + ToLowerInvariant()
  • Python: Added .lower() to filename generation

Also renamed existing snapshot files to lowercase and removed duplicates that only differed by case.

All SDK test harnesses now generate lowercase snapshot filenames to avoid
collisions when checking out on macOS/Windows (case-insensitive filesystems).

- Node.js: Added .toLowerCase() to filename generation
- Go: Added strings.ToLower() to filename generation
- .NET: Simplified to single regex + ToLowerInvariant()
- Python: Added .lower() to filename generation

Also renamed existing snapshot files to lowercase and removed duplicates
that only differed by case.
@friggeri friggeri requested a review from a team as a code owner January 14, 2026 17:53
Copilot AI review requested due to automatic review settings January 14, 2026 17:53
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes snapshot filename collisions that occur on case-insensitive filesystems (macOS/Windows) by ensuring all SDK test harnesses generate lowercase snapshot filenames.

Changes:

  • Modified filename generation in all four SDK test harnesses (Node.js, Go, Python, .NET) to convert test names to lowercase
  • Renamed existing snapshot files from mixed-case to lowercase (e.g., accept_MCP_* → accept_mcp_*)
  • Removed duplicate snapshot files that only differed by case

Reviewed changes

Copilot reviewed 7 out of 16 changed files in this pull request and generated no comments.

Show a summary per file
File Description
python/e2e/testharness/context.py Added .lower() to sanitized test name generation
nodejs/test/e2e/harness/sdkTestContext.ts Added .toLowerCase() to task name filename conversion
go/e2e/testharness/context.go Added strings.ToLower() to sanitized name generation
dotnet/test/Harness/E2ETestContext.cs Simplified regex logic and added .ToLowerInvariant()
test/snapshots/mcpservers/accept_mcp_server_config_on_create.yaml New lowercase snapshot file
test/snapshots/mcpservers/accept_mcp_server_config_on_resume.yaml New lowercase snapshot file
test/snapshots/mcpservers/accept_MCP_server_config_on_create.yaml Removed mixed-case duplicate
test/snapshots/mcpservers/accept_MCP_server_config_on_resume.yaml Removed mixed-case duplicate
test/snapshots/mcp-and-agents/should_accept_both_MCP_servers_and_custom_agents.yaml Removed mixed-case duplicate (moved to combinedconfiguration)
test/snapshots/combinedconfiguration/accept_mcp_servers_and_custom_agents.yaml New lowercase snapshot file
test/snapshots/session/should_create_a_session_with_replaced_systemmessage_config.yaml New lowercase snapshot file
test/snapshots/session/should_create_a_session_with_excludedtools.yaml New lowercase snapshot file
test/snapshots/session/should_create_a_session_with_availabletools.yaml New lowercase snapshot file
test/snapshots/session/should_create_a_session_with_appended_systemmessage_config.yaml New lowercase snapshot file
test/snapshots/permissions/should_receive_toolcallid_in_permission_requests.yaml New lowercase snapshot file
test/snapshots/ask/should_invoke_onevent_callback_for_each_event.yaml New lowercase snapshot file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@friggeri friggeri added this pull request to the merge queue Jan 14, 2026
Merged via the queue into main with commit 3087d8c Jan 14, 2026
43 of 44 checks passed
jmoseley pushed a commit that referenced this pull request Jan 21, 2026
tclem added a commit that referenced this pull request Apr 30, 2026
Closes RFD-400 review finding #2 (idle_waiter slot leak on external
cancellation). See cancel-safety review session db4b1ac8-... for the
full report.

`Session::send_and_wait` installs an `IdleWaiter` slot under
`self.idle_waiter`, then awaits the response. Internal failure paths
(send_inner error, oneshot closure, internal timeout) clean up the
slot. External cancellation — caller wraps `send_and_wait` in
`tokio::time::timeout`, races it in `select!`, or aborts the
JoinHandle — does not. The cleanup at the event loop's `else` branch
only fires when the channel itself closes (i.e., the entire session
is going away), not when an individual call is cancelled.

Effect: any external cancellation between "install waiter" and
"drain response" leaves `idle_waiter = Some(...)` forever. All
subsequent `send` and `send_and_wait` calls return
`SendWhileWaiting`, permanently bricking the session.

Fix: `WaiterGuard` RAII helper that takes the slot on Drop. Construct
right after install, let RAII handle every exit path. The explicit
`self.idle_waiter.lock().take()` calls inside the function disappear,
and the slot is cleared on every cancellation path automatically.

Mutex conversion (folded in from finding #5):

- `Session::idle_waiter`: `tokio::sync::Mutex<Option<IdleWaiter>>` ->
  `parking_lot::Mutex<Option<IdleWaiter>>`. Lock is never held across
  `.await` in any code path; the conversion is what makes
  WaiterGuard's synchronous Drop work without needing an async-spawn
  fallback.

`event_loop` mutex stays `tokio::sync::Mutex` for now — commit C
converts it as part of cooperative shutdown (so the conversion lands
alongside the matching change to Drop for Session).

Tests: two new regression tests in tests/session_test.rs

- `send_and_wait_outer_cancellation_clears_waiter`: outer
  `tokio::time::timeout(50ms, ...)` around `send_and_wait` with a
  60-second inner timeout. Outer fires, dropping the future. Verify
  the next `send` succeeds (no SendWhileWaiting).
- `send_and_wait_drop_clears_waiter`: explicit `JoinHandle::abort` of
  an in-flight send_and_wait. Verify the next `send` succeeds.

Existing 211 tests continue to pass; total now 213.

Validation: cargo test --all-features, cargo doc -D warnings, cargo
+nightly fmt --check, cargo clippy -- -D warnings all clean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

3 participants