Skip to content

fix(realtime): delete files by absolute path - #1153

Draft
aoright wants to merge 1 commit into
vitali87:mainfrom
aoright:fix/realtime-absolute-file-deletion
Draft

fix(realtime): delete files by absolute path#1153
aoright wants to merge 1 commit into
vitali87:mainfrom
aoright:fix/realtime-absolute-file-deletion

Conversation

@aoright

@aoright aoright commented Aug 10, 2026

Copy link
Copy Markdown

Summary

Type of Change

  • Bug fix
  • New feature
  • Performance improvement
  • Refactoring (no functional changes)
  • Documentation
  • CI/CD or tooling
  • Dependencies

Related Issues

Fixes #1141

Test Plan

  • Unit tests pass (make test-parallel or uv run pytest -n auto -m "not integration")
  • New tests added
  • Integration tests pass (make test-integration, requires Docker)
  • Manual testing (describe below)

Regression verification:

  • before the production fix, the two updated assertions failed with relative paths
  • focused realtime/watcher tests: 40 passed
  • full non-integration suite: 6,786 passed, 35 skipped
  • integration suite: 299 passed, 5 skipped
  • all pre-commit hooks passed, including Ruff, format, ty, README generation, and Bandit

Checklist

  • PR title follows Conventional Commits format
  • All pre-commit checks pass (make pre-commit)
  • No hardcoded strings in non-config/non-constants files
  • No # type: ignore, cast(), Any, or object type hints
  • No new comments or docstrings (code should be self-documenting)

AI assistance

AI assistance was used to investigate the issue, implement the focused fix, and update regression assertions. The final diff was manually reviewed and validated with the full test and pre-commit suites above.

Summary by CodeRabbit

  • Bug Fixes
    • Improved file deletion handling by consistently resolving file locations before removal.
    • Prevented path-related mismatches that could cause file-node deletions to target the wrong location.
    • Preserved existing module deletion behavior and project scope handling.

@vitali87

Copy link
Copy Markdown
Owner

Thanks for this — the root cause and fix are correct. `CYPHER_DELETE_FILE` matches on `absolute_path` (MATCH (f:File {absolute_path: $path})), but the realtime updater was binding `$path` to the repo-relative string, so it never matched and deletions silently no-opped. Resolving to the absolute POSIX path is right, and it lines up with the batch-delete path (graph_updater.py:1860, already resolve().as_posix()) and issue #897.

Approved CI to run. One optional nit (your call, not a blocker): the following debug line still formats relative_path_str, so the log now shows the relative path while the query deletes by the absolute one — you may want to log path.resolve().as_posix() there too for consistency:

logger.debug(logs.DELETION_QUERY.format(path=relative_path_str))

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8af75d67-f18b-4ba6-b7fd-b82a629b52d1

📥 Commits

Reviewing files that changed from the base of the PR and between 234816e and dd19554.

📒 Files selected for processing (2)
  • codebase_rag/tests/test_realtime_event_filtering.py
  • realtime_updater.py

📝 Walkthrough

Walkthrough

The realtime watcher now passes resolved absolute paths to CYPHER_DELETE_FILE. Tests validate absolute paths for file deletion while preserving relative paths for module deletion.

Changes

Realtime file deletion

Layer / File(s) Summary
Use resolved paths for file deletion
realtime_updater.py, codebase_rag/tests/test_realtime_event_filtering.py
File deletion now uses path.resolve().as_posix(). Tests expect resolved absolute paths for deleted files. Module deletion expectations remain relative.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: vitali87

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: realtime file deletion now uses absolute paths.
Description check ✅ Passed The description includes the required summary, change type, issue, test plan, checklist, and validation details.
Linked Issues check ✅ Passed The changes satisfy #1141 by using resolved absolute paths for File deletion, retaining relative Module deletion, and updating regression assertions.
Out of Scope Changes check ✅ Passed The production and test changes are limited to the linked issue objectives and contain no unrelated modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@vitali87

Copy link
Copy Markdown
Owner

@coderabbitai review

@vitali87

Copy link
Copy Markdown
Owner

@greptileai review

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@greptile-apps

greptile-apps Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Realtime deletion now uses the resolved absolute path that identifies stored File nodes, while module deletion continues to use its project-scoped relative identity. A focused regular-file deletion check passed for the updated handler.

