Skip to content
Merged
1 change: 1 addition & 0 deletions AGENTS.develop.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ Never `unwrap_or_default()` a store error on a search path — "no results" and

## Changelog highlights (recent)

- **v1.5.33 (pending)** — FTS commit-failure hardening: per-file transient redrive, crash-safe vector rollback, mixed-generation sweep in refresh, stale note on get_chunk
- **v1.5.33 (pending)** — `.codesearchinclude` whitelist: when present (repo root or `~/.codesearch/`), only matching files are indexed; ignore rules still win, absent list = historical behavior
- **v1.5.33 (pending)** — MCP tools declare `readOnlyHint` annotations: Claude Code plan mode auto-allows all six tools instead of prompting every call
- **v1.5.33 (pending)** — force reindex (`n`, `index -f`) rebuilds the SCIP symbol indexes too — shared `finish_force_reindex` tail for HTTP + TUI; `?symbols=true` stays symbol-only, plain reindex stays gate-driven
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ finalized in place with a date — no renaming/migration step needed.

### Fixed

- **A failed FTS commit no longer leaves the index in mixed generations.** On Windows an indexer/AV filter holding a freshly created tantivy segment file makes the FTS commit fail (os error 5) and the writer is discarded by design — but the per-file incremental paths inserted the new chunks into the vector store first with no rollback, so the failed attempt's ids were orphaned (never in file_meta) while the tracked generation was already deleted: search (FTS) and get_chunk (vector) then disagreed and stale lines kept coming back (the HUSQ.Aprimo worktree symptom). Three layers now: the per-file paths redrive on the transient race like force reindex already did; a failed publish rolls the fresh chunk ids back out of both stores (file_meta stays old, so the next pass heals clean); and the refresh sweep deletes untracked vector chunks and re-indexes live files whose tracked ids went missing, so already-corrupted indexes heal on the next refresh without a force reindex. get_chunk also warns when the source file is newer than the last indexing write. The fts/ subdir is now marked hidden on Windows too.

- **MCP tools now declare `readOnlyHint` annotations, so Claude Code plan mode auto-allows them.** None of the six tools (`search`, `find`, `explore`, `get_chunk`, `status`, `find_impact`) set rmcp `annotations`, and plan mode only auto-allows MCP tools that declare `readOnlyHint: true` — every codesearch call in plan mode was blocked or prompted (in `-p` mode it failed outright), in the main session and in subagents alike. All six are read-only index queries; they now declare `read_only_hint = true, destructive_hint = false, idempotent_hint = true, open_world_hint = false`, and the 6-tool registration test pins the hint so a future tool cannot ship without it.

- **A force reindex now rebuilds the SCIP symbol indexes too.** `n` in the serve TUI and `codesearch index -f` promised "rebuild everything" but dated from before the symbol indexes existed: the HTTP handler forced the symbol pass only behind the separate `?symbols=true` flag (so a fresh SCIP gate — no `.cs` changes — skipped it), and the TUI's force reindex never ran a symbol pass at all. Field effect: after Razor joined the text index, `find_impact` kept answering from ~19-hour-old references. Force now implies symbols (`finish_force_reindex` is the shared tail of the HTTP and TUI force paths: fresh FSW, then a forced, gate-bypassing symbol pass); `?symbols=true` stays the explicit no-force symbol-only trigger, and a plain reindex stays gate-driven. Local CLI builds (`index -f --local` / delegation failure) still build no symbols — serve owns the symbol pipeline there.
Expand Down
8 changes: 8 additions & 0 deletions src/cache/file_meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,14 @@ impl FileMetaStore {
self.files.remove(&path_str)
}

/// Non-destructive per-file chunk-id lookup — unlike [`Self::remove_file`],
/// which clears the entry as a side effect. Same key normalization.
pub fn file_chunk_ids(&self, key: &str) -> Option<Vec<u32>> {
self.files
.get(&normalize_path_str(key))
.map(|m| m.chunk_ids.clone())
}

/// Re-key entries still filed under an absolute path inside `project_root`
/// (the pre-relative-key format) to their project-relative storage key.
///
Expand Down
Loading
Loading