Skip to content

fix: route every transcript client through the centralized proxy (#1087) - #1129

Closed
groupthinking wants to merge 3 commits into
mainfrom
fix/centralized-transcript-proxy-1087
Closed

fix: route every transcript client through the centralized proxy (#1087)#1129
groupthinking wants to merge 3 commits into
mainfrom
fix/centralized-transcript-proxy-1087

Conversation

@groupthinking

@groupthinking groupthinking commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Canonical issue

Closes #1087

#1087 asks for three things: (a) migrate transcript calls to the
youtube-transcript-api v1.x instance API, (b) add centralized outbound proxy
handling
, and (c) redact credentials from logs.

Only (b) was outstanding, and only partially — the helper existed but six
call sites never used it. Evidence for the other two on origin/main:

Part State on main Evidence
(a) v1.x instance API done (#496) grep -rn "YouTubeTranscriptApi\.\(get_transcript|get_transcripts|list_transcripts\)"0 hits. Live surface is instance-only: .fetch / .list / .to_raw_data(). Floor pinned youtube-transcript-api>=1.0.0 in pyproject.toml:109 and requirements.txt:63.
(b) centralized proxy gap — fixed here 6 of 14 constructions omitted proxy_config (table below).
(c) redacted logging present; hardening in flight redact_proxy_credentials lives in src/youtube_extension/utils/proxy.py:70; #1118 (which targets issue 1113) generalises it. Deliberately not touched here to keep the PRs disjoint.

Outcome

youtube-transcript-api >= 1.0 only honours a proxy when a proxy_config is
passed to the constructor. A bare YouTubeTranscriptApi() egresses from the
host's own IP regardless of WEBSHARE_PROXY_URL. Six call sites did exactly
that, so the "centralized" proxy was silently bypassed on those paths — and
because the fallback paths are the ones that run after YouTube starts blocking,
these were the calls that most needed the proxy.

File:line Call Note
src/integration/youtube_api.py:99 .fetch(video_id, languages=…) primary transcript fetch for the integration client
src/agents/process_video_with_mcp.py:222 .fetch(video_id) inside _extract_transcript_with_rotation
src/agents/process_video_with_mcp.py:233 .list(video_id) same method's fallback
src/agents/interactive_metadata_extractor.py:87 .fetch(video_id)
src/mcp/mcp_video_processor.py:694 .fetch(…) _direct_extraction
src/mcp/mcp_video_processor.py:718 .list(video_id) _routed_extraction

The method name _extract_transcript_with_rotation states the intent that the
code did not implement.

Each site now resolves its config from the canonical helper
youtube_extension.utils.proxy.get_transcript_proxy_config(), wrapped in the
guarded-import pattern this repo already uses in
src/agents/gemini_video_master_agent.py:59-66, so these modules stay importable
when executed outside the package. No behaviour change when no proxy is
configured
— the helper returns None, which is what the constructor
defaulted to before.

Regression guard

tests/unit/test_transcript_proxy_coverage.py (11 tests) walks the AST of every
.py under src/ and shared/ and fails if any YouTubeTranscriptApi(...)
construction omits proxy_config. Reviewing this by eye does not scale to 14
call sites across 6 modules, and the failure mode is silent.

It also carries an explicit anti-vacuity canary
(test_guard_finds_the_client_at_all): if the client is renamed upstream or the
scan roots stop resolving, the guard fails instead of passing over an empty
set. This repo has repeatedly shipped checks that never actually check
(#1116, #1121, #1091); this one is built not to.

Risk

  • Low. No control flow changed; one keyword argument added per call site.
  • When WEBSHARE_PROXY_URL is unset the helper returns None — byte-identical
    behaviour to the previous bare constructor.
  • The guarded import cannot break module loading: on ImportError it defines a
    local stub returning None.
  • The AST guard scans src/ and shared/ only. Tests may still construct bare
    clients against stubs — intentional.
  • Not fixed here: the credential-redaction hardening tracked in issue 1113 (owned by
    fix(security): stop proxy credentials leaking from subprocess errors #1118). Kept disjoint so neither PR blocks the other.

Verification

All commands run at 5659f2b9c.

Suite: pytest tests/unit/test_transcript_proxy_coverage.py21 passed.

Coverage of the fix: grep -rn "YouTubeTranscriptApi(" src/ shared/ → 14
constructions, 14 pass proxy_config, 0 bare.

Mutation testing — the guard is worthless if it cannot fail. Each mutation
was applied, the suite run, then reverted; every one is killed:

# Mutation Result
M1 Revert one fix (mcp_video_processor.py:701) 1 failed
M2 Strip proxy_config from a pre-existing correct site (robust.py:454) 1 failed
M3 Replace helper call with literal proxy_config=None 1 failed
M4 Break SOURCE_ROOTS so the scan matches nothing 1 failed (canary)
M5 Rename CLIENT_NAME (simulates upstream rename) 1 failed (canary)
M6 Module stops importing the canonical helper 1 failed
M7 Helper drops the configured URL (GenericProxyConfig("","")) 1 failed
M8 Helper always returns None (the exact production bug) 1 failed
M9 Restore the silent stub the review flagged 1 failed
M10 Bootstrap depth wrong (parents[1]parents[0]) 1 failed
M11 Restore the silent skip of a missing source root 1 failed

Baseline and post-revert state: 21 passed each time.

M7/M8 target the helper rather than the call sites, which closes the loop: the
structural test proves every site passes proxy_config=<helper>(), and
test_proxy_helper_returns_config_carrying_the_url_when_set proves the helper
returns a config actually carrying the URL. Together they establish that every
site is genuinely proxied, not merely syntactically compliant. That test stubs
youtube_transcript_api.proxies, so it holds without the optional extra
installed.

Unplanned real-world validation: mid-review a stray git checkout -- reverted
all four source files. The guard caught it immediately and named every site:

AssertionError: 6 YouTubeTranscriptApi(...) construction(s) omit 'proxy_config='
and will bypass the centralized proxy:
    src/agents/interactive_metadata_extractor.py:87
    src/agents/process_video_with_mcp.py:233
    src/agents/process_video_with_mcp.py:222
    ...

No regressions. Test collection over tests/unit, measured against a clean
origin/main worktree with the same interpreter:

tests collected collection errors
origin/main 4023 75
this branch 4044 75

+21 is exactly this PR's new tests; the 75 errors are pre-existing
(missing optional deps) and unchanged. The two failures in files that import
the changed modules (tests/utilities/process_video_with_mcp.py, missing
aiohttp; test_security_agent_distinguishes_eval_from_literal_eval) reproduce
byte-identically on the clean origin/main worktree.

Lint held at baseline. ruff check on the four changed files: 25 before,
25 after
— no new findings. black --check --diff per file, this branch vs
origin/main:

File main this branch
youtube_api.py 43 41
interactive_metadata_extractor.py 328 328
process_video_with_mcp.py 163 163
mcp_video_processor.py 0 0

Measured as changed lines (grep -c '^[+-][^+-]'), not hunks — hunk counts are an
unstable metric here, since inserting a line can split one existing mega-hunk into
two and report a regression with zero new unformatted code.

Those files were never black-formatted; this PR does not add drift and does not
reformat unrelated lines. The new test file is clean under both black and
ruff.

Compile check: python -m py_compile passes on all four modified modules.

Review remediation

Review found the guarded import this branch introduced was itself a silent
bypass, and it was right. When these modules are executed by path — the
documented CLI entry point — youtube_extension is not importable, so the
fallback stub returned None and proxy_config=get_transcript_proxy_config()
egressed from the host IP. The call site still read as proxied, which is
exactly the failure mode this PR exists to eliminate.

All four modules now bootstrap src onto sys.path and re-attempt the
canonical helper, raising ImportError if it is still unreachable. The proxy is
either honoured or the module refuses to load. Bootstrapping is safe: proxy.py
is stdlib-only apart from a guarded youtube_transcript_api.proxies import, and
its package __init__ chain pulls only re and typing — verified by importing
it from /tmp with no PYTHONPATH.

The guard suite was hardened against three ways it could pass while protecting
less than it claimed:

  • a missing configured source root was skipped silently
  • SOURCE_ROOTS could be narrowed by hand with every other test still green, so
    the required roots are now rediscovered by AST-scanning the repository for
    YouTubeTranscriptApi constructions
  • referencing the helper was satisfied by the call site alone, so a broken import
    passed; every ImportFrom targeting the proxy module must now bind the helper

Two of the tests added in this round were themselves vacuous and were caught only
by mutation, which is the honest headline here:

  1. the bootstrap-depth test computed parents[1] from a test-side constant, so
    mutating the source's index changed nothing it observed. It now parses the
    index out of the source AST, scoped to the sys.path.insert call node —
    necessary because process_video_with_mcp.py contains an unrelated
    pre-existing parents[2].
  2. the helper-reference test asserted PROXY_HELPER in source, which the call
    site satisfies on its own.

The repo-wide scan is AST-based rather than grep-based for a concrete reason:
scripts/skill_builder.py contains YouTubeTranscriptApi(...) inside a string
literal, which grep would report as an unproxied egress path. It is fail-loud on
unparseable files rather than best-effort — all 662 non-excluded files parse today.

Production evidence

  • Failure being removed: with WEBSHARE_PROXY_URL set, the six listed call
    sites connected to YouTube from the pod's own IP. On the paths that matter
    most — the .list() fallbacks reached only after a primary fetch fails, i.e.
    when YouTube is already rate-limiting — this produced IpBlocked /
    TooManyRequests that the proxy existed specifically to prevent.
  • After: all 14 constructions in src/ and shared/ route through
    get_transcript_proxy_config().
  • Deployments without a proxy are unaffected: the helper returns None when
    WEBSHARE_PROXY_URL is unset, asserted by
    test_proxy_helper_returns_none_without_configuration.
  • Durability: the AST guard fails CI on any future bare construction, so
    this class of regression cannot silently return.

youtube-transcript-api >=1.0 only honours a proxy when a ``proxy_config``
is passed to the constructor. Six call sites across four modules built a
bare ``YouTubeTranscriptApi()``, so they egressed from the host's own IP
and bypassed WEBSHARE_PROXY_URL entirely — including
``_extract_transcript_with_rotation``, whose name implies the opposite.

- src/integration/youtube_api.py:99
- src/agents/process_video_with_mcp.py:222,233
- src/agents/interactive_metadata_extractor.py:87
- src/mcp/mcp_video_processor.py:694,718

Each now resolves its config from the canonical
``youtube_extension.utils.proxy.get_transcript_proxy_config`` helper,
guarded by the import fallback this repo already uses in
gemini_video_master_agent.py so modules stay importable outside the
package. The helper returns None when no proxy is configured, so direct
connections keep working unchanged.

Adds tests/unit/test_transcript_proxy_coverage.py: an AST walk over src/
and shared/ that fails if any construction omits proxy_config, plus a
canary that fails if the scan ever matches nothing (the vacuity mode that
has bitten this repo repeatedly).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 31, 2026 06:11
@vercel

vercel Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
v0-uvai Canceled Canceled Jul 31, 2026 8:09am

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • tests/unit/test_transcript_proxy_coverage.py is excluded by !tests/**

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 61f8508c-d943-41df-bfa9-ea7042492975

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • Improved reliability when retrieving YouTube transcripts by routing requests through the configured proxy.
    • Added clear errors when the required transcript proxy configuration is unavailable.
    • Improved transcript retrieval when running supported tools directly from the command line.

Walkthrough

The change centralizes proxy configuration for YouTube transcript clients. Four transcript modules support standalone imports, fail fast when the helper is unavailable, and pass the proxy configuration to direct, routed, and transcript-list requests.

Changes

Transcript proxy enforcement

Layer / File(s) Summary
Load and validate proxy configuration
src/agents/interactive_metadata_extractor.py, src/agents/process_video_with_mcp.py, src/integration/youtube_api.py, src/mcp/mcp_video_processor.py
The modules load get_transcript_proxy_config, bootstrap standalone imports through src, and raise ImportError when loading fails.
Configure transcript API clients
src/agents/interactive_metadata_extractor.py, src/agents/process_video_with_mcp.py, src/integration/youtube_api.py, src/mcp/mcp_video_processor.py
YouTube transcript clients now receive the proxy configuration for direct, routed, and transcript-list retrieval.
Estimated code review effort: 3 (Moderate) ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TranscriptProcessor
  participant ProxyConfig
  participant YouTubeTranscriptApi
  TranscriptProcessor->>ProxyConfig: load get_transcript_proxy_config()
  ProxyConfig-->>TranscriptProcessor: return proxy settings
  TranscriptProcessor->>YouTubeTranscriptApi: construct client with proxy settings
  YouTubeTranscriptApi-->>TranscriptProcessor: fetch transcript data
Loading

Possibly related PRs

  • groupthinking/EventRelay#496: Both changes update the same YouTube transcript call sites. This change adds proxy configuration to those clients.

Suggested labels: architecture-gap

Poem

Proxies guide the transcript stream,
Clients now follow one clear scheme.
Missing helpers stop the run,
Standalone paths still find the sun.
YouTube calls now route with care.

🚥 Pre-merge checks | ✅ 5 | ❌ 2

❌ Failed checks (2 inconclusive)

Check name Status Explanation Resolution
Enforce Copilot Verification ❓ Inconclusive Evidence gathering in progress. Need verify the pull request's GitHub Copilot review and approval status from repository or pull-request metadata.
Require Ai Unit Tests ❓ Inconclusive Initial evidence is not yet collected for the required label or test commitment. Inspect the current checkout and connected pull-request metadata for the copilot-rabbit label and test-file changes.
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR completes the outstanding centralized proxy requirement for issue #1087; v1.x migration and existing redaction support are explicitly documented as already addressed.
Out of Scope Changes check ✅ Passed The source and test changes directly support proxy enforcement, fail-closed helper loading, and regression prevention for issue #1087.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title clearly summarizes the main change: routing every transcript client through the centralized proxy.
Description check ✅ Passed The description clearly covers the issue, outcome, scope, risk, verification, production evidence, exclusions, and review remediation.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Fix failing CI checks
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/centralized-transcript-proxy-1087
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/centralized-transcript-proxy-1087

Warning

Review ran into problems

🔥 Problems

These MCP integrations need to be re-authenticated in the Integrations settings: Sentry


Linked repositories: Public OSS repositories can only analyze public repositories installed in this organization. No linked repositories were analyzed; skipped groupthinking/uvai-skills.


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.

❤️ Share

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

@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA 49e887c.
Ensure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice.

Scanned Files

None

@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown

Agent Completion Truth Gate: NOT_APPLICABLE

Evidence agrees.

Machine-readable verdict
{
  "details": {},
  "reasons": [],
  "verdict": "not_applicable"
}

Workflow evidence

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Not ready to approve

Standalone CLIs can still bypass configured proxies, and the regression guard accepts several noncompliant constructions.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Pull request overview

Routes remaining transcript clients through the centralized outbound proxy and adds an AST-based regression guard.

Changes:

  • Passes canonical proxy configuration to six transcript client constructions.
  • Adds repository-wide proxy coverage tests and helper validation.
File summaries
File Description
src/integration/youtube_api.py Proxies transcript fetching.
src/agents/process_video_with_mcp.py Proxies primary and fallback extraction.
src/agents/interactive_metadata_extractor.py Proxies metadata transcript extraction.
src/mcp/mcp_video_processor.py Proxies direct and routed extraction.
tests/unit/test_transcript_proxy_coverage.py Adds structural regression guards.
Review details

Suppressed comments (2)

tests/unit/test_transcript_proxy_coverage.py:159

  • This only proves that the helper's name occurs somewhere in the module and rejects literal None; a constructor using proxy_config=custom_config, object(), or another noncanonical value still passes. That contradicts this test's stated guarantee that each caller sources the argument from the canonical helper. Inspect each proxy_config AST value and require a call to get_transcript_proxy_config().
    assert PROXY_HELPER in source, (
        f"{module_path} constructs {CLIENT_NAME} but never references "
        f"{PROXY_HELPER}; proxy_config is likely hardcoded."
    )

tests/unit/test_transcript_proxy_coverage.py:73

  • Treating any **kwargs as compliant leaves the new guard open to exactly the silent bypass it is meant to prevent: YouTubeTranscriptApi(**{}) (or a mapping without proxy_config) passes this check while egressing directly. Require an explicit proxy_config= keyword; callers using a mapping can still spell that argument out alongside **kwargs.
        # ``**kwargs`` — the keyword may be supplied dynamically; treat the
        # call as opaque rather than reporting a false positive.
        if keyword.arg is None:
            return True
  • Files reviewed: 5/5 changed files
  • Comments generated: 3
  • Review effort level: Balanced

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

Comment thread src/agents/interactive_metadata_extractor.py Outdated
Comment thread src/agents/process_video_with_mcp.py Outdated
Comment thread tests/unit/test_transcript_proxy_coverage.py Outdated
@groupthinking
groupthinking marked this pull request as draft July 31, 2026 06:17

Copy link
Copy Markdown
Owner Author

Automated remediation pass — adjudication of the open Copilot review

I verified Copilot's two "🟡 not ready to approve" findings against the guard source at b6f4cf3fd. Both are valid, but both are latent — no current call site hits either — so neither blocks the production fix. The six call sites do pass proxy_config=get_transcript_proxy_config(), and pytest tests/unit/test_transcript_proxy_coverage.py is green. They're gaps in the durability net (this PR's stated value), so worth a short follow-up if you want it airtight:

  1. _has_required_keyword (line ~73)if keyword.arg is None: return True treats any **kwargs unpack as compliant, so a future YouTubeTranscriptApi(**opts) with no proxy_config key would pass the guard while egressing direct. Requiring an explicit proxy_config= keyword closes it; no current site uses **kwargs, so tightening it won't create false positives today.
  2. test_module_resolves_proxy_config_from_the_canonical_helper (line ~159)assert PROXY_HELPER in source only proves the helper name appears somewhere in the file; it doesn't bind each construction's proxy_config= value to a get_transcript_proxy_config() call, so proxy_config=other_config (or the name in a comment) would pass. Inspecting each call's proxy_config AST value and requiring it be a Call to the helper closes it.

Other state at b6f4cf3fd:

  • Core code CI is green: CI, CodeQL Analysis, Security Scan, Secret Scan, Dependency Review, PR Checks all ✅.
  • mergeable_state: unstable traces to meta/governance workflows still settling or flapping across re-runs (Agent completion enforcement, PR Governance, branch-cleanup.yml) — not code-test failures. The agent-completion/truth-gate/pr-1129 status resolved to not_applicable / all rules passed.
  • CodeRabbit auto-skipped this PR ("Review skipped: excluded by label configuration"), so it did not actually review — flagging in case a CodeRabbit pass was expected.

Recommendation: the production change is sound and complete; merge is a maintainer call (protected main, not automerge-labeled). The two guard gaps above are optional hardening, not merge blockers. I did not push (this branch is outside my write scope) and did not merge.


Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Verified Copilot's review — all five findings are real (not false positives), with severity bounded:

Source — fail-open proxy bypass (interactive_metadata_extractor.py, process_video_with_mcp.py): Confirmed. Both modules have __main__ entrypoints and use the try/except ImportError → return None stub. Run by path without PYTHONPATH=src/editable install, import youtube_extension fails, the stub returns None, and with WEBSHARE_PROXY_URL set the client is built proxy_config=None — host-IP egress, silently bypassing the proxy this PR exists to enforce.

Severity Copilot didn't bound: the production path is unaffected — uvicorn runs with PYTHONPATH=src (per CLAUDE.md), so the real helper resolves and the proxy applies. The gap is standalone/CLI execution only, so it's hardening, not an active prod regression. Cheap fix if you want it closed: in the except branch, add the repo root to sys.path and re-import, or fail closed (raise) when a proxy env var is set rather than returning None.

Tests — test_transcript_proxy_coverage.py (the stronger three): these undercut the PR's own "non-vacuity is the point" claim, so they're the ones worth blocking on:

  • **kwargs-only construction (YouTubeTranscriptApi(**{})) is treated as compliant → the exact silent bypass the guard targets passes it.
  • PROXY_HELPER in source passes for proxy_config=<any non-None value> (e.g. object()), not only the canonical helper.
  • A missing/misspelled source root is silently skipped, so the anti-vacuity canary can pass with shared/ unguarded.

Suggest requiring an explicit proxy_config= keyword whose AST value is a call to get_transcript_proxy_config(), and failing on any missing configured root.

Recommendation: hold merge until at least the three test-guard holes are closed; the standalone fail-open is lower priority (prod unaffected) but worth the few-line change while here. CI is otherwise green (test/build/lint/security/CodeQL/coverage all pass; the agent-completion gate red is the unrelated harness misfire, not this diff). I'm leaving the edits to you rather than pushing — the fail-open vs fail-closed choice for standalone execution is a security-relevant design call that should be yours.


Generated by Claude Code

…roxy

Review on #1129 found the guarded-import fallback introduced by this branch
was itself a silent bypass: when a module is executed by path (the documented
CLI entry point) youtube_extension is not importable, so the stub returned
None and proxy_config=get_transcript_proxy_config() egressed directly from
the host IP -- the exact failure this issue exists to prevent.

Replace the stub in all four standalone-executable modules with a sys.path
bootstrap to the repository's src directory, falling back to a hard
ImportError. The proxy is now either honoured or the module refuses to load;
it is never silently skipped.

Harden the guard suite against three ways it could pass while protecting
less than it claims:
- a missing configured source root was skipped silently
- SOURCE_ROOTS could be narrowed by hand with every other test still green;
  the required roots are now rediscovered from the tree
- referencing the helper was satisfied by the call site alone, so a broken
  import passed; every import from the proxy module must now bind the helper

All 9 mutations kill their tests, including one that revealed a newly added
test was itself vacuous (it asserted parents[1] from a test-side constant
rather than the index the source actually uses).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown

🔍 PR Validation

⚠️ Large PR detected (559 lines changed)

Copy link
Copy Markdown
Owner Author

PR remediation run — ready-for-review pass at head 5659f2b. Terminal state: HALTED (awaiting maintainer merge + trusted-publication attestation).

  • Code CI: green. validate, CodeQL, bandit, python-safety, trivy, npm-audit, Generate and Upload Coverage, dependency-review, and the Vercel preview are all ✅. The guard suite tests/unit/test_transcript_proxy_coverage.py passes.
  • Diff red-team: clean. All 6 call sites across the 4 modules now construct YouTubeTranscriptApi(proxy_config=get_transcript_proxy_config()); the guarded import bootstraps src onto sys.path and raises ImportError (fail-closed) rather than silently returning None. No control-flow change; byte-identical when WEBSHARE_PROXY_URL is unset. Nothing adversarial in the diff.
  • Review: the three Copilot findings are addressed at this head (threads are now outdated). The two latent guard gaps flagged earlier — _has_required_keyword treating **kwargs as compliant, and the PROXY_HELPER in source substring check — remain but are non-blocking: no current call site triggers either, and the substring check is now backed by the ImportFrom-binding and literal-None assertions.
  • Sole red check — Agent completion enforcement: this is not flapping. It is a deterministic failure with reason: missing_trusted_publication: the gate looks for an Agent Lock trusted publication check-run on the head SHA, finds none, and fails closed. It will stay red until a trusted publisher emits that attestation (or the check is removed from the required set) — it will not self-resolve on re-run. No autonomous agent can manufacture that attestation.

Not done, by design: no push (branch fix/centralized-transcript-proxy-1087 is outside my write scope) and no merge (protected main, not automerge-labeled → maintainer sign-off required).

Staged next step once the trusted publication lands (or the gate is waived) and you approve:

gh pr merge 1129 --repo groupthinking/EventRelay --squash

Generated by Claude Code

@groupthinking
groupthinking marked this pull request as draft July 31, 2026 07:09

Copy link
Copy Markdown
Owner Author

@coderabbitai review

Please review exact head 5659f2b9ccbb0bfada3a0675f5076c8e6d12de1b. The PR remains draft; this request is for independent exact-head verification after the three Copilot findings were addressed.

@linear-code
linear-code Bot marked this pull request as ready for review July 31, 2026 07:21
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

@groupthinking I will review pull request #1129 at commit 5659f2b9ccbb0bfada3a0675f5076c8e6d12de1b.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@src/agents/interactive_metadata_extractor.py`:
- Around line 106-109: Remove fabricated transcript fallbacks and ensure only
validated real transcript data is returned. In
src/agents/interactive_metadata_extractor.py lines 106-109, stop invoking the
placeholder _generate_transcript_whisper fallback after the YouTube request
fails. In src/agents/process_video_with_mcp.py lines 241-246, propagate the
direct extraction failure when no real fallback succeeds. In
src/agents/process_video_with_mcp.py lines 257-260, replace the fixed result in
RealVideoProcessor._extract_transcript_with_rotation with actual subtitle
extraction, or raise a typed extraction error when unavailable.
- Around line 106-109: Introduce one shared transcript HTTP-client factory that
returns a requests.Session enforcing finite connect and read timeouts, then pass
its result via http_client= to every YouTubeTranscriptApi call. Update
src/agents/interactive_metadata_extractor.py lines 106-109,
src/agents/process_video_with_mcp.py lines 241-246 and 257-260,
src/integration/youtube_api.py lines 118-120, and src/mcp/mcp_video_processor.py
lines 713 and 737; apply the same bounded-session pattern to all transcript
fetches under src/youtube_extension/backend. Preserve existing proxy
configuration and fetch behavior while ensuring every transcript client uses the
shared timeout-enabled session.
🪄 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: Repository YAML (base), Repository UI (inherited), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 759ea240-3ded-4491-8ef1-955c0d0b8eeb

📥 Commits

Reviewing files that changed from the base of the PR and between abd9332 and 5659f2b.

⛔ Files ignored due to path filters (1)
  • tests/unit/test_transcript_proxy_coverage.py is excluded by !tests/**
📒 Files selected for processing (4)
  • src/agents/interactive_metadata_extractor.py
  • src/agents/process_video_with_mcp.py
  • src/integration/youtube_api.py
  • src/mcp/mcp_video_processor.py
📜 Review details
⚠️ CI failures not shown inline (2)

GitHub Actions: Agent completion enforcement / 0_Agent completion enforcement.txt: fix: route every transcript client through the centralized proxy (#1087)

Conclusion: failure

View job details

##[group]Run actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3
 with:
   script: const fs = require('fs');
const pull = await github.rest.pulls.get({
  owner: context.repo.owner,
  repo: context.repo.repo,
  pull_number: Number(process.env.PR)
});
let verdict = {
  conclusion: 'failure',
  reason: 'verifier_did_not_publish',
  details: {}
};
try {
  verdict = JSON.parse(fs.readFileSync(
    'enforcement-verdict.json', 'utf8'
  ));
} catch (error) {
  core.warning(error.message);
}
const conclusion = verdict.conclusion === 'success'
  ? 'success'
  : 'failure';
const summary = JSON.stringify(verdict);
await github.rest.checks.create({
  owner: context.repo.owner,
  repo: context.repo.repo,
  name: 'Agent completion enforcement',
  head_sha: pull.data.head.sha,
  status: 'completed',
  conclusion,
  output: {
    title: conclusion === 'success'
      ? 'Trusted evidence verified'
      : 'Trusted evidence blocked',
    summary: summary.slice(0, 60000)
  }
});
if (conclusion !== 'success') {
  core.setFailed(verdict.reason || 'trusted evidence blocked');
}
   github-***REDACTED_SECRET_ASSIGNMENT***
   debug: false
   user-agent: actions/github-script
   result-encoding: json
   retries: 0
   retry-exempt-status-codes: 400,401,403,404,422
 env:
   PR: 1129
 ##[endgroup]
 ##[error]missing_trusted_publication

GitHub Actions: Agent completion enforcement / Agent completion enforcement: fix: route every transcript client through the centralized proxy (#1087)

Conclusion: failure

View job details

##[group]Run actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3
 with:
   script: const fs = require('fs');
const pull = await github.rest.pulls.get({
  owner: context.repo.owner,
  repo: context.repo.repo,
  pull_number: Number(process.env.PR)
});
let verdict = {
  conclusion: 'failure',
  reason: 'verifier_did_not_publish',
  details: {}
};
try {
  verdict = JSON.parse(fs.readFileSync(
    'enforcement-verdict.json', 'utf8'
  ));
} catch (error) {
  core.warning(error.message);
}
const conclusion = verdict.conclusion === 'success'
  ? 'success'
  : 'failure';
const summary = JSON.stringify(verdict);
await github.rest.checks.create({
  owner: context.repo.owner,
  repo: context.repo.repo,
  name: 'Agent completion enforcement',
  head_sha: pull.data.head.sha,
  status: 'completed',
  conclusion,
  output: {
    title: conclusion === 'success'
      ? 'Trusted evidence verified'
      : 'Trusted evidence blocked',
    summary: summary.slice(0, 60000)
  }
});
if (conclusion !== 'success') {
  core.setFailed(verdict.reason || 'trusted evidence blocked');
}
   github-***REDACTED_SECRET_ASSIGNMENT***
   debug: false
   user-agent: actions/github-script
   result-encoding: json
   retries: 0
   retry-exempt-status-codes: 400,401,403,404,422
 env:
   PR: 1129
 ##[endgroup]
 ##[error]missing_trusted_publication
🧰 Additional context used
📓 Path-based instructions (12)
**/*.{py,js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{py,js,jsx,ts,tsx}: Use Python 3.9+ and Node 18+ for development
Never hardcode API keys, database URLs, or secrets in code
Make minimal, surgical changes and avoid deleting working code unless fixing security issues

Files:

  • src/integration/youtube_api.py
  • src/agents/interactive_metadata_extractor.py
  • src/agents/process_video_with_mcp.py
  • src/mcp/mcp_video_processor.py
**/*.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.py: Always use type hints for Python functions
Use Black formatter with 88 character line length for Python code
Follow PEP 8 conventions for Python code
Use descriptive variable names and add docstrings to all public functions in Python
Group imports in Python: standard library, third-party, local
Use SQLAlchemy ORM and never write raw SQL queries
Use environment variables via os.getenv() or pydantic-settings to access configuration
Wrap database operations in try-except blocks and use context managers or FastAPI dependencies for connection cleanup
Implement comprehensive error handling with proper logging in all functions
Version APIs using /api/v1/ prefix for stability
Use JSON-RPC 2.0 protocol for all MCP communication
Follow the single-flow workflow: YouTube link → context extraction → agent dispatch → outputs
Use context managers for resource management in Python code
Implement comprehensive input validation and sanitize outputs for security
Use parameterized queries and SQLAlchemy ORM to prevent SQL injection
Define API request/response models using Pydantic for FastAPI endpoints
Store the single unified workflow as the only workflow; never introduce alternate flows or manual triggers
Use SQLAlchemy with connection pooling for database connections and manage sessions with context managers
Provide sensible defaults for non-sensitive configuration in Python settings
Maintain backward compatibility and do not break existing API endpoints
Include comprehensive logging for debugging in MCP implementations

Files:

  • src/integration/youtube_api.py
  • src/agents/interactive_metadata_extractor.py
  • src/agents/process_video_with_mcp.py
  • src/mcp/mcp_video_processor.py

⚙️ CodeRabbit configuration file

Python backend code. Check for type hints, proper exception handling, async context manager usage, and potential blocking calls in async functions. Flag any bare except clauses or missing timeout parameters on network calls. CRITICAL: Flag any file that contains placeholder/stub implementations — especially in unified_ai_sdk. Any class or function that says "TODO: Replace with production implementation" or returns mock/fake data must be flagged as a blocking issue. Flag any code generation output that reaches users without AST validation or syntax checking.

Files:

  • src/integration/youtube_api.py
  • src/agents/interactive_metadata_extractor.py
  • src/agents/process_video_with_mcp.py
  • src/mcp/mcp_video_processor.py
**/*.{py,js,ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Maintain >80% code coverage for new features

Files:

  • src/integration/youtube_api.py
  • src/agents/interactive_metadata_extractor.py
  • src/agents/process_video_with_mcp.py
  • src/mcp/mcp_video_processor.py
**/*.{py,ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{py,ts,tsx}: Keep frontend and backend data models synchronized using matching Pydantic (backend) and TypeScript (frontend) interfaces
Use type-safe interfaces for backend-frontend data exchange

**/*.{py,ts,tsx}: Production code must use real behavior only: no mock delays, fake data, or simulated responses.
Maintain strict type safety: mypy strict mode for Python and TypeScript strict mode for the frontend.
Name events using the <domain>.<entity>.<action> format.

Files:

  • src/integration/youtube_api.py
  • src/agents/interactive_metadata_extractor.py
  • src/agents/process_video_with_mcp.py
  • src/mcp/mcp_video_processor.py
**/*

📄 CodeRabbit inference engine (Custom checks)

**/*: Strictly verify that GitHub Copilot has explicitly reviewed and approved the pull request; human approvals alone must not satisfy this check.
Before allowing a merge, require the copilot-rabbit label and AI-generated unit tests committed alongside the code changes; fail the check if either is missing.

For Vercel-specific work, include https://vercel.com/docs/llms-full.txt in the AI assistant context set.

Files:

  • src/integration/youtube_api.py
  • src/agents/interactive_metadata_extractor.py
  • src/agents/process_video_with_mcp.py
  • src/mcp/mcp_video_processor.py
**/*.{py,pyw}

📄 CodeRabbit inference engine (AGENTS.md)

Write Python code to remain compatible with Linux and Windows where possible, including correct handling of asyncio event loops.

Files:

  • src/integration/youtube_api.py
  • src/agents/interactive_metadata_extractor.py
  • src/agents/process_video_with_mcp.py
  • src/mcp/mcp_video_processor.py
src/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.py: Format Python code with Black using an 88-character line length.
Sort Python imports with isort using the Black profile.
Run Ruff with E, W, F, I, B, C4, and UP rules; E501 is ignored.
Use mypy strict mode; untyped function definitions are disallowed.
Target Python 3.9 or newer.
Validate backend inputs with Pydantic and sanitize subprocess arguments.
Use Anthropic SDK features thinking={"type": "adaptive"} and output_config={"effort": "..."} with anthropic>=0.105.0; do not add TypeError fallbacks for these parameters.

Use the service container dependency-injection pattern in backend/containers/.

Files:

  • src/integration/youtube_api.py
  • src/agents/interactive_metadata_extractor.py
  • src/agents/process_video_with_mcp.py
  • src/mcp/mcp_video_processor.py
**/*.{py,ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not commit secrets; store keys and credentials in gitignored .env files.

Files:

  • src/integration/youtube_api.py
  • src/agents/interactive_metadata_extractor.py
  • src/agents/process_video_with_mcp.py
  • src/mcp/mcp_video_processor.py
**/*.{py,pyi}

📄 CodeRabbit inference engine (GEMINI.md)

**/*.{py,pyi}: Use Black formatting with an 88-character line length for Python code.
Use Ruff with rules E, W, F, I, B, C4, and UP for Python linting.
Use strict mypy type checking; do not define untyped functions.
Target Python 3.9 or newer.
Validate Python inputs with Pydantic.
Sanitize subprocess arguments before execution.
Do not add mock delays or fake data to production Python code; production runs in REAL_MODE_ONLY.
Keep secrets out of Python source code; load keys and credentials from environment variables instead.
Use absolute imports that resolve with PYTHONPATH=src in the Python backend.

Files:

  • src/integration/youtube_api.py
  • src/agents/interactive_metadata_extractor.py
  • src/agents/process_video_with_mcp.py
  • src/mcp/mcp_video_processor.py
**/*.{py,pyi,ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

**/*.{py,pyi,ts,tsx}: Preserve the single workflow: YouTube link → transcript → events → agents → outputs; do not introduce alternative flows or manual triggers that bypass it.
Use event names following <domain>.<entity>.<action>, such as youtube.video.captured.
Make surgical, precise changes and do not delete working code without justification.

Files:

  • src/integration/youtube_api.py
  • src/agents/interactive_metadata_extractor.py
  • src/agents/process_video_with_mcp.py
  • src/mcp/mcp_video_processor.py
src/mcp/**/*.py

📄 CodeRabbit inference engine (.cursorrules)

In src/mcp/, MCP tool definitions and the registry must be maintained as real tool implementations.

Files:

  • src/mcp/mcp_video_processor.py
**/mcp*/**

⚙️ CodeRabbit configuration file

MCP (Model Context Protocol) integration code. Verify tools follow proper MCP protocol structure — correct tool definitions, input schemas, and response formats. Flag any MCP tool that doesn't handle errors gracefully or lacks proper input validation.

Files:

  • src/mcp/mcp_video_processor.py
🔍 Remote MCP GitHub Copilot

Additional review context

  • PR #1129 is open at head 5659f2b; latest CodeRabbit review approved it. Core checks—including tests, build, lint, CodeQL, security scans, coverage, and dependency review—passed. Agent completion enforcement remains failed, while PR Governance passed.

  • Issue #1087 remains open and is directly linked. PR #496 previously completed the youtube-transcript-api >=1.0 instance-API migration; this PR addresses the remaining proxy-routing gap.

  • pyproject.toml declares youtube-transcript-api>=1.0.0 only under the optional youtube extra. The canonical helper validates WEBSHARE_PROXY_URL, creates GenericProxyConfig(http_url=url, https_url=url), and returns None when unset, malformed, or when proxy support is unavailable.

  • A separate local _get_transcript_proxy_config() still exists in shared/libs/youtube_proxy.py; its two client constructions use that local helper rather than the canonical youtube_extension.utils.proxy.get_transcript_proxy_config(). The new canonical-helper test lists only seven src/ modules, so it does not enforce canonical-helper provenance for shared/.

  • Copilot’s remaining guard concerns are real in the current test source: any **kwargs is accepted as compliant, and the canonical-helper check verifies helper-name presence/import binding but not that each proxy_config AST value is specifically a call to get_transcript_proxy_config(). No current call site uses **kwargs, and CodeRabbit approved the exact head.

Comment on lines +106 to +109
None,
lambda: YouTubeTranscriptApi(proxy_config=get_transcript_proxy_config())
.fetch(video_id)
.to_raw_data(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🔴 Critical | 🏗️ Heavy lift

Stop returning fabricated transcript results.

Both paths report successful extraction after real extraction fails. InteractiveMetadataExtractor.extract_transcript falls back to _generate_transcript_whisper, which returns a hard-coded segment. RealVideoProcessor._extract_transcript_with_rotation returns a fixed segment after yt_dlp.extract_info() without extracting subtitle content. This sends false video data to downstream agents.

Use a real transcriber and validate its output. If no real transcript is available, raise a typed extraction error.

  • src/agents/interactive_metadata_extractor.py#L106-L109: Do not call the placeholder transcript fallback after this request fails.
  • src/agents/process_video_with_mcp.py#L241-L246: Propagate the direct extraction failure when no real fallback succeeds.
  • src/agents/process_video_with_mcp.py#L257-L260: Replace the fixed yt_dlp fallback result with actual subtitle extraction or an error.

As per coding guidelines, “Production code must use real behavior only: no mock delays, fake data, or simulated responses.” As per path instructions, “Flag any file that contains placeholder/stub implementations … or returns mock/fake data.”

📍 Affects 2 files
  • src/agents/interactive_metadata_extractor.py#L106-L109 (this comment)
  • src/agents/process_video_with_mcp.py#L241-L246
  • src/agents/process_video_with_mcp.py#L257-L260
🤖 Prompt for 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.

In `@src/agents/interactive_metadata_extractor.py` around lines 106 - 109, Remove
fabricated transcript fallbacks and ensure only validated real transcript data
is returned. In src/agents/interactive_metadata_extractor.py lines 106-109, stop
invoking the placeholder _generate_transcript_whisper fallback after the YouTube
request fails. In src/agents/process_video_with_mcp.py lines 241-246, propagate
the direct extraction failure when no real fallback succeeds. In
src/agents/process_video_with_mcp.py lines 257-260, replace the fixed result in
RealVideoProcessor._extract_transcript_with_rotation with actual subtitle
extraction, or raise a typed extraction error when unavailable.

Sources: Coding guidelines, Path instructions


🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

# Locate every transcript client construction and any existing bounded Session wrapper.
rg -n -C 3 --glob='*.py' 'YouTubeTranscriptApi\s*\(' src
rg -n -C 3 --glob='*.py' 'http_client\s*=|class .*Session|def request\(' src

# Confirm the declared youtube-transcript-api constraint.
sed -n '1,220p' pyproject.toml

Repository: groupthinking/EventRelay

Length of output: 16595


🌐 Web query:

youtube-transcript-api http_client YouTubeTranscriptApi __init__ _http_client requests Session timeout

💡 Result:

In the python library youtube-transcript-api, you can control the HTTP configuration by passing a custom requests.Session object to the YouTubeTranscriptApi constructor via the http_client parameter [1][2]. While the library does not have a native timeout parameter, you can manage request timeouts by configuring the Session object before passing it to the API [1][2][3]. To set a timeout for all requests made by the library: 1. Initialize a requests.Session object. 2. Manually set a default timeout for the session's request methods or use a transport adapter. A common pattern in the requests library is to monkeypatch the session or override the request method, as requests.Session does not have a built-in default timeout attribute [3]. Example of passing a custom session: from requests import Session from youtube_transcript_api import YouTubeTranscriptApi # Create a session http_client = Session # Customize the session (e.g., custom headers) http_client.headers.update({"Accept-Encoding": "gzip, deflate"}) # Inject the session into the API ytt_api = YouTubeTranscriptApi(http_client=http_client) ytt_api.fetch(video_id) Note that YouTubeTranscriptApi is not thread-safe because it uses a requests.Session object internally [2][4]. If you are working in a multi-threaded environment, you must initialize a new instance of YouTubeTranscriptApi (and ideally a new requests.Session) per thread [2][4]. Regarding the timeout specifically, users have noted that the library lacks a direct timeout argument, and requests for this feature have been discussed in the project's issue tracker [3]. Users are often advised to handle timeouts by wrapping the API calls or customizing the underlying requests session [3].

Citations:


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

# Inspect the executor call sites and whether any youtube-transcript-api call
# passes http_client or configures timeouts.
rg -n -C 4 'http_client|timeout' src/agents src/integration/youtube_api.py src/mcp/mcp_video_processor.py src/youtube_extension/backend/enhanced_video_processor.py src/youtube_extension/backend/services/youtube/adapters 2>/dev/null || true

# Static model of YouTubeTranscriptApi construction semantics by reading the installed package
# if available, without network access or repo execution.
python3 - <<'PY'
import inspect, importlib.util
mods = ["youtube_transcript_api._api", "youtube_transcript_api"]
for mod_name in mods:
    spec = importlib.util.find_spec(mod_name)
    print(mod_name, "FOUND" if spec else "NOT_FOUND", getattr(spec, "origin", None))
    if spec:
        mod = importlib.util.module_from_spec(spec)
        try:
            spec.loader.exec_module(mod)
        except Exception as exc:
            print("LOAD_ERROR", type(exc).__name__, str(exc))
            continue
        if hasattr(mod, "YouTubeTranscriptApi"):
            print("YouTubeTranscriptApi file:", getattr(mod.YouTubeTranscriptApi, "__module__", None))
            print(inspect.signature(mod.YouTubeTranscriptApi.__init__))
            src = inspect.getsource(mod.YouTubeTranscriptApi.__init__)
            print(src)
PY

Repository: groupthinking/EventRelay

Length of output: 40895


Set a finite HTTP timeout for every transcript client.

youtube-transcript-api accepts a custom HTTP client, but these calls pass only proxy_config. Without an enforced connect/read timeout, a blocked transcript/SRT fetch can hold an executor worker and stall the surrounding timeout or circuit-breaker path.

Add one shared transcript HTTP-client factory that creates a requests.Session with bounded connect and read timeouts, and pass it through http_client= at every transcript API call, including:

  • src/agents/interactive_metadata_extractor.py#L106-L109
  • src/agents/process_video_with_mcp.py#L241-L246
  • src/agents/process_video_with_mcp.py#L257-L260
  • src/integration/youtube_api.py#L118-C20
  • src/mcp/mcp_video_processor.py#L713
  • src/mcp/mcp_video_processor.py#L737

Apply the same bounded-session pattern to the other YouTube transcript fetches under src/youtube_extension/backend, since they create the same unbounded client.

📍 Affects 4 files
  • src/agents/interactive_metadata_extractor.py#L106-L109 (this comment)
  • src/agents/process_video_with_mcp.py#L241-L246
  • src/agents/process_video_with_mcp.py#L257-L260
  • src/integration/youtube_api.py#L118-L120
  • src/mcp/mcp_video_processor.py#L713-L713
  • src/mcp/mcp_video_processor.py#L737-L737
🤖 Prompt for 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.

In `@src/agents/interactive_metadata_extractor.py` around lines 106 - 109,
Introduce one shared transcript HTTP-client factory that returns a
requests.Session enforcing finite connect and read timeouts, then pass its
result via http_client= to every YouTubeTranscriptApi call. Update
src/agents/interactive_metadata_extractor.py lines 106-109,
src/agents/process_video_with_mcp.py lines 241-246 and 257-260,
src/integration/youtube_api.py lines 118-120, and src/mcp/mcp_video_processor.py
lines 713 and 737; apply the same bounded-session pattern to all transcript
fetches under src/youtube_extension/backend. Preserve existing proxy
configuration and fetch behavior while ensuring every transcript client uses the
shared timeout-enabled session.

Source: Path instructions

@groupthinking
groupthinking marked this pull request as draft July 31, 2026 08:07

Copy link
Copy Markdown
Owner Author

Exact-head triage for CodeRabbit thread PRRT_kwDORAYbZs6VWQZB:

  • Fabricated transcript fallback: confirmed real, but pre-existing. main@abd93326 already calls _generate_transcript_whisper() after extraction failure and already returns the fixed "Transcript extracted via yt-dlp" segment. This branch changes only transcript-client proxy construction at those sites.
  • Unbounded HTTP client: confirmed pre-existing and cross-cutting. main@abd93326 already constructs every transcript client without http_client=. The requested shared bounded-session factory spans all transcript clients and is broader than focused issue Migrate YouTube transcript client to v1.x with proxy support #1087’s proxy-routing repair.

The consolidated thread remains unresolved. Neither finding is being folded speculatively into #1129; both require a focused child issue and canonical repair unit. #1129 remains draft. The test-only guard hardening from duplicate #1131 has been transferred to canonical head 49e887ced1a7a9d915c802ea8259e239e3d1ac87; #1131 is closed as a preserved-branch duplicate.

Copy link
Copy Markdown
Owner Author

@coderabbitai review

Exact-head review requested for 49e887ced1a7a9d915c802ea8259e239e3d1ac87 after transferring the verified test-only guard hardening from closed duplicate #1131. The existing consolidated thread PRRT_kwDORAYbZs6VWQZB remains intentionally unresolved: its fabricated-fallback and bounded-HTTP findings are real, pre-existing on main, and outside focused issue #1087. Please review the current exact head; do not treat that broader thread as resolved.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

@groupthinking I will review pull request #1129 at commit 49e887ced1a7a9d915c802ea8259e239e3d1ac87.

I will assess the transferred guard hardening and the focused proxy-routing change. I will not treat PRRT_kwDORAYbZs6VWQZB as resolved.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Owner Author

Closing — branch orphaned by the secret-purge force-push

No common ancestor with current main, so this branch is not rebaseable.

The work is unlanded — routing every transcript client through the centralized proxy, plus rejecting opaque and foreign proxy configs.

Two pre-existing gaps were identified on this PR's review thread and are worth carrying forward as their own focused issues rather than being lost here: fabricated transcript fallbacks, and unbounded HTTP clients.

Tracked in #1378. Branch retained for archive-tagging.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate YouTube transcript client to v1.x with proxy support

2 participants