Match video title in search, not just transcript (#89) - #115
Conversation
searchVideos() queried only video_segments_fts (chapter title + transcript), so a query word that lives only in the human-curated title was unmatchable — "changelog" is never spoken in narration, so "RouterOS 7.23 changelog - VRF offloading…" ranked #15 on `changelog 7.23 routeros`, below the display cutoff. It now also consults the already-trigger-maintained videos_fts (title + description; no schema change), ranking strong-before-weak: title-AND, transcript-AND, then the OR fallbacks in the same order, deduped by video. On the live corpus the target video moves #15 -> #1, and `changelog 7.NN routeros` resolves to the matching release video. Scoped to the FTS match surface only: the shared extractTerms/stop-word handling that shreds dotted versions (7.23 -> 7,23) and drops "routeros" is left untouched — RouterOS version strings as first-class query tokens across routeros_search is separate, broader work. Closes #89 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📜 Recent review details🧰 Additional context used📓 Path-based instructions (7)**/*.{ts,tsx}📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
src/**/*.{ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{ts,tsx,md}📄 CodeRabbit inference engine (AGENTS.md)
Files:
*📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
**/*.md📄 CodeRabbit inference engine (CLAUDE.md)
Files:
CHANGELOG.md📄 CodeRabbit inference engine (CLAUDE.md)
Files:
src/{query,mcp,browse}.ts📄 CodeRabbit inference engine (AGENTS.md)
Files:
🔇 Additional comments (3)
📝 WalkthroughWalkthrough
ChangesVideo search
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
Suggested labels: Sequence Diagram(s)sequenceDiagram
participant SearchVideos
participant TitleFTS
participant TranscriptFTS
SearchVideos->>TitleFTS: Query title and description
TitleFTS-->>SearchVideos: Ranked title results
SearchVideos->>TranscriptFTS: Query transcript segments
TranscriptFTS-->>SearchVideos: Best segment per video with excerpts
SearchVideos->>SearchVideos: Deduplicate video_id and apply limit
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Pull request overview
Improves Rosetta’s video search retrieval so queries can match against video titles/descriptions (via the existing videos_fts) in addition to transcript segments, addressing the ranking gap described in issue #89.
Changes:
- Update
searchVideos()to query bothvideos_ftsandvideo_segments_fts, merging results in a strong-before-weak order with per-video deduping. - Add an integration test proving a title-only keyword (e.g., “changelog”) surfaces the expected video even when the transcript never contains that term.
- Document the user-visible behavior change under
[Unreleased]inCHANGELOG.md.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/query.ts | Adds title/description FTS querying to searchVideos() and merges results with dedupe/ordering. |
| src/query.test.ts | Adds a fixture + test asserting title-only hits are surfaced for issue #89. |
| CHANGELOG.md | Records the user-visible fix for video search title matching. |
…arch # Conflicts: # CHANGELOG.md
Codex ReviewNot ready to merge yet. The implementation works, but I found one code correctness issue and one mandatory project-process issue.
Everything else looks healthy:
|
searchVideos() limited transcript rows before the caller deduped them by video, so a video with several matching segments consumed the top-`limit` rows and hid distinct videos ranked just below the cutoff — "firewall filter" returned 8 unique videos of 10 while limit 20 found 15. runVideosFtsQuery now picks the best-ranked segment PER VIDEO before applying LIMIT. fts5 snippet() can't run alongside a window function, so it's two bounded steps: a ROW_NUMBER() window query selects one segment per video ordered by rank, then a second MATCH fetches excerpts for just those rowids. Live DB: "firewall filter"/"vlan bridge" now fill 10/10 unique at limit 10; changelog target stays #1. Adds a dedup regression test (one video with 3 matching segments must not crowd out another). Also switches the videos_fts excerpt to snippet(..., -1, ...) so it reflects whichever column (title or description) matched. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Both Codex findings addressed in 1. Under-fill after dedup (correctness). Confirmed and fixed. The root cause was intra-source: 2. Issue-linking (process). Verification after both fixes: |
|
@coderabbitai we hit a review limit. do a review of the PR as it stands now. |
|
✅ Action performedReview finished.
|
The 0.11.0 low-hanging slice of #89, per the scope split on the issue.
Problem
searchVideos()matched onlyvideo_segments_fts(chapter title + transcript). Words that live only in the video title — "changelog" is never spoken in the narration — were unmatchable, so "RouterOS 7.23 changelog — VRF offloading, DoH with HTTP/2, …" ranked #15 onchangelog 7.23 routeros, below every display cutoff, even though the video was correctly extracted.Fix — the title into the FTS match surface (no schema change)
videos_fts(FTS5 overtitle+description) already exists and is trigger-maintained;searchVideos()just never consulted it. It now queries both indexes and merges strong-before-weak:videos_fts), then transcript-AND (video_segments_fts)Deduped by video, capped at
limit. A title-only hit borrows the video's first segment forchapter_title/start_s(LEFT JOIN, so a transcript-less video still returns) and its excerpt is a snippet of the matched title/description — so the result shape is identical to a transcript hit.Title-AND leads because the title is the curated summary; a query word found only there is a strong relevance signal. Existing anchors are unaffected: they're multi-term AND queries the short titles don't fully satisfy, so title-AND returns nothing and the prior transcript behavior stands.
Explicitly out of scope (deferred, broader effort)
The shared
extractTerms/STOP_WORDSchanges — preserving dotted versions (7.23→ one token instead of7,23) and reconsideringrouterosas a stop word — are not touched here. They live on the page-search path too, so they move the golden/eval baseline, and "RouterOS version strings as first-class query tokens acrossrouteros_search" deserves a deliberate design pass rather than a video-search bolt-on. The fix works today regardless: unicode61 already splits the title's7.23into7/23, so title-AND(changelog,23) matches.Verification
ros-help.db, rc.102): target8X0Aewng-BMmoves npm prerelease dist-tag channel (alpha/beta/rc/next) + coverage reporting #15 → Add SafeSkill security badge (73/100 — Passes with Notes) #1 onchangelog 7.23 routeros;changelog 7.22 routeros→ the 7.22 changelog video Add SafeSkill security badge (73/100 — Passes with Notes) #1;vlan bridgestill returns VLAN videos first (no obvious regression).src/query.test.ts): a changelog-titled fixture whose transcript never says "changelog" now surfaces Add SafeSkill security badge (73/100 — Passes with Notes) #1, with the excerpt proving the hit came from the title.bun test899 pass / 0 fail; typecheck + biome + markdownlint clean.Issue linking
Closes #89 — the video-title match slice is delivered here.
The deferred remainder (dotted-version tokenization +
routerosstop-word handling across the shared query path) is split into follow-up #116 per the mandatory partial-landing rule, carrying over #89's un-done acceptance bullets.Summary by CodeRabbit