[object Object]

← back to Dw Image Dup Audit

auto-save: 2026-07-21T18:09:04 (4 files) — fix-ledger.jsonl fix-run.js run-summary.json twin-draft.js

8c2eae0deb60e5e774aef98b923498d6c6b2343f · 2026-07-21 18:09:07 -0700 · Steve Abrams

Files touched

Diff

commit 8c2eae0deb60e5e774aef98b923498d6c6b2343f
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Jul 21 18:09:07 2026 -0700

    auto-save: 2026-07-21T18:09:04 (4 files) — fix-ledger.jsonl fix-run.js run-summary.json twin-draft.js
---
 fix-ledger.jsonl | 134 ++++++++++++++++++++++++++++++++++++++++++++++
 fix-run.js       | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 run-summary.json |  93 ++++++++++++++++++++++++++++++++
 twin-draft.js    |  69 ++++++++++++++++++++++++
 4 files changed, 455 insertions(+)

diff --git a/fix-ledger.jsonl b/fix-ledger.jsonl
new file mode 100644
index 0000000..3444946
--- /dev/null
+++ b/fix-ledger.jsonl
@@ -0,0 +1,134 @@
+{"ts":"2026-07-22T00:56:42.412Z","act":"imgdel","handle":"palais-gold-glam-pr-801196","imageId":37711452274739,"oldSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065368_palais-umber_47c286d3-1acc-4ce7-8059-aa7dba19b451.jpg?v=1784304820","ok":true}
+{"ts":"2026-07-22T00:56:42.415Z","act":"imgfix","handle":"palais-gold-glam-pr-801196","ok":true,"newImageId":37739570167859,"newSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065364_palais-gold-glam_650_1024x1024_60a1f7b0-3d37-4bbf-842b-41a4d05c4feb.jpg?v=1784681800"}
+{"ts":"2026-07-22T00:56:45.634Z","act":"imgdel","handle":"palais-juniper-pr-801206","imageId":37711452340275,"oldSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065368_palais-umber_c0a0a365-2210-4e7c-a529-1420bbb62c41.jpg?v=1784304822","ok":true}
+{"ts":"2026-07-22T00:56:45.634Z","act":"imgfix","handle":"palais-juniper-pr-801206","ok":true,"newImageId":37739570266163,"newSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065363_palais-juniper_650_1024x1024_89912b2d-aefb-4ccc-8200-062e7e1e8f8b.jpg?v=1784681804"}
+{"ts":"2026-07-22T00:56:48.617Z","act":"imgdel","handle":"palais-new-jade-pr-801216","imageId":37711452373043,"oldSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065368_palais-umber_39fa4abd-13b2-4add-a95a-ef4bcb549c8c.jpg?v=1784304825","ok":true}
+{"ts":"2026-07-22T00:56:48.617Z","act":"imgfix","handle":"palais-new-jade-pr-801216","ok":true,"newImageId":37739570331699,"newSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065362_palais-new-jade_650_1024x1024_beaa41af-07ea-4083-a06a-be00c4dd19d7.jpg?v=1784681807"}
+{"ts":"2026-07-22T00:56:51.749Z","act":"imgdel","handle":"palais-peacock-pr-801226","imageId":37711452602419,"oldSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065368_palais-umber_d111ef40-3bf8-43bf-8bae-af90ca8bd733.jpg?v=1784304828","ok":true}
+{"ts":"2026-07-22T00:56:51.750Z","act":"imgfix","handle":"palais-peacock-pr-801226","ok":true,"newImageId":37739570430003,"newSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065360_palais-peacock_650_1024x1024_c20ce0dc-28c8-4c64-ba09-a08fa3d22145.jpg?v=1784681810"}
+{"ts":"2026-07-22T00:56:54.767Z","act":"imgdel","handle":"palais-stone-pr-801236","imageId":37711452635187,"oldSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065368_palais-umber_d024cfc4-b3e4-4971-9c3d-10f841c1c464.jpg?v=1784304830","ok":true}
+{"ts":"2026-07-22T00:56:54.767Z","act":"imgfix","handle":"palais-stone-pr-801236","ok":true,"newImageId":37739570528307,"newSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065367_palais-stone_650_1024x1024_4241bcfe-9ddd-4e24-849c-bf327c0fa2dc.jpg?v=1784681813"}
+{"ts":"2026-07-22T00:56:57.862Z","act":"imgdel","handle":"bergamo-azure-pr-801136","imageId":37711452045363,"oldSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065370_bergamo-teal_54be6b9b-a25f-4069-bda8-786d0f375204.jpg?v=1784304804","ok":true}
+{"ts":"2026-07-22T00:56:57.863Z","act":"imgfix","handle":"bergamo-azure-pr-801136","ok":true,"newImageId":37739570593843,"newSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065369_bergamo-azure_650_1024x1024_fc6fc2fc-b7a4-498c-ab81-71cf6f0808f4.jpg?v=1784681816"}
+{"ts":"2026-07-22T00:57:01.138Z","act":"imgdel","handle":"bergamo-tan-pr-801146","imageId":37711452078131,"oldSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065370_bergamo-teal_acdaeb1e-5328-4830-8078-b5ad7dad10bc.jpg?v=1784304807","ok":true}
+{"ts":"2026-07-22T00:57:01.138Z","act":"imgfix","handle":"bergamo-tan-pr-801146","ok":true,"newImageId":37739570692147,"newSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065372_bergamo-tan_650_1024x1024_b973c923-4e74-4fcb-9dbd-064db8a3ef12.jpg?v=1784681819"}
+{"ts":"2026-07-22T00:57:04.017Z","act":"imgdel","handle":"chess-cappuccino-pr-801156","imageId":37711452143667,"oldSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065373_chess-viridian_ce4c8d62-882c-4517-82e8-345dcf10c4ac.jpg?v=1784304809","ok":true}
+{"ts":"2026-07-22T00:57:04.018Z","act":"imgfix","handle":"chess-cappuccino-pr-801156","ok":true,"newImageId":37739570757683,"newSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065377_chess-cappuccino_650_1024x1024_a1d8a026-84d6-42f8-ae3c-6b155783df70.jpg?v=1784681822"}
+{"ts":"2026-07-22T00:57:07.114Z","act":"imgdel","handle":"chess-oat-pr-801166","imageId":37711452176435,"oldSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065373_chess-viridian_82af2202-b1aa-433f-9769-78ea98bbb0a1.jpg?v=1784304812","ok":true}
+{"ts":"2026-07-22T00:57:07.115Z","act":"imgfix","handle":"chess-oat-pr-801166","ok":true,"newImageId":37739570823219,"newSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065375_chess-oat_650_1024x1024_fec4f23b-354e-4bbc-9c1e-639b8b0ca230.jpg?v=1784681825"}
+{"ts":"2026-07-22T00:57:10.098Z","act":"imgdel","handle":"manila-gold-glam-pr-801176","imageId":37711452209203,"oldSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065379_manila-viridian_a417ceb6-88e6-412a-b5af-e1e8af4c0e27.jpg?v=1784304815","ok":true}
+{"ts":"2026-07-22T00:57:10.098Z","act":"imgfix","handle":"manila-gold-glam-pr-801176","ok":true,"newImageId":37739570921523,"newSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065380_manila-gold-glam_650_1024x1024_7dc11719-73c6-4de1-a9c3-9fe69affea4e.jpg?v=1784681828"}
+{"ts":"2026-07-22T00:57:13.305Z","act":"imgdel","handle":"manila-oat-pr-801186","imageId":37711452241971,"oldSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065379_manila-viridian_c14a2e9e-5c21-4f1d-a5e3-664c952c4770.jpg?v=1784304817","ok":true}
+{"ts":"2026-07-22T00:57:13.305Z","act":"imgfix","handle":"manila-oat-pr-801186","ok":true,"newImageId":37739571281971,"newSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065378_manila-oat_650_1024x1024_79a84cb6-0527-4c5d-a0b9-e232e4b8f26f.jpg?v=1784681831"}
+{"ts":"2026-07-22T00:57:16.291Z","act":"imgdel","handle":"shantung-aged-stone-pr-801246","imageId":37711452667955,"oldSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065386_shantung-taupe_fe25914a-4b8a-4969-bbeb-0f949f8f7fdd.jpg?v=1784304833","ok":true}
+{"ts":"2026-07-22T00:57:16.292Z","act":"imgfix","handle":"shantung-aged-stone-pr-801246","ok":true,"newImageId":37739571380275,"newSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065389_shantung-aged-stone_650_1024x1024_201302eb-7c4c-4021-8cc2-5a4d81834000.jpg?v=1784681834"}
+{"ts":"2026-07-22T00:57:19.299Z","act":"imgdel","handle":"shantung-celadon-pr-801256","imageId":37711452700723,"oldSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065386_shantung-taupe_387ccd47-2ca7-4f18-9708-a5eb6336b658.jpg?v=1784304836","ok":true}
+{"ts":"2026-07-22T00:57:19.299Z","act":"imgfix","handle":"shantung-celadon-pr-801256","ok":true,"newImageId":37739571478579,"newSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065388_shantung-celadon_650_1024x1024_22a411de-204a-47df-aa6c-e72b57728d84.jpg?v=1784681837"}
+{"ts":"2026-07-22T00:57:22.579Z","act":"imgdel","handle":"shantung-deep-aqua-pr-801266","imageId":37711452733491,"oldSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065386_shantung-taupe_932d5154-8222-4e49-96c2-a3077c87b933.jpg?v=1784304838","ok":true}
+{"ts":"2026-07-22T00:57:22.579Z","act":"imgfix","handle":"shantung-deep-aqua-pr-801266","ok":true,"newImageId":37739571675187,"newSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065385_shantung-deep-aqua_650_1024x1024_05516cdc-9a5a-4c6a-8a59-faa1929303af.jpg?v=1784681840"}
+{"ts":"2026-07-22T00:57:25.648Z","act":"imgdel","handle":"shantung-new-jade-pr-801276","imageId":37711452766259,"oldSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065386_shantung-taupe_5a875121-5214-4036-b199-a72a5fd340ee.jpg?v=1784304841","ok":true}
+{"ts":"2026-07-22T00:57:25.649Z","act":"imgfix","handle":"shantung-new-jade-pr-801276","ok":true,"newImageId":37739572822067,"newSrc":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065384_shantung-new-jade_650_1024x1024_ea69a746-8f89-4ffe-9a3c-7d058721d920.jpg?v=1784681844"}
+{"ts":"2026-07-22T00:57:27.420Z","act":"draft","handle":"ala-forliata-wallpaper-ele-42864","id":1496140972144,"title":"Ala Forliata Wallcovering","reason":"garbage-image","ok":true}
+{"ts":"2026-07-22T00:57:28.974Z","act":"draft","handle":"luega-glam-weave-prt-16113","id":1501383655536,"title":"Luega Glam Weave | Phillipe Romano","reason":"garbage-image","ok":true}
+{"ts":"2026-07-22T00:57:30.728Z","act":"draft","handle":"montenegro-metallic-natural-stripe-prp-56504","id":1500058714224,"title":"Montenegro Metallic Natural Stripe | Phillipe Romano","reason":"garbage-image","ok":true}
+{"ts":"2026-07-22T00:57:32.353Z","act":"draft","handle":"montenegro-metallic-natural-stripe-prp-56505","id":1500059074672,"title":"Montenegro Metallic Natural Stripe | Phillipe Romano","reason":"garbage-image","ok":true}
+{"ts":"2026-07-22T00:57:33.900Z","act":"draft","handle":"montenegro-metallic-natural-stripe-prp-56506","id":1500059271280,"title":"Montenegro Metallic Natural Stripe | Phillipe Romano","reason":"garbage-image","ok":true}
+{"ts":"2026-07-22T00:57:35.519Z","act":"draft","handle":"montenegro-metallic-natural-stripe-prp-56507","id":1500059598960,"title":"Montenegro Metallic Natural Stripe | Phillipe Romano","reason":"garbage-image","ok":true}
+{"ts":"2026-07-22T00:57:37.139Z","act":"draft","handle":"montenegro-metallic-natural-stripe-prp-56508","id":1500059828336,"title":"Montenegro Metallic Natural Stripe | Phillipe Romano","reason":"garbage-image","ok":true}
+{"ts":"2026-07-22T00:57:38.699Z","act":"draft","handle":"phillipe-romano-natural-with-metal-prt-16716","id":1501380706416,"title":"Natural with Metal | Phillipe Romano","reason":"garbage-image","ok":true}
+{"ts":"2026-07-22T00:57:40.384Z","act":"draft","handle":"phillipe-romano-natural-with-metal-prt-16174","id":1501393649776,"title":"Natural with Metal | Phillipe Romano","reason":"garbage-image","ok":true}
+{"ts":"2026-07-22T00:57:41.976Z","act":"draft","handle":"pisaro-peacock-damask-walls-prp-56548","id":1500073885808,"title":"Pisaro Peacock Damask Walls","reason":"garbage-image","ok":true}
+{"ts":"2026-07-22T00:57:43.557Z","act":"draft","handle":"st-barton-paper-weave-prp-56513","id":1500061532272,"title":"St Barton Paper Weave | Phillipe Romano","reason":"garbage-image","ok":true}
+{"ts":"2026-07-22T00:57:45.244Z","act":"draft","handle":"tompkins-stain-repellent-real-dupione-silk-xws-52882","id":1499629060208,"title":"Tompkins Stain Repellent Real Dupione Silk | Phillipe Romano","reason":"garbage-image","ok":true}
+{"ts":"2026-07-22T00:57:46.817Z","act":"draft","handle":"tompkins-stain-repellent-real-dupione-silk-xws-52883","id":1499629355120,"title":"Tompkins Stain Repellent Real Dupione Silk | Phillipe Romano","reason":"garbage-image","ok":true}
+{"ts":"2026-07-22T00:57:48.392Z","act":"draft","handle":"dwjj-40600-davide","id":6882876424243,"title":"Davide Printed Paperweave Naturals | Phillipe Romano","reason":"garbage-image","ok":true}
+{"ts":"2026-07-22T00:57:49.991Z","act":"draft","handle":"dwjj-40560-giacomo","id":6882876260403,"title":"Giacomo Paper Naturals | Phillipe Romano","reason":"garbage-image","ok":true}
+{"ts":"2026-07-22T00:57:51.581Z","act":"draft","handle":"dwjj-40570-giacomo","id":6882876293171,"title":"Giacomo Paper Naturals | Phillipe Romano","reason":"garbage-image","ok":true}
+{"ts":"2026-07-22T00:57:53.222Z","act":"draft","handle":"dwjj-40540-marco","id":6882876194867,"title":"Marco Printed Paperweave Naturals | Phillipe Romano","reason":"garbage-image","ok":true}
+{"ts":"2026-07-22T00:57:54.825Z","act":"draft","handle":"mr-miyago-cork-wallpaper-2","id":6672899768371,"title":"Mr. Miyago Cork | Phillipe Romano","reason":"garbage-image","ok":true}
+{"ts":"2026-07-22T00:57:56.408Z","act":"draft","handle":"mr-miyago-cork-wallpaper-7","id":6672902553651,"title":"Mr. Miyago Cork | Phillipe Romano","reason":"garbage-image","ok":true}
+{"ts":"2026-07-22T00:57:58.012Z","act":"draft","handle":"xxp-969203-designerwallcoverings-los-angeles","id":6936687804467,"title":"Kingston-Color Name Durable Vinyl | Phillipe Romano","reason":"garbage-image","ok":true}
+{"ts":"2026-07-22T00:57:59.082Z","act":"draft","handle":"ws5128-placeholder-wallcovering-winfield-thybony","id":7822233763891,"title":"Como Seta - Khaki Wallcovering | Phillipe Romano","reason":"no-image","ok":true}
+{"ts":"2026-07-22T00:58:00.226Z","act":"draft","handle":"wp7596-placeholder-wallcovering-winfield-thybony","id":7822233468979,"title":"Lecce Papiro - Beige Wallcovering | Phillipe Romano","reason":"no-image","ok":true}
+{"ts":"2026-07-22T00:58:01.278Z","act":"draft","handle":"wp7593-placeholder-wallcovering-winfield-thybony","id":7822233370675,"title":"Lecce Papiro - Dark Blue Wallcovering | Phillipe Romano","reason":"no-image","ok":true}
+{"ts":"2026-07-22T00:58:03.080Z","act":"clone-draft","handle":"italechio-wallpaper-xg2-66894","id":1497142296688,"title":"Italechio Wallcovering","ok":true}
+{"ts":"2026-07-22T00:58:04.838Z","act":"clone-draft","handle":"kiligano-libra-wallpaper-xg4-66916","id":1497146916976,"title":"Kiligano Libra Wallcovering","ok":true}
+{"ts":"2026-07-22T00:58:06.480Z","act":"clone-draft","handle":"luxuria-fine-textile-wallcoverings-m2323","id":4395702157363,"title":"Luxuria Beige | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:08.085Z","act":"clone-draft","handle":"luxuria-fine-textile-wallcoverings-m4752","id":4395707105331,"title":"Luxuria Brown | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:09.762Z","act":"clone-draft","handle":"luxuria-fine-textile-wallcoverings-m4701","id":4395706679347,"title":"Luxuria Dark Beige | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:11.393Z","act":"clone-draft","handle":"luxuria-fine-textile-wallcoverings-m2680","id":4395704090675,"title":"Luxuria Dark Blue | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:13.076Z","act":"clone-draft","handle":"luxuria-fine-textile-wallcoverings-m4721","id":4395706777651,"title":"Luxuria Dark Brown | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:14.693Z","act":"clone-draft","handle":"luxuria-fine-textile-wallcoverings-m4097","id":4395706122291,"title":"Luxuria Dark Gray | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:16.405Z","act":"clone-draft","handle":"luxuria-fine-textile-wallcoverings-m2630","id":4395703566387,"title":"Luxuria Dark Olive Green | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:18.321Z","act":"clone-draft","handle":"luxuria-fine-textile-wallcoverings-m2668","id":4395703926835,"title":"Luxuria Gold | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:19.989Z","act":"clone-draft","handle":"luxuria-fine-textile-wallcoverings-m6215","id":4395711234099,"title":"Luxuria Golden Brown | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:21.527Z","act":"clone-draft","handle":"luxuria-fine-textile-wallcoverings-m4084","id":4395705434163,"title":"Luxuria Golden Yellow | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:23.060Z","act":"clone-draft","handle":"luxuria-fine-textile-wallcoverings-m4088","id":4395705761843,"title":"Luxuria Gray | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:25.123Z","act":"clone-draft","handle":"luxuria-fine-textile-wallcoverings-m3020","id":4395705040947,"title":"Luxuria Khaki | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:26.990Z","act":"clone-draft","handle":"luxuria-fine-textile-wallcoverings-m4095","id":4395706089523,"title":"Luxuria Lavender | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:28.571Z","act":"clone-draft","handle":"luxuria-fine-textile-wallcoverings-m2334","id":4395702485043,"title":"Luxuria Light Beige | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:30.168Z","act":"clone-draft","handle":"luxuria-fine-textile-wallcoverings-m6064","id":4395708907571,"title":"Luxuria Light Green | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:31.770Z","act":"clone-draft","handle":"luxuria-fine-textile-wallcoverings-m4085","id":4395705696307,"title":"Luxuria Light Yellow | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:33.285Z","act":"clone-draft","handle":"luxuria-fine-textile-wallcoverings-m4727","id":4395706941491,"title":"Luxuria Olive Green | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:35.469Z","act":"clone-draft","handle":"luxuria-fine-textile-wallcoverings-m2350","id":4395702648883,"title":"Luxuria Pale Yellow | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:37.117Z","act":"clone-draft","handle":"luxuria-fine-textile-wallcoverings-m2342","id":4395702616115,"title":"Luxuria Purple | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:38.735Z","act":"clone-draft","handle":"luxuria-fine-textile-wallcoverings-m6427","id":4395712741427,"title":"Luxuria Red | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:40.649Z","act":"clone-draft","handle":"luxuria-fine-textile-wallcoverings-m6019","id":4395707990067,"title":"Luxuria Rose | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:42.361Z","act":"clone-draft","handle":"luxuria-fine-textile-wallcoverings-m2329","id":4395702452275,"title":"Luxuria Tan | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:43.930Z","act":"clone-draft","handle":"luxuria-fine-textile-wallcoverings-m2690","id":4395704156211,"title":"Luxuria Teal | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:45.472Z","act":"clone-draft","handle":"marigot-metal","id":7791161999411,"title":"Madison - Metal Graffiti-Free Vinyl | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:47.079Z","act":"clone-draft","handle":"marigot-rural","id":7791162097715,"title":"Madison - Rural Graffiti-Free Vinyl | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:48.647Z","act":"clone-draft","handle":"marigot-seaside","id":7791162130483,"title":"Madison - Seaside Graffiti-Free Vinyl | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:50.504Z","act":"clone-draft","handle":"manchioneel-almond","id":7791162163251,"title":"Malacca - Almond Tekloom | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:52.548Z","act":"clone-draft","handle":"manchioneel-fresh","id":7791162261555,"title":"Malacca - Fresh Tekloom | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:54.349Z","act":"clone-draft","handle":"manchioneel-lark","id":7791162425395,"title":"Malacca - Lark Tekloom | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:56.370Z","act":"clone-draft","handle":"manchioneel-oatmeal","id":7791162589235,"title":"Malacca - Oatmeal Tekloom | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:58.010Z","act":"clone-draft","handle":"manchioneel-river","id":7791162884147,"title":"Malacca - River Tekloom | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:58:59.592Z","act":"clone-draft","handle":"manchioneel-spring","id":7791163047987,"title":"Malacca - Spring Tekloom | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:01.043Z","act":"clone-draft","handle":"manchioneel-straw","id":7791163211827,"title":"Malacca - Straw Tekloom | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:02.911Z","act":"clone-draft","handle":"medici-real-cork-stripe-wallpaper-cork","id":1496098013296,"title":"Medici Real Cork Stripe | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:04.594Z","act":"clone-draft","handle":"pleats-68400-plt","id":1495794253936,"title":"Pleats | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:06.248Z","act":"clone-draft","handle":"the-real-deal-linen-trd-23520","id":1496089788528,"title":"The Real Deal Linen","ok":true}
+{"ts":"2026-07-22T00:59:07.893Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-428","id":1498812940400,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:09.710Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-427","id":1498812776560,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:11.473Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-426","id":1498812579952,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:13.311Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-440","id":1498815266928,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:15.141Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-441","id":1498815398000,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:17.332Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-405","id":1498808418416,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:19.188Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-403","id":1498807926896,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:20.838Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-404","id":1498808156272,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:22.612Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-402","id":1498804420720,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:24.403Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-401","id":1498804256880,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:26.059Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-406","id":1498808549488,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:27.637Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-407","id":1498808778864,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:29.387Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-408","id":1498808975472,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:31.056Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-409","id":1498809139312,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:32.732Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-410","id":1498809270384,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:34.281Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-411","id":1498809434224,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:35.968Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-412","id":1498809696368,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:37.533Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-413","id":1498809991280,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:39.040Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-414","id":1498810187888,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:40.703Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-415","id":1498810351728,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:42.243Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-416","id":1498810548336,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:43.842Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-417","id":1498810777712,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:45.557Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-418","id":1498810941552,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:47.420Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-419","id":1498811170928,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:49.192Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-420","id":1498811334768,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:50.855Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-421","id":1498811596912,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:52.538Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-423","id":1498811957360,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:54.069Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-425","id":1498812317808,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:55.661Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-429","id":1498813104240,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:57.278Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-430","id":1498813235312,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T00:59:58.866Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-431","id":1498813431920,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T01:00:00.444Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-432","id":1498813792368,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T01:00:02.388Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-433","id":1498813956208,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T01:00:04.259Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-434","id":1498814152816,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T01:00:05.927Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-435","id":1498814382192,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T01:00:07.664Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-436","id":1498814546032,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T01:00:09.406Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-437","id":1498814742640,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T01:00:11.103Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-438","id":1498814873712,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T01:00:13.002Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-439","id":1498815103088,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T01:00:14.828Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-442","id":1498815627376,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T01:00:16.961Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-443","id":1498815889520,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T01:00:18.765Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-444","id":1498816053360,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
+{"ts":"2026-07-22T01:00:20.472Z","act":"clone-draft","handle":"decorator-grasscloth-vol-2-by-phillipe-romano-488-445","id":1498816217200,"title":"Decorator Grasscloth Vol. 2 | Phillipe Romano","ok":true}
diff --git a/fix-run.js b/fix-run.js
new file mode 100644
index 0000000..6bb95e9
--- /dev/null
+++ b/fix-run.js
@@ -0,0 +1,159 @@
+#!/usr/bin/env node
+// DW PR-line dup-image remediation 2026-07-21. Writes are live Shopify (Steve-approved "run all").
+// Ledger: every write appended to fix-ledger.jsonl for reversibility.
+const https = require("https");
+const fs = require("fs");
+const TOKEN = process.env.SHOPIFY_ADMIN_TOKEN;
+const HOST = "designer-laboratory-sandbox.myshopify.com";
+const API = "/admin/api/2024-10";
+const LEDGER = __dirname + "/fix-ledger.jsonl";
+const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
+
+function req(method, path, body) {
+  return new Promise((res, rej) => {
+    const data = body ? JSON.stringify(body) : null;
+    const r = https.request(
+      { host: HOST, path, method, headers: { "X-Shopify-Access-Token": TOKEN, "Content-Type": "application/json", ...(data ? { "Content-Length": Buffer.byteLength(data) } : {}) } },
+      (resp) => { let d = ""; resp.on("data", (c) => (d += c)); resp.on("end", () => res({ status: resp.statusCode, body: d, link: resp.headers.link || "" })); }
+    );
+    r.on("error", rej);
+    if (data) r.write(data);
+    r.end();
+  });
+}
+async function reqRetry(method, path, body) {
+  for (let i = 0; i < 5; i++) {
+    const r = await req(method, path, body);
+    if (r.status === 429) { await sleep(2000); continue; }
+    return r;
+  }
+  throw new Error("429 persisted " + path);
+}
+const ledger = (e) => fs.appendFileSync(LEDGER, JSON.stringify({ ts: new Date().toISOString(), ...e }) + "\n");
+
+// ---- plan ----
+const IMAGE_FIXES = { // handle -> correct CDN file base (already uploaded to DW Shopify Files)
+  "palais-gold-glam-pr-801196": "0065364_palais-gold-glam",
+  "palais-juniper-pr-801206": "0065363_palais-juniper",
+  "palais-new-jade-pr-801216": "0065362_palais-new-jade",
+  "palais-peacock-pr-801226": "0065360_palais-peacock",
+  "palais-stone-pr-801236": "0065367_palais-stone",
+  "bergamo-azure-pr-801136": "0065369_bergamo-azure",
+  "bergamo-tan-pr-801146": "0065372_bergamo-tan",
+  "chess-cappuccino-pr-801156": "0065377_chess-cappuccino",
+  "chess-oat-pr-801166": "0065375_chess-oat",
+  "manila-gold-glam-pr-801176": "0065380_manila-gold-glam",
+  "manila-oat-pr-801186": "0065378_manila-oat",
+  "shantung-aged-stone-pr-801246": "0065389_shantung-aged-stone",
+  "shantung-celadon-pr-801256": "0065388_shantung-celadon",
+  "shantung-deep-aqua-pr-801266": "0065385_shantung-deep-aqua",
+  "shantung-new-jade-pr-801276": "0065384_shantung-new-jade",
+};
+const IMG_VERSIONS = { // v= params captured from live CDN listing
+  "0065360_palais-peacock": "1783366540", "0065362_palais-new-jade": "1783366545", "0065363_palais-juniper": "1783366550",
+  "0065364_palais-gold-glam": "1783366555", "0065367_palais-stone": "1783366571", "0065369_bergamo-azure": "1783366582",
+  "0065372_bergamo-tan": "1783366597", "0065375_chess-oat": "1783366613", "0065377_chess-cappuccino": "1783366620",
+  "0065378_manila-oat": "1783366625", "0065380_manila-gold-glam": "1783366636", "0065384_shantung-new-jade": "1783366673",
+  "0065385_shantung-deep-aqua": "1783366679", "0065388_shantung-celadon": "1783366695", "0065389_shantung-aged-stone": "1783366701",
+};
+const DRAFT_GARBAGE = [ // placeholder gif / image.jpg / broken title
+  "ala-forliata-wallpaper-ele-42864", "luega-glam-weave-prt-16113",
+  "montenegro-metallic-natural-stripe-prp-56504", "montenegro-metallic-natural-stripe-prp-56505",
+  "montenegro-metallic-natural-stripe-prp-56506", "montenegro-metallic-natural-stripe-prp-56507",
+  "montenegro-metallic-natural-stripe-prp-56508",
+  "phillipe-romano-natural-with-metal-prt-16716", "phillipe-romano-natural-with-metal-prt-16174",
+  "pisaro-peacock-damask-walls-prp-56548", "st-barton-paper-weave-prp-56513",
+  "tompkins-stain-repellent-real-dupione-silk-xws-52882", "tompkins-stain-repellent-real-dupione-silk-xws-52883",
+  "dwjj-40600-davide", "dwjj-40560-giacomo", "dwjj-40570-giacomo", "dwjj-40540-marco",
+  "mr-miyago-cork-wallpaper-2", "mr-miyago-cork-wallpaper-7",
+  "xxp-969203-designerwallcoverings-los-angeles", // "Kingston-Color Name" template-bug title
+];
+
+(async () => {
+  // 1) full fetch: handle -> {id, images, title, status}
+  console.log("fetching PR line…");
+  let path = `${API}/products.json?vendor=${encodeURIComponent("Phillipe Romano")}&fields=id,title,handle,status,images&limit=250`;
+  const byHandle = {};
+  const noImageActive = [];
+  while (path) {
+    const { status, body, link } = await reqRetry("GET", path);
+    if (status !== 200) throw new Error("fetch " + status);
+    for (const p of JSON.parse(body).products) {
+      byHandle[p.handle] = p;
+      if (p.status === "active" && (!p.images || p.images.length === 0)) noImageActive.push(p.handle);
+    }
+    const m = link.match(/<https:\/\/[^>]+(\/admin[^>]+)>; rel="next"/);
+    path = m ? m[1] : null;
+    await sleep(550);
+  }
+  console.log("products:", Object.keys(byHandle).length, "| no-image actives:", noImageActive.length, noImageActive.join(","));
+
+  // 2) image re-points
+  let fixed = 0;
+  for (const [handle, base] of Object.entries(IMAGE_FIXES)) {
+    const p = byHandle[handle];
+    if (!p) { ledger({ act: "imgfix", handle, ok: false, err: "not found" }); continue; }
+    const src = `https://www.designerwallcoverings.com/cdn/shop/files/${base}_650_1024x1024.jpg?v=${IMG_VERSIONS[base]}`;
+    const cur = p.images[0];
+    if (cur && cur.src.includes(base.split("_")[0])) { ledger({ act: "imgfix", handle, ok: true, skip: "already correct" }); continue; }
+    const add = await reqRetry("POST", `${API}/products/${p.id}/images.json`, { image: { src, alt: p.title } });
+    await sleep(550);
+    if (add.status !== 200 && add.status !== 201) { ledger({ act: "imgfix", handle, ok: false, err: add.status + add.body.slice(0, 150) }); console.log("FAIL add", handle, add.status); continue; }
+    const newImg = JSON.parse(add.body).image;
+    for (const old of p.images) {
+      const del = await reqRetry("DELETE", `${API}/products/${p.id}/images/${old.id}.json`);
+      await sleep(550);
+      ledger({ act: "imgdel", handle, imageId: old.id, oldSrc: old.src, ok: del.status === 200 });
+    }
+    ledger({ act: "imgfix", handle, ok: true, newImageId: newImg.id, newSrc: newImg.src });
+    fixed++; console.log("fixed", handle);
+  }
+
+  // 3) drafts: garbage + no-image actives
+  const toDraft = [...new Set([...DRAFT_GARBAGE, ...noImageActive])];
+  let drafted = 0;
+  for (const handle of toDraft) {
+    const p = byHandle[handle];
+    if (!p) { ledger({ act: "draft", handle, ok: false, err: "not found" }); continue; }
+    if (p.status !== "active") { ledger({ act: "draft", handle, ok: true, skip: "not active" }); continue; }
+    const r = await reqRetry("PUT", `${API}/products/${p.id}.json`, { product: { id: p.id, status: "draft" } });
+    await sleep(550);
+    const ok = r.status === 200;
+    ledger({ act: "draft", handle, id: p.id, title: p.title, reason: DRAFT_GARBAGE.includes(handle) ? "garbage-image" : "no-image", ok });
+    if (ok) { drafted++; console.log("drafted", handle); } else console.log("FAIL draft", handle, r.status);
+  }
+
+  // 4) exact clones + Luxuria m↔lxpr + Decorator book dups, derived from audit JSON
+  const audit = JSON.parse(fs.readFileSync(__dirname + "/pr-dup-images-2026-07-21.json"));
+  const cloneDrafts = new Set();
+  const strip = (t) => t.replace(/\s*\|\s*Phillipe Romano\s*$/i, "").trim().toLowerCase();
+  for (const g of audit.colorway) {
+    const titles = g.items.map(([t]) => strip(t));
+    if (g.items.length === 2 && titles[0] === titles[1] && !/memo sample/.test(titles[0])) {
+      // identical-title clone pair: keep the SKU-suffixed/longer handle, draft the other
+      const [a, b] = g.items.map(([, h]) => h);
+      const score = (h) => (/-(dwpr|lxpr|grs|grt|prt|prp|prw|pr)-?\d/.test(h) ? 2 : 0) + h.length / 100;
+      cloneDrafts.add(score(a) >= score(b) ? b : a);
+    }
+    // Luxuria same-color m#### vs lxpr-#### -> draft the m#### handle
+    if (titles.every((t) => t.startsWith("luxuria")) && titles[0] === titles[1]) {
+      for (const [, h] of g.items) if (/-m\d+$/.test(h)) cloneDrafts.add(h);
+    }
+  }
+  for (const g of audit.crossline) {
+    for (const [t, h] of g.items) if (strip(t) === "decorator grasscloth vol. 2") cloneDrafts.add(h);
+  }
+  let clones = 0;
+  for (const handle of cloneDrafts) {
+    const p = byHandle[handle];
+    if (!p || p.status !== "active") { ledger({ act: "clone-draft", handle, ok: true, skip: "missing/not-active" }); continue; }
+    const r = await reqRetry("PUT", `${API}/products/${p.id}.json`, { product: { id: p.id, status: "draft" } });
+    await sleep(550);
+    const ok = r.status === 200;
+    ledger({ act: "clone-draft", handle, id: p.id, title: p.title, ok });
+    if (ok) { clones++; console.log("clone-drafted", handle); } else console.log("FAIL clone-draft", handle, r.status);
+  }
+
+  console.log(`\nDONE. image-fixed=${fixed} garbage/no-img drafted=${drafted} clone-drafted=${clones}`);
+  fs.writeFileSync(__dirname + "/run-summary.json", JSON.stringify({ fixed, drafted, clones, noImageActive, cloneDrafts: [...cloneDrafts] }, null, 1));
+})().catch((e) => { console.error("FATAL", e); process.exit(1); });
diff --git a/run-summary.json b/run-summary.json
new file mode 100644
index 0000000..2619020
--- /dev/null
+++ b/run-summary.json
@@ -0,0 +1,93 @@
+{
+ "fixed": 15,
+ "drafted": 23,
+ "clones": 81,
+ "noImageActive": [
+  "ws5128-placeholder-wallcovering-winfield-thybony",
+  "wp7596-placeholder-wallcovering-winfield-thybony",
+  "wp7593-placeholder-wallcovering-winfield-thybony"
+ ],
+ "cloneDrafts": [
+  "italechio-wallpaper-xg2-66894",
+  "kiligano-libra-wallpaper-xg4-66916",
+  "luxuria-fine-textile-wallcoverings-m2323",
+  "luxuria-fine-textile-wallcoverings-m4752",
+  "luxuria-fine-textile-wallcoverings-m4701",
+  "luxuria-fine-textile-wallcoverings-m2680",
+  "luxuria-fine-textile-wallcoverings-m4721",
+  "luxuria-fine-textile-wallcoverings-m4097",
+  "luxuria-fine-textile-wallcoverings-m2630",
+  "luxuria-fine-textile-wallcoverings-m2668",
+  "luxuria-fine-textile-wallcoverings-m6215",
+  "luxuria-fine-textile-wallcoverings-m4084",
+  "luxuria-fine-textile-wallcoverings-m4088",
+  "luxuria-fine-textile-wallcoverings-m3020",
+  "luxuria-fine-textile-wallcoverings-m4095",
+  "luxuria-fine-textile-wallcoverings-m2334",
+  "luxuria-fine-textile-wallcoverings-m6064",
+  "luxuria-fine-textile-wallcoverings-m4085",
+  "luxuria-fine-textile-wallcoverings-m4727",
+  "luxuria-fine-textile-wallcoverings-m2350",
+  "luxuria-fine-textile-wallcoverings-m2342",
+  "luxuria-fine-textile-wallcoverings-m6427",
+  "luxuria-fine-textile-wallcoverings-m6019",
+  "luxuria-fine-textile-wallcoverings-m2329",
+  "luxuria-fine-textile-wallcoverings-m2690",
+  "marigot-metal",
+  "marigot-rural",
+  "marigot-seaside",
+  "manchioneel-almond",
+  "manchioneel-fresh",
+  "manchioneel-lark",
+  "manchioneel-oatmeal",
+  "manchioneel-river",
+  "manchioneel-spring",
+  "manchioneel-straw",
+  "medici-real-cork-stripe-wallpaper-cork",
+  "pleats-68400-plt",
+  "the-real-deal-linen-trd-23520",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-428",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-427",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-426",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-440",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-441",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-405",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-403",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-404",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-402",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-401",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-406",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-407",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-408",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-409",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-410",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-411",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-412",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-413",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-414",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-415",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-416",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-417",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-418",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-419",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-420",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-421",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-423",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-425",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-429",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-430",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-431",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-432",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-433",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-434",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-435",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-436",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-437",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-438",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-439",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-442",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-443",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-444",
+  "decorator-grasscloth-vol-2-by-phillipe-romano-488-445"
+ ]
+}
\ No newline at end of file
diff --git a/twin-draft.js b/twin-draft.js
new file mode 100644
index 0000000..20598dc
--- /dev/null
+++ b/twin-draft.js
@@ -0,0 +1,69 @@
+#!/usr/bin/env node
+// Phase 2 per DTD verdict A (4/5, 2026-07-21): in each old/new twin pair, DRAFT the NEW
+// WallQuest-real-named import; the OLD private-label listing stays ACTIVE.
+// Reversible status writes only; ledgered to fix-ledger.jsonl.
+const https = require("https");
+const fs = require("fs");
+const TOKEN = process.env.SHOPIFY_ADMIN_TOKEN;
+const HOST = "designer-laboratory-sandbox.myshopify.com";
+const API = "/admin/api/2024-10";
+const LEDGER = __dirname + "/fix-ledger.jsonl";
+const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
+function req(method, path, body) {
+  return new Promise((res, rej) => {
+    const data = body ? JSON.stringify(body) : null;
+    const r = https.request(
+      { host: HOST, path, method, headers: { "X-Shopify-Access-Token": TOKEN, "Content-Type": "application/json", ...(data ? { "Content-Length": Buffer.byteLength(data) } : {}) } },
+      (resp) => { let d = ""; resp.on("data", (c) => (d += c)); resp.on("end", () => res({ status: resp.statusCode, body: d })); }
+    );
+    r.on("error", rej);
+    if (data) r.write(data);
+    r.end();
+  });
+}
+async function reqRetry(method, path, body) {
+  for (let i = 0; i < 5; i++) {
+    const r = await req(method, path, body);
+    if (r.status === 429) { await sleep(2000); continue; }
+    return r;
+  }
+  throw new Error("429 persisted " + path);
+}
+const ledger = (e) => fs.appendFileSync(LEDGER, JSON.stringify({ ts: new Date().toISOString(), ...e }) + "\n");
+
+// WQ-real mill-name prefixes = the NEW-generation side of each pair (the drafted side).
+const MILL_PREFIXES = [
+  "Enya Sisal", "Meilin Grasscloth", "Meilian Raffia", "Anhe Abaca",
+  "Huanzhu Leaf Stripe", "Pei Ling Lattice", "Yujin Cork", "Zinzhu Jute",
+  "Malia ", "Playa Jute", "Roark Flax", "Cebu Hemp", "Bergamo Wheat",
+  "Shantung Taupe", "Manila Viridian",
+];
+
+(async () => {
+  const audit = JSON.parse(fs.readFileSync(__dirname + "/pr-dup-images-2026-07-21.json"));
+  const targets = new Map(); // handle -> title
+  for (const g of audit.crossline) {
+    const titles = g.items.map(([t]) => t);
+    // only act on groups that actually contain an old-generation twin (a non-mill-named partner)
+    const hasOldTwin = g.items.some(([t]) => !MILL_PREFIXES.some((p) => t.startsWith(p)));
+    if (!hasOldTwin) continue;
+    for (const [t, h] of g.items) {
+      if (MILL_PREFIXES.some((p) => t.startsWith(p))) targets.set(h, t);
+    }
+  }
+  console.log("twin-draft targets:", targets.size);
+  let drafted = 0, skipped = 0, failed = 0;
+  for (const [handle, title] of targets) {
+    const g = await reqRetry("GET", `${API}/products.json?handle=${handle}&fields=id,status,title`);
+    await sleep(550);
+    const p = (JSON.parse(g.body).products || [])[0];
+    if (!p) { ledger({ act: "twin-draft", handle, ok: false, err: "not found" }); failed++; continue; }
+    if (p.status !== "active") { ledger({ act: "twin-draft", handle, ok: true, skip: "not active" }); skipped++; continue; }
+    const r = await reqRetry("PUT", `${API}/products/${p.id}.json`, { product: { id: p.id, status: "draft" } });
+    await sleep(550);
+    const ok = r.status === 200;
+    ledger({ act: "twin-draft", handle, id: p.id, title, ok });
+    if (ok) { drafted++; console.log("twin-drafted", handle); } else { failed++; console.log("FAIL", handle, r.status); }
+  }
+  console.log(`\nTWIN-DRAFT DONE. drafted=${drafted} skipped=${skipped} failed=${failed}`);
+})().catch((e) => { console.error("FATAL", e); process.exit(1); });

← 19b5746 PR line duplicate-image audit 2026-07-21: 624 groups, 89 col  ·  back to Dw Image Dup Audit  ·  auto-save: 2026-07-22T06:41:50 (2 files) — rename-run.js wq- 6836d19 →