Core: cache, background refresh and stale-result protection #7

Closed
opened 2026-10-01 21:55:16 -05:00 by deadstyle · 1 comment
Owner

Problem

The UI must feel instant while browsing (j/k through repos and boxes) and must not show the wrong data when results arrive late. The design calls for rendering from cache immediately, refreshing in the background, and r to force a refresh. Without a deliberate core layer, every view would reinvent this, and stale responses would land on whatever is now selected.

Plan

internal/core, talking only to forge.Forge:

  1. A session-scoped cache keyed by request (host, repo, kind, filters), recording when each entry was fetched.
  2. A load API used by the UI that returns cached data at once, plus a tea.Cmd that refreshes it. Results carry the request key so the UI can drop stale ones (go-development → Bubble Tea rules).
  3. Cancellation: navigating away cancels in-flight requests through context.
  4. Repo-list activity ordering.
  5. Concurrency limits on background fetches, so a large repo list doesn't flood the forge (this matters for GitHub rate limits later).

Opus settles the concurrency and cancellation design inside this ticket and records an ADR, since every view depends on it.

Plan-review additions (#17)

  • Host-wide scans have completeness state. Loading every repo for the ★ view runs with bounded concurrency and reports progress as "scanned X of Y repositories", plus which repos failed. Partial results are usable, but they're labelled partial, and anything that acts on them (bulk merge) can see that coverage is incomplete.
  • Pagination is followed to the end; a page failure marks that repo as failed rather than silently returning a short list.
  • Which repos count as "the host" is a product question on #13. Build against "repos the user can access" behind one function so the boundary can change.

Context

  • docs/architecture.md → "Caching and refresh".
  • docs/design.md → Open questions (interval polling vs manual r is a pending product decision; build manual refresh now, in a way that allows a timer to be added later).
  • Depends on the domain model / Forge interface ticket.
## Problem The UI must feel instant while browsing (`j`/`k` through repos and boxes) and must not show the wrong data when results arrive late. The design calls for rendering from cache immediately, refreshing in the background, and `r` to force a refresh. Without a deliberate core layer, every view would reinvent this, and stale responses would land on whatever is now selected. ## Plan `internal/core`, talking only to `forge.Forge`: 1. A session-scoped cache keyed by request (host, repo, kind, filters), recording when each entry was fetched. 2. A load API used by the UI that returns cached data at once, plus a `tea.Cmd` that refreshes it. Results carry the request key so the UI can drop stale ones (`go-development` → Bubble Tea rules). 3. Cancellation: navigating away cancels in-flight requests through context. 4. Repo-list activity ordering. 5. Concurrency limits on background fetches, so a large repo list doesn't flood the forge (this matters for GitHub rate limits later). Opus settles the concurrency and cancellation design inside this ticket and records an ADR, since every view depends on it. ### Plan-review additions (#17) - **Host-wide scans have completeness state.** Loading every repo for the ★ view runs with bounded concurrency and reports progress as "scanned X of Y repositories", plus which repos failed. Partial results are usable, but they're labelled partial, and anything that acts on them (bulk merge) can see that coverage is incomplete. - Pagination is followed to the end; a page failure marks that repo as failed rather than silently returning a short list. - Which repos count as "the host" is a product question on #13. Build against "repos the user can access" behind one function so the boundary can change. ## Context - `docs/architecture.md` → "Caching and refresh". - `docs/design.md` → Open questions (interval polling vs manual `r` is a pending product decision; build manual refresh now, in a way that allows a timer to be added later). - Depends on the domain model / `Forge` interface ticket.
Author
Owner

🤖 Merged in #28. Screens can show what's already loaded instantly and refresh in the background. Forge calls run at most four at a time, a failed refresh keeps the last good data, and host-wide scans report 'scanned X of Y' exactly. The UI owns the five-minute timer and r (#8).

🤖 Merged in #28. Screens can show what's already loaded instantly and refresh in the background. Forge calls run at most four at a time, a failed refresh keeps the last good data, and host-wide scans report 'scanned X of Y' exactly. The UI owns the five-minute timer and r (#8).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
deadstyle/lazyforge#7
No description provided.