fix: transaction safety, resource cleanup, and truncation signaling (#258, #259, #260, #261)#279
Open
azizur100389 wants to merge 1 commit intotirth8205:mainfrom
Open
Conversation
…irth8205#258, tirth8205#259, tirth8205#260, tirth8205#261) Four reliability hardening fixes that improve crash safety, resource cleanup, and API transparency across the graph pipeline. Fix 1: wrap incremental_trace_flows DELETEs in a transaction (tirth8205#258) ------------------------------------------------------------------- File: code_review_graph/flows.py:499-502 The DELETE loop in incremental_trace_flows deleted flow_memberships and flows rows one at a time without an explicit transaction. A crash mid-loop could leave orphaned flow_memberships rows pointing at deleted flows. Fix: wrap the DELETE loop in BEGIN IMMEDIATE / COMMIT / ROLLBACK, matching the pattern already used by store_flows at line 406. Includes an in_transaction guard to flush any implicit transaction first. Test: test_incremental_trace_flows_delete_is_atomic — verifies no orphaned memberships exist after an incremental re-trace. Fix 2: atomic FTS index rebuild (tirth8205#259) -------------------------------------- File: code_review_graph/search.py:39-54 rebuild_fts_index performed DROP, CREATE, and INSERT across three separate statements with commits between them. A crash after DROP but before CREATE would leave the DB without an FTS table entirely. Fix: wrap the entire DROP + CREATE + INSERT sequence in a single BEGIN IMMEDIATE transaction so the operation is all-or-nothing. Test: test_fts_rebuild_is_atomic — verifies double-rebuild leaves the table intact and queryable. Fix 3: EmbeddingStore context manager support (tirth8205#260) ---------------------------------------------------- File: code_review_graph/embeddings.py:391+ EmbeddingStore opens a SQLite connection in __init__ but did not implement __enter__/__exit__. If an exception occurred during usage before close() was called, the connection leaked. Fix: add __enter__ and __exit__ methods following the same pattern as GraphStore (graph.py:154-157). Test: test_supports_context_manager, test_context_manager_closes_on_exception. Fix 4: truncation signal for find_dependents (tirth8205#261) ---------------------------------------------------- File: code_review_graph/incremental.py:434-465 When find_dependents hit _MAX_DEPENDENT_FILES (500), it truncated the result and logged a warning, but the caller received a plain list with no indication that it was incomplete. Callers had to guess whether they got the full dependent set or a truncated one. Fix: introduce DependentList (a transparent list subclass with a .truncated boolean attribute). Existing callers that iterate, len(), or slice continue to work unchanged; only callers that specifically check .truncated benefit from the signal. Tests: test_truncated_flag_set_when_capped (600 deps, expects True), test_truncated_flag_false_when_not_capped (small chain, expects False). Files changed ------------- - code_review_graph/flows.py — transaction wrap around DELETE loop - code_review_graph/search.py — atomic FTS rebuild - code_review_graph/embeddings.py — __enter__/__exit__ on EmbeddingStore - code_review_graph/incremental.py — DependentList with .truncated flag - tests/test_flows.py — orphan membership check - tests/test_search.py — double-rebuild atomicity test - tests/test_embeddings.py — context manager tests - tests/test_incremental.py — truncation flag tests Test results ------------ Stage 1 (new targeted tests): 6/6 passed. Stage 2 (all affected test files): 137 passed, 3 pre-existing failures (find_repo_root flakiness + UTF-8 gitignore — covered by PRs tirth8205#274/tirth8205#242). Stage 3 (full suite): 784 passed, 8 pre-existing Windows failures (all covered by parallel PRs). Stage 4 (ruff check on all 8 changed files): clean. Stage 5 (mypy on all 4 changed source files): clean. Zero regressions.
474e507 to
f55681c
Compare
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.
Summary
Four reliability hardening fixes that improve crash safety, resource cleanup, and API transparency across the graph pipeline. 8 files changed, +206 / -25, 6 new regression tests.
Closes #258, closes #259, closes #260, closes #261.
Fix 1 — Wrap
incremental_trace_flowsDELETEs in a transaction (#258)File:
code_review_graph/flows.py:499-502The DELETE loop deleted
flow_membershipsandflowsrows one at a time without an explicit transaction. A crash mid-loop could leave orphanedflow_membershipsrows pointing at deleted flows.Fix: Wrap in
BEGIN IMMEDIATE/COMMIT/ROLLBACK, matching the pattern already used bystore_flowsat line 406. Includes anin_transactionguard to flush any implicit transaction first.Test:
test_incremental_trace_flows_delete_is_atomic— verifies zero orphaned memberships after an incremental re-trace.Fix 2 — Atomic FTS index rebuild (#259)
File:
code_review_graph/search.py:39-54rebuild_fts_indexperformed DROP, CREATE, and INSERT across three separate statements with commits between them. A crash after DROP but before CREATE would leave the DB without an FTS table entirely.Fix: Wrap the entire DROP + CREATE + INSERT sequence in a single
BEGIN IMMEDIATEtransaction so the operation is all-or-nothing.Test:
test_fts_rebuild_is_atomic— verifies double-rebuild leaves the table intact and queryable.Fix 3 —
EmbeddingStorecontext manager support (#260)File:
code_review_graph/embeddings.py:391+EmbeddingStoreopens a SQLite connection in__init__but did not implement__enter__/__exit__. If an exception occurred during usage beforeclose()was called, the connection leaked.Fix: Add
__enter__and__exit__methods following the same pattern asGraphStore(graph.py:154-157).Tests:
test_supports_context_manager,test_context_manager_closes_on_exception.Fix 4 — Truncation signal for
find_dependents(#261)File:
code_review_graph/incremental.py:434-465When
find_dependentshit_MAX_DEPENDENT_FILES(500), it truncated the result and logged a warning, but the caller received a plainlistwith no indication that it was incomplete.Fix: Introduce
DependentList— a transparentlistsubclass with a.truncatedboolean attribute. Existing callers that iterate,len(), or slice continue to work unchanged; only callers that specifically check.truncatedbenefit from the signal.Tests:
test_truncated_flag_set_when_capped(600 deps →truncated=True),test_truncated_flag_false_when_not_capped(small chain →truncated=False).Files changed (8 files, +206 / -25)
code_review_graph/flows.pycode_review_graph/search.pycode_review_graph/embeddings.py__enter__/__exit__onEmbeddingStorecode_review_graph/incremental.pyDependentListwith.truncatedflagtests/test_flows.pytests/test_search.pytests/test_embeddings.pytests/test_incremental.pyTest results
ruff checkon all 8 changed filesmypyon all 4 changed source filesZero regressions. All fixes follow established patterns already used elsewhere in the codebase.