Skip to content

fix(session-ingest): resolve a forwarded exit_cli when ownership ends - #4827

Open
iscekic wants to merge 2 commits into
mainfrom
remote-cli-69f6
Open

fix(session-ingest): resolve a forwarded exit_cli when ownership ends#4827
iscekic wants to merge 2 commits into
mainfrom
remote-cli-69f6

Conversation

@iscekic

@iscekic iscekic commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Two remote-CLI defects, one small fix each.

Defect A — a successful /exit reported as "Session owner changed". Root cause: the CLI ACKs
exit_cli only after the detach heartbeat that removes the session, so the relay always failed
the pending command first and the user saw "Session owner changed" for an exit that had succeeded.
The relay now treats ownership ending as the requested outcome for a forwarded exit_cli:
failPendingCommandsForOwnerChange resolves it with result: {} (byte-identical to the CLI's own
ACK, and the only shape the SDK's strict exitSessionResponseSchema accepts) when no next owner
appears, and failPendingCommandsForSocket does the same when the owning CLI socket is really
gone (cliGone = !replaced). Genuine takeovers, reconnect socket replacements, and every other
command keep failing with SESSION_OWNER_CHANGED exactly as before. No mobile or SDK change: with
the relay fixed, the client's existing error classification is already correct.

Defect B — a remote CLI missing from the "Run on" targets — splits in two:

  1. Half 1 (a plain kilo TUI with /remote, or config auto-enable) is already fixed upstream.
    In the released CLI (@kilocode/cli 7.4.16) only the kilo remote command path advertises the
    instance; kilocode main commit a19d44c3ef (PR Advertise the instance from enableRemote and report attention status on the heartbeat kilocode#12532) moved advertisement
    into KiloSessions.enableRemote(), so every enable path advertises. That commit is not an
    ancestor of the v7.4.16 release tag — the fix awaits a CLI release, and no code change is
    warranted in either repository.
  2. Half 2 (headless kilo remote on ≤ 7.4.16) is not reproducible on the current baseline. On
    7.4.16 the kilo remote handler already advertises before enableRemote(), and it was observed
    working: a headless kilo remote appeared in the picker, while a relay-enabled TUI on the same
    version did not (observation run 2026-07-28, iOS simulator, personal context, account
    e2e-mobile-remote-cli-69f6@example.com). The most likely reading of the report is that the
    user's "kilo remote" was the TUI's /remote — i.e. Half 1. Remaining open candidates: org
    context (the Run-on selector is intentionally hidden for any organization), and a degraded
    heartbeat that omits instance, which wipes a previously advertised row until the next full
    heartbeat. Neither is settled here and neither is chased.

Why Defect B ships only one string. The upstream fix exists and re-implementing it would
collide with a19d44c3ef; relaxing getConnectedInstances() to synthesize rows would invent
hostname/project/version only the CLI knows. What no upstream commit solves is the empty state:
today a user whose CLI is connected but cannot advertise is told "No CLI instances connected" —
full stop. The description now names both recoveries: run kilo remote, or update Kilo CLI if
one is already running
. No new snapshot test for one display literal — the picker's four states
are already covered as pure logic by resolveInstancePickerViewState, and a snapshot here would be
coverage theatre.

Verification

  • Defect A confirmed test-first: the new relay case "heartbeat drops the session mid-exit_cli"
    failed with SESSION_OWNER_CHANGED before the fix, then passed after (the fix, not the
    validation, changed — the relay's exit_cli validation is untouched).
  • services/session-ingest: pnpm test (612 passed), pnpm typecheck, pnpm lint — green;
    pre-existing owner-change tests unmodified.
  • apps/mobile: pnpm format && pnpm typecheck && pnpm lint && pnpm check:unused && pnpm test
    (2337 passed) — green.
  • Defect B Run 1 (released CLI 7.4.16, planner observation 2026-07-28): headless kilo remote
    appeared in the Run-on picker (Igor-MacBook.local / remote-cli-69f6); with the TUI's
    relay additionally enabled the picker still showed only that one instance — Half 1
    reproduced, Half 2 refuted in one screen. (Two screenshots were captured; GitHub's API
    cannot attach binaries to PRs, so their content is transcribed here — nothing else in them
    is load-bearing.)
  • Defect A /exit E2E on the simulator (plan 1.7): in progress; results will be added before
    merge.
  • Defect B Run 2 E2E (plan 2.4): Half 1 against a CLI built from kilocode origin/main
    (detached worktree, merge-base guard on a19d44c3ef passed); in progress.

E2E note: simulator sign-in relied on the documented throwaway Maestro workaround (type the
address, then pressKey: Enter — the Send-code button sits under the keyboard window).
apps/mobile/e2e/** was not edited; the real harness fix is #4820.

Visual Changes

Instance-picker empty state (zero connected CLIs), description only:

Before After
"Run `kilo remote` in a project on your computer to connect one." "Run `kilo remote` in a project on your computer, or update Kilo CLI if one is already running."

Reviewer Notes

  • Focus: UserConnectionDO.ts failPendingCommandsForOwnerChange /
    failPendingCommandsForSocket — the only behavioral change is the payload branch for forwarded
    exit_cli; call sites did not move, send/delete ordering is unchanged, and the
    'CLI disconnected' string path is preserved.
  • The pre-forward SESSION_OWNER_CHANGED in handleWebCommand is deliberately untouched: nothing
    was sent there, and reporting success would claim an exit worked when it was never forwarded.
  • A reconnect socket replacement keeps the retryable error for exit_cli on purpose: the CLI
    process is alive and the exit's outcome is genuinely unknown.

iscekic added 2 commits July 28, 2026 15:37
A successful remote /exit was reported to the app as "Session owner
changed": the CLI ACKs exit_cli only after the detach heartbeat that
removes the session, so the relay always failed the pending command
first. For a forwarded exit_cli, ownership ending is the requested
outcome, so resolve it with result: {} (the CLI's own ACK shape) when
the owner-change path sees no next owner or when the owning socket is
really gone. Genuine takeovers, reconnect replacements, and every other
command keep failing with SESSION_OWNER_CHANGED.
A CLI too old to advertise itself is connected but never offered as a
Run on target, and the empty state only said nothing was connected.
Name both recoveries: run kilo remote, or update Kilo CLI if one is
already running.
@iscekic iscekic self-assigned this Jul 28, 2026
@kilo-code-bot

kilo-code-bot Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

The relay fix for forwarded exit_cli (resolving with result: {} only when the owning CLI/session ownership is genuinely gone, and still failing with SESSION_OWNER_CHANGED for takeovers, reconnects, and every other command) is correctly scoped and covered by new tests; the one-line mobile empty-state copy change is trivial and low risk.

Files Reviewed (3 files)
  • services/session-ingest/src/dos/UserConnectionDO.ts
  • services/session-ingest/src/dos/UserConnectionDO.test.ts
  • apps/mobile/src/app/(app)/agent-chat/instance-picker.tsx

Reviewed by claude-sonnet-5 · Input: 30 · Output: 5.7K · Cached: 812.1K

Review guidance: REVIEW.md from base branch main

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