[object Object]

← back to All Designerwallcoverings

live-stock verify: 4 NEW vendors live-verified via schema-public (Mind the Gap/Graham & Brown/Innovations USA/Rebel Walls, in_stock:true, $0.03 ea) — live_capable 4→8, all verified; harden schema-public to read Magento microdata href; AS Creation/Designers Guild/Marburg kept wired-but-dim (JS-rendered availability, parse pending) rather than burn sessions for unknown; total verify spend $0.247 logged to cost-tracker

3790ba824058c598bacd8a00e44d6f6e24567cb0 · 2026-07-07 10:21:32 -0700 · Steve

Files touched

Diff

commit 3790ba824058c598bacd8a00e44d6f6e24567cb0
Author: Steve <steve@designerwallcoverings.com>
Date:   Tue Jul 7 10:21:32 2026 -0700

    live-stock verify: 4 NEW vendors live-verified via schema-public (Mind the Gap/Graham & Brown/Innovations USA/Rebel Walls, in_stock:true, $0.03 ea) — live_capable 4→8, all verified; harden schema-public to read Magento microdata href; AS Creation/Designers Guild/Marburg kept wired-but-dim (JS-rendered availability, parse pending) rather than burn sessions for unknown; total verify spend $0.247 logged to cost-tracker
---
 data/live-stock-coverage.json     | 39 +++++++++++++++------------------------
 scripts/adapters/schema-public.js | 15 ++++++++++-----
 scripts/build-coverage.js         | 16 +++++++++++++++-
 3 files changed, 40 insertions(+), 30 deletions(-)

