Skip to content

fix(manager): cotal attach gives runtime-correct hint (cmux ≠ tmux)#30

Open
Lanzelot1 wants to merge 2 commits into
mainfrom
fix/attach-runtime-hint
Open

fix(manager): cotal attach gives runtime-correct hint (cmux ≠ tmux)#30
Lanzelot1 wants to merge 2 commits into
mainfrom
fix/attach-runtime-hint

Conversation

@Lanzelot1

Copy link
Copy Markdown
Collaborator

Problem

Running cotal attach --name <agent> against a cmux-runtime agent printed a tmux instruction:

× attach needs the pty runtime; under tmux run tmux attach -t cotal-main:<name>

cmux is not tmux — it's a standalone GUI multiplexer with its own CLI — so that hint is wrong and confuses users (seen in the wild). opAttach only special-cased pty and assumed every other runtime was tmux; cmux was added later and fell into the tmux branch.

Fix

opAttach (implementations/manager/src/manager.ts) now delegates to the agent handle's own attach(), so each runtime gives its own guidance:

  • pty → streams over the WS attach endpoint (unchanged)
  • tmuxtmux attach -t cotal-<space>:<name>
  • cmuxswitch to the "cotal-<name>" cmux tab

Also sharpens the runtime section in docs/architecture.md and adds pnpm smoke:attach covering all three runtimes.

Testing

  • pnpm --filter @cotal-ai/manager --filter @cotal-ai/cmux typecheck — clean
  • pnpm smoke:attach — pty/tmux/cmux all pass (cmux opened+closed a real tab)
  • Live end-to-end: cotal cmux --spawn … then cotal attachcmux runtime: switch to the "cotal-<name>" cmux tab to watch it (no tmux text)

🤖 Generated with Claude Code

Lanzelot1 and others added 2 commits June 15, 2026 12:30
opAttach assumed non-pty == tmux, so cmux users got a tmux attach command.
Delegate to the handle's own attach() so each runtime speaks for itself
(tmux → tmux attach -t …; cmux → switch to the cotal-<name> tab). Add
pnpm smoke:attach covering pty/tmux/cmux, and sharpen the docs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
davidfarah2003 added a commit that referenced this pull request Jul 16, 2026
…est subject (B1 structural half)

Closes the structural half of the mediator authority-boundary blocker
(fact-3/distsys B1): the obligation coordinate's caller identity is no
longer a public argument.

- obtain* now take a BRANDED MediatedRequest built by
  mediatedRequestFromSubject(subject), which parses the endpoint +
  caller triple STRUCTURALLY from an authenticated ep/epj request
  subject through core's parseEpSubject. A hand-assembled request never
  authorizes (WeakSet brand), and a request whose subject names a
  different endpoint is refused by this mediator. The caller-chosen
  request id (a body field, per 13.4) stays an explicit op argument;
  everything identifying WHO the caller is comes from the subject.
- AdmissionIdentity split into MediatedRequest (subject-derived identity)
  and AdmissionOp (target/policy/id operation coordinates).

Smoke 42/42: the obligation key embeds the subject-derived caller
triple; a hand-assembled request and a foreign-endpoint request both
refuse; a non-request subject refuses at construction. Temp-revert of
the brand check fails exactly those two probes. Full smoke:ci green.

Still open: the scoped admission-mediator credential profile +
confinement smoke (B1's broker-enforcement half), tracked task #30.
davidfarah2003 added a commit that referenced this pull request Jul 16, 2026
…finement probe (D14 slice a)

The two 13.9 ownership-matrix rows whose residual is "explicit per D32"
get their grant builders and a live broker probe (the B1 broker half,
task #30; the first D14/D32 slice):

- admissionMediatorGrants (core, endpoint-binding): the endpoint's
  oblig.*.<e>.> CAS writes, the endpoint-literal terminal-rejection
  decision publish, the fencing leader reads (records/EPF/EPW
  STREAM.MSG.GET), the 13.12 bind-time shape proof (records
  STREAM.INFO), and the per-run enumeration consumer whose CREATE row
  PINS the filter to the endpoint's own oblig subtree. No
  CONSUMER.DELETE row: the throwaway scan is collected by its own
  inactive_threshold, and a delete grant would reach every records
  consumer by name. The three D32 residuals are stated on the builder:
  the own-endpoint ACCEPTANCE-forge (rejection-only is not
  subject-expressible: both decisions share the create-only decision
  subject for first-wins settlement), the space-wide body-selected
  MSG.GET read exposure, and the name-wildcard enumeration consumer.
- retirementCleanerGrants (core): per LISTED pool only (never a
  wildcard), bind-only durable rows + the pool-scoped wrk terminal
  publish, plus the space-wide EPF MSG.GET terminal-observe read
  (explicit per D32); no epw publish, no consumer create/update/delete,
  no stream delete.
- SPEC 13.9: the acceptance-obligation row now NAMES the own-endpoint
  acceptance-forge residual verbatim (an escalation to injecting
  executed work, never merely reject/stall), per the security lane's
  requirement; docs bundle regenerated.

The confinement smoke (mediator-confinement, 26 checks, live broker
with plain user authorization built FROM the builders): the REAL
mediator runs over the scoped credential end-to-end with its obligation
identity fed from a LIVE broker-delivered subject (a subscription's
msg.subject into mediatedRequestFromSubject, closing the "inert
structural half" gap), wins the create-fence, settles, and emits a
core-valid rejection; the REAL exact-pool cleaner reaches proven
quiescence over its scoped credential. Denials, broker-enforced on the
same credentials: cross-endpoint decision forge, foreign oblig subtree,
govern head, auth store, foreign-filter enumeration consumer, records
message-delete/purge, Direct Get, pool enqueue (mediator); non-listed
pool wrk, any decision publish, epw enqueue, foreign durable bind,
consumer create/delete, stream purge, EPW leader read, records writes
(cleaner). The own-endpoint decision publish is asserted POSSIBLE, so
the named D32 residual is proven present rather than silently implied
absent. Wired into smoke:ci; full gate green.

The provision-path mint wiring (which authority mints these profiles,
gate-fenced) intentionally rides the production activation slice; the
rows and their broker enforcement are what this slice pins.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant