Skip to content

fix(core): project-scoped forget, dim-safe cosine, precise question detection#25

Merged
krishpinto merged 2 commits into
mainfrom
worktree-code-review-fixes
Jun 30, 2026
Merged

fix(core): project-scoped forget, dim-safe cosine, precise question detection#25
krishpinto merged 2 commits into
mainfrom
worktree-code-review-fixes

Conversation

@krishpinto

@krishpinto krishpinto commented Jun 30, 2026

Copy link
Copy Markdown
Owner

What

Three correctness fixes surfaced while auditing the engine (grasp-core). Each is independent, small, and unit-tested.

1. forget() over-matched sibling projects

The processed_files cleanup used LIKE '%slug%' — an unanchored substring match. Consequences:

  • Forgetting c--projects-grasp also cleared records for c--projects-grasp-core (substring), forcing a needless full re-import of the sibling.
  • _ / % in a slug acted as SQL wildcards.

Now it matches the project's transcript directory as an anchored, escaped prefix. A new escape_like helper escapes %, _, and \ so Windows paths stay literal under LIKE … ESCAPE '\'.

2. cosine() silently mis-scored mismatched dimensions

a.iter().zip(b) truncates to the shorter slice, so a stale embedding of a different length produced a bogus (partial) similarity. The embeddings table already stores a per-row dim, so a future model/DIM change can leave differently-sized vectors behind — those must not corrupt ranking or semantic edges. Now returns 0.0 on a dimension mismatch.

3. is_question() false-positives on substrings

A bare contains("what ") flagged "somewhat slow" as a question. Now interrogatives match only at a word boundary (start of string or after a non-alphanumeric char).

Tests

  • escape_like_escapes_wildcards_and_backslashes
  • cosine_of_mismatched_dimensions_is_zero, cosine_of_identical_unit_vectors_is_one
  • question_detection_respects_word_boundaries

Full grasp-core suite green (29 passed, 2 pre-existing ignored), and grasp-cli builds clean.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Fixed similarity scoring so vectors of different lengths no longer yield misleading results.
    • Improved question detection by requiring interrogative keywords to appear at real word boundaries, reducing false matches inside other words.
    • Strengthened project “forget” cleanup to precisely target only records under the project’s transcript directory prefix, avoiding accidental deletion of unrelated items.

…estion detection

Three correctness fixes found auditing the engine:

- forget(): the processed_files cleanup used `LIKE '%slug%'`, an unanchored
  substring match. It also cleared sibling projects (forgetting `…-grasp`
  matched `…-grasp-core`) and treated `_`/`%` in a slug as wildcards, forcing
  needless re-imports. Now matches the project's transcript directory as an
  escaped, anchored prefix (`escape_like` handles Windows backslashes).

- cosine(): `zip` silently computed a truncated dot product when vector
  lengths differed. The `embeddings` table stores a per-row `dim`, so a future
  model/DIM change can leave stale vectors of another length — those must not
  corrupt ranking or semantic edges. Now returns 0.0 on a dimension mismatch.

- is_question(): a bare `contains("what ")` flagged "somewhat" (and similar)
  as questions. Now matches interrogatives only at a word boundary.

Each fix has unit-test coverage; full grasp-core suite green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 30, 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: 8d2479bc-6830-4b42-90a4-21a812cb2dc7

📥 Commits

Reviewing files that changed from the base of the PR and between 5b20c97 and 646358b.

📒 Files selected for processing (1)
  • crates/grasp-core/src/lib.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/grasp-core/src/lib.rs

📝 Walkthrough

Walkthrough

Three correctness fixes in grasp-core: cosine now returns 0.0 when input slice lengths differ; is_question switches from substring matching to word-boundary detection via a new helper; and Grasp::forget uses a new escape_like function to safely build an anchored SQL LIKE prefix for processed_files deletion.

Changes

Correctness Fixes

Layer / File(s) Summary
Cosine similarity dimension guard
crates/grasp-core/src/embed.rs
cosine returns 0.0 when slice lengths differ instead of silently truncating; test added for mismatch and identical-vector cases.
Word-boundary keyword detection
crates/grasp-core/src/extractor.rs
is_question uses new contains_at_word_boundary helper instead of str::contains; test asserts true positives and rejects embedded substrings like "somewhat".
escape_like helper and anchored forget deletion
crates/grasp-core/src/lib.rs
New escape_like escapes %, _, and backslashes for SQL LIKE; Grasp::forget now builds a project-directory prefix and deletes only matching processed_files rows using ESCAPE '\\', with unit tests for the helper.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 A cosine that slipped on unequal feet,
A keyword that hid in words incomplete,
A wildcard that wandered where it shouldn't roam—
The rabbit patched each, and brought the code home.
Now tests stand guard so bugs dare not repeat! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the three core correctness fixes in grasp-core and matches the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch worktree-code-review-fixes

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/grasp-core/src/lib.rs`:
- Around line 185-195: The `processed_files` cleanup is rebuilding the deletion
prefix from `config.claude_projects_dir`, which misses imports created from a
custom project path. Update the cleanup logic in this import flow to use the
actual stored project/file path that was inserted into
`processed_files.file_path` (the same `file.to_string_lossy()`-based value)
instead of reconstructing it from the configured projects dir. Keep the existing
`LIKE`/`escape_like` approach, but base the prefix on the real path associated
with the imported project so stale rows are removed correctly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 45ef2a02-c9a9-4112-bd0c-8632f987d06c

📥 Commits

Reviewing files that changed from the base of the PR and between 28ab11a and 5b20c97.

📒 Files selected for processing (3)
  • crates/grasp-core/src/embed.rs
  • crates/grasp-core/src/extractor.rs
  • crates/grasp-core/src/lib.rs

Comment thread crates/grasp-core/src/lib.rs Outdated
Addresses CodeRabbit's Major finding on PR #25. The processed_files cleanup
rebuilt its prefix from claude_projects_dir, which misses transcripts imported
from a custom path (`grasp import --path …`) — their processed_files rows live
outside claude_projects_dir, so forgetting such a project left stale rows and
re-imports were wrongly skipped.

Now read projects.path (the real import directory recorded at import time)
before deleting the project row, and use it as the LIKE prefix base, falling
back to claude_projects_dir.join(slug) when no row exists.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@krishpinto
krishpinto merged commit 53422dc into main Jun 30, 2026
3 checks passed
@krishpinto
krishpinto deleted the worktree-code-review-fixes branch June 30, 2026 14:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant