Skip to content

fix(vtex): cache bounded legacy map= PLP shapes, keep deep facet crawl uncached - #1687

Draft
pedrofrxncx wants to merge 2 commits into
mainfrom
fix/legacy-plp-cachekey-map
Draft

pedrofrxncx wants to merge 2 commits into
mainfrom
fix/legacy-plp-cachekey-map

Conversation

@pedrofrxncx

@pedrofrxncx pedrofrxncx commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

Why

#1570 made the legacy PLP cacheKey return null for any URL containing map=. deco treats a null key as no-store, so every legacy ?map= page bypasses the CDN, including the clean ones like brand links (/<brand>?map=b) and category+brand pages (/a/b?map=c,b).

The reason for #1570 (thanks @guitavano) was that bots crawl endless filter combinations. Each one is a one-off URL, and caching them pushed hot entries out of the loader cache. This PR keeps that protection and only re-enables caching for shapes with bounded cardinality.

Data (miess, Cloudflare, last 24h, GET ?map= pages)

Shape Requests Unique URIs Reuse
≥3 map parts, spec filters, priceFrom, ft, or map not matching the path 44,385 42,824 ~1.0
≤2 parts, only c/b, matching the path 3,140 1,477 ~2.1
any shape with q/ft search param 2,362 2,307 ~1.0

So caching the deep combinations buys nothing and only churns the cache. The bounded shapes repeat.

Change

  • map= URLs get a key only when the map has ≤2 parts, every part is c or b, and the part count matches the path segment count. Everything else still returns null, same as today.
  • Adds fmap and PS to the key, only when present. The loader reads both from the URL: fmap drives the facets query and PS the page size. Keys for URLs without them are byte-identical to before.
  • Search terms not in cachedSearchTerms still return null.

Tests

productListingPage_test.ts:

  • /brand?map=b and /cat/brand?map=c,b get keys, and different maps get different keys
  • deep (c,c,c), specificationFilter_*, priceFrom, ft, and mismatched map/path stay null
  • fmap/PS vary the key
  • keys for URLs without map/fmap/PS exactly match the current output
  • uncached search terms stay null

deno fmt --check, deno lint and deno check vtex/mod.ts are clean.

Not done yet

Draft until it's validated on a miess-01 preview pinned to this commit, compared against production on the same URLs.

The deep facet crawl (44k req/day, ~1.9 GB) stays uncached. Reducing that is a robots.txt / bot-rule decision, not a cache one.

#1570 made cacheKey return null for any URL containing "map=", to avoid
stale faceted results. A null key makes deco mark the whole page
no-store, so every legacy ?map= URL (brand links /<brand>?map=b,
category+brand /a/b?map=c,b, static-filter facet links) is uncacheable
at the CDN.

The key already varies on map. What it was missing are two inputs the
loader reads straight from the URL: fmap, which drives the facets query
(and which static-filter facet links set alongside map), and PS, the
page size. Add both to the key (only when present, so existing keys are
unchanged) and drop the map bail-out. Uncached search terms still
return null.
@github-actions

Copy link
Copy Markdown
Contributor

Tagging Options

Should a new tag be published when this PR is merged?

  • 👍 for Patch 0.165.4 update
  • 🎉 for Minor 0.166.0 update
  • 🚀 for Major 1.0.0 update

@coderabbitai

coderabbitai Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 11173fa2-1bde-4b75-884f-6107243a9574
📥 Commits

Reviewing files that changed from the base of the PR and between a00cfd6 and 5644f10.

📒 Files selected for processing: 2
  • vtex/loaders/legacy/productListingPage.ts
  • vtex/loaders/legacy/productListingPage_test.ts

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📝 Walkthrough

The product listing cache key now includes fmap and PS values when present. Legacy map URLs can produce cache keys, while search terms absent from ctx.cachedSearchTerms still return null. Tests cover these behaviors and expected keys for other URL parameters.

Changes: Product listing cache keys

Layer / File(s) Summary
Cache-key construction and validation
vtex/loaders/legacy/productListingPage.ts, vtex/loaders/legacy/productListingPage_test.ts
cacheKey no longer bypasses caching for legacy map URLs. It includes fmap and PS in the key when present, and returns null when a search term is absent from ctx.cachedSearchTerms. Tests cover these cases and expected keys for URLs without those parameters.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~8 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to 5644f

No confirmed issue blocks merging. The cache’s handling of request-specific navigation URLs remains unverified.

Pre-merge checks: Passed 5
Passed Passed checks: 5 passed
Check name Status Explanation
Docstring Coverage Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 2…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Title check Passed The title clearly identifies the main change: bounded caching for legacy map= PLP shapes while keeping deep facet crawls uncached.
Description check Passed The description clearly explains the motivation, data, implementation, tests, validation status, and remaining work. It does not include the template's Issue Link, Loom Video, or Demonstration Link se…
✨ Finishing Touches: 💡 1
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
🛠️ Fix failing CI checks: 💡
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="vtex/loaders/legacy/productListingPage.ts">

<violation number="1" location="vtex/loaders/legacy/productListingPage.ts:453">
P2: Removing the map bypass lets a PLP with `props.ft` cache without checking that term against `cachedSearchTerms`; the loader uses `props.ft` as its effective full-text term. Apply the allowlist check to the effective term so unlisted searches remain uncached.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

hasMap ||
(searchTerm && !cachedSearchTerms.includes(searchTerm.toLowerCase()))
) {
if (searchTerm && !cachedSearchTerms.includes(searchTerm.toLowerCase())) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Removing the map bypass lets a PLP with props.ft cache without checking that term against cachedSearchTerms; the loader uses props.ft as its effective full-text term. Apply the allowlist check to the effective term so unlisted searches remain uncached.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At vtex/loaders/legacy/productListingPage.ts, line 453:

<comment>Removing the map bypass lets a PLP with `props.ft` cache without checking that term against `cachedSearchTerms`; the loader uses `props.ft` as its effective full-text term. Apply the allowlist check to the effective term so unlisted searches remain uncached.</comment>

<file context>
@@ -449,12 +449,8 @@ export const cacheKey = (props: Props, req: Request, ctx: AppContext) => {
-    hasMap ||
-    (searchTerm && !cachedSearchTerms.includes(searchTerm.toLowerCase()))
-  ) {
+  if (searchTerm && !cachedSearchTerms.includes(searchTerm.toLowerCase())) {
     return null;
   }
</file context>
Suggested change
if (searchTerm && !cachedSearchTerms.includes(searchTerm.toLowerCase())) {
const effectiveSearchTerm = props.ft || searchTerm;
if (
effectiveSearchTerm &&
!cachedSearchTerms.includes(effectiveSearchTerm.toLowerCase())
) {

@pedrofrxncx
pedrofrxncx marked this pull request as draft October 14, 2026 17:01
Deep facet combinations, spec filters, price ranges and ft text segments
are bot crawl space with ~1.0 reuse; caching them evicts hot entries.
Cache only up to 2 c/b map segments that match the path.
@pedrofrxncx pedrofrxncx changed the title fix(vtex): key legacy PLP cache on fmap/PS instead of skipping map URLs fix(vtex): cache bounded legacy map= PLP shapes, keep deep facet crawl uncached Oct 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant