Skip to content

fix(orch): engine-worker IPC crashes Pi on stale extension context #620

Description

@daemons2000

Summary

TaskPlane 0.30.4 crashes Pi 0.83 during normal Runtime V2 batch startup when the asynchronous engine-worker IPC handler uses a captured ExtensionContext after Pi has marked it stale.

The engine subprocess may continue briefly, but the supervising Pi process exits. This is a TaskPlane/Pi infrastructure failure before normal lane supervision, not a worker-model failure.

Environment

  • TaskPlane: 0.30.4
  • Pi: @earendil-works/pi-coding-agent 0.83.0
  • Node.js: 24.18.0
  • OS: Windows
  • Orchestration: repo mode, one supervised lane

Reproduction

From a configured repository with one ready packet:

pi --approve --no-session --thinking high -p "/orch taskplane-tasks/TP-XXX/PROMPT.md"

The same exception reproduced through a persistent direct-Node Pi invocation, so this is not specific to --no-session print mode.

Observed behavior

TaskPlane begins batch planning, then Pi exits:

Error: This extension ctx is stale after session replacement or reload.
    at ExtensionRunner.assertActive (.../pi-coding-agent/dist/core/extensions/runner.js:360:19)
    at get ui (.../pi-coding-agent/dist/core/extensions/runner.js:462:24)
    at ChildProcess.<anonymous> (.../taskplane/extensions/taskplane/extension.ts:1288:13)

The failing 0.30.4 code is the asynchronous startBatchInWorker() IPC handler:

child.on("message", (msg: WorkerToMainMessage) => {
  switch (msg.type) {
    case "notify":
      ctx.ui.notify(msg.msg, msg.level);
      updateWidget();
      break;
  }
});

updateOrchWidget() also retains orchWidgetCtx from session_start and calls ctx.ui.setWidget(...), which can fail under the same stale-context condition.

Root cause

Long-lived worker-process callbacks capture command/session extension contexts and perform UI-only side effects after Pi session replacement/reload. Pi 0.83 rejects those stale handles. The guard error is uncaught in TaskPlane's child event callback, so it terminates the supervising Pi process.

A package-wide search in 0.30.4 found no withSession implementation in TaskPlane for these callbacks.

Expected behavior

  • Engine state and lane execution must not crash because an old UI context is unavailable.
  • Post-replacement work should use Pi's supported withSession/fresh-context mechanism where possible.
  • If no active UI context exists, notification/widget refresh should be skipped without suppressing non-stale errors or engine failures.
  • Dashboard/runtime persistence and review/verification behavior must remain unchanged.

Bounded compatibility validation

A hash-pinned local compatibility patch guarded only asynchronous UI operations:

  • Treat the exact Pi stale-context error as an unavailable UI sink.
  • Skip only ctx.ui.notify(...) / ctx.ui.setWidget(...) for that exact error.
  • Rethrow every other error.
  • Do not alter engine state, review policy, verification, retries, or failure propagation.

Installed source SHA-256:

  • Original extension.ts: 091c111440a26a9e466b6838e7bc2945c8d8420c7df8104e5f294be6279ab2fd
  • Locally patched: edf04f685a69025e0d20ae9259c6f9bc0f9a19f1d3a30a0e90f3f6edb8755da1

After that patch, the identical /orch path passed the former crash point, created exactly one isolated lane, started its worker, and successfully exercised the configured code-navigation tools during preflight.

The validation environment imposed a hard 60-second command bound, so the exact batch processes were terminated at that bound and no claim of task completion is made. This proves the stale-context crash was removed, not that a full task completed.

Relationship to #597

Related to #597, but distinct:

The same lifecycle rule should be applied consistently across both background paths.

Acceptance criteria

  • /orch <packet> does not terminate Pi when worker IPC arrives after session replacement/reload.
  • UI notifications/widgets use a fresh supported context or safely no-op only for Pi's exact stale-context error.
  • Non-stale notification errors still surface.
  • Runtime batch/lane state continues to persist and remains observable from the dashboard.
  • Supervisor, reviewer, merger, strict verification, and failure handling retain their existing authority.
  • A regression test covers an IPC notify and widget refresh after context invalidation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions