Skip to content

fix(mcp): name chats in list_chats the way the UI does, not an 8-char id slice (#614) - #626

Open
edspencer wants to merge 1 commit into
mainfrom
fix/614-list-chats-preview-name
Open

fix(mcp): name chats in list_chats the way the UI does, not an 8-char id slice (#614)#626
edspencer wants to merge 1 commit into
mainfrom
fix/614-list-chats-preview-name

Conversation

@edspencer

Copy link
Copy Markdown
Owner

Half of #614 — the half that doesn't need a cross-repo release.

The problem

The MCP projection resolved a chat's name as customName ?? autoName ?? sessionId.slice(0, 8) (management-ops.ts:199), omitting the preview step the REST DTO has (chat-dto.ts:241). For the same chat, the web UI showed prose and MCP showed a hash.

autoName can't cover the gap. Core derives it only from type: "summary" records, and current Claude Code writes ai-title instead. Measured across all 1,704 transcripts on this instance:

carry an ai-title record 1,649
carry a summary record 0

So the chain effectively ran customName ?? slice(0,8), and 39 of 96 (41%) chats in a real list_chats {} response came back named after their own sessionId — 18 paddock, 9 coderabbit, 8 herdctl, 2 edspencer-net, 1 hushpod, 1 eightsleep.

This is worse than ugly. The stub looks like an id, and feeding one back to read_chat returns a successful empty result rather than an error — so a caller can conclude "empty chat" about a conversation it never opened.

It also silently broke a documented instruction. The Night-Watch reviewer is told to skip chats whose name contains "night-watch". The prior run's actual title is "Night-Watch nightly quality review system" — the filter could not fire, two nights running, and it spent a read_chat re-identifying the chat by content instead. Both reports say so out loud: "hash-named, evades the name filter" / "hash-named, content-matched".

The change

  • Extract the preload/attachment preview recovery out of buildProjectChats into a shared recoverPreview, so the REST DTO and the MCP list run the same logic and can't drift on this again. (The drift is the bug — a second copy of the chain would just re-introduce it later.)
  • Use the full chain in listChats, including the raw-preview fallback, so MCP and the UI agree case for case.
  • Only polluted previews pay for the extra head-of-file read; everything else returns without I/O, so list_chats stays cheap as advertised.

One deliberate non-improvement

When a preload wrapper is truncated before the My request: marker and the untruncated message can't be read from disk, there's nothing to recover and both surfaces fall through to the raw <project-context>… preview. That's a wart — but the point of #614 is that the two surfaces must not disagree, so I matched it and pinned it with a test rather than quietly making one surface "nicer". Worth fixing separately if you want it.

What this does NOT do

Teaching autoName to read ai-title is the other half. It lives in @herdctl/core and needs a herdctl PR, a publish and a bump here — a coordinated release I didn't want to bundle into this. So chats with no title and no preview still fall back to the slice; that's correct behaviour for a genuinely nameless chat. #614 stays open for the ai-title work.

Also not attempted: the extra triage fields (messageCount, errorCount) from the issue. errorCount means parsing every transcript per list call — a performance design question, not a code change.

Verification

  • New management-ops-chat-name.test.ts: 7 passed
  • Confirmed 3 of them fail against the old one-liner (expected 'cccccccc' to be 'Audit the Night-Watch run against the…') rather than passing vacuously
  • Full server suite: 1447 passed / 116 files (1440 before + 7 new) — the chat-dto extraction breaks nothing
  • npm run typecheck: clean (server + web)

Companions: #613 (the read_chat fidelity defect) and #625 (descriptions, CI green).

… id slice (#614)

The MCP projection resolved a chat's name as
`customName ?? autoName ?? sessionId.slice(0, 8)`, omitting the `preview`
step the REST DTO has (`chat-dto.ts:241`). So for the same chat the web UI
showed prose and MCP showed a hash.

`autoName` cannot cover the gap: core derives it only from `type:"summary"`
records, and current Claude Code writes `ai-title` instead. Across the 1,704
transcripts on this instance, 1,649 carry an `ai-title` and 0 carry a
`summary` — so the chain effectively ran `customName ?? slice(0,8)` and 39 of
96 listed chats (41%) came back named after their own sessionId.

That is worse than ugly. The stub LOOKS like an id, and feeding one back to
`read_chat` returns a successful empty result rather than an error, so a
caller can conclude "empty chat" about a conversation it never opened. It
also silently broke a documented instruction: the Night-Watch reviewer is
told to skip chats whose name contains "night-watch", and the prior run's
actual title is "Night-Watch nightly quality review system" — the filter
could not fire, two nights running, and it burned a read re-identifying the
chat by content instead.

- Extract the preload/attachment preview recovery out of `buildProjectChats`
  into a shared `recoverPreview`, so the REST DTO and the MCP list run the
  same logic and cannot drift on this again.
- Use the full chain in `listChats`, including the raw-preview fallback, so
  MCP and the UI agree case for case — the truncated-wrapper wart included,
  which is pinned by a test rather than quietly "improved" on one surface.
- Only polluted previews pay for the extra head-of-file read; everything
  else returns without I/O, so `list_chats` stays cheap.

This is half of #614. The other half — teaching `autoName` to read
`ai-title` — lives in `@herdctl/core` and needs a coordinated release, so it
is deliberately not attempted here.

Verified the three behavioural tests fail against the old one-liner rather
than passing vacuously. Full server suite 1447 passed; typecheck clean.

Co-Authored-By: Claude <noreply@anthropic.com>
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying paddock with  Cloudflare Pages  Cloudflare Pages

Latest commit: 612c4e3
Status: ✅  Deploy successful!
Preview URL: https://ffffff1e.paddock-7u2.pages.dev
Branch Preview URL: https://fix-614-list-chats-preview-n.paddock-7u2.pages.dev

View logs

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