← 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
M 5x/clickthrough.mjsM server.js
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 →