[object Object]

← back to All Designerwallcoverings

live-stock coverage audit: classify all 254 display-vendors into feasibility tiers (data/live-stock-coverage.json + scripts/build-coverage.js)

93e37e27db451b26c8e2eaf1c70d9e59cd611ec3 · 2026-07-07 09:23:12 -0700 · Steve

Files touched

Diff

commit 93e37e27db451b26c8e2eaf1c70d9e59cd611ec3
Author: Steve <steve@designerwallcoverings.com>
Date:   Tue Jul 7 09:23:12 2026 -0700

    live-stock coverage audit: classify all 254 display-vendors into feasibility tiers (data/live-stock-coverage.json + scripts/build-coverage.js)
---
 data/live-stock-coverage.json | 2809 +++++++++++++++++++++++++++++++++++++++++
 scripts/build-coverage.js     |  217 ++++
 2 files changed, 3026 insertions(+)

diff --git a/data/live-stock-coverage.json b/data/live-stock-coverage.json
new file mode 100644
index 0000000..a03c611
--- /dev/null
+++ b/data/live-stock-coverage.json
@@ -0,0 +1,2809 @@
+{
+  "generated_at": "2026-07-07T16:22:59.582Z",
+  "generator": "scripts/build-coverage.js",
+  "total_display_vendors": 254,
+  "counts": {
+    "PORTAL_CREDS": 5,
+    "PUBLIC_STOCK": 12,
+    "PORTAL_NO_CREDS": 30,
+    "QUOTE_ONLY": 35,
+    "NO_STOCK": 172,
+    "live_capable": 13
+  },
+  "vendors": {
+    "1838 Wallcoverings": {
+      "tier": "PUBLIC_STOCK",
+      "live_capable": true,
+      "adapter": "shopify-public",
+      "reason": "public Shopify storefront stock (.js feed)",
+      "catalog_table": "w1838_catalog",
+      "backing": "1838 Wallcoverings",
+      "match": "exact",
+      "products": 481,
+      "active": 465
+    },
+    "420 Studios": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 1,
+      "active": 0
+    },
+    "A.S. Création": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 1,
+      "active": 1
+    },
+    "Abel Macias": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 1,
+      "active": 0
+    },
+    "Alan Campbell": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "quadrille_house_catalog",
+      "backing": "Alan Campbell",
+      "match": "exact",
+      "products": 3,
+      "active": 3
+    },
+    "Ananbo": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Ananbo",
+      "match": "exact",
+      "products": 1,
+      "active": 1
+    },
+    "Andrew Martin": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "andrew_martin_catalog",
+      "backing": "Andrew Martin",
+      "match": "exact",
+      "products": 7,
+      "active": 5
+    },
+    "Anna French": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "anna_french_catalog",
+      "backing": "Anna French",
+      "match": "exact",
+      "products": 1108,
+      "active": 814
+    },
+    "Apartment Wallpaper": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 101,
+      "active": 39
+    },
+    "Architectural Fabrics": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 483,
+      "active": 328
+    },
+    "Architectural Wallcoverings": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 9,
+      "active": 4
+    },
+    "Armani Casa": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "armani_casa_catalog",
+      "backing": "Armani Casa",
+      "match": "exact",
+      "products": 226,
+      "active": 0
+    },
+    "Armani/Casa": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 9,
+      "active": 0
+    },
+    "Arte": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 3,
+      "active": 0
+    },
+    "Arte International": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "arte_catalog",
+      "backing": "Arte International",
+      "match": "exact",
+      "products": 631,
+      "active": 523
+    },
+    "Artmura": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 161,
+      "active": 144
+    },
+    "AS Creation": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "as_creation_catalog",
+      "backing": "AS Creation",
+      "match": "exact",
+      "products": 505,
+      "active": 327
+    },
+    "Atomic 50 Ceilings": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "atomic50_catalog",
+      "backing": "Atomic 50 Ceilings",
+      "match": "exact",
+      "products": 2,
+      "active": 2
+    },
+    "Backdrop": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Backdrop",
+      "match": "exact",
+      "products": 9,
+      "active": 9
+    },
+    "Baker Lifestyle": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "baker_lifestyle_catalog",
+      "backing": "Baker Lifestyle",
+      "match": "exact",
+      "products": 8,
+      "active": 4
+    },
+    "Belarte Studio": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 11,
+      "active": 0
+    },
+    "Bespoke": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 632,
+      "active": 0
+    },
+    "Big Sur Beans": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 3,
+      "active": 0
+    },
+    "Black Edition": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "black_edition_catalog",
+      "backing": "Black Edition",
+      "match": "exact",
+      "products": 5,
+      "active": 3
+    },
+    "Boråstapeter": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 32,
+      "active": 31
+    },
+    "Boråstapeter Wallpaper": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 2,
+      "active": 0
+    },
+    "Brand McKenzie": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "brand_mckenzie_catalog",
+      "backing": "Brand McKenzie",
+      "match": "exact",
+      "products": 165,
+      "active": 156
+    },
+    "British Walls": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "british_walls_catalog",
+      "backing": "British Walls",
+      "match": "exact",
+      "products": 506,
+      "active": 472
+    },
+    "Brunschwig & Fils": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "brunschwig_catalog",
+      "backing": "Brunschwig & Fils",
+      "match": "exact",
+      "products": 3371,
+      "active": 2761
+    },
+    "Carlisle & Co. Walls": {
+      "tier": "PUBLIC_STOCK",
+      "live_capable": true,
+      "adapter": "shopify-public",
+      "reason": "public Shopify storefront stock (.js feed)",
+      "catalog_table": "carlisle_catalog",
+      "backing": "Carlisle & Co",
+      "match": "suffix-strip",
+      "products": 441,
+      "active": 0
+    },
+    "Caroline Cecil Textiles": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 6,
+      "active": 3
+    },
+    "Catchii Netherlands Europe": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 1,
+      "active": 1
+    },
+    "Celerie Kemble": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "vendor_catalog",
+      "backing": "Celerie Kemble",
+      "match": "exact",
+      "products": 1,
+      "active": 1
+    },
+    "Charles Burger": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "quadrille_house_catalog",
+      "backing": "Charles Burger",
+      "match": "exact",
+      "products": 3,
+      "active": 3
+    },
+    "China Seas": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "china_seas_catalog",
+      "backing": "China Seas",
+      "match": "exact",
+      "products": 1806,
+      "active": 1776
+    },
+    "China Seas Fabrics": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "china_seas_catalog",
+      "backing": "China Seas",
+      "match": "suffix-strip",
+      "products": 2,
+      "active": 0
+    },
+    "China Seas Wallpaper": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "china_seas_catalog",
+      "backing": "China Seas",
+      "match": "suffix-strip",
+      "products": 2,
+      "active": 0
+    },
+    "Christian Lacroix Europe": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 175,
+      "active": 170
+    },
+    "Clarence House": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": null,
+      "backing": "Clarence House",
+      "match": "exact",
+      "products": 2,
+      "active": 2
+    },
+    "Clarke and Clarke": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "clarke_clarke_catalog",
+      "backing": "Clarke And Clarke",
+      "match": "exact",
+      "products": 3,
+      "active": 3
+    },
+    "Clarke And Clarke": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "clarke_clarke_catalog",
+      "backing": "Clarke And Clarke",
+      "match": "exact",
+      "products": 3927,
+      "active": 3573
+    },
+    "Cloth and Paper": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "quadrille_house_catalog",
+      "backing": "Cloth and Paper",
+      "match": "exact",
+      "products": 3,
+      "active": 3
+    },
+    "CMO Paris": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "cmo_paris_catalog",
+      "backing": "CMO Paris",
+      "match": "exact",
+      "products": 1,
+      "active": 0
+    },
+    "Cole & Son": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "coleson_catalog",
+      "backing": "Cole & Son",
+      "match": "exact",
+      "products": 1268,
+      "active": 1238
+    },
+    "Colefax and Fowler": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 361,
+      "active": 0
+    },
+    "Contrado": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "contrado_catalog",
+      "backing": "Contrado",
+      "match": "exact",
+      "products": 19,
+      "active": 15
+    },
+    "Coordonn��": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 1,
+      "active": 1
+    },
+    "Coordonné": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "coordonne_catalog",
+      "backing": "Coordonné",
+      "match": "exact",
+      "products": 1353,
+      "active": 1336
+    },
+    "Coordonné Europe": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "coordonne_catalog",
+      "backing": "Coordonné",
+      "match": "suffix-strip",
+      "products": 29,
+      "active": 0
+    },
+    "Cowtan & Tout": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "cowtan_tout_catalog",
+      "backing": "Cowtan & Tout",
+      "match": "exact",
+      "products": 453,
+      "active": 0
+    },
+    "Daisy Bennett": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Daisy Bennett",
+      "match": "exact",
+      "products": 70,
+      "active": 68
+    },
+    "Dedar": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "dedar_catalog",
+      "backing": "Dedar",
+      "match": "exact",
+      "products": 1,
+      "active": 1
+    },
+    "Designer Wallcoverings": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "folia_catalog",
+      "backing": "Folia Fabrics",
+      "match": "private-label",
+      "products": 2262,
+      "active": 1532
+    },
+    "Designer Wallcoverings and Fabrics": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 15,
+      "active": 0
+    },
+    "Designers Guild": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "designers_guild_catalog",
+      "backing": "Designers Guild",
+      "match": "exact",
+      "products": 879,
+      "active": 853
+    },
+    "Designtex": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "designtex_catalog",
+      "backing": "Designtex",
+      "match": "exact",
+      "products": 317,
+      "active": 288
+    },
+    "Dolce & Gabbana": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "dolce_gabbana_catalog",
+      "backing": "Dolce & Gabbana",
+      "match": "exact",
+      "products": 36,
+      "active": 27
+    },
+    "Donghia": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "donghia_catalog",
+      "backing": "Donghia",
+      "match": "exact",
+      "products": 161,
+      "active": 157
+    },
+    "Dupenny": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Dupenny",
+      "match": "exact",
+      "products": 1,
+      "active": 1
+    },
+    "DW Bespoke Murals": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 1,
+      "active": 0
+    },
+    "DW Bespoke Studio": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "bespoke_catalog",
+      "backing": "DW Bespoke Studio",
+      "match": "exact",
+      "products": 2331,
+      "active": 921
+    },
+    "DW Bespoke Studio To Go": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 9,
+      "active": 0
+    },
+    "DW Bespoke Studios To Go": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 592,
+      "active": 0
+    },
+    "DW Exclusive Wallpaper": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 1,
+      "active": 1
+    },
+    "DW Home": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 79,
+      "active": 37
+    },
+    "DW Internal": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 1,
+      "active": 0
+    },
+    "DWHD": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 1,
+      "active": 1
+    },
+    "Edge Wallcovering": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Edge",
+      "match": "suffix-strip",
+      "products": 1,
+      "active": 1
+    },
+    "Edge Wallpaper": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Edge",
+      "match": "suffix-strip",
+      "products": 1,
+      "active": 0
+    },
+    "Elitis": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "elitis_catalog",
+      "backing": "Elitis",
+      "match": "exact",
+      "products": 244,
+      "active": 243
+    },
+    "Emiliana Parati": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Emiliana Parati",
+      "match": "exact",
+      "products": 15,
+      "active": 1
+    },
+    "Erika Wakerly": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Erika Wakerly",
+      "match": "exact",
+      "products": 2,
+      "active": 2
+    },
+    "Et Cie Wall Panels": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 461,
+      "active": 0
+    },
+    "F. Schumacher Fabrics": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 67,
+      "active": 0
+    },
+    "Fabricut": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "fabricut_catalog",
+      "backing": "Fabricut",
+      "match": "exact",
+      "products": 46,
+      "active": 3
+    },
+    "FallingStar Studio": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 42,
+      "active": 42
+    },
+    "Farrow & Ball": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "farrow_ball_catalog",
+      "backing": "Farrow & Ball",
+      "match": "exact",
+      "products": 2,
+      "active": 1
+    },
+    "Fentucci": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "fentucci_catalog",
+      "backing": "Fentucci",
+      "match": "exact",
+      "products": 2950,
+      "active": 358
+    },
+    "Fentucci Fabrics": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "fentucci_catalog",
+      "backing": "Fentucci",
+      "match": "suffix-strip",
+      "products": 379,
+      "active": 0
+    },
+    "Fentucci Murals": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "fentucci_catalog",
+      "backing": "Fentucci",
+      "match": "suffix-strip",
+      "products": 8,
+      "active": 0
+    },
+    "Fentucci Naturals": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "fentucci_naturals_catalog",
+      "backing": "Fentucci Naturals",
+      "match": "exact",
+      "products": 148,
+      "active": 0
+    },
+    "Fentucci Naturals Walls": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "fentucci_naturals_catalog",
+      "backing": "Fentucci Naturals",
+      "match": "suffix-strip",
+      "products": 38,
+      "active": 0
+    },
+    "Fentucci Wallpaper": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "fentucci_catalog",
+      "backing": "Fentucci",
+      "match": "suffix-strip",
+      "products": 15,
+      "active": 0
+    },
+    "Flavor Paper": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": null,
+      "backing": "Flavor Paper",
+      "match": "exact",
+      "products": 65,
+      "active": 0
+    },
+    "Florence Broadhurst": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": null,
+      "backing": "Florence Broadhurst",
+      "match": "exact",
+      "products": 25,
+      "active": 0
+    },
+    "Florentina Feathers": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 43,
+      "active": 0
+    },
+    "Franquemont London": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 26,
+      "active": 26
+    },
+    "French Market": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "French Market",
+      "match": "exact",
+      "products": 1,
+      "active": 1
+    },
+    "G P & J Baker": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 2,
+      "active": 1
+    },
+    "Gaston Y Daniela": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "gaston_daniela_catalog",
+      "backing": "Gaston Y Daniela",
+      "match": "exact",
+      "products": 2293,
+      "active": 2151
+    },
+    "Glambeads by DW": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 59,
+      "active": 58
+    },
+    "Glass Beaded": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 107,
+      "active": 39
+    },
+    "Glitter Walls": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "glitter_walls_catalog",
+      "backing": "Glitter Walls (multi-source)",
+      "match": "private-label",
+      "products": 551,
+      "active": 403
+    },
+    "GP & J Baker": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "gp_baker_catalog",
+      "backing": "GP & J Baker",
+      "match": "exact",
+      "products": 1885,
+      "active": 1197
+    },
+    "Graduate Collection": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Graduate Collection",
+      "match": "exact",
+      "products": 50,
+      "active": 49
+    },
+    "Graduate Collection UK": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Graduate Collection",
+      "match": "suffix-strip",
+      "products": 37,
+      "active": 35
+    },
+    "Graham & Brown": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "graham_brown_catalog",
+      "backing": "Graham & Brown",
+      "match": "exact",
+      "products": 1679,
+      "active": 405
+    },
+    "Grasscloth": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "quadrille_house_catalog",
+      "backing": "Grasscloth",
+      "match": "exact",
+      "products": 3,
+      "active": 0
+    },
+    "Grasscloth Wallpaper": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "quadrille_house_catalog",
+      "backing": "Grasscloth",
+      "match": "suffix-strip",
+      "products": 1,
+      "active": 0
+    },
+    "Hand Crafted": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 162,
+      "active": 40
+    },
+    "Happy Menocal": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Happy Menocal",
+      "match": "exact",
+      "products": 1,
+      "active": 1
+    },
+    "Harlequin": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "harlequin_catalog",
+      "backing": "Harlequin",
+      "match": "exact",
+      "products": 586,
+      "active": 583
+    },
+    "Heritage Collection": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 1,
+      "active": 0
+    },
+    "Hermes": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "hermes_catalog",
+      "backing": "Hermes",
+      "match": "exact",
+      "products": 29,
+      "active": 0
+    },
+    "Hinson": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 2,
+      "active": 0
+    },
+    "Holland and Sherry": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": null,
+      "backing": "Holland and Sherry",
+      "match": "exact",
+      "products": 3,
+      "active": 3
+    },
+    "Holly Hunt": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "holly_hunt_catalog",
+      "backing": "Holly Hunt",
+      "match": "exact",
+      "products": 1,
+      "active": 0
+    },
+    "Holly Hunt In Stock": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 1,
+      "active": 0
+    },
+    "Holly Hunt Walls": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "holly_hunt_catalog",
+      "backing": "Holly Hunt",
+      "match": "suffix-strip",
+      "products": 1257,
+      "active": 0
+    },
+    "Hollywood Acoustical": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 63,
+      "active": 13
+    },
+    "Hollywood Wallcoverings": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "hollywood_catalog",
+      "backing": "Hollywood Wallcoverings",
+      "match": "exact",
+      "products": 5640,
+      "active": 3155
+    },
+    "Home Couture": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "quadrille_house_catalog",
+      "backing": "Home Couture",
+      "match": "exact",
+      "products": 3,
+      "active": 3
+    },
+    "Hospitality Wallcoverings": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 98,
+      "active": 96
+    },
+    "Hygge & West": {
+      "tier": "PUBLIC_STOCK",
+      "live_capable": true,
+      "adapter": "shopify-public",
+      "reason": "public Shopify storefront stock (.js feed)",
+      "catalog_table": "hygge_catalog",
+      "backing": "Hygge & West",
+      "match": "exact",
+      "products": 11,
+      "active": 10
+    },
+    "IKSEL": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": null,
+      "backing": "IKSEL",
+      "match": "exact",
+      "products": 88,
+      "active": 0
+    },
+    "Innovations": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "innovations_catalog",
+      "backing": "Innovations",
+      "match": "exact",
+      "products": 9,
+      "active": 8
+    },
+    "Innovations USA": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "innovations_catalog",
+      "backing": "Innovations",
+      "match": "suffix-strip",
+      "products": 471,
+      "active": 210
+    },
+    "Jane Churchill": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 202,
+      "active": 0
+    },
+    "Jeffrey Stevens": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "jeffrey_stevens_catalog",
+      "backing": "York (Jeffrey Stevens source)",
+      "match": "private-label",
+      "products": 3809,
+      "active": 1498
+    },
+    "JF Fabrics": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "jf_fabrics_catalog",
+      "backing": "JF Fabrics",
+      "match": "exact",
+      "products": 2643,
+      "active": 0
+    },
+    "JF FABRICS at DW": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 3240,
+      "active": 0
+    },
+    "Kelly Wearstler": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "vendor_catalog",
+      "backing": "Kelly Wearstler",
+      "match": "exact",
+      "products": 1,
+      "active": 1
+    },
+    "Kirkby Design": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "kirkby_catalog",
+      "backing": "Kirkby Design",
+      "match": "exact",
+      "products": 3,
+      "active": 2
+    },
+    "Koroseal": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "koroseal_catalog",
+      "backing": "Koroseal",
+      "match": "exact",
+      "products": 2548,
+      "active": 2351
+    },
+    "Kravet": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "kravet_catalog",
+      "backing": "Kravet",
+      "match": "exact",
+      "products": 4902,
+      "active": 2227
+    },
+    "Kravet Couture": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 4,
+      "active": 2
+    },
+    "Kravet Design": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 4,
+      "active": 2
+    },
+    "LA Walls": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "la_walls_catalog",
+      "backing": "LA Walls",
+      "match": "exact",
+      "products": 728,
+      "active": 535
+    },
+    "Larsen": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 65,
+      "active": 0
+    },
+    "Laura Ashley Wallpaper": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "laura_ashley_catalog",
+      "backing": "Laura Ashley",
+      "match": "suffix-strip",
+      "products": 158,
+      "active": 110
+    },
+    "Lee Jofa": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "lee_jofa_catalog",
+      "backing": "Lee Jofa",
+      "match": "exact",
+      "products": 3695,
+      "active": 2152
+    },
+    "Lee Jofa Modern": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 2,
+      "active": 1
+    },
+    "LEED Walls": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "leed_walls_catalog",
+      "backing": "LEED Walls",
+      "match": "exact",
+      "products": 129,
+      "active": 75
+    },
+    "Limited Stock": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 122,
+      "active": 0
+    },
+    "Limited Stock Flock": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 4,
+      "active": 0
+    },
+    "Limited Stock Flocked": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 60,
+      "active": 0
+    },
+    "Limited Stock Prints": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 60,
+      "active": 0
+    },
+    "Lincrusta": {
+      "tier": "PUBLIC_STOCK",
+      "live_capable": false,
+      "adapter": "woo-public",
+      "reason": "WooCommerce stock adapter ready — pending per-site verification",
+      "catalog_table": "lincrusta_catalog",
+      "backing": "Lincrusta",
+      "match": "exact",
+      "products": 96,
+      "active": 47
+    },
+    "Linherr Hollingsworth": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Linherr Hollingsworth",
+      "match": "exact",
+      "products": 1,
+      "active": 1
+    },
+    "Los Angeles Fabrics": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 2366,
+      "active": 1840
+    },
+    "Luxury Murals": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 56,
+      "active": 56
+    },
+    "Madagascar Walls": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 68,
+      "active": 49
+    },
+    "Malibu": {
+      "tier": "PORTAL_CREDS",
+      "live_capable": true,
+      "adapter": "wallquest",
+      "reason": "WallQuest trade portal (creds on file)",
+      "catalog_table": "wallquest_catalog",
+      "backing": null,
+      "match": "unmatched",
+      "products": 3,
+      "active": 3
+    },
+    "Malibu Wallpaper": {
+      "tier": "PORTAL_CREDS",
+      "live_capable": true,
+      "adapter": "wallquest",
+      "reason": "WallQuest trade portal (creds on file)",
+      "catalog_table": "wallquest_catalog",
+      "backing": "Malibu Wallpaper",
+      "match": "exact",
+      "products": 4031,
+      "active": 2596
+    },
+    "Malibu Walls": {
+      "tier": "PORTAL_CREDS",
+      "live_capable": true,
+      "adapter": "wallquest",
+      "reason": "WallQuest trade portal (creds on file)",
+      "catalog_table": "wallquest_catalog",
+      "backing": null,
+      "match": "unmatched",
+      "products": 119,
+      "active": 1
+    },
+    "Manuel Canovas": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "manuel_canovas_catalog",
+      "backing": "Manuel Canovas",
+      "match": "exact",
+      "products": 195,
+      "active": 0
+    },
+    "Marburg": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "marburg_catalog",
+      "backing": "Marburg",
+      "match": "exact",
+      "products": 121,
+      "active": 112
+    },
+    "Marimekko Exclusive": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 36,
+      "active": 35
+    },
+    "Mark Alexander": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "mark_alexander_catalog",
+      "backing": "Mark Alexander",
+      "match": "exact",
+      "products": 2,
+      "active": 1
+    },
+    "Martyn Lawrence Bullard": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 77,
+      "active": 0
+    },
+    "Maya Romanoff": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "maya_catalog",
+      "backing": "Maya Romanoff",
+      "match": "exact",
+      "products": 690,
+      "active": 624
+    },
+    "MC Escher Wallpaper": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "MC Escher",
+      "match": "suffix-strip",
+      "products": 50,
+      "active": 50
+    },
+    "Mid Century Modern": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 112,
+      "active": 106
+    },
+    "Milton & King": {
+      "tier": "PUBLIC_STOCK",
+      "live_capable": false,
+      "adapter": "woo-public",
+      "reason": "WooCommerce stock adapter ready — pending per-site verification",
+      "catalog_table": "milton_king_catalog",
+      "backing": "Milton & King",
+      "match": "exact",
+      "products": 2,
+      "active": 1
+    },
+    "Mind the Gap": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "mindthegap_catalog",
+      "backing": "Mind the Gap",
+      "match": "exact",
+      "products": 1261,
+      "active": 1134
+    },
+    "Missoni Fabric": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "missoni_catalog",
+      "backing": "Missoni",
+      "match": "suffix-strip",
+      "products": 2,
+      "active": 0
+    },
+    "Missoni Home": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "missoni_catalog",
+      "backing": "Missoni",
+      "match": "suffix-strip",
+      "products": 5,
+      "active": 0
+    },
+    "Missoni Wallpaper": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "missoni_catalog",
+      "backing": "Missoni",
+      "match": "suffix-strip",
+      "products": 119,
+      "active": 57
+    },
+    "Morris and Company": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": null,
+      "backing": "Morris and Company",
+      "match": "exact",
+      "products": 1,
+      "active": 1
+    },
+    "Mulberry": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "mulberry_catalog",
+      "backing": "Mulberry",
+      "match": "exact",
+      "products": 484,
+      "active": 319
+    },
+    "Natural Paint": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 26,
+      "active": 26
+    },
+    "Newmor": {
+      "tier": "PUBLIC_STOCK",
+      "live_capable": false,
+      "adapter": "woo-public",
+      "reason": "WooCommerce stock adapter ready — pending per-site verification",
+      "catalog_table": "newmor_catalog",
+      "backing": "Newmor",
+      "match": "exact",
+      "products": 1,
+      "active": 0
+    },
+    "Newmor Wallcoverings": {
+      "tier": "PUBLIC_STOCK",
+      "live_capable": false,
+      "adapter": "woo-public",
+      "reason": "WooCommerce stock adapter ready — pending per-site verification",
+      "catalog_table": "newmor_catalog",
+      "backing": "Newmor",
+      "match": "suffix-strip",
+      "products": 542,
+      "active": 515
+    },
+    "Nina Campbell": {
+      "tier": "PUBLIC_STOCK",
+      "live_capable": true,
+      "adapter": "shopify-public",
+      "reason": "public Shopify storefront stock (.js feed)",
+      "catalog_table": "nina_campbell_catalog",
+      "backing": "Nina Campbell",
+      "match": "exact",
+      "products": 791,
+      "active": 551
+    },
+    "Nina Campbell Wallcoverings": {
+      "tier": "PUBLIC_STOCK",
+      "live_capable": true,
+      "adapter": "shopify-public",
+      "reason": "public Shopify storefront stock (.js feed)",
+      "catalog_table": "nina_campbell_catalog",
+      "backing": "Nina Campbell",
+      "match": "suffix-strip",
+      "products": 111,
+      "active": 0
+    },
+    "NLXL": {
+      "tier": "PUBLIC_STOCK",
+      "live_capable": true,
+      "adapter": "shopify-public",
+      "reason": "public Shopify storefront stock (.js feed)",
+      "catalog_table": "nlxl_catalog",
+      "backing": "NLXL",
+      "match": "exact",
+      "products": 10,
+      "active": 9
+    },
+    "Nobilis": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "nobilis_catalog",
+      "backing": "Nobilis",
+      "match": "exact",
+      "products": 179,
+      "active": 75
+    },
+    "Novasuede": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "novasuede_catalog",
+      "backing": "Novasuede",
+      "match": "exact",
+      "products": 196,
+      "active": 157
+    },
+    "OLIVIA AND POPP": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Olivia and Popp",
+      "match": "exact",
+      "products": 1,
+      "active": 1
+    },
+    "Osborne & Little": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "osborne_catalog",
+      "backing": "Osborne & Little",
+      "match": "exact",
+      "products": 1041,
+      "active": 957
+    },
+    "Osborne & Little Fabrics": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "osborne_catalog",
+      "backing": "Osborne & Little",
+      "match": "suffix-strip",
+      "products": 1101,
+      "active": 0
+    },
+    "Parkertex": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 29,
+      "active": 0
+    },
+    "Patty Madden": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Patty Madden",
+      "match": "exact",
+      "products": 2,
+      "active": 2
+    },
+    "Paul Montgomery": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "paul_montgomery_catalog",
+      "backing": "Paul Montgomery",
+      "match": "exact",
+      "products": 656,
+      "active": 0
+    },
+    "Paul Montgomery Art Prints": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 397,
+      "active": 0
+    },
+    "Paul Montgomery Original Art": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 49,
+      "active": 0
+    },
+    "Paul Montgomery Studios": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "paul_montgomery_catalog",
+      "backing": "Paul Montgomery",
+      "match": "suffix-strip",
+      "products": 443,
+      "active": 0
+    },
+    "Peel and Stick": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 92,
+      "active": 0
+    },
+    "Peg Norriss": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Peg Norriss",
+      "match": "exact",
+      "products": 3,
+      "active": 3
+    },
+    "Phillip Jeffries": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "pj_catalog",
+      "backing": "Phillip Jeffries",
+      "match": "exact",
+      "products": 3087,
+      "active": 2473
+    },
+    "Phillipe Romano": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "astek_catalog",
+      "backing": "Astek",
+      "match": "private-label",
+      "products": 18919,
+      "active": 10136
+    },
+    "Phyllis Morris": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 28,
+      "active": 27
+    },
+    "Pierre Frey": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "pierre_frey_catalog",
+      "backing": "Pierre Frey",
+      "match": "exact",
+      "products": 3,
+      "active": 3
+    },
+    "Pixels": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Pixels",
+      "match": "exact",
+      "products": 59,
+      "active": 59
+    },
+    "Plains": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "quadrille_house_catalog",
+      "backing": "Plains",
+      "match": "exact",
+      "products": 3,
+      "active": 3
+    },
+    "Porsche™ Paint - Speed Yellow": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 1,
+      "active": 0
+    },
+    "PR Faux Leather": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 418,
+      "active": 327
+    },
+    "Primo Leathers": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "primo_leathers_catalog",
+      "backing": "Primo Leathers",
+      "match": "exact",
+      "products": 135,
+      "active": 109
+    },
+    "Printy6": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Printy6",
+      "match": "exact",
+      "products": 1,
+      "active": 1
+    },
+    "PS Removable Wallpaper": {
+      "tier": "PORTAL_CREDS",
+      "live_capable": true,
+      "adapter": "wallquest",
+      "reason": "WallQuest trade portal (creds on file)",
+      "catalog_table": "wallquest_catalog",
+      "backing": null,
+      "match": "unmatched",
+      "products": 737,
+      "active": 736
+    },
+    "Quadrille": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "quadrille_house_catalog",
+      "backing": "Quadrille",
+      "match": "exact",
+      "products": 9,
+      "active": 9
+    },
+    "Ralph Lauren": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "rl_catalog",
+      "backing": "Ralph Lauren",
+      "match": "exact",
+      "products": 460,
+      "active": 142
+    },
+    "Ralph Lauren Fabric": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "rl_catalog",
+      "backing": "Ralph Lauren",
+      "match": "suffix-strip",
+      "products": 1742,
+      "active": 0
+    },
+    "Ralph Lauren Fabrics": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "rl_catalog",
+      "backing": "Ralph Lauren",
+      "match": "suffix-strip",
+      "products": 6,
+      "active": 0
+    },
+    "Ralph Lauren Wallpaper": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "rl_catalog",
+      "backing": "Ralph Lauren",
+      "match": "suffix-strip",
+      "products": 316,
+      "active": 0
+    },
+    "Rebecca Moses": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 1,
+      "active": 1
+    },
+    "Rebel Studio": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Rebel Studio",
+      "match": "exact",
+      "products": 2,
+      "active": 1
+    },
+    "Rebel Walls": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "rebelwalls_catalog",
+      "backing": "Rebel Walls",
+      "match": "exact",
+      "products": 3721,
+      "active": 3613
+    },
+    "Retro Walls": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 1073,
+      "active": 63
+    },
+    "Roberto Cavalli": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "roberto_cavalli_catalog",
+      "backing": "Roberto Cavalli",
+      "match": "exact",
+      "products": 1,
+      "active": 1
+    },
+    "Roberto Cavalli Wallpaper": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "roberto_cavalli_catalog",
+      "backing": "Roberto Cavalli",
+      "match": "suffix-strip",
+      "products": 180,
+      "active": 149
+    },
+    "Romo": {
+      "tier": "PORTAL_CREDS",
+      "live_capable": true,
+      "adapter": "romo",
+      "reason": "Romo trade portal (creds on file)",
+      "catalog_table": "romo_catalog",
+      "backing": "Romo",
+      "match": "exact",
+      "products": 568,
+      "active": 521
+    },
+    "Ronald Redding": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 732,
+      "active": 211
+    },
+    "Sacha Walckhoff": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Sacha Walckhoff",
+      "match": "exact",
+      "products": 3,
+      "active": 3
+    },
+    "Sancar": {
+      "tier": "PUBLIC_STOCK",
+      "live_capable": true,
+      "adapter": "shopify-public",
+      "reason": "public Shopify storefront stock (.js feed)",
+      "catalog_table": "sancar_catalog",
+      "backing": "Sancar",
+      "match": "exact",
+      "products": 42,
+      "active": 42
+    },
+    "Sandberg": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "sandberg_catalog",
+      "backing": "Sandberg",
+      "match": "exact",
+      "products": 991,
+      "active": 769
+    },
+    "Sara Bergqvist": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Sara Bergqvist",
+      "match": "exact",
+      "products": 1,
+      "active": 1
+    },
+    "Sarah Bartholomew": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Sarah Bartholomew",
+      "match": "exact",
+      "products": 1,
+      "active": 1
+    },
+    "Scalamandre": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "scalamandre_catalog",
+      "backing": "Scalamandre",
+      "match": "exact",
+      "products": 1280,
+      "active": 418
+    },
+    "Scalamandre Fabrics": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "scalamandre_catalog",
+      "backing": "Scalamandre",
+      "match": "suffix-strip",
+      "products": 10178,
+      "active": 1
+    },
+    "Scalamandre Wallpaper": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "scalamandre_catalog",
+      "backing": "Scalamandre",
+      "match": "suffix-strip",
+      "products": 1153,
+      "active": 966
+    },
+    "Schumacher": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "schumacher_catalog",
+      "backing": "Schumacher",
+      "match": "exact",
+      "products": 5180,
+      "active": 2340
+    },
+    "Schumacher Fabrics": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "schumacher_catalog",
+      "backing": "Schumacher",
+      "match": "suffix-strip",
+      "products": 4802,
+      "active": 0
+    },
+    "Schumacher Pillows": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "schumacher_catalog",
+      "backing": "Schumacher",
+      "match": "suffix-strip",
+      "products": 17,
+      "active": 0
+    },
+    "Schumacher Trim": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "schumacher_catalog",
+      "backing": "Schumacher",
+      "match": "suffix-strip",
+      "products": 1174,
+      "active": 0
+    },
+    "Schumacher USA": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "schumacher_catalog",
+      "backing": "Schumacher",
+      "match": "suffix-strip",
+      "products": 343,
+      "active": 0
+    },
+    "Schumacher Wallcoverings": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "schumacher_catalog",
+      "backing": "Schumacher",
+      "match": "suffix-strip",
+      "products": 1,
+      "active": 0
+    },
+    "Schumacher Wallpaper": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "schumacher_catalog",
+      "backing": "Schumacher",
+      "match": "suffix-strip",
+      "products": 2057,
+      "active": 0
+    },
+    "Scion": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 2,
+      "active": 1
+    },
+    "Showroom Line": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 43,
+      "active": 11
+    },
+    "Sir Edward": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 31,
+      "active": 0
+    },
+    "Sister Parish": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "sisterparish_catalog",
+      "backing": "Sister Parish",
+      "match": "exact",
+      "products": 72,
+      "active": 72
+    },
+    "Steve Abrams Studios": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 55,
+      "active": 51
+    },
+    "Steven Abrams Photography": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 1,
+      "active": 1
+    },
+    "Studio Ditte": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Studio Ditte",
+      "match": "exact",
+      "products": 1,
+      "active": 1
+    },
+    "Studio Printworks": {
+      "tier": "PUBLIC_STOCK",
+      "live_capable": true,
+      "adapter": "shopify-public",
+      "reason": "public Shopify storefront stock (.js feed)",
+      "catalog_table": "studio_printworks_catalog",
+      "backing": "Studio Printworks",
+      "match": "exact",
+      "products": 1,
+      "active": 0
+    },
+    "SUGARBOO": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 10,
+      "active": 10
+    },
+    "Suncloth": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "quadrille_house_catalog",
+      "backing": "Suncloth",
+      "match": "exact",
+      "products": 3,
+      "active": 3
+    },
+    "Surface Stick": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "surface_stick_catalog",
+      "backing": "Surface Stick",
+      "match": "exact",
+      "products": 751,
+      "active": 743
+    },
+    "Telefina Fine Fabrics": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 64,
+      "active": 0
+    },
+    "TEST": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 5,
+      "active": 0
+    },
+    "The Set Decorator": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 1,
+      "active": 0
+    },
+    "Thibaut": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "thibaut_catalog",
+      "backing": "Thibaut",
+      "match": "exact",
+      "products": 3874,
+      "active": 2052
+    },
+    "Threads": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "threads_catalog",
+      "backing": "Threads",
+      "match": "exact",
+      "products": 81,
+      "active": 71
+    },
+    "Timorous Beasties": {
+      "tier": "PORTAL_NO_CREDS",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor portal exists but no trade credentials on file — supply creds to enable",
+      "catalog_table": "timorous_catalog",
+      "backing": "Timorous Beasties",
+      "match": "exact",
+      "products": 2,
+      "active": 0
+    },
+    "Traditional Whimsy": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 214,
+      "active": 90
+    },
+    "Tres Tintas": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "tres_tintas_catalog",
+      "backing": "Tres Tintas",
+      "match": "exact",
+      "products": 577,
+      "active": 577
+    },
+    "Trikes-DL Couch-Eykon-Source-One": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 1,
+      "active": 0
+    },
+    "Trikes-DL Couch-Eykon-Tower": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 808,
+      "active": 0
+    },
+    "TWIL": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line (private-label aggregate or unmapped)",
+      "catalog_table": null,
+      "backing": null,
+      "match": "unmatched",
+      "products": 190,
+      "active": 0
+    },
+    "Ultrasuede": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "ultrasuede_catalog",
+      "backing": "Ultrasuede",
+      "match": "exact",
+      "products": 111,
+      "active": 108
+    },
+    "Vahallan": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Vahallan",
+      "match": "exact",
+      "products": 4,
+      "active": 4
+    },
+    "Versa Designed Surfaces": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "versa_catalog",
+      "backing": "Versa Designed Surfaces",
+      "match": "exact",
+      "products": 884,
+      "active": 842
+    },
+    "Versace": {
+      "tier": "QUOTE_ONLY",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "vendor does not publish live stock (to-the-trade / quote-only)",
+      "catalog_table": "versace_catalog",
+      "backing": "Versace",
+      "match": "exact",
+      "products": 542,
+      "active": 472
+    },
+    "Villa Nova": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "villa_nova_catalog",
+      "backing": "Villa Nova",
+      "match": "exact",
+      "products": 3,
+      "active": 3
+    },
+    "Wallpaper NYC": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Wallpaper NYC",
+      "match": "exact",
+      "products": 95,
+      "active": 12
+    },
+    "William Morris": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "william_morris_catalog",
+      "backing": "William Morris",
+      "match": "exact",
+      "products": 533,
+      "active": 526
+    },
+    "Winfield Thybony": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Winfield Thybony",
+      "match": "exact",
+      "products": 3,
+      "active": 2
+    },
+    "Witch & Watchman": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "vendor_catalog",
+      "backing": "Witch & Watchman",
+      "match": "exact",
+      "products": 10,
+      "active": 10
+    },
+    "Wolf Gordon": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "wolf_gordon_catalog",
+      "backing": "Wolf Gordon",
+      "match": "exact",
+      "products": 1527,
+      "active": 688
+    },
+    "Zeuxis Parrhasius at DW": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": null,
+      "backing": "Zeuxis Parrhasius",
+      "match": "suffix-strip",
+      "products": 5,
+      "active": 5
+    },
+    "Zeuxis Parrhasius Europe": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": null,
+      "backing": "Zeuxis Parrhasius",
+      "match": "suffix-strip",
+      "products": 32,
+      "active": 22
+    },
+    "Zinc Textile": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "zinc_catalog",
+      "backing": "Zinc Textile",
+      "match": "exact",
+      "products": 3,
+      "active": 3
+    },
+    "Zoffany": {
+      "tier": "NO_STOCK",
+      "live_capable": false,
+      "adapter": null,
+      "reason": "no live stock source identified for this line",
+      "catalog_table": "zoffany_catalog",
+      "backing": "Zoffany",
+      "match": "exact",
+      "products": 358,
+      "active": 322
+    }
+  }
+}
\ No newline at end of file
diff --git a/scripts/build-coverage.js b/scripts/build-coverage.js
new file mode 100644
index 0000000..8ce7486
--- /dev/null
+++ b/scripts/build-coverage.js
@@ -0,0 +1,217 @@
+#!/usr/bin/env node
+// build-coverage.js — the LIVE-STOCK COVERAGE AUDIT generator for all.designerwallcoverings.com.
+//
+// Classifies EVERY display-vendor in the grid into a feasibility tier and writes the
+// committed source-of-truth at data/live-stock-coverage.json. The server reads that file
+// to drive each card's "Check Live" enable/dim (data-driven, not hardcoded per vendor),
+// and the live worker reads the per-vendor `adapter` + `catalog_table` to route a scrape.
+//
+// Tiers (Steve's audit spec):
+//   PORTAL_CREDS    — backing vendor has a login portal AND trade creds on file → live-capable (metered).
+//   PUBLIC_STOCK    — backing storefront exposes stock with no login (Shopify .js / Woo Store API) → live-capable (metered headless).
+//   PORTAL_NO_CREDS — a portal exists but no creds → NOT live yet (needs creds); dims with that reason.
+//   QUOTE_ONLY      — to-the-trade / quote-only line that publishes no stock anywhere → NOT feasible; always dims.
+//   NO_STOCK        — no live stock source identified (private-label aggregate, one-off, internal) → dims.
+//
+//   $0 (local) — pure Postgres reads, no paid API.
+//
+//   node scripts/build-coverage.js            # write data/live-stock-coverage.json
+//   node scripts/build-coverage.js --dry      # print summary, don't write
+const fs = require('fs');
+const path = require('path');
+const { Pool } = require('pg');
+try { require('dotenv').config({ path: path.join(__dirname, '..', '.env') }); } catch {}
+
+const DSN = process.env.DATABASE_URL || 'postgresql:///dw_unified?host=/tmp';
+const OUT = path.join(__dirname, '..', 'data', 'live-stock-coverage.json');
+const DRY = process.argv.includes('--dry');
+
+// Mirror server.js's public-facing exclusion — banned upstream/private-label source names
+// never surface on the public grid, so they are not display-vendors we classify.
+const BANNED = /brewster|york|wallquest|wall\s*quest|newwall|new\s*wall\b|command\s*54|justin\s*david|nicolette\s*mayer|seabrook|chesapeake|nextwall|desima|carlsten/i;
+
+const norm = (s) => String(s || '').trim().toLowerCase().replace(/[.\s]+$/, '');
+// suffixes that distinguish a display-vendor variant from its registry parent
+const SUFFIX = /\s+(fabrics?|wallpapers?|wallcoverings?|walls?|trim|pillows?|murals?|at dw|europe|usa|uk|to go|home|studios?)$/i;
+const stripSuffix = (s) => { let p = String(s || ''); for (let i = 0; i < 3; i++) { const n = p.replace(SUFFIX, ''); if (n === p) break; p = n; } return p.trim(); };
+
+// Platform is detected from the catalog's PRODUCT_URL pattern, NOT vendor_registry.website_tech_stack
+// (that field is ~70% blank/wrong — hygge is tagged "unreachable" yet is a live public Shopify store).
+// CANONICAL Shopify storefront product URL = host/products/<single-handle> (exactly one segment after
+// /products/, so it exposes a public <url>.js stock feed). Thibaut's /products/wallcoverings/<code> has
+// TWO segments → login-gated, correctly excluded. Our own storefront is excluded (circular).
+const CANONICAL_SHOPIFY = /^https?:\/\/([^/]+)\/products\/[^/?#]+\/?(?:[?#].*)?$/i;
+const isCanonicalShopify = (url) => { const m = CANONICAL_SHOPIFY.exec(String(url || '')); return !!m && !/designerwallcoverings\.com/i.test(m[1]); };
+// WooCommerce single-product URL = host/product/<slug> (singular) → /wp-json/wc/store/products?slug=
+const WOO_URL = /^https?:\/\/[^/]+\/product\/[^/?#]+/i;
+// display-vendor labels that are WallQuest-backed but don't resolve through vendor_registry
+// (the private-label names the grid shows; SKUs live in wallquest_catalog).
+const WALLQUEST_ALIASES = new Set(['malibu wallpaper', 'ps removable wallpaper', 'malibu walls', 'malibu']);
+
+// 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.
+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',
+  'fortuny fabrics', 'pierre frey', 'manuel canovas', 'jim thompson', 'jim thompson fabrics',
+  'nobilis', 'elitis', 'maya romanoff', 'donghia', 'hermes', 'armani casa', 'armani/casa',
+  'dolce & gabbana', 'dolce and gabbana', 'versace', 'roberto cavalli', 'roberto cavalli wallpaper',
+  'christian lacroix europe', 'missoni home', 'missoni wallpaper', 'missoni fabric',
+  'kelly wearstler', 'martyn lawrence bullard', 'celerie kemble', 'sister parish',
+  'holly hunt', 'holly hunt walls', 'holly hunt in stock', 'quadrille', 'china seas',
+  'alan campbell', 'home couture', 'cloth and paper', 'charles burger', 'grasscloth',
+]);
+
+async function main() {
+  const pool = new Pool({ connectionString: DSN, max: 2 });
+
+  // 1. distinct display-vendors from the grid (same filter the server applies)
+  const { rows: vRows } = await pool.query(
+    `SELECT vendor, count(*)::int AS total,
+            count(*) FILTER (WHERE upper(coalesce(status,''))='ACTIVE')::int AS active
+       FROM shopify_products
+      WHERE coalesce(status,'') <> 'DELETED_FROM_SHOPIFY' AND vendor IS NOT NULL AND vendor <> ''
+      GROUP BY vendor`);
+  const displayVendors = vRows.filter((r) => !BANNED.test(r.vendor));
+
+  // 2. vendor_registry — the credential + portal + platform truth
+  const { rows: reg } = await pool.query(
+    `SELECT vendor_name, vendor_code, coalesce(private_label_name,'') AS private_label_name,
+            coalesce(catalog_table,'') AS catalog_table, coalesce(login_url,'') AS login_url,
+            (trade_password IS NOT NULL AND trade_password <> '') AS has_pass,
+            lower(coalesce(website_tech_stack,'')) AS stack,
+            coalesce(website_url,'') AS website_url,
+            display_prices
+       FROM vendor_registry`);
+
+  // 3. per catalog table: does it carry resolvable product_urls, and what PLATFORM are they?
+  //    (sampled from the URLs themselves — the reliable signal, vs the broken tech_stack field.)
+  const { rows: urlTabs } = await pool.query(
+    `SELECT c.table_name FROM information_schema.columns c
+      WHERE c.table_schema='public' AND c.column_name='product_url'
+        AND (c.table_name ~ '_catalog$' OR c.table_name ~ '^catalog_')`);
+  const catUrlCount = new Map(), catShopify = new Map(), catWoo = new Map();
+  for (const { table_name } of urlTabs) {
+    try {
+      const { rows } = await pool.query(
+        `SELECT product_url FROM "${table_name}" WHERE product_url IS NOT NULL AND product_url <> '' LIMIT 40`);
+      catUrlCount.set(table_name, rows.length);
+      const shop = rows.filter((r) => isCanonicalShopify(r.product_url)).length;
+      const woo = rows.filter((r) => WOO_URL.test(r.product_url)).length;
+      // majority-of-sample vote so one odd URL doesn't flip the platform
+      catShopify.set(table_name, rows.length > 0 && shop >= Math.max(1, rows.length * 0.5));
+      catWoo.set(table_name, rows.length > 0 && woo >= Math.max(1, rows.length * 0.5));
+    } catch { /* skip unreadable */ }
+  }
+  const hasUrls = (tbl) => tbl && (catUrlCount.get(tbl) || 0) > 0;
+  // shared bucket table is NOT per-SKU resolvable for a single vendor's live URL
+  const dedicated = (tbl) => tbl && tbl !== 'vendor_catalog';
+
+  // registry lookup indexes
+  const byName = new Map();          // lower(vendor_name) → row
+  const byPrivateLabel = new Map();  // lower(private_label_name) → [rows]
+  for (const r of reg) {
+    byName.set(norm(r.vendor_name), r);
+    if (r.private_label_name) (byPrivateLabel.get(norm(r.private_label_name)) || byPrivateLabel.set(norm(r.private_label_name), []).get(norm(r.private_label_name))).push(r);
+  }
+  // resolve a display-vendor → best backing registry row (+ how it matched)
+  function resolve(vendor) {
+    const v = norm(vendor);
+    if (byName.has(v)) return { row: byName.get(v), method: 'exact' };
+    // display name IS a private-label bucket → pick the strongest backing (creds > shopify > first)
+    if (byPrivateLabel.has(v)) {
+      const rows = byPrivateLabel.get(v);
+      const pick = rows.find((r) => r.has_pass) || rows.find((r) => catShopify.get(r.catalog_table)) || rows[0];
+      return { row: pick, method: 'private-label' };
+    }
+    const s = norm(stripSuffix(vendor));
+    if (s !== v && byName.has(s)) return { row: byName.get(s), method: 'suffix-strip' };
+    return { row: null, method: 'unmatched' };
+  }
+
+  // adapter routing (only the reliable-contract adapters ENABLE; Woo is wired-but-dimmed)
+  function classify(vendor, backing, method) {
+    const v = norm(vendor);
+    // A private-label BUCKET (e.g. "Phillipe Romano" = Astek + Command54 + Justin David) aggregates
+    // many upstreams — a single backing catalog can't represent it, so a public-stock scrape would
+    // mostly mis-route and could associate the private label with a real vendor's site. Only 1:1
+    // matches (exact / suffix-strip) earn a public-stock adapter; buckets stay dim unless WallQuest-backed.
+    const oneToOne = method === 'exact' || method === 'suffix-strip';
+    // 0. WallQuest-backed private labels that don't resolve through vendor_registry — the grid
+    //    shows the private-label name; SKUs live in wallquest_catalog (the adapter looks them up).
+    if (WALLQUEST_ALIASES.has(v))
+      return { tier: 'PORTAL_CREDS', live_capable: true, adapter: 'wallquest',
+        reason: 'WallQuest trade portal (creds on file)', catalog_table: 'wallquest_catalog' };
+    if (QUOTE_ONLY.has(v)) return { tier: 'QUOTE_ONLY', live_capable: false, adapter: null,
+      reason: 'vendor does not publish live stock (to-the-trade / quote-only)' };
+    if (!backing) return { tier: 'NO_STOCK', live_capable: false, adapter: null,
+      reason: 'no live stock source identified for this line (private-label aggregate or unmapped)' };
+
+    const tbl = backing.catalog_table || '', pl = norm(backing.private_label_name);
+    const isWQ = /^(wallquest|malibu|brewster)_catalog$/.test(tbl) || pl === 'malibu wallpaper';
+    const isRomo = norm(backing.vendor_code) === 'romo' || norm(backing.vendor_name) === 'romo';
+    // 1. PORTAL+CREDS — wired portal adapters. WallQuest resolves via wallquest_catalog regardless of
+    //    which sister row (brewster/malibu) mapped; Romo logs into trade.theromogroup.com.
+    if (isWQ)
+      return { tier: 'PORTAL_CREDS', live_capable: true, adapter: 'wallquest',
+        reason: 'WallQuest trade portal (creds on file)', catalog_table: 'wallquest_catalog' };
+    if (isRomo && hasUrls(tbl))
+      return { tier: 'PORTAL_CREDS', live_capable: true, adapter: 'romo',
+        reason: 'Romo trade portal (creds on file)', catalog_table: tbl || 'romo_catalog' };
+    // 2. PUBLIC_STOCK (Shopify) — canonical public .js feed, dedicated catalog, no login → ENABLE.
+    //    Precedes the portal check: a login_url may exist (an account page) yet stock is public.
+    if (oneToOne && dedicated(tbl) && hasUrls(tbl) && catShopify.get(tbl))
+      return { tier: 'PUBLIC_STOCK', live_capable: true, adapter: 'shopify-public',
+        reason: 'public Shopify storefront stock (.js feed)', catalog_table: tbl };
+    if (backing.has_pass) // creds exist but no adapter wired for this specific portal yet
+      return { tier: 'PORTAL_CREDS', live_capable: false, adapter: null,
+        reason: 'backing portal has trade creds but no live adapter wired yet', catalog_table: tbl };
+    // 3. PORTAL+NO-CREDS — a login portal exists but no creds (Magento/B2B hide stock) → needs creds
+    if (backing.login_url)
+      return { tier: 'PORTAL_NO_CREDS', live_capable: false, adapter: null,
+        reason: 'vendor portal exists but no trade credentials on file — supply creds to enable', catalog_table: tbl };
+    // 4. PUBLIC_STOCK (Woo) — WooCommerce Store API; adapter wired but not per-site verified → dim
+    if (oneToOne && dedicated(tbl) && hasUrls(tbl) && catWoo.get(tbl))
+      return { tier: 'PUBLIC_STOCK', live_capable: false, adapter: 'woo-public',
+        reason: 'WooCommerce stock adapter ready — pending per-site verification', catalog_table: tbl };
+    // 5. explicit quote-only signal from registry
+    if (backing.display_prices === false)
+      return { tier: 'QUOTE_ONLY', live_capable: false, adapter: null,
+        reason: 'vendor does not publish live stock (to-the-trade / quote-only)' };
+    return { tier: 'NO_STOCK', live_capable: false, adapter: null,
+      reason: 'no live stock source identified for this line' };
+  }
+
+  const vendors = {};
+  const counts = { PORTAL_CREDS: 0, PUBLIC_STOCK: 0, PORTAL_NO_CREDS: 0, QUOTE_ONLY: 0, NO_STOCK: 0, live_capable: 0 };
+  for (const dv of displayVendors) {
+    const { row: backing, method } = resolve(dv.vendor);
+    const c = classify(dv.vendor, backing, method);
+    vendors[dv.vendor] = {
+      tier: c.tier, live_capable: c.live_capable, adapter: c.adapter || null, reason: c.reason,
+      catalog_table: c.catalog_table || (backing && backing.catalog_table) || null,
+      backing: backing ? backing.vendor_name : null, match: method,
+      products: dv.total, active: dv.active,
+    };
+    counts[c.tier] = (counts[c.tier] || 0) + 1;
+    if (c.live_capable) counts.live_capable += 1;
+  }
+
+  const out = {
+    generated_at: new Date().toISOString(),
+    generator: 'scripts/build-coverage.js',
+    total_display_vendors: displayVendors.length,
+    counts,
+    // vendors keyed by the exact display-vendor string the grid uses (case-sensitive)
+    vendors,
+  };
+  await pool.end();
+
+  if (DRY) { console.log(JSON.stringify({ counts, total: out.total_display_vendors }, null, 2)); return; }
+  fs.writeFileSync(OUT, JSON.stringify(out, null, 2));
+  console.log(`coverage → ${OUT}`);
+  console.log(`  ${out.total_display_vendors} display-vendors | live-capable ${counts.live_capable}`);
+  console.log(`  PORTAL_CREDS ${counts.PORTAL_CREDS} · PUBLIC_STOCK ${counts.PUBLIC_STOCK} · PORTAL_NO_CREDS ${counts.PORTAL_NO_CREDS} · QUOTE_ONLY ${counts.QUOTE_ONLY} · NO_STOCK ${counts.NO_STOCK}`);
+}
+
+main().catch((e) => { console.error('coverage build failed:', e.message); process.exit(1); });

← 8c24b22 all-dw: show Mfr # (mfr_sku) + Mfr Name (supplier_name) as c  ·  back to All Designerwallcoverings  ·  live-stock adapter framework: generalized per-vendor registr af39b75 →