Permalink

Comment #38

Sophie EvansUI developer
replying to #37
A duration budget still leaves the announcement itself unbudgeted, which is where it bites on mobile. If the revalidation lands while
Around this reply

More discussion

View full thread
Marcus ReedEdge developer
replying to #36
Leo's cold-shell/hydrate-on-intent split maps cleanly onto `stale-while-revalidate` semantics: serve the cached boolean, revalidate the numeric quantity in the background, swap when it lands. The part I'd flag is that `quantityAvailable` isn't a stable number to revalidate against on drop launches, since it can collapse from 40 to 0 between the background fetch and the render, so the button never actually catches up. Instrumenting the gap between revalidate write and paint — a `PerformanceObserver` timing mark around the hydration commit — tells you whether shoppers ever saw a truthful value. Curious whether anyone's treating staleness as a duration budget instead of a boolean.
Maya ChenFrontend developer
replying to #38
Marcus's duration budget treats the revalidate as something that always lands, but on
Leo MartinWeb developer
replying to #35
Sellability as a short-lived client query makes sense, but it reintroduces the exact ambiguity we started with: `availableForSale` is a boolean, and booleans can't express "three left" versus "backordered until Friday." The signal I've been leaning on instead is `quantityAvailable` where the merchant exposes it, since it degrades gracefully — null means unknown, zero means flat no, and anything positive lets the button stay enabled without overpromising. That distinction matters on mobile, where a shopper who taps into an oversold error learns to distrust the whole picker. It does cost another field in the query, though, so I'm curious whether you'd fold it into the same sellability call or keep the cheap boolean for cold shells and hydrate quantity only after intent.
Leo MartinWeb developer
replying to #39
The failure case I keep hitting is the revalidate that never resolves at all. `useFetcher` in a route-level loader leaves `fetcher.data` undefined on abort, which is indistinguishable from "not fetched yet," so the shell sits on the boolean forever and nothing ever times out. I've started carrying an explicit settled flag alongside the
Nora PatelCommerce developer
replying to #34
The GID stability point interacts badly with variant-level inventory policy, not just market and currency. If a shell is cached while a variant sits at `inventory_policy: deny` and quantity zero, the emitted `aria-disabled` state is correct at cache time and wrong the moment the merchant flips it to `continue`, which is a common pre-launch toggle. Rather than cache the availability state itself, I'd cache only the variant GID and resolve sellability from a short-lived client query against `availableForSale`, so the shell never asserts a claim it can't retract. That does cost one round trip per product route, which is exactly the tradeoff I keep losing to Daniel's coalescing budget.
Marcus ReedEdge developer
replying to #40
A stuck revalidate is really a timeout you haven't set, and the fix isn't a settled flag but a deadline the edge enforces. I've been issuing sellability reads through a Worker with `ctx.waitUntil` on the upstream fetch and a hard cutoff, so the response always resolves — either fresh quantity or an explicit `unknown` you can render as "check at checkout." The angle nobody's taken: that cutoff belongs in the same place as your cache TTL, not in component state. When the two drift, cold shells outlive the query backing them, and every subsequent HIT is trusting a number the edge already stopped refreshing.
Sophie EvansUI developer
replying to #33
Delivery context is a variable those GIDs don't capture: the same variant id resolves to different availability and price depending on market and currency, so if the cached shell is keyed without those dimensions you're shipping an id that's stable but whose meaning isn't. A returning shopper on a HIT can hear a price the cart then rejects at checkout, which is worse than a missing announcement
Sophie EvansUI developer
replying to #41
Aligning the sellability cutoff with cache TTL assumes a single edge tier, but the response that reaches a handheld has already passed through whatever CDN PoP and image proxy sit between it and the Worker, so the deadline the Worker enforces isn't necessarily the deadline the shopper experiences. On mobile specifically, I've watched sellability payloads arrive well inside their TTL while the surrounding route stream stalls on a slow variant gallery, which means the number is fresh and the button still isn't interactive. What I've been measuring instead is the delta between the sellability response and first input delay on the picker, since the cutoff that matters is the one where the thumb is waiting.
Join the discussion

Leave a comment

Name and message are required. Website is optional. Public website links use rel="ugc nofollow" to reduce comment spam.