Skip to content

feat(fetch): header-exact backoff, workdir watch, PR-list throttle#9

Merged
jcardonne merged 1 commit into
mainfrom
feat/backoff-headers-workdir-watch
Jul 12, 2026
Merged

feat(fetch): header-exact backoff, workdir watch, PR-list throttle#9
jcardonne merged 1 commit into
mainfrom
feat/backoff-headers-workdir-watch

Conversation

@jcardonne

Copy link
Copy Markdown
Owner

Follow-ups from the auto-refresh work, in order.

Header-exact rate-limit backoff

The avatar API path (ureq) reads Retry-After / X-RateLimit-Reset / RateLimit-Reset on a 403/429 and emits a rate-limited event with the precise seconds; the UI pauses exactly that long instead of the CLI-string heuristic's 15-min fallback. On such a cutoff we also stop negative-caching un-scanned authors (they'd otherwise show Gravatar for the whole negative-TTL). CLI errors (gh/glab/git) keep the text heuristic - now confirmed against real provider output and locked as regression tests (GitHub primary/secondary, GitLab/git 429, abuse-detection; not plain 403/network; 429 word-boundaried).

Workdir watch for instant WIP

The FS watcher now also watches the working tree, gitignore-filtered (is_relevant_change): an external editor save refreshes the WIP list live, while build dirs (node_modules, target, dist) churning stay ignored so they can't spam refreshes. Paths canonicalised for the macOS /private symlink. ponytail: note left re: Linux inotify watch-count on huge trees.

PR-list throttle

Background loop lists PRs/MRs at a coarser cadence (PR_REFRESH_MS = 15min) than the cheap git fetch - PR-list spawns a gh/glab subprocess + hits the API bucket. Focus/return and user ops still list immediately.

Testable wiring

Background-refresh decisions (fetch gate, watcher-echo grace, PR cadence, backoff window) extracted into pure predicates (src/refreshPolicy.ts) that RepoView calls, and unit-tested. Settings copy updated for the new defaults.

Verify

  • Rust: backoff_secs precedence/clamp/fallback; is_relevant_change git-state vs workdir vs gitignored vs out-of-tree; watcher still fires on .git write + idempotent. 67 pass, 0 warnings.
  • Frontend: refreshPolicy predicates (15), real rate-limit strings, extendBackoff. 76 pass, tsc + build clean.

Notes

  • .gitignore change (ignore graphify-out/) is intentionally not in this branch - kept local per instruction.
  • Not yet driven in the running GUI - the end-to-end /verify pass is still the outstanding "NOW" item.

https://claude.ai/code/session_01RVF5LSdTyciWKY1k5sedU8

…throttle

Header-exact backoff: the avatar API path (ureq) now reads Retry-After /
X-RateLimit-Reset / RateLimit-Reset on a 403/429 and emits `rate-limited` with
the precise seconds, so the UI pauses exactly as long as the provider asks
instead of the CLI-error string heuristic's 15-min fallback. On such a cutoff we
also stop negative-caching un-scanned authors (they'd wrongly show Gravatar for
the negative-TTL). CLI errors (gh/glab/git) still use the confirmed text match.

Workdir watch: the FS watcher now also watches the working tree, gitignore-
filtered (is_relevant_change), so an external editor save refreshes the WIP list
live - while build dirs (node_modules, target, dist) churning stay ignored and
can't spam refreshes. Paths are canonicalised for the macOS /private symlink.

PR-list throttle: the background loop lists PRs/MRs at a coarser cadence
(PR_REFRESH_MS) than the cheap git fetch, since it spawns a gh/glab subprocess
and hits the API bucket. Focus/return and user ops still list immediately.

The background-refresh decision logic (fetch gate, watcher-echo grace, PR
cadence, backoff window) is extracted into pure predicates in refreshPolicy.ts
and unit-tested, plus real GitHub/GitLab/git rate-limit strings locked as
regression tests for isRateLimited. Settings copy notes the new defaults.
@jcardonne
jcardonne merged commit 98ce6ad into main Jul 12, 2026
1 of 2 checks passed
@jcardonne
jcardonne deleted the feat/backoff-headers-workdir-watch branch July 12, 2026 23:26
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 0.31.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant