Symptom
Renaming a machine from the app has no lasting effect — the new name reverts on refresh.
Root cause
The rename UI works end-to-end on the client: apps/ui/sources/app/(app)/machine/[id]/index.tsx → machineUpdateMetadata (sync/ops/machines.ts) → encrypted machine-update-metadata socket emit. But the server handler (apps/server/sources/app/api/socket/machineUpdateHandler.ts, readAuthenticatedMachineId) requires a machine-scoped socket and returns { result: 'error', message: 'Machine-scoped socket required' } for the app's user-scoped socket. The optimistic local update then evaporates on the next refresh.
Secondary defect: on a successful update the change event fans out with recipientFilter: machine-scoped-only, so user-scoped clients would never receive it anyway.
Not a daemon-clobber problem: the daemon's reconnect metadata refresh (startDaemon.ts) spreads existing metadata and preserves displayName.
Decision needed (why this isn't a straight PR)
- (a) allow authenticated user-scoped metadata updates — REST endpoint or relaxed socket gate, keeping the version-conflict merge (
machineMetadataMerge.ts); works with daemon offline; or
- (b) route the rename through the daemon RPC over its existing machine-scoped socket; preserves the machine-scoped-write invariant but fails when the daemon is offline.
Acceptance criteria
- Rename persists across refresh and daemon reconnect.
- Update event reaches user-scoped clients.
- Explicit behavior when the daemon is offline.
- Server + UI tests for the authz path.
Bug discovered by @hubikj; root-cause investigation and this write-up produced with Claude (AI). Code references checked against the dev tip as of 2026-08-11.
Symptom
Renaming a machine from the app has no lasting effect — the new name reverts on refresh.
Root cause
The rename UI works end-to-end on the client:
apps/ui/sources/app/(app)/machine/[id]/index.tsx→machineUpdateMetadata(sync/ops/machines.ts) → encryptedmachine-update-metadatasocket emit. But the server handler (apps/server/sources/app/api/socket/machineUpdateHandler.ts,readAuthenticatedMachineId) requires a machine-scoped socket and returns{ result: 'error', message: 'Machine-scoped socket required' }for the app's user-scoped socket. The optimistic local update then evaporates on the next refresh.Secondary defect: on a successful update the change event fans out with
recipientFilter: machine-scoped-only, so user-scoped clients would never receive it anyway.Not a daemon-clobber problem: the daemon's reconnect metadata refresh (
startDaemon.ts) spreads existing metadata and preservesdisplayName.Decision needed (why this isn't a straight PR)
machineMetadataMerge.ts); works with daemon offline; orAcceptance criteria
Bug discovered by @hubikj; root-cause investigation and this write-up produced with Claude (AI). Code references checked against the
devtip as of 2026-08-11.