← 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
M scripts/tk11673-june-titletag/.gitignoreA scripts/tk11673-june-titletag/verify-exhaustive.mjs
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 →