Repository navigation
Key todo provider session locks by identity, not service ID - #503
Merged
Quim Muntal (qmuntal) merged 6 commits intoJul 19, 2026
Merged
Quim Muntal (qmuntal) merged 6 commits into
Quim Muntal (qmuntal) merged 6 commits into
Conversation
The todo context provider keyed its per-session lock registry by Session.ServiceID(), which breaks the synchronization guarantee the lock is meant to provide: - a service ID may be empty, collapsing unrelated sessions onto one shared "_default" lock; - distinct sessions can share a service ID and unexpectedly share a lock; - the service ID is mutable, so one session can resolve to different locks over its lifetime; - registry entries were never removed and accumulated for the provider's lifetime. Key the registry by session object identity via weak.Pointer[agent.Session] instead, with a runtime.AddCleanup to drop entries once a session is collected. This mirrors the agentmode fix in microsoft#491 and matches the .NET provider, which keys its per-session lock by object identity via ConditionalWeakTable. A nil/absent session uses the shared fallback lock. Adds internal tests covering: same session -> same lock; distinct sessions with empty service IDs -> distinct locks; distinct sessions sharing a service ID -> distinct locks; nil session -> fallback lock; stale entries drained after GC.
Contributor
There was a problem hiding this comment.
Pull request overview
This pull request fixes the todo context provider’s per-session lock registry so it is keyed by session object identity rather than Session.ServiceID(), avoiding lock collisions/mutation issues and preventing unbounded registry growth by removing entries after session GC.
Changes:
- Reworked
Provider.getSessionLockto key the lock registry byweak.Pointer[agent.Session]and to register aruntime.AddCleanupcallback that deletes the entry when the session is collected. - Updated provider documentation/comments to accurately describe the identity-keyed behavior and the GC cleanup behavior.
- Added internal tests validating lock identity semantics and that stale registry entries are cleaned up after GC.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
agent/harness/todo/todo.go |
Keys session locks by weak session identity and deletes lock entries via runtime.AddCleanup on session GC. |
agent/harness/todo/getsessionlock_internal_test.go |
Adds coverage for same-session lock stability, distinct-session lock separation, nil-session fallback, and cleanup of stale entries. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Quim Muntal (qmuntal)
requested changes
Jul 17, 2026
Address review feedback (prefer black-box). Replace the white-box getSessionLock identity tests with a black-box concurrency test in todo_test.go that exercises the per-session lock via concurrent tool invocations and public reads on a shared session, mirroring the resolution merged for the agentmode provider (microsoft#491).
Quim Muntal (qmuntal)
approved these changes
Jul 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The
todocontext provider keys its per-session lock registry bySession.ServiceID(). This is the same latent issue that was corrected for theagentmodeprovider in #491, and it breaks the synchronization guarantee the per-session lock exists to provide:"_default"lock;Fix
Key the registry by session object identity via
weak.Pointer[agent.Session], with aruntime.AddCleanupthat drops each entry once its session is garbage-collected (the cleanup captures only the weak key, never the session). A nil/absent session uses the shared fallback lock.This mirrors the approach taken for
agentmodein #491 and — notably — restores parity with .NET: the existing code comment already stated the intent was to match ".NET's per-session SemaphoreSlim via ConditionalWeakTable," butConditionalWeakTableis identity-keyed, so theServiceID-keyed Go implementation had actually diverged from it. Identity keying is the alignment.Public API
No exported symbols change; the fix is internal to the
todoprovider's lock registry.Tests
Adds
getsessionlock_internal_test.go(packagetodo) covering the same cases requested during the #491 review:*agent.Sessionalways receives the same lock;go test -race -shuffle=on ./agent/harness/todopasses;go build ./...andgo vet ./...clean; gofumpt clean.Requires Go 1.25 (
weak,runtime.AddCleanup), which the module already targets.