Repository navigation
refactor(store): single module for review-history SQL - #585
Merged
Merged
Conversation
Move all SQL for reviews/findings/finding_events into engine::review_store (replaces engine::db_writer). cora findings, debt tracker and review/scan persistence call it and hold no SQL. Store takes a &Connection so it is testable with in-memory SQLite; best-effort persistence policy is explicit in persist_review_best_effort. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: ajianaz <ajianaz@users.noreply.github.com>
This was referenced Oct 8, 2026
Closed
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.
What
Adds
engine::review_store, the single module that owns SQL forreviews/findings/finding_events(schema stays inindex/schema.rs, unchanged). It replacesengine::db_writer.Interface:
ReviewStore<'a>over a borrowed&Connection(testable with in-memory SQLite):record_review,resolve_stale,list_findings(&FindingFilter),stats,finding_status,dismiss(id, reason),reopen(id)(both returnTransition::{NotFound, Unchanged, Applied}),reviews_for_root.open_read()/open_write()(+open_read_at(path)), allResult.persist_review_best_effort(&ReviewRecord)/persist_on(&conn, ..). It records the review and auto-resolves stale findings and never fails; errors are logged atdebug.review.rsandscan.rs(3 call sites) now make one call instead of an open/save/fingerprint/resolve block each.load_debt_rows(project_root)feedsdebt_tracker::snapshots_from_rows(pure conversion);debt_trackerno longer has SQL.Error policy: store methods surface errors to callers that can act on them (the
cora findingsCLI). Only the review/scan persistence path and the read-only debt report swallow errors, each through one named function.SQL sites migrated (checklist for reviewers)
Found via
grep -rnE 'findings|finding_events|reviews' srcfiltered to SQL verbs;schema.rs(DDL + its own migration tests) is intentionally left.commands/findings.rslist query (JOIN + dynamic filters)ReviewStore::list_findingscommands/findings.rs5xcount(*)(stats)ReviewStore::statscommands/findings.rsdismiss: SELECT status, UPDATE, INSERT eventReviewStore::dismisscommands/findings.rsreopen: SELECT status, UPDATE, INSERT eventReviewStore::reopenengine/db_writer.rsINSERT reviews / findings / finding_events('opened')ReviewStore::record_reviewengine/db_writer.rsSELECT stale + UPDATE resolved + INSERT 'auto_resolved'ReviewStore::resolve_staleengine/db_writer.rsopen_db,open_db_for_read,open_db_for_write(Option)open_read/open_write(Result)engine/debt_tracker.rsprojects lookup + reviews SELECT + 2x GROUP BY findingsReviewStore::reviews_for_rootsrc/mcp/tools.rsdebt_tracker::load_snapshots)Why
Closes #571. Review-history SQL was spread over four files,
open_db_*swallowed errors viaOption, and the status transitions could only be reached through the CLI against the real$HOMEdatabase, so they were untested. Now every path is covered by in-memory tests and the best-effort-vs-surface decision is explicit.Behavior changes (none user-visible on success):
record_reviewand status transitions now run in a transaction (a mid-way failure no longer leaves a review row without findings, or a status change without its event).resolve_staleis also a single transaction.findings list/statsnow propagate a SQL/row error instead of silently dropping rows / showing 0. A missing or unopenable DB still prints the same "could not open cora.db" message with exit 1.Left out / noticed:
cora findings list --severity Xnever matches anything. Severities are stored lowercase (Severity::to_string) but the filter upper-cases its argument, and the list renderer'sCRITICAL/MAJORcolour match is likewise dead. This is pre-existing; I kept it so the refactor stays behavior-preserving and pinned it in a test with a comment. Worth a separate fix.Testing
cargo fmt,cargo clippy --all-targets --features tree-sitter -- -D warnings: clean.cargo test --features tree-sitter -- --skip index:: --skip watch::: all pass (924 unit + integration). In my sandbox theindex::/commands::watchtests hang (not touched by this change), so I skipped them.engine::review_store::tests, 13): record + findings +openedevents round trip, atomic rollback on failure, list filters (open/all/file/limit), dismiss, dismiss again, reopen, already-open no-op, not-found, reopen after auto-resolve,auto_resolvedevent and project isolation, stats, debt reads (open-only breakdown, unknown project), best-effort persistence (success + auto-resolve, and broken-schema returns default without error), read-only open of a missing DB errors. Plusdebt_tracker::snapshots_from_store_rows.HOME(DB created byfindings dismissmigrations, then seeded with sqlite3):findings liston no DB:Error: could not open cora.db, exit 1#2 minor src/b.rs :9 | Meh [OPEN]/#1 critical ...dismiss 1 --reason wontfix->Finding #1 dismissed.exit 0;reopen 2->already open.exit 0;reopen 1->reopened.;dismiss 42->not found.exit 1finding_events:dismissed|wontfix,reopened|Manually reopened via CLI,dismissed|Manually dismissed via CLIstats/list --all --jsonoutput as expected.Closes #571
🤖 Generated with Claude Code