[object Object]

← back to Designerwallcoverings

TK-11673: exhaustive post-apply verification (read-only) — replaces the 40-row sample

eafc12ec970630232863de8816e84fa7465059e3 · 2026-09-16 16:14:12 -0700 · Steve Abrams

The apply was verified with a random 40-row live sample = 0.5% of 8,369 live product
titles, which cannot distinguish a full apply from a partial one. This measures the
whole population, and adds the assertion nobody made: that the 5,787 over60_only rows
Steve explicitly HELD were not touched, proving apply.mjs respected --scope=defect.

Result: APPLIED 8,369/8,369 as expected, HELD 5,787/5,787 untouched, 0 corrector misses.
One residual (dwsa-305801-1) is an UPSTREAM defect in the product title itself
("Do the Can CanWallcovering Retro" glues the word, so collapseDupWc correctly declined
to touch it) — attributed, not blamed, so it reports WARN rather than a false FAIL.

Carries the TK-11574 provenance guard: fails hard if it attaches to a bulk op another
session started.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Files touched

Diff

commit eafc12ec970630232863de8816e84fa7465059e3
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Sep 16 16:14:12 2026 -0700

    TK-11673: exhaustive post-apply verification (read-only) — replaces the 40-row sample
    
    The apply was verified with a random 40-row live sample = 0.5% of 8,369 live product
    titles, which cannot distinguish a full apply from a partial one. This measures the
    whole population, and adds the assertion nobody made: that the 5,787 over60_only rows
    Steve explicitly HELD were not touched, proving apply.mjs respected --scope=defect.
    
    Result: APPLIED 8,369/8,369 as expected, HELD 5,787/5,787 untouched, 0 corrector misses.
    One residual (dwsa-305801-1) is an UPSTREAM defect in the product title itself
    ("Do the Can CanWallcovering Retro" glues the word, so collapseDupWc correctly declined
    to touch it) — attributed, not blamed, so it reports WARN rather than a false FAIL.
    
    Carries the TK-11574 provenance guard: fails hard if it attaches to a bulk op another
    session started.
    
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---
 scripts/tk11673-june-titletag/.gitignore           |   1 +
 .../tk11673-june-titletag/verify-exhaustive.mjs    | 113 +++++++++++++++++++++
 2 files changed, 114 insertions(+)

diff --git a/scripts/tk11673-june-titletag/.gitignore b/scripts/tk11673-june-titletag/.gitignore
index cec189c..fd42001 100644
--- a/scripts/tk11673-june-titletag/.gitignore
+++ b/scripts/tk11673-june-titletag/.gitignore
@@ -1 +1,2 @@
 map.json
+verify-raw.jsonl
diff --git a/scripts/tk11673-june-titletag/verify-exhaustive.mjs b/scripts/tk11673-june-titletag/verify-exhaustive.mjs
new file mode 100644
index 0000000..e3b93ae
--- /dev/null
+++ b/scripts/tk11673-june-titletag/verify-exhaustive.mjs
@@ -0,0 +1,113 @@
+// TK-11673 EXHAUSTIVE post-apply verification. READ-ONLY, $0.
+// The apply was verified with a random 40-row live sample = 0.5% of 8,369 live product
+// titles. A sample that size cannot distinguish "all 8,369 landed" from "most landed and
+// a slice silently didn't" — the population-vs-sample false-green. This measures ALL of it.
+//
+// TWO independent assertions, because the apply had a SCOPE as well as a target:
+//   1. APPLIED  (bucket defect|whitespace, n=8,369) -> live title_tag MUST equal new_title_tag
+//   2. HELD     (bucket over60_only,      n=5,787) -> live title_tag MUST still equal
+//      old_title_tag. This is the one nobody checked: it proves apply.mjs did NOT exceed
+//      its --scope=defect and quietly rewrite the rows Steve explicitly held back.
+// A row whose live value matches NEITHER is NOT-MEASURED, never silently passed.
+import { gql } from '../lib/shopify.mjs';
+import fs from 'node:fs';
+
+const DIR = '/Users/macstudio3/Projects/designerwallcoverings/scripts/tk11673-june-titletag';
+const RAW = `${DIR}/verify-raw.jsonl`;
+const BULK_QUERY = `{
+  products { edges { node {
+    id handle status
+    metafield(namespace:"global", key:"title_tag") { value updatedAt }
+  } } }
+}`;
+
+async function startBulk(){
+  const d = await gql(`mutation { bulkOperationRunQuery(query: ${JSON.stringify(BULK_QUERY)}) {
+    bulkOperation { id status } userErrors { field message } } }`);
+  if (d.__err) { console.error('GraphQL error', JSON.stringify(d.__err)); process.exit(1); }
+  const ue = d.bulkOperationRunQuery.userErrors;
+  if (ue.length) { console.error('userErrors', ue); process.exit(1); }
+  return d.bulkOperationRunQuery.bulkOperation.id;
+}
+async function poll(startedId){
+  for(;;){
+    const d = await gql(`{ currentBulkOperation(type: QUERY) { id status errorCode objectCount url } }`);
+    if (d.__err) { console.error('\nGraphQL error', JSON.stringify(d.__err)); process.exit(1); }
+    const b = d.currentBulkOperation;
+    process.stderr.write(`\r  bulk ${b.status} objs=${b.objectCount}   `);
+    if (b.status==='COMPLETED'){
+      // PROVENANCE GUARD (the TK-11574 lesson): never trust an op another session started.
+      if (startedId && b.id !== startedId){ console.error(`\nPROVENANCE FAIL: attached to ${b.id}, started ${startedId}`); process.exit(2); }
+      process.stderr.write('\n'); return b;
+    }
+    if (['FAILED','CANCELED'].includes(b.status)){ console.error('\nbulk',b); process.exit(1); }
+    await new Promise(r=>setTimeout(r,3000));
+  }
+}
+
+let jsonl;
+if (process.env.USE_CACHE==='1' && fs.existsSync(RAW)) { console.error('using cached',RAW); jsonl=fs.readFileSync(RAW,'utf8'); }
+else {
+  console.error('starting POST-APPLY title_tag bulk export ...');
+  const id = await startBulk(); const done = await poll(id);
+  if(!done.url){ console.error('no results url'); process.exit(1); }
+  jsonl = await (await fetch(done.url)).text();
+  fs.writeFileSync(RAW, jsonl); console.error('cached ->', RAW);
+}
+
+const live = new Map();
+for (const line of jsonl.split('\n')){
+  if(!line) continue; let n; try{ n=JSON.parse(line);}catch{continue;}
+  if(!n.id || !n.id.includes('/Product/')) continue;
+  live.set(n.handle, { status:n.status, tag:(n.metafield?.value ?? null) });
+}
+
+const map = JSON.parse(fs.readFileSync(`${DIR}/map.json`,'utf8'));
+const rows = Array.isArray(map) ? map : (map.rows||[]);
+const norm = s => (s??'').replace(/\s+/g,' ').trim();
+
+const res = {};
+for (const [label, pred] of [['APPLIED', r=>r.bucket==='defect'||r.bucket==='whitespace'],
+                             ['HELD',    r=>r.bucket==='over60_only']]){
+  const set = rows.filter(pred);
+  let matchExpected=0, matchOther=0, notMeasured=0, absent=0;
+  const problems=[];
+  for(const r of set){
+    const L = live.get(r.handle);
+    if(!L){ absent++; problems.push({handle:r.handle,why:'product-not-in-catalog'}); continue; }
+    if(L.tag===null){ notMeasured++; problems.push({handle:r.handle,why:'title_tag now ABSENT (neither old nor new)'}); continue; }
+    const cur=norm(L.tag), oldv=norm(r.old_title_tag), newv=norm(r.new_title_tag);
+    const expected = label==='APPLIED' ? newv : oldv;
+    const other    = label==='APPLIED' ? oldv : newv;
+    if(cur===expected) matchExpected++;
+    else if(cur===other){ matchOther++; problems.push({handle:r.handle,why:label==='APPLIED'?'STILL OLD — apply did not land':'REWRITTEN — apply exceeded its scope onto a HELD row',cur:cur.slice(0,70)}); }
+    else { notMeasured++; problems.push({handle:r.handle,why:'value matches neither old nor new (changed since by something else)',cur:cur.slice(0,70)}); }
+  }
+  res[label]={population:set.length, as_expected:matchExpected, wrong_state:matchOther, not_measured:notMeasured, absent, problems:problems.slice(0,10)};
+}
+
+// Residual defect signatures across the APPLIED set, checked INDEPENDENTLY of the map.
+// Deliberately laxer than the corrector's own DUP_RE (no \b) so a doubling the corrector
+// could not see still surfaces. But a hit is then ATTRIBUTED, not blamed: if the product's
+// own title glues the word (e.g. "Do the Can CanWallcovering Retro" -> "CanWallcovering
+// Wallcovering"), there is no word boundary, collapseDupWc correctly declines to touch it,
+// and the defect is UPSTREAM in the product title — not an apply failure. Calling that a
+// FAIL would be a false RED, the mirror of the false green this script exists to prevent.
+const DUP_LAX=/Wallcovering\s+Wallcovering/i, DUP_STRICT=/\b(wallcoverings?)\s+(wallcoverings?)\b/i;
+let correctorMiss=0, sourceTitleDefect=0; const residRows=[];
+for(const r of rows.filter(r=>r.bucket==='defect'||r.bucket==='whitespace')){
+  const L=live.get(r.handle); if(!L||L.tag==null) continue;
+  const dup=DUP_LAX.test(L.tag), ell=/\.\.\.\s*$/.test(L.tag.trim());
+  if(!dup && !ell) continue;
+  const upstream = dup && !DUP_STRICT.test(L.tag);   // glued in the source title
+  if(upstream) sourceTitleDefect++; else correctorMiss++;
+  residRows.push({handle:r.handle,vendor:r.vendor,product_title:r.title,live_title_tag:L.tag,
+    kind: upstream?'upstream-source-title-glued (corrector correctly declined)':'corrector-miss'});
+}
+res.residual = {corrector_miss:correctorMiss, upstream_source_title_defect:sourceTitleDefect, rows:residRows};
+
+const bad = res.APPLIED.wrong_state + res.HELD.wrong_state + correctorMiss;
+const unmeasured = sourceTitleDefect + res.APPLIED.not_measured + res.HELD.not_measured + res.APPLIED.absent + res.HELD.absent;
+res.verdict = bad>0 ? 'FAIL' : (unmeasured>0 ? 'WARN' : 'PASS');
+res.note = 'APPLIED must equal new_title_tag; HELD must still equal old_title_tag (proves apply respected --scope=defect). Anything matching neither is NOT-MEASURED, never a silent pass.';
+console.log(JSON.stringify(res,null,2));

← 869dbfb auto-data-snapshot: 2026-09-16T15:43:40 (1 data files) — dat  ·  back to Designerwallcoverings  ·  TK-11758: gate snapshot write to --apply only; --undo reads 7a1a14c →