← 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
M data/live-stock-coverage.jsonM scripts/adapters/schema-public.jsM scripts/build-coverage.js
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 →