When Claude writes the response file after the 60 s pollForResponse
window expires (e.g. the tmux pane was busy mid-turn when the message
arrived), the SSE stream has already closed with an error and the
file sits unread on disk forever. The chat shows a permanent timeout
even though the answer exists.
Backend:
- LocalPaliadinService.StartJanitor: scans responseDir every 2 s and
patches rows whose response is still NULL when the file lands.
completeTurnLate stamps error_code='late' so the FE can render a
marker. Guarded with WHERE response IS NULL to never overwrite a
real response if RunTurn races.
- Paliadin.GetTurn(callerID, turnID) on the shared paliadinDB. Same
visibility predicate as ListRecentTurns.
- GET /api/paliadin/turns/{id} — owner-gated; lets the chat UI
discover late-arrived responses without a refresh.
Frontend:
- paliadin-late-poll.ts: shared 3 s / 10 min poller.
- paliadin.ts + paliadin-widget.ts: on SSE error, show
"wartet auf späte Antwort", kick off the poller, swap bubble in
place when response arrives + retroactively persist to history.
- i18n: paliadin.late.waiting + paliadin.late.marker (DE/EN).
- CSS: --late-pending opacity tweak, --late neutral background,
italic-grey "verspätet" tag.