fix(claude): explain missing-transcript resume failures; add t3 session audit|reset - #52

Open
DanielGGordon wants to merge 1 commit into
mainfrom
t3code/fix-message-send-failure
Open

fix(claude): explain missing-transcript resume failures; add t3 session audit|reset#52
DanielGGordon wants to merge 1 commit into
mainfrom
t3code/fix-message-send-failure

Conversation

@DanielGGordon

Copy link
Copy Markdown
Owner

Problem

Sending in a Claude thread whose persisted resume cursor points at a transcript that no longer exists on this host failed with only "Claude runtime stream failed." The real cause — Claude Code's No conversation found with session ID: <id> — was emitted one event earlier and then overwritten by the generic stream-exit error, so the thread gave no hint at what was missing or how to recover. Found on prod thread 89de3af4… ("Second Brain Architecture Review"); an audit of the prod DB shows 72 non-deleted Claude threads (43 unarchived, mostly claude-import-* from another machine) in the same state.

Changes

Adapter (ClaudeAdapter.ts, claudeSessionTranscript.ts)

  • Recognise the CLI's missing-transcript result error and emit a runtime error that names the session id, the expected ~/.claude/projects/<encoded cwd>/<id>.jsonl path, and the two ways out (restore the file and resend, or t3 session reset <threadId>). Detail payload carries reason: "resume_transcript_missing".
  • Keep that explanation through the subsequent stream exit instead of replacing it with "Claude runtime stream failed."
  • The resume cursor is deliberately not cleared — the transcript may still be recoverable from the machine the conversation ran on.

CLI (cli/session.ts, shared cli/offlineRuntime.ts)

  • t3 session audit [--json] [--include-deleted] [--all] [--projects-dir] — lists every Claude thread whose transcript is missing (or relocated under a different project folder) with lifecycle, title, cwd, session id and the exact path to restore. Read-only.
  • t3 session reset <threadId> [--yes] — prints the current cursor (so it can be restored by hand) and only clears it with --yes.
  • Both run offline against the state DB and are safe while the server is serving (WAL; the server re-reads bindings on every session start). The offline runtime layer that was private to t3 import is now shared.

Docs: README feature bullet, AGENTS.md ops section.

Verification

  • tsgo --noEmit clean; vp lint clean; vp fmt --check clean.
  • New tests: claudeSessionTranscript.test.ts (encoding, error parsing, message), cli/session.test.ts (binding → target, lifecycle, row formatting), ClaudeAdapter.test.ts ("explains a resume whose transcript is missing and keeps that explanation on stream exit").
  • Full apps/server suite: 1777 passed; the single failure (server.test.ts > preserves structured workspace rpc failures) is pre-existing and fails identically on main.
  • Ran t3 session audit against the live prod DB: 137 Claude threads with cursors → 65 present, 0 relocated, 72 missing, ~4s. t3 session reset dry run verified to leave the row untouched; on a thread with no cursor it reports "nothing to reset".

🤖 Generated with Claude Code

…ion audit|reset`
Sending in a Claude thread whose persisted resume cursor points at a transcript
that no longer exists on this host (imported from another machine, host
reprovisioned) failed with the generic "Claude runtime stream failed." The
actual cause — the CLI's `No conversation found with session ID: <id>` — was
emitted one event earlier and then overwritten, so the thread gave no hint at
what was missing or how to recover.
Adapter: recognise the CLI's missing-transcript result, emit a runtime error
that names the session id and the expected `~/.claude/projects/<cwd>/<id>.jsonl`
path plus the two ways out (restore the file, or `t3 session reset`), and keep
that message through the subsequent stream exit instead of replacing it. The
resume cursor is deliberately left intact so the transcript can still be
restored from wherever the conversation ran.
CLI: `t3 session audit` lists every Claude thread whose transcript is missing
(or relocated) with the path to restore; `t3 session reset <threadId>` prints
the current cursor and, only with `--yes`, clears it so the thread starts a
fresh Claude session. Both run offline against the state DB and are safe while
the server is serving (WAL; bindings are re-read on every session start). The
offline CLI runtime layer previously private to `t3 import` is shared.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL labels Aug 25, 2026
@DanielGGordon

DanielGGordon commented Aug 25, 2026

Copy link
Copy Markdown
OwnerAuthor

Test deployment

This branch is running on test slot 7448 with a copy of the prod threads (so the stale-cursor threads are there to try).

Pairing link:https://15.204.108.12:7448/pair#token=9DHXVHVUCX8R
(one-time, short expiry — if it's stale, re-mint on the server with node scripts/test-status.ts --pair 7448)

To see the change: open a Claude thread whose transcript is missing (e.g. "Install Cursor CLI" or any claude-import-… thread for DanCode / gphotos-to-constant-contact) and send anything. Instead of "Claude runtime stream failed." the thread now shows which ~/.claude/projects/…/<session>.jsonl is missing and the two ways out (restore the file, or t3 session reset <threadId>).

CLI, from the worktree on the server:

node apps/server/src/bin.ts session audit # read-only list of affected threads + paths to restore
node apps/server/src/bin.ts session reset <threadId># dry run; add --yes to actually clear the cursor

Slot: external 7448 ⇄ loopback 3778.

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

Labels

size:XLvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@DanielGGordon
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(claude): explain missing-transcript resume failures; add t3 session audit|reset - #52

Open
DanielGGordon wants to merge 1 commit into
mainfrom
t3code/fix-message-send-failure
Open

fix(claude): explain missing-transcript resume failures; add t3 session audit|reset#52
DanielGGordon wants to merge 1 commit into
mainfrom
t3code/fix-message-send-failure

Conversation

@DanielGGordon

Copy link
Copy Markdown
Owner

Problem

Sending in a Claude thread whose persisted resume cursor points at a transcript that no longer exists on this host failed with only "Claude runtime stream failed." The real cause — Claude Code's No conversation found with session ID: <id> — was emitted one event earlier and then overwritten by the generic stream-exit error, so the thread gave no hint at what was missing or how to recover. Found on prod thread 89de3af4… ("Second Brain Architecture Review"); an audit of the prod DB shows 72 non-deleted Claude threads (43 unarchived, mostly claude-import-* from another machine) in the same state.

Changes

Adapter (ClaudeAdapter.ts, claudeSessionTranscript.ts)

  • Recognise the CLI's missing-transcript result error and emit a runtime error that names the session id, the expected ~/.claude/projects/<encoded cwd>/<id>.jsonl path, and the two ways out (restore the file and resend, or t3 session reset <threadId>). Detail payload carries reason: "resume_transcript_missing".
  • Keep that explanation through the subsequent stream exit instead of replacing it with "Claude runtime stream failed."
  • The resume cursor is deliberately not cleared — the transcript may still be recoverable from the machine the conversation ran on.

CLI (cli/session.ts, shared cli/offlineRuntime.ts)

  • t3 session audit [--json] [--include-deleted] [--all] [--projects-dir] — lists every Claude thread whose transcript is missing (or relocated under a different project folder) with lifecycle, title, cwd, session id and the exact path to restore. Read-only.
  • t3 session reset <threadId> [--yes] — prints the current cursor (so it can be restored by hand) and only clears it with --yes.
  • Both run offline against the state DB and are safe while the server is serving (WAL; the server re-reads bindings on every session start). The offline runtime layer that was private to t3 import is now shared.

Docs: README feature bullet, AGENTS.md ops section.

Verification

  • tsgo --noEmit clean; vp lint clean; vp fmt --check clean.
  • New tests: claudeSessionTranscript.test.ts (encoding, error parsing, message), cli/session.test.ts (binding → target, lifecycle, row formatting), ClaudeAdapter.test.ts ("explains a resume whose transcript is missing and keeps that explanation on stream exit").
  • Full apps/server suite: 1777 passed; the single failure (server.test.ts > preserves structured workspace rpc failures) is pre-existing and fails identically on main.
  • Ran t3 session audit against the live prod DB: 137 Claude threads with cursors → 65 present, 0 relocated, 72 missing, ~4s. t3 session reset dry run verified to leave the row untouched; on a thread with no cursor it reports "nothing to reset".

🤖 Generated with Claude Code

…ion audit|reset`
Sending in a Claude thread whose persisted resume cursor points at a transcript
that no longer exists on this host (imported from another machine, host
reprovisioned) failed with the generic "Claude runtime stream failed." The
actual cause — the CLI's `No conversation found with session ID: <id>` — was
emitted one event earlier and then overwritten, so the thread gave no hint at
what was missing or how to recover.
Adapter: recognise the CLI's missing-transcript result, emit a runtime error
that names the session id and the expected `~/.claude/projects/<cwd>/<id>.jsonl`
path plus the two ways out (restore the file, or `t3 session reset`), and keep
that message through the subsequent stream exit instead of replacing it. The
resume cursor is deliberately left intact so the transcript can still be
restored from wherever the conversation ran.
CLI: `t3 session audit` lists every Claude thread whose transcript is missing
(or relocated) with the path to restore; `t3 session reset <threadId>` prints
the current cursor and, only with `--yes`, clears it so the thread starts a
fresh Claude session. Both run offline against the state DB and are safe while
the server is serving (WAL; bindings are re-read on every session start). The
offline CLI runtime layer previously private to `t3 import` is shared.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL labels Aug 25, 2026
@DanielGGordon

DanielGGordon commented Aug 25, 2026

Copy link
Copy Markdown
OwnerAuthor

Test deployment

This branch is running on test slot 7448 with a copy of the prod threads (so the stale-cursor threads are there to try).

Pairing link:https://15.204.108.12:7448/pair#token=9DHXVHVUCX8R
(one-time, short expiry — if it's stale, re-mint on the server with node scripts/test-status.ts --pair 7448)

To see the change: open a Claude thread whose transcript is missing (e.g. "Install Cursor CLI" or any claude-import-… thread for DanCode / gphotos-to-constant-contact) and send anything. Instead of "Claude runtime stream failed." the thread now shows which ~/.claude/projects/…/<session>.jsonl is missing and the two ways out (restore the file, or t3 session reset <threadId>).

CLI, from the worktree on the server:

node apps/server/src/bin.ts session audit # read-only list of affected threads + paths to restore
node apps/server/src/bin.ts session reset <threadId># dry run; add --yes to actually clear the cursor

Slot: external 7448 ⇄ loopback 3778.

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

Labels

size:XLvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@DanielGGordon
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(claude): explain missing-transcript resume failures; add t3 session audit|reset - #52

Open
DanielGGordon wants to merge 1 commit into
mainfrom
t3code/fix-message-send-failure
Open

fix(claude): explain missing-transcript resume failures; add t3 session audit|reset#52
DanielGGordon wants to merge 1 commit into
mainfrom
t3code/fix-message-send-failure

Conversation

@DanielGGordon

Copy link
Copy Markdown
Owner

Problem

Sending in a Claude thread whose persisted resume cursor points at a transcript that no longer exists on this host failed with only "Claude runtime stream failed." The real cause — Claude Code's No conversation found with session ID: <id> — was emitted one event earlier and then overwritten by the generic stream-exit error, so the thread gave no hint at what was missing or how to recover. Found on prod thread 89de3af4… ("Second Brain Architecture Review"); an audit of the prod DB shows 72 non-deleted Claude threads (43 unarchived, mostly claude-import-* from another machine) in the same state.

Changes

Adapter (ClaudeAdapter.ts, claudeSessionTranscript.ts)

  • Recognise the CLI's missing-transcript result error and emit a runtime error that names the session id, the expected ~/.claude/projects/<encoded cwd>/<id>.jsonl path, and the two ways out (restore the file and resend, or t3 session reset <threadId>). Detail payload carries reason: "resume_transcript_missing".
  • Keep that explanation through the subsequent stream exit instead of replacing it with "Claude runtime stream failed."
  • The resume cursor is deliberately not cleared — the transcript may still be recoverable from the machine the conversation ran on.

CLI (cli/session.ts, shared cli/offlineRuntime.ts)

  • t3 session audit [--json] [--include-deleted] [--all] [--projects-dir] — lists every Claude thread whose transcript is missing (or relocated under a different project folder) with lifecycle, title, cwd, session id and the exact path to restore. Read-only.
  • t3 session reset <threadId> [--yes] — prints the current cursor (so it can be restored by hand) and only clears it with --yes.
  • Both run offline against the state DB and are safe while the server is serving (WAL; the server re-reads bindings on every session start). The offline runtime layer that was private to t3 import is now shared.

Docs: README feature bullet, AGENTS.md ops section.

Verification

  • tsgo --noEmit clean; vp lint clean; vp fmt --check clean.
  • New tests: claudeSessionTranscript.test.ts (encoding, error parsing, message), cli/session.test.ts (binding → target, lifecycle, row formatting), ClaudeAdapter.test.ts ("explains a resume whose transcript is missing and keeps that explanation on stream exit").
  • Full apps/server suite: 1777 passed; the single failure (server.test.ts > preserves structured workspace rpc failures) is pre-existing and fails identically on main.
  • Ran t3 session audit against the live prod DB: 137 Claude threads with cursors → 65 present, 0 relocated, 72 missing, ~4s. t3 session reset dry run verified to leave the row untouched; on a thread with no cursor it reports "nothing to reset".

🤖 Generated with Claude Code

…ion audit|reset`
Sending in a Claude thread whose persisted resume cursor points at a transcript
that no longer exists on this host (imported from another machine, host
reprovisioned) failed with the generic "Claude runtime stream failed." The
actual cause — the CLI's `No conversation found with session ID: <id>` — was
emitted one event earlier and then overwritten, so the thread gave no hint at
what was missing or how to recover.
Adapter: recognise the CLI's missing-transcript result, emit a runtime error
that names the session id and the expected `~/.claude/projects/<cwd>/<id>.jsonl`
path plus the two ways out (restore the file, or `t3 session reset`), and keep
that message through the subsequent stream exit instead of replacing it. The
resume cursor is deliberately left intact so the transcript can still be
restored from wherever the conversation ran.
CLI: `t3 session audit` lists every Claude thread whose transcript is missing
(or relocated) with the path to restore; `t3 session reset <threadId>` prints
the current cursor and, only with `--yes`, clears it so the thread starts a
fresh Claude session. Both run offline against the state DB and are safe while
the server is serving (WAL; bindings are re-read on every session start). The
offline CLI runtime layer previously private to `t3 import` is shared.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL labels Aug 25, 2026
@DanielGGordon

DanielGGordon commented Aug 25, 2026

Copy link
Copy Markdown
OwnerAuthor

Test deployment

This branch is running on test slot 7448 with a copy of the prod threads (so the stale-cursor threads are there to try).

Pairing link:https://15.204.108.12:7448/pair#token=9DHXVHVUCX8R
(one-time, short expiry — if it's stale, re-mint on the server with node scripts/test-status.ts --pair 7448)

To see the change: open a Claude thread whose transcript is missing (e.g. "Install Cursor CLI" or any claude-import-… thread for DanCode / gphotos-to-constant-contact) and send anything. Instead of "Claude runtime stream failed." the thread now shows which ~/.claude/projects/…/<session>.jsonl is missing and the two ways out (restore the file, or t3 session reset <threadId>).

CLI, from the worktree on the server:

node apps/server/src/bin.ts session audit # read-only list of affected threads + paths to restore
node apps/server/src/bin.ts session reset <threadId># dry run; add --yes to actually clear the cursor

Slot: external 7448 ⇄ loopback 3778.

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

Labels

size:XLvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@DanielGGordon
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(claude): explain missing-transcript resume failures; add t3 session audit|reset - #52

Open
DanielGGordon wants to merge 1 commit into
mainfrom
t3code/fix-message-send-failure
Open

fix(claude): explain missing-transcript resume failures; add t3 session audit|reset#52
DanielGGordon wants to merge 1 commit into
mainfrom
t3code/fix-message-send-failure

Conversation

@DanielGGordon

Copy link
Copy Markdown
Owner

Problem

Sending in a Claude thread whose persisted resume cursor points at a transcript that no longer exists on this host failed with only "Claude runtime stream failed." The real cause — Claude Code's No conversation found with session ID: <id> — was emitted one event earlier and then overwritten by the generic stream-exit error, so the thread gave no hint at what was missing or how to recover. Found on prod thread 89de3af4… ("Second Brain Architecture Review"); an audit of the prod DB shows 72 non-deleted Claude threads (43 unarchived, mostly claude-import-* from another machine) in the same state.

Changes

Adapter (ClaudeAdapter.ts, claudeSessionTranscript.ts)

  • Recognise the CLI's missing-transcript result error and emit a runtime error that names the session id, the expected ~/.claude/projects/<encoded cwd>/<id>.jsonl path, and the two ways out (restore the file and resend, or t3 session reset <threadId>). Detail payload carries reason: "resume_transcript_missing".
  • Keep that explanation through the subsequent stream exit instead of replacing it with "Claude runtime stream failed."
  • The resume cursor is deliberately not cleared — the transcript may still be recoverable from the machine the conversation ran on.

CLI (cli/session.ts, shared cli/offlineRuntime.ts)

  • t3 session audit [--json] [--include-deleted] [--all] [--projects-dir] — lists every Claude thread whose transcript is missing (or relocated under a different project folder) with lifecycle, title, cwd, session id and the exact path to restore. Read-only.
  • t3 session reset <threadId> [--yes] — prints the current cursor (so it can be restored by hand) and only clears it with --yes.
  • Both run offline against the state DB and are safe while the server is serving (WAL; the server re-reads bindings on every session start). The offline runtime layer that was private to t3 import is now shared.

Docs: README feature bullet, AGENTS.md ops section.

Verification

  • tsgo --noEmit clean; vp lint clean; vp fmt --check clean.
  • New tests: claudeSessionTranscript.test.ts (encoding, error parsing, message), cli/session.test.ts (binding → target, lifecycle, row formatting), ClaudeAdapter.test.ts ("explains a resume whose transcript is missing and keeps that explanation on stream exit").
  • Full apps/server suite: 1777 passed; the single failure (server.test.ts > preserves structured workspace rpc failures) is pre-existing and fails identically on main.
  • Ran t3 session audit against the live prod DB: 137 Claude threads with cursors → 65 present, 0 relocated, 72 missing, ~4s. t3 session reset dry run verified to leave the row untouched; on a thread with no cursor it reports "nothing to reset".

🤖 Generated with Claude Code

…ion audit|reset`
Sending in a Claude thread whose persisted resume cursor points at a transcript
that no longer exists on this host (imported from another machine, host
reprovisioned) failed with the generic "Claude runtime stream failed." The
actual cause — the CLI's `No conversation found with session ID: <id>` — was
emitted one event earlier and then overwritten, so the thread gave no hint at
what was missing or how to recover.
Adapter: recognise the CLI's missing-transcript result, emit a runtime error
that names the session id and the expected `~/.claude/projects/<cwd>/<id>.jsonl`
path plus the two ways out (restore the file, or `t3 session reset`), and keep
that message through the subsequent stream exit instead of replacing it. The
resume cursor is deliberately left intact so the transcript can still be
restored from wherever the conversation ran.
CLI: `t3 session audit` lists every Claude thread whose transcript is missing
(or relocated) with the path to restore; `t3 session reset <threadId>` prints
the current cursor and, only with `--yes`, clears it so the thread starts a
fresh Claude session. Both run offline against the state DB and are safe while
the server is serving (WAL; bindings are re-read on every session start). The
offline CLI runtime layer previously private to `t3 import` is shared.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL labels Aug 25, 2026
@DanielGGordon

DanielGGordon commented Aug 25, 2026

Copy link
Copy Markdown
OwnerAuthor

Test deployment

This branch is running on test slot 7448 with a copy of the prod threads (so the stale-cursor threads are there to try).

Pairing link:https://15.204.108.12:7448/pair#token=9DHXVHVUCX8R
(one-time, short expiry — if it's stale, re-mint on the server with node scripts/test-status.ts --pair 7448)

To see the change: open a Claude thread whose transcript is missing (e.g. "Install Cursor CLI" or any claude-import-… thread for DanCode / gphotos-to-constant-contact) and send anything. Instead of "Claude runtime stream failed." the thread now shows which ~/.claude/projects/…/<session>.jsonl is missing and the two ways out (restore the file, or t3 session reset <threadId>).

CLI, from the worktree on the server:

node apps/server/src/bin.ts session audit # read-only list of affected threads + paths to restore
node apps/server/src/bin.ts session reset <threadId># dry run; add --yes to actually clear the cursor

Slot: external 7448 ⇄ loopback 3778.

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

Labels

size:XLvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@DanielGGordon
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(claude): explain missing-transcript resume failures; add t3 session audit|reset - #52

Open
DanielGGordon wants to merge 1 commit into
mainfrom
t3code/fix-message-send-failure
Open

fix(claude): explain missing-transcript resume failures; add t3 session audit|reset#52
DanielGGordon wants to merge 1 commit into
mainfrom
t3code/fix-message-send-failure

Conversation

@DanielGGordon

Copy link
Copy Markdown
Owner

Problem

Sending in a Claude thread whose persisted resume cursor points at a transcript that no longer exists on this host failed with only "Claude runtime stream failed." The real cause — Claude Code's No conversation found with session ID: <id> — was emitted one event earlier and then overwritten by the generic stream-exit error, so the thread gave no hint at what was missing or how to recover. Found on prod thread 89de3af4… ("Second Brain Architecture Review"); an audit of the prod DB shows 72 non-deleted Claude threads (43 unarchived, mostly claude-import-* from another machine) in the same state.

Changes

Adapter (ClaudeAdapter.ts, claudeSessionTranscript.ts)

  • Recognise the CLI's missing-transcript result error and emit a runtime error that names the session id, the expected ~/.claude/projects/<encoded cwd>/<id>.jsonl path, and the two ways out (restore the file and resend, or t3 session reset <threadId>). Detail payload carries reason: "resume_transcript_missing".
  • Keep that explanation through the subsequent stream exit instead of replacing it with "Claude runtime stream failed."
  • The resume cursor is deliberately not cleared — the transcript may still be recoverable from the machine the conversation ran on.

CLI (cli/session.ts, shared cli/offlineRuntime.ts)

  • t3 session audit [--json] [--include-deleted] [--all] [--projects-dir] — lists every Claude thread whose transcript is missing (or relocated under a different project folder) with lifecycle, title, cwd, session id and the exact path to restore. Read-only.
  • t3 session reset <threadId> [--yes] — prints the current cursor (so it can be restored by hand) and only clears it with --yes.
  • Both run offline against the state DB and are safe while the server is serving (WAL; the server re-reads bindings on every session start). The offline runtime layer that was private to t3 import is now shared.

Docs: README feature bullet, AGENTS.md ops section.

Verification

  • tsgo --noEmit clean; vp lint clean; vp fmt --check clean.
  • New tests: claudeSessionTranscript.test.ts (encoding, error parsing, message), cli/session.test.ts (binding → target, lifecycle, row formatting), ClaudeAdapter.test.ts ("explains a resume whose transcript is missing and keeps that explanation on stream exit").
  • Full apps/server suite: 1777 passed; the single failure (server.test.ts > preserves structured workspace rpc failures) is pre-existing and fails identically on main.
  • Ran t3 session audit against the live prod DB: 137 Claude threads with cursors → 65 present, 0 relocated, 72 missing, ~4s. t3 session reset dry run verified to leave the row untouched; on a thread with no cursor it reports "nothing to reset".

🤖 Generated with Claude Code

…ion audit|reset`
Sending in a Claude thread whose persisted resume cursor points at a transcript
that no longer exists on this host (imported from another machine, host
reprovisioned) failed with the generic "Claude runtime stream failed." The
actual cause — the CLI's `No conversation found with session ID: <id>` — was
emitted one event earlier and then overwritten, so the thread gave no hint at
what was missing or how to recover.
Adapter: recognise the CLI's missing-transcript result, emit a runtime error
that names the session id and the expected `~/.claude/projects/<cwd>/<id>.jsonl`
path plus the two ways out (restore the file, or `t3 session reset`), and keep
that message through the subsequent stream exit instead of replacing it. The
resume cursor is deliberately left intact so the transcript can still be
restored from wherever the conversation ran.
CLI: `t3 session audit` lists every Claude thread whose transcript is missing
(or relocated) with the path to restore; `t3 session reset <threadId>` prints
the current cursor and, only with `--yes`, clears it so the thread starts a
fresh Claude session. Both run offline against the state DB and are safe while
the server is serving (WAL; bindings are re-read on every session start). The
offline CLI runtime layer previously private to `t3 import` is shared.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL labels Aug 25, 2026
@DanielGGordon

DanielGGordon commented Aug 25, 2026

Copy link
Copy Markdown
OwnerAuthor

Test deployment

This branch is running on test slot 7448 with a copy of the prod threads (so the stale-cursor threads are there to try).

Pairing link:https://15.204.108.12:7448/pair#token=9DHXVHVUCX8R
(one-time, short expiry — if it's stale, re-mint on the server with node scripts/test-status.ts --pair 7448)

To see the change: open a Claude thread whose transcript is missing (e.g. "Install Cursor CLI" or any claude-import-… thread for DanCode / gphotos-to-constant-contact) and send anything. Instead of "Claude runtime stream failed." the thread now shows which ~/.claude/projects/…/<session>.jsonl is missing and the two ways out (restore the file, or t3 session reset <threadId>).

CLI, from the worktree on the server:

node apps/server/src/bin.ts session audit # read-only list of affected threads + paths to restore
node apps/server/src/bin.ts session reset <threadId># dry run; add --yes to actually clear the cursor

Slot: external 7448 ⇄ loopback 3778.

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

Labels

size:XLvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@DanielGGordon
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(claude): explain missing-transcript resume failures; add t3 session audit|reset - #52

Open
DanielGGordon wants to merge 1 commit into
mainfrom
t3code/fix-message-send-failure
Open

fix(claude): explain missing-transcript resume failures; add t3 session audit|reset#52
DanielGGordon wants to merge 1 commit into
mainfrom
t3code/fix-message-send-failure

Conversation

@DanielGGordon

Copy link
Copy Markdown
Owner

Problem

Sending in a Claude thread whose persisted resume cursor points at a transcript that no longer exists on this host failed with only "Claude runtime stream failed." The real cause — Claude Code's No conversation found with session ID: <id> — was emitted one event earlier and then overwritten by the generic stream-exit error, so the thread gave no hint at what was missing or how to recover. Found on prod thread 89de3af4… ("Second Brain Architecture Review"); an audit of the prod DB shows 72 non-deleted Claude threads (43 unarchived, mostly claude-import-* from another machine) in the same state.

Changes

Adapter (ClaudeAdapter.ts, claudeSessionTranscript.ts)

  • Recognise the CLI's missing-transcript result error and emit a runtime error that names the session id, the expected ~/.claude/projects/<encoded cwd>/<id>.jsonl path, and the two ways out (restore the file and resend, or t3 session reset <threadId>). Detail payload carries reason: "resume_transcript_missing".
  • Keep that explanation through the subsequent stream exit instead of replacing it with "Claude runtime stream failed."
  • The resume cursor is deliberately not cleared — the transcript may still be recoverable from the machine the conversation ran on.

CLI (cli/session.ts, shared cli/offlineRuntime.ts)

  • t3 session audit [--json] [--include-deleted] [--all] [--projects-dir] — lists every Claude thread whose transcript is missing (or relocated under a different project folder) with lifecycle, title, cwd, session id and the exact path to restore. Read-only.
  • t3 session reset <threadId> [--yes] — prints the current cursor (so it can be restored by hand) and only clears it with --yes.
  • Both run offline against the state DB and are safe while the server is serving (WAL; the server re-reads bindings on every session start). The offline runtime layer that was private to t3 import is now shared.

Docs: README feature bullet, AGENTS.md ops section.

Verification

  • tsgo --noEmit clean; vp lint clean; vp fmt --check clean.
  • New tests: claudeSessionTranscript.test.ts (encoding, error parsing, message), cli/session.test.ts (binding → target, lifecycle, row formatting), ClaudeAdapter.test.ts ("explains a resume whose transcript is missing and keeps that explanation on stream exit").
  • Full apps/server suite: 1777 passed; the single failure (server.test.ts > preserves structured workspace rpc failures) is pre-existing and fails identically on main.
  • Ran t3 session audit against the live prod DB: 137 Claude threads with cursors → 65 present, 0 relocated, 72 missing, ~4s. t3 session reset dry run verified to leave the row untouched; on a thread with no cursor it reports "nothing to reset".

🤖 Generated with Claude Code

…ion audit|reset`
Sending in a Claude thread whose persisted resume cursor points at a transcript
that no longer exists on this host (imported from another machine, host
reprovisioned) failed with the generic "Claude runtime stream failed." The
actual cause — the CLI's `No conversation found with session ID: <id>` — was
emitted one event earlier and then overwritten, so the thread gave no hint at
what was missing or how to recover.
Adapter: recognise the CLI's missing-transcript result, emit a runtime error
that names the session id and the expected `~/.claude/projects/<cwd>/<id>.jsonl`
path plus the two ways out (restore the file, or `t3 session reset`), and keep
that message through the subsequent stream exit instead of replacing it. The
resume cursor is deliberately left intact so the transcript can still be
restored from wherever the conversation ran.
CLI: `t3 session audit` lists every Claude thread whose transcript is missing
(or relocated) with the path to restore; `t3 session reset <threadId>` prints
the current cursor and, only with `--yes`, clears it so the thread starts a
fresh Claude session. Both run offline against the state DB and are safe while
the server is serving (WAL; bindings are re-read on every session start). The
offline CLI runtime layer previously private to `t3 import` is shared.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL labels Aug 25, 2026
@DanielGGordon

DanielGGordon commented Aug 25, 2026

Copy link
Copy Markdown
OwnerAuthor

Test deployment

This branch is running on test slot 7448 with a copy of the prod threads (so the stale-cursor threads are there to try).

Pairing link:https://15.204.108.12:7448/pair#token=9DHXVHVUCX8R
(one-time, short expiry — if it's stale, re-mint on the server with node scripts/test-status.ts --pair 7448)

To see the change: open a Claude thread whose transcript is missing (e.g. "Install Cursor CLI" or any claude-import-… thread for DanCode / gphotos-to-constant-contact) and send anything. Instead of "Claude runtime stream failed." the thread now shows which ~/.claude/projects/…/<session>.jsonl is missing and the two ways out (restore the file, or t3 session reset <threadId>).

CLI, from the worktree on the server:

node apps/server/src/bin.ts session audit # read-only list of affected threads + paths to restore
node apps/server/src/bin.ts session reset <threadId># dry run; add --yes to actually clear the cursor

Slot: external 7448 ⇄ loopback 3778.

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

Labels

size:XLvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@DanielGGordon
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(claude): explain missing-transcript resume failures; add t3 session audit|reset - #52

Open
DanielGGordon wants to merge 1 commit into
mainfrom
t3code/fix-message-send-failure
Open

fix(claude): explain missing-transcript resume failures; add t3 session audit|reset#52
DanielGGordon wants to merge 1 commit into
mainfrom
t3code/fix-message-send-failure

Conversation

@DanielGGordon

Copy link
Copy Markdown
Owner

Problem

Sending in a Claude thread whose persisted resume cursor points at a transcript that no longer exists on this host failed with only "Claude runtime stream failed." The real cause — Claude Code's No conversation found with session ID: <id> — was emitted one event earlier and then overwritten by the generic stream-exit error, so the thread gave no hint at what was missing or how to recover. Found on prod thread 89de3af4… ("Second Brain Architecture Review"); an audit of the prod DB shows 72 non-deleted Claude threads (43 unarchived, mostly claude-import-* from another machine) in the same state.

Changes

Adapter (ClaudeAdapter.ts, claudeSessionTranscript.ts)

  • Recognise the CLI's missing-transcript result error and emit a runtime error that names the session id, the expected ~/.claude/projects/<encoded cwd>/<id>.jsonl path, and the two ways out (restore the file and resend, or t3 session reset <threadId>). Detail payload carries reason: "resume_transcript_missing".
  • Keep that explanation through the subsequent stream exit instead of replacing it with "Claude runtime stream failed."
  • The resume cursor is deliberately not cleared — the transcript may still be recoverable from the machine the conversation ran on.

CLI (cli/session.ts, shared cli/offlineRuntime.ts)

  • t3 session audit [--json] [--include-deleted] [--all] [--projects-dir] — lists every Claude thread whose transcript is missing (or relocated under a different project folder) with lifecycle, title, cwd, session id and the exact path to restore. Read-only.
  • t3 session reset <threadId> [--yes] — prints the current cursor (so it can be restored by hand) and only clears it with --yes.
  • Both run offline against the state DB and are safe while the server is serving (WAL; the server re-reads bindings on every session start). The offline runtime layer that was private to t3 import is now shared.

Docs: README feature bullet, AGENTS.md ops section.

Verification

  • tsgo --noEmit clean; vp lint clean; vp fmt --check clean.
  • New tests: claudeSessionTranscript.test.ts (encoding, error parsing, message), cli/session.test.ts (binding → target, lifecycle, row formatting), ClaudeAdapter.test.ts ("explains a resume whose transcript is missing and keeps that explanation on stream exit").
  • Full apps/server suite: 1777 passed; the single failure (server.test.ts > preserves structured workspace rpc failures) is pre-existing and fails identically on main.
  • Ran t3 session audit against the live prod DB: 137 Claude threads with cursors → 65 present, 0 relocated, 72 missing, ~4s. t3 session reset dry run verified to leave the row untouched; on a thread with no cursor it reports "nothing to reset".

🤖 Generated with Claude Code

…ion audit|reset`
Sending in a Claude thread whose persisted resume cursor points at a transcript
that no longer exists on this host (imported from another machine, host
reprovisioned) failed with the generic "Claude runtime stream failed." The
actual cause — the CLI's `No conversation found with session ID: <id>` — was
emitted one event earlier and then overwritten, so the thread gave no hint at
what was missing or how to recover.
Adapter: recognise the CLI's missing-transcript result, emit a runtime error
that names the session id and the expected `~/.claude/projects/<cwd>/<id>.jsonl`
path plus the two ways out (restore the file, or `t3 session reset`), and keep
that message through the subsequent stream exit instead of replacing it. The
resume cursor is deliberately left intact so the transcript can still be
restored from wherever the conversation ran.
CLI: `t3 session audit` lists every Claude thread whose transcript is missing
(or relocated) with the path to restore; `t3 session reset <threadId>` prints
the current cursor and, only with `--yes`, clears it so the thread starts a
fresh Claude session. Both run offline against the state DB and are safe while
the server is serving (WAL; bindings are re-read on every session start). The
offline CLI runtime layer previously private to `t3 import` is shared.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL labels Aug 25, 2026
@DanielGGordon

DanielGGordon commented Aug 25, 2026

Copy link
Copy Markdown
OwnerAuthor

Test deployment

This branch is running on test slot 7448 with a copy of the prod threads (so the stale-cursor threads are there to try).

Pairing link:https://15.204.108.12:7448/pair#token=9DHXVHVUCX8R
(one-time, short expiry — if it's stale, re-mint on the server with node scripts/test-status.ts --pair 7448)

To see the change: open a Claude thread whose transcript is missing (e.g. "Install Cursor CLI" or any claude-import-… thread for DanCode / gphotos-to-constant-contact) and send anything. Instead of "Claude runtime stream failed." the thread now shows which ~/.claude/projects/…/<session>.jsonl is missing and the two ways out (restore the file, or t3 session reset <threadId>).

CLI, from the worktree on the server:

node apps/server/src/bin.ts session audit # read-only list of affected threads + paths to restore
node apps/server/src/bin.ts session reset <threadId># dry run; add --yes to actually clear the cursor

Slot: external 7448 ⇄ loopback 3778.

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

Labels

size:XLvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@DanielGGordon
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(claude): explain missing-transcript resume failures; add t3 session audit|reset - #52

Open
DanielGGordon wants to merge 1 commit into
mainfrom
t3code/fix-message-send-failure
Open

fix(claude): explain missing-transcript resume failures; add t3 session audit|reset#52
DanielGGordon wants to merge 1 commit into
mainfrom
t3code/fix-message-send-failure

Conversation

@DanielGGordon

Copy link
Copy Markdown
Owner

Problem

Sending in a Claude thread whose persisted resume cursor points at a transcript that no longer exists on this host failed with only "Claude runtime stream failed." The real cause — Claude Code's No conversation found with session ID: <id> — was emitted one event earlier and then overwritten by the generic stream-exit error, so the thread gave no hint at what was missing or how to recover. Found on prod thread 89de3af4… ("Second Brain Architecture Review"); an audit of the prod DB shows 72 non-deleted Claude threads (43 unarchived, mostly claude-import-* from another machine) in the same state.

Changes

Adapter (ClaudeAdapter.ts, claudeSessionTranscript.ts)

  • Recognise the CLI's missing-transcript result error and emit a runtime error that names the session id, the expected ~/.claude/projects/<encoded cwd>/<id>.jsonl path, and the two ways out (restore the file and resend, or t3 session reset <threadId>). Detail payload carries reason: "resume_transcript_missing".
  • Keep that explanation through the subsequent stream exit instead of replacing it with "Claude runtime stream failed."
  • The resume cursor is deliberately not cleared — the transcript may still be recoverable from the machine the conversation ran on.

CLI (cli/session.ts, shared cli/offlineRuntime.ts)

  • t3 session audit [--json] [--include-deleted] [--all] [--projects-dir] — lists every Claude thread whose transcript is missing (or relocated under a different project folder) with lifecycle, title, cwd, session id and the exact path to restore. Read-only.
  • t3 session reset <threadId> [--yes] — prints the current cursor (so it can be restored by hand) and only clears it with --yes.
  • Both run offline against the state DB and are safe while the server is serving (WAL; the server re-reads bindings on every session start). The offline runtime layer that was private to t3 import is now shared.

Docs: README feature bullet, AGENTS.md ops section.

Verification

  • tsgo --noEmit clean; vp lint clean; vp fmt --check clean.
  • New tests: claudeSessionTranscript.test.ts (encoding, error parsing, message), cli/session.test.ts (binding → target, lifecycle, row formatting), ClaudeAdapter.test.ts ("explains a resume whose transcript is missing and keeps that explanation on stream exit").
  • Full apps/server suite: 1777 passed; the single failure (server.test.ts > preserves structured workspace rpc failures) is pre-existing and fails identically on main.
  • Ran t3 session audit against the live prod DB: 137 Claude threads with cursors → 65 present, 0 relocated, 72 missing, ~4s. t3 session reset dry run verified to leave the row untouched; on a thread with no cursor it reports "nothing to reset".

🤖 Generated with Claude Code

…ion audit|reset`
Sending in a Claude thread whose persisted resume cursor points at a transcript
that no longer exists on this host (imported from another machine, host
reprovisioned) failed with the generic "Claude runtime stream failed." The
actual cause — the CLI's `No conversation found with session ID: <id>` — was
emitted one event earlier and then overwritten, so the thread gave no hint at
what was missing or how to recover.
Adapter: recognise the CLI's missing-transcript result, emit a runtime error
that names the session id and the expected `~/.claude/projects/<cwd>/<id>.jsonl`
path plus the two ways out (restore the file, or `t3 session reset`), and keep
that message through the subsequent stream exit instead of replacing it. The
resume cursor is deliberately left intact so the transcript can still be
restored from wherever the conversation ran.
CLI: `t3 session audit` lists every Claude thread whose transcript is missing
(or relocated) with the path to restore; `t3 session reset <threadId>` prints
the current cursor and, only with `--yes`, clears it so the thread starts a
fresh Claude session. Both run offline against the state DB and are safe while
the server is serving (WAL; bindings are re-read on every session start). The
offline CLI runtime layer previously private to `t3 import` is shared.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL labels Aug 25, 2026
@DanielGGordon

DanielGGordon commented Aug 25, 2026

Copy link
Copy Markdown
OwnerAuthor

Test deployment

This branch is running on test slot 7448 with a copy of the prod threads (so the stale-cursor threads are there to try).

Pairing link:https://15.204.108.12:7448/pair#token=9DHXVHVUCX8R
(one-time, short expiry — if it's stale, re-mint on the server with node scripts/test-status.ts --pair 7448)

To see the change: open a Claude thread whose transcript is missing (e.g. "Install Cursor CLI" or any claude-import-… thread for DanCode / gphotos-to-constant-contact) and send anything. Instead of "Claude runtime stream failed." the thread now shows which ~/.claude/projects/…/<session>.jsonl is missing and the two ways out (restore the file, or t3 session reset <threadId>).

CLI, from the worktree on the server:

node apps/server/src/bin.ts session audit # read-only list of affected threads + paths to restore
node apps/server/src/bin.ts session reset <threadId># dry run; add --yes to actually clear the cursor

Slot: external 7448 ⇄ loopback 3778.

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

Labels

size:XLvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@DanielGGordon