moving
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled

This commit is contained in:
Oleg Maslov
2026-09-02 10:10:29 +02:00
commit 0c3e2ead3b
3841 changed files with 970576 additions and 0 deletions

View File

@@ -0,0 +1,87 @@
# 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?