[object Object]

← back to Elitis Price 2026

WS4 cleanup: retitle VP-963->Osorno, archive Raffia/Frivole SKU-collision dup (live)

b42aea3f6e4d3c290e4412e97fb1aa410e78a8bc · 2026-07-11 08:18:13 -0700 · Steve Abrams

Files touched

Diff

commit b42aea3f6e4d3c290e4412e97fb1aa410e78a8bc
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sat Jul 11 08:18:13 2026 -0700

    WS4 cleanup: retitle VP-963->Osorno, archive Raffia/Frivole SKU-collision dup (live)
---
 exec/ledger/ws4_cleanup.csv |  4 +++
 exec/ws4_cleanup.py         | 72 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 76 insertions(+)

diff --git a/exec/ledger/ws4_cleanup.csv b/exec/ledger/ws4_cleanup.csv
new file mode 100644
index 0000000..98e02b2
--- /dev/null
+++ b/exec/ledger/ws4_cleanup.csv
@@ -0,0 +1,4 @@
+ts,action,product_id,before,after,status

+2026-07-11T08:17:32,retitle,7787408261171,Vp 963 01 Is Offered up in Broad Flat Areas As If Made From Pure Pigments. | Elitis,Osorno 01 | Elitis,OK

+2026-07-11T08:17:34,retitle,7789388660787,Vp 963 03 Is Offered up in Broad Flat Areas As If Made From Pure Pigments. | Elitis,Osorno 03 | Elitis,OK

+2026-07-11T08:17:35,archive,7787007475763,Raffia Ii Vp 1048 02 | Elitis,ARCHIVED,OK

diff --git a/exec/ws4_cleanup.py b/exec/ws4_cleanup.py
new file mode 100644
index 0000000..9dec3a4
--- /dev/null
+++ b/exec/ws4_cleanup.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python3
+"""WS4 - post-reconciliation cleanup of 3 pre-existing Elitis defects (live).
+1) Retitle scraped-sentence garbage titles on VP-963-01/-03 to real pattern 'Osorno'.
+2) Archive the mongrel 'Raffia Ii Vp 1048 02' product that dodged the WS2 VP-1048
+   archive and collides on SKU DWEL-142747 with the legit 'Frivole' VP-1036-44.
+Idempotent (checks current state first). $0 (Shopify Admin API is free).
+Steve-approved via AskUserQuestion 2026-07-11 (options A + B)."""
+import sys, os, csv, datetime
+sys.path.insert(0, "lib")
+from shopify import gql
+
+LEDGER = os.path.join("ledger", "ws4_cleanup.csv")
+M_UPD = """mutation($input:ProductInput!){ productUpdate(input:$input){
+  product{ id legacyResourceId title status handle } userErrors{ field message } } }"""
+
+RETITLE = [
+    (7787408261171, "Osorno 01 | Elitis"),   # was: Vp 963 01 Is Offered up...
+    (7789388660787, "Osorno 03 | Elitis"),   # was: Vp 963 03 Is Offered up...
+]
+ARCHIVE = [
+    (7787007475763, "Raffia Ii Vp 1048 02 | Elitis"),  # mongrel dup -> ARCHIVED
+]
+
+
+def gid(pid):
+    return f"gid://shopify/Product/{pid}"
+
+
+def log(action, pid, before, after, status):
+    new = not (os.path.exists(LEDGER) and os.path.getsize(LEDGER) > 0)
+    with open(LEDGER, "a", newline="") as f:
+        w = csv.writer(f)
+        if new:
+            w.writerow(["ts", "action", "product_id", "before", "after", "status"])
+        w.writerow([datetime.datetime.now().isoformat(timespec="seconds"),
+                    action, pid, before, after, status])
+
+
+def run():
+    for pid, newtitle in RETITLE:
+        cur = gql("query($id:ID!){ product(id:$id){ title } }", {"id": gid(pid)})["product"]
+        if cur["title"] == newtitle:
+            print(f"  [skip] {pid} already '{newtitle}'")
+            log("retitle", pid, cur["title"], newtitle, "SKIP")
+            continue
+        r = gql(M_UPD, {"input": {"id": gid(pid), "title": newtitle}})
+        ue = r["productUpdate"]["userErrors"]
+        if ue:
+            print(f"  [ERR] {pid}: {ue}")
+            log("retitle", pid, cur["title"], newtitle, "ERR:" + str(ue))
+            continue
+        print(f"  [ok] retitle {pid}: {cur['title'][:40]!r} -> {newtitle!r}")
+        log("retitle", pid, cur["title"], newtitle, "OK")
+    for pid, title in ARCHIVE:
+        cur = gql("query($id:ID!){ product(id:$id){ status title } }", {"id": gid(pid)})["product"]
+        if cur["status"] == "ARCHIVED":
+            print(f"  [skip] {pid} already ARCHIVED")
+            log("archive", pid, title, "ARCHIVED", "SKIP")
+            continue
+        r = gql(M_UPD, {"input": {"id": gid(pid), "status": "ARCHIVED"}})
+        ue = r["productUpdate"]["userErrors"]
+        if ue:
+            print(f"  [ERR] {pid}: {ue}")
+            log("archive", pid, title, "ARCHIVED", "ERR:" + str(ue))
+            continue
+        print(f"  [ok] archive {pid}: {title!r} ({cur['status']} -> ARCHIVED)")
+        log("archive", pid, title, "ARCHIVED", "OK")
+
+
+if __name__ == "__main__":
+    run()
+    print("\nWS4 cleanup done.")

← 0d7dccc WS3: build 328 Elitis DRAFT colorways (exact-pattern-join, r  ·  back to Elitis Price 2026  ·  WS3b: Bucket B accent/fuzzy matcher recovers 30 draft colorw 8620c28 →