API: 1d fresh + 7d stale-while-revalidate (auto-invalidate on art changes) - #166
Merged
Conversation
The API used to mark every render `immutable, max-age=31536000` — fine for a deterministic render pre-sub-animations, wrong now that sprite art can change on the same ID. After PR #156 shipped new sprite sheets, `/browse` and `/bot/[id]` kept serving pre-animation GIFs from the CDN until a manual dashboard purge. New policy: `public, max-age=86400, stale-while-revalidate=604800`. - 1 day fresh — CDN + browser serve instantly, no revalidation. - 7 days stale — stale content still served, background refetch triggers a new render. Art updates propagate within a day of deploy. - 30 days past stale window — cold render. Manual CDN purge is still available for urgent changes. This just removes the requirement to do it every time. - `app/src/lib/api.ts`: exported as `DETERMINISTIC_CACHE`. Applied to `imageResponse()` (PNG / GIF / WebP). - `/api/pixabot/{id}` SVG branch: same header (was hardcoded). - `/api/pixabot/batch` deterministic response: same. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
pablostanley
added a commit
that referenced
this pull request
Apr 20, 2026
PR #165 added the frames metadata endpoint with a hand-rolled `immutable` Cache-Control header — the exact policy PR #166 just moved every other deterministic endpoint away from. Make it consistent so animVersion bumps propagate within ~1 day without a manual purge. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
pablostanley
added a commit
that referenced
this pull request
Apr 20, 2026
PR #165 added the frames metadata endpoint with a hand-rolled `immutable` Cache-Control header — the exact policy PR #166 just moved every other deterministic endpoint away from. Make it consistent so animVersion bumps propagate within ~1 day without a manual purge. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
pablostanley
added a commit
that referenced
this pull request
Apr 20, 2026
PR #166 swapped the deterministic cache header from 1-year immutable to 1-day fresh + 7-day stale-while-revalidate. The ?v= versioning story we shipped in PRs #164–#165 assumed the old immutable headers, so the docs overclaimed how long stale animations linger. Updates: - api.mdx intro / embedding blurb / caching section reflect the SWR window (≤ 1 day fresh, up to 8 days long-tail). - Animation-versioning section frames ?v=N as the escape hatch for instant propagation rather than "the only way out of an immutable trap." - openapi.json descriptions match. - Root CLAUDE.md points agents at DETERMINISTIC_CACHE in app/src/lib/api.ts. No code changes — /frames route was already switched to DETERMINISTIC_CACHE in PR #168. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 tasks
pablostanley
added a commit
that referenced
this pull request
Apr 20, 2026
PR #166 swapped the deterministic cache header from 1-year immutable to 1-day fresh + 7-day stale-while-revalidate. The ?v= versioning story we shipped in PRs #164–#165 assumed the old immutable headers, so the docs overclaimed how long stale animations linger. Updates: - api.mdx intro / embedding blurb / caching section reflect the SWR window (≤ 1 day fresh, up to 8 days long-tail). - Animation-versioning section frames ?v=N as the escape hatch for instant propagation rather than "the only way out of an immutable trap." - openapi.json descriptions match. - Root CLAUDE.md points agents at DETERMINISTIC_CACHE in app/src/lib/api.ts. No code changes — /frames route was already switched to DETERMINISTIC_CACHE in PR #168. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
pablostanley
added a commit
that referenced
this pull request
Apr 20, 2026
… cache policy
Rolls the important stuff from this long session into the living docs
so next-agent (or next-me) doesn't have to reread the whole thread.
CLAUDE.md
- **Key conventions**: replace the old 8-frame-bounce line with the
16-tick super-loop model; add sub-animation `kind` (static/blink/
sequence) + `resolveFrameIndex` as the one source for frame picks;
document `TOTAL_COMBOS_LABEL` as the single-source for the count;
add the keydown `hasModifier` rule (earned from the ⌘R bug).
- **Adding new parts**: split static vs animated workflows. Static
is flat PNG + stitcher copy-through. Animated uses subdir layouts
(blink: open/closed pair, sequence: numbered) that the stitcher
detects automatically; updated the parts.ts entry shape
(`'name'` vs `{ name, frames, kind }`).
- **npm**: drop the stale "CLI token caveat" note — first-publish
is done, token allow-list extended.
- **API**: refresh the endpoint list (frames metadata, batch, palette
+ bg params); document the 1d fresh / 7d SWR cache policy and the
same-origin rate-limit bypass.
ROADMAP.md
- Appends Done entries for PR #158 (⌘R guard), #160 (SW bump),
#162 (TOTAL_COMBOS dedupe), #166/#168/#169 (cache revalidate),
and #170 (browse 429s). Each entry includes the "why we needed it"
so future readers see the failure mode, not just the fix.
Memory (not in this commit; lives outside the repo):
- New `feedback_keyboard_modifier_guard.md` — the ⌘R lesson promoted
to a rule.
- New `project_animation_infra.md` — the sub-animation mental model.
- Updated `project_npm_published.md` with current versions of core /
react / cli.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
pablostanley
added a commit
that referenced
this pull request
Apr 20, 2026
… cache policy (#171) Rolls the important stuff from this long session into the living docs so next-agent (or next-me) doesn't have to reread the whole thread. CLAUDE.md - **Key conventions**: replace the old 8-frame-bounce line with the 16-tick super-loop model; add sub-animation `kind` (static/blink/ sequence) + `resolveFrameIndex` as the one source for frame picks; document `TOTAL_COMBOS_LABEL` as the single-source for the count; add the keydown `hasModifier` rule (earned from the ⌘R bug). - **Adding new parts**: split static vs animated workflows. Static is flat PNG + stitcher copy-through. Animated uses subdir layouts (blink: open/closed pair, sequence: numbered) that the stitcher detects automatically; updated the parts.ts entry shape (`'name'` vs `{ name, frames, kind }`). - **npm**: drop the stale "CLI token caveat" note — first-publish is done, token allow-list extended. - **API**: refresh the endpoint list (frames metadata, batch, palette + bg params); document the 1d fresh / 7d SWR cache policy and the same-origin rate-limit bypass. ROADMAP.md - Appends Done entries for PR #158 (⌘R guard), #160 (SW bump), #162 (TOTAL_COMBOS dedupe), #166/#168/#169 (cache revalidate), and #170 (browse 429s). Each entry includes the "why we needed it" so future readers see the failure mode, not just the fix. Memory (not in this commit; lives outside the repo): - New `feedback_keyboard_modifier_guard.md` — the ⌘R lesson promoted to a rule. - New `project_animation_infra.md` — the sub-animation mental model. - Updated `project_npm_published.md` with current versions of core / react / cli. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
API renders were tagged `Cache-Control: immutable` — fine back when `/api/pixabot/{id}` was truly deterministic forever. PR #156 broke that assumption: sprite art can now change on the same ID. Yesterday's purge was the manifestation.
What
Replace `immutable, max-age=31536000` with `max-age=86400, stale-while-revalidate=604800` for all deterministic image + SVG + JSON responses.
Translation: after an art change, within ~1 day of traffic on a given URL, the cache has the new render. Manual dashboard purge still works for urgent rollout.
Scope
Random endpoints (`/api/pixabot/random`) keep `no-store` — they're not deterministic.
Test plan
🤖 Generated with Claude Code