Confidence Score: 5/5

No blocking failure remains.

The focused deletion check confirmed that regular files are deleted using their stored absolute-path identity and that module deletion retains its project scope.

T-Rex T-Rex Logs

What T-Rex did

  • Ran the realtime-delete-contract harness with a mocked regular-file DELETE event, which showed the updated implementation resolves to an absolute POSIX path and retains the scoped project-relative module-delete parameters, allowing the handler to evaluate the focused contract assertions.
  • The pre-change approach failed when nested/regular.py was supplied to CYPHER_DELETE_FILE, while the post-change approach passes with the resolved absolute POSIX path while retaining scoped module-delete semantics.

View all artifacts

T-Rex Ran code and verified through T-Rex

Reviews (2): Last reviewed commit: "fix(realtime): delete files by absolute ..." | Re-trigger Greptile

Comment thread realtime_updater.py
# Delete File node (for all files including non-code like .md, .json)
ingestor.execute_write(CYPHER_DELETE_FILE, {KEY_PATH: relative_path_str})
ingestor.execute_write(
CYPHER_DELETE_FILE, {KEY_PATH: path.resolve().as_posix()}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Deleted symlink identity is lost

A deletion event is handled after a symlink has been removed, so path.resolve() now returns the missing symlink pathname rather than the target’s canonical path that was stored in File.absolute_path while the link existed. CYPHER_DELETE_FILE consequently receives an identity that cannot match the indexed File node, leaving stale graph data after a symlinked file is deleted. Preserve the indexed resolved path for watched files, or maintain a lexical-path-to-indexed-path mapping for DELETE events.

Artifacts

Direct pathlib symlink resolve harness source

  • This exact authored self-contained Python harness creates a symlink, resolves it before and after unlinking it, and prints both identities, with the takeaway that unlinking changes resolve output from target identity to missing-link identity.

Pathlib symlink resolution before unlink

  • This command capture runs the direct harness while the symlink exists and shows resolve equals the canonical target identity, with the takeaway that indexing a live symlink records its target path.

Pathlib symlink resolution after unlink

  • This command capture runs the direct harness after unlinking the symlink and shows resolve returns the missing symlink pathname instead of the target path, with the takeaway that the deletion identity does not match the indexed identity.

View artifacts

T-Rex Ran code and verified through T-Rex

Prompt To Fix With AI
This is a comment left during a code review.
Path: realtime_updater.py
Line: 270

Comment:
**Deleted symlink identity is lost**

A deletion event is handled after a symlink has been removed, so `path.resolve()` now returns the missing symlink pathname rather than the target’s canonical path that was stored in `File.absolute_path` while the link existed. `CYPHER_DELETE_FILE` consequently receives an identity that cannot match the indexed File node, leaving stale graph data after a symlinked file is deleted. Preserve the indexed resolved path for watched files, or maintain a lexical-path-to-indexed-path mapping for DELETE events.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good find, and the mechanism is correct: cached_resolve_posix() calls Path.resolve() at ingest (so a symlink is stored under its target's canonical path), and once the link is deleted resolve() can no longer follow it, so the delete key misses.

However this is pre-existing and not introduced by this PR — the batch-delete path already does the same thing at graph_updater.py:1860 (deleted_path.resolve().as_posix(), issue #897). This PR brings the realtime path into parity with it and correctly fixes the common regular-file case, which was the actual bug (relative key vs absolute_path match). The symlink edge case needs a separate identity strategy for both paths, so Iʼve split it out as #1154 rather than block this fix.

@aoright — nothing for you to change here on account of this; the symlink handling is tracked in #1154 and is out of scope for this PR.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point — the symlink gap predates this PR and is consistently present in the batch path at graph_updater.py:1860, so this change correctly achieves parity rather than introducing a regression. Splitting it to #1154 is the right call.

Acknowledged, no action needed here on that front.

@vitali87

Copy link
Copy Markdown
Owner

@greptileai the symlink-deletion case is a valid but pre-existing gap (shared with the batch path at graph_updater.py:1860); Iʼve tracked it separately in #1154 so it doesnʼt block this regular-file fix. Please re-review with that scope in mind.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

fix(realtime): File deletion uses relative path after absolute-path migration

2 participants