fix: a pinned session's telemetry names the picked workspace
Issue for this PR
Closes #1671
Type of change
- Bug fix
- New feature
- Refactor / code improvement
- Documentation
What does this PR do?
An IDE extension can start serve with a workspace pin. The pin decides identity, skills, memory and tool routing, but a turn's telemetry rows read only the project's on-disk link, where the pin is never written. So a pinned session sent no workspace_id, or the id of the project's own link.
resolveTurnBinding in state.ts gives a turn's workspace the way routing does: the pin first, then the on-disk link. turnBinding resolves it once per turn, and prompt.ts uses that one verdict for attached files and for the turn's rows.
- A pin that can't be honoured names no workspace, as routing refuses it. It never falls back to the link.
- Unpinned turns keep the local cache read, which makes no network call.
- Past the validation TTL the pin's verdict is a network call. A turn waits for it once, at most 3 seconds, then sends its rows without a workspace. Routing joins that request while it is in flight.
How did you verify your code works?
Tests. pinned-workspace-loop.test.ts runs the real prompt loop. Before the fix a pinned session stamped the link or nothing, a refused pin stamped the link, and attached files each resolved the pin again. routing-pin.test.ts covers a malformed pin, a directory outside the root, the wait, and one verdict per turn.
E2E. The released VS Code extension 0.15.0 in code-server, signed in, with its own selection pinning serve. CLI rows went to a local catcher.
| Project's on-disk link | v0.12.9 | This branch |
|---|---|---|
| A different workspace | the link's id | the pinned id |
| None | no id | the pinned id |
That held on session_start, task_classified, task_outcome_signal, agent_outcome, session_end, and tool_call where a tool failed. Not exercised: via_workspace, which needs the engine.
Suites. test/altimate/workspace and test/altimate/telemetry pass locally and typecheck is clean. The full suite runs in CI.
Cost side effects
None. A pinned turn reads the existing validation memo. Past its TTL, or for a pin the account can't see, which is never memoized, it is one validation request per turn.
Screenshots / recordings
Not a UI change.
Checklist
- I have tested my changes locally
- I have not included unrelated changes in this PR
- I checked for cost side effects (model calls, queries or cloud resources that grow with user data) and described them, or wrote "none"
🤖 Generated with Claude Code
https://claude.ai/code/session_01VEmKQswEEpkYFmMEngESx8
Summary by cubic
Fixes a pinned session's telemetry rows naming the wrong workspace, or none. Telemetry read only the project's on-disk link, but the IDE extension's pin is never written there, so a pinned session stamped no workspace_id or the link's id. resolveTurnBinding resolves a turn's workspace the way routing does: the pin first, then the on-disk link.
Behavior
- A pin that cannot be honored names no workspace, never falling back to the project's link.
- Unpinned turns keep the local cache read, with no credentials and no network.
- A turn resolves its workspace once: past the validation TTL the first read waits at most 3 seconds for the pin's verdict, and all later reads in the turn — the attached files and the loop — share that answer. The routing read later in the turn joins the same request, so a failed validation doesn't run twice.
- Each new turn of a session resolves its own workspace; a later turn never inherits the first turn's verdict.
Summary by CodeRabbit
- Bug Fixes
- Session telemetry and attachment reads now consistently use the workspace selected for the prompt turn. A valid workspace pin takes precedence over the project’s linked workspace.
- When no pin is set, the project’s linked workspace is used. If a pin is invalid or cannot be verified in time, records are no longer attributed to the project’s linked workspace as a fallback.
- Workspace selection is resolved independently for each prompt turn, including later turns in the same session.