# ISS-0109 Plan: Lark bot 诊断完成后未将分析结果展示给用户

## Background

GitHub issue #661 reports that when a user triggers a diagnosis via the Investibook Lark bot,
the analysis results are **not shown** to the user in the Lark conversation. The user notes
that the local agent can successfully obtain and display the results, but the Lark bot does not.

- Workspace: `lark-ws-5aec03b6-1b79-4559-9c94-61ad9a2c7523`
- Environment: prod (`investibook.com`)
- User feedback: "会华丽没有展示出对应的分析结果，本地 agent 可以得到分析结果"
  (Investibook did not display the corresponding analysis results; local agent can get results)

## Observed Behavior

1. User sends a diagnosis request to the Lark bot in a Lark chat
2. The Lark bot workspace `lark-ws-5aec03b6-1b79-4559-9c94-61ad9a2c7523` is created and
   the diagnosis appears to run (14 sources attached)
3. Diagnosis completes internally (agent produces results), but **no results are posted
   back to the Lark conversation**
4. Using the local agent directly for the same case returns results correctly

## Root Cause Analysis

There are several candidate root causes for why Lark bot loses the diagnosis result:

### Candidate 1: Lark Webhook Timeout
Lark webhook calls have a 5-second reply timeout. If the diagnosis takes longer (typical
diagnosis takes 60-180s), the webhook response cannot carry the result. The bot must
acknowledge the webhook immediately and send the result asynchronously via Lark API.

### Candidate 2: SSE Connection Dropped Before Completion
The Lark bot may use an SSE connection to the Investibook backend for the diagnosis session.
If the SSE connection drops (timeout, network issue) before the `complete` event is received,
the result is never extracted and posted to Lark.

### Candidate 3: Missing Async Callback in Long-Running Session
`lark.py` may not have a mechanism to post results back to Lark after long-running sessions.
The `acp.py` auto-chat path used for Lark sessions may not trigger a Lark reply on completion.

### Candidate 4: Message Persistence Gap
The Lark session messages may not be correctly persisted. If the diagnosis runs but the
assistant message is not saved (similar to ISS-0030 for the web frontend), the result
is lost before it can be sent to Lark.

## Code Paths to Investigate

1. `backend/investibook/api/lark.py` — webhook handler and Lark message posting logic
2. `backend/investibook/core/acp.py` — auto-chat/session completion callback
3. `backend/investibook/core/lark_bot.py` — bot session management

Key questions:
- Does `lark.py` use an async callback on session completion, or does it rely on the
  webhook response?
- Is there a `send_lark_message()` call triggered when the diagnosis `complete` event fires?
- Is there a timeout on the SSE consumer in the Lark path?

## Fix Plan

### Step 1: Diagnose the actual failure mode
Pull workspace `lark-ws-5aec03b6-1b79-4559-9c94-61ad9a2c7523` messages from prod to
determine if the diagnosis actually ran to completion (messages exist in backend) vs.
the session was incomplete.

### Step 2: Ensure async result delivery
If the Lark bot is relying on the webhook response to deliver results:
- Change to async mode: acknowledge Lark webhook immediately (HTTP 200)
- On diagnosis `complete`, call `lark.send_message(chat_id, result_text)` asynchronously
- This is the standard pattern for Lark bots with long-running tasks

### Step 3: Add error handling for dropped connections
In the Lark SSE consumer loop, if the connection drops before `complete`:
- Log the partial result
- Retry connection and pick up where it left off (or re-send `/force-continue`)
- If recovery fails, send a Lark message: "诊断未能完成，请重试"

### Step 4: Verify message persistence
Ensure that for Lark sessions, the assistant messages are persisted to the backend
(same as the web frontend fix in ISS-0030/PR#283), so the result is not lost if the
Lark callback fails.

## Verification

1. Trigger a new Lark bot diagnosis session on a known case
2. Monitor `lark_bot.py` logs for the `complete` event handling
3. Confirm the result message is posted to the Lark chat within 5 seconds of completion
4. Verify the result is also persisted in the workspace messages API
