stacklok / stacklok/mecatl

mecatui: safely hand off control of a live pending permission approval

Open
#1,439 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

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

Description

Problem

A mecatui Converse stream is the sole control channel for a live agent run. If its client disconnects or a second same-owner client wants to take over while the server still owns a run parked on a parent permission ask, the replacement client cannot attach to that run, receive the outstanding ask, or submit a verdict.

This is distinct from #852's durable recovery case: #852 can resume a StateAwaiting snapshot after the original engine/run is gone. This issue concerns a still-live run and therefore needs an explicit connection/control ownership model.

Current behavior

  • Converse permits only Prompt or Retry as its first frame; it has no live-run attachment start frame.
  • Permission controls route only to the existing stream's active in-memory run.
  • A received-side EOF stops the control reader, but relay ownership remains with the run; if the run is parked and emits no further event, it can remain parked until the RPC context is cancelled or another lifecycle event occurs.
  • On an outbound send failure, the relay cancels and drains the run. The normal durable outcome is then cancelled, not a live attachment opportunity.
  • The live event subscription is read-only and deliberately does not recreate permission asks or provide approval control.
  • A session lease prevents another engine from mutating the same session, but it does not provide a new TUI a way to take over a healthy live run's control stream.

Desired outcome

Define and implement a safe, owner-authorized live run/approval handoff so a replacement client can recover control of an active parent permission ask without introducing duplicate verdicts or tool execution.

Acceptance considerations

  • Define whether a new attachment revokes the prior client immediately, requires an explicit takeover action, or rejects while the current control stream is healthy.
  • The server, not either client, must serialize the handoff and make exactly one controller authoritative.
  • The replacement client receives the current parent pending ask and can submit a verdict with server acknowledgement.
  • A stale former controller's Allow/Deny/Cancel frames cannot affect the run after handoff.
  • Preserve owner isolation and run-ID correlation; do not reveal an active session or ask to a different owner.
  • Preserve session-lease single-writer behavior. This is client/control ownership, not a reason to add a global store lock.
  • Specify behavior for send-half EOF, full transport/context cancellation, server restart, lease loss, and simultaneous handoff attempts.
  • Parent-owned asks only initially. Child/parallel/team ask handoff is explicitly out of scope.
  • Add offline gRPC and mecatui tests for takeover, stale control rejection, exactly-once execution, and no client-side false approval.

Non-goals

  • Do not replace #852's persisted-awaiting rehydration path.
  • Do not infer current approval state from the event log.
  • Do not add automatic approval replay.
  • Do not add a global filesystem/store lock that prevents different sessions from running concurrently.

Context

  • internal/adapter/server/grpc.go (Converse, readControl, relayRun)
  • internal/adapter/server/service.go (approveLiveRun, lease loss handling)
  • cmd/mecatui/ui/approval.go and cmd/mecatui/ui/update.go
  • #852

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.

Research direction

Start with internal/adapter/server/grpc.go, especially Converse, readControl, and relayRun, then inspect approveLiveRun and lease-loss handling in internal/adapter/server/service.go. Read cmd/mecatui/ui/approval.go and update.go before defining the ownership flow. Done means the offline gRPC and mecatui tests cover takeover, stale-control rejection, exactly-once execution, and no false approval.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, grpc
Domain
api, backend, cli
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.