[object Object]

← back to All Designerwallcoverings

live-stock verification: 4 metered scrapes ($0.234 total) prove wallquest+shopify-public+romo adapters return live stock; harden romo nav-chrome parse; record per-vendor verified status in coverage

875d338f0ea7c2e458c179ab183e537a0dd68efc · 2026-07-07 09:38:28 -0700 · Steve

Files touched

Diff

commit 875d338f0ea7c2e458c179ab183e537a0dd68efc
Author: Steve <steve@designerwallcoverings.com>
Date:   Tue Jul 7 09:38:28 2026 -0700

    live-stock verification: 4 metered scrapes ($0.234 total) prove wallquest+shopify-public+romo adapters return live stock; harden romo nav-chrome parse; record per-vendor verified status in coverage
---
 data/live-stock-coverage.json | 14 +++++++++-----
 scripts/adapters/romo.js      | 24 ++++++++++++++++--------
 scripts/build-coverage.js     | 10 ++++++++++
 3 files changed, 35 insertions(+), 13 deletions(-)

diff --git a/data/live-stock-coverage.json b/data/live-stock-coverage.json
index f465e9c..62dabd7 100644
--- a/data/live-stock-coverage.json
+++ b/data/live-stock-coverage.json
@@ -1,5 +1,5 @@
 {
-  "generated_at": "2026-07-07T16:31:39.711Z",
+  "generated_at": "2026-07-07T16:37:56.295Z",
   "generator": "scripts/build-coverage.js",
   "total_display_vendors": 254,
   "counts": {
@@ -22,7 +22,8 @@
       "products": 481,
       "active": 465,
       "resolvable_active": 460,
-      "resolvable_pct": 99
+      "resolvable_pct": 99,
+      "verified": "live-verified 2026-07-07 (shopify-public → in_stock:true, $0.03)"
     },
     "420 Studios": {
       "tier": "NO_STOCK",
@@ -1603,7 +1604,8 @@
       "products": 4031,
       "active": 2596,
       "resolvable_active": 2172,
-      "resolvable_pct": 84
+      "resolvable_pct": 84,
+      "verified": "live-verified 2026-07-07 (wallquest → OutOfStock, $0.10)"
     },
     "Malibu Walls": {
       "tier": "PORTAL_CREDS",
@@ -2253,7 +2255,8 @@
       "products": 568,
       "active": 521,
       "resolvable_active": 502,
-      "resolvable_pct": 96
+      "resolvable_pct": 96,
+      "verified": "reaches live portal 2026-07-07 ($0.08) — stock-parse selectors pending tuning"
     },
     "Ronald Redding": {
       "tier": "NO_STOCK",
@@ -2288,7 +2291,8 @@
       "products": 42,
       "active": 42,
       "resolvable_active": 42,
-      "resolvable_pct": 100
+      "resolvable_pct": 100,
+      "verified": "live-verified 2026-07-07 (shopify-public → in_stock:true, $0.03)"
     },
     "Sandberg": {
       "tier": "NO_STOCK",
diff --git a/scripts/adapters/romo.js b/scripts/adapters/romo.js
index ed1b59a..abf690f 100644
--- a/scripts/adapters/romo.js
+++ b/scripts/adapters/romo.js
@@ -28,19 +28,27 @@ async function run({ sku, pool, newSession, romoLogin, catalogTable, log }) {
     await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 45000 });
     await page.waitForTimeout(6000);
 
-    const availTxt = await page.$$eval(
-      '[class*=stock], [class*=availab], [itemprop=availability], .product-form__inventory, button[name=add]',
+    // schema.org availability is authoritative — prefer it over noisy DOM text.
+    const ld = await page.$$eval('script[type="application/ld+json"]', (els) => els.map((e) => e.textContent).join(' ')).catch(() => '');
+    // product-scoped availability text (avoid the global nav, which carries "Discontinued List" /
+    // "Sale List" / "Check Stock" menu links that would falsely trip out-of-stock).
+    let availTxt = await page.$$eval(
+      '[itemprop=availability], .product [class*=stock], .product [class*=availab], .product-form__inventory, button[name=add], [class*=add-to]',
       (els) => els.map((e) => (e.getAttribute('content') || e.getAttribute('aria-label') || e.textContent || '').trim()).filter(Boolean).join(' | ')
     ).catch(() => '');
-    // schema.org availability from any JSON-LD block
-    const ld = await page.$$eval('script[type="application/ld+json"]', (els) => els.map((e) => e.textContent).join(' ')).catch(() => '');
-    const hay = (availTxt + ' ' + ld);
+    // strip obvious nav-menu chrome so it can't masquerade as product stock state
+    const NAV = /(discontinued|sale|stock)\s+list|check\s+stock|stock\s+list/ig;
+    availTxt = String(availTxt).replace(NAV, '').trim();
 
     let in_stock = null;
-    if (/out\s*of\s*stock|sold\s*out|unavailable|OutOfStock|discontinued/i.test(hay)) in_stock = false;
-    else if (/in\s*stock|in-?stock|InStock|add to (cart|basket|bag)|available/i.test(hay)) in_stock = true;
+    if (/OutOfStock|SoldOut/i.test(ld)) in_stock = false;
+    else if (/InStock/i.test(ld)) in_stock = true;
+    else if (/out\s*of\s*stock|sold\s*out|unavailable/i.test(availTxt)) in_stock = false;
+    else if (/in\s*stock|in-?stock|add to (cart|basket|bag)/i.test(availTxt)) in_stock = true;
+    // else: unknown (null) — never guess from nav chrome
 
-    const label = availTxt ? availTxt.slice(0, 60) : (in_stock === true ? 'in stock' : in_stock === false ? 'out of stock' : 'unknown');
+    const label = in_stock === true ? 'in stock' : in_stock === false ? 'out of stock'
+      : (availTxt ? availTxt.slice(0, 60) : 'unknown (parse pending verification)');
 
     return {
       available: true, session_opened: true, vendor: 'Romo',
diff --git a/scripts/build-coverage.js b/scripts/build-coverage.js
index 1e61904..d7328c3 100644
--- a/scripts/build-coverage.js
+++ b/scripts/build-coverage.js
@@ -50,6 +50,15 @@ const WALLQUEST_ALIASES = new Set(['malibu wallpaper', 'ps removable wallpaper',
 
 // Known to-the-trade / quote-only houses that publish NO stock anywhere (memory + DW knowledge).
 // A matched vendor here is QUOTE_ONLY regardless of a marketing site existing.
+// Live-verification status from real metered scrapes (see the coverage report). Enabled vendors not
+// listed here are wired but not yet proven with a live scrape (honest — the framework routes them).
+const VERIFIED = {
+  '1838 Wallcoverings': 'live-verified 2026-07-07 (shopify-public → in_stock:true, $0.03)',
+  'Sancar': 'live-verified 2026-07-07 (shopify-public → in_stock:true, $0.03)',
+  'Malibu Wallpaper': 'live-verified 2026-07-07 (wallquest → OutOfStock, $0.10)',
+  'Romo': 'reaches live portal 2026-07-07 ($0.08) — stock-parse selectors pending tuning',
+};
+
 const QUOTE_ONLY = new Set([
   'dedar', 'de gournay', 'de gournay murals', 'fromental', 'gracie', 'iksel', 'zuber',
   'porter teleo', 'holland and sherry', 'holland & sherry', 'clarence house', 'fortuny',
@@ -220,6 +229,7 @@ async function main() {
         entry.reason = `adapter wired (${entry.adapter}) but display SKUs don't align with the ${entry.catalog_table} catalog (${resolvable} of ${active} active resolvable) — needs SKU remap`;
       }
     }
+    if (entry.live_capable) entry.verified = VERIFIED[dv.vendor] || 'wired — not yet live-verified';
     vendors[dv.vendor] = entry;
     counts[c.tier] = (counts[c.tier] || 0) + 1;
     if (entry.live_capable) counts.live_capable += 1;

← 5d8857a adapters: shared grid-SKU→catalog resolver (bridge via shopi  ·  back to All Designerwallcoverings  ·  live-stock: daily $ kill-switch — global per-day spend ceili 2c397b4 →