Skip to content

fetchRepoFocusManifestFile's GitHub raw-content fetch has no AbortSignal.timeout, unlike its review/signals siblings #7071

Description

@JSONbored

Context

fetchRepoFocusManifestFile in src/signals/focus-manifest-loader.ts (line 96-114) fetches a repo's .loopover.yml/.loopover.json manifest from GitHub's raw-content CDN, trying up to 4 candidate paths (MANIFEST_FILE_CANDIDATES, line 20) in sequence:

for (const path of MANIFEST_FILE_CANDIDATES) {
  const url = `https://github.com/ghraw/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/HEAD/${path}`;
  try {
    const response = await fetch(url, { headers: { Accept: "application/json", "User-Agent": "loopover" } });
    ...

None of these fetch() calls (up to 4 sequential attempts per repo) carry an AbortSignal.timeout(...), unlike the established convention elsewhere in src/review/**/src/signals/**: src/review/enrichment-wire.ts uses AbortSignal.timeout(5000)/timeoutMs, src/review/alerts.ts uses AbortSignal.timeout(10_000), src/review/visual/actions-fallback.ts uses AbortSignal.timeout(DEFAULT_TIMEOUT_MS) (20s), and src/review/visual/capture.ts uses AbortSignal.timeout(EXTERNAL_SCREENSHOT_FETCH_TIMEOUT_MS) (8s).

fetchRepoFocusManifestFile feeds loadRepoFocusManifestWithCachePolicy (the public entry point used by loadRepoFocusManifest/loadPublicRepoFocusManifest), which is on the cold-cache path for resolving a repo's gate/review policy on webhook and sweep processing — a slow or hanging github.com/ghraw response (or a slow candidate path in the loop before falling through to a working one) has no per-request ceiling here and can stall manifest resolution for that repo.

Requirements

  • fetchRepoFocusManifestFile (src/signals/focus-manifest-loader.ts) must pass an AbortSignal.timeout(...) to each candidate-path fetch(url, ...) call inside its loop.
  • Introduce a named timeout constant local to this file (matching the existing per-file convention, e.g. src/review/visual/capture.ts's EXTERNAL_SCREENSHOT_FETCH_TIMEOUT_MS) rather than a bare inline number.
  • A timeout on one candidate path must continue to the next candidate exactly like today's existing catch { // try the next candidate path } handles a network/HTTP failure — AbortSignal.timeout rejects with a TimeoutError, which is already caught by the existing broad catch block, so no new catch branch is needed, only the added signal.
  • No change to the function's return contract (still resolves to string | null).

Deliverables

  • fetchRepoFocusManifestFile in src/signals/focus-manifest-loader.ts passes a bounded AbortSignal.timeout(...) on every candidate-path fetch.
  • A regression test asserting that a hung candidate-path fetch causes the loader to move on to the next candidate (or return null if it was the last candidate) within the bounded timeout, rather than hanging.
  • Existing success-path and all-candidates-miss tests continue to pass unchanged.

Test Coverage Requirements

src/signals/focus-manifest-loader.ts is under src/** (measured by Codecov). This PR must hit 99%+ patch coverage on every changed line and branch, including the new timeout path exercised by the regression test above.

Expected Outcome

Every candidate-path fetch inside fetchRepoFocusManifestFile is bounded by an explicit timeout, consistent with every other external fetch in src/review/**/src/signals/**, so a slow or hanging github.com/ghraw response can no longer stall repo manifest resolution.

Links & Resources

  • src/signals/focus-manifest-loader.ts (fetchRepoFocusManifestFile, lines 96-114; MANIFEST_FILE_CANDIDATES, line 20)
  • Sibling timeout conventions: src/review/visual/capture.ts (EXTERNAL_SCREENSHOT_FETCH_TIMEOUT_MS), src/review/alerts.ts, src/review/visual/actions-fallback.ts (DEFAULT_TIMEOUT_MS)

Metadata

Metadata

Assignees

No one assigned

    Labels

    gittensor:bugGittensor-scored bug fix — scores a 0.05x multiplier.help wantedExtra attention is needed

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions