Skip to content

Transcript state on the Project singleton is not isolated per SDK context #2267

Open

Description

@serafkul

Summary

Project is a process-wide singleton, but the session id it is appending for is
context-scoped (AsyncLocalStorage). With two SDK sessions overlapping in one
process, records can be written to the wrong session's transcript file.

This was found by CodeRabbit during review of #2253 and is split out here
deliberately: #2253 fixes the sequential case and does not claim to make
overlapping turns safe. Filing it so the remaining hazard is not carried
silently by that PR.

Mechanism

  • recordTranscript() resolves the session id from the SDK context, so inside
    session A's context it returns A.
  • Project.appendEntry() compares its sessionId argument with
    getSessionId(). When they differ it resolves the file per session via
    getExistingSessionFile(sessionId), which is safe. When they match it writes
    to the cached this.sessionFile.
  • switchSession() emits a process-wide signal that clears that cached pointer,
    and the next resolution fills it from whichever session asked.

So if session B switches while a turn in session A is still in flight, A's
isCurrentSession check passes — the id really is A in A's context — and the
append lands in the file B resolved. The record is lost from A's transcript and
resuming A misses it.

Scope of a fix

The transcript state on Project has to become context-scoped, both fields:

  • sessionFile — the cached path;
  • pendingEntries — the buffer.

Both, and not one: resetSessionFile() drops pendingEntries along with the
path, and simply preserving that buffer across a switch would be worse than the
bug. Those entries belong to the session that buffered them, so carrying them
forward would flush them into the next session's file. Doing this properly means
flushing them to their own session on the way out.

That is a change to a singleton a lot of call sites reach through, and it wants
its own concurrency tests, which is why it is not folded into #2253.

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions