[object Object]

← back to All Designerwallcoverings

live-stock: structured-only availability vote (kills Osborne discontinued-banner false-OOS) + Magento tocart/title CTA read; stamp DG/Marburg/Osborne live-verified

77f866b0eea5bf2ecc526f8e523ad839d93d7308 · 2026-07-07 12:53:49 -0700 · Steve

Files touched

Diff

commit 77f866b0eea5bf2ecc526f8e523ad839d93d7308
Author: Steve <steve@designerwallcoverings.com>
Date:   Tue Jul 7 12:53:49 2026 -0700

    live-stock: structured-only availability vote (kills Osborne discontinued-banner false-OOS) + Magento tocart/title CTA read; stamp DG/Marburg/Osborne live-verified
---
 data/live-stock-coverage.json     | 12 ++++++------
 scripts/adapters/schema-public.js | 24 ++++++++++++++++--------
 scripts/build-coverage.js         |  3 +++
 3 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/data/live-stock-coverage.json b/data/live-stock-coverage.json
index 4ee93bc..ad99641 100644
--- a/data/live-stock-coverage.json
+++ b/data/live-stock-coverage.json
@@ -1,5 +1,5 @@
 {
-  "generated_at": "2026-07-07T19:46:15.280Z",
+  "generated_at": "2026-07-07T19:53:42.984Z",
   "generator": "scripts/build-coverage.js",
   "total_display_vendors": 254,
   "counts": {
@@ -624,7 +624,7 @@
       "active": 853,
       "resolvable_active": 189,
       "resolvable_pct": 22,
-      "verified": "wired — not yet live-verified"
+      "verified": "live-verified 2026-07-07 (schema-public → in_stock:true via structured availability vote, $0.03)"
     },
     "Designtex": {
       "tier": "PUBLIC_STOCK",
@@ -1658,7 +1658,7 @@
       "active": 112,
       "resolvable_active": 96,
       "resolvable_pct": 86,
-      "verified": "wired — not yet live-verified"
+      "verified": "live-verified 2026-07-07 (schema-public → in_stock:true via WooCommerce stock class, $0.03)"
     },
     "Marimekko Exclusive": {
       "tier": "NO_STOCK",
@@ -1923,7 +1923,7 @@
       "active": 957,
       "resolvable_active": 350,
       "resolvable_pct": 37,
-      "verified": "wired — not yet live-verified"
+      "verified": "live-verified 2026-07-07 (schema-public → in_stock:true via enabled add-to-cart; SKU remap by leading mfr code, $0.03)"
     },
     "Osborne & Little Fabrics": {
       "tier": "PUBLIC_STOCK",
@@ -2042,8 +2042,8 @@
       "live_capable": false,
       "adapter": null,
       "reason": "no live stock source identified for this line",
-      "catalog_table": "astek_catalog",
-      "backing": "Astek",
+      "catalog_table": "twil_karin_catalog",
+      "backing": "TWIL Karin",
       "match": "private-label",
       "products": 18919,
       "active": 10136
diff --git a/scripts/adapters/schema-public.js b/scripts/adapters/schema-public.js
index f8aa19e..d5f7f4b 100644
--- a/scripts/adapters/schema-public.js
+++ b/scripts/adapters/schema-public.js
@@ -70,14 +70,19 @@ async function run({ sku, pool, newSession, catalogTable, log }) {
     if (in_stock === null) {
       const vote = await page.evaluate(() => {
         const html = document.documentElement.innerHTML || '';
-        const nRe = (re) => (html.match(re) || []).length;
-        // structural WooCommerce stock classes (whitespace-exact class token)
+        const n = (re) => (html.match(re) || []).length;
+        // STRUCTURED-ONLY: count availability tokens only where they appear in a machine-readable
+        // context — a schema.org/<token> URL, or a JSON "…availability":"<token>" key (incl.
+        // backslash-escaped JSON strings), or a WooCommerce structural stock class. This deliberately
+        // does NOT match the bare English words in prose: e.g. Osborne & Little stamps a
+        // "…Limited and Discontinued fabrics…" Warehouse-Sale banner on EVERY page, and a loose word
+        // match would read every Osborne product out-of-stock. Structural gating kills that false read.
         const wooIn = document.querySelectorAll('[class~="instock"]').length;
         const wooOut = document.querySelectorAll('[class~="outofstock"]').length;
-        // schema.org availability tokens anywhere in the server-rendered markup (case-insensitive
-        // also catches the lowercase Woo class text, harmless double-count in the same direction)
-        const inTok = nRe(/InStock|LimitedAvailability|PreOrder/gi) + wooIn;
-        const outTok = nRe(/OutOfStock|SoldOut|Discontinued|BackOrder/gi) + wooOut;
+        const inTok = n(/schema\.org\/(?:InStock|LimitedAvailability|PreOrder)/gi)
+          + n(/[Aa]vailability\\?"?\s*:\s*\\?"?(?:InStock|LimitedAvailability|PreOrder)/g) + wooIn;
+        const outTok = n(/schema\.org\/(?:OutOfStock|SoldOut|Discontinued|BackOrder)/gi)
+          + n(/[Aa]vailability\\?"?\s*:\s*\\?"?(?:OutOfStock|SoldOut|Discontinued|BackOrder)/g) + wooOut;
         return { inTok, outTok };
       }).catch(() => ({ inTok: 0, outTok: 0 }));
       if (vote.inTok || vote.outTok) {
@@ -90,8 +95,11 @@ async function run({ sku, pool, newSession, catalogTable, log }) {
     // 3. add-to-cart CTA state (last resort — presence of an enabled add-to-cart ⇒ purchasable).
     if (in_stock === null) {
       const cta = await page.$$eval(
-        'button[name=add], button[type=submit], [class*=add-to], [class*=addto], a[href*=cart]',
-        (els) => els.filter((e) => /add to (cart|basket|bag|sample)|add sample/i.test(e.textContent || e.getAttribute('aria-label') || ''))
+        // [class*=tocart] = Magento's canonical add-to-cart button class (Osborne & Little). Magento
+        // often keeps the visible label in title=/aria-label rather than textContent, so we test all three.
+        'button[name=add], button[type=submit], [class*=add-to], [class*=addto], [class*=tocart], a[href*=cart]',
+        (els) => els.filter((e) => /add to (cart|basket|bag|sample)|add sample/i.test(
+            [e.textContent, e.getAttribute('aria-label'), e.getAttribute('title')].filter(Boolean).join(' ')))
           .map((e) => (e.disabled || /disabled/i.test(e.className) ? 'disabled' : 'enabled')).join(',')
       ).catch(() => '');
       if (/enabled/.test(cta)) in_stock = true;
diff --git a/scripts/build-coverage.js b/scripts/build-coverage.js
index 0c5f9e8..ffeb0dc 100644
--- a/scripts/build-coverage.js
+++ b/scripts/build-coverage.js
@@ -61,6 +61,9 @@ const VERIFIED = {
   '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)',
+  'Designers Guild': 'live-verified 2026-07-07 (schema-public → in_stock:true via structured availability vote, $0.03)',
+  'Marburg': 'live-verified 2026-07-07 (schema-public → in_stock:true via WooCommerce stock class, $0.03)',
+  'Osborne & Little': 'live-verified 2026-07-07 (schema-public → in_stock:true via enabled add-to-cart; SKU remap by leading mfr code, $0.03)',
 };
 
 // PUBLIC-SCHEMA vendors — to-the-trade / Magento / custom storefronts whose ANONYMOUS product

← 0ccd9b9 live-stock: tune schema-public for Designers Guild + Marburg  ·  back to All Designerwallcoverings  ·  all.dw: register Pierre Frey microsite (slug pierrefrey, wav d537f75 →