feat: tier 3 polish — indexing status surfaces + citation reliability #2
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feature/tier3-polish"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Two Tier 3 polish slices on one branch.
Indexing status surfaces (Slice A):
last_index_event: Arc<std::sync::Mutex<Option<IndexEvent>>>latched onAppState; updated bysend_event, cleared byrotate_index_cancel.GET /index/statereturns the latched event (or 204).IndexerProviderfetches it on mount / vault switch — webview reload mid-indexing now resumes the live phase instead of dropping to idle.VaultsRightgains a one-line index strip;NavRailgains an amber-pulse / red-dot badge on the Indexer item (visible from any section).Citation reliability (Slice B):
/notes/lookupresolves each title via three strategies: case-insensitive exact title → FTS5title:"..."phrase →LIKE %term%. Each hit carriesmatch_quality∈ {exact, fts, like} andquery(the original wikilink target, so fuzzy hits resolve back to the user input).Vec<note>to{ notes: [...], unresolved: [...] }. Missing titles surface as syntheticFileReferences withmatchQuality: "missing".Wikilinkrenders three states: clean (exact), dashed-fuzzy (FTS/LIKE, with "Closest match" hint), strike-through-missing (broken,aria-disabled,cursor: not-allowed).useChatnow splits[[Note|Alias]]and only looks up the target half.Spec'd
citation_warningSSE event folded into the lookup response — the existing post-streamlookupNotescall carries the same info. Rationale in the plan.Implementation plan:
docs/superpowers/plans/2026-05-18-tier3-polish.md.Test plan
Three-tier resolver per title: 1. case-insensitive exact title match -> match_quality: "exact" 2. FTS5 title-column phrase match -> match_quality: "fts" 3. LIKE %term% fallback -> match_quality: "like" Response shape: { notes: [...], unresolved: [...] }. Each note carries `match_quality` AND `query` (the original input title) so the frontend Wikilink component can match by user input rather than by resolved DB filename. Misses go in `unresolved`. note_row uses rusqlite .optional() so only QueryReturnedNoRows becomes None — real errors propagate as AppError::Internal instead of being silently swallowed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>Resolution order: query-based match first (canonical, works for any match_quality), filename match as legacy backstop, then missing placeholder match. Renders three states: - exact : unchanged - fuzzy : dashed border + amber icon + "Closest match: ..." title - missing : strikethrough, muted, cursor not-allowed, no preview / Obsidian handoff; aria-disabled for screen readers Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>