← back to Dw Activation Debug TK11314

scripts/verify-scheduled-run.js

74 lines

#!/usr/bin/env node
'use strict';
// Read-only verification of the first natural hourly tick after the canary.
// Independent fresh API/PDP reads; no activation modules or Shopify mutations.
const fs = require('node:fs');
const path = require('node:path');
const os = require('node:os');
const assert = require('node:assert/strict');
const evidence = path.resolve('verification/rollout');
const before = JSON.parse(fs.readFileSync(path.join(evidence, 'canary-before.json')));
const canary = JSON.parse(fs.readFileSync(path.join(evidence, 'canary-verified.json')));
const snapshot = JSON.parse(fs.readFileSync('verification/live-products-20260909.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 root = path.join(os.homedir(), 'Projects/dw-rotation-activator');
async function main() {
  const lines = fs.readFileSync(before.audit_path).subarray(before.audit_offset).toString().trim();
  const rows = lines ? lines.split('\n').map(JSON.parse) : [];
  const allActivated = rows.filter(r => r.action === 'activated');
  const activated = allActivated.filter(r => r.ts > canary.timestamp);
  const log = fs.readFileSync(path.join(root, 'drain.log'), 'utf8');
  const runLog = log.slice(log.lastIndexOf('rotation-activate start slot_max=21'));
  assert.match(runLog, /rotation-activate end rc=0/, 'Natural hourly run has not finished successfully');
  const completed = runLog.match(/scanned=(\d+)\s+activated=(\d+)\s+published=(\d+)/);
  assert.ok(completed, 'Missing completed-run summary');
  assert.equal(activated.length, Number(completed[2]), 'Audit and completed-run count disagree');
  assert.equal(activated.length, Number(completed[3]), 'Not every activation was published');
  assert.ok(activated.length > 0 && activated.length <= 21, 'Activation count outside slot allowance');
  assert.equal(new Set(allActivated.map(r => r.shopify_id)).size, allActivated.length, 'Duplicate activation');
  const ids = activated.map(r => r.shopify_id);
  const baselineIds = new Set(snapshot.products.filter(p => p.status === 'DRAFT').map(p => p.id));
  assert.ok(ids.every(id => baselineIds.has(id)), 'Missing DRAFT baseline');
  assert.ok(activated.every(r => r.passes === true && r.settlement?.verdict === 'PASS' && r.published === true));
  const query = `query($ids:[ID!]!){nodes(ids:$ids){... on Product{
    id title handle status tags googlePublished:publishedOnPublication(publicationId:"gid://shopify/Publication/29646651457")
    resourcePublicationsV2(first:50){nodes{isPublished publication{name}} pageInfo{hasNextPage}}
  }}}`;
  const response = await fetch('https://designer-laboratory-sandbox.myshopify.com/admin/api/2026-07/graphql.json', {
    method: 'POST', headers: { 'X-Shopify-Access-Token': token, 'Content-Type': 'application/json' },
    body: JSON.stringify({ query, variables: { ids } }), signal: AbortSignal.timeout(30000),
  });
  const json = await response.json();
  assert.equal(response.status, 200); assert.equal(json.errors, undefined, JSON.stringify(json.errors));
  assert.equal(json.data.nodes.length, ids.length);
  for (const product of json.data.nodes) {
    assert.ok(product && ids.includes(product.id));
    assert.equal(product.status, 'ACTIVE');
    assert.ok(product.tags.includes('New Arrival'));
    assert.equal(product.googlePublished, false);
    assert.equal(product.resourcePublicationsV2.pageInfo.hasNextPage, false);
    assert.ok(product.resourcePublicationsV2.nodes.some(p => p.isPublished && p.publication.name === 'Online Store'));
  }
  const ledger = JSON.parse(fs.readFileSync(path.join(root, `out/activation-ledger-${before.ledger.date}.json`)));
  assert.equal(ledger.used, before.ledger.used + allActivated.length);
  assert.ok(ledger.used <= 500);
  const storefront = [];
  for (const product of [json.data.nodes[0], json.data.nodes.at(-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: response.status, product_id_found: true });
  }
  const report = { timestamp: new Date().toISOString(), verdict: 'PASS', mutations: 0,
    scheduled_activated: activated.length, daily_ledger: ledger, rows_read: rows.length,
    scanned: Number(completed[1]), slot_max: 21, completed_run_log: runLog,
    activations: activated, products: json.data.nodes, storefront,
    independent_verifier: 'Separate Admin API and public storefront reads, no activation imports' };
  fs.writeFileSync(path.join(evidence, 'scheduled-run-verified.json'), JSON.stringify(report, null, 2)+'\n');
  console.log(JSON.stringify({ verdict: report.verdict, scheduled_activated: activated.length, ledger, storefront }));
}
main().catch(error => { console.error(error.message); process.exitCode = 1; });