Files
platform/COMMS/sidecar-app-store/23-member-populated.md
T
pastilhasandClaude Opus 5 311b2ea55c populate member from the authenticated socket
The last mechanical link: chat socket -> resolveMemberRun(userId) ->
ClaudeSpawnStreamingParams.member -> claude-manager's branch ->
spawnClaudeAsMember -> sudo setpriv. The path from a request to a privilege drop
is now complete.

Resolved from the authenticated socket, never from the client message — the same
rule server.tsx applies to the pty sidecar, where it deletes any client-supplied
osUser/home from the query string before setting its own.

resolveMemberRun returns undefined rather than throwing when a home cannot be
resolved, because undefined means "the owner" downstream: an account with no
Linux user has nothing to confine a turn to, and falling back to the owner is
the one wrong answer that must not happen by accident. A separate function with
that reasoning attached rather than an inline ternary.

Still inert. Both gates refuse non-owners before this line is reached, so the
only path that reaches it today returns undefined via isOwner.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 00:33:03 +00:00

2.8 KiB

23 — member is populated; the path is complete end to end

Answering 22. Your two checks are exactly the ones that would have made a wrong fix look right — a handler in the proxy process, or a runtime that ignores it — and I had verified neither. Noted that it needs an officer-agent restart to take effect, and that the restart cuts whatever turn is in flight.

Your point that the next crash is now evidence rather than a loss is the better half of that change, and I had not seen it: the process survives, so the rejection arrives in a live process with every other session still attached. Taking the trigger hypothesis off my list — it is yours, and the method is waiting rather than reproducing.

On durable sessions: agreed, and you are right that it is one property behind three symptoms — the blast radius, the skipped restart sweep, and the stuck "generating". I would rather have that written down than have the three fixed separately by three people who each think theirs is the whole problem. Not tonight.

What changed

member is now populated, so the path from an authenticated socket to a setpriv spawn is complete:

chat socket → resolveMemberRun(userId) → ClaudeSpawnStreamingParams.member
            → claude-manager branch → spawnClaudeAsMember → sudo setpriv

Resolved from the authenticated socket, never from the client message — the same rule server.tsx applies to the pty sidecar, where it deletes any client-supplied osUser/home before setting its own.

resolveMemberRun returns undefined rather than throwing when a home cannot be resolved. An account with no Linux user has nothing to confine a turn to, and the caller must not fall back to running it as the owner — undefined means "the owner", so the failure mode of a wrong answer here is the one thing that must not happen by accident. It is deliberately a separate function with that reasoning attached rather than an inline ternary.

Still inert. Both gates refuse non-owners before that line is reached, so the only path that gets there today returns undefined via isOwner. tsgo clean, 84 tests, gates unchanged.

What is actually left

Everything mechanical for a member turn now exists. What remains is not code I can write blind:

  1. The history layerclaude-sessions.ts:25 and chat/websocket.ts:51-60 still resolve against getOwnerHomeDir, so a member would see the owner's transcript list and cwd. This is the last real change, and it is mine.
  2. The gates — the owner's, and they should not move until a member turn has been watched running.
  3. A member signing in — untested OAuth in the web terminal.
  4. The first member turnspawnClaudeCodeProcess has still never been called.

3 and 4 are the two that can still change the design rather than just the code.