Skip to content

fix(transfer): resolve imported thread id on Windows and surface import failures - #701

Open
JMak-Security wants to merge 1 commit into
openai:mainfrom
JMak-Security:fix/windows-transfer-ledger-lookup
Open

fix(transfer): resolve imported thread id on Windows and surface import failures#701
JMak-Security wants to merge 1 commit into
openai:mainfrom
JMak-Security:fix/windows-transfer-ledger-lookup

Conversation

@JMak-Security

Copy link
Copy Markdown

What

/codex:transfer reported failure on every attempt on Windows even though the
Claude session was imported successfully — the imported thread existed and was
resumable, but the user was told it failed and never got the thread id.

Root cause (per #618): the post-import lookup in external_agent_session_imports.json
could never match the record:

  1. Verbatim path mismatch. Codex writes source_path via Rust's
    fs::canonicalize, which on Windows emits a verbatim extended-length path
    (\?\C:\...). The plugin compared it against fs.realpathSync(), which never
    carries that prefix, so the strict equality was always false on Windows.
  2. Hash of a live transcript. content_sha256 was recomputed from the source
    after import, but the source is the live Claude transcript that keeps growing
    during the import. The recomputed hash no longer matches the imported snapshot —
    breaking the lookup on every platform when transferring the running session
    (the normal case).

Fix

Prefer the authoritative externalAgentConfig/import/completed notification, whose
successes[].target is the imported thread id, and keep the ledger as a fallback
with both comparisons relaxed:

  • requestExternalAgentSessionImport now returns the completion params.
  • importedThreadIdFromCompletion resolves the thread id from the notification.
  • Paths are normalized (normalizeImportPath: strip the verbatim \?\ / \?\UNC\
    prefix, case-insensitive on Windows) before comparison.
  • content_sha256 is demoted from a requirement to a preference.
  • On failure, failures[] from the notification is surfaced instead of a generic
    "did not record an imported thread" message.

Tests

Adds tests/codex-transfer.test.mjs covering verbatim/UNC path normalization,
completion-target resolution (matched + fallback), and failure-detail extraction.
npm test and npm run build pass.

Fixes #618

…ures

`/codex:transfer` reported failure on every attempt on Windows even when the
Claude session imported successfully, because the post-import ledger lookup in
`external_agent_session_imports.json` could never match:

- Codex writes `source_path` via Rust's `fs::canonicalize`, which on Windows
  emits a verbatim extended-length path (`\?\C:\...`), while the plugin compared
  it against `fs.realpathSync()`, which never carries that prefix. The strict
  equality was therefore always false on Windows.
- `content_sha256` was recomputed from the source after import, but the source is
  the live Claude transcript that keeps growing during the import, so the hash no
  longer matched the imported snapshot — breaking the lookup on every platform for
  the common case of transferring the running session.

Prefer the authoritative `externalAgentConfig/import/completed` notification,
whose `successes[].target` is the imported thread id, and fall back to the ledger
with both comparisons relaxed: paths are normalized (verbatim prefix stripped,
case-insensitive on Windows) and `content_sha256` is demoted from a requirement to
a preference. On failure, surface `failures[]` from the notification instead of a
generic message.

Adds regression tests for path normalization and completion/failure parsing.

Fixes openai#618

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@JMak-Security
JMak-Security requested a review from a team August 30, 2026 15:08

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3fa57011cb

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +1163 to +1165
const threadId =
importedThreadIdFromCompletion(completion, options.sourcePath) ??
importedThreadIdForSource(options.sourcePath);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject failed re-imports before reading the ledger

When this source was imported previously and a later import completes without a success target, the unconditional ledger fallback can return the earlier thread. Because importedThreadIdForSource now accepts a path match even when the current content hash differs, a changed transcript whose new import fails is reported as successfully imported while the user is given a stale thread that lacks the latest session content; only use the ledger when the completion lacks result data, not when it explicitly contains no matching success.

Useful? React with 👍 / 👎.

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.

/codex:transfer always fails on Windows: ledger lookup can never match (verbatim \?\ paths + hash of a live transcript)

2 participants