# Session Tooltip Freshness Design

## Problem

The active-session tooltip can show an AI summary that is technically cached
correctly but no longer represents the current task. The most visible failure is
a running session whose tooltip headline still describes an older task while the
latest prompt and progress have already moved on.

This is worse than an empty tooltip because it gives false confidence. The
operator uses the tooltip to decide which session needs attention, so stale
intent text can send the user to the wrong session or hide a current blocker.

## Existing Behavior

Current flow:

1. `stream-view.js` opens the tooltip after hover and fetches
   `/api/sessions/:id/summary?turns=3`.
2. `SessionStream` stores cleaned user prompts in `userPromptCache`.
3. A new user prompt debounces AI summary generation by 2 seconds.
4. The configured provider generates a 10-15 word summary over the cached
   prompt list.
5. `getSummary()` returns `summary`, `intent`, `displayPrompt`, `lastPrompt`,
   and `progress`.

Current failure modes:

- Cached `intent.source = ai-summary` is treated as authoritative even when its
  timestamp is older than the latest prompt.
- The tooltip does not refetch or rerender while it is already open for the same
  session.
- The AI summary input is a flat list of recent prompts, so older work can
  dominate the summary after a task switch.
- The UI label `Intent` does not explain freshness or distinguish current
  prompt evidence from slower AI synthesis.

## Design Principles

- Latest user intent is the primary truth. AI is a compression layer, not a
  source of freshness.
- Stale AI should be visible as context, never promoted as the current task.
- Refresh should be scoped to visible UI. Do not add broad polling across every
  session.
- The tooltip should be copyable, stable, dense, and operational.
- Existing API fields must stay backward compatible for Session Overview and
  older clients.

## API Contract

`GET /api/sessions/:id/summary` keeps existing fields and adds:

```js
{
  currentTask: {
    text: string | null,
    source: 'latest-prompt' | 'ai-summary' | 'prompt-fallback' | 'title-fallback' | 'missing',
    freshness: 'fresh' | 'updating' | 'stale' | 'missing',
    updatedAt: number,
    promptTimestamp: number,
    staleReason?: string
  },
  latestPrompt: {
    text: string | null,
    timestamp: number
  },
  aiSummary: {
    text: string | null,
    source: string | null,
    status: 'fresh' | 'updating' | 'stale' | 'fallback' | 'unavailable',
    updatedAt: number,
    promptTimestamp: number,
    promptCount: number,
    staleReason?: string
  }
}
```

Compatibility mapping:

- `intent` remains present.
- `summary` remains present.
- When AI is stale, `intent.text` should follow `currentTask.text` so existing
  clients do not keep rendering stale AI as the primary task.
- `aiSummary.text` retains the older AI text for secondary display.

Freshness rules:

- If usable AI summary exists and `aiSummary.updatedAt >= latestPrompt.timestamp`,
  `currentTask.source = ai-summary` and `freshness = fresh`.
- If usable AI summary exists but is older than the latest prompt,
  `currentTask.source = latest-prompt`, `freshness = updating`, and
  `aiSummary.status = stale` or `updating`.
- If no AI summary exists, use the most recent content-rich prompt and mark the
  AI summary as `unavailable` or `fallback`.
- If a fallback summary is raw prompt text, keep current task on prompt evidence
  and mark `aiSummary.status = fallback`.

## Summary Generation

Change the AI prompt from a flat prompt list to latest-prompt-weighted input.

Recommended input:

```text
Latest prompt:
<most recent cleaned prompt>

Recent context:
1. <older prompt>
2. <older prompt>
3. <older prompt>
```

Recommended system prompt:

```text
Summarize the user's current task. Prioritize the latest prompt. Use older
prompts only as context. Return 8-14 words. Return only the summary, no quotes
or prefix.
```

The cached summary should record the prompt timestamp and prompt count used to
generate it. This makes freshness testable without depending on provider speed.

## Tooltip UX

Replace the main `Intent` section with `Current Task`.

Fresh state:

```text
CURRENT TASK
[AI SUMMARY] [FRESH] [now]
Fixing Wall-E session history restore and tooltip freshness.
```

Updating state:

```text
CURRENT TASK
[LATEST PROMPT] [UPDATING] [now]
Does WallE coding agent have auto compact logic like OpenCode or Claude?

AI SUMMARY
[STALE] [2m ago]
Previous: Fixing session tab drag behavior and search issues.
```

Unavailable state:

```text
CURRENT TASK
[LATEST PROMPT] [FALLBACK] [now]
Fix the session tooltip freshness behavior.
```

Progress remains separate and should keep using assistant-event evidence.

Interaction behavior:

- Opening a tooltip fetches summary immediately.
- If the tooltip is already open for that session, new stream events rerender it.
- While visible, perform a lightweight refresh every 10 seconds.
- Stop the refresh timer when the tooltip is hidden.
- Clicking inside the tooltip continues to preserve it for copy/select.
- Activating a different session tooltip replaces the current tooltip.

## Implementation Plan

Phase 1: documentation

- Add this design note.
- Commit documentation by itself after TL review.

Phase 2: backend freshness

- Extend `SessionStream` cached summary metadata with prompt timestamp/count.
- Add `latestPrompt`, `aiSummary`, and `currentTask` to `getSummary()`.
- Ensure `intent` maps to `currentTask`, not stale AI.
- Update summary generation prompt to prioritize latest prompt.
- Add unit tests for fresh, stale, fallback, and provider-lag cases.

Phase 3: tooltip UI

- Render `Current Task` from `currentTask`.
- Render stale AI only as secondary context.
- Add freshness/status pills.
- Add visible-tooltip refresh and stream-event rerender.
- Add browser/render coverage for a tooltip that updates while open.

Phase 4: dev validation

- Start isolated CTM via `ctm-dev`.
- Verify service health on the dev port pair.
- Exercise stale summary behavior through a real browser.
- Confirm no browser console errors for the tooltip flow.
- Commit implementation after TL review.

## Test Matrix

Backend:

- AI summary generated after latest prompt: primary task is AI summary.
- AI summary timestamp older than latest prompt: primary task is latest prompt.
- AI provider slow or failed: primary task remains latest prompt.
- Fallback summary raw prompt: primary task remains prompt evidence.
- Summary generation input puts latest prompt before recent context.

Frontend:

- Tooltip opens and labels `Current Task`.
- Stale AI is demoted into `AI Summary`.
- New user stream event updates an already-open tooltip.
- Fresh summary event promotes AI summary.
- Tooltip remains copyable and dismisses only on outside click or another
  tooltip activation.

Dev validation:

- CTM dev server starts on a random non-primary port.
- `/api/services/status` succeeds on the dev port.
- Browser test uses the dev port, never `3456` or `3457`.
- Screenshot or DOM assertions prove the freshness state.
