{"record":{"id":"c23f14d018a4eb39","repo":"stablyai/orca","slug":"need-2-terminals-to-bulk-switch-got-switchtarg","errorCode":null,"errorMessage":"Need ≥2 terminals to bulk-switch; got ${switchTargets.length}. notes=${notes.join('; ')}","messagePattern":"Need ≥2 terminals to bulk-switch; got (.+?)\\. notes=(.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"config/scripts/live-remote-bulk-open-freeze-repro.mjs","lineNumber":190,"sourceCode":"        (t) => typeof t.handle === 'string' && t.handle.startsWith('term_') && t.connected !== false\n      )\n      .map((t) => ({ handle: t.handle, title: t.title, worktreeId: t.worktreeId }))\n    notes.push(`live terminals listed=${live.length}`)\n  } catch (error) {\n    notes.push(`terminal list failed: ${String(error).slice(0, 200)}`)\n  }\n\n  let switchTargets = [...created.map((c) => c.handle), ...live.map((t) => t.handle)].filter(\n    (v, i, a) => typeof v === 'string' && a.indexOf(v) === i\n  )\n\n  if (shouldCapSwitchTargets(maxSwitchTargets) && switchTargets.length > maxSwitchTargets) {\n    switchTargets = applySwitchTargetCap(switchTargets, maxSwitchTargets)\n    amplificationSteps.push(`capped switchTargets=${maxSwitchTargets}`)\n  }\n\n  if (switchTargets.length < 2) {\n    throw new Error(\n      `Need ≥2 terminals to bulk-switch; got ${switchTargets.length}. notes=${notes.join('; ')}`\n    )\n  }\n\n  amplificationSteps.push(\n    `switchTargets=${switchTargets.length} passes=${switchPasses} parallel=${parallel}`\n  )\n  console.log(\n    `[live-freeze] bulk-switching ${switchTargets.length} terminals × ${switchPasses} passes (parallel=${parallel})`\n  )\n\n  let maxSwitchMs = 0\n  let maxBatchWallMs = 0\n  let sumSwitchMs = 0\n  let switchCount = 0\n  const switchStarted = performance.now()\n\n  for (let pass = 0; pass < switchPasses; pass += 1) {","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/config/scripts/live-remote-bulk-open-freeze-repro.mjs#L172-L208","documentation":"The bulk-switch phase requires at least two distinct terminal handles to exercise cross-terminal switching under load. The script unions newly-created terminals with already-live ones, dedupes by handle, optionally caps the set, and then asserts >= 2 remain. With fewer than two, the switch amplification would be a degenerate no-op that cannot reproduce the freeze.","triggerScenarios":"createCount is 0 or all create calls failed AND the live terminal list returned zero or one handle; or the cap (maxSwitchTargets) reduced the deduped set below 2; or handles came back as non-strings and were filtered out by the typeof v === 'string' guard.","commonSituations":"Running with createCount=0 against an idle environment with one open terminal, a remote where terminal creation silently failed, a version mismatch returning handles under a different field name so they all get filtered, or an overly aggressive maxSwitchTargets cap.","solutions":["Increase createCount so at least two terminals are guaranteed created, or open terminals manually first.","Inspect the joined notes string in the message — it reports list failures and counts that pinpoint whether create or list is the lossy step.","If applySwitchTargetCap is collapsing the set, raise maxSwitchTargets or disable the cap via shouldCapSwitchTargets.","Verify the live terminal handle field name matches what listLiveTerminalHandles reads so dedup keeps the values."],"exampleFix":"// before\nconst createCount = 0\n\n// after\nconst createCount = Math.max(2, createCount)","handlingStrategy":"validation","validationCode":"if (createCount + liveCount < 2) {\n  throw new Error(`Need >=2 terminals for bulk-switch; createCount=${createCount} live=${liveCount}`)\n}","typeGuard":"const hasMinHandles = (arr, n = 2) => Array.isArray(arr) && arr.filter(h => typeof h === 'string').length >= n","tryCatchPattern":null,"preventionTips":["Compute the expected handle union size before launching the expensive switch phase.","Log created.length and live.length into notes so a shortfall is diagnosable.","Disable the switch-target cap when the source set is already small."],"tags":["terminal","validation","bulk-switch","freeze-repro"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}