diff --git a/data/live-stock-coverage.json b/data/live-stock-coverage.json
index 63e15a3..7c4ccf8 100644
--- a/data/live-stock-coverage.json
+++ b/data/live-stock-coverage.json
@@ -1,5 +1,5 @@
 {
-  "generated_at": "2026-07-07T17:15:01.445Z",
+  "generated_at": "2026-07-07T17:20:44.460Z",
   "generator": "scripts/build-coverage.js",
   "total_display_vendors": 254,
   "counts": {
@@ -8,7 +8,7 @@
     "PORTAL_NO_CREDS": 18,
     "QUOTE_ONLY": 35,
     "NO_STOCK": 172,
-    "live_capable": 11
+    "live_capable": 8
   },
   "vendors": {
     "1838 Wallcoverings": {
@@ -192,17 +192,14 @@
     },
     "AS Creation": {
       "tier": "PUBLIC_STOCK",
-      "live_capable": true,
+      "live_capable": false,
       "adapter": "schema-public",
-      "reason": "public schema.org/Magento availability (no login required)",
+      "reason": "schema-public adapter wired but sampled SKUs return no definitive stock (JS-rendered availability — parse tuning pending)",
       "catalog_table": "as_creation_catalog",
       "backing": "AS Creation",
       "match": "exact",
       "products": 505,
-      "active": 327,
-      "resolvable_active": 326,
-      "resolvable_pct": 100,
-      "verified": "wired — not yet live-verified"
+      "active": 327
     },
     "Atomic 50 Ceilings": {
       "tier": "NO_STOCK",
@@ -617,17 +614,14 @@
     },
     "Designers Guild": {
       "tier": "PUBLIC_STOCK",
-      "live_capable": true,
+      "live_capable": false,
       "adapter": "schema-public",
-      "reason": "public schema.org/Magento availability (no login required)",
+      "reason": "schema-public adapter wired but sampled SKUs return no definitive stock (JS-rendered availability — parse tuning pending)",
       "catalog_table": "designers_guild_catalog",
       "backing": "Designers Guild",
       "match": "exact",
       "products": 879,
-      "active": 853,
-      "resolvable_active": 189,
-      "resolvable_pct": 22,
-      "verified": "wired — not yet live-verified"
+      "active": 853
     },
     "Designtex": {
       "tier": "PUBLIC_STOCK",
@@ -1094,7 +1088,7 @@
       "active": 405,
       "resolvable_active": 399,
       "resolvable_pct": 99,
-      "verified": "wired — not yet live-verified"
+      "verified": "live-verified 2026-07-07 (schema-public → in_stock:true, $0.03)"
     },
     "Grasscloth": {
       "tier": "QUOTE_ONLY",
@@ -1321,7 +1315,7 @@
       "active": 210,
       "resolvable_active": 91,
       "resolvable_pct": 43,
-      "verified": "wired — not yet live-verified"
+      "verified": "live-verified 2026-07-07 (schema-public → in_stock:true, $0.03)"
     },
     "Jane Churchill": {
       "tier": "NO_STOCK",
@@ -1651,17 +1645,14 @@
     },
     "Marburg": {
       "tier": "PUBLIC_STOCK",
-      "live_capable": true,
+      "live_capable": false,
       "adapter": "schema-public",
-      "reason": "public schema.org/Magento availability (no login required)",
+      "reason": "schema-public adapter wired but sampled SKUs return no definitive stock (JS-rendered availability — parse tuning pending)",
       "catalog_table": "marburg_catalog",
       "backing": "Marburg",
       "match": "exact",
       "products": 121,
-      "active": 112,
-      "resolvable_active": 96,
-      "resolvable_pct": 86,
-      "verified": "wired — not yet live-verified"
+      "active": 112
     },
     "Marimekko Exclusive": {
       "tier": "NO_STOCK",
@@ -1752,7 +1743,7 @@
       "active": 1134,
       "resolvable_active": 924,
       "resolvable_pct": 81,
-      "verified": "wired — not yet live-verified"
+      "verified": "live-verified 2026-07-07 (schema-public → in_stock:true, $0.03)"
     },
     "Missoni Fabric": {
       "tier": "QUOTE_ONLY",
@@ -2240,7 +2231,7 @@
       "active": 3613,
       "resolvable_active": 1028,
       "resolvable_pct": 28,
-      "verified": "wired — not yet live-verified"
+      "verified": "live-verified 2026-07-07 (schema-public → in_stock:true, $0.03)"
     },
     "Retro Walls": {
       "tier": "NO_STOCK",
diff --git a/scripts/adapters/schema-public.js b/scripts/adapters/schema-public.js
index 323aea8..88c06e0 100644
--- a/scripts/adapters/schema-public.js
+++ b/scripts/adapters/schema-public.js
@@ -33,21 +33,26 @@ async function run({ sku, pool, newSession, catalogTable, log }) {
     // 1. schema.org JSON-LD — parse every ld+json block, look for an Offer availability.
     const ldRaw = await page.$$eval('script[type="application/ld+json"]', (els) => els.map((e) => e.textContent).join('\n')).catch(() => '');
     let in_stock = null, ldAvail = null;
+    const readAvail = (s) => { if (/OutOfStock|SoldOut|Discontinued|BackOrder/i.test(s)) return false; if (/InStock|LimitedAvailability|PreOrder|OnlineOnly|InStoreOnly/i.test(s)) return true; return null; };
     if (ldRaw) {
       const m = ldRaw.match(/"availability"\s*:\s*"([^"]+)"/i);
-      if (m) { ldAvail = m[1]; if (/OutOfStock|SoldOut|Discontinued|BackOrder/i.test(ldAvail)) in_stock = false; else if (/InStock|LimitedAvailability|PreOrder|OnlineOnly|InStoreOnly/i.test(ldAvail)) in_stock = true; }
+      if (m) { ldAvail = m[1]; in_stock = readAvail(ldAvail); }
     }
 
-    // 2. product-scoped DOM stock markup (avoid global nav chrome).
+    // 2. product-scoped DOM stock markup — read microdata too. Magento often emits availability as
+    //    <link itemprop="availability" href="http://schema.org/InStock"> (empty textContent, signal
+    //    lives in the HREF), so we read href/content/title/text and match the bare schema token.
     let domTxt = '';
     if (in_stock === null) {
       domTxt = await page.$$eval(
-        '[itemprop=availability], .product [class*=stock], .product-info [class*=stock], [class*=availab], .stock, .product-form__inventory',
-        (els) => els.map((e) => (e.getAttribute('content') || e.getAttribute('title') || e.textContent || '').trim()).filter(Boolean).join(' | ')
+        '[itemprop=availability], link[itemprop=availability], meta[itemprop=availability], .product [class*=stock], .product-info [class*=stock], [class*=availab], .stock, .product-form__inventory',
+        (els) => els.map((e) => (e.getAttribute('href') || e.getAttribute('content') || e.getAttribute('title') || e.textContent || '').trim()).filter(Boolean).join(' | ')
       ).catch(() => '');
       const NAV = /(discontinued|sale|stock)\s+list|check\s+stock|stock\s+list/ig;
       const t = String(domTxt).replace(NAV, '');
-      if (/out\s*of\s*stock|sold\s*out|unavailable|no longer available/i.test(t)) in_stock = false;
+      const tok = readAvail(t); // bare schema.org/InStock|OutOfStock token in an href/content
+      if (tok !== null) in_stock = tok;
+      else if (/out\s*of\s*stock|sold\s*out|unavailable|no longer available/i.test(t)) in_stock = false;
       else if (/in\s*stock|in-?stock|available/i.test(t)) in_stock = true;
     }
 
diff --git a/scripts/build-coverage.js b/scripts/build-coverage.js
index 1b8f00e..fbdfe4c 100644
--- a/scripts/build-coverage.js
+++ b/scripts/build-coverage.js
@@ -57,6 +57,10 @@ const VERIFIED = {
   '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',
+  'Mind the Gap': 'live-verified 2026-07-07 (schema-public → in_stock:true, $0.03)',
+  'Graham & Brown': 'live-verified 2026-07-07 (schema-public → in_stock:true, $0.03)',
+  'Innovations USA': 'live-verified 2026-07-07 (schema-public → in_stock:true, $0.03)',
+  'Rebel Walls': 'live-verified 2026-07-07 (schema-public → in_stock:true, $0.03)',
 };
 
 // PUBLIC-SCHEMA vendors — to-the-trade / Magento / custom storefronts whose ANONYMOUS product
@@ -71,6 +75,12 @@ const SCHEMA_PUBLIC = new Set([
   'as creation', 'contrado', 'rebel walls',
 ]);
 
+// schema-public vendors WIRED but kept DIM: a metered probe (2026-07-07) reached the anonymous PDP
+// yet returned no definitive stock state (availability is JS-rendered / non-standard), so enabling
+// would burn a session for "unknown". Adapter stays attached so enabling is a one-flag change once
+// the parse is tuned. Honest: reachable, but no readable public stock signal on the sampled SKUs.
+const SCHEMA_PARSE_PENDING = new Set(['as creation', 'designers guild', 'marburg']);
+
 // Portals that require a login AND publish only PRICE (a wholesale price sheet / SFTP feed), never
 // live inventory — enabling a metered scrape would burn a session to read a price we can't surface.
 // Honest dim: creds may exist, but the portal has no live-stock signal to read.
@@ -193,9 +203,13 @@ async function main() {
         reason: 'public Shopify storefront stock (.js feed)', catalog_table: tbl };
     // 2b. PUBLIC_STOCK (schema.org) — probed vendors whose anonymous PDP emits Offer availability.
     //     Precedes the portal branches so a login_url doesn't force these to dim as PORTAL_NO_CREDS.
-    if (SCHEMA_PUBLIC.has(v) && oneToOne && dedicated(tbl) && hasUrls(tbl))
+    if (SCHEMA_PUBLIC.has(v) && oneToOne && dedicated(tbl) && hasUrls(tbl)) {
+      if (SCHEMA_PARSE_PENDING.has(v))
+        return { tier: 'PUBLIC_STOCK', live_capable: false, adapter: 'schema-public',
+          reason: 'schema-public adapter wired but sampled SKUs return no definitive stock (JS-rendered availability — parse tuning pending)', catalog_table: tbl };
       return { tier: 'PUBLIC_STOCK', live_capable: true, adapter: 'schema-public',
         reason: 'public schema.org/Magento availability (no login required)', catalog_table: tbl };
+    }
     // 2c. PORTAL, PRICE-ONLY — login publishes a price sheet, not live stock → honest dim.
     if (NO_LIVE_STOCK_PORTAL.has(v))
       return { tier: 'PORTAL_NO_CREDS', live_capable: false, adapter: null,

← d1be0d2 live-stock: generic schema-public adapter (login-free schema  ·  back to All Designerwallcoverings  ·  live-stock: tune schema-public for Designers Guild + Marburg 0ccd9b9 →