← back to Gmc Titlefix
step-e-verify-all.js
52 lines
// STEP 2 — READ-ONLY full verify. Pages the entire live Content feed once, then
// confirms each of the 29,672 risky offers now has an effective title starting "Sample:".
// Writes /tmp/gmc-verify-result.json + a human summary. Safe to re-run anytime.
const {token,MERCHANT}=require('./_auth');
const fs=require('fs');
const list=require('./gmc_titlefix_list.json');
const risky=new Map(list.map(r=>[r.offerId,r])); // offerId -> row
const vendorOf=row=>{ const t=row.currentTitle||''; const m=t.match(/(?:by|\|)\s*([^|]+?)\s*$/); return (m&&m[1].trim())||'(unknown)'; };
(async()=>{
let tok=await token(), tokAt=Date.now();
const title=new Map(); // offerId -> effective title (only for risky offers)
let page=0, pageToken=undefined, scanned=0;
do{
if(Date.now()-tokAt>50*60*1000){ tok=await token(); tokAt=Date.now(); }
const u=new URL(`https://shoppingcontent.googleapis.com/content/v2.1/${MERCHANT}/products`);
u.searchParams.set('maxResults','250'); if(pageToken) u.searchParams.set('pageToken',pageToken);
let r,j,tries=0;
do{ r=await fetch(u,{headers:{Authorization:'Bearer '+tok}}); j=await r.json();
if(r.status>=500){ tries++; await new Promise(s=>setTimeout(s,2000)); } else break; }while(tries<4);
if(!r.ok){ console.error('feed page',page,'HTTP',r.status,JSON.stringify(j).slice(0,200)); break; }
for(const p of (j.resources||[])){ scanned++; if(risky.has(p.offerId)) title.set(p.offerId, p.title||''); }
pageToken=j.nextPageToken; page++;
if(page%25===0) console.log(` paged ${page} | scanned ${scanned} | matched ${title.size}/${risky.size}`);
}while(pageToken);
let flipped=0, notyet=0, missing=0;
const notFlipped=[], byVendorNot={}, notFlippedAll=[];
for(const [offerId,row] of risky){
if(!title.has(offerId)){ missing++; continue; } // gone from feed → never retry (ghost)
if(/^Sample:/.test(title.get(offerId))) flipped++;
else { notyet++; notFlippedAll.push(offerId); const v=vendorOf(row); byVendorNot[v]=(byVendorNot[v]||0)+1;
if(notFlipped.length<25) notFlipped.push({offerId, title:title.get(offerId).slice(0,80)}); }
}
// Full not-flipped offerId list (present-in-feed only) — drives the bounded retry (step-f). DTD-unanimous 2026-06-18.
fs.writeFileSync('/tmp/gmc-notflipped.json', JSON.stringify(notFlippedAll));
const result={ ts:new Date().toISOString(), totalRisky:risky.size, feedOffersScanned:scanned,
flipped, notyet, missingFromFeed:missing,
flipRatePct:+(100*flipped/risky.size).toFixed(2),
byVendorNotFlipped:Object.fromEntries(Object.entries(byVendorNot).sort((a,b)=>b[1]-a[1]).slice(0,15)),
sampleNotFlipped:notFlipped };
fs.writeFileSync('/tmp/gmc-verify-result.json', JSON.stringify(result,null,2));
console.log('\n===== STEP-2 VERIFY =====');
console.log(`flipped: ${flipped}/${risky.size} (${result.flipRatePct}%)`);
console.log(`not yet: ${notyet}`);
console.log(`missing from feed (deleted/archived since list built): ${missing}`);
if(notyet){ console.log('top vendors still unflipped:', JSON.stringify(result.byVendorNotFlipped)); }
const verdict = (flipped===risky.size) ? 'PASS' : (flipped+missing===risky.size) ? 'PASS* (all live offers flipped; rest gone from feed)' : 'PARTIAL';
console.log('VERDICT:', verdict);
fs.writeFileSync('/tmp/gmc-verify-verdict.txt', verdict);
})().catch(e=>{ console.error('ERR',e.message); process.exit(1); });