[object Object]

← back to Dw Pairs Well

5x sweep 4 (contrarian FIX FIRST): no-store on all product-link-carrying responses — link guarantee now enforced at serve time; clickthrough gains real terminal assertions + unknown-SKU error-state coverage

f2f2ae64d52fac16ed7ec68db317f058fe760cd3 · 2026-07-13 01:20:05 -0700 · Steve Abrams

Files touched

Diff

commit f2f2ae64d52fac16ed7ec68db317f058fe760cd3
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon Jul 13 01:20:05 2026 -0700

    5x sweep 4 (contrarian FIX FIRST): no-store on all product-link-carrying responses — link guarantee now enforced at serve time; clickthrough gains real terminal assertions + unknown-SKU error-state coverage
---
 5x/clickthrough.mjs | 18 ++++++++++++++++--
 server.js           | 14 ++++++++++----
 2 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/5x/clickthrough.mjs b/5x/clickthrough.mjs
index 1c6d0ed..ed1ab9f 100644
--- a/5x/clickthrough.mjs
+++ b/5x/clickthrough.mjs
@@ -83,9 +83,23 @@ await step('paint-brand checkbox toggles cleanly', async () => {
   await cb.click(); await page.waitForTimeout(400); await cb.click();
 });
 
-await step('second sample chip → grid swaps, still error-free', async () => {
+await step('second sample chip → grid swaps with real cards', async () => {
+  const prevTitle = await page.locator('#product-title').textContent();
   await page.locator('button[data-sku]').nth(3).click();
-  await page.waitForTimeout(2500);
+  await page.waitForFunction(prev => {
+    const t = document.querySelector('#product-title');
+    return t && t.textContent.trim().length > 3 && t.textContent !== prev;
+  }, prevTitle, { timeout: 25000 });
+  await page.waitForFunction(() => {
+    const g = document.getElementById('catalog-grid');
+    return g && !g.hidden && g.querySelectorAll('a[href*="/products/"], img').length > 0;
+  }, null, { timeout: 25000 });
+});
+
+await step('unknown SKU → graceful error state, no console errors', async () => {
+  await page.fill('#sku', 'NOPE-0000000');
+  await page.locator('#load').click();
+  await page.waitForTimeout(2500);   // UI must absorb the 404 without throwing
 });
 
 await browser.close();
diff --git a/server.js b/server.js
index 9b32216..f746c93 100644
--- a/server.js
+++ b/server.js
@@ -807,7 +807,10 @@ app.get('/api/colorways', async (req, res) => {
       }))
       .sort((a, b) => String(a.color_name).localeCompare(String(b.color_name)));
 
-    res.set('Cache-Control', 'public, max-age=300');
+    // no-store: this response carries /products/ links whose ACTIVE+published gate is
+    // checked at GENERATION time — caching would let an archived product serve a dead
+    // link for the TTL window (contrarian finding, 2026-07-13).
+    res.set('Cache-Control', 'no-store');
     res.json({
       ok: true,
       pattern_id: key,
@@ -972,7 +975,8 @@ app.get('/api/collection-grouped', async (req, res) => {
     const start = (page - 1) * per;
     const slice = arr.slice(start, start + per);
 
-    res.set('Cache-Control', 'public, max-age=180');
+    // no-store: carries product_url links — see link-guarantee cache note on /api/colorways.
+    res.set('Cache-Control', 'no-store');
     res.json({
       ok: true,
       collection: vendor ? { vendor } : { all: true },
@@ -1052,7 +1056,8 @@ app.get('/api/similar', async (req, res) => {
     }
     const paletteWithPaints = hexList => hexList.map(h => ({ hex: h, paints: paintsFor(h) }));
 
-    res.set('Cache-Control', 'public, max-age=300');
+    // no-store: carries /products/ links — see link-guarantee cache note on /api/colorways.
+    res.set('Cache-Control', 'no-store');
     res.json({
       ok: true,
       engine: usedEngine,
@@ -1162,7 +1167,8 @@ app.get('/api/pairs', async (req, res) => {
       return hexList.map(h => ({ hex: h, paints: paintsFor(h) }));
     }
 
-    res.set('Cache-Control', 'public, max-age=300');
+    // no-store: carries /products/ links — see link-guarantee cache note on /api/colorways.
+    res.set('Cache-Control', 'no-store');
     res.json({
       ok: true,
       engine: usedEngine,

← 5a3ae69 5x sweeps 2-3 clean (2 consecutive) — REPORT.md; stop condit  ·  back to Dw Pairs Well  ·  5x sweep 5: color+texture lock in clipSimilarTop (CLIP cosin 0d36db3 →