From c750ce9e62eaf9d3214462184d5052cb604adec6 Mon Sep 17 00:00:00 2001 From: indifferentketchup Date: Sat, 16 May 2026 15:20:03 +0000 Subject: [PATCH] fix(api): suppress no-op session_renamed publish on PATCH /api/sessions/:id The v1.4 publisher fired whenever the PATCH body included `name`, including no-op rename calls (PATCH { name } where name === currentName). Read the prior name with a fast SELECT before the UPDATE and only publish session_renamed when the post-update name actually differs. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/server/src/routes/sessions.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/server/src/routes/sessions.ts b/apps/server/src/routes/sessions.ts index 707f8ad..2f087ea 100644 --- a/apps/server/src/routes/sessions.ts +++ b/apps/server/src/routes/sessions.ts @@ -120,6 +120,15 @@ export function registerSessionRoutes( return { error: 'invalid body', details: parsed.error.flatten() }; } const { name, model, system_prompt } = parsed.data; + // Read the prior name so the post-update publish can skip no-op renames + // (PATCH { name: "Foo" } where the session is already "Foo"). The window + // between SELECT and UPDATE is sub-millisecond in the same request handler; + // a concurrent rename in that gap would just mean one stale publish, which + // existing clients dedup by id. + const before = await sql<{ name: string }[]>` + SELECT name FROM sessions WHERE id = ${req.params.id} + `; + const priorName = before[0]?.name; const rows = await sql` UPDATE sessions SET @@ -135,7 +144,7 @@ export function registerSessionRoutes( return { error: 'session not found' }; } const session = rows[0]!; - if (name !== undefined) { + if (name !== undefined && session.name !== priorName) { broker.publishUser('default', { type: 'session_renamed', session_id: session.id,