Core Data: Cache-bust refetches of an already received resolution - #81938
Draft
adamsilverstein wants to merge 2 commits into
Draft
adamsilverstein wants to merge 2 commits into
adamsilverstein wants to merge 2 commits into
Conversation
A resolver re-runs for a resolution it has already resolved only after an invalidation, which means the data is believed to have changed on the server. Some hosts cache REST responses keyed on the full request URL, even authenticated ones WordPress marks no-cache, and serve such a refetch the very response the invalidation is trying to replace: a client-side media upload refetches the attachment record with the same URL it requested before the sub-sizes were generated, so the Image block's Resolution control never appears. Append a cache-busting argument to these refetches so they reach the server. First requests are left untouched and stay cacheable. See #81844.
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
|
Size Change: +81 B (0%) Total Size: 7.75 MB 📦 View Changed
|
adamsilverstein
marked this pull request as draft
August 21, 2026 21:27
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.
Another round with Claude on #81844, this time chasing the cache angle:
See #81844 - the response-ordering guards in #81846/#81886 close a real race, but the behavior reported there (stale
media_details.sizesserved consistently, surviving a reload) points at the refetch itself being served stale data. This is the client-side hardening for that case.Note
Stacked on #81886 (in turn stacked on #81846) - only the last commit here is new.
What?
getEntityRecordandgetEntityRecordsnow append a cache-busting argument to a request made after the same resolution has already received a response. First requests are untouched and stay cacheable.Why?
A resolver only re-runs for a resolution it has already resolved after an invalidation - which means the data is believed to have changed on the server. Some hosts cache REST responses keyed on the full request URL, even authenticated ones WordPress marks
no-cache. Such a cache serves an invalidation-triggered refetch the very response the invalidation is trying to replace, because the refetch uses the exact same URL as the request that populated the cache.Client-side media uploads are where this bites. The attachment record is fetched while sub-sizes are still being generated -
media_details.sizesis empty until thefinalizerequest writes them - and the post-upload refetch asks for the same URL. Served the stale copy, the store keeps an attachment without sizes, the Image block's Resolution control never appears, and nothing invalidates it afterwards. The ordering guards cannot help here: the newest response is the stale one.Worth noting the limit up front: this protects refetches only. A fresh editor load's first request still uses the plain URL, so a cache entry poisoned mid-upload can serve it until the entry expires. That part is not fixable client-side - caching authenticated REST responses against their
no-cacheheaders is a hosting misconfiguration - but this change keeps the current session correct instead of leaving the stale copy in charge of it.How?
The
lastReceivedResponsebookkeeping added in #81846 already records, per registry and resolution, that a response has been received. A request whose resolution is already recorded there is a refetch, and gets_cacheBust=<timestamp>-<sequence>appended - to the request path only, never to the query used for store keys, so resolution state and stable keys are unchanged. The REST API ignores unknown parameters.getEntityRecordsfetch branches; the pages of a progressive run share it.Testing Instructions
All tests were verified to fail without the change and pass with it.
Unit - refetches are busted, first and unrelated requests are not:
E2E - simulates a full-URL-keyed cache in front of
wp-json(every attachment GET is served from a cache once a response for that exact URL has been seen) and uploads through the real client-side pipeline:Manual: insert an Image block, upload a JPEG, and watch the Network tab filtered on
/wp/v2/media. The attachment GET issued mid-upload uses the plain URL; the refetch after the upload completes carries_cacheBust=.... The Resolution control appears in the block's Settings panel once the refetch lands.AI Use
Code and description written with 🤖 Claude Code. I will review and test.