Context: fetchTeamGitHubSnapshot (packages/server-core/src/github-team.ts, ~:560) runs gh issue list --limit 100 + gh pr list --limit 50 and is UNCACHED — and buildActivity and buildWorkBoard (team-dashboard.ts:131,156) each call it separately, so every activity(15s)/board(30s) poll cycle spawns up to 4 gh processes costing 10-35s each on slow-DNS networks.
Spec:
- Add a per-repoPath cache around
fetchTeamGitHubSnapshot with TTL 150_000ms (matching the fetchGitHubPRStatus cache bumped in af80ddc), stale-while-revalidate: expired entry → return the stale snapshot immediately AND kick one background refresh (dedupe concurrent refreshes — single-flight per repoPath).
- First-ever call (no cached entry) still awaits the live fetch.
- Keep it in github-team.ts next to the existing cache; same pattern (module-level Map). Import-time DB-free constraint applies.
- Unit tests (bun test, follow github-team.test.ts patterns with mocked exec): fresh miss awaits; hit within TTL returns cached without spawning; stale hit returns stale + triggers exactly one refresh under concurrent calls; refresh failure keeps serving stale.
Note: issue on replacing gh spawns with in-process fetch will change the transport UNDER this cache — keep the cache at the fetchTeamGitHubSnapshot boundary (transport-agnostic) so the two changes compose.
Acceptance: tests above pass; typecheck passes; activity + board polls after warmup spawn zero gh processes within the TTL window.
🤖 Generated with Claude Code
Context:
fetchTeamGitHubSnapshot(packages/server-core/src/github-team.ts, ~:560) runsgh issue list --limit 100+gh pr list --limit 50and is UNCACHED — andbuildActivityandbuildWorkBoard(team-dashboard.ts:131,156) each call it separately, so every activity(15s)/board(30s) poll cycle spawns up to 4 gh processes costing 10-35s each on slow-DNS networks.Spec:
fetchTeamGitHubSnapshotwith TTL 150_000ms (matching the fetchGitHubPRStatus cache bumped in af80ddc), stale-while-revalidate: expired entry → return the stale snapshot immediately AND kick one background refresh (dedupe concurrent refreshes — single-flight per repoPath).Note: issue on replacing gh spawns with in-process fetch will change the transport UNDER this cache — keep the cache at the
fetchTeamGitHubSnapshotboundary (transport-agnostic) so the two changes compose.Acceptance: tests above pass; typecheck passes; activity + board polls after warmup spawn zero gh processes within the TTL window.
🤖 Generated with Claude Code