{"record":{"id":"f7b64802d739d650","repo":"BigPizzaV3/CodexPlusPlus","slug":"id-bridge-data","errorCode":null,"errorMessage":"记录中的任务 ID 与当前任务不一致","messagePattern":"记录中的任务 ID 与当前任务不一致","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"tools/conversation-canvas/bridge-data.mjs","lineNumber":17,"sourceCode":"import {parseMessage,buildGraph} from './model.mjs';\n\nexport function graphFromExport(result, threadId, annotations={nodes:[]}) {\n  if(result?.status!=='ok')throw new Error(result?.message||'Codex++ 会话读取失败');\n  if(result.kind!=='codex-rollout'||result.session_id!==threadId||typeof result.content!=='string')throw new Error('会话接口返回了不匹配的数据');\n  const messages=[],seen=new Set();\n  let declaredId=null;\n  // Ignore an unfinished JSONL tail; the next refresh will read the completed line.\n  const lines=result.content.slice(0,result.content.lastIndexOf('\\n')+1).split('\\n');\n  for(let i=0;i<lines.length;i++){\n    if(!lines[i].trim())continue;\n    let r;try{r=JSON.parse(lines[i]);}catch{continue;}\n    if(r.type==='session_meta')declaredId=r.payload?.id;\n    const m=parseMessage(r,`message-${threadId}-line-${i}`);\n    if(m&&!seen.has(m.id)){seen.add(m.id);messages.push(m);}\n  }\n  if(declaredId&&declaredId!==threadId)throw new Error('记录中的任务 ID 与当前任务不一致');\n  return {threadId,title:annotations.title||'当前对话',messages,...buildGraph(messages,annotations)};\n}\n","sourceCodeStart":1,"sourceCodeEnd":20,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/tools/conversation-canvas/bridge-data.mjs#L1-L20","documentation":"bridge-data.mjs's graphFromExport, after parsing all rollout lines, throws '记录中的任务 ID 与当前任务不一致' when the rollout's session_meta payload.id (declaredId) differs from the requested threadId. This prevents graphing another session's transcript under the current thread.","triggerScenarios":"graphFromExport called via sync with rollout content whose session_meta declares a different id than the threadId argument — wrong rollout file served, thread forked/resumed with a new id, or merged/renamed rollout files.","commonSituations":"Host serving a cached rollout for an old task; resuming a session that writes a new session_meta id; consumers reading the wrong .jsonl in ~/.codex/sessions.","solutions":["Refresh so the bridge re-reads the rollout matching the current threadId","Fix the host's rollout-path resolution for the requested id","If the id legitimately changed on resume, remap the canvas task id to declaredId","Ensure only one session_meta with the correct id exists in the file"],"exampleFix":"// before\nif(declaredId&&declaredId!==threadId)throw new Error('记录中的任务 ID 与当前任务不一致');\n// after\nif(declaredId&&declaredId!==threadId){ console.warn(`rollout ${declaredId} != thread ${threadId}`); throw new Error('记录中的任务 ID 与当前任务不一致'); }","handlingStrategy":"validation","validationCode":"function declaredSessionId(content){ for (const line of content.split('\\n')) { try { const r=JSON.parse(line); if (r.type==='session_meta') return r.payload?.id; } catch {} } return null; }\nif (declaredSessionId(result.content) !== threadId) throw new Error('记录中的任务 ID 与当前任务不一致');","typeGuard":null,"tryCatchPattern":"try { return graphFromExport(result, threadId, ann); } catch (e) { if (String(e.message).includes('不一致')) { console.warn('stale rollout for', threadId); return resync(); } throw e; }","preventionTips":["Resolve the rollout file strictly by thread id","Re-read after task resume/fork since ids can change","Validate session_meta before long-running parses"],"tags":["identity","validation","runtime"],"backgroundTag":"identifier-mismatch","analyzedSha":"b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6","analyzedAt":"2026-09-19T23:35:21.129Z","contentChangedAt":"2026-09-19T23:35:21.129Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}