← back to Gmc Titlefix
TK-11233 B3: Kravet-family hi-res re-fetch canary (read-only enumerate + gated reversible apply)
4e97f128f706fc3ed517e751697691463aa115c6 · 2026-09-04 11:04:23 -0700 · Steve
Measures served vs Brandfolder-original per item; only re-fetches when original >=1500px
(40-sample: 21 viable / 16 orig-also-small excluded / 3 already-ok). Apply is hard-gated
(--apply + TK11233_APPROVED=1), ADDS new primary media without deleting the original, and is
reversible via --rollback <run-log>. Nothing fired.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dj5vkpUp18yQkVZEYNdSCG
Files touched
A data/tk11233-kravet-hires-canary.jsonA tk11233-kravet-hires-canary.mjs
Diff
commit 4e97f128f706fc3ed517e751697691463aa115c6
Author: Steve <steve@designerwallcoverings.com>
Date: Fri Sep 4 11:04:23 2026 -0700
TK-11233 B3: Kravet-family hi-res re-fetch canary (read-only enumerate + gated reversible apply)
Measures served vs Brandfolder-original per item; only re-fetches when original >=1500px
(40-sample: 21 viable / 16 orig-also-small excluded / 3 already-ok). Apply is hard-gated
(--apply + TK11233_APPROVED=1), ADDS new primary media without deleting the original, and is
reversible via --rollback <run-log>. Nothing fired.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dj5vkpUp18yQkVZEYNdSCG
---
data/tk11233-kravet-hires-canary.json | 689 ++++++++++++++++++++++++++++++++++
tk11233-kravet-hires-canary.mjs | 170 +++++++++
2 files changed, 859 insertions(+)
diff --git a/data/tk11233-kravet-hires-canary.json b/data/tk11233-kravet-hires-canary.json
new file mode 100644
index 0000000..99a5d37
--- /dev/null
+++ b/data/tk11233-kravet-hires-canary.json
@@ -0,0 +1,689 @@
+{
+ "ticket": "TK-11233",
+ "bucket": "B3-kravet-hires",
+ "checked_at": "2026-09-04T18:03:22.924Z",
+ "scope": "ACTIVE Kravet-family products in kravet_catalog with Brandfolder originals",
+ "thresholds": {
+ "served_ok_px": 1024,
+ "min_original_px": 1500
+ },
+ "sample": 40,
+ "counts": {
+ "needs_hires": 21,
+ "original_also_small_excluded": 16,
+ "already_ok": 3,
+ "errors": 0
+ },
+ "needs_hires": [
+ {
+ "pid": "7413673689139",
+ "gid": "gid://shopify/Product/7413673689139",
+ "vendor": "Brunschwig & Fils",
+ "sku": "33345.1121.0",
+ "orig": "2000x2000",
+ "title": "Martel Weave - Cream Ivory By Brunschwig & Fils | Vienne Silks | Geometric Multipurpose Silk",
+ "media_id": "gid://shopify/MediaImage/24121475334195",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 2000,
+ "orig_url": "https://cdn.brandfolder.io/XSDLGRW8/at/q44fy3-a5yhmw-6g3pym/33345_1121.jpg"
+ },
+ {
+ "pid": "7413614346291",
+ "gid": "gid://shopify/Product/7413614346291",
+ "vendor": "Brunschwig & Fils",
+ "sku": "2023109.353.0",
+ "orig": "3791x3792",
+ "title": "Cernay Moire - Blue Blue By Brunschwig & Fils | Alsace Weaves | Texture Upholstery Silk",
+ "media_id": "gid://shopify/MediaImage/24121346359347",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 3792,
+ "orig_url": "https://cdn.brandfolder.io/UT8SLOWQ/at/rhjksgc989t3cgtn6br5xtv/2023109_353.jpg"
+ },
+ {
+ "pid": "7413590261811",
+ "gid": "gid://shopify/Product/7413590261811",
+ "vendor": "Brunschwig & Fils",
+ "sku": "2020184.5.0",
+ "orig": "3226x3226",
+ "title": "Embrun Woven - Blue Blue By Brunschwig & Fils | Durance |Small Scale Upholstery Weave",
+ "media_id": "gid://shopify/MediaImage/24121321226291",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 3226,
+ "orig_url": "https://cdn.brandfolder.io/UT8SLOWQ/as/5n7g78wfjcbwkvkxbqhm36/2020184_5.jpg"
+ },
+ {
+ "pid": "7413717106739",
+ "gid": "gid://shopify/Product/7413717106739",
+ "vendor": "Brunschwig & Fils",
+ "sku": "35515.35.0",
+ "orig": "4500x4500",
+ "title": "Seijun - Antique Gold By Brunschwig & Fils | Solid Texture Wallcovering Silk",
+ "media_id": "gid://shopify/MediaImage/24121578258483",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 4500,
+ "orig_url": "https://cdn.brandfolder.io/XSDLGRW8/at/q44gbr-8z7gjk-bukd2f/35515_35.jpg"
+ },
+ {
+ "pid": "7413740503091",
+ "gid": "gid://shopify/Product/7413740503091",
+ "vendor": "Brunschwig & Fils",
+ "sku": "36095.3.0",
+ "orig": "3007x3008",
+ "title": "Loriyan Tape - Fiesta Green By Brunschwig & Fils | Treillis Passementerie | Trim Braid / Tape",
+ "media_id": "gid://shopify/MediaImage/24121637142579",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 3008,
+ "orig_url": "https://cdn.brandfolder.io/XSDLGRW8/at/rf6b2hmkpm6c4cxh87wp6jcx/36095_3.jpg"
+ },
+ {
+ "pid": "7413692694579",
+ "gid": "gid://shopify/Product/7413692694579",
+ "vendor": "Brunschwig & Fils",
+ "sku": "34329.11.0",
+ "orig": "2048x2048",
+ "title": "Ninon Taffetas - Bleu Blue By Brunschwig & Fils | Solid Upholstery Silk",
+ "media_id": "gid://shopify/MediaImage/24121516785715",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 2048,
+ "orig_url": "https://cdn.brandfolder.io/GI4CWF96/at/q44g35-74q9g8-fgiv4i/34329_11.jpg"
+ },
+ {
+ "pid": "7413728149555",
+ "gid": "gid://shopify/Product/7413728149555",
+ "vendor": "Brunschwig & Fils",
+ "sku": "35909.23.0",
+ "orig": "6000x6000",
+ "title": "Vernay - Red White By Brunschwig & Fils | Cadenet Wallcoverings | Botanical & Floral Wallcovering Print",
+ "media_id": "gid://shopify/MediaImage/24121607716915",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 6000,
+ "orig_url": "https://cdn.brandfolder.io/XSDLGRW8/as/s6cbrxkcmvvhr8s7jtk6qs8/35909_23.jpg"
+ },
+ {
+ "pid": "7413685059635",
+ "gid": "gid://shopify/Product/7413685059635",
+ "vendor": "Brunschwig & Fils",
+ "sku": "34031.16.0",
+ "orig": "1500x1500",
+ "title": "Bird And Thistle - Gray Grey By Brunschwig & Fils | Volume 56 | Toile Wallcovering Print",
+ "media_id": "gid://shopify/MediaImage/24121501220915",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 1500,
+ "orig_url": "https://cdn.brandfolder.io/XSDLGRW8/at/q44g0z-2buay8-ezaapl/34031_16.jpg"
+ },
+ {
+ "pid": "7413747515443",
+ "gid": "gid://shopify/Product/7413747515443",
+ "vendor": "Brunschwig & Fils",
+ "sku": "36336.11.0",
+ "orig": "4334x4334",
+ "title": "Barodet Cord - Leaf Green By Brunschwig & Fils | Passementerie Volume I | Trim Cord",
+ "media_id": "gid://shopify/MediaImage/24121655296051",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 4334,
+ "orig_url": "https://cdn.brandfolder.io/XSDLGRW8/at/czkt4k6qfj8mfcw98qb86fs/36336_11.jpg"
+ },
+ {
+ "pid": "7413592916019",
+ "gid": "gid://shopify/Product/7413592916019",
+ "vendor": "Brunschwig & Fils",
+ "sku": "2020198.357.0",
+ "orig": "3173x3173",
+ "title": "Adrien Cotton - Mahogany Chocolate By Brunschwig & Fils | Solid Texture Multipurpose",
+ "media_id": "gid://shopify/MediaImage/24121324109875",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 3173,
+ "orig_url": "https://cdn.brandfolder.io/UT8SLOWQ/at/c937f7vfvg788n27p3jjtcf/2020198_357.jpg"
+ },
+ {
+ "pid": "7413537570867",
+ "gid": "gid://shopify/Product/7413537570867",
+ "vendor": "Brunschwig & Fils",
+ "sku": "2018148.68.0",
+ "orig": "3374x3374",
+ "title": "Otes Solid - Pebble Light Grey By Brunschwig & Fils | L'Atelier Moderne |Solid Texture Multipurpose",
+ "media_id": "gid://shopify/MediaImage/24121298550835",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 3374,
+ "orig_url": "https://cdn.brandfolder.io/UT8SLOWQ/at/q44etn-9akzlk-e6skup/2018148_68.jpg"
+ },
+ {
+ "pid": "7413723627571",
+ "gid": "gid://shopify/Product/7413723627571",
+ "vendor": "Brunschwig & Fils",
+ "sku": "35520.511.0",
+ "orig": "3428x3428",
+ "title": "La Pagode - Teal By Brunschwig & Fils | Les Ensembliers Wallcoverings | Chinoiserie Wallcovering Embroidery",
+ "media_id": "gid://shopify/MediaImage/24121595494451",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 3428,
+ "orig_url": "https://cdn.brandfolder.io/XSDLGRW8/at/q44gby-e3ptjk-flu2y7/35520_511.jpg"
+ },
+ {
+ "pid": "7413594161203",
+ "gid": "gid://shopify/Product/7413594161203",
+ "vendor": "Brunschwig & Fils",
+ "sku": "2020204.73.0",
+ "orig": "4480x4480",
+ "title": "Les Vagues Emb - Sky/Royal Dark Blue By Brunschwig & Fils | Les Ensembliers | Geometric Multipurpose Embroidery",
+ "media_id": "gid://shopify/MediaImage/24121325649971",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 4480,
+ "orig_url": "https://cdn.brandfolder.io/UT8SLOWQ/at/k4p2f4nc37nxgkjg32vc6/2020204_73.jpg"
+ },
+ {
+ "pid": "7413675032627",
+ "gid": "gid://shopify/Product/7413675032627",
+ "vendor": "Brunschwig & Fils",
+ "sku": "33353.106.0",
+ "orig": "2000x2000",
+ "title": "Arnaud Damask - Blue Light Blue By Brunschwig & Fils | Vienne Silks | Damask Multipurpose Silk",
+ "media_id": "gid://shopify/MediaImage/24121478512691",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 2000,
+ "orig_url": "https://cdn.brandfolder.io/XSDLGRW8/at/q44fy3-5bfcqg-bgl4es/33345_106.jpg"
+ },
+ {
+ "pid": "7413715828787",
+ "gid": "gid://shopify/Product/7413715828787",
+ "vendor": "Brunschwig & Fils",
+ "sku": "35495.15.0",
+ "orig": "3000x3000",
+ "title": "Kochi - Persimon Burgundy By Brunschwig & Fils | Solid Texture",
+ "media_id": "gid://shopify/MediaImage/24121574326323",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 3000,
+ "orig_url": "https://cdn.brandfolder.io/XSDLGRW8/as/739ppr8s46gsnv6ngv7n45tt/35495_15.jpg"
+ },
+ {
+ "pid": "7413535014963",
+ "gid": "gid://shopify/Product/7413535014963",
+ "vendor": "Brunschwig & Fils",
+ "sku": "2018148.16.0",
+ "orig": "3471x3471",
+ "title": "Celestin - Paprika Rust By Brunschwig & Fils | L'Atelier Moderne | Texture Upholstery Chenille",
+ "media_id": "gid://shopify/MediaImage/24121297338419",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 3471,
+ "orig_url": "https://cdn.brandfolder.io/UT8SLOWQ/at/q44etm-6yoqfk-b9x4bo/2018148_16.jpg"
+ },
+ {
+ "pid": "7413617557555",
+ "gid": "gid://shopify/Product/7413617557555",
+ "vendor": "Brunschwig & Fils",
+ "sku": "2023122.24.0",
+ "orig": "3178x3178",
+ "title": "Nadari Print - Peach/Gold Multi By Brunschwig & Fils | Folio Francais | Global Multipurpose Print",
+ "media_id": "gid://shopify/MediaImage/24121351110707",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 3178,
+ "orig_url": "https://cdn.brandfolder.io/UT8SLOWQ/at/bntn47xhncbbnrr4bncnx9wr/2023122_24.jpg"
+ },
+ {
+ "pid": "7413730410547",
+ "gid": "gid://shopify/Product/7413730410547",
+ "vendor": "Brunschwig & Fils",
+ "sku": "35966.1635.0",
+ "orig": "4379x4379",
+ "title": "Tourbillon - Lapis Turquoise By Brunschwig & Fils | Celeste Wallcovering | Modern Wallcovering Print",
+ "media_id": "gid://shopify/MediaImage/24121613451315",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 4379,
+ "orig_url": "https://cdn.brandfolder.io/XSDLGRW8/as/33fbq8bvk6v4fsfqnp2w7wp/35966_1635.jpg"
+ },
+ {
+ "pid": "7413607727155",
+ "gid": "gid://shopify/Product/7413607727155",
+ "vendor": "Brunschwig & Fils",
+ "sku": "2022112.417.0",
+ "orig": "4480x4480",
+ "title": "Bird & Swing Hb - Aqua Turquoise By Brunschwig & Fils | Botanical & Floral Multipurpose Print",
+ "media_id": "gid://shopify/MediaImage/24121338200115",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 4480,
+ "orig_url": "https://cdn.brandfolder.io/UT8SLOWQ/at/6wm97ktcqhrzt7kwkwsnk/2022112_417.jpg"
+ },
+ {
+ "pid": "7413738831923",
+ "gid": "gid://shopify/Product/7413738831923",
+ "vendor": "Brunschwig & Fils",
+ "sku": "36086.31.0",
+ "orig": "3544x3544",
+ "title": "Sanchi Tape - Oyster Grey By Brunschwig & Fils | Treillis Passementerie | Trim Braid / Tape",
+ "media_id": "gid://shopify/MediaImage/24121632653363",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 3544,
+ "orig_url": "https://cdn.brandfolder.io/XSDLGRW8/as/vm746897j3c474mrxpg3mcs/36086_31.jpg"
+ },
+ {
+ "pid": "7413590917171",
+ "gid": "gid://shopify/Product/7413590917171",
+ "vendor": "Brunschwig & Fils",
+ "sku": "2020188.134.0",
+ "orig": "3226x3226",
+ "title": "Chamas Stripe - Indigo Indigo By Brunschwig & Fils | Durance | Stripes Upholstery",
+ "media_id": "gid://shopify/MediaImage/24121321979955",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 3226,
+ "orig_url": "https://cdn.brandfolder.io/UT8SLOWQ/as/qxvgw8jfx4jm4h8jfqr4nxz/2020188_134.jpg"
+ }
+ ],
+ "original_also_small_excluded": [
+ {
+ "pid": "7413635514419",
+ "gid": "gid://shopify/Product/7413635514419",
+ "vendor": "Brunschwig & Fils",
+ "sku": "30787.3.0",
+ "orig": "1024x1024",
+ "title": "De Blois Velvet - Leaf Green By Brunschwig & Fils | Chaumont Velvets |Dots Texture Upholstery Velvet",
+ "media_id": "gid://shopify/MediaImage/24121380864051",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 1024,
+ "orig_url": "https://cdn.brandfolder.io/XSDLGRW8/at/q44fg7-4usbx4-bjrs9q/30787_3.jpg",
+ "note": "original-also-small → excluded (defer to upscale program)"
+ },
+ {
+ "pid": "7413540028467",
+ "gid": "gid://shopify/Product/7413540028467",
+ "vendor": "Brunschwig & Fils",
+ "sku": "2019102.147.0",
+ "orig": "1200x1200",
+ "title": "Le Zebre Emb - Leaf Green By Brunschwig & Fils | Cape Comorin | Animal Skins Multipurpose Embroidery",
+ "media_id": "gid://shopify/MediaImage/24121299828787",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 1200,
+ "orig_url": "https://cdn.brandfolder.io/UT8SLOWQ/at/q71mtc-chl5w8-g9ox8r/2019102_147.jpg",
+ "note": "original-also-small → excluded (defer to upscale program)"
+ },
+ {
+ "pid": "7413681324083",
+ "gid": "gid://shopify/Product/7413681324083",
+ "vendor": "Brunschwig & Fils",
+ "sku": "33851.515.0",
+ "orig": "1024x1024",
+ "title": "La Mer Weave - Teal Turquoise By Brunschwig & Fils | Les Ensembliers L'Eternel Ete |Abstract Texture Upholstery Indoor / Outdoor",
+ "media_id": "gid://shopify/MediaImage/24121491914803",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 1024,
+ "orig_url": "https://cdn.brandfolder.io/XSDLGRW8/at/q44fwj-gguw4w-5ldo94/33127_515.jpg",
+ "note": "original-also-small → excluded (defer to upscale program)"
+ },
+ {
+ "pid": "7413688336435",
+ "gid": "gid://shopify/Product/7413688336435",
+ "vendor": "Brunschwig & Fils",
+ "sku": "34258.116.0",
+ "orig": "1024x1024",
+ "title": "Fabriano Cotton And Linen Print - Grey Multi By Brunschwig & Fils | Cevennes | Botanical & Floral Multipurpose Print",
+ "media_id": "gid://shopify/MediaImage/24121505611827",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 1024,
+ "orig_url": "https://cdn.brandfolder.io/XSDLGRW8/at/q44gk8-4qxcu0-bvwfa/8014101_116.jpg",
+ "note": "original-also-small → excluded (defer to upscale program)"
+ },
+ {
+ "pid": "7413728739379",
+ "gid": "gid://shopify/Product/7413728739379",
+ "vendor": "Brunschwig & Fils",
+ "sku": "35916.1.0",
+ "orig": "800x800",
+ "title": "Visan - Navy/Sky White By Brunschwig & Fils | Cadenet Wallcoverings | Paisley Wallcovering Print",
+ "media_id": "gid://shopify/MediaImage/24121608929331",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 800,
+ "orig_url": "https://cdn.brandfolder.io/XSDLGRW8/as/qdmdaz-bnfd5s-3i5ya6/35916_1.jpg",
+ "note": "original-also-small → excluded (defer to upscale program)"
+ },
+ {
+ "pid": "7413518696499",
+ "gid": "gid://shopify/Product/7413518696499",
+ "vendor": "Brunschwig & Fils",
+ "sku": "2016122.1611.0",
+ "orig": "1024x1024",
+ "title": "Bachelor Mohair - Mineral Grey By Brunschwig & Fils | Solid Texture Upholstery Mohair",
+ "media_id": "gid://shopify/MediaImage/24121265389619",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 1024,
+ "orig_url": "https://cdn.brandfolder.io/UT8SLOWQ/at/q44g35-arhto8-ckqudj/34328_1611.jpg",
+ "note": "original-also-small → excluded (defer to upscale program)"
+ },
+ {
+ "pid": "7413729689651",
+ "gid": "gid://shopify/Product/7413729689651",
+ "vendor": "Brunschwig & Fils",
+ "sku": "35916.323.0",
+ "orig": "800x800",
+ "title": "Petit Leopard - Rose Pink By Brunschwig & Fils | Madeleine Castaing Wallcoverings |Animal/Insects Animal Skins Wallcovering Print",
+ "media_id": "gid://shopify/MediaImage/24121611943987",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 800,
+ "orig_url": "https://cdn.brandfolder.io/XSDLGRW8/as/qdmdaz-bnfd5s-7hlpmw/35916_323.jpg",
+ "note": "original-also-small → excluded (defer to upscale program)"
+ },
+ {
+ "pid": "7413513715763",
+ "gid": "gid://shopify/Product/7413513715763",
+ "vendor": "Brunschwig & Fils",
+ "sku": "2012175.97.0",
+ "orig": "1024x1024",
+ "title": "Charmant Velvet - Hazelnut Brown By Brunschwig & Fils | Solid Texture Upholstery Velvet",
+ "media_id": "gid://shopify/MediaImage/24121252675635",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 1024,
+ "orig_url": "https://cdn.brandfolder.io/UT8SLOWQ/at/q44fs2-b12bog-alur5t/32344_97.jpg",
+ "note": "original-also-small → excluded (defer to upscale program)"
+ },
+ {
+ "pid": "7413684207667",
+ "gid": "gid://shopify/Product/7413684207667",
+ "vendor": "Brunschwig & Fils",
+ "sku": "33886.111.0",
+ "orig": "1024x1024",
+ "title": "Talavera - Indigo By Brunschwig & Fils | Botanical & Floral Wallcovering Print",
+ "media_id": "gid://shopify/MediaImage/24121499222067",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 1024,
+ "orig_url": "https://cdn.brandfolder.io/XSDLGRW8/at/q44g0e-2i8kaw-21qeb6/33886_111.jpg",
+ "note": "original-also-small → excluded (defer to upscale program)"
+ },
+ {
+ "pid": "7413690171443",
+ "gid": "gid://shopify/Product/7413690171443",
+ "vendor": "Brunschwig & Fils",
+ "sku": "34259.012.0",
+ "orig": "1024x1024",
+ "title": "Barclay Texture - Terracotta Orange By Brunschwig & Fils | Texture Upholstery Chenille",
+ "media_id": "gid://shopify/MediaImage/24121509511219",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 1024,
+ "orig_url": "https://cdn.brandfolder.io/XSDLGRW8/at/q44gzr-367kz4-ag8ksc/BR-89778_012.jpg",
+ "note": "original-also-small → excluded (defer to upscale program)"
+ },
+ {
+ "pid": "7413643935795",
+ "gid": "gid://shopify/Product/7413643935795",
+ "vendor": "Brunschwig & Fils",
+ "sku": "31326.23.0",
+ "orig": "1024x1024",
+ "title": "Weymouth Print - Red Red By Brunschwig & Fils | Manoir | Botanical & Floral Multipurpose Print",
+ "media_id": "gid://shopify/MediaImage/24121396527155",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 1024,
+ "orig_url": "https://cdn.brandfolder.io/XSDLGRW8/at/q44fid-9j8ni8-89fr9p/31326_23.jpg",
+ "note": "original-also-small → excluded (defer to upscale program)"
+ },
+ {
+ "pid": "7413691646003",
+ "gid": "gid://shopify/Product/7413691646003",
+ "vendor": "Brunschwig & Fils",
+ "sku": "34328.135.0",
+ "orig": "1024x1024",
+ "title": "Satin La Tour - Champagne Beige By Brunschwig & Fils | Solid Texture Upholstery Silk",
+ "media_id": "gid://shopify/MediaImage/24121513607219",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 1024,
+ "orig_url": "https://cdn.brandfolder.io/UT8SLOWQ/at/q44g33-7wpwww-emuife/34328_135.jpg",
+ "note": "original-also-small → excluded (defer to upscale program)"
+ },
+ {
+ "pid": "7413561524275",
+ "gid": "gid://shopify/Product/7413561524275",
+ "vendor": "Brunschwig & Fils",
+ "sku": "2020129.136.0",
+ "orig": "886x886",
+ "title": "Tepey Chenille - Blue Blue By Brunschwig & Fils | Chambery Textures | Texture Upholstery Chenille",
+ "media_id": "gid://shopify/MediaImage/24121317457971",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 886,
+ "orig_url": "https://cdn.brandfolder.io/UT8SLOWQ/as/qd9h2f-dvcc5c-4s65za/2020129_136.jpg",
+ "note": "original-also-small → excluded (defer to upscale program)"
+ },
+ {
+ "pid": "7413519941683",
+ "gid": "gid://shopify/Product/7413519941683",
+ "vendor": "Brunschwig & Fils",
+ "sku": "2016122.909.0",
+ "orig": "1024x1024",
+ "title": "Bachelor Mohair - Persimmon Rust By Brunschwig & Fils | Solid Texture Upholstery Mohair",
+ "media_id": "gid://shopify/MediaImage/24121268535347",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 1024,
+ "orig_url": "https://cdn.brandfolder.io/UT8SLOWQ/at/q44g35-1b00t4-6x5bjv/34328_909.jpg",
+ "note": "original-also-small → excluded (defer to upscale program)"
+ },
+ {
+ "pid": "7413515419699",
+ "gid": "gid://shopify/Product/7413515419699",
+ "vendor": "Brunschwig & Fils",
+ "sku": "2012176.50.0",
+ "orig": "1024x1024",
+ "title": "Charmant Velvet - Chianti Purple By Brunschwig & Fils | Solid Texture Upholstery Velvet",
+ "media_id": "gid://shopify/MediaImage/24121256771635",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 1024,
+ "orig_url": "https://cdn.brandfolder.io/UT8SLOWQ/at/q44fct-abs0ug-708khx/30421_50.jpg",
+ "note": "original-also-small → excluded (defer to upscale program)"
+ },
+ {
+ "pid": "7413696299059",
+ "gid": "gid://shopify/Product/7413696299059",
+ "vendor": "Brunschwig & Fils",
+ "sku": "34397.1616.0",
+ "orig": "1024x1024",
+ "title": "Autun Mohair Velvet - Almond Beige By Brunschwig & Fils | Solid Texture Upholstery Mohair",
+ "media_id": "gid://shopify/MediaImage/24121523666995",
+ "served_long": 400,
+ "served": "400x400",
+ "orig_long": 1024,
+ "orig_url": "https://cdn.brandfolder.io/UT8SLOWQ/at/q44g4r-ffqmfc-6txnip/34397_1616.jpg",
+ "note": "original-also-small → excluded (defer to upscale program)"
+ }
+ ],
+ "already_ok": [
+ {
+ "pid": "7821709967411",
+ "gid": "gid://shopify/Product/7821709967411",
+ "vendor": "Cole & Son",
+ "sku": "119/10045.CS.0",
+ "orig": "1319x1319",
+ "title": "Protea Garden Silk Olvgrn&Tngrn/Wht | Cole & Son",
+ "media_id": "gid://shopify/MediaImage/28084866056243",
+ "served_long": 1319,
+ "served": "1319x1319",
+ "orig_long": 1319,
+ "orig_url": "https://cdn.brandfolder.io/UT8SLOWQ/at/sspw6zkt3r87s9nqjsfb2b2p/119_10045_CS.jpg"
+ },
+ {
+ "pid": "7413664743475",
+ "gid": "gid://shopify/Product/7413664743475",
+ "vendor": "Brunschwig & Fils",
+ "sku": "32949.30.0",
+ "orig": "1024x1024",
+ "title": "Aurel Print - Gold/Red Yellow By Brunschwig & Fils | Cadenet | Flora & Fauna Multipurpose Print",
+ "media_id": "gid://shopify/MediaImage/24121442304051",
+ "served_long": 1200,
+ "served": "1200x1200",
+ "orig_long": 1024,
+ "orig_url": "https://cdn.brandfolder.io/XSDLGRW8/at/q44fvp-2yx6zk-b9e919/32949_30.jpg"
+ },
+ {
+ "pid": "7413726445619",
+ "gid": "gid://shopify/Product/7413726445619",
+ "vendor": "Brunschwig & Fils",
+ "sku": "35766.1623.0",
+ "orig": "2764x2764",
+ "title": "Marindol - Canary Yellow By Brunschwig & Fils | Manoir Wallcoverings | Paisley Wallcovering Print",
+ "media_id": "gid://shopify/MediaImage/24121602474035",
+ "served_long": 1200,
+ "served": "1200x1200",
+ "orig_long": 2764,
+ "orig_url": "https://cdn.brandfolder.io/XSDLGRW8/as/n8kc77xsrn7rjqwk8ctgzn4/35766_1623.jpg"
+ }
+ ],
+ "errors": [],
+ "rollback_map": [
+ {
+ "gid": "gid://shopify/Product/7413673689139",
+ "old_primary_media_id": "gid://shopify/MediaImage/24121475334195",
+ "old_primary_src": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/8023144_16_8efdeb09-eeb0-4980-b509-88004ca61e31.jpg?v=1725920701",
+ "old_media_count": 10
+ },
+ {
+ "gid": "gid://shopify/Product/7413614346291",
+ "old_primary_media_id": "gid://shopify/MediaImage/24121346359347",
+ "old_primary_src": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/8019119_5_d5a5fde4-e9b7-4251-9d3e-4656c1577630.jpg?v=1725919232",
+ "old_media_count": 2
+ },
+ {
+ "gid": "gid://shopify/Product/7413590261811",
+ "old_primary_media_id": "gid://shopify/MediaImage/24121321226291",
+ "old_primary_src": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/8017102_5_d2cf225e-dfed-41ef-a9b0-06ed2e40e58d.jpg?v=1725918858",
+ "old_media_count": 2
+ },
+ {
+ "gid": "gid://shopify/Product/7413717106739",
+ "old_primary_media_id": "gid://shopify/MediaImage/24121578258483",
+ "old_primary_src": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/P8015147_14_5696e7a7-2f01-43a2-bf26-1ac00e754ffb.jpg?v=1725922434",
+ "old_media_count": 1
+ },
+ {
+ "gid": "gid://shopify/Product/7413740503091",
+ "old_primary_media_id": "gid://shopify/MediaImage/24121637142579",
+ "old_primary_src": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/T8019104_37_149ba74c-ab7b-458a-8981-1919f50cb8ac.jpg?v=1725923422",
+ "old_media_count": 1
+ },
+ {
+ "gid": "gid://shopify/Product/7413692694579",
+ "old_primary_media_id": "gid://shopify/MediaImage/24121516785715",
+ "old_primary_src": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/BR-81081_PPO_b70d081d-083a-4e33-a87e-9e997b9b71bb.jpg?v=1725921379",
+ "old_media_count": 2
+ },
+ {
+ "gid": "gid://shopify/Product/7413728149555",
+ "old_primary_media_id": "gid://shopify/MediaImage/24121607716915",
+ "old_primary_src": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/P8023101_19_a6bb2a95-25c9-44b8-b2cb-d444cd2f1c90.jpg?v=1725922935",
+ "old_media_count": 1
+ },
+ {
+ "gid": "gid://shopify/Product/7413685059635",
+ "old_primary_media_id": "gid://shopify/MediaImage/24121501220915",
+ "old_primary_src": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/BR-69518_11_52b7714b-010b-4a04-a3fe-de88faccd010.jpg?v=1725921098",
+ "old_media_count": 2
+ },
+ {
+ "gid": "gid://shopify/Product/7413747515443",
+ "old_primary_media_id": "gid://shopify/MediaImage/24121655296051",
+ "old_primary_src": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/T8020106_3_aeb8dba0-76e0-4b51-9c82-12d9cced6dd7.jpg?v=1725923698",
+ "old_media_count": 2
+ },
+ {
+ "gid": "gid://shopify/Product/7413592916019",
+ "old_primary_media_id": "gid://shopify/MediaImage/24121324109875",
+ "old_primary_src": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/8017121_6_6027aadb-e06c-44ff-b6b0-5b162881c6f1.jpg?v=1725918908",
+ "old_media_count": 1
+ },
+ {
+ "gid": "gid://shopify/Product/7413537570867",
+ "old_primary_media_id": "gid://shopify/MediaImage/24121298550835",
+ "old_primary_src": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/8015167_21_1ddc6832-bad7-4053-936f-d7c0dcadc8a8.jpg?v=1725918557",
+ "old_media_count": 10
+ },
+ {
+ "gid": "gid://shopify/Product/7413723627571",
+ "old_primary_media_id": "gid://shopify/MediaImage/24121595494451",
+ "old_primary_src": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/P8020108_35_f3afd4ba-dbe6-4ac9-a195-b930f188a780.jpg?v=1725922727",
+ "old_media_count": 2
+ },
+ {
+ "gid": "gid://shopify/Product/7413594161203",
+ "old_primary_media_id": "gid://shopify/MediaImage/24121325649971",
+ "old_primary_src": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/8017128_50_f950ea0c-14ca-4fcf-9886-6c52b009b3ad.jpg?v=1725918932",
+ "old_media_count": 1
+ },
+ {
+ "gid": "gid://shopify/Product/7413675032627",
+ "old_primary_media_id": "gid://shopify/MediaImage/24121478512691",
+ "old_primary_src": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/8023150_5_ce893327-c3a9-4bf2-ac71-94adbdc5b22c.jpg?v=1725920768",
+ "old_media_count": 6
+ },
+ {
+ "gid": "gid://shopify/Product/7413715828787",
+ "old_primary_media_id": "gid://shopify/MediaImage/24121574326323",
+ "old_primary_src": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/P8015146_19_4f6a5b7a-da7e-4ae1-b9c8-a7311f939df5.jpg?v=1725922374",
+ "old_media_count": 1
+ },
+ {
+ "gid": "gid://shopify/Product/7413535014963",
+ "old_primary_media_id": "gid://shopify/MediaImage/24121297338419",
+ "old_primary_src": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/8015160_12_e3b4e683-677b-4d1b-b1c3-bdbeb64e8edf.jpg?v=1725918543",
+ "old_media_count": 10
+ },
+ {
+ "gid": "gid://shopify/Product/7413617557555",
+ "old_primary_media_id": "gid://shopify/MediaImage/24121351110707",
+ "old_primary_src": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/8019129_124_af2b32c2-7159-4a60-87bf-95dccb6c94be.jpg?v=1725919292",
+ "old_media_count": 2
+ },
+ {
+ "gid": "gid://shopify/Product/7413730410547",
+ "old_primary_media_id": "gid://shopify/MediaImage/24121613451315",
+ "old_primary_src": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/P8023111_355_cc6be34b-fcab-4450-a076-0342b49cb04c.jpg?v=1725923055",
+ "old_media_count": 1
+ },
+ {
+ "gid": "gid://shopify/Product/7413607727155",
+ "old_primary_media_id": "gid://shopify/MediaImage/24121338200115",
+ "old_primary_src": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/8019100_13_dd17de81-f915-421f-bdc1-6083f57a32d4.jpg?v=1725919144",
+ "old_media_count": 1
+ },
+ {
+ "gid": "gid://shopify/Product/7413738831923",
+ "old_primary_media_id": "gid://shopify/MediaImage/24121632653363",
+ "old_primary_src": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/T8019100_11_3a8fcb7a-6a9d-461a-8186-b34ca9e3a4bd.jpg?v=1725923342",
+ "old_media_count": 2
+ },
+ {
+ "gid": "gid://shopify/Product/7413590917171",
+ "old_primary_media_id": "gid://shopify/MediaImage/24121321979955",
+ "old_primary_src": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/8017103_50_e838c916-f364-4e43-b17a-2206ed3eb96a.jpg?v=1725918873",
+ "old_media_count": 2
+ }
+ ],
+ "apply_gate": "HARD-GATED — requires --apply AND env TK11233_APPROVED=1; apply ADDS new media (never deletes the original); reversible via --rollback <run-log>."
+}
\ No newline at end of file
diff --git a/tk11233-kravet-hires-canary.mjs b/tk11233-kravet-hires-canary.mjs
new file mode 100644
index 0000000..55f192e
--- /dev/null
+++ b/tk11233-kravet-hires-canary.mjs
@@ -0,0 +1,170 @@
+#!/usr/bin/env node
+// TK-11233 Bucket-3 — Kravet-family HI-RES image re-fetch canary.
+//
+// PROBLEM: DW downsized Kravet-family masters to ~400px on ingest, so Google flags
+// image_too_small_for_high_resolution (12,777 warns) → free/enhanced-listing demotion.
+// The vendor originals live on Kravet's Brandfolder DAM (cdn.brandfolder.io) and are
+// MOSTLY 2500–4361px — but NOT ALL (verified 1/5 sample was 427px). So we re-fetch the
+// ORIGINAL and re-upload ONLY when the original actually clears the bar. This naturally
+// excludes Phillipe Romano / Koroseal (different catalog tables, genuinely-capped originals).
+//
+// SAFETY / REVERSIBILITY:
+// * DEFAULT = read-only enumerate. Measures served vs original, classifies, writes a
+// candidate list + rollback map. Fires NOTHING.
+// * --apply is HARD-GATED: refuses unless BOTH `--apply` AND env TK11233_APPROVED=1.
+// Apply ADDS the hi-res image as new media and moves it to position 1 — it NEVER deletes
+// the existing master. Rollback = delete the newly-added media + restore prior order,
+// recorded per-product in the run-log. The original image is never destroyed.
+//
+// Usage:
+// node tk11233-kravet-hires-canary.mjs # canary enumerate (default N=25), read-only
+// node tk11233-kravet-hires-canary.mjs --limit 100 # bigger read-only enumeration
+// node tk11233-kravet-hires-canary.mjs --apply # REFUSES unless TK11233_APPROVED=1
+// TK11233_APPROVED=1 node ... --apply --limit 25 # gated apply (do NOT run without approval)
+// node tk11233-kravet-hires-canary.mjs --rollback <run-log.jsonl> # undo an apply run
+
+import { execSync } from 'child_process';
+import fs from 'fs';
+import os from 'os';
+
+const SHOP = 'designer-laboratory-sandbox';
+const MIN_HIRES = 1500; // require original ≥1500px on the long edge to bother (Google bar is 1024; headroom)
+const SERVED_MAX_OK = 1024; // served ≥1024 = already fine, skip
+const LIMIT = parseInt((process.argv.find(a=>a==='--limit') ? process.argv[process.argv.indexOf('--limit')+1] : '25'), 10);
+const APPLY = process.argv.includes('--apply');
+const ROLLBACK = process.argv.includes('--rollback') ? process.argv[process.argv.indexOf('--rollback')+1] : null;
+const OUT = new URL('./data/tk11233-kravet-hires-canary.json', import.meta.url).pathname;
+const RUNLOG = new URL(`./data/tk11233-kravet-hires-apply-${new Date().toISOString().replace(/[:.]/g,'-')}.jsonl`, import.meta.url).pathname;
+
+const shopTok = (fs.readFileSync(process.env.HOME + '/Projects/secrets-manager/.env', 'utf8')
+ .match(/^SHOPIFY_FULL_ACCESS_TOKEN=(.+)$/m) || [])[1];
+if (!shopTok) { console.error('missing SHOPIFY_FULL_ACCESS_TOKEN'); process.exit(2); }
+
+async function shopify(query, variables) {
+ const r = await fetch(`https://${SHOP}.myshopify.com/admin/api/2024-10/graphql.json`, {
+ method: 'POST',
+ headers: { 'X-Shopify-Access-Token': shopTok, 'Content-Type': 'application/json' },
+ body: JSON.stringify({ query, variables }), signal: AbortSignal.timeout(60000) });
+ const j = await r.json();
+ if (j.errors) throw new Error('shopify gql: ' + JSON.stringify(j.errors));
+ return j.data;
+}
+
+// measure remote image on the long edge via curl + sips (local, $0)
+function dims(url) {
+ try {
+ const tmp = `${os.tmpdir()}/tk11233-${Math.random().toString(36).slice(2)}.img`;
+ execSync(`curl -s -m 30 -o ${tmp} ${JSON.stringify(url)}`, { stdio: 'ignore' });
+ const out = execSync(`sips -g pixelWidth -g pixelHeight ${tmp} 2>/dev/null || true`).toString();
+ fs.unlinkSync(tmp);
+ const w = +(out.match(/pixelWidth:\s*(\d+)/)||[])[1] || 0;
+ const h = +(out.match(/pixelHeight:\s*(\d+)/)||[])[1] || 0;
+ return { w, h, long: Math.max(w, h) };
+ } catch { return { w: 0, h: 0, long: 0 }; }
+}
+
+function pickCandidates(limit) {
+ // ACTIVE Kravet-family products joined to kravet_catalog (brandfolder originals only).
+ // kravet_catalog membership is what scopes this to the Kravet family — PR/Koroseal are other tables.
+ const sql = `SELECT sp.shopify_id, sp.vendor, c.mfr_sku, c.image_url AS orig_url FROM shopify_products sp JOIN kravet_catalog c ON c.shopify_product_id::text = sp.shopify_id::text WHERE sp.status='ACTIVE' AND c.image_url ~ 'brandfolder' AND sp.shopify_id IS NOT NULL ORDER BY random() LIMIT ${limit};`;
+ const raw = execSync(`psql "host=/tmp dbname=dw_unified" -tA -F'\t' -c ${JSON.stringify(sql)}`).toString().trim();
+ if (!raw) return [];
+ return raw.split('\n').map(l => { const [gid, vendor, sku, orig] = l.split('\t'); const pid = (gid.match(/(\d+)$/)||[])[1]; return { pid, gid, vendor, sku, orig }; });
+}
+
+async function primaryMedia(pid) {
+ const gid = `gid://shopify/Product/${pid}`;
+ const d = await shopify(`query($id:ID!){ product(id:$id){ id title
+ media(first:10){ nodes{ id mediaContentType
+ ... on MediaImage { image { url width height } } } } } }`, { id: gid });
+ const p = d.product; if (!p) return null;
+ const imgs = p.media.nodes.filter(n => n.mediaContentType === 'IMAGE');
+ return { gid, title: p.title, first: imgs[0] || null, mediaCount: imgs.length };
+}
+
+async function enumerate() {
+ const cands = pickCandidates(LIMIT);
+ const needs = [], origSmall = [], alreadyOk = [], errors = [];
+ const rollbackMap = [];
+ for (const c of cands) {
+ try {
+ const m = await primaryMedia(c.pid);
+ if (!m || !m.first) { errors.push({ ...c, why: 'no-media' }); continue; }
+ // served size Google sees = the master's Shopify image width/height (feed image_url)
+ const servedLong = Math.max(m.first.image.width || 0, m.first.image.height || 0);
+ const od = dims(c.orig);
+ const row = { ...c, gid: m.gid, title: m.title, media_id: m.first.id,
+ served_long: servedLong, served: `${m.first.image.width}x${m.first.image.height}`,
+ orig_long: od.long, orig: `${od.w}x${od.h}`, orig_url: c.orig };
+ if (servedLong >= SERVED_MAX_OK) { alreadyOk.push(row); }
+ else if (od.long >= MIN_HIRES) { needs.push(row);
+ rollbackMap.push({ gid: m.gid, old_primary_media_id: m.first.id, old_primary_src: m.first.image.url, old_media_count: m.mediaCount }); }
+ else { origSmall.push({ ...row, note: 'original-also-small → excluded (defer to upscale program)' }); }
+ } catch (e) { errors.push({ ...c, why: String(e).slice(0,120) }); }
+ }
+ const report = {
+ ticket: 'TK-11233', bucket: 'B3-kravet-hires', checked_at: new Date().toISOString(),
+ scope: 'ACTIVE Kravet-family products in kravet_catalog with Brandfolder originals',
+ thresholds: { served_ok_px: SERVED_MAX_OK, min_original_px: MIN_HIRES },
+ sample: cands.length,
+ counts: { needs_hires: needs.length, original_also_small_excluded: origSmall.length, already_ok: alreadyOk.length, errors: errors.length },
+ needs_hires: needs, original_also_small_excluded: origSmall, already_ok: alreadyOk, errors,
+ rollback_map: rollbackMap,
+ apply_gate: 'HARD-GATED — requires --apply AND env TK11233_APPROVED=1; apply ADDS new media (never deletes the original); reversible via --rollback <run-log>.'
+ };
+ fs.writeFileSync(OUT, JSON.stringify(report, null, 2));
+ console.log(`\n=== TK-11233 Kravet hi-res canary — sample ${cands.length} ===`);
+ console.log(` NEEDS_HIRES (served<${SERVED_MAX_OK} & orig≥${MIN_HIRES}) : ${needs.length}`);
+ console.log(` ORIG_ALSO_SMALL (excluded, defer) : ${origSmall.length}`);
+ console.log(` ALREADY_OK (served≥${SERVED_MAX_OK}) : ${alreadyOk.length}`);
+ console.log(` ERRORS : ${errors.length}`);
+ console.log(` → report: ${OUT}`);
+ needs.slice(0,8).forEach(r => console.log(` + ${r.vendor} ${r.sku} served=${r.served} orig=${r.orig}`));
+ origSmall.slice(0,5).forEach(r => console.log(` - EXCLUDE ${r.vendor} ${r.sku} orig=${r.orig}`));
+ console.log(`\ncost: $0 (Shopify reads + local sips). Nothing fired.`);
+ return report;
+}
+
+async function apply() {
+ if (!APPLY || process.env.TK11233_APPROVED !== '1') {
+ console.error('\n⛔ GATED: apply refused. Requires BOTH --apply AND env TK11233_APPROVED=1.');
+ console.error(' This writes customer-facing product media → must carry a logged TK-11248 approval first.');
+ process.exit(3);
+ }
+ const rpt = await enumerate();
+ console.log(`\n=== APPLY (gated, approved) — adding hi-res primary to ${rpt.needs_hires.length} products ===`);
+ for (const r of rpt.needs_hires) {
+ try {
+ const cm = await shopify(`mutation($pid:ID!,$media:[CreateMediaInput!]!){
+ productCreateMedia(productId:$pid, media:$media){ media{ id status } mediaUserErrors{ field message } } }`,
+ { pid: r.gid, media: [{ originalSource: r.orig_url, mediaContentType: 'IMAGE', alt: r.title }] });
+ const newId = cm.productCreateMedia.media?.[0]?.id;
+ const errs = cm.productCreateMedia.mediaUserErrors;
+ if (!newId || errs.length) { fs.appendFileSync(RUNLOG, JSON.stringify({ ...r, ok:false, errs })+'\n'); continue; }
+ // move new media to position 1 (primary) — reversible reorder
+ await shopify(`mutation($id:ID!,$moves:[MoveInput!]!){ productReorderMedia(id:$id, moves:$moves){ job{ id } userErrors{ message } } }`,
+ { id: r.gid, moves: [{ id: newId, newPosition: '0' }] });
+ fs.appendFileSync(RUNLOG, JSON.stringify({ gid:r.gid, sku:r.sku, ok:true,
+ added_media_id:newId, old_primary_media_id:r.media_id, old_primary_src:r.served,
+ undo:`delete media ${newId} + restore ${r.media_id} to position 0` })+'\n');
+ console.log(` ✓ ${r.sku} +hi-res ${r.orig}`);
+ } catch (e) { fs.appendFileSync(RUNLOG, JSON.stringify({ ...r, ok:false, err:String(e).slice(0,160) })+'\n'); }
+ }
+ console.log(`\nrun-log (rollback source): ${RUNLOG}`);
+}
+
+async function rollback(logPath) {
+ const lines = fs.readFileSync(logPath,'utf8').trim().split('\n').map(l=>JSON.parse(l)).filter(r=>r.ok && r.added_media_id);
+ console.log(`=== ROLLBACK ${lines.length} added media (deleting new, restoring original order) ===`);
+ for (const r of lines) {
+ try {
+ await shopify(`mutation($mediaIds:[ID!]!,$pid:ID!){ productDeleteMedia(mediaIds:$mediaIds, productId:$pid){ deletedMediaIds mediaUserErrors{ message } } }`,
+ { mediaIds:[r.added_media_id], pid:r.gid });
+ console.log(` ↩ ${r.sku} removed ${r.added_media_id}`);
+ } catch(e){ console.error(` ✗ ${r.sku} ${String(e).slice(0,100)}`); }
+ }
+}
+
+if (ROLLBACK) rollback(ROLLBACK);
+else if (APPLY) apply();
+else enumerate();
← 9b6af59 TK-10993 Track G: read-only policy-disapproval enumerator
·
back to Gmc Titlefix
·
TK-11233 B3: --min/--cap args for approved canary run (thres 835144c →