Cloud start: record why the harness login was or was not passed

Merged
TE
4d ago
+165-56

The coordinator's ask: "A silent .skip is a bug anyway, because users get the bare "rejected" card with no reason. Have passHarnessLogin record why it skipped in the start report, and log it: the DEV/dogfood gate, caller owns, guest kind, and the machine's login reading."

Why

A Cloud start that passes no Claude login leaves the machine's Claude signed out, and every turn there fails with "The provider rejected Claude Code's credentials on this Cloud machine". That is the item 14 and handoff captures, even after #31183. The start skipped without saying which check stopped it, and no capture could tell.

Change

  • CloudHarnessLoginDecision (CmuxNextCloudCredentials) owns the decision that CloudStartChat.loginStep made, unchanged, and names its reason: build-gate-off, no-transfer-for-harness, signed-out, caller-not-owner, guest-not-owner, guest-kind-unread, machine-login-kept, install-cached or confirm-first.
  • The guest probe prints vm-kind:<kind>, so an exec that failed reads as guest-kind-unread. Before, a failed exec and a team guest looked the same.
  • passHarnessLogin logs a one-line summary (public, with no token or provider output) and keeps it on the machine's cloud.machines row as harness_login, with the outcome (installed, declined, or the transfer's fixed failure text). An example: skip (guest-not-owner): gate on, provider claude, signed in yes, caller owns yes, guest team, machine login -, cached yes.
  • No change in behaviour: the same checks in the same order. CmuxNextApp is one line shorter.

Tests

CloudStartChatLoginTests: every reason, the summary's exact text, and the probe's marker parsing (plus a real run of the probe). Fleet: the app compile and the suite (results in the comments).

Agent session: agent session

šŸ¤– Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Records why a Cloud start skips passing its harness login, so a machine left signed out carries its reason in the log and the cloud.machines row instead of a silent skip that showed only the bare "rejected" card.

  • New CloudHarnessLoginDecision names the deciding check: the DEV/dogfood gate, no transfer for the harness, signed out, caller not owner, guest not owner, guest kind unread, machine login kept, install cached, or confirm first.
  • The guest probe prints vm-kind:<kind>, so an exec that failed reads as guest-kind-unread instead of looking like a team guest.
  • passHarnessLogin logs a one-line public summary and keeps it on the machine as harness_login, with the outcome (installed, declined, or the transfer's fixed failure text).
  • No behavior change: the same checks run in the same order.