feat(store,api): four-state conversation status — active/pending/closed/spam (HT-26) - #25
Conversation
…ed/spam (HT-26) Migration 004 renames 'open' to 'active' (old CHECK dropped before the backfill — order is load-bearing) and adds 'pending' and 'spam'; the column default moves to 'active' so inbound mail keeps creating conversations through the unchanged status-less INSERT. Store: ConversationStatus/ConversationFolder types; listConversations filters by FOLDER (open = active + pending; closed/spam exact); setConversationStatus accepts all four (deleted still excluded); appendThread reopens closed AND spam to active — pending deliberately stays pending (an Agent statement, never auto-cleared). API: GET ?status= accepts open|closed|spam folders (active/pending rejected — folders are the reading grain); PATCH accepts all four statuses; wire summaries carry the real status. Per specs/api/agent-inbox-v1.md §2/§3a/§4a/§4b as amended to v1.1 (HT-25, PR #24). Upgrade path proven: migration-004-over-003 test seeds 'open' rows and verifies the backfill; the full suite runs against both PGlite and the Postgres adapter schema test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
📝 WalkthroughWalkthroughThe PR migrates conversations from open/closed semantics to active, pending, closed, and spam statuses, while retaining deleted storage rows. It adds database migration 004, folder-based listing, expanded status updates, reopening behavior, and corresponding API, store, migration, and integration tests. ChangesConversation status model
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant conversations_api
participant ConversationStore
Client->>conversations_api: list with status folder
conversations_api->>ConversationStore: listConversations with folder
ConversationStore-->>conversations_api: summaries with ConversationStatus
conversations_api-->>Client: conversation summaries
Client->>conversations_api: patch status or reply
conversations_api->>ConversationStore: update or append thread
ConversationStore-->>conversations_api: updated conversation status
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/store/conversations.ts (1)
383-384: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winStale doc reference:
options.status→options.folder.This PR renames
ListConversationsOptions.statustofolder(see lines 465-471), but this doc comment onlistConversationsstill saysoptions.statusand links to{@linkListConversationsOptions.status}, which no longer exists. The@linkis now broken and the prose is misleading for future readers.📝 Proposed fix
- * `deleted` conversation is NEVER returned, regardless of - * `options.status` — see {`@link` ListConversationsOptions.status}. + * `deleted` conversation is NEVER returned, regardless of + * `options.folder` — see {`@link` ListConversationsOptions.folder}.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/store/conversations.ts` around lines 383 - 384, Update the listConversations documentation to refer to options.folder and link to ListConversationsOptions.folder instead of the removed status property, preserving the existing statement that deleted conversations are never returned.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/store/conversations.ts`:
- Around line 383-384: Update the listConversations documentation to refer to
options.folder and link to ListConversationsOptions.folder instead of the
removed status property, preserving the existing statement that deleted
conversations are never returned.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 9dd3fde6-1b36-4cdb-89a5-a3477418d1d7
📒 Files selected for processing (8)
src/api/conversations.tssrc/api/index.test.tssrc/db/migrate.test.tssrc/db/migrate.tssrc/db/postgres.test.tssrc/dev/seed.test.tssrc/store/conversations.test.tssrc/store/conversations.ts
Why
First implementation increment of the v1.1 contract (HT-26; spec amendment HT-25 / #24). The status model is the foundational change every other v1.1 ticket layers on.
What
Migration 004 —
ConversationStatusbecomesactive | pending | closed | spam(+deleted, unchanged and never surfaced):open → activebackfill (updating first would fail on any non-fresh DB — same discipline as migration 002's backfill), new CHECK added after.'active', so the inbound-mail path's status-less INSERT is untouched.'open'is no longer a legal value — a rename, not a widening.Store —
ConversationStatus/ConversationFoldertypes.listConversationsnow filters by folder (open= active + pending;closed/spamexact; omitted = everything but deleted). Summaries carry the real status.setConversationStatusaccepts all four;deletedremains unreachable (and now unsettable by type).appendThreadreopens closed and spam toactive; pending deliberately stays pending — it's an Agent statement the spec says is never set (or cleared) automatically.API —
GET /conversations?status=acceptsopen|closed|spam; raw statuses (active/pending) are rejected 400 — folders are the reading grain.PATCHaccepts all four statuses;deletedstill 400.Evidence
npm test: 341/341 pass (18 files), including 10 new tests: migration-004 upgrade path over a seeded pre-004 database ('open'→'active', closed/deleted untouched), fresh-install CHECK/default behavior, spam-reopen + pending-stays-pending at store and API level, folder semantics incl. the active+pending union, PATCH pending/spam round-trips, and raw-status filter rejection.Spec
Written against
specs/api/agent-inbox-v1.mdv1.1 as amended in #24 (§2 status semantics, §3a folder listing, §4a spam-reopen, §4b four-value PATCH). Merge #24 first (or together) so spec and behavior land consistently.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes