← back to Designer Wallcoverings
TK-11534: doubleroll length backfill — additive --only-skus/--length-map/--width-map/--catalog-only flags + 47-SKU recoverable backfill assets (Steve-approved fix-forward)
31eff9bd88985de7a74fb41e014634a06e95b3b8 · 2026-09-13 00:23:57 -0700 · Steve
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUKRS8nTAFtE1hmVpgSHm2
Files touched
M shopify/scripts/set-doubleroll-lengths.pyA shopify/scripts/tk11534-doubleroll/cores-thibaut.txtA shopify/scripts/tk11534-doubleroll/cores-wallquest.txtA shopify/scripts/tk11534-doubleroll/dr-before-snapshot.jsonA shopify/scripts/tk11534-doubleroll/dr-snap-rollback.mjsA shopify/scripts/tk11534-doubleroll/lenmap-thibaut.txtA shopify/scripts/tk11534-doubleroll/lenmap-wallquest.txtA shopify/scripts/tk11534-doubleroll/widthmap-thibaut.txtA shopify/scripts/tk11534-doubleroll/widthmap-wallquest.txt
Diff
commit 31eff9bd88985de7a74fb41e014634a06e95b3b8
Author: Steve <steve@designerwallcoverings.com>
Date: Sun Sep 13 00:23:57 2026 -0700
TK-11534: doubleroll length backfill — additive --only-skus/--length-map/--width-map/--catalog-only flags + 47-SKU recoverable backfill assets (Steve-approved fix-forward)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUKRS8nTAFtE1hmVpgSHm2
---
shopify/scripts/set-doubleroll-lengths.py | 57 +++-
.../scripts/tk11534-doubleroll/cores-thibaut.txt | 91 +++++
.../scripts/tk11534-doubleroll/cores-wallquest.txt | 117 +++++++
.../tk11534-doubleroll/dr-before-snapshot.json | 375 +++++++++++++++++++++
.../tk11534-doubleroll/dr-snap-rollback.mjs | 43 +++
.../scripts/tk11534-doubleroll/lenmap-thibaut.txt | 33 ++
.../tk11534-doubleroll/lenmap-wallquest.txt | 25 ++
.../tk11534-doubleroll/widthmap-thibaut.txt | 33 ++
.../tk11534-doubleroll/widthmap-wallquest.txt | 25 ++
9 files changed, 796 insertions(+), 3 deletions(-)
diff --git a/shopify/scripts/set-doubleroll-lengths.py b/shopify/scripts/set-doubleroll-lengths.py
index 35f4bf7c..cfb2edbe 100644
--- a/shopify/scripts/set-doubleroll-lengths.py
+++ b/shopify/scripts/set-doubleroll-lengths.py
@@ -61,6 +61,45 @@ CFG = VENDORS[VKEY]
BEFORE = os.path.join(HERE, "audits", f"doubleroll-lengths-{VKEY}-before.jsonl")
os.makedirs(os.path.dirname(BEFORE), exist_ok=True)
+# TK-11534 (additive, opt-in — default behavior unchanged when flags absent):
+# --only-skus <file> scope processing to a newline-delimited allowlist of dw_sku CORES
+# (prefix+number, e.g. DWTT-80002 / DWQW-57999); products outside it
+# are fully skipped (no writes at all).
+# --catalog-only resolve LENGTH strictly from the vendor STAGING catalog — do NOT
+# derive from the live global.length, the width field, or the
+# width->length standard map. This stamps ONLY the staging-recoverable
+# subset and never guesses a length (honors "don't derive the ~120").
+CATALOG_ONLY = "--catalog-only" in sys.argv
+_only_path = arg("--only-skus")
+def core_of(sku):
+ m = re.match(r"^(DW[A-Z]{2}|LOD|CDA)-\d+", (sku or "").upper())
+ return m.group(0) if m else (sku or "").upper()
+ONLY_CORES = None
+if _only_path:
+ with open(_only_path) as _f:
+ ONLY_CORES = {core_of(l.strip()) for l in _f if l.strip()}
+# --length-map <file> TSV "CORE\tlength-string" supplying the AUTHORITATIVE staging length
+# per product (resolved via the correct per-vendor mfr_sku join, which
+# the naive dwsku catalog join misses). Highest-priority length source;
+# the script's OWN single/double classifier + writer still apply.
+def _load_map(path):
+ m = {}
+ if path:
+ with open(path) as _f:
+ for _l in _f:
+ _l = _l.rstrip("\n")
+ if not _l.strip():
+ continue
+ _c, _, _v = _l.partition("\t")
+ if _c.strip() and _v.strip():
+ m[core_of(_c.strip())] = _v.strip()
+ return m
+LEN_MAP = _load_map(arg("--length-map"))
+# --width-map <file> TSV "CORE\twidth-string" supplying the staging WIDTH (mfr_sku join),
+# used only by the single/double classifier's plausible-roll-width gate
+# when the live global.width metafield is absent. Never derives length.
+WIDTH_MAP = _load_map(arg("--width-map"))
+
# single ~28-32 sqft, double ~56-64; windows chosen wide enough for real variance,
# narrow enough that a mural (14 sqft) or a jumbo panel falls in the ODD gap.
SINGLE_LO, SINGLE_HI = 22, 42
@@ -231,6 +270,9 @@ def main():
"roll_variants": [v["sku"] for v in roll_vars]}) + "\n")
if not roll_vars:
continue
+ # TK-11534 scope allowlist: skip products outside the flagged set entirely (no writes)
+ if ONLY_CORES is not None and core_of(dwsku_of(roll_vars[0]["sku"])) not in ONLY_CORES:
+ continue
roll += 1
# ---- min/step = 2 (idempotent), always for roll products ----
@@ -246,19 +288,28 @@ def main():
dwsku = dwsku_of(roll_vars[0]["sku"])
cat_w, cat_L = catalog.get(dwsku, ("", ""))
W = cat_w or (p["w"] or {}).get("value") or ""
- L = cat_L or (p["len"] or {}).get("value") or ""
+ _mapW = WIDTH_MAP.get(core_of(dwsku))
+ if not width_in(W) and _mapW:
+ W = _mapW
+ # --catalog-only: LENGTH strictly from staging catalog (no live global.length fallback)
+ L = cat_L if CATALOG_ONLY else (cat_L or (p["len"] or {}).get("value") or "")
+ # --length-map override: authoritative staging length resolved via correct mfr_sku join
+ _mapL = LEN_MAP.get(core_of(dwsku))
+ if _mapL:
+ L = _mapL
# Dirty WallQuest data: the length may be empty while the full "W x L" dimension is
# crammed into the width field ("20.5in x 16.5ft"), OR a "W x L" string sits in the
# length field itself (CDA rows). Reduce any "A x B" to just its LENGTH token (after
# the last 'x') so we never treat a width×length string as a bare length (which would
# double BOTH numbers). Then fall back to the width field's 2nd token if length is empty.
L = only_length(L)
- if not length_ft(L):
+ if not length_ft(L) and not CATALOG_ONLY:
L = only_length(W, second_only=True)
wi = width_in(W)
# last resort ($0, no re-scrape): fill from the vendor's own width->length standard,
# keyed on the (now-cleaned) width. This value is the vendor's standard roll length.
- if not length_ft(L) and wi is not None:
+ # Skipped under --catalog-only (never derive a length; leave such products ODD/untouched).
+ if not length_ft(L) and wi is not None and not CATALOG_ONLY:
L = width_std.get(round(wi*2)/2, L)
lf = length_ft(L)
if not (wi and lf and lf > 0):
diff --git a/shopify/scripts/tk11534-doubleroll/cores-thibaut.txt b/shopify/scripts/tk11534-doubleroll/cores-thibaut.txt
new file mode 100644
index 00000000..231d4546
--- /dev/null
+++ b/shopify/scripts/tk11534-doubleroll/cores-thibaut.txt
@@ -0,0 +1,91 @@
+DWTT-70856
+DWTT-70844
+DWTT-70668
+DWTT-70660
+DWTT-70169
+DWTT-80002
+DWTT-80004
+DWTT-80005
+DWTT-80006
+DWTT-74478
+DWTT-74563
+DWTT-74565
+DWTT-80307
+DWTT-70630
+DWTT-70570
+DWTT-70070
+DWTT-70360
+DWTT-70380
+DWTT-71046
+DWTT-71047
+DWTT-71049
+DWTT-71078
+DWTT-71079
+DWTT-71081
+DWTT-71083
+DWTT-71053
+DWTT-71054
+DWTT-71055
+DWTT-71092
+DWTT-71097
+DWTT-71098
+DWTT-71099
+DWTT-71028
+DWTT-71030
+DWTT-80947
+DWTT-80957
+DWTT-80964
+DWTT-80965
+DWTT-80980
+DWTT-80883
+DWTT-80886
+DWTT-80908
+DWTT-80912
+DWTT-80934
+DWTT-80935
+DWTT-80752
+DWTT-80755
+DWTT-80756
+DWTT-70251
+DWTT-80758
+DWTT-80759
+DWTT-80760
+DWTT-80769
+DWTT-80776
+DWTT-80780
+DWTT-80652
+DWTT-80657
+DWTT-70581
+DWTT-70582
+DWTT-80681
+DWTT-80695
+DWTT-70554
+DWTT-81110
+DWTT-80706
+DWTT-80716
+DWTT-71128
+DWTT-80156
+DWTT-81061
+DWTT-81074
+DWTT-81075
+DWTT-81077
+DWTT-80241
+DWTT-80244
+DWTT-80246
+DWTT-80255
+DWTT-80267
+DWTT-80274
+DWTT-80617
+DWTT-80620
+DWTT-80627
+DWTT-80789
+DWTT-80790
+DWTT-80791
+DWTT-80041
+DWTT-80042
+DWTT-80569
+DWTT-80570
+DWTT-80571
+DWTT-80238
+DWTT-80239
+DWTT-80240
diff --git a/shopify/scripts/tk11534-doubleroll/cores-wallquest.txt b/shopify/scripts/tk11534-doubleroll/cores-wallquest.txt
new file mode 100644
index 00000000..178caa31
--- /dev/null
+++ b/shopify/scripts/tk11534-doubleroll/cores-wallquest.txt
@@ -0,0 +1,117 @@
+DWQW-57001
+DWQW-57002
+DWQW-58287
+DWQW-58289
+DWQW-58603
+DWQW-57999
+DWQW-58456
+DWQW-58483
+DWQW-56166
+DWQW-57522
+DWQW-57523
+DWQW-57525
+DWQW-57526
+DWQW-57245
+DWQW-57247
+DWQW-57248
+DWQW-58416
+DWQW-56976
+DWQW-56977
+DWQW-56978
+DWQW-56980
+DWQW-56981
+LOD-43303
+LOD-43304
+LOD-43305
+LOD-43306
+LOD-43307
+LOD-43308
+LOD-43309
+LOD-43310
+LOD-43318
+LOD-43322
+LOD-43323
+LOD-43324
+LOD-43329
+LOD-43331
+LOD-43332
+LOD-43333
+LOD-43335
+CDA-96700
+CDA-96701
+CDA-96702
+CDA-96703
+CDA-96704
+CDA-96705
+CDA-96706
+CDA-96707
+CDA-96708
+CDA-96709
+CDA-96714
+CDA-96715
+CDA-96716
+CDA-96717
+CDA-96719
+CDA-96720
+CDA-96721
+CDA-96722
+CDA-96723
+CDA-96724
+CDA-96725
+CDA-96726
+CDA-96727
+CDA-96729
+CDA-96730
+CDA-96731
+CDA-96732
+CDA-96733
+CDA-96734
+CDA-96735
+CDA-96736
+CDA-96737
+CDA-96738
+CDA-96739
+CDA-96740
+CDA-96741
+CDA-96742
+CDA-96743
+CDA-96744
+CDA-96745
+CDA-96746
+CDA-96747
+CDA-96748
+CDA-96749
+CDA-96750
+CDA-96751
+CDA-96753
+CDA-96754
+CDA-96755
+CDA-96756
+CDA-96757
+CDA-96758
+CDA-96759
+CDA-96760
+DWQW-58182
+DWQW-57544
+DWQW-57502
+DWQW-57503
+DWQW-57504
+DWQW-57506
+DWQW-57217
+DWQW-57218
+DWQW-57219
+DWQW-57224
+DWQW-57225
+DWQW-57099
+DWQW-57100
+DWQW-57101
+DWQW-57103
+DWQW-57125
+DWQW-57126
+DWQW-57127
+DWQW-57128
+DWQW-57133
+DWQW-57134
+DWQW-57135
+DWQW-56973
+DWQW-56974
diff --git a/shopify/scripts/tk11534-doubleroll/dr-before-snapshot.json b/shopify/scripts/tk11534-doubleroll/dr-before-snapshot.json
new file mode 100644
index 00000000..315667b4
--- /dev/null
+++ b/shopify/scripts/tk11534-doubleroll/dr-before-snapshot.json
@@ -0,0 +1,375 @@
+[
+ {
+ "core": "DWTT-70169",
+ "gid": "gid://shopify/Product/6944670613555",
+ "sr": null,
+ "dr": null,
+ "uom": null
+ },
+ {
+ "core": "DWTT-80002",
+ "gid": "gid://shopify/Product/7552655917107",
+ "sr": null,
+ "dr": null,
+ "uom": null
+ },
+ {
+ "core": "DWTT-80004",
+ "gid": "gid://shopify/Product/7552656015411",
+ "sr": null,
+ "dr": null,
+ "uom": "Priced Per Single Roll"
+ },
+ {
+ "core": "DWTT-80005",
+ "gid": "gid://shopify/Product/7552656080947",
+ "sr": null,
+ "dr": null,
+ "uom": "Priced Per Single Roll"
+ },
+ {
+ "core": "DWTT-80006",
+ "gid": "gid://shopify/Product/7552656146483",
+ "sr": null,
+ "dr": null,
+ "uom": "Priced Per Single Roll"
+ },
+ {
+ "core": "DWTT-71046",
+ "found": false
+ },
+ {
+ "core": "DWTT-71047",
+ "found": false
+ },
+ {
+ "core": "DWTT-71049",
+ "found": false
+ },
+ {
+ "core": "DWTT-71078",
+ "found": false
+ },
+ {
+ "core": "DWTT-71079",
+ "found": false
+ },
+ {
+ "core": "DWTT-71081",
+ "found": false
+ },
+ {
+ "core": "DWTT-71083",
+ "found": false
+ },
+ {
+ "core": "DWTT-71092",
+ "found": false
+ },
+ {
+ "core": "DWTT-71097",
+ "found": false
+ },
+ {
+ "core": "DWTT-71098",
+ "found": false
+ },
+ {
+ "core": "DWTT-71099",
+ "found": false
+ },
+ {
+ "core": "DWTT-80752",
+ "gid": "gid://shopify/Product/7552722141235",
+ "sr": null,
+ "dr": null,
+ "uom": null
+ },
+ {
+ "core": "DWTT-80755",
+ "gid": "gid://shopify/Product/7552722305075",
+ "sr": null,
+ "dr": null,
+ "uom": null
+ },
+ {
+ "core": "DWTT-80756",
+ "gid": "gid://shopify/Product/7552722370611",
+ "sr": null,
+ "dr": null,
+ "uom": null
+ },
+ {
+ "core": "DWTT-70251",
+ "gid": "gid://shopify/Product/6944673464371",
+ "sr": null,
+ "dr": null,
+ "uom": "Priced Per Single Roll"
+ },
+ {
+ "core": "DWTT-80758",
+ "gid": "gid://shopify/Product/7552722468915",
+ "sr": null,
+ "dr": null,
+ "uom": null
+ },
+ {
+ "core": "DWTT-80759",
+ "gid": "gid://shopify/Product/7552722501683",
+ "sr": null,
+ "dr": null,
+ "uom": null
+ },
+ {
+ "core": "DWTT-80760",
+ "gid": "gid://shopify/Product/7552722534451",
+ "sr": null,
+ "dr": null,
+ "uom": null
+ },
+ {
+ "core": "DWTT-80769",
+ "gid": "gid://shopify/Product/7552722927667",
+ "sr": null,
+ "dr": null,
+ "uom": null
+ },
+ {
+ "core": "DWTT-80776",
+ "gid": "gid://shopify/Product/7552723288115",
+ "sr": null,
+ "dr": null,
+ "uom": null
+ },
+ {
+ "core": "DWTT-80780",
+ "gid": "gid://shopify/Product/7552723484723",
+ "sr": null,
+ "dr": null,
+ "uom": null
+ },
+ {
+ "core": "DWTT-80657",
+ "gid": "gid://shopify/Product/7552714604595",
+ "sr": null,
+ "dr": null,
+ "uom": null
+ },
+ {
+ "core": "DWTT-70581",
+ "gid": "gid://shopify/Product/6944685654067",
+ "sr": null,
+ "dr": null,
+ "uom": null
+ },
+ {
+ "core": "DWTT-70582",
+ "gid": "gid://shopify/Product/6944685686835",
+ "sr": null,
+ "dr": null,
+ "uom": null
+ },
+ {
+ "core": "DWTT-80681",
+ "gid": "gid://shopify/Product/7552715849779",
+ "sr": null,
+ "dr": null,
+ "uom": null
+ },
+ {
+ "core": "DWTT-70554",
+ "gid": "gid://shopify/Product/6944684769331",
+ "sr": null,
+ "dr": null,
+ "uom": "Priced Per Single Roll"
+ },
+ {
+ "core": "DWTT-80706",
+ "gid": "gid://shopify/Product/7552717848627",
+ "sr": null,
+ "dr": null,
+ "uom": null
+ },
+ {
+ "core": "DWTT-80716",
+ "gid": "gid://shopify/Product/7552720306227",
+ "sr": null,
+ "dr": null,
+ "uom": null
+ },
+ {
+ "core": "DWQW-57999",
+ "gid": "gid://shopify/Product/7317649227827",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57522",
+ "gid": "gid://shopify/Product/7292575514675",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57523",
+ "gid": "gid://shopify/Product/7292576956467",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57525",
+ "gid": "gid://shopify/Product/7292578922547",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57526",
+ "gid": "gid://shopify/Product/7292579971123",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57245",
+ "gid": "gid://shopify/Product/7292377563187",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57247",
+ "gid": "gid://shopify/Product/7292379070515",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57248",
+ "gid": "gid://shopify/Product/7292379889715",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57502",
+ "gid": "gid://shopify/Product/7292554706995",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57503",
+ "gid": "gid://shopify/Product/7292555853875",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57504",
+ "gid": "gid://shopify/Product/7292556738611",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57506",
+ "gid": "gid://shopify/Product/7292558770227",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57217",
+ "gid": "gid://shopify/Product/7292354461747",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57218",
+ "gid": "gid://shopify/Product/7292355280947",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57219",
+ "gid": "gid://shopify/Product/7292356067379",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57224",
+ "gid": "gid://shopify/Product/7292360654899",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57225",
+ "gid": "gid://shopify/Product/7292361539635",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57099",
+ "gid": "gid://shopify/Product/7292291088435",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57100",
+ "gid": "gid://shopify/Product/7292292038707",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57101",
+ "gid": "gid://shopify/Product/7292292857907",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57103",
+ "gid": "gid://shopify/Product/7292294365235",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57125",
+ "gid": "gid://shopify/Product/7292312059955",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57126",
+ "gid": "gid://shopify/Product/7292312846387",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57127",
+ "gid": "gid://shopify/Product/7292313927731",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ },
+ {
+ "core": "DWQW-57128",
+ "gid": "gid://shopify/Product/7292315009075",
+ "sr": null,
+ "dr": null,
+ "uom": "Full Roll"
+ }
+]
\ No newline at end of file
diff --git a/shopify/scripts/tk11534-doubleroll/dr-snap-rollback.mjs b/shopify/scripts/tk11534-doubleroll/dr-snap-rollback.mjs
new file mode 100644
index 00000000..9c6d5777
--- /dev/null
+++ b/shopify/scripts/tk11534-doubleroll/dr-snap-rollback.mjs
@@ -0,0 +1,43 @@
+import fs from 'node:fs';
+import { gql } from '/Users/macstudio3/Projects/designerwallcoverings/scripts/lib/shopify.mjs';
+const SC='/private/tmp/claude-501/-Users-macstudio3-Projects-designerwallcoverings/f5511869-92b7-4c17-a6d8-32c84b0a7711/scratchpad';
+const SNAP=SC+'/dr-before-snapshot.json';
+const MODE=process.argv[2]; // snap | undo
+const cores=[];
+for(const v of ['thibaut','wallquest']){ for(const l of fs.readFileSync(`${SC}/lenmap-${v}.txt`,'utf8').trim().split('\n')){ if(l) cores.push({vendor:v, core:l.split('\t')[0]}); } }
+async function findProduct(core){
+ // find the product owning a variant whose sku core matches
+ const d=await gql(`query($q:String!){ productVariants(first:5, query:$q){ nodes{ sku product{ id
+ sr:metafield(namespace:"global",key:"single_roll_length"){id value}
+ dr:metafield(namespace:"global",key:"double_roll_length"){id value}
+ uom:metafield(namespace:"global",key:"unit_of_measure"){id value} } } } }`, { q:`sku:${core}*` });
+ for(const v of d.productVariants.nodes){ const c=(v.sku||'').toUpperCase().match(/^(DW[A-Z]{2}|LOD|CDA)-\d+/); if(c&&c[0]===core) return v.product; }
+ return null;
+}
+if(MODE==='snap'){
+ const snap=[];
+ for(const {core} of cores){ const p=await findProduct(core); if(!p){snap.push({core,found:false});continue;}
+ snap.push({core, gid:p.id, sr:p.sr?.value??null, dr:p.dr?.value??null, uom:p.uom?.value??null}); }
+ fs.writeFileSync(SNAP, JSON.stringify(snap,null,1));
+ const withVals=snap.filter(s=>s.found!==false && (s.sr||s.dr));
+ console.log(`snapshot ${snap.length} cores -> ${SNAP}; already-nonnull SR/DR: ${withVals.length}`);
+} else if(MODE==='undo'){
+ const snap=JSON.parse(fs.readFileSync(SNAP,'utf8'));
+ const DEL=`mutation($mf:[MetafieldIdentifierInput!]!){ metafieldsDelete(metafields:$mf){ deletedMetafields{key} userErrors{message} } }`;
+ const SET=`mutation($mfs:[MetafieldsSetInput!]!){ metafieldsSet(metafields:$mfs){ userErrors{message} } }`;
+ let done=0;
+ for(const s of snap){ if(!s.gid) continue;
+ // restore each of sr/dr/uom to prior: delete if prior null else set
+ const toDel=[], toSet=[];
+ for(const k of [['single_roll_length','sr'],['double_roll_length','dr'],['unit_of_measure','uom']]){
+ if(s[k[1]]==null) toDel.push({ownerId:s.gid, namespace:'global', key:k[0]});
+ else toSet.push({ownerId:s.gid, namespace:'global', key:k[0], type:'single_line_text_field', value:s[k[1]]});
+ }
+ if(process.argv[3]==='--apply'){
+ if(toDel.length){ const r=await gql(DEL,{mf:toDel}); if(r?.__err) console.log('del err',s.core,JSON.stringify(r.__err).slice(0,120)); }
+ if(toSet.length){ const r=await gql(SET,{mfs:toSet}); if(r?.__err) console.log('set err',s.core,JSON.stringify(r.__err).slice(0,120)); }
+ }
+ done++;
+ }
+ console.log(`undo ${process.argv[3]==='--apply'?'APPLIED':'DRY'} on ${done} products`);
+}
diff --git a/shopify/scripts/tk11534-doubleroll/lenmap-thibaut.txt b/shopify/scripts/tk11534-doubleroll/lenmap-thibaut.txt
new file mode 100644
index 00000000..55c66ce2
--- /dev/null
+++ b/shopify/scripts/tk11534-doubleroll/lenmap-thibaut.txt
@@ -0,0 +1,33 @@
+DWTT-70169 4 yd (3.66 m)
+DWTT-80002 4.5 yd (4.11 m)
+DWTT-80004 4.5 yd (4.11 m)
+DWTT-80005 4.5 yd (4.11 m)
+DWTT-80006 4.5 yd (4.11 m)
+DWTT-71046 4.5 yd (4.11 m)
+DWTT-71047 4.5 yd (4.11 m)
+DWTT-71049 4.5 yd (4.11 m)
+DWTT-71078 4.5 yd (4.11 m)
+DWTT-71079 4.5 yd (4.11 m)
+DWTT-71081 4.5 yd (4.11 m)
+DWTT-71083 4.5 yd (4.11 m)
+DWTT-71092 4.5 yd (4.11 m)
+DWTT-71097 4.5 yd (4.11 m)
+DWTT-71098 4.5 yd (4.11 m)
+DWTT-71099 4.5 yd (4.11 m)
+DWTT-80752 4.5 yd (4.11 m)
+DWTT-80755 4.5 yd (4.11 m)
+DWTT-80756 4.5 yd (4.11 m)
+DWTT-70251 4.5 yd (4.11 m)
+DWTT-80758 4.5 yd (4.11 m)
+DWTT-80759 4.5 yd (4.11 m)
+DWTT-80760 4.5 yd (4.11 m)
+DWTT-80769 4.5 yd (4.11 m)
+DWTT-80776 4.5 yd (4.11 m)
+DWTT-80780 4.5 yd (4.11 m)
+DWTT-80657 4.5 yd (4.11 m)
+DWTT-70581 4.5 yd (4.11 m)
+DWTT-70582 4.5 yd (4.11 m)
+DWTT-80681 4.5 yd (4.11 m)
+DWTT-70554 4.5 yd (4.11 m)
+DWTT-80706 4.5 yd (4.11 m)
+DWTT-80716 4.5 yd (4.11 m)
diff --git a/shopify/scripts/tk11534-doubleroll/lenmap-wallquest.txt b/shopify/scripts/tk11534-doubleroll/lenmap-wallquest.txt
new file mode 100644
index 00000000..7aae97e4
--- /dev/null
+++ b/shopify/scripts/tk11534-doubleroll/lenmap-wallquest.txt
@@ -0,0 +1,25 @@
+DWQW-57999 9 yd | 8.2 m
+DWQW-57522 11 yd | 10 m
+DWQW-57523 11 yd | 10 m
+DWQW-57525 11 yd | 10 m
+DWQW-57526 11 yd | 10 m
+DWQW-57245 11 yd | 10 m
+DWQW-57247 11 yd | 10 m
+DWQW-57248 11 yd | 10 m
+DWQW-57502 11 yd | 10 m
+DWQW-57503 11 yd | 10 m
+DWQW-57504 11 yd | 10 m
+DWQW-57506 11 yd | 10 m
+DWQW-57217 9 yd | 8.2 m
+DWQW-57218 9 yd | 8.2 m
+DWQW-57219 9 yd | 8.2 m
+DWQW-57224 11 yd | 10 m
+DWQW-57225 11 yd | 10 m
+DWQW-57099 9 yd | 8.2 m
+DWQW-57100 9 yd | 8.2 m
+DWQW-57101 9 yd | 8.2 m
+DWQW-57103 9 yd | 8.2 m
+DWQW-57125 9 yd | 8.2 m
+DWQW-57126 9 yd | 8.2 m
+DWQW-57127 9 yd | 8.2 m
+DWQW-57128 9 yd | 8.2 m
diff --git a/shopify/scripts/tk11534-doubleroll/widthmap-thibaut.txt b/shopify/scripts/tk11534-doubleroll/widthmap-thibaut.txt
new file mode 100644
index 00000000..761e976e
--- /dev/null
+++ b/shopify/scripts/tk11534-doubleroll/widthmap-thibaut.txt
@@ -0,0 +1,33 @@
+DWTT-70169 36
+DWTT-80002 27 in (68.58 cm)
+DWTT-80004 27" x 4.5yds
+DWTT-80005 27" x 4.5yds
+DWTT-80006 27" x 4.5yds
+DWTT-71046 54 in (137.16 cm)
+DWTT-71047 54 in (137.16 cm)
+DWTT-71049 54 in (137.16 cm)
+DWTT-71078 53 in (134.62 cm)
+DWTT-71079 53 in (134.62 cm)
+DWTT-71081 53 in (134.62 cm)
+DWTT-71083 53 in (134.62 cm)
+DWTT-71092 54 in (137.16 cm)
+DWTT-71097 54 in (137.16 cm)
+DWTT-71098 54 in (137.16 cm)
+DWTT-71099 54 in (137.16 cm)
+DWTT-80752 27 in (68.58 cm)
+DWTT-80755 27 in (68.58 cm)
+DWTT-80756 27 in (68.58 cm)
+DWTT-70251 27 in (68.58 cm)
+DWTT-80758 27 in (68.58 cm)
+DWTT-80759 27 in (68.58 cm)
+DWTT-80760 27 in (68.58 cm)
+DWTT-80769 27 in (68.58 cm)
+DWTT-80776 27 in (68.58 cm)
+DWTT-80780 27 in (68.58 cm)
+DWTT-80657 27 in (68.58 cm)
+DWTT-70581 27" x 4.5yds
+DWTT-70582 27" x 4.5yds
+DWTT-80681 27 in (68.58 cm)
+DWTT-70554 27" x 4.5yds
+DWTT-80706 27
+DWTT-80716 27
diff --git a/shopify/scripts/tk11534-doubleroll/widthmap-wallquest.txt b/shopify/scripts/tk11534-doubleroll/widthmap-wallquest.txt
new file mode 100644
index 00000000..dcece404
--- /dev/null
+++ b/shopify/scripts/tk11534-doubleroll/widthmap-wallquest.txt
@@ -0,0 +1,25 @@
+DWQW-57999 27 in | 68.5 cm
+DWQW-57522 20.5 in | 52.1 cm
+DWQW-57523 20.5 in | 52.1 cm
+DWQW-57525 20.5 in | 52.1 cm
+DWQW-57526 20.5 in | 52.1 cm
+DWQW-57245 20.5 in | 52.1 cm
+DWQW-57247 20.5 in | 52.1 cm
+DWQW-57248 20.5 in | 52.1 cm
+DWQW-57502 20.5 in | 52.1 cm
+DWQW-57503 20.5 in | 52.1 cm
+DWQW-57504 20.5 in | 52.1 cm
+DWQW-57506 20.5 in | 52.1 cm
+DWQW-57217 27 in | 68.5 cm
+DWQW-57218 27 in | 68.5 cm
+DWQW-57219 27 in | 68.5 cm
+DWQW-57224 20.5 in | 52.1 cm
+DWQW-57225 20.5 in | 52.1 cm
+DWQW-57099 27 in | 68.5 cm
+DWQW-57100 27 in | 68.5 cm
+DWQW-57101 27 in | 68.5 cm
+DWQW-57103 27 in | 68.5 cm
+DWQW-57125 27 in | 68.5 cm
+DWQW-57126 27 in | 68.5 cm
+DWQW-57127 27 in | 68.5 cm
+DWQW-57128 27 in | 68.5 cm
← fb16e055 auto-data-snapshot: 2026-09-12T23:45:38 (5 data files) — DW-
·
back to Designer Wallcoverings
·
TK-11534: make doubleroll rollback self-contained (self-rela 40beee57 →