[object Object]

← back to Designer Wallcoverings

auto-save: 2026-07-27T20:24:23 (9 files) — shopify/scripts/data/tk135/audit-grid.png shopify/scripts/data/tk135/audit-thumbs/ shopify/scripts/data/tk135/bakeoff-grid.png shopify/scripts/data/tk135/bakeoff-thumbs/ shopify/scripts/data/tk135/material-sample200-unmatched.tsv

7ff5efd785f55e82049b90ac9f7297d8792d7cee · 2026-07-27 20:24:29 -0700 · Steve Abrams

Files touched

Diff

commit 7ff5efd785f55e82049b90ac9f7297d8792d7cee
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon Jul 27 20:24:29 2026 -0700

    auto-save: 2026-07-27T20:24:23 (9 files) — shopify/scripts/data/tk135/audit-grid.png shopify/scripts/data/tk135/audit-thumbs/ shopify/scripts/data/tk135/bakeoff-grid.png shopify/scripts/data/tk135/bakeoff-thumbs/ shopify/scripts/data/tk135/material-sample200-unmatched.tsv
---
 shopify/scripts/data/tk135/audit-grid.png          | Bin 0 -> 883857 bytes
 .../data/tk135/audit-thumbs/1495138402416.jpg      | Bin 0 -> 112645 bytes
 .../data/tk135/audit-thumbs/4509315170355.jpg      | Bin 0 -> 17706 bytes
 .../data/tk135/audit-thumbs/7375645245491.jpg      | Bin 0 -> 15434 bytes
 .../data/tk135/audit-thumbs/7422637310003.jpg      | Bin 0 -> 21950 bytes
 .../data/tk135/audit-thumbs/7866927120435.jpg      | Bin 0 -> 23908 bytes
 .../data/tk135/audit-thumbs/7878155206707.jpg      | Bin 0 -> 25580 bytes
 shopify/scripts/data/tk135/bakeoff-grid.png        | Bin 0 -> 866139 bytes
 .../data/tk135/bakeoff-thumbs/1495150952560.jpg    | Bin 0 -> 78286 bytes
 .../data/tk135/bakeoff-thumbs/1497253183600.jpg    | Bin 0 -> 6065 bytes
 .../data/tk135/bakeoff-thumbs/6829062881331.jpg    | Bin 0 -> 7465 bytes
 .../data/tk135/bakeoff-thumbs/7584977715251.jpg    | Bin 0 -> 5155 bytes
 .../data/tk135/bakeoff-thumbs/7855831384115.jpg    | Bin 0 -> 9429 bytes
 .../data/tk135/bakeoff-thumbs/7855840002099.jpg    | Bin 0 -> 7753 bytes
 .../data/tk135/bakeoff-thumbs/7882757308467.jpg    | Bin 0 -> 5100 bytes
 .../data/tk135/bakeoff-thumbs/7882828120115.jpg    | Bin 0 -> 15627 bytes
 .../data/tk135/bakeoff-thumbs/7896279056435.jpg    | Bin 0 -> 17003 bytes
 .../data/tk135/bakeoff-thumbs/7896475795507.jpg    | Bin 0 -> 15128 bytes
 .../data/tk135/material-sample200-unmatched.tsv    | 105 ++++++++
 shopify/scripts/data/tk135/material-sample200.tsv  |  95 +++++++
 shopify/scripts/data/tk135/vision-bakeoff-10.tsv   |  10 +
 shopify/scripts/data/tk17/batchA-full-run.json     |  24 ++
 .../scripts/tk135-material-classifier-dryrun.js    | 294 +++++++++++++++++++++
 23 files changed, 528 insertions(+)

diff --git a/shopify/scripts/data/tk135/audit-grid.png b/shopify/scripts/data/tk135/audit-grid.png
new file mode 100644
index 00000000..8d0bc1f2
Binary files /dev/null and b/shopify/scripts/data/tk135/audit-grid.png differ
diff --git a/shopify/scripts/data/tk135/audit-thumbs/1495138402416.jpg b/shopify/scripts/data/tk135/audit-thumbs/1495138402416.jpg
new file mode 100644
index 00000000..600eaddc
Binary files /dev/null and b/shopify/scripts/data/tk135/audit-thumbs/1495138402416.jpg differ
diff --git a/shopify/scripts/data/tk135/audit-thumbs/4509315170355.jpg b/shopify/scripts/data/tk135/audit-thumbs/4509315170355.jpg
new file mode 100644
index 00000000..6ad28236
Binary files /dev/null and b/shopify/scripts/data/tk135/audit-thumbs/4509315170355.jpg differ
diff --git a/shopify/scripts/data/tk135/audit-thumbs/7375645245491.jpg b/shopify/scripts/data/tk135/audit-thumbs/7375645245491.jpg
new file mode 100644
index 00000000..019d8396
Binary files /dev/null and b/shopify/scripts/data/tk135/audit-thumbs/7375645245491.jpg differ
diff --git a/shopify/scripts/data/tk135/audit-thumbs/7422637310003.jpg b/shopify/scripts/data/tk135/audit-thumbs/7422637310003.jpg
new file mode 100644
index 00000000..02f13ac3
Binary files /dev/null and b/shopify/scripts/data/tk135/audit-thumbs/7422637310003.jpg differ
diff --git a/shopify/scripts/data/tk135/audit-thumbs/7866927120435.jpg b/shopify/scripts/data/tk135/audit-thumbs/7866927120435.jpg
new file mode 100644
index 00000000..f9534538
Binary files /dev/null and b/shopify/scripts/data/tk135/audit-thumbs/7866927120435.jpg differ
diff --git a/shopify/scripts/data/tk135/audit-thumbs/7878155206707.jpg b/shopify/scripts/data/tk135/audit-thumbs/7878155206707.jpg
new file mode 100644
index 00000000..4e83d896
Binary files /dev/null and b/shopify/scripts/data/tk135/audit-thumbs/7878155206707.jpg differ
diff --git a/shopify/scripts/data/tk135/bakeoff-grid.png b/shopify/scripts/data/tk135/bakeoff-grid.png
new file mode 100644
index 00000000..30312807
Binary files /dev/null and b/shopify/scripts/data/tk135/bakeoff-grid.png differ
diff --git a/shopify/scripts/data/tk135/bakeoff-thumbs/1495150952560.jpg b/shopify/scripts/data/tk135/bakeoff-thumbs/1495150952560.jpg
new file mode 100644
index 00000000..66a7a45c
Binary files /dev/null and b/shopify/scripts/data/tk135/bakeoff-thumbs/1495150952560.jpg differ
diff --git a/shopify/scripts/data/tk135/bakeoff-thumbs/1497253183600.jpg b/shopify/scripts/data/tk135/bakeoff-thumbs/1497253183600.jpg
new file mode 100644
index 00000000..348b461e
Binary files /dev/null and b/shopify/scripts/data/tk135/bakeoff-thumbs/1497253183600.jpg differ
diff --git a/shopify/scripts/data/tk135/bakeoff-thumbs/6829062881331.jpg b/shopify/scripts/data/tk135/bakeoff-thumbs/6829062881331.jpg
new file mode 100644
index 00000000..372713ae
Binary files /dev/null and b/shopify/scripts/data/tk135/bakeoff-thumbs/6829062881331.jpg differ
diff --git a/shopify/scripts/data/tk135/bakeoff-thumbs/7584977715251.jpg b/shopify/scripts/data/tk135/bakeoff-thumbs/7584977715251.jpg
new file mode 100644
index 00000000..a64d1c75
Binary files /dev/null and b/shopify/scripts/data/tk135/bakeoff-thumbs/7584977715251.jpg differ
diff --git a/shopify/scripts/data/tk135/bakeoff-thumbs/7855831384115.jpg b/shopify/scripts/data/tk135/bakeoff-thumbs/7855831384115.jpg
new file mode 100644
index 00000000..641d00db
Binary files /dev/null and b/shopify/scripts/data/tk135/bakeoff-thumbs/7855831384115.jpg differ
diff --git a/shopify/scripts/data/tk135/bakeoff-thumbs/7855840002099.jpg b/shopify/scripts/data/tk135/bakeoff-thumbs/7855840002099.jpg
new file mode 100644
index 00000000..a3827dfe
Binary files /dev/null and b/shopify/scripts/data/tk135/bakeoff-thumbs/7855840002099.jpg differ
diff --git a/shopify/scripts/data/tk135/bakeoff-thumbs/7882757308467.jpg b/shopify/scripts/data/tk135/bakeoff-thumbs/7882757308467.jpg
new file mode 100644
index 00000000..4c676fde
Binary files /dev/null and b/shopify/scripts/data/tk135/bakeoff-thumbs/7882757308467.jpg differ
diff --git a/shopify/scripts/data/tk135/bakeoff-thumbs/7882828120115.jpg b/shopify/scripts/data/tk135/bakeoff-thumbs/7882828120115.jpg
new file mode 100644
index 00000000..c32ecacf
Binary files /dev/null and b/shopify/scripts/data/tk135/bakeoff-thumbs/7882828120115.jpg differ
diff --git a/shopify/scripts/data/tk135/bakeoff-thumbs/7896279056435.jpg b/shopify/scripts/data/tk135/bakeoff-thumbs/7896279056435.jpg
new file mode 100644
index 00000000..c4fbd169
Binary files /dev/null and b/shopify/scripts/data/tk135/bakeoff-thumbs/7896279056435.jpg differ
diff --git a/shopify/scripts/data/tk135/bakeoff-thumbs/7896475795507.jpg b/shopify/scripts/data/tk135/bakeoff-thumbs/7896475795507.jpg
new file mode 100644
index 00000000..d94a4518
Binary files /dev/null and b/shopify/scripts/data/tk135/bakeoff-thumbs/7896475795507.jpg differ
diff --git a/shopify/scripts/data/tk135/material-sample200-unmatched.tsv b/shopify/scripts/data/tk135/material-sample200-unmatched.tsv
new file mode 100644
index 00000000..23b7698a
--- /dev/null
+++ b/shopify/scripts/data/tk135/material-sample200-unmatched.tsv
@@ -0,0 +1,105 @@
+gid://shopify/Product/7416208261171	Clarke And Clarke	Latour - Taupe  By Clarke And Clarke | Clarke & Clarke Latour |  Multipurpose Weave
+gid://shopify/Product/7874381742131	Suncloth	Multi Blues Classic | Suncloth
+gid://shopify/Product/7810558853171	Los Angeles Fabrics	Trellis - Artisan | Commercial Fabric | Los Angeles Fabrics
+gid://shopify/Product/6606477918259	Designer Wallcoverings	Helen's Houndstooth Check White Table Runner on Lilly
+gid://shopify/Product/7416831246387	Clarke And Clarke	Miami - Cream Ivory By Clarke And Clarke | Clarke & Clarke Miami | Solid Drapery Velvet
+gid://shopify/Product/7882832576563	Phillipe Romano	Islamorada-Pewter Wallcovering | Phillipe Romano
+gid://shopify/Product/7810579562547	Los Angeles Fabrics	Soaring - Filigree | Commercial Fabric | Los Angeles Fabrics
+gid://shopify/Product/7878419054643	Pierre Frey	Brissac Celadon | Pierre Frey
+gid://shopify/Product/7876562059315	Thibaut	Night Garden, Spa Blue Wallcoverings | Thibaut
+gid://shopify/Product/7880946155571	Elitis	Madagascar À Peine Éclose ! | Elitis
+gid://shopify/Product/1498301923440	Phillipe Romano	Italiano Textile | Phillipe Romano
+gid://shopify/Product/1499205337200	Phillipe Romano	Uxbridge Specialty Wallcovering
+gid://shopify/Product/7422312546355	Brunschwig & Fils	Coeur Bullion-L - Ecru White By Brunschwig & Fils | Le Coeur Passementerie |  Trim Bullion
+gid://shopify/Product/7422317887539	Brunschwig & Fils	Coeur Tassel - Coral Orange By Brunschwig & Fils | Le Coeur Passementerie |  Trim Tassel / Tieback
+gid://shopify/Product/7867618033715	Thibaut	Balin Ikat, Beige Wallcoverings | Thibaut
+gid://shopify/Product/7422933303347	Lee Jofa	Dame - Straw/Ebony Beige By Lee Jofa Modern | Kelly Wearstler Leather Collection |Animal Skins  Upholstery Leather/Suede
+gid://shopify/Product/7810456223795	Los Angeles Fabrics	Dolphin - Gardenia | Commercial Fabric | Los Angeles Fabrics
+gid://shopify/Product/7421915529267	GP & J Baker	Baker House Fr Velvet - Indigo Blue By G P & J Baker | Baker House Fr Velvet |Solid  Upholstery Velvet
+gid://shopify/Product/7882770153523	Hollywood Wallcoverings	Beam 250 Timber 9H x 108L Harvest Tan | Hollywood Wallcoverings
+gid://shopify/Product/7416228347955	Clarke And Clarke	Bw1023 - Black/White  By Clarke And Clarke | Clarke & Clarke Black + White |  Multipurpose Weave
+gid://shopify/Product/7416185520179	Clarke And Clarke	Casanova - Antique  By Clarke And Clarke | Clarke & Clarke Casanova |Solid Texture Multipurpose Chenille
+gid://shopify/Product/7810450325555	Los Angeles Fabrics	Flamingo - Horseradish | Commercial Fabric | Los Angeles Fabrics
+gid://shopify/Product/1495149903984	PR Faux Leather	Glaze�� - Faux Vintage Leather - Bordeaux
+gid://shopify/Product/7416219500595	Clarke And Clarke	Highlander - Moss  By Clarke And Clarke | Clarke & Clarke Highlander 2 |Solid Texture Multipurpose
+gid://shopify/Product/7864389632051	Los Angeles Fabrics	Infatuation - Tinsel | Commercial Fabric | Los Angeles Fabrics
+gid://shopify/Product/7416163008563	Clarke And Clarke	Linoso - Pesto  By Clarke And Clarke | Clarke & Clarke Linoso Ii |Solid Texture Multipurpose
+gid://shopify/Product/7416315871283	Clarke And Clarke	Martello - Charcoal  By Clarke And Clarke | Clarke & Clarke Martello |  Multipurpose Velvet
+gid://shopify/Product/1495121363056	PR Faux Leather	Milano�� Classic Faux Leather - Brandy
+gid://shopify/Product/7810568028211	Los Angeles Fabrics	Nectar - Macaw | Commercial Fabric | Los Angeles Fabrics
+gid://shopify/Product/4693301067827	Nina Campbell	Nina Campbell Fabric - Chartreuse Green Wallcovering | Nina Campbell
+gid://shopify/Product/4693305524275	Nina Campbell	Nina Campbell Fabric - Oatmeal Wallcovering | Nina Campbell
+gid://shopify/Product/4693303328819	Nina Campbell	Nina Campbell Fabric - Teal Blue Wallcovering | Nina Campbell
+gid://shopify/Product/7821430325299	Novasuede	Novasuede™ Fabric & Wallcovering - Verdigris
+gid://shopify/Product/7416690212915	Clarke And Clarke	Puro - Chalk  By Clarke And Clarke | Clarke & Clarke Lusso Sheers |Solid  Drapery Weave
+gid://shopify/Product/7796281475123	Los Angeles Fabrics	Sandbar - Ironwood Faux Leather | Commercial Fabric | Los Angeles Fabrics
+gid://shopify/Product/7810445279283	Los Angeles Fabrics	Shorescape - Plateau | Commercial Fabric | Los Angeles Fabrics
+gid://shopify/Product/7876656922675	Suncloth	Tashkent, Pale Griege on White | Suncloth
+gid://shopify/Product/7099513143347	Hollywood Acoustical	Yettington Acoustical Wallcovering
+gid://shopify/Product/7875514990643	Kravet	Kravet Basics, Seafoam Green Wallcoverings | Kravet
+gid://shopify/Product/7866117095475	Thibaut	Palampore Leaf, Blue and White Wallcoverings | Thibaut
+gid://shopify/Product/7552688947251	Anna French	Woodland Blue Wallcovering
+gid://shopify/Product/1497511362672	Phillipe Romano	GlamFab - Pleated Knit Backed Fabric for Walls
+gid://shopify/Product/7880018493491	Hollywood Wallcoverings	South Salmon Silhouette | Hollywood Wallcoverings
+gid://shopify/Product/7896373329971	Carnegie	Carnegie Xorel Prism
+gid://shopify/Product/7817253322803	AS Creation	Michalsky 6 Gray Wallcovering | AS Creation
+gid://shopify/Product/7864807096371	Wolf Gordon	Divine Frosted | Wolf Gordon Wallcoverings
+gid://shopify/Product/1502346805360	Phillipe Romano	Merana | Phillipe Romano
+gid://shopify/Product/7882827694131	Phillipe Romano	Edgartown-Putty Wallcovering | Phillipe Romano
+gid://shopify/Product/7297436713011	PS Removable Wallpaper	Malibu Ps Wood Panel Rustic Wood - Alabaster | Peel and Stick Removable Wallcovering
+gid://shopify/Product/1498005569648	Phillipe Romano	Alaminos Arrowroot | Phillipe Romano
+gid://shopify/Product/4396410699827	Phillipe Romano	Luxuria Beige | Phillipe Romano
+gid://shopify/Product/7896398856243	Coordonné	Rolling-Stripes Sage | Coordonné
+gid://shopify/Product/7384904826931	Maya Romanoff	Grand Scale Ajiro Coffers - Chestnut | Maya Romanoff
+gid://shopify/Product/7898462978099	CMO Paris	Bois Marbré Ecaille Zinc | CMO Paris
+gid://shopify/Product/7877387911219	Kravet	On the Horizon, Off-White Wallcoverings | Kravet
+gid://shopify/Product/7866952253491	Thibaut	Gibson, Navy Wallcoverings | Thibaut
+gid://shopify/Product/7882842767411	Phillipe Romano	Osterville-Harbor Mist Wallcovering | Phillipe Romano
+gid://shopify/Product/7896290459699	Anthology	Anthology - Nisiros Bronze / Basalt Wallcovering | Anthology
+gid://shopify/Product/7882831462451	Phillipe Romano	Jupiter-Flint Wallcovering | Phillipe Romano
+gid://shopify/Product/1499742109808	Phillipe Romano	Boynton Stain Repellent Real Suede | Phillipe Romano
+gid://shopify/Product/7876147511347	Kravet	Kravet Basics, Forest Green Wallcoverings | Kravet
+gid://shopify/Product/7865301827635	Thibaut	Westmont, Blush Wallcoverings | Thibaut
+gid://shopify/Product/7794234720307	Zoffany	Artisan Palampore - Primrose wallcovering | Zoffany
+gid://shopify/Product/1495881711728	Designer Wallcoverings	Et Cie The Huntington Wall Mural Panel #6
+gid://shopify/Product/7876473913395	Thibaut	Virginia, Cream and Aqua Wallcoverings | Thibaut
+gid://shopify/Product/7880948285491	Elitis	Volute Y Faire Son Miel | Elitis
+gid://shopify/Product/6944664682547	Thibaut	Indies Ikat Lavender and French Blue - Lavender and French Blue Wallcovering | Thibaut
+gid://shopify/Product/7388488826931	Phillipe Romano	La Calabria Mint Natural | Phillipe Romano
+gid://shopify/Product/7793953275955	Zoffany	Emperors Musician - Indigo wallcovering | Zoffany
+gid://shopify/Product/7880948678707	Elitis	Moshi Moshi Donner Du Sens | Elitis
+gid://shopify/Product/7817251586099	AS Creation	Daniel Hechter 7 Dark Purple Wallcovering | AS Creation
+gid://shopify/Product/7878157664307	Pierre Frey	Les ombrelles rayure Bleu | Pierre Frey
+gid://shopify/Product/7897178800179	Vahallan	Liana Wallcovering | Vahallan
+gid://shopify/Product/7692850462771	Novasuede	Novasuede™ - Buff Luxury Suede
+gid://shopify/Product/7817254404147	AS Creation	A.s. Creation Design Panel Anna D Andrea Green Wallcovering | AS Creation
+gid://shopify/Product/7692852035635	Novasuede	Novasuede™ - Light Amethyst Luxury Suede
+gid://shopify/Product/7817258303539	AS Creation	Walls By Patel Beige Wallcovering | AS Creation
+gid://shopify/Product/1499597570160	Phillipe Romano	Fulton Stain Repellent Real Textile | Phillipe Romano
+gid://shopify/Product/7880940945459	Elitis	Cesteria Les Fibres Du Plaisir | Elitis
+gid://shopify/Product/7810544566323	Los Angeles Fabrics	Aloha - Summit | Commercial Fabric | Los Angeles Fabrics
+gid://shopify/Product/7832785813555	Scalamandre	Backyard Bengal Outdoor Pillow Lumbar 14X22 Ivy | Scalamandre
+gid://shopify/Product/7801633701939	Thibaut	Bree Tape Tapes & Trims – Paprika and Soft Gold Fabric | Thibaut
+gid://shopify/Product/7896369725491	Carnegie	Carnegie Pigment
+gid://shopify/Product/7896367464499	Carnegie	Carnegie Xorel Strie
+gid://shopify/Product/7810432663603	Los Angeles Fabrics	Coralia - Sorghum | Commercial Fabric | Los Angeles Fabrics
+gid://shopify/Product/7422349705267	Gaston Y Daniela	Kf Gyd:: -  Yellow By Gaston Y Daniela | Gaston Africalia |Solid Texture Upholstery Indoor / Outdoor
+gid://shopify/Product/7416207671347	Clarke And Clarke	Latour - Citrus  By Clarke And Clarke | Clarke & Clarke Latour |  Multipurpose Weave
+gid://shopify/Product/7413740437555	Brunschwig & Fils	Loriyan Tape - Multi Multi By Brunschwig & Fils | Treillis Passementerie |  Trim Braid / Tape
+gid://shopify/Product/7810573697075	Los Angeles Fabrics	Seafarer - Waterfront | Commercial Fabric | Los Angeles Fabrics
+gid://shopify/Product/7810545483827	Los Angeles Fabrics	Steward - Rainbow | Commercial Fabric | Los Angeles Fabrics
+gid://shopify/Product/7810559115315	Los Angeles Fabrics	Trellis - Poinsettia | Commercial Fabric | Los Angeles Fabrics
+gid://shopify/Product/4466673811507	Innovations USA	Zion | Innovations USA
+gid://shopify/Product/7832779587635	Scalamandre	Backyard Bengal Outdoor Pillow Square 22X22 Ivy | Scalamandre
+gid://shopify/Product/7422134059059	Lee Jofa	Avignon Tape - Grey White By Lee Jofa | Suzanne Kasler Collection Ii |  Trim Braid / Tape
+gid://shopify/Product/7799402823731	Atomic 50 Ceilings	AT50-04 Unfinished | Atomic 50
+gid://shopify/Product/7832789516339	Scalamandre	Corbet Pillow Square 22X22 Blue | Scalamandre
+gid://shopify/Product/7864374263859	Los Angeles Fabrics	Hampton - Key Lime | Commercial Fabric | Los Angeles Fabrics
+gid://shopify/Product/7810441248819	Los Angeles Fabrics	Iguana - Cay | Commercial Fabric | Los Angeles Fabrics
+gid://shopify/Product/7419648114739	Gaston Y Daniela	Kurt - Lino Beige By Gaston Y Daniela | Lorenzo Castillo Vi | Texture Upholstery Indoor / Outdoor
+gid://shopify/Product/7810541912115	Los Angeles Fabrics	Liana - Tangerine | Commercial Fabric | Los Angeles Fabrics
+gid://shopify/Product/7416909266995	Clarke And Clarke	Majorelle - Outdoor Ivory By Clarke And Clarke | Clarke & Clarke Alfresco |Botanical & Floral Tropical Multipurpose Indoor / Outdoor
+gid://shopify/Product/7874108293171	Plains	Mink | Plains
+gid://shopify/Product/7422386503731	Gaston Y Daniela	Olmo - Crudo White By Gaston Y Daniela | Gaston Libreria |Solid Texture Upholstery
+gid://shopify/Product/7832786239539	Scalamandre	Pomfret Pillow Square 22X22 Lapis | Scalamandre
+gid://shopify/Product/4466669846579	Innovations USA	Spalt | Innovations USA
diff --git a/shopify/scripts/data/tk135/material-sample200.tsv b/shopify/scripts/data/tk135/material-sample200.tsv
new file mode 100644
index 00000000..fbbc4e03
--- /dev/null
+++ b/shopify/scripts/data/tk135/material-sample200.tsv
@@ -0,0 +1,95 @@
+gid://shopify/Product/7899330707507	Sisal
+gid://shopify/Product/7822756511795	Silk
+gid://shopify/Product/7896254119987	Silk
+gid://shopify/Product/7896255496243	Vinyl
+gid://shopify/Product/7865241239603	Vinyl
+gid://shopify/Product/7896256970803	Vinyl
+gid://shopify/Product/7865526976563	Vinyl
+gid://shopify/Product/7896220762163	Paper
+gid://shopify/Product/7896225185843	Silk
+gid://shopify/Product/7878818988083	Wool
+gid://shopify/Product/7832788926515	Linen
+gid://shopify/Product/7878808240179	Wool
+gid://shopify/Product/7897507299379	Vinyl
+gid://shopify/Product/7421293789235	Cotton
+gid://shopify/Product/6948078157875	Cotton
+gid://shopify/Product/7416184537139	Cotton
+gid://shopify/Product/7416245289011	Cotton
+gid://shopify/Product/7416881217587	Silk
+gid://shopify/Product/7419530805299	Wool
+gid://shopify/Product/7422104469555	Cotton
+gid://shopify/Product/7864792743987	Mylar
+gid://shopify/Product/7297457520691	Vinyl
+gid://shopify/Product/7896995594291	Wool
+gid://shopify/Product/7297527218227	Vinyl
+gid://shopify/Product/7297400504371	Vinyl
+gid://shopify/Product/7297531740211	Vinyl
+gid://shopify/Product/7896462557235	Wool
+gid://shopify/Product/7896451612723	Wool
+gid://shopify/Product/7896461344819	Wool
+gid://shopify/Product/7896372314163	Wool
+gid://shopify/Product/7422417567795	Wool
+gid://shopify/Product/7898836762675	Silk
+gid://shopify/Product/4396398936115	Silk
+gid://shopify/Product/4396416925747	Silk
+gid://shopify/Product/6948076847155	Grasscloth
+gid://shopify/Product/7882836279347	Vinyl
+gid://shopify/Product/7882822385715	Non-woven
+gid://shopify/Product/7297460568115	Paper-weave
+gid://shopify/Product/7297412759603	Paper-weave
+gid://shopify/Product/7297376911411	Paper-weave
+gid://shopify/Product/7297533575219	Paper-weave
+gid://shopify/Product/6941805346867	Wool
+gid://shopify/Product/7421296410675	Silk
+gid://shopify/Product/7882825662515	Grasscloth
+gid://shopify/Product/7896295637043	Vinyl
+gid://shopify/Product/7876903043123	Vinyl
+gid://shopify/Product/7865526747187	Paper-weave
+gid://shopify/Product/7896263458867	Non-woven
+gid://shopify/Product/7692851052595	Vinyl
+gid://shopify/Product/4348479078451	Non-woven
+gid://shopify/Product/7896288493619	Silk
+gid://shopify/Product/7814464831539	Cork
+gid://shopify/Product/7864373280819	Vinyl
+gid://shopify/Product/1501217030256	Vinyl
+gid://shopify/Product/7882811310131	Grasscloth
+gid://shopify/Product/7887507390515	Linen
+gid://shopify/Product/7876465164339	Vinyl
+gid://shopify/Product/7870482776115	Vinyl
+gid://shopify/Product/7882810851379	Paper-weave
+gid://shopify/Product/7876774920243	Vinyl
+gid://shopify/Product/7817263415347	Non-woven
+gid://shopify/Product/7876147576883	Vinyl
+gid://shopify/Product/7870604345395	Vinyl
+gid://shopify/Product/7877196021811	Vinyl
+gid://shopify/Product/7870021107763	Vinyl
+gid://shopify/Product/1497504776304	Paper-weave
+gid://shopify/Product/7882812162099	Paper-weave
+gid://shopify/Product/7421293461555	Silk
+gid://shopify/Product/7870218895411	Wool
+gid://shopify/Product/7419637661747	Silk
+gid://shopify/Product/7416866275379	Silk
+gid://shopify/Product/7417272369203	Silk
+gid://shopify/Product/7885998293043	Paper
+gid://shopify/Product/7880944975923	Silk
+gid://shopify/Product/6948084482099	Vinyl
+gid://shopify/Product/7794228133939	Vinyl
+gid://shopify/Product/7876062838835	Vinyl
+gid://shopify/Product/7793954488371	Vinyl
+gid://shopify/Product/7864796119091	Vinyl
+gid://shopify/Product/7880940388403	Silk
+gid://shopify/Product/7873963458611	Vinyl
+gid://shopify/Product/7880947466291	Silk
+gid://shopify/Product/7817262956595	Vinyl
+gid://shopify/Product/1495880990832	Vinyl
+gid://shopify/Product/7878391529523	Cotton
+gid://shopify/Product/7413738602547	Cotton
+gid://shopify/Product/7832781193267	Wool
+gid://shopify/Product/7416185421875	Silk
+gid://shopify/Product/7422348099635	Wool
+gid://shopify/Product/7413668413491	Linen
+gid://shopify/Product/7413642133555	Cotton
+gid://shopify/Product/7422865571891	Wool
+gid://shopify/Product/7878412304435	Silk
+gid://shopify/Product/7878384910387	Silk
+gid://shopify/Product/7885749846067	Vinyl
diff --git a/shopify/scripts/data/tk135/vision-bakeoff-10.tsv b/shopify/scripts/data/tk135/vision-bakeoff-10.tsv
new file mode 100644
index 00000000..e8d6171f
--- /dev/null
+++ b/shopify/scripts/data/tk135/vision-bakeoff-10.tsv
@@ -0,0 +1,10 @@
+gid://shopify/Product/7896279056435		https://cdn.shopify.com/s/files/1/0015/4117/7456/files/GWP-3727.355.0.jpg?v=1784734742	UNMATCHED:Roulade Paper Navy/Teal | Groundworks
+gid://shopify/Product/6829062881331		https://cdn.shopify.com/s/files/1/0015/4117/7456/files/prw-920571-mks-012.jpg?v=1781716164	UNMATCHED:Roseland Heights Type 2 | Phillipe Romano
+gid://shopify/Product/7882757308467		https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0148968_crossroad-wallpaper-whitewash_abfafda2-c68d-4cfe-922e-c7a2956b99f2.jpg?v=1783866063	UNMATCHED:Crossroad Whitewash | Jeffrey Stevens
+gid://shopify/Product/7882828120115		https://cdn.shopify.com/s/files/1/0015/4117/7456/files/3b0d60193d283c498b57bec9778fd493.jpg?v=1783880854	UNMATCHED:Vineyard Haven-Oak Buff Wallcovering | Phillipe Romano
+gid://shopify/Product/7584977715251		https://cdn.shopify.com/s/files/1/0015/4117/7456/files/MARMORINO_TERRA_7321-12_new_f812593d-a513-495a-a72e-10915d4ead1c.jpg?v=1751949555	UNMATCHED:Marmorino Terra - Burnt Sienna Commercial Wallcovering | Kor
+gid://shopify/Product/7855831384115		https://cdn.shopify.com/s/files/1/0015/4117/7456/files/R19712_interior1.jpg?v=1781029646	UNMATCHED:Colorful Sunset - Golden Orange | Rebel Walls
+gid://shopify/Product/1495150952560		https://cdn.shopify.com/s/files/1/0015/4117/7456/products/3953d719bb51792fda1ddd6b0f90e2a6.png?v=1572308967	UNMATCHED:Glaze�� - Faux Vintage Leather - Walnut
+gid://shopify/Product/1497253183600		https://cdn.shopify.com/s/files/1/0015/4117/7456/products/2f256cebc7289705a473d9153b37eeef.jpg?v=1572309624	UNMATCHED:Palerma with Surface Stick - Faux Wood Grain Self Adhesive
+gid://shopify/Product/7855840002099		https://cdn.shopify.com/s/files/1/0015/4117/7456/files/R19047_interior1.jpg?v=1781030117	UNMATCHED:Downhill - Cool Gray | Rebel Walls
+gid://shopify/Product/7896475795507		https://cdn.shopify.com/s/files/1/0015/4117/7456/files/BBSU04.jpg?v=1784741564	UNMATCHED:London Big Sur Coast Road Wallcovering | Phillipe Romano
diff --git a/shopify/scripts/data/tk17/batchA-full-run.json b/shopify/scripts/data/tk17/batchA-full-run.json
new file mode 100644
index 00000000..aba4a200
--- /dev/null
+++ b/shopify/scripts/data/tk17/batchA-full-run.json
@@ -0,0 +1,24 @@
+{
+  "ticket": "TK-17",
+  "batch": "A",
+  "started": "2026-07-28T00:52:37.239Z",
+  "apply": true,
+  "worklist": "/Users/macstudio3/Projects/consulting-designerwallcoverings-com/data/work-orders/execution/batchA-quotes-tag-worklist.tsv",
+  "tag": "quotes",
+  "tagged": 9684,
+  "errors": [],
+  "byVendor": {
+    "Alan Campbell": 434,
+    "Architectural Fabrics": 328,
+    "China Seas": 1776,
+    "Donghia": 154,
+    "Home Couture": 229,
+    "Koroseal": 2454,
+    "Maya Romanoff": 624,
+    "Newmor Wallcoverings": 512,
+    "Phillip Jeffries": 2461,
+    "Quadrille": 443,
+    "Wolf Gordon": 269
+  },
+  "finished": "2026-07-28T03:11:17.502Z"
+}
\ No newline at end of file
diff --git a/shopify/scripts/tk135-material-classifier-dryrun.js b/shopify/scripts/tk135-material-classifier-dryrun.js
new file mode 100644
index 00000000..a5d75504
--- /dev/null
+++ b/shopify/scripts/tk135-material-classifier-dryrun.js
@@ -0,0 +1,294 @@
+#!/usr/bin/env node
+/**
+ * TK-00135 — MATERIAL descriptor backfill DRY-RUN (free/local, NO WRITES, NO paid API).
+ *
+ * HARD CONSTRAINTS (Steve):
+ *   - local models only  ->  $0 (local)
+ *   - NO LIVE WRITES to Shopify / PostgreSQL — this only emits a proposed TSV,
+ *     gated for Steve.
+ *   - Output tags are BARE VALUES, NO label prefix:  "Linen", "Grasscloth",
+ *     "Vinyl"  — NEVER "material:Linen".
+ *
+ * Classifies every ACTIVE product that is MISSING a material tag into one of the
+ * 15 buckets, resolving by SOURCE PRIORITY (deterministic first, qwen2.5 only
+ * for the ambiguous remainder):
+ *   1. specs / specifications metafield  (specs.material / .composition / .content
+ *                                          / specifications.material_type)
+ *   2. existing composition tag          ("Cotton - 90%;Linen - 10%" etc.)
+ *   3. TITLE keywords
+ *   4. vendor conventions                (vendors that are ~all one material)
+ *   5. qwen2.5:latest                    (ambiguous remainder, local, $0)
+ *
+ * Buckets (BARE output values):
+ *   Cotton Linen Vinyl Grasscloth Silk Paper Paper-weave Mylar Cork Wool
+ *   Jute Sisal Mica Metallic Non-woven
+ *
+ * Inputs (produced by the SQL pulls documented in the ticket log):
+ *   --active   TSV: gid \t title \t vendor \t product_type \t specs_material
+ *                   \t specs_composition \t specs_content \t spec_material_type
+ *   --tags     TSV: gid \t comma-joined-tags   (to find composition tags + the
+ *                   set already-having-material, which we SKIP)
+ *   --vendorconv JSON: { "<vendor>": "<BareMaterial>" }   (data-derived conventions)
+ *
+ * Usage:
+ *   node tk135-material-classifier-dryrun.js                 # full dry-run
+ *   node tk135-material-classifier-dryrun.js --sample 200    # 200-product validation
+ *   node tk135-material-classifier-dryrun.js --no-llm        # deterministic only
+ *   node tk135-material-classifier-dryrun.js --llm-batch 15  # qwen batch size
+ *
+ * NOTHING here writes to Shopify or Postgres.  Output is a proposal TSV only.
+ */
+const fs = require('fs');
+const path = require('path');
+const { execSync } = require('child_process');
+
+const args = process.argv.slice(2);
+const arg = (k, d) => { const i = args.indexOf(k); return i >= 0 ? args[i + 1] : d; };
+const has = (k) => args.includes(k);
+
+const ACTIVE = arg('--active', '/tmp/tk135-active-full.tsv');
+const TAGS   = arg('--tags',   '/tmp/tk135-mat-active-tags.tsv');
+const VCONV  = arg('--vendorconv', '/tmp/tk135-vendor-conv.json');
+const OUT    = arg('--out', path.join(__dirname, 'data/tk135/material-proposed.tsv'));
+const SAMPLE = parseInt(arg('--sample', '0'), 10);       // 0 = full run
+const NO_LLM = has('--no-llm');
+const LLM_BATCH = parseInt(arg('--llm-batch', '15'), 10);
+const LLM_MODEL = arg('--llm-model', 'qwen2.5:latest');
+
+// ---- the 15 buckets, ordered most-specific -> most-generic ----------------
+// Each bucket: BARE output value + keyword list. Order matters: "Paper-weave"
+// must be tested before "Paper"; "Grasscloth"/"Non-woven" before fibre words.
+const BUCKETS = [
+  ['Paper-weave', ['paper weave', 'paper-weave', 'paperweave']],
+  ['Grasscloth',  ['grasscloth', 'grass cloth', 'grass and natural', 'grass - 100', 'hemp grasscloth']],
+  ['Non-woven',   ['non-woven', 'non woven', 'nonwoven']],
+  ['Vinyl',       ['vinyl', 'pvc', 'poly vinyl chloride', 'polyvinyl chloride']],
+  ['Cotton',      ['cotton']],
+  ['Linen',       ['linen']],
+  ['Silk',        ['silk']],
+  ['Wool',        ['wool', 'mohair']],
+  ['Jute',        ['jute']],
+  ['Sisal',       ['sisal']],
+  ['Mica',        ['mica']],
+  ['Cork',        ['cork']],
+  ['Mylar',       ['mylar']],
+  ['Metallic',    ['metallic']],
+  ['Paper',       ['paper']],
+];
+const VALID = new Set(BUCKETS.map((b) => b[0]));
+
+// keyword -> bucket for the LLM output normalizer
+const KW2BUCKET = {};
+for (const [val, kws] of BUCKETS) for (const kw of kws) KW2BUCKET[kw] = val;
+
+// Whole-tag / composition-tag classifier (strong): tag == kw or "kw - N%..."
+function fromTagList(tagsLower, strongOnly) {
+  const joined = ' , ' + tagsLower.join(' , ') + ' , ';
+  for (const [val, kws] of BUCKETS) {
+    for (const kw of kws) {
+      for (const t of tagsLower) {
+        if (t === kw || t.startsWith(kw + ' - ') || t.startsWith(kw + ' on ')) return val;
+      }
+    }
+  }
+  if (strongOnly) return null;
+  for (const [val, kws] of BUCKETS) {
+    for (const kw of kws) if (joined.includes(' ' + kw) || joined.includes(kw)) return val;
+  }
+  return null;
+}
+
+// Free-text classifier for a metafield string ("Silk - 85%, Polyester - 15%",
+// "Type II 20oz Vinyl", "Paulownia Veneer", ...). Uses the FIRST/dominant
+// component so a Silk-dominant blend classifies Silk, not the polyester filler.
+function fromText(text) {
+  if (!text) return null;
+  const s = String(text).toLowerCase();
+  // dominant component = first listed (compositions list primary fibre first)
+  for (const [val, kws] of BUCKETS) {
+    for (const kw of kws) {
+      const i = s.indexOf(kw);
+      if (i >= 0) return val;
+    }
+  }
+  return null;
+}
+
+// Title-keyword classifier: word-boundary so "paperweave" motifs don't
+// false-hit; require the keyword to appear as a real token.
+function fromTitle(title) {
+  if (!title) return null;
+  const s = title.toLowerCase();
+  for (const [val, kws] of BUCKETS) {
+    for (const kw of kws) {
+      const re = new RegExp('(^|[^a-z])' + kw.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + '($|[^a-z])', 'i');
+      if (re.test(s)) return val;
+    }
+  }
+  return null;
+}
+
+// ---- load inputs ----------------------------------------------------------
+const tagsByGid = new Map();       // gid -> lowercased tag array
+const hasMaterialGid = new Set();  // gids that already carry a material (SKIP)
+for (const line of fs.readFileSync(TAGS, 'utf8').split('\n')) {
+  if (!line) continue;
+  const i = line.indexOf('\t');
+  if (i < 0) continue;
+  const gid = line.slice(0, i);
+  const tagsLower = line.slice(i + 1).split(',').map((t) => t.trim().toLowerCase());
+  tagsByGid.set(gid, tagsLower);
+  if (fromTagList(tagsLower, false)) hasMaterialGid.add(gid);
+}
+
+let vendorConv = {};
+try { vendorConv = JSON.parse(fs.readFileSync(VCONV, 'utf8')); } catch { vendorConv = {}; }
+// normalize vendor keys to lower for match
+const vendorConvLC = {};
+for (const [k, v] of Object.entries(vendorConv)) vendorConvLC[k.toLowerCase()] = v;
+
+// active rows
+const active = [];
+for (const line of fs.readFileSync(ACTIVE, 'utf8').split('\n')) {
+  if (!line) continue;
+  const p = line.split('\t');
+  active.push({
+    gid: p[0], title: p[1] || '', vendor: p[2] || '', ptype: p[3] || '',
+    m_material: p[4] || '', m_comp: p[5] || '', m_content: p[6] || '', m_mtype: p[7] || '',
+  });
+}
+
+// ---- the missing set (active AND not already having material) -------------
+let missing = active.filter((r) => tagsByGid.has(r.gid) && !hasMaterialGid.has(r.gid));
+if (SAMPLE > 0) {
+  // deterministic sample: every Nth so it spans vendors, capped at SAMPLE
+  const step = Math.max(1, Math.floor(missing.length / SAMPLE));
+  missing = missing.filter((_, i) => i % step === 0).slice(0, SAMPLE);
+}
+
+// ---- deterministic pass ---------------------------------------------------
+const proposed = [];   // { gid, material, source, title, vendor }
+const forLLM = [];
+const srcCount = {};
+function record(r, material, source) {
+  proposed.push({ gid: r.gid, material, source, title: r.title, vendor: r.vendor });
+  srcCount[source] = (srcCount[source] || 0) + 1;
+}
+for (const r of missing) {
+  // 1. specs / specifications metafield
+  let v = fromText(r.m_material) || fromText(r.m_comp) || fromText(r.m_content) || fromText(r.m_mtype);
+  if (v) { record(r, v, 'specs-metafield'); continue; }
+  // 2. existing composition tag (strong whole-tag / "X - N%")
+  v = fromTagList(tagsByGid.get(r.gid) || [], true);
+  if (v) { record(r, v, 'composition-tag'); continue; }
+  // 3. TITLE keywords
+  v = fromTitle(r.title);
+  if (v) { record(r, v, 'title-keyword'); continue; }
+  // 4. vendor convention
+  v = vendorConvLC[r.vendor.toLowerCase()];
+  if (v && VALID.has(v)) { record(r, v, 'vendor-convention'); continue; }
+  // 5. remainder -> qwen2.5 (or unmatched if --no-llm)
+  forLLM.push(r);
+}
+
+// ---- type-plausibility guard ----------------------------------------------
+// A textile product cannot be a hard-surface wallcovering material. This rejects
+// qwen's hallucinated "fabric -> Cork/Mylar/Mica/..." picks -> route to unmatched
+// (honest: better unlabeled than wrong).
+const FABRIC_TYPE = /fabric|pillow|drapery|upholst|trim|tassel|cushion|throw|textile|runner|sheer/i;
+// materials that make sense for a textile
+const FABRIC_OK = new Set(['Cotton', 'Linen', 'Silk', 'Wool', 'Jute', 'Sisal', 'Metallic']);
+function plausible(material, ptype, title) {
+  if (FABRIC_TYPE.test(ptype) || (!ptype && FABRIC_TYPE.test(title))) {
+    return FABRIC_OK.has(material);
+  }
+  return true; // wallcovering: any bucket allowed
+}
+
+// ---- qwen2.5 pass (local, $0) for the ambiguous remainder -----------------
+const unmatched = [];
+function askQwen(batch) {
+  const list = batch.map((r, i) =>
+    `${i + 1}. ${r.title.replace(/\s+/g, ' ').slice(0, 110)} | ${r.vendor} | ${r.ptype}`
+  ).join('\n');
+  const prompt =
+`Classify each numbered wallcovering/fabric product into ONE material.
+Choose from EXACTLY: Cotton, Linen, Vinyl, Grasscloth, Silk, Paper, Paper-weave, Mylar, Cork, Wool, Jute, Sisal, Mica, Metallic, Non-woven, Unknown.
+Guidance: velvet/chenille/upholstery fabric with no stated fiber = Cotton; sheer/drapery fabric = Linen; contract/commercial wallcovering = Vinyl; if genuinely unclear = Unknown.
+Output ONE line per item, format exactly: <number>. <Material>
+Do not explain.
+
+${list}`;
+  const tmp = `/tmp/tk135-mat-qwen-${process.pid}.txt`;
+  fs.writeFileSync(tmp, prompt);
+  let out = '';
+  try {
+    out = execSync(`ollama run ${LLM_MODEL} < ${tmp}`, { encoding: 'utf8', timeout: 180000, maxBuffer: 1 << 22 });
+  } catch (e) { out = (e.stdout || '').toString(); }
+  try { fs.unlinkSync(tmp); } catch {}
+  const map = {};
+  for (const m of out.matchAll(/^\s*(\d+)\s*[=:.\)]\s*([A-Za-z][A-Za-z\- ]*)/gm)) {
+    map[+m[1]] = m[2].trim();
+  }
+  return map;
+}
+function normalizeLLM(raw) {
+  if (!raw) return null;
+  const s = raw.trim().toLowerCase();
+  for (const val of VALID) if (s === val.toLowerCase()) return val;
+  // keyword contains
+  for (const kw in KW2BUCKET) if (s.includes(kw)) return KW2BUCKET[kw];
+  return null;
+}
+
+if (!NO_LLM && forLLM.length) {
+  for (let i = 0; i < forLLM.length; i += LLM_BATCH) {
+    const batch = forLLM.slice(i, i + LLM_BATCH);
+    const map = askQwen(batch);
+    batch.forEach((r, j) => {
+      const val = normalizeLLM(map[j + 1]);
+      if (val && plausible(val, r.ptype, r.title)) record(r, val, 'qwen2.5');
+      else unmatched.push(r);
+    });
+    if ((i / LLM_BATCH) % 10 === 0) {
+      process.stderr.write(`  qwen ${Math.min(i + LLM_BATCH, forLLM.length)}/${forLLM.length}\r`);
+    }
+  }
+  process.stderr.write('\n');
+} else {
+  for (const r of forLLM) unmatched.push(r);
+}
+
+// ---- write proposal (BARE values) + unmatched -----------------------------
+fs.mkdirSync(path.dirname(OUT), { recursive: true });
+fs.writeFileSync(OUT, proposed.map((p) => `${p.gid}\t${p.material}`).join('\n') + (proposed.length ? '\n' : ''));
+const UNM = OUT.replace(/\.tsv$/, '-unmatched.tsv');
+fs.writeFileSync(UNM, unmatched.map((u) => `${u.gid}\t${u.vendor}\t${u.title.replace(/\t/g, ' ')}`).join('\n') + (unmatched.length ? '\n' : ''));
+
+// ---- report ---------------------------------------------------------------
+const dist = {};
+for (const p of proposed) dist[p.material] = (dist[p.material] || 0) + 1;
+const N = missing.length;
+console.log(`TK-135 MATERIAL DRY-RUN — NO WRITES  ·  cost: $0 (local)`);
+console.log(`  mode: ${SAMPLE > 0 ? `SAMPLE (${SAMPLE})` : 'FULL'}${NO_LLM ? '  [--no-llm]' : ''}`);
+console.log(`  active total (in tags file): ${tagsByGid.size}`);
+console.log(`  already have material (skipped): ${hasMaterialGid.size}`);
+console.log(`  MISSING material (input): ${N}`);
+console.log(`  classified: ${proposed.length}  (${(100 * proposed.length / N).toFixed(1)}%)   unmatched: ${unmatched.length}  (${(100 * unmatched.length / N).toFixed(1)}%)`);
+console.log(`\n  === source breakdown ===`);
+for (const [k, v] of Object.entries(srcCount).sort((a, b) => b[1] - a[1])) {
+  console.log(`    ${String(v).padStart(6)}  (${(100 * v / N).toFixed(1)}%)  ${k}`);
+}
+console.log(`\n  === material distribution (BARE values) ===`);
+for (const [k, v] of Object.entries(dist).sort((a, b) => b[1] - a[1])) {
+  console.log(`    ${String(v).padStart(6)}  ${k}`);
+}
+console.log(`\n  === 10 sample classifications (gid · source · title -> BARE) ===`);
+proposed.slice(0, 10).forEach((p) => {
+  console.log(`    [${p.source.padEnd(16)}] ${p.title.slice(0, 44).padEnd(44)} -> ${p.material}`);
+});
+console.log(`\n  === 8 sample UNMATCHED ===`);
+unmatched.slice(0, 8).forEach((u) => console.log(`    ${u.vendor.slice(0, 18).padEnd(18)} | ${u.title.slice(0, 46)}`));
+console.log(`\n  proposed TSV  -> ${OUT}   (${proposed.length} rows, format: <gid>\\t<BareMaterialValue>)`);
+console.log(`  unmatched TSV -> ${UNM}   (${unmatched.length} rows)`);
+console.log(`\n  NO Shopify / PostgreSQL writes performed. Proposal is gated for Steve.`);

← 16012764 TK-135: stamp custom.color_normalized_at per SKU (durable de  ·  back to Designer Wallcoverings  ·  TK-135: material classifier — 24,581 bare primary-material t fcb3debd →