feat(store,api): conversation tags + single-Agent assignee (HT-29, HT-31) - #28
Merged
Conversation
…-31)
One PR for two sibling v1.1 increments that share every touchpoint
(summary shape, router, summary-returning UPDATEs) — separate PRs
would have guaranteed a conflict-and-rebase cycle with no isolation
benefit.
Migration 006: tags jsonb NOT NULL DEFAULT '[]' (no side table — v1
has no tag-filtered listing, spec §4e) and nullable assignee text
CHECKed to 'me' (single-Agent by construction, spec §4f). No backfill
needed: both defaults are correct for every existing row.
Store: setConversationTags (persists verbatim; HTTP layer normalizes)
and setConversationAssignee — neither bumps updated_at (metadata, not
activity, per spec). The summary RETURNING clause is now one shared
helper across status/tags/assignee so all summary-shaped UPDATEs map
identically.
API: PUT /conversations/{id}/tags (trim -> lowercase -> dedupe
preserving order; 1-40 chars after trim, else 400) and PUT
/conversations/{id}/assignee ({assignee: 'me' | null}, property
required). tags/assignee on every wire summary and detail.
369/369 tests: migration 006 upgrade path + CHECK enforcement,
replace-set round-trips with no-bump proof, normalization on the wire,
validation matrices, 404 trio, Allow headers.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (8)
📝 WalkthroughWalkthroughConversation records now support normalized tags and nullable assignee metadata across migrations, storage, API routing, update handlers, responses, and tests. New PUT endpoints replace tags or claim/release assignees. ChangesConversation metadata
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant InboxApi
participant Router
participant ConversationHandlers
participant ConversationStore
participant Database
Client->>InboxApi: PUT tags or assignee
InboxApi->>Router: Match request route
Router-->>InboxApi: Return conversation route
InboxApi->>ConversationHandlers: Dispatch update
ConversationHandlers->>ConversationStore: Update metadata
ConversationStore->>Database: Persist and return summary
Database-->>ConversationStore: Updated summary
ConversationStore-->>ConversationHandlers: Summary or null
ConversationHandlers-->>Client: API response
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 |
This was referenced Jul 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Fourth v1.1 increment — two tickets in one PR, deliberately: HT-29 (tags) and HT-31 (assignee) touch identical regions (summary shape, router, the summary-returning UPDATE pattern, the same test tails), so separate PRs would have guaranteed another conflict-and-rebase cycle like #27's, with no isolation benefit. Every line traces to one of the two named tickets. Spec: §4e/§4f (v1.1, #24).
What
Migration 006
tags jsonb NOT NULL DEFAULT '[]'— replace-set storage, no side table (v1 has no tag-filtered listing per spec §4e; a tag table would be structure with no query to serve).assignee text+CHECK (assignee IS NULL OR assignee = 'me')— single-Agent by construction; a future multi-Agent migration must widen it explicitly.Store
setConversationTags/setConversationAssignee— summary-returning UPDATEs; neither bumpsupdated_at(metadata, not activity — spec), proven by tests.API
PUT …/tags: normalization in the handler (trim → lowercase → dedupe preserving first occurrence), validation on the trimmed value (1–40 chars);[]clears.PUT …/assignee:{ assignee: 'me' | null }— property must be present; anything else 400.tags/assigneeon every wire summary and detail; router gains the two PUT-only routes with correctAllowbehavior.Evidence
updated_at-bump proofs for both writes, wire normalization (' Bug '+'bug'→['bug']), validation matrices for both bodies, the missing/deleted/non-UUID 404 trio on both routes, 405Allow: PUT, 401.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes