store: catalog fetch uses force-cache, so a rebuild can verify against a stale catalog #64

Closed
opened 2026-08-28 01:13:59 +00:00 by yuris · 0 comments
Owner

Surfaced by Author44b and flagged for propagation by Reviewer56r1 during PR #62. Filed because it generalises well beyond that PR.

The trap

apps/store/lib/catalog.ts fetches the catalog with cache: "force-cache". So a rebuild can serve a stale catalog and render a previous run's data.

That is fine — arguably correct — for production builds, where the catalog is fetched once per deploy. It is a problem for verification, because it silently invalidates a check that looks conclusive.

Why it matters more than it sounds

Most PRs in this session's three waves were verified, at least in part, by reading storefront output:

  • #47 read chip colours, JSON-LD availability states and the WhatsApp message out of a built export.
  • #46 read facet counts and URL round-trips out of a built /products.
  • #54 and #52 measured computed CSS values on rendered pages.
  • #63 built a fixture from real production data and asserted on built HTML.
  • #62 rebuilt the storefront to confirm an uploaded image actually decoded.

In every one of those, the reviewer or author changed a fixture, rebuilt, and read the result. With force-cache, the first such rebuild after a fixture change can render the previous fixture — and the check passes or fails for the wrong reason. It fools you exactly once, which is the worst frequency: often enough to matter, rare enough to look like a flake.

No agent was caught by it in a way that changed a verdict, as far as I can tell. That is luck, not process.

What to do

This is not obviously a code bug — the caching may be exactly what production wants. The deliverable is that the verification procedure stops being silently wrong. Options, in rough order of preference:

  1. Make freshness explicit at build time. If the catalog fetch can key on something that changes per build (the catalog's own generatedAt, a build id, or an explicit revalidate), a stale read becomes impossible rather than merely unlikely.
  2. Document the defeat. Wherever the rebuild/verification steps live, record that a fixture change requires defeating the cache — and how (clear .next/cache, vary the fixture URL, or set the relevant env). Any agent or human verifying storefront output needs this before they trust a rendered result.
  3. Assert freshness in the check itself. Have verification read something from the built output that identifies which fixture produced it, so a stale render is self-evident instead of invisible.

Option 2 is the minimum and should happen regardless of whether 1 or 3 is adopted.

Scope note

Do not change caching behaviour purely to make verification easier without confirming what production needs. force-cache on a static export fetched once per deploy is a reasonable choice; the defect is that nothing warns a verifier about it.

Acceptance

The verification path is either provably fresh or explicitly documented as needing a cache defeat; anyone reading storefront output to verify a change can tell which fixture produced it.

Surfaced by `Author44b` and flagged for propagation by `Reviewer56r1` during PR #62. Filed because it generalises well beyond that PR. ## The trap `apps/store/lib/catalog.ts` fetches the catalog with `cache: "force-cache"`. So **a rebuild can serve a stale catalog and render a previous run's data.** That is fine — arguably correct — for production builds, where the catalog is fetched once per deploy. It is a problem for **verification**, because it silently invalidates a check that looks conclusive. ## Why it matters more than it sounds Most PRs in this session's three waves were verified, at least in part, **by reading storefront output**: - #47 read chip colours, JSON-LD availability states and the WhatsApp message out of a built export. - #46 read facet counts and URL round-trips out of a built `/products`. - #54 and #52 measured computed CSS values on rendered pages. - #63 built a fixture from real production data and asserted on built HTML. - #62 rebuilt the storefront to confirm an uploaded image actually decoded. In every one of those, the reviewer or author changed a fixture, rebuilt, and read the result. With `force-cache`, **the first such rebuild after a fixture change can render the previous fixture** — and the check passes or fails for the wrong reason. It fools you exactly once, which is the worst frequency: often enough to matter, rare enough to look like a flake. No agent was caught by it in a way that changed a verdict, as far as I can tell. That is luck, not process. ## What to do This is not obviously a code bug — the caching may be exactly what production wants. The deliverable is that **the verification procedure stops being silently wrong**. Options, in rough order of preference: 1. **Make freshness explicit at build time.** If the catalog fetch can key on something that changes per build (the catalog's own `generatedAt`, a build id, or an explicit revalidate), a stale read becomes impossible rather than merely unlikely. 2. **Document the defeat.** Wherever the rebuild/verification steps live, record that a fixture change requires defeating the cache — and how (clear `.next/cache`, vary the fixture URL, or set the relevant env). Any agent or human verifying storefront output needs this before they trust a rendered result. 3. **Assert freshness in the check itself.** Have verification read something from the built output that identifies *which* fixture produced it, so a stale render is self-evident instead of invisible. Option 2 is the minimum and should happen regardless of whether 1 or 3 is adopted. ## Scope note Do **not** change caching behaviour purely to make verification easier without confirming what production needs. `force-cache` on a static export fetched once per deploy is a reasonable choice; the defect is that nothing warns a verifier about it. ## Acceptance The verification path is either provably fresh or explicitly documented as needing a cache defeat; anyone reading storefront output to verify a change can tell which fixture produced it.
yuris closed this issue 2026-08-28 03:00:07 +00:00
Sign in to join this conversation.
No labels
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
yuris/garage#64
No description provided.