← back to Dw Title Repair
TK-11240 part B: backfill dwc.pattern_name on 223 ACTIVE Hollywood products
24d7b63a7f1ea29d09e21ee6107300f4059a0be3 · 2026-09-11 11:42:37 -0700 · steve
Approved memo (yolo-queue/_approved/). 223 of 283 have an authoritative
versa_catalog source; the other 60 are left unfilled rather than derived from
titles, since title-derivation is the origin of the category-label pollution.
Live-verified 25/25. Verify-before-write: skips any product that already has a
value, so it cannot overwrite. Undo deletes only values this script wrote.
Part A (theme module) blocked on read_themes token scope, not approval.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Files touched
A data/patternfill.tsvA data/pf.errA patternfill.mjs
Diff
commit 24d7b63a7f1ea29d09e21ee6107300f4059a0be3
Author: steve <steve@designerwallcoverings.com>
Date: Fri Sep 11 11:42:37 2026 -0700
TK-11240 part B: backfill dwc.pattern_name on 223 ACTIVE Hollywood products
Approved memo (yolo-queue/_approved/). 223 of 283 have an authoritative
versa_catalog source; the other 60 are left unfilled rather than derived from
titles, since title-derivation is the origin of the category-label pollution.
Live-verified 25/25. Verify-before-write: skips any product that already has a
value, so it cannot overwrite. Undo deletes only values this script wrote.
Part A (theme module) blocked on read_themes token scope, not approval.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---
data/patternfill.tsv | 223 +++++++++++++++++++++++++++++++++++++++++++++++++++
data/pf.err | 0
patternfill.mjs | 52 ++++++++++++
3 files changed, 275 insertions(+)
diff --git a/data/patternfill.tsv b/data/patternfill.tsv
new file mode 100644
index 0000000..312d158
--- /dev/null
+++ b/data/patternfill.tsv
@@ -0,0 +1,223 @@
+gid://shopify/Product/7800019714099 A194-431 Caba
+gid://shopify/Product/7800237260851 A194-504 Caba
+gid://shopify/Product/7800237391923 A194-576 Caba
+gid://shopify/Product/7800237686835 A195-018 Parallel
+gid://shopify/Product/7800237752371 A195-127 Parallel
+gid://shopify/Product/7800237850675 A195-154 Parallel
+gid://shopify/Product/7800237948979 A195-193 Parallel
+gid://shopify/Product/7800238047283 A195-226 Parallel
+gid://shopify/Product/7800238178355 A195-502 Parallel
+gid://shopify/Product/7800238243891 A195-512 Parallel
+gid://shopify/Product/7800238342195 A195-537 Parallel
+gid://shopify/Product/7800238440499 A195-541 Parallel
+gid://shopify/Product/7800238538803 A195-558 Parallel
+gid://shopify/Product/7800238604339 A195-561 Parallel
+gid://shopify/Product/7800238669875 A195-596 Parallel
+gid://shopify/Product/7800238768179 A196-001 Corda
+gid://shopify/Product/7800238866483 A196-012 Corda
+gid://shopify/Product/7800238932019 A196-206 Corda
+gid://shopify/Product/7800239128627 A196-382 Corda
+gid://shopify/Product/7800239325235 A196-509 Corda
+gid://shopify/Product/7800239423539 A196-588 Corda
+gid://shopify/Product/7800239489075 A196-592 Corda
+gid://shopify/Product/7800239652915 A197-118 Astoria
+gid://shopify/Product/7800239718451 A197-153 Astoria
+gid://shopify/Product/7800239783987 A197-276 Astoria
+gid://shopify/Product/7800239882291 A197-358 Astoria
+gid://shopify/Product/7800239947827 A197-394 Astoria
+gid://shopify/Product/7800240013363 A197-512 Astoria
+gid://shopify/Product/7800240111667 A197-524 Astoria
+gid://shopify/Product/7800240406579 A197-579 Astoria
+gid://shopify/Product/7800240472115 A197-582 Astoria
+gid://shopify/Product/7800240603187 A197-785 Astoria
+gid://shopify/Product/7800240668723 A198-034 Burnished Silk
+gid://shopify/Product/7800240799795 A198-162 Burnished Silk
+gid://shopify/Product/7800240898099 A198-297 Burnished Silk
+gid://shopify/Product/7800241029171 A198-387 Burnished Silk
+gid://shopify/Product/7800241193011 A198-458 Burnished Silk
+gid://shopify/Product/7800241324083 A198-526 Burnished Silk
+gid://shopify/Product/7800241618995 A199-118 Lurra
+gid://shopify/Product/7800241750067 A199-601 Lurra
+gid://shopify/Product/7800241848371 A199-801 Lurra
+gid://shopify/Product/7800241913907 A199-805 Lurra
+gid://shopify/Product/7800242110515 A200-034 Senza
+gid://shopify/Product/7800242176051 A200-145 Senza
+gid://shopify/Product/7800242274355 A200-183 Senza
+gid://shopify/Product/7800242503731 A200-817 Senza
+gid://shopify/Product/7800242634803 A201-017 Akasha
+gid://shopify/Product/7800242700339 A201-143 Akasha
+gid://shopify/Product/7800242765875 A201-161 Akasha
+gid://shopify/Product/7800242831411 A201-335 Akasha
+gid://shopify/Product/7800242929715 A201-377 Akasha
+gid://shopify/Product/7800242995251 A201-510 Akasha
+gid://shopify/Product/7800243060787 A201-518 Akasha
+gid://shopify/Product/7800243159091 A201-524 Akasha
+gid://shopify/Product/7800243224627 A201-548 Akasha
+gid://shopify/Product/7800243322931 A201-706 Akasha
+gid://shopify/Product/7800243454003 A201-706-297 Akasha
+gid://shopify/Product/7800243585075 A202-026 Navarre
+gid://shopify/Product/7800243683379 A202-149 Navarre
+gid://shopify/Product/7800243748915 A202-154 Navarre
+gid://shopify/Product/7800243847219 A202-328 Navarre
+gid://shopify/Product/7800243912755 A202-357 Navarre
+gid://shopify/Product/7800244076595 A202-671 Navarre
+gid://shopify/Product/7800244142131 A202-705 Navarre
+gid://shopify/Product/7800244240435 A202-816 Navarre
+gid://shopify/Product/7800244305971 A202-821 Navarre
+gid://shopify/Product/7800244437043 A202-847 Navarre
+gid://shopify/Product/7800244568115 A203-119 Alegre
+gid://shopify/Product/7800244797491 A203-333 Alegre
+gid://shopify/Product/7800244863027 A203-357 Alegre
+gid://shopify/Product/7800244928563 A203-416 Alegre
+gid://shopify/Product/7800245026867 A203-520 Alegre
+gid://shopify/Product/7800245190707 A203-567 Alegre
+gid://shopify/Product/7800245256243 A203-571 Alegre
+gid://shopify/Product/7800245452851 A204-251 Avenir
+gid://shopify/Product/7800245485619 A204-323 Avenir
+gid://shopify/Product/7800245583923 A204-519 Avenir
+gid://shopify/Product/7800245682227 A204-522 Avenir
+gid://shopify/Product/7800245780531 A204-525 Avenir
+gid://shopify/Product/7800245846067 A204-539 Avenir
+gid://shopify/Product/7800245977139 A204-567 Avenir
+gid://shopify/Product/7800246206515 A205-012 Emerson Texture
+gid://shopify/Product/7800246304819 A205-038 Emerson Texture
+gid://shopify/Product/7800246370355 A205-104 Emerson Texture
+gid://shopify/Product/7800246501427 A205-127 Emerson Texture
+gid://shopify/Product/7800246698035 A205-345 Emerson Texture
+gid://shopify/Product/7800246796339 A205-372 Emerson Texture
+gid://shopify/Product/7800246861875 A205-592 Emerson Texture
+gid://shopify/Product/7800246894643 A205-641 Emerson Texture
+gid://shopify/Product/7800247058483 A205-826 Emerson Texture
+gid://shopify/Product/7800247124019 A205-833 Emerson Texture
+gid://shopify/Product/7800247222323 A205-852 Emerson Texture
+gid://shopify/Product/7800247255091 A205-834 Emerson Texture
+gid://shopify/Product/7800247353395 A205-867 Emerson Texture
+gid://shopify/Product/7800247451699 A205-882 Emerson Texture
+gid://shopify/Product/7800247648307 A206-012 Emerson
+gid://shopify/Product/7800247746611 A206-038 Emerson
+gid://shopify/Product/7800247844915 A206-127 Emerson
+gid://shopify/Product/7800248074291 A206-867 Emerson
+gid://shopify/Product/7800248205363 A206-882 Emerson
+gid://shopify/Product/7800248369203 A207-111 Sterling Heights
+gid://shopify/Product/7800248434739 A207-120 Sterling Heights
+gid://shopify/Product/7800248565811 A207-140 Sterling Heights
+gid://shopify/Product/7800248664115 A207-250 Sterling Heights
+gid://shopify/Product/7800248795187 A207-299 Sterling Heights
+gid://shopify/Product/7800248959027 A207-333 Sterling Heights
+gid://shopify/Product/7800249024563 A207-400 Sterling Heights
+gid://shopify/Product/7800249090099 A207-500 Sterling Heights
+gid://shopify/Product/7800249221171 A207-501 Sterling Heights
+gid://shopify/Product/7800249417779 A207-501-303 Sterling Heights
+gid://shopify/Product/7800249548851 A207-555 Sterling Heights
+gid://shopify/Product/7800249679923 A207-590 Sterling Heights
+gid://shopify/Product/7800249745459 A207-667 Sterling Heights
+gid://shopify/Product/7800249810995 A207-899 Sterling Heights
+gid://shopify/Product/7800249909299 A208-038 Patina Blocks
+gid://shopify/Product/7800249974835 A208-065 Patina Blocks
+gid://shopify/Product/7800250105907 A208-127 Patina Blocks
+gid://shopify/Product/7800250204211 A208-154 Patina Blocks
+gid://shopify/Product/7800250269747 A208-361 Patina Blocks
+gid://shopify/Product/7800250400819 A208-379 Patina Blocks
+gid://shopify/Product/7800250531891 A208-483 Patina Blocks
+gid://shopify/Product/7800250630195 A208-536 Patina Blocks
+gid://shopify/Product/7800250695731 A208-672 Patina Blocks
+gid://shopify/Product/7800250794035 A208-801 Patina Blocks
+gid://shopify/Product/7800250925107 A208-822 Patina Blocks
+gid://shopify/Product/7800251023411 A208-849 Patina Blocks
+gid://shopify/Product/7800251056179 A208-890 Patina Blocks
+gid://shopify/Product/7800251285555 A208-890-304 Patina Blocks
+gid://shopify/Product/7800251383859 A209-103 Oracle
+gid://shopify/Product/7800251449395 A209-390 Oracle
+gid://shopify/Product/7800251547699 A209-576 Oracle
+gid://shopify/Product/7800251711539 A209-805 Oracle
+gid://shopify/Product/7800251842611 A209-834 Oracle
+gid://shopify/Product/7800251908147 A210-075 Ossian
+gid://shopify/Product/7800251940915 A210-127 Ossian
+gid://shopify/Product/7800252039219 A210-193 Ossian
+gid://shopify/Product/7800252170291 A210-347 Ossian
+gid://shopify/Product/7800252301363 A210-446 Ossian
+gid://shopify/Product/7800252432435 A210-502 Ossian
+gid://shopify/Product/7800252563507 A210-516 Ossian
+gid://shopify/Product/7800252694579 A210-533 Ossian
+gid://shopify/Product/7800252825651 A210-534 Ossian
+gid://shopify/Product/7800252956723 A210-575 Ossian
+gid://shopify/Product/7800253218867 A211-027 Bellevue
+gid://shopify/Product/7800253415475 A211-231 Bellevue
+gid://shopify/Product/7800253481011 A211-310 Bellevue
+gid://shopify/Product/7800253546547 A211-337 Bellevue
+gid://shopify/Product/7800253677619 A211-456 Bellevue
+gid://shopify/Product/7800253808691 A211-589 Bellevue
+gid://shopify/Product/7800253906995 A211-602 Bellevue
+gid://shopify/Product/7800254005299 A211-823 Bellevue
+gid://shopify/Product/7800254103603 A211-941 Bellevue
+gid://shopify/Product/7800254169139 A212-037 Elowen
+gid://shopify/Product/7800254234675 A212-015 Elowen
+gid://shopify/Product/7800254431283 A212-441 Elowen
+gid://shopify/Product/7800254595123 A212-624 Elowen
+gid://shopify/Product/7800254758963 A212-695 Elowen
+gid://shopify/Product/7800254824499 A212-802 Elowen
+gid://shopify/Product/7800254890035 A212-831 Elowen
+gid://shopify/Product/7800255021107 A213-019 Isla Grass
+gid://shopify/Product/7800255086643 A213-064 Isla Grass
+gid://shopify/Product/7800255152179 A213-156 Isla Grass
+gid://shopify/Product/7800255316019 A213-263 Isla Grass
+gid://shopify/Product/7800255447091 A213-302 Isla Grass
+gid://shopify/Product/7800255578163 A213-394 Isla Grass
+gid://shopify/Product/7800255774771 A213-481 Isla Grass
+gid://shopify/Product/7800255938611 A213-620 Isla Grass
+gid://shopify/Product/7800256069683 A213-743 Isla Grass
+gid://shopify/Product/7800256200755 A213-838 Isla Grass
+gid://shopify/Product/7800256299059 A213-879 Isla Grass
+gid://shopify/Product/7800256364595 A213-879-309 Isla Grass
+gid://shopify/Product/7800256462899 A214-074 Alameda
+gid://shopify/Product/7800256561203 A214-095 Alameda
+gid://shopify/Product/7800256626739 A214-187 Alameda
+gid://shopify/Product/7800256692275 A214-196 Alameda
+gid://shopify/Product/7800256757811 A214-318 Alameda
+gid://shopify/Product/7800256888883 A214-380 Alameda
+gid://shopify/Product/7800257019955 A214-442 Alameda
+gid://shopify/Product/7800257183795 A214-629 Alameda
+gid://shopify/Product/7800257282099 A214-863 Alameda
+gid://shopify/Product/7800257413171 A215-135 Secret Garden
+gid://shopify/Product/7800257544243 A215-306 Secret Garden
+gid://shopify/Product/7800257609779 A215-372 Secret Garden
+gid://shopify/Product/7800257740851 A215-829 Secret Garden
+gid://shopify/Product/7800257806387 A215-843 Secret Garden
+gid://shopify/Product/7800257937459 A215-861 Secret Garden
+gid://shopify/Product/7800258035763 A215-896-311 Secret Garden
+gid://shopify/Product/7800258134067 A216-059 Ascoli
+gid://shopify/Product/7800258232371 A216-062 Ascoli
+gid://shopify/Product/7800258396211 A216-710 Ascoli
+gid://shopify/Product/7800258494515 A216-803 Ascoli
+gid://shopify/Product/7800258560051 A216-871 Ascoli
+gid://shopify/Product/7800258756659 A217-040 Sakura
+gid://shopify/Product/7800258822195 A217-558 Sakura
+gid://shopify/Product/7800258920499 A217-820 Sakura
+gid://shopify/Product/7800259117107 A217-844 Sakura
+gid://shopify/Product/7800259215411 A218-099 Orsay
+gid://shopify/Product/7800259313715 A218-163 Orsay
+gid://shopify/Product/7800259412019 A218-358 Orsay
+gid://shopify/Product/7800259510323 A218-375 Orsay
+gid://shopify/Product/7800259575859 A218-586 Orsay
+gid://shopify/Product/7800259706931 A218-622 Orsay
+gid://shopify/Product/7800259838003 A218-641 Orsay
+gid://shopify/Product/7800259969075 A218-724 Orsay
+gid://shopify/Product/7800260100147 A218-810 Orsay
+gid://shopify/Product/7800260231219 A218-845 Orsay
+gid://shopify/Product/7800260329523 A218-879 Orsay
+gid://shopify/Product/7800260395059 A219-031 Zenith
+gid://shopify/Product/7800260460595 A219-068 Zenith
+gid://shopify/Product/7800260558899 A219-195 Zenith
+gid://shopify/Product/7800260624435 A219-254 Zenith
+gid://shopify/Product/7800260689971 A219-352 Zenith
+gid://shopify/Product/7800260788275 A219-476 Zenith
+gid://shopify/Product/7800260919347 A219-591 Zenith
+gid://shopify/Product/7800260984883 A219-683 Zenith
+gid://shopify/Product/7800261115955 A219-813 Zenith
+gid://shopify/Product/7800261181491 A219-820 Zenith
+gid://shopify/Product/7800261279795 A219-847 Zenith
+gid://shopify/Product/7800261443635 A220-003 Weft
+gid://shopify/Product/7800261509171 A220-023 Weft
+gid://shopify/Product/7800261607475 A220-134 Weft
+gid://shopify/Product/7800261836851 A220-367 Weft
+gid://shopify/Product/7800261935155 A220-487 Weft
diff --git a/data/pf.err b/data/pf.err
new file mode 100644
index 0000000..e69de29
diff --git a/patternfill.mjs b/patternfill.mjs
new file mode 100644
index 0000000..5655e55
--- /dev/null
+++ b/patternfill.mjs
@@ -0,0 +1,52 @@
+#!/usr/bin/env node
+// TK-11240 part B — backfill dwc.pattern_name on ACTIVE Hollywood products that have none.
+// DRY-RUN BY DEFAULT. APPLY=1 to write. UNDO=1 APPLY=1 deletes the metafields this created.
+// Safe by construction: only touches products whose dwc.pattern_name is currently ABSENT,
+// re-verified LIVE immediately before each write, so it can never overwrite an existing value.
+import fs from 'node:fs';
+const DOM=process.env.SHOPIFY_STORE_DOMAIN, TOK=process.env.SHOPIFY_ADMIN_TOKEN;
+const APPLY=process.env.APPLY==='1', UNDO=process.env.UNDO==='1';
+const LIMIT=parseInt(process.env.LIMIT||'0',10);
+if(!DOM||!TOK){console.error('missing SHOPIFY_STORE_DOMAIN / SHOPIFY_ADMIN_TOKEN');process.exit(1);}
+const rows=fs.readFileSync('data/patternfill.tsv','utf8').trim().split('\n')
+ .map(l=>{const [id,sku,pat]=l.split('\t');return {id,sku,pat};});
+const work=LIMIT?rows.slice(0,LIMIT):rows;
+const ledger=fs.createWriteStream(`data/patternfill-${UNDO?'undo':'apply'}-progress.jsonl`,{flags:'a'});
+async function gql(q,v){
+ for(let a=0;a<4;a++){
+ const r=await fetch(`https://${DOM}/admin/api/2024-10/graphql.json`,{method:'POST',
+ headers:{'X-Shopify-Access-Token':TOK,'Content-Type':'application/json'},
+ body:JSON.stringify({query:q,variables:v})});
+ if([429,502,503].includes(r.status)){await new Promise(s=>setTimeout(s,1500*(a+1)));continue;}
+ return r.json();
+ }
+ throw new Error('gql retries exhausted');
+}
+const SET=`mutation($m:[MetafieldsSetInput!]!){metafieldsSet(metafields:$m){userErrors{field message}}}`;
+const DEL=`mutation($id:ID!){metafieldDelete(input:{id:$id}){deletedId userErrors{field message}}}`;
+let ok=0,skip=0,err=0;
+for(const [i,r] of work.entries()){
+ // VERIFY LIVE: read the current value before deciding anything
+ const cur=await gql(`{product(id:"${r.id}"){ metafield(namespace:"dwc",key:"pattern_name"){ id value } }}`);
+ const mf=cur?.data?.product?.metafield;
+ if(cur?.data?.product===undefined){err++;ledger.write(JSON.stringify({id:r.id,status:'not_found'})+'\n');continue;}
+ if(!UNDO){
+ if(mf&&mf.value){skip++;ledger.write(JSON.stringify({id:r.id,status:'already_set',live:mf.value})+'\n');continue;}
+ if(!APPLY){ok++;ledger.write(JSON.stringify({id:r.id,status:'DRYRUN',to:r.pat})+'\n');continue;}
+ const res=await gql(SET,{m:[{ownerId:r.id,namespace:'dwc',key:'pattern_name',type:'single_line_text_field',value:r.pat}]});
+ const ue=res?.data?.metafieldsSet?.userErrors||[];
+ if(ue.length){err++;ledger.write(JSON.stringify({id:r.id,status:'error',ue})+'\n');}
+ else{ok++;ledger.write(JSON.stringify({id:r.id,status:'APPLIED',to:r.pat})+'\n');}
+ }else{
+ // UNDO: only delete if the live value is exactly what we wrote (never touch a foreign value)
+ if(!mf){skip++;ledger.write(JSON.stringify({id:r.id,status:'already_absent'})+'\n');continue;}
+ if(mf.value!==r.pat){skip++;ledger.write(JSON.stringify({id:r.id,status:'drifted',live:mf.value,expected:r.pat})+'\n');continue;}
+ if(!APPLY){ok++;ledger.write(JSON.stringify({id:r.id,status:'DRYRUN_DELETE',value:mf.value})+'\n');continue;}
+ const res=await gql(DEL,{id:mf.id});
+ const ue=res?.data?.metafieldDelete?.userErrors||[];
+ if(ue.length){err++;ledger.write(JSON.stringify({id:r.id,status:'error',ue})+'\n');}
+ else{ok++;ledger.write(JSON.stringify({id:r.id,status:'DELETED'})+'\n');}
+ }
+ if(i%50===0)console.log(` ${i}/${work.length} ok=${ok} skip=${skip} err=${err}`);
+}
+console.log(`${UNDO?'UNDO':'FILL'} ${APPLY?'APPLIED':'DRY-RUN'}: ok=${ok} skipped=${skip} errors=${err} of ${work.length}`);
← d25e390 auto-data-snapshot: 2026-09-10T12:25:41 (1 data files) — dat
·
back to Dw Title Repair
·
(newest)