feat(mark): add AI-generated one-sentence review titles#349
Conversation
Ask the review agent for a single-sentence title (max 15 words) that conveys overall confidence in the changes. The title is returned in a ```review-title fenced block alongside the existing review-comments block. Backend changes: - Add nullable `title` column to the `reviews` table (schema v18) - Add `title` field to the Review model and ReviewTimelineItem - Extract the review title from agent output in session_runner and persist it via a new `update_review_title` store method - Include the title in branch context timeline entries Frontend changes: - Add `title` to the ReviewTimelineItem TypeScript type - Display the review title in the branch timeline, falling back to "Code Review" when no title is available
…scription Update the code review prompt to explicitly instruct the LLM to focus the review title on its confidence level rather than describing what the changes do. This produces more useful at-a-glance signals in the branch timeline. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Drop the "This title will be shown in the branch timeline" clause from the review prompt — it leaks UI implementation details to the LLM without improving output quality. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0accc05f76
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| conn.execute_batch("ALTER TABLE reviews ADD COLUMN title TEXT DEFAULT NULL;") | ||
| .ok(); // Ignore error if column already exists (fresh DB) |
There was a problem hiding this comment.
Fail migration if adding reviews.title does not succeed
This migration swallows every ALTER TABLE error via .ok() and then unconditionally stamps schema_version to 18, so a non-duplicate failure (for example a locked/corrupt DB) leaves the DB marked as upgraded while still missing reviews.title. After that, the new SELECT ... title ... FROM reviews queries in store/reviews.rs will fail at runtime with no such column: title, effectively breaking review loading until a reset. The migration should only ignore the specific "duplicate column" case or abort without bumping the schema version.
Useful? React with 👍 / 👎.
| let start_pos = text.find(marker)?; | ||
| let block_start = start_pos + marker.len(); | ||
| let content_start = block_start + text[block_start..].find('\n')? + 1; | ||
| let end_pos = find_closing_fence(&text[content_start..])?; |
There was a problem hiding this comment.
Parse beyond first review-title marker
extract_review_title only checks the first occurrence of ````review-title`` and returns immediately; if that first block is malformed/empty but a later assistant message contains a valid title block, the function still returns None and the review title is never persisted. Since `run_post_completion_hooks` concatenates all assistant messages and retries can produce multiple blocks, this causes lost titles in real sessions. Iterate through markers (like `extract_review_comments`) and pick a valid non-empty block.
Useful? React with 👍 / 👎.
…ction When the LLM discusses the extraction logic in its preamble (e.g. mentioning `"```review-title"` as a string), `text.find(marker)` matched the mid-line mention instead of the actual fenced block. This caused the entire preamble + fenced block content to be stored as the review title. Fix by adding `find_opening_fence()` which requires the marker to appear at column 0 (start of text or after `\n`), matching the same convention used by `find_closing_fence()`. Applied to both title and comment extraction. Also suppress streaming hints when review fenced blocks are detected (the surrounding text is just LLM preamble, not a useful status), and instruct the LLM not to produce text outside the fenced blocks. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Drop the "Do not include any text outside the two fenced blocks" instruction and its corresponding test assertion, allowing the LLM to produce preamble text if it wants to. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
titlecolumn to reviews and areview-titlefenced block to the AI review prompt, so each code review gets an AI-generated one-sentence title reflecting confidence levelsession_runner, alongside existing comment extractionTest plan
extract_review_title(simple, whitespace trimming, missing, empty, alongside comments)titlecolumn)🤖 Generated with Claude Code