fix(db): fold reverse-dep edge deletion into NativeDatabase.purgeFilesData#679
fix(db): fold reverse-dep edge deletion into NativeDatabase.purgeFilesData#679carlos-alm merged 2 commits intomainfrom
Conversation
…sData (#670) purgeFilesData committed its own transaction via the rusqlite connection while the reverse-dep outgoing-edge purge ran through better-sqlite3. If the process was interrupted between the two, dangling edges could remain. Add an optional reverse_dep_files parameter to purge_files_data so both operations happen in a single transaction. The better-sqlite3 fallback path retains the original two-step behavior.
|
Claude finished @carlos-alm's task —— View job PR Review CompleteReview Tasks
Root Cause AnalysisProblem Being Solved: Fix atomicity gap where Why This Approach: Adding optional Risk Assessment: Low risk - purely additive change with comprehensive backward compatibility and extensive test coverage. Backlog Compliance
Technical ReviewImplementation Quality ⭐⭐⭐⭐☆Rust Changes (native_db.rs:720-795):
TypeScript Integration (detect-changes.ts:340-355):
Type Safety (types.ts:2079):
Test Coverage ⭐⭐⭐⭐⭐Comprehensive test suite covers:
Code Quality AssessmentStrengths:
Minor Observations:
Critical ConcernsNone. This is a well-implemented fix for a real atomicity issue. Final Recommendation
This PR directly addresses the core problem of preventing graph corruption that could confuse AI agents, making it valuable for the stated mission. |
Greptile SummaryThis PR closes the atomicity gap between file-purge and reverse-dependency edge deletion by folding both operations into a single rusqlite transaction inside Key changes:
Confidence Score: 5/5Safe to merge — the atomicity fix is correct, backwards-compatible, and well-tested with no P0/P1 issues found. All findings are P2 or lower. The Rust transaction logic, early-return guard, TypeScript call-site refactor, and fallback path are all correct. The new test suite exercises every meaningful edge case. No overlap between No files require special attention. Important Files Changed
Sequence DiagramsequenceDiagram
participant DC as detect-changes.ts
participant NDB as NativeDatabase (rusqlite)
participant BSQ as better-sqlite3 db
note over DC: handleScopedBuild / handleIncrementalBuild
DC->>BSQ: findReverseDependencies(db, changedRelPaths)
BSQ-->>DC: reverseDeps: Set<string>
alt ctx.nativeDb available (native path)
DC->>NDB: purgeFilesData(filesToPurge, false, reverseDepList)
note over NDB: BEGIN TRANSACTION
NDB->>NDB: DELETE embeddings/cfg/dataflow/nodes/edges for each file in filesToPurge
NDB->>NDB: DELETE outgoing edges for each file in reverseDepList
note over NDB: COMMIT (atomic)
NDB-->>DC: Ok(())
else better-sqlite3 fallback
alt hasPurge
DC->>BSQ: purgeFilesFromGraph(db, filesToPurge)
end
alt hasReverseDeps
DC->>BSQ: DELETE edges WHERE source_id IN nodes(file=relPath)
end
end
DC->>DC: push reverseDepList into ctx.parseChanges (_reverseDepOnly)
Reviews (1): Last reviewed commit: "fix(db): fold reverse-dep edge deletion ..." | Re-trigger Greptile |
Summary
Closes #670.
reverse_dep_filesparameter toNativeDatabase.purge_files_data(Rust/napi-rs) so file purge and reverse-dep outgoing-edge deletion happen in a single rusqlite transactionpurgeAndAddReverseDepsindetect-changes.tsto pass reverse-dep files through the native path, eliminating the cross-connection atomicity gapContext
purgeFilesDatacommitted its own transaction via the persistent NativeDatabase (rusqlite) connection, while the immediately following reverse-dep edge purge ran through the better-sqlite3dbhandle. If the process was interrupted between the two, dangling edges pointing to already-purged nodes could remain. This was a pre-existing atomicity gap flagged in PR #669 review.Test plan
purge-files.test.tspasses (better-sqlite3 path unchanged)native-db-purge-reverse-deps.test.tscovers: combined purge + reverse-dep, outgoing-only deletion, backwards-compat (no reverse-dep param), empty lists, reverse-dep-only call