88 lines
5.5 KiB
Markdown
88 lines
5.5 KiB
Markdown
# 03 — Continuity Moments (Auto-Resume Banner)
|
|
|
|
**Author:** CC (Block B design pass)
|
|
**Date:** 2026-05-01
|
|
**Status:** AWAITING_RATIFICATION
|
|
**Estimate:** ~120 LOC + ~2-3h wall-clock
|
|
**Touches:** apps/web (1 file: ChatApp.tsx OR new ContinuityBanner.tsx), packages/server (1 endpoint extension)
|
|
|
|
---
|
|
|
|
## User story
|
|
|
|
When I open Chat after closing it for hours/days, I want a 1-line banner reminding me where I left off — what I last decided, what's still open — and a one-click way to continue or start fresh, so I don't have to re-orient myself manually.
|
|
|
|
## Acceptance criteria
|
|
|
|
1. When ChatApp mounts AND `messages.length === 0` AND last session for the workspace was within the past 7 days, render a "Picking up where you left off" banner at the top of the chat.
|
|
2. Banner content: 1-line headline ("Yesterday you decided X") + 2 buttons: `Continue` (loads last session messages) + `Start fresh` (dismisses banner, opens empty input).
|
|
3. Banner suppressed for fresh workspaces (sessionCount=0) and for sessions older than 7 days (handoff to LoginBriefing's domain).
|
|
4. Dismissing banner via `Start fresh` sets a per-workspace flag `continuity:dismissed:{wsId}` so the banner doesn't re-render same session.
|
|
5. Continuity banner replaces neither WorkspaceBriefing nor LoginBriefing — it's a third surface specific to "between-session" memory.
|
|
|
|
## UI sketch
|
|
|
|
```
|
|
ChatApp top, above message list:
|
|
┌──────────────────────────────────────────────────────────┐
|
|
│ ⟳ Picking up where you left off ✕ │
|
|
│ Yesterday you decided: ship migrations Wednesday. │
|
|
│ 2 open follow-ups · last session 16h ago │
|
|
│ │
|
|
│ [ Continue conversation ] [ Start fresh ] │
|
|
└──────────────────────────────────────────────────────────┘
|
|
|
|
After click Continue: banner fades, last session messages stream into the chat.
|
|
After click Start fresh: banner removed for this session, input focused.
|
|
```
|
|
|
|
## Data model
|
|
|
|
No new tables. Extends existing endpoints:
|
|
- `GET /api/workspaces/:id/context` — already returns `recentThreads[]`. Pull `recentThreads[0]` if its `lastActive` ≤ 7 days. Add `lastDecision` field (top decision content from yesterday) — drawable from existing `recentDecisions[0]`.
|
|
- New endpoint `POST /api/sessions/:id/load` — already exists conceptually as `getHistory(workspaceId, sessionId)`. Confirm wire-up.
|
|
|
|
Frontend localStorage:
|
|
```
|
|
continuity:dismissed:{wsId} = ISO timestamp
|
|
```
|
|
Set on Start-fresh click. Banner suppressed for that workspace until next mount where lastActive moves forward (i.e. user has actually had new activity).
|
|
|
|
## Implementation notes
|
|
|
|
- Existing `WorkspaceBriefing` already shows `recentThreads[]` as a list. Continuity banner is a focused alternative: ONE thread, biggest decision, action-oriented buttons.
|
|
- Decision: keep WorkspaceBriefing for the "browse" affordance (5 recent threads + memories + decisions list) and add ContinuityBanner as the "resume" affordance (1 thread, 1 click to continue). They co-exist, both above chat list, ContinuityBanner above WorkspaceBriefing.
|
|
- Continue button: calls existing session load mechanism — `setActiveSession(threadId)` then `loadSessionHistory(threadId)`.
|
|
- Decision extraction: `recentDecisions[0]` from workspace-context already filtered for last 24h elsewhere; reuse.
|
|
|
|
## Estimate
|
|
|
|
- ContinuityBanner component: ~70 LOC
|
|
- ChatApp wire-up + localStorage logic: ~30 LOC
|
|
- Server context extension (lastDecision field): ~10 LOC
|
|
- Tests: ~30 LOC (banner render conditions, dismissal flag, time-window logic)
|
|
- **Total ~140 LOC, ~2-3h with verification.**
|
|
|
|
## Risks + open questions
|
|
|
|
1. **Three surfaces collide** — ContinuityBanner + WorkspaceBriefing + LoginBriefing all surface "what you did last" content. Need clear visual hierarchy: LoginBriefing (cross-workspace), WorkspaceBriefing (this workspace overview), ContinuityBanner (one-click resume).
|
|
2. **Stale banner** — user opens Chat at 2am after a 12-hour break. Banner says "Yesterday you...". Linguistic edge case (was it really yesterday?). Use existing `timeAgo()` helper.
|
|
3. **Continue vs new session** — clicking Continue should load the OLD session's messages OR start a NEW session that references them? v1: load old session messages so user sees full context.
|
|
4. **Multiple workspaces** — banner only fires for the active workspace. Cross-workspace continuity prompts are LoginBriefing's job.
|
|
5. **Fresh user** — sessionCount=0 → banner suppressed. But what about a returning user with one stub workspace and no real sessions? Same: suppress.
|
|
|
|
## Out of scope (v1)
|
|
|
|
- Voice continuity ("Resume our conversation where I asked about X").
|
|
- Multi-thread continuity (continue the most-impactful thread, not just newest).
|
|
- Smart "you might want to follow up on X" suggestion engine. (That's the Daily Brief's domain.)
|
|
- Cross-device continuity sync (already handled by server-side session storage; no client work needed).
|
|
|
|
## PM decisions needed
|
|
|
|
- [ ] GO / MODIFY / SKIP
|
|
- [ ] Time window — 7 days reasonable? or shorter (3 days)? or 30 days?
|
|
- [ ] Dismissal scope — per-session (re-show next mount) or per-day?
|
|
- [ ] Continue button behavior — load old messages vs new session w/ context inject
|
|
- [ ] Co-existence with WorkspaceBriefing — both above chat OR Continuity replaces Briefing for last-7-day case?
|