← back to Dw Gemini Skip TK11321

scripts/verify-owner-skip-independent.js

93 lines

#!/usr/bin/env node
'use strict';
// Independent read-only API/storefront verifier. No activation-module imports.
const fs = require('node:fs');
const path = require('node:path');
const os = require('node:os');
const assert = require('node:assert/strict');
const [phase, expectedArg] = process.argv.slice(2);
if (!['before', 'after'].includes(phase)) throw new Error('Usage: verifier before | after <cumulative new count>');
const evidence = path.resolve('verification/tk11321');
const production = path.join(os.homedir(), 'Projects/dw-rotation-activator');
const day = new Date().toISOString().slice(0, 10);
const auditPath = path.join(production, `out/rotation-activations-${day}.jsonl`);
const ledgerPath = path.join(production, `out/activation-ledger-${day}.json`);
const env = fs.readFileSync(path.join(os.homedir(), 'Projects/secrets-manager/.env'), 'utf8');
const token = (env.match(/^SHOPIFY_ADMIN_TOKEN=(.*)$/m) || [])[1]?.trim().replace(/^['"]|['"]$/g, '');
const policy = JSON.parse(fs.readFileSync('config/gemini-review-policy.json'));
const blocked = new Set(policy.historical_blocked_ids);
const candidates = fs.readFileSync(`out/rotation-activations-${day}.jsonl`, 'utf8').trim().split('\n').map(JSON.parse);
const predicted = candidates.filter(r => r.action === 'dryrun-would-activate').map(r => r.shopify_id);
assert.equal(predicted.length, 21); assert.equal(new Set(predicted).size, 21);
const negativeIds = [...new Set(candidates.filter(r => r.action === 'settlement-block' || r.action === 'skip-gate').map(r => r.shopify_id))].filter(id => !predicted.includes(id));
const controls = [...new Set([...negativeIds.filter(id => blocked.has(id)), ...negativeIds.filter(id => !blocked.has(id)).slice(0, 2)])];
const query = `query($ids:[ID!]!){nodes(ids:$ids){... on Product{
 id title vendor status handle tags images(first:1){nodes{url}}
 variants(first:100){nodes{id sku title price} pageInfo{hasNextPage}}
 review:metafield(namespace:"internal",key:"settlement_hold"){value}
 googlePublished:publishedOnPublication(publicationId:"gid://shopify/Publication/29646651457")
 resourcePublicationsV2(first:50){nodes{isPublished publication{id name}} pageInfo{hasNextPage}}
}}}`;
async function readProducts(ids) {
 const products = [];
 for (let i=0; i<ids.length; i+=40) {
  const response = await fetch('https://designer-laboratory-sandbox.myshopify.com/admin/api/2026-07/graphql.json', {
   method:'POST', headers:{'Content-Type':'application/json','X-Shopify-Access-Token':token},
   body:JSON.stringify({query,variables:{ids:ids.slice(i,i+40)}}), signal:AbortSignal.timeout(30000),
  });
  const result=await response.json();
  assert.equal(response.status,200); assert.equal(result.errors,undefined,JSON.stringify(result.errors));
  assert.equal(result.data.nodes.length,ids.slice(i,i+40).length);
  assert.ok(result.data.nodes.every(Boolean)); products.push(...result.data.nodes);
 }
 return products;
}
async function main() {
 if (phase==='before') {
  const products=await readProducts([...predicted,...controls]);
  assert.ok(products.every(p=>p.status==='DRAFT'));
  assert.ok(products.every(p=>!p.variants.pageInfo.hasNextPage && !p.resourcePublicationsV2.pageInfo.hasNextPage));
  const report={timestamp:new Date().toISOString(),mutations:0,predicted,controls,products,
   ledger:JSON.parse(fs.readFileSync(ledgerPath)),audit_offset:fs.statSync(auditPath).size,audit_path:auditPath};
  fs.writeFileSync(path.join(evidence,'live-before.json'),JSON.stringify(report,null,2)+'\n');
  console.log(JSON.stringify({phase,products:products.length,candidates:predicted.length,controls:controls.length,ledger:report.ledger,first:products[0].title}));
  return;
 }
 const expected=Number(expectedArg); assert.ok([1,21].includes(expected));
 const before=JSON.parse(fs.readFileSync(path.join(evidence,'live-before.json')));
 const rows=fs.readFileSync(auditPath).subarray(before.audit_offset).toString().trim().split('\n').filter(Boolean).map(JSON.parse);
 const activated=rows.filter(r=>r.action==='activated');
 assert.equal(activated.length,expected);
 assert.equal(new Set(activated.map(r=>r.shopify_id)).size,expected);
 assert.ok(activated.every(r=>predicted.includes(r.shopify_id) && !blocked.has(r.shopify_id)));
 assert.ok(activated.every(r=>r.passes===true && r.published===true && r.settlement.verdict==='SKIPPED_BY_OWNER' && r.settlement.review_performed===false && r.settlement.authorization.ticket==='TK-11321' && r.settlement.cost===0));
 const ids=[...activated.map(r=>r.shopify_id),...controls];
 const products=await readProducts(ids);
 const old=new Map(before.products.map(p=>[p.id,p]));
 for (const product of products) {
  if (controls.includes(product.id)) { assert.equal(product.status,'DRAFT','Negative control was published'); continue; }
  assert.equal(product.status,'ACTIVE'); assert.ok(product.tags.includes('New Arrival'));
  assert.equal(product.googlePublished,false);
  assert.deepEqual(product.variants,old.get(product.id).variants,'Variant or price changed');
  assert.deepEqual(product.images,old.get(product.id).images,'Primary image changed');
  assert.equal(product.title,old.get(product.id).title); assert.equal(product.vendor,old.get(product.id).vendor);
  assert.ok(product.resourcePublicationsV2.nodes.some(p=>p.isPublished && p.publication.name==='Online Store'));
  const review=JSON.parse(product.review.value);
  assert.equal(review.verdict,'SKIPPED_BY_OWNER'); assert.equal(review.reason,'owner-authorized-no-gemini:TK-11321');
 }
 const ledger=JSON.parse(fs.readFileSync(ledgerPath)); assert.equal(ledger.used,before.ledger.used+expected);
 const storefront=[];
 for (const product of [products[0],...(expected>1?[products[expected-1]]:[])]) {
  const url=`https://www.designerwallcoverings.com/products/${product.handle}`;
  const response=await fetch(url,{signal:AbortSignal.timeout(30000)}); const html=await response.text();
  assert.equal(response.status,200); assert.ok(html.includes(product.id.split('/').pop()));
  storefront.push({url,status:200,product_id_found:true});
 }
 const report={timestamp:new Date().toISOString(),verdict:'PASS',mutations:0,newly_activated:expected,
  ledger_before:before.ledger,ledger_after:ledger,controls_still_draft:controls.length,activated,products,storefront,
  independent_verifier:'Separate read-only Admin API2026-07 and public PDP reads; no activation imports'};
 fs.writeFileSync(path.join(evidence,`live-verified-${expected}.json`),JSON.stringify(report,null,2)+'\n');
 console.log(JSON.stringify({verdict:report.verdict,newly_activated:expected,ledger,controls_still_draft:controls.length,storefront}));
}
main().catch(error=>{console.error(error.message);process.exitCode=1;});