[object Object]

← 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

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)