Skip to content

fix(api): /api/v1/capabilities Cache-Control + must-revalidate (BUG-API-039/311)#193

Merged
mastermanas805 merged 1 commit into
masterfrom
bug-api-039-capabilities-cache
May 30, 2026
Merged

fix(api): /api/v1/capabilities Cache-Control + must-revalidate (BUG-API-039/311)#193
mastermanas805 merged 1 commit into
masterfrom
bug-api-039-capabilities-cache

Conversation

@mastermanas805

Copy link
Copy Markdown
Member

Summary

  • /api/v1/capabilities is dashboard-hit on every navigation (sidebar tile counts, billing card, settings) but the tier matrix is immutable for the life of the running pod.
  • Without a Cache-Control hint, each nav re-fetched ~4 KB; sidebar fanout meant 4-6 redundant fetches per nav (see BUG-DASH-016).
  • Stamp `public, max-age=60, must-revalidate` so browser/edge caches serve for a minute while still re-validating on expiry. The rule-23 deploy cycle invalidates the cache shortly after any plans.yaml change ships.

Coverage block

```
Symptom: /api/v1/capabilities uncached, no Cache-Control (BUG-API-039)
/api/v1/capabilities no Last-Modified (BUG-API-311)
Enumeration: rg -F 'capabilities' internal/handlers/capabilities.go (1 emit Get)
rg -F 'NewCapabilitiesHandler' internal/router/router.go
Sites found: 1
Sites touched: 1
Coverage test: TestCapabilities_CacheControlPublicMaxAge60 asserts the exact
'public, max-age=60, must-revalidate' string on the 200 path.
Live verified: pending auto-deploy + curl -I https://api.instanode.dev/api/v1/capabilities | grep -i cache-control
```

Inbox reference

  • BUG-API-039 (P2 — /api/v1/capabilities uncached, no Cache-Control)
  • BUG-API-311 (P2 — /api/v1/capabilities no Last-Modified)

Caching + consistency tradeoff (per memory rule)

  • Staleness window: 60s (max-age). `must-revalidate` blocks stale-while-revalidate proxies from serving indefinitely-stale rows after extended offline.
  • Real-world change cadence: tier matrix changes only with plans.yaml + redeploy; rule-23 deploy cycle is minutes, so 60s is well below the user-observable change window.
  • No user discrimination: response is identical for every caller, so `public` is safe.

Test plan

🤖 Generated with Claude Code

…PI-039/311)

/api/v1/capabilities is dashboard-hit on every navigation (sidebar tile
counts, billing card, settings page) but the tier matrix is immutable
for the life of the running pod — it only changes on a plans.yaml edit
+ redeploy. Without a Cache-Control hint each nav re-fetched the full
~4 KB matrix; sidebar fanout meant 4-6 redundant fetches per nav
(see BUG-DASH-016).

Stamp `public, max-age=60, must-revalidate` so browser/edge caches serve
the matrix for a minute while still re-validating on expiry. The rule-23
deploy cycle flips the /healthz commit_id which invalidates the proxy
cache shortly after a plans.yaml change ships, so the 60s ceiling is
well below the user-observable change window.

Coverage block:
  Symptom:        /api/v1/capabilities uncached, no Cache-Control (BUG-API-039)
                  /api/v1/capabilities no Last-Modified (BUG-API-311)
  Enumeration:    rg -F 'capabilities' internal/handlers/capabilities.go
                  rg -F 'NewCapabilitiesHandler' internal/router/router.go
                  (1 emit site — internal/handlers/capabilities.go Get)
  Sites found:    1
  Sites touched:  1
  Coverage test:  TestCapabilities_CacheControlPublicMaxAge60 asserts the
                  exact `public, max-age=60, must-revalidate` string on
                  the 200 path so a future deletion fails before merge.
  Live verified:  pending auto-deploy + `curl -I https://api.instanode.dev/api/v1/capabilities | grep -i cache-control`

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mastermanas805 mastermanas805 force-pushed the bug-api-039-capabilities-cache branch from 0e5fa78 to 6dba22a Compare May 30, 2026 08:50
@mastermanas805 mastermanas805 merged commit bc7cc64 into master May 30, 2026
14 checks passed
@mastermanas805 mastermanas805 deleted the bug-api-039-capabilities-cache branch May 30, 2026 09:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant