stacklok / stacklok/mecatl

fix(mecatui): recover permission approval after interrupted stream

Open
#852 6 comments 0 reactions 1 assignee View on GitHub

@jbeda is already working on this.

Since Aug 30, 2026.

bug tui
Dominant language
Go
Stars
152
Forks
16
Avg merge
14h 48m
Merged PRs (30d)
536

Description

Summary

A mecatui session can be left durably awaiting when its permission-approval stream ends before a verdict reaches the server. A subsequent prompt against that session then fails with:

session: illegal state transition: BeginTurn from "awaiting"

Incident evidence

  • The affected stored session was awaiting, with a persisted pending Bash approval.
  • Its event sidecar contained the matching permission.ask, followed by cancellation; it contained no allow/deny verdict.
  • Three later attempts initialized the session and then failed at BeginTurn from "awaiting".
  • The reporter was using embedded mecatui, not --connect; therefore coffee-shop Wi-Fi is unlikely to be the direct transport cause. A TUI/process/embedded-stream interruption remains plausible.
  • Reporter source/build identity is still pending.

No prompts, tool arguments, credentials, or session/ask identifiers are included here.

Code-path findings

  1. The TUI tears down an active or awaiting run on StreamErrMsg and StreamClosedMsg. endRun cancels the run context and closes the approval modal; it does not send an approval verdict.
    • cmd/mecatui/ui/update.go (StreamErrMsg, StreamClosedMsg, endRun)
  2. The approval path records the ask as locally resolved before SendApproval returns successfully. If send fails, the resulting stream error ends the run and there is no retry or restored pending-ask UI.
    • cmd/mecatui/ui/approval.go (approvalSendCmd, applyApprovalSurfaceIntent)
  3. The engine persists the session's awaiting state before emitting permission.ask; client cancellation/disconnect does not synthesize an allow/deny verdict.
    • engine/agent/permission.go (PauseForApproval path)
  4. A new prompt intentionally does not resolve an awaiting session, so it eventually reaches BeginTurn and fails.
    • internal/adapter/server/service.go (loadAndReopen / StartRunContent)
    • engine/session/session.go (BeginTurn)

Expected behavior

If mecatui has displayed a permission ask but the run/stream fails before the server confirms the verdict, the user should be able to recover the pending ask and explicitly approve or deny it. The UI must not silently discard the only affordance for a durable pending approval.

A new prompt should not fail with a raw illegal-transition error when the session has an unresolved approval; it should either surface the pending approval or provide a clear recovery action.

Follow-up investigation / solution space

Do not choose an approach yet. Evaluate:

  • retaining/restoring an unresolved approval modal after stream failure or restart;
  • acknowledgement-aware approval submission (do not mark an ask locally resolved until the server confirms it);
  • querying/reconciling durable pending asks when a session is adopted or reopened;
  • a server/client recovery protocol for an embedded-stream interruption;
  • clearer new-prompt handling for awaiting sessions.

Add regression coverage for an approval ask followed by stream interruption, then a UI/session recovery and verdict submission.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.