stacklok / stacklok/mecatl

Enforce single-driver-per-session across frontends (TUI/HTTP/K8s) with explicit handoff

Open
#632 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

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

Description

Problem

mecatl's session model is implicitly one driver + decoupled observers/readers — but "single driver" is not actually enforced. Run-start IS serialized per session (runEntryMu same-process, optional SessionLease cross-process), yet live-run signaling (Cancel, Approve, ResumeApproval, CancelChild, and the new steer/steer_cancel) is NOT client-scoped: any Converse stream attached to the session can fire control frames at the one live run. Steer is the newest writer, but the shared-control shape predates it.

This was surfaced while discussing the steer message_id correlation (steerMsgIDs FIFO matches drain→sender by text-match): it assumes ONE writer's batching discipline, so a second concurrent writer (TUI + HTTP, or two TUIs) can mis-correlate an echo. That's a steer-specific symptom of the general multi-writer hole.

Goal

Enforce "one driver at a time per session" across ALL clients, with explicit handoff. Observers/readers (Subscribe / EventLog.Read replay) attached but read-only. Switching frontends (TUI → HTTP → TUI) should be a clean close-one/open-the-other, not concurrent driving.

Why it matters for disconnect/reconnect

The architecture supports decoupled readers + a driver, and client takeover across frontends is desirable (the TUI↔HTTP switch). But until ownership is scoped, two drivers racing prompts/steers is a confusion vector, and the durable-subscription surface doesn't yet broadcast run events to Subscribers (see the live-feed gap — a second reader can't follow a driver's run live without polling).

Notes

  • Live-run control frames today ride the same Converse stream the starter opened; a second stream firing them is un-scoped.
  • Steer's single-slot inbox serializes the value, but not the writer.
  • This likely wants an ADR (multi-frontend session ownership) — a driver-scoping contract + an ownership/handoff event, plus the live-feed-to-subscription gap closed, so observers see a driver's events (incl. steer acks/echo) broadcast rather than polled.

Relates to #512 (steer) — steer is the forcing case; not solved there.

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 by tracing the Go session entry points named here: Converse, Subscribe, EventLog.Read, run-control frames, runEntryMu, and SessionLease. Read the steer correlation path and related issue #512, then define the ownership and handoff contract plus live-feed behavior in an ADR. Done means one driver is enforced across frontends, handoff is explicit, and observers receive the driver's events.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
api, backend-api-design, distributed-systems
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.