Commit Graph

3 Commits

Author SHA1 Message Date
Daniel Zivkovic 0a5102e193 fix(youtube): surface transcript-fetch ratio in footer + add degraded nudge
When yt-dlp is installed but stale (or otherwise unable to fetch transcripts
for any returned videos), runs previously reported YouTube as fully
successful in two user-facing surfaces:

  1. Footer (render.py): showed "N videos | M views" with no indication
     that zero transcripts were captured. The "with transcripts" segment
     was conditionally suppressed when the count was zero - converting
     the canonical stale-binary failure mode into a silent absence at
     the very surface users read for "did this work?".

  2. Quality nudge (quality_nudge.py): classified YouTube as "active"
     based purely on yt-dlp installation + absence of a top-level error.
     Per-video transcript-fetch ratio was never inspected. A run that
     returned N videos with 0 transcripts (canonical stale-binary
     failure) was reported as fully active.

The engine itself logs the failure correctly at default stderr level
(`[YouTube] Got transcripts for 0/N videos (N failed)`), but that line
gets buried in 100+ lines of parallel-source progress output and is
contradicted by the success-shaped footer and nudge that follow.

This change makes both conclusion surfaces honest:

* render.py footer always renders "M/N with transcripts" so the ratio
  is visible regardless of value. Zero is no longer hidden. Format is
  M/N (not bare M) so the denominator is in the message and the user
  does not have to cross-reference the "videos" count.

* quality_nudge.py adds a third tier between "active" and "missing":
  "degraded". Triggered when yt-dlp is installed AND videos were
  returned AND transcript-fetch ratio is below threshold (default 50%,
  tunable via DEGRADED_TRANSCRIPT_THRESHOLD env var). Emits an
  actionable nudge: "YouTube returned N videos but only M transcripts
  captured. The most common cause is a stale yt-dlp binary - YouTube's
  caption format changes frequently and old binaries silently fail
  every transcript. Update via your package manager: scoop update
  yt-dlp (Windows), brew upgrade yt-dlp (macOS), or pip install -U
  yt-dlp."

* last30days.py populates youtube_videos_count and
  youtube_transcripts_count in the research_results dict it passes to
  compute_quality_score, enabling the new degraded check at the call
  site.

Threshold rationale: 50% accommodates a few legitimate
caption-disabled videos in a multi-video result, but a stale-binary
run that fails every transcript trips the nudge cleanly.

Score impact: degradation is informational, not score-affecting.
YouTube still counts as "active" in score_pct so users do not see
their score drop for a fixable client-side issue. The nudge directs
them to their own package manager.

Tests:

* tests/test_quality_nudge.py: 6 new TestYouTubeDegraded cases cover
  zero-transcripts-flags-degraded, partial-above-threshold-does-not-flag,
  zero-videos-does-not-flag (no false positives on absence),
  one-of-three-flags-degraded, threshold-tunable-via-config, and
  degraded-does-not-affect-score.

* tests/test_render_v3.py: 4 new YoutubeFooterTranscriptRatioTests
  cases cover zero-transcripts-with-videos-renders-zero-over-total
  (the regression repro), partial-renders-ratio, full-renders-ratio,
  and no-videos-suppresses-entire-segment.

All 29 new test cases verified GREEN with the fix and RED without it
(temp-reverted both files separately to confirm each test catches the
specific regression it asserts).

Integration validation: ran the engine against an intentionally stale
yt-dlp 2025.03.31 binary placed first on PATH. Pre-fix the footer
showed `YouTube: 3 videos | 386,815 views` (no transcript signal).
Post-fix the footer shows `YouTube: 3 videos | 386,815 views | 0/3
with transcripts` and stderr emits "Degraded: YouTube" plus the
actionable update-yt-dlp nudge.

Out of scope (deserves its own PR): exposing transcripts_captured in
the EVIDENCE FOR SYNTHESIS block so the synthesizing model can flag
degradation in prose. Larger schema-touching change.
2026-05-17 00:13:56 -07:00
Matt Van Horn 0a9ff16dfc feat: v3.0.0 - intelligent search, GitHub person/project mode, ELI5, 13+ sources
v3 rewrites the search engine from the ground up:

- Intelligent pre-research: resolves X handles, GitHub repos, subreddits,
  TikTok hashtags, and YouTube channels before searching
- GitHub person-mode: PR velocity, top repos by stars, release notes
- GitHub project-mode: live star counts, README, releases, top issues
- ELI5 mode: plain language synthesis, no jargon
- 13+ sources: Reddit, X, YouTube, TikTok, Instagram, HN, Polymarket,
  GitHub, Threads, Pinterest, Perplexity, Bluesky, Web
- Free Reddit comments via public JSON (no API key needed)
- Fun judge v2: humor scoring baked into narrative
- Cookie consent before browser scanning
- 10,000 free ScrapeCreators calls
- 1,012 tests

Thank you to the community contributors whose issues and PRs shaped v3:
@uppinote20 (#143), @zerone0x (#134, #136), @thinkun (#116),
@thomasmktong (#124), @fanispoulinakisai-boop (#100), @pejmanjohn (#78),
@zl190 (#115), @hnshah (#84, #85, #86)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 10:52:23 -07:00
Matt Van Horn 775596ce21 feat: v2.9.6 — free-first NUX, cookie extraction, quality scoring
Setup wizard with consent-first cookie extraction (Chrome/Firefox/Safari),
yt-dlp auto-install, ScrapeCreators push, quality scoring (5 core sources),
status banner redesign, honest Reddit labeling, inline YouTube transcripts,
Exa free web search, Reddit public fallback, and post-research quality nudge.

Co-authored-by: Matt Van Horn <mvanhorn@MacBook-Pro.local>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 14:33:17 -07:00