{"record":{"id":"4bbfa0e8a7149ad4","repo":"stablyai/orca","slug":"recorded-benchmark-helper-pid-changed-before-signa","errorCode":null,"errorMessage":"Recorded benchmark helper PID changed before signaling","messagePattern":"Recorded benchmark helper PID changed before signaling","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"config/scripts/macos-computer-helper-owner-loss-processes.mjs","lineNumber":356,"sourceCode":"  expectedCommandFragment,\n  signal,\n  operations = processSignalOperations\n) {\n  validateDetachedIdentity(identity, expectedCommandFragment)\n  const currentIdentity = operations.processIdentity(identity.pid)\n  if (!currentIdentity) {\n    return false\n  }\n  if (!sameIdentity(currentIdentity, identity)) {\n    throw new Error('Recorded benchmark helper PID now belongs to another process')\n  }\n  let stopped = false\n  try {\n    operations.signalProcess(identity.pid, 'SIGSTOP')\n    stopped = true\n    const stoppedIdentity = operations.processIdentity(identity.pid)\n    if (!sameIdentity(stoppedIdentity, identity)) {\n      throw new Error('Recorded benchmark helper PID changed before signaling')\n    }\n    operations.signalProcess(-identity.pgid, signal)\n    if (signal !== 'SIGKILL') {\n      operations.signalProcess(-identity.pgid, 'SIGCONT')\n    }\n    stopped = false\n    return true\n  } catch (error) {\n    let resumeError\n    if (stopped) {\n      try {\n        operations.signalProcess(identity.pid, 'SIGCONT')\n      } catch (caught) {\n        if (caught?.code !== 'ESRCH') {\n          resumeError = caught\n        }\n      }\n    }","sourceCodeStart":338,"sourceCodeEnd":374,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/config/scripts/macos-computer-helper-owner-loss-processes.mjs#L338-L374","documentation":"Within signalProcessIdentity, after SIGSTOP'ing the recorded helper, the code re-reads its identity. If sameIdentity fails, the process changed during the stop window — same PID-recycle race as 144 but caught one step later. The function then attempts a SIGCONT recovery before re-throwing.","triggerScenarios":"operations.signalProcess(identity.pid, 'SIGSTOP') succeeds, then operations.processIdentity(identity.pid) returns an identity whose pgid or command differs from the recorded one.","commonSituations":"Helper exited immediately upon SIGSTOP (signal handler called _exit) and the PID was reused before the re-check; or test stubs return inconsistent identities across calls.","solutions":["Treat as an invalid trial — the helper is not reliably controllable; re-spawn it","Stop using SIGSTOP for helpers with handlers that exit on stop; use SIGKILL-only signaling for those","Make test stubs deterministic: processIdentity should return the same object for a given pid until an explicit exit is simulated","Add a processIdentityIsCurrent gate before signaling to fail fast with 144 instead"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  signalProcessIdentity(recorded, frag, sig)\n} catch (error) {\n  if (/changed before signaling/.test(error.message)) {\n    killProcessMatchingCommand([frag])\n  } else throw error\n}","preventionTips":["Avoid SIGSTOP for helpers that exit on stop; use SIGKILL-only signaling","Make test stubs return identical identities for a pid until an explicit exit","Re-spawn the helper rather than retrying on the same recycled pid"],"tags":["pid-reuse","race-condition","process-management","signals"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}