fix(useSection): key lazy-section cache on block content, not release revision
Why
useSection builds the /deco/render URL with __cb = hash(release revision, vary, href, deploymentId). The release revision changes on every CMS publish, even a decofile-only publish that doesn't redeploy. So every publish changes the URL of every lazy section on every page, and the CDN entries already warm under max-age=300, stale-while-revalidate=3600 are thrown away.
Measured on miess-01 (2026-10-13, 10:00–21:00Z, Cloudflare logs for www.miess.com.br):
- 33 publishes in bursts. Only 1 of them redeployed; the rest were decofile-only hot-reloads.
/deco/renderhit rate was about 33–41% in quiet windows and fell to 13–20% during publish bursts.- Misses where the same render URL minus
__cbhad been requested in the previous 65 minutes under a different__cb:- ~72.8k of 174k render misses (~42%), about 364 MB of origin egress plus 72.8k extra origin SSR renders.
- 7–12k per hour in burst hours, against about 400 per hour with no publishes.
- That's roughly 3k extra origin renders and ~15 MB per publish.
- Most of those keys are PDP/PLP lazy sections whose own page didn't change. A home banner publish invalidated all of them.
What
The global revision is replaced with a content version: a hash of the named blocks (resolvable entries) on the section's resolve chain, for example pages-category-…, plus any named section block the section is resolved through.
- Block hashes are memoized per block object. Decofile providers replace changed blocks with freshly parsed objects and keep identity for unchanged ones; no in-place mutation.
- If the chain has no named block, it falls back to the revision, so behavior is the same as today there.
deploymentId,varyandhrefstay in the key, so a deploy still busts everything.
Same-shell semantics are unchanged:
- A stale HTML shell still points at a key whose content hash differs whenever its page changed. That includes index shifts in
sections, because the page block's content changes. - The server still renders from the current decofile, exactly as today on a miss.
Trade-off: a change to a named block that is referenced from a section's props but isn't on its resolve chain (e.g. a shared loader config) no longer busts that section's render URL. It refreshes through the normal max-age=300 + SWR revalidation, the same freshness HTML pages already have.
Tests
hooks/useSection.test.tsx: a new block-content__cbsuite, 4 steps:- stable when another block is published;
- changes when a block on the chain changes;
- changes with the deployment;
- falls back to the revision.
- The new steps fail on
main(2 of 4) and pass with this change. - Full suite: 85 passed, 0 failed.
Not validated yet (why this is a draft)
- No end-to-end run on a real site. That needs a site pinned to this branch and a check that, after a decofile-only publish, unchanged pages keep their
__cbwhile the edited page's sections get a new one. - No production measurement of hit rate after rollout.
Summary by cubic
Keys the lazy-section cache on the content of the blocks on the section's resolve chain instead of the global release revision, so a CMS publish that doesn't change a page no longer invalidates that page's warm CDN entries.
- The
__cbhash now covers the named blocks the section resolves through (e.g. the page), with hashes memoized per block object. - Falls back to the release revision when the chain has no named blocks;
deploymentId,vary, andhrefremain in the key. - Trade-off: changes to named blocks referenced in props but not on the resolve chain skip the immediate cache bust and refresh via the normal 300s TTL + stale-while-revalidate.
- Adds tests covering stability across unrelated publishes, invalidation on block or deployment changes, and the revision fallback.