feat: scope local reviews to comparisons

This commit is contained in:
2026-10-25 01:00:58 +02:00
parent 815fcccbe8
commit 448c3bf477
15 changed files with 760 additions and 72 deletions
+7 -5
View File
@@ -504,8 +504,8 @@ Local review buffers (comments, summaries, overview, and stored-review selector)
| `:review.verdict looks_good` | Record **Looks good** |
| `:review.verdict changes_requested` | Record **Changes requested**; `none` clears the verdict |
| `:review.save [path]` | Commit to SQLite; with a path, also export JSON for sharing |
| `:review.open [id or path]` | Show stored reviews, open a stored review ID, or import a JSON review as a new review |
| `:review.new` | Create a separate stored review for the current repository |
| `:review.open [id or path]` | Show reviews for the current scope, open a matching stored review ID, or import matching JSON as a new review |
| `:review.new` | Create another stored review for the current comparison or ordinary-source scope |
File checkmarks remain diff-specific (`:diff.review.toggle`).
@@ -519,13 +519,15 @@ From the shell, use `vamp --review delete REVIEW_ID COMMENT_ID [--repo PATH] [--
Use `vamp --review resolve REVIEW_ID COMMENT_ID [--repo PATH] [--json]` after addressing and verifying feedback to mark it resolved without changing its body or original anchor. The command prints the updated review's remaining unresolved comments and full counts; `show REVIEW_ID --all` still includes the resolved original. Repeating resolution succeeds without a write or revision bump. Both IDs must be positive and refer to the selected repository; invalid targets and absent storage fail without creating or changing stored data. Like deletion, resolution rejects stale saves from an editor holding the previous review revision.
Storage defaults to `$XDG_DATA_HOME/vamp/reviews/reviews.sqlite3`, or `~/.local/share/vamp/reviews/reviews.sqlite3` when XDG_DATA_HOME is unset or relative. Configure `review_directory` to override its directory; relative configuration paths resolve against the config file. Repository identity is the canonical checkout root. Each review has a persistent database ID independent of comparison revisions, so reopening changed revisions retains stale comments. Opening a comparison automatically restores the repository's sole review. Multiple reviews open a floating selector: move to an entry and press Enter, or use `:review.open id`. Use `:review.new` for another independent review.
Storage defaults to `$XDG_DATA_HOME/vamp/reviews/reviews.sqlite3`, or `~/.local/share/vamp/reviews/reviews.sqlite3` when XDG_DATA_HOME is unset or relative. Configure `review_directory` to override its directory; relative configuration paths resolve against the config file. Review scope is the canonical checkout root plus the ordered, resolved Before/After identities, not branch/bookmark labels. Opening a different pair selects its existing review or starts an empty one; reopening the same pair restores its feedback, verdict, and file progress. A sole matching review restores automatically; multiple reviews for that scope open a floating selector. Move to an entry and press Enter, or use `:review.open id`. `:review.new` creates another review within the same scope. Opening or importing a review from a different scope is rejected rather than reassigning its feedback.
Working edits and in-place checkout refreshes retain the comparison's initial review scope. Explicitly opening a comparison resolves its endpoints again: changed Working contents or moved bookmarks can therefore select a different review. Ordinary source-buffer comments use a separate repository-local source scope, never the last comparison's review. Unsaved review drafts block scope changes until saved or discarded. Opening an empty scope does not write storage until a review change is committed.
Write errors, locked databases, incompatible schemas, and conflicting edits from another editor instance retain dirty drafts and report the failure. Failed text saves leave the committed review unchanged; unrelated metadata autosaves cannot commit those drafts. Normal destructive closes remain guarded until drafts are explicitly saved or discarded. `:w!` does not bypass database revision conflicts; export your draft before reopening the current stored review. JSON exports retain external-file-change protection. Only the current database schema is accepted; existing incompatible databases are preserved rather than reset or migrated.
The current SQLite format is schema 3: typed `reviews`, `comments`, and `reviewed_files` tables, not serialized JSON documents. Older databases are incompatible and are left untouched; there is no migration or automatic reset. JSON version 4 is the sharing format, independent of the database schema.
The current SQLite format is schema 4: typed `reviews`, `comments`, and `reviewed_files` tables, not serialized JSON documents. Review rows store nullable Before/After identities; both are null for source reviews. Older databases, including schema 3, are incompatible and are left untouched; there is no migration or automatic reset. JSON version 5 is the sharing format, independent of the database schema.
Version 4 JSON is the agent-readable sharing format: repository root, summary, optional verdict, comments, and a required `reviewed_files` array. Each reviewed file stores its immutable per-file `revisions` pair (`file:` identities encoding mode, Git object ID or exact data, and notices), relative `path`, optional rename `old_path`, and optional exact live `after` text. Comments have stable IDs, bodies, required boolean `resolved` states, and anchors. New comments are unresolved. Database review IDs and optimistic storage revisions stay internal. Each anchor retains its immutable comparison revision, side, relative path (old path for renamed Before files), and exact whole-file text including the final newline. `start` and `end` contain zero-based source `row` and extended-grapheme `column` coordinates; `end` is exclusive. Columns count complete Unicode graphemes, not bytes, code points, UTF-16 units, or screen cells. Overview/window labels display one-based rows and columns. Older JSON formats are rejected and preserved without migration. Working comparisons use content-addressed snapshot IDs; captured text additionally freezes live unsaved edits. Stored reviews have a 64 MiB aggregate text budget including 64 bytes of overhead per comment and reviewed file; imported/exported JSON files have a separate 64 MiB serialized-size limit.
Version 5 JSON is the agent-readable sharing format: repository root, `comparison` (an ordered Before/After identity pair, or `null` for source reviews), summary, optional verdict, comments, and a required `reviewed_files` array. Each reviewed file stores its immutable per-file `revisions` pair (`file:` identities encoding mode, Git object ID or exact data, and notices), relative `path`, optional rename `old_path`, and optional exact live `after` text. Comments have stable IDs, bodies, required boolean `resolved` states, and anchors. New comments are unresolved. Database review IDs and optimistic storage revisions stay internal. Each anchor retains its immutable comparison revision, side, relative path (old path for renamed Before files), and exact whole-file text including the final newline. `start` and `end` contain zero-based source `row` and extended-grapheme `column` coordinates; `end` is exclusive. Columns count complete Unicode graphemes, not bytes, code points, UTF-16 units, or screen cells. Overview/window labels display one-based rows and columns. Older JSON formats are rejected and preserved without migration. Working comparisons use content-addressed snapshot IDs; captured text additionally freezes live unsaved edits. Stored reviews have a 64 MiB aggregate text budget including 64 bytes of overhead per comment and reviewed file; imported/exported JSON files have a separate 64 MiB serialized-size limit.
Reopening requires the same repository root. Unchanged comment ranges follow edits elsewhere in the file, including inserted/deleted lines above and column shifts before a partial-line selection. Working-snapshot refreshes can retain these attachments; unrelated immutable revisions and paths do not match. Mapping requires an unchanged, unambiguous text region containing the selection. Modified/deleted selections or ambiguous repeated regions are **stale**: comments remain available through the overview and next/previous navigation, with original snapshot coordinates and no current-source marker or jump. Saved anchors and exported excerpts remain unchanged. Unloaded files are shown as **not checked** until visited; refresh the overview to update its statuses. There is no server, authentication, or review-publishing operation.