Expand description
Review-thread persistence on the redb review_threads table.
The /diff overlay’s line comments persist here per (project, branch) so a review round survives closing the overlay and forge
restarts. Keyed by (project, branch) - the whole set for a branch
is one serde-json blob. project is the forge.toml project NAME
(worktree-agnostic), never the directory-hash key.
Re-exports§
use anyhow::Context;🔒use forge_primitives::review::ReviewAuthor;🔒use forge_primitives::review::ReviewComment;🔒use forge_primitives::review::ReviewSet;🔒use forge_primitives::review::ReviewStatus;🔒use forge_primitives::review::ReviewThread;🔒use redb::ReadableTable;🔒use redb::TableDefinition;🔒use super::Db;🔒
Structs§
- Thread
Membership 🔒 - Membership a row carries on the thread rather than its turns - the shape stored while a thread could only belong to one review.
Constants§
- REVIEWS 🔒
- Submitted reviews per
(project, branch)- the sealed groupings a thread’s turns point into. Sibling ofREVIEW_THREADS; the whole set for a branch is one serde-json blob. - REVIEW_
THREADS 🔒
Functions§
- append_
reply - Append an agent reply to the thread
idin(project, branch): push aReviewCommentauthored byAgent { label: author_label }, flip anOpenthread toAddressed(a Resolved / Outdated / already-Addressed thread keeps its state), bumpupdated_at, and persist in one write transaction. Returns the thread’s status after the append. Errors when no thread carriesid, so a stale comment_id surfaces rather than silently no-op’ing. An emptyatis stamped with the current instant. - decode 🔒
- Decode a stored blob into threads, mapping a decode failure to an
error tagged with the owning
(project, branch)so a corrupt row is diagnosable rather than a bare serde message. Lifts membership off any row still carrying it on the thread (seelift_thread_membership). - decode_
reviews 🔒 - Decode a stored blob into reviews, tagged with the owning
(project, branch)on failure so a corrupt row is diagnosable. - delete
- Delete the whole thread set for
(project, branch). Returns whether a row existed. - delete_
branch_ state - Drop both of
(project, branch)’s rows in one write transaction. - find_
thread_ by_ id - Look up one thread by its globally-unique
idin(project, branch).Nonewhen the branch has no such thread (or no row).comment_idin the review MCP maps to thisid. - lift_
thread_ 🔒membership - Attribute a pre-per-turn row’s history: a thread filed as a whole has
its user turns stamped with that review, so they read as the round they
were actually part of instead of as unfiled. Positional - the mirror
decode ignores every other key, so it aligns with
threads. Only applies where no turn is filed yet, leaving a re-saved row’s own membership alone; the new shape persists on the thread’s next write. - load
- Load every thread for
(project, branch). Empty when the branch has no row (or the table doesn’t exist yet). - load_
reviews - Load every submitted review for
(project, branch), oldest first. Empty when the branch has no row (or the table doesn’t exist yet). - remove_
thread - Remove the single thread
idfrom(project, branch), dropping the row entirely when it was the last one. Returns whether a thread was removed. Used when the user clears a reopened comment’s text to delete it, so it doesn’t resurrect on the next hydrate. - review_
branches - The branches under
projectthat hold at least one submitted review, in key order. Seeks straight to the project’s first key and stops at its last, so thereview__listempty path can ask “is this review filed against another branch?” without scanning the table. - rfc3339_
now 🔒 - RFC3339 timestamp for the current instant, matching the
mcp::peershelper’s shape. - save
- Overwrite the whole thread set for
(project, branch). An empty slice removes the row rather than storing an empty blob. - set_
status - Set the status of the thread
idin(project, branch), bumping itsupdated_at. Returns whether a matching thread was found. - stored_
branches - Every branch under
projectholding review state of either kind, deduped, in key order. Same per-project seek asreview_branches, run over both tables: a branch can carry drafted threads and no submitted review, so a sweep consulting only the reviews table would leave its threads row behind. - submit_
review - Seal a new review for
(project, branch): mint its number (existing count + 1), stamp every still-unfiled user turn on each listed thread with the new review id, and append theReviewSet. Turns already filed never move, so a thread whose earlier turns went into review 1 and whose reply goes into review 2 belongs to both. A thread that gains a turn this way isAddressedno longer - the agent owes an answer again - so it flips back toOpen; aResolved/Outdatedthread keeps its state. Agent replies are answers to a round rather than part of one and are never stamped. One write transaction spans both tables so the stamp and the append land together. - upsert
- Insert
thread, replacing any existing thread with the same id in the branch’s set; appends when the id is new. Stampsupdated_atto now and fillscreated_at(preserved from the existing row on replace, set to now when the caller left it empty) so a view need not carry a clock. - write_
corrupt_ reviews_ row_ for_ test - Test-only sibling of
write_corrupt_row_for_testfor thereviewstable, so a caller can exercise the reviews load-error path. - write_
corrupt_ row_ for_ test - Test-only: write undecodable bytes into the
(project, branch)row so a caller can exercise the load-error path (a corrupt / partially written redb row). Feature-gated for cross-crate test access.