← back to Gmc Titlefix
TK-11844/11847: resolve bare-offer product status; guard destinationStatuses; harden vid fallback
7657c83bad3b05b7b2215443546282497d8e7385 · 2026-09-16 15:55:56 -0700 · Steve
- tk11844: build variantId->productId map so bare-numeric offers (offerId IS the
variant id) resolve their product; shopify_product_status was
"(bare-offer:unknown-pid)" for 7/27 rows. Re-run: all 27 now ACTIVE, and 2 of the
formerly-blind bare offers are SERVING on ACTIVE products (Sakka, Haiku). Removed
dead `sp` line that needlessly materialized pjProducts.entries() per hit.
- tk11847: guard p.destinationStatuses?.[0]?.status (empty array no longer throws
and silently drops the GMC read into parity_unknown); harden vid to fall back to
the numeric tail so prefixed offers without ?variant= still resolve.
Both scripts remain strictly read-only ($0, no Shopify/GMC writes).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TAwgQZWgKL5R6d5uLG3QUt
Files touched
M data/tk11844-pj-authoritative-join.jsonM tk11844-pj-authoritative-join.mjsA tk11847-verify-parity.mjs
Diff
commit 7657c83bad3b05b7b2215443546282497d8e7385
Author: Steve <steve@designerwallcoverings.com>
Date: Wed Sep 16 15:55:56 2026 -0700
TK-11844/11847: resolve bare-offer product status; guard destinationStatuses; harden vid fallback
- tk11844: build variantId->productId map so bare-numeric offers (offerId IS the
variant id) resolve their product; shopify_product_status was
"(bare-offer:unknown-pid)" for 7/27 rows. Re-run: all 27 now ACTIVE, and 2 of the
formerly-blind bare offers are SERVING on ACTIVE products (Sakka, Haiku). Removed
dead `sp` line that needlessly materialized pjProducts.entries() per hit.
- tk11847: guard p.destinationStatuses?.[0]?.status (empty array no longer throws
and silently drops the GMC read into parity_unknown); harden vid to fall back to
the numeric tail so prefixed offers without ?variant= still resolve.
Both scripts remain strictly read-only ($0, no Shopify/GMC writes).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TAwgQZWgKL5R6d5uLG3QUt
---
data/tk11844-pj-authoritative-join.json | 30 ++++++------
tk11844-pj-authoritative-join.mjs | 11 +++--
tk11847-verify-parity.mjs | 82 +++++++++++++++++++++++++++++++++
3 files changed, 104 insertions(+), 19 deletions(-)
diff --git a/data/tk11844-pj-authoritative-join.json b/data/tk11844-pj-authoritative-join.json
index af0ce9f..2c31625 100644
--- a/data/tk11844-pj-authoritative-join.json
+++ b/data/tk11844-pj-authoritative-join.json
@@ -1,7 +1,7 @@
{
"ticket": "TK-11844",
"read_only": true,
- "fetched_at": "2026-09-16T21:41:39.126Z",
+ "fetched_at": "2026-09-16T22:55:22.976Z",
"method": "authoritative Shopify vendor->id-set join on live GMC offers (both offerId forms)",
"walk_complete": true,
"total_offers_walked": 61992,
@@ -26,9 +26,9 @@
"title": "Sakka - White on Marshmallow Manila Hemp 11' Panel Height - Mural Repeat: 264\" (",
"brand": null,
"price": 5212.67,
- "shopify_productId": null,
+ "shopify_productId": "7375889825843",
"shopify_variantId": "44455859126323",
- "shopify_product_status": "(bare-offer:unknown-pid)",
+ "shopify_product_status": "ACTIVE",
"issues": [],
"link": "https://www.designerwallcoverings.com/products/dwjp-13182-philip-jeffries-sakka-white-on-marshmallow-manila-hemp-11-panel-height-mural-repeat-264-670-6-cm-h-9022"
},
@@ -42,9 +42,9 @@
"title": "Haiku - Red Rejuvination on Venetian Glass Glam Grass 11' Panel Height - Mural R",
"brand": null,
"price": 5212.67,
- "shopify_productId": null,
+ "shopify_productId": "7375889137715",
"shopify_variantId": "44455856701491",
- "shopify_product_status": "(bare-offer:unknown-pid)",
+ "shopify_product_status": "ACTIVE",
"issues": [],
"link": "https://www.designerwallcoverings.com/products/dwjp-13178-philip-jeffries-haiku-red-rejuvination-on-venetian-glass-glam-grass-11-panel-height-mural-repeat-264-670-6-cm-h-9020?variant=44455856701491"
},
@@ -390,9 +390,9 @@
"title": "",
"brand": null,
"price": 7,
- "shopify_productId": null,
+ "shopify_productId": "7375633416243",
"shopify_variantId": "42511636201523",
- "shopify_product_status": "(bare-offer:unknown-pid)",
+ "shopify_product_status": "ACTIVE",
"issues": [
"DISAPPROVED|item_missing_required_attribute"
],
@@ -408,9 +408,9 @@
"title": "",
"brand": null,
"price": 7,
- "shopify_productId": null,
+ "shopify_productId": "7375654158387",
"shopify_variantId": "42511667757107",
- "shopify_product_status": "(bare-offer:unknown-pid)",
+ "shopify_product_status": "ACTIVE",
"issues": [
"DISAPPROVED|item_missing_required_attribute"
],
@@ -426,9 +426,9 @@
"title": "",
"brand": null,
"price": 7,
- "shopify_productId": null,
+ "shopify_productId": "7375739027507",
"shopify_variantId": "42511905947699",
- "shopify_product_status": "(bare-offer:unknown-pid)",
+ "shopify_product_status": "ACTIVE",
"issues": [
"DISAPPROVED|item_missing_required_attribute"
],
@@ -444,9 +444,9 @@
"title": "",
"brand": null,
"price": 7,
- "shopify_productId": null,
+ "shopify_productId": "7375630401587",
"shopify_variantId": "42511624405043",
- "shopify_product_status": "(bare-offer:unknown-pid)",
+ "shopify_product_status": "ACTIVE",
"issues": [
"DISAPPROVED|item_missing_required_attribute"
],
@@ -462,9 +462,9 @@
"title": "Saint Germain Hemp II - Silver On White",
"brand": null,
"price": 4.25,
- "shopify_productId": null,
+ "shopify_productId": "7375727231027",
"shopify_variantId": "42511885860915",
- "shopify_product_status": "(bare-offer:unknown-pid)",
+ "shopify_product_status": "ACTIVE",
"issues": [
"DISAPPROVED|tobacco_policy_violation"
],
diff --git a/tk11844-pj-authoritative-join.mjs b/tk11844-pj-authoritative-join.mjs
index 5798486..32cde50 100644
--- a/tk11844-pj-authoritative-join.mjs
+++ b/tk11844-pj-authoritative-join.mjs
@@ -35,13 +35,14 @@ async function sgql(q,v){for(let a=0;a<6;a++){const r=await fetch(SURL,{method:'
console.error('[1/3] Shopify: enumerating vendor=Phillip Jeffries products+variants...');
const pjProductIds=new Set(), pjVariantIds=new Set();
const pjProducts=new Map(); // productId -> {title,handle,status}
+const pjVariantToProduct=new Map(); // variantId -> productId (so bare offers can resolve their product)
let after=null, ppages=0;
do{
const d=await sgql(`query($a:String){products(first:100,after:$a,query:"vendor:'Phillip Jeffries'"){pageInfo{hasNextPage endCursor} nodes{id title handle status variants(first:100){nodes{id}}}}}`,{a:after});
for(const p of d.products.nodes){
const pid=numTail(p.id); pjProductIds.add(pid);
pjProducts.set(pid,{title:p.title,handle:p.handle,status:p.status});
- for(const v of p.variants.nodes) pjVariantIds.add(numTail(v.id));
+ for(const v of p.variants.nodes){ const vid=numTail(v.id); pjVariantIds.add(vid); pjVariantToProduct.set(vid,pid); }
}
after=d.products.pageInfo.hasNextPage?d.products.pageInfo.endCursor:null; ppages++;
if(ppages%5===0) process.stderr.write(` p${ppages}(${pjProductIds.size})`);
@@ -79,7 +80,9 @@ try{
const approved=ds.filter(d=>(d.approvedCountries||[]).length>0).length;
const disapproved=ds.filter(d=>(d.disapprovedCountries||[]).length>0).length;
const textWouldMatch=isPJtext(a.brand)||isPJtext(a.title)||isPJtext((a.productTypes||[]).join(' '));
- const sp=pjProducts.get(productId)|| (variantId? [...pjProducts.entries()].length&&null : null);
+ // resolve the product even for bare offers, whose offerId is the variant id
+ const resolvedPid = productId || (variantId && pjVariantToProduct.get(variantId)) || null;
+ const sp = resolvedPid ? pjProducts.get(resolvedPid) : null;
hits.push({
offerId:p.offerId,
form: /^\d+$/.test(String(p.offerId))?'bare':'prefixed',
@@ -90,9 +93,9 @@ try{
title:(a.title||'').slice(0,80),
brand:a.brand||null,
price:money(a.price),
- shopify_productId:productId||null,
+ shopify_productId:resolvedPid,
shopify_variantId:variantId||null,
- shopify_product_status: productId&&pjProducts.get(productId)?pjProducts.get(productId).status:'(bare-offer:unknown-pid)',
+ shopify_product_status: sp?sp.status:'(unknown-pid)',
issues:[...new Set((ps.itemLevelIssues||[]).map(i=>`${i.severity}|${i.code}`))],
link:a.link||null,
});
diff --git a/tk11847-verify-parity.mjs b/tk11847-verify-parity.mjs
new file mode 100644
index 0000000..819860c
--- /dev/null
+++ b/tk11847-verify-parity.mjs
@@ -0,0 +1,82 @@
+// TK-11847 READ-ONLY re-verify + price-parity + second-cause probe for the 29
+// legal_restrictions (alcohol-classifier) false-positive offers. $0. No writes anywhere.
+// GMC reads via mc-read v1 (token API). Shopify landing via public products.json, paced 2.5s.
+import fs from 'fs';
+import { createRequire } from 'module';
+const require = createRequire(import.meta.url);
+const mc = require('./_mc-read-v1.js');
+
+const EV = JSON.parse(fs.readFileSync('/Users/macstudio3/Projects/gmc-titlefix/data/tk11449-policy-locate.json','utf8'));
+const rows = EV.rows.filter(r => r.issues.some(i => i.includes('legal_restrictions')));
+const UA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125 Safari/537.36';
+
+// colorway-drink false-positive lexicon (name-based)
+const DRINK = /\b(champagne|chardonnay|zinfandel|merlot|cabernet|prosecco|riesling|sauvignon|pinot|rosé|rose wine|sherry|brandy|whiskey|whisky|bourbon|tequila|vodka|absinthe|chianti|burgundy|bordeaux|sangria|mimosa|bellini|cognac)\b/i;
+
+const out = [];
+for (const r of rows) {
+ const u = new URL(r.link);
+ const handle = u.pathname.split('/').pop();
+ const vid = u.searchParams.get('variant') || String(r.offerId).match(/(\d+)$/)?.[1] || r.offerId;
+ const rec = { offerId: r.offerId, title: r.title, handle, vid,
+ ev_ctx_approved: r.ctx_approved, ev_ctx_disapproved: r.ctx_disapproved };
+
+ // --- GMC current status (READ-ONLY) ---
+ try {
+ const p = await mc.getProduct('online:en:US:' + r.offerId);
+ rec.advertised = p.price ? Number(p.price.value) : null;
+ rec.gmc_dest = p.destinationStatuses?.[0]?.status ?? null;
+ const dis = [...new Set(p.itemLevelIssues.filter(i=>i.servability==='disapproved').map(i=>i.code))];
+ const noimp = [...new Set(p.itemLevelIssues.filter(i=>i.servability==='not_impacted').map(i=>i.code))];
+ rec.disapproved_codes = dis;
+ rec.notimpacted_codes = noimp;
+ rec.still_legal_restrictions = dis.includes('legal_restrictions_policy_violation');
+ rec.other_disapprovals = dis.filter(c => c !== 'legal_restrictions_policy_violation');
+ // second-cause probe: title has no drink word => capture attributes that a classifier might read
+ rec.title_has_drink_word = DRINK.test(r.title);
+ if (!rec.title_has_drink_word) {
+ const a = (p._v1 && p._v1.productAttributes) || {};
+ rec.probe = {
+ productTypes: a.productTypes || null,
+ googleProductCategory: a.googleProductCategory || null,
+ description: (a.description||'').slice(0,240),
+ productDetails: a.productDetails ? a.productDetails.map(d=>`${d.attributeName}=${d.attributeValue}`).slice(0,12) : null,
+ customLabels: [a.customLabel0,a.customLabel1,a.customLabel2,a.customLabel3,a.customLabel4].filter(Boolean),
+ };
+ }
+ } catch(e) { rec.gmc_err = String(e).slice(0,120); }
+
+ // --- Shopify landing parity (READ-ONLY public feed) ---
+ try {
+ const res = await fetch(`https://www.designerwallcoverings.com/products/${handle}.json`,
+ { headers:{'User-Agent':UA}, signal:AbortSignal.timeout(30000) });
+ rec.http = res.status;
+ if (res.ok) {
+ const p = (await res.json()).product;
+ rec.published = !!p.published_at;
+ rec.variants = p.variants.length;
+ const v = p.variants.find(v=>String(v.id)===String(vid));
+ rec.landing_variant_found = !!v;
+ rec.landing_price = v ? Number(v.price) : null;
+ rec.parity = (v && rec.advertised!=null) ? (Math.abs(Number(v.price)-rec.advertised)<0.005) : null;
+ }
+ } catch(e) { rec.http = 'ERR '+String(e).slice(0,60); }
+
+ out.push(rec);
+ const drk = rec.title_has_drink_word ? 'DRINK' : 'NO-WORD';
+ console.log(`${rec.parity===true?'PAR-OK ':rec.parity===false?'PAR-BAD':'PAR-??'} ${rec.still_legal_restrictions?'LR':' '} ${drk.padEnd(7)} adv=${String(rec.advertised).padEnd(7)} land=${String(rec.landing_price).padEnd(7)} other=${(rec.other_disapprovals||[]).join(',')||'-'} ${rec.title}`);
+ await new Promise(z=>setTimeout(z, 2500));
+}
+
+const summary = {
+ total: out.length,
+ still_legal_restrictions: out.filter(r=>r.still_legal_restrictions).length,
+ parity_ok: out.filter(r=>r.parity===true).length,
+ parity_bad: out.filter(r=>r.parity===false).length,
+ parity_unknown: out.filter(r=>r.parity==null).length,
+ with_other_disapprovals: out.filter(r=>(r.other_disapprovals||[]).length).length,
+ no_drink_word: out.filter(r=>r.title_has_drink_word===false).length,
+};
+fs.writeFileSync('/Users/macstudio3/Projects/gmc-titlefix/data/tk11847-verify-parity.json',
+ JSON.stringify({ ticket:'TK-11847', read_only:true, fetched_at:new Date().toISOString(), merchant:mc.MERCHANT, summary, rows:out }, null, 1));
+console.log('\nSUMMARY', JSON.stringify(summary));
← e92df0c TK-11844: authoritative Shopify->GMC identity join for Phill
·
back to Gmc Titlefix
·
auto-data-snapshot: 2026-09-17T09:53:49 (2 data files) — dat 2378dcd →