{"record":{"id":"84e040dd11fb70c4","repo":"deepseek-ai/deepseek-harness","slug":"compactregion-end-seq-end-is-not-a-balanced-bo","errorCode":null,"errorMessage":"compactRegion: end seq ${end} is not a balanced boundary (would split a step, or the step is still open)","messagePattern":"compactRegion: end seq (.+?) is not a balanced boundary \\(would split a step, or the step is still open\\)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/compaction/compaction-basic/src/region.ts","lineNumber":332,"sourceCode":"/** Validate one requested surface-position span before asynchronous work begins. */\nfunction validateSurfaceRegion(session: Session, start: number, end: number): SurfaceSelection {\n  const nodes = session.surface.nodes\n  const startIdx = nodes.indexOf(start)\n  const endIdx = nodes.indexOf(end)\n  if (startIdx === -1) throw new Error(`compactRegion: start seq ${start} not found in surface`)\n  if (endIdx === -1) throw new Error(`compactRegion: end seq ${end} not found in surface`)\n  if (startIdx > endIdx) {\n    throw new Error(\n      `compactRegion: start seq ${start} (position ${startIdx}) is after end seq ${end} (position ${endIdx}) on the surface`,\n    )\n  }\n  // oxlint-disable-next-line typescript/no-non-null-assertion\n  if (!toolPairingBalancedBefore(session, nodes[startIdx]!)) {\n    throw new Error(`compactRegion: start seq ${start} is not a balanced boundary (would split a step's tool-call/result pair)`)\n  }\n  // oxlint-disable-next-line typescript/no-non-null-assertion\n  if (!toolPairingBalancedAfter(session, nodes[endIdx]!)) {\n    throw new Error(`compactRegion: end seq ${end} is not a balanced boundary (would split a step, or the step is still open)`)\n  }\n\n  return { start, end, startIdx, endIdx, shadowedSeqs: nodes.slice(startIdx, endIdx + 1) }\n}\n\n/** Snapshot pricing and replay input for a validated surface range. */\nfunction prepareCompaction(\n  dependencies: RegionDependencies,\n  session: Session,\n  selection: SurfaceSelection,\n): PreparedCompaction {\n  const measurement = dependencies.meter.measure(session)\n  const selectedNodes = measurement.nodes.slice(selection.startIdx, selection.endIdx + 1)\n  if (selectedNodes.length !== selection.shadowedSeqs.length\n    || selectedNodes.some((node, index) => node.seq !== selection.shadowedSeqs[index])) {\n    throw new SurfaceChangedError('compaction: selected surface changed before summarization began')\n  }\n  return {","sourceCodeStart":314,"sourceCodeEnd":350,"githubUrl":"https://github.com/deepseek-ai/deepseek-harness/blob/b150a551b8d465e31e418e1b2eaf5e79bbb7d28e/packages/compaction/compaction-basic/src/region.ts#L314-L350","documentation":"The cut immediately after `end` is crossed by an in-progress tool call — the replacement would split a step, or the step at the surface tail is still open (a tool-call whose tool/result has not landed yet). Checked with toolPairingBalancedAfter; both edges must be balanced so assistant tool calls stay paired with their results.","triggerScenarios":"`end` lands on an assistant message whose tool-calls are answered by later tool/result nodes; `end` is the surface tail while tools are still executing in the open turn; ending on a node whose following cut has a nonzero in-progress tool-call count.","commonSituations":"Calling compactRegion mid-turn while subprocess or shell tools are still running; cutting at the last assistant message of a parallel-tool step.","solutions":["Move end earlier to a seq where toolPairingBalancedAfter(session, seq) returns true","If the tail step is still open, wait for its tool results to land before compacting","End on a completed tool/result or on a user-message boundary"],"exampleFix":"// before: end on the surface tail while a tool call is open\nawait ctx.compaction.compactRegion(start, nodes[nodes.length - 1]!, agent)\n\n// after: back off to a balanced trailing cut\nimport { toolPairingBalancedAfter } from '@deepseek-ai/dsh-compaction'\nconst nodes = agent.session.surface.nodes\nlet j = nodes.length - 1\nwhile (!toolPairingBalancedAfter(agent.session, nodes[j]!)) j -= 1\nawait ctx.compaction.compactRegion(start, nodes[j]!, agent)","handlingStrategy":"validation","validationCode":"import { toolPairingBalancedAfter } from '@deepseek-ai/dsh-compaction'\nif (!toolPairingBalancedAfter(agent.session, end)) {\n  // back the end off to the previous balanced cut, or wait for open steps to close\n  const nodes = agent.session.surface.nodes\n  let j = nodes.indexOf(end)\n  while (!toolPairingBalancedAfter(agent.session, nodes[j]!)) j -= 1\n  end = nodes[j]!\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Check toolPairingBalancedAfter on the end seq before every compactRegion call","Do not end a span at the surface tail while a tool call is unanswered","Compact when the turn is between steps, not while tools are executing"],"tags":["compaction","tool-calls","surface","validation"],"backgroundTag":"unbalanced-tool-call-boundary","analyzedSha":"b150a551b8d465e31e418e1b2eaf5e79bbb7d28e","analyzedAt":"2026-08-24T18:12:29.105Z","schemaVersion":2},"datasetVersion":"2026-08-24T22:17:12.610Z"}