← back to Dw Settlement Audit
settlement audit: gate faithfulness fix — verbatim binding vault text, 5-detector + JS combinator, NEEDS_REVIEW + audit-trail SHA stamp
c88735e553da4fff575ed4ba289fc2d2966e813b · 2026-05-18 20:40:43 -0700 · SteveStudio2
Files touched
D progress2.txtD report.htmlM report.jsD report.mdD verdicts.jsonlM verify-candidates.js
Diff
commit c88735e553da4fff575ed4ba289fc2d2966e813b
Author: SteveStudio2 <steve@designerwallcoverings.com>
Date: Mon May 18 20:40:43 2026 -0700
settlement audit: gate faithfulness fix — verbatim binding vault text, 5-detector + JS combinator, NEEDS_REVIEW + audit-trail SHA stamp
---
progress2.txt | 1 -
report.html | 39 ----------------
report.js | 65 ++++++++++++++++++---------
report.md | 33 --------------
verdicts.jsonl | 23 ----------
verify-candidates.js | 122 +++++++++++++++++++++++++++++++++++----------------
6 files changed, 127 insertions(+), 156 deletions(-)
diff --git a/progress2.txt b/progress2.txt
deleted file mode 100644
index fa7bd72..0000000
--- a/progress2.txt
+++ /dev/null
@@ -1 +0,0 @@
-verified 20/3434 (of 3434 total) | PROHIBITED 2 | BORDERLINE 0 | ERROR 0 | 2026-05-19T03:08:51.395Z
diff --git a/report.html b/report.html
deleted file mode 100644
index 3b74960..0000000
--- a/report.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<!doctype html><meta charset=utf-8><title>DW Settlement Audit</title>
-<style>
-body{font:15px/1.5 -apple-system,system-ui,sans-serif;background:#faf8f4;color:#1a1710;margin:0;padding:32px}
-h1{margin:0 0 4px}.summary{color:#555;margin-bottom:24px}
-.summary b{color:#b3261e}
-.card{display:flex;gap:16px;background:#fff;border-radius:8px;padding:14px;margin-bottom:14px;box-shadow:0 1px 4px #0001}
-.card img{width:160px;height:160px;object-fit:cover;object-position:center 12%;border-radius:6px;flex:none}
-.noimg{width:160px;height:160px;background:#eee;display:flex;align-items:center;justify-content:center;color:#999;border-radius:6px;flex:none}
-.meta{flex:1;min-width:0}.meta h3{margin:4px 0}
-.badge{color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:4px}
-.sub{color:#777;font-size:13px;margin:2px 0}.gate{font-size:13px;margin:4px 0}
-.reason{font-style:italic;color:#444;margin:4px 0}
-a{color:#0b6}
-</style>
-<h1>DW Settlement Audit — Verdict Report</h1>
-<p class="summary">Generated 2026-05-19T03:09:09.870Z · 23 verified ·
-<b>2 PROHIBITED</b> · 0 BORDERLINE ·
-21 PERMITTED · 0 errors.
-Report-only — no product changed.</p>
-<div class="card" style="border-left:5px solid #b3261e">
- <img src="https://cdn.shopify.com/s/files/1/0015/4117/7456/files/119_5026_CS_adf49c63-9746-4d3a-a08f-a309c13aaabd.jpg?v=1753304804" loading="lazy">
- <div class="meta">
- <span class="badge" style="background:#b3261e">PROHIBITED</span>
- <h3>Afrika Kingdom - Olgreen & Spgreen/Cream Green | Cole & Son Ardmore-Jabula | Novelty Wallcovering</h3>
- <p class="sub">ID 7421498490931 · active · published · keyword: palm</p>
- <p class="gate">Part A: <b>true</b> (a1 true / a2 true / a3 true) · Part B: <b>true</b> · Birds</p>
- <p class="reason">Part A is satisfied by repeating foliage, open space, and multiple colors. Part B is satisfied by the presence of birds.</p>
- <a href="https://admin.shopify.com/store/designer-laboratory-sandbox/products/7421498490931" target="_blank">Open in Shopify admin →</a>
- </div></div>
-<div class="card" style="border-left:5px solid #b3261e">
- <img src="https://cdn.shopify.com/s/files/1/0015/4117/7456/files/119_5027_CS_0d775841-54b1-4b05-a798-343e3662f7ad.jpg?v=1753304801" loading="lazy">
- <div class="meta">
- <span class="badge" style="background:#b3261e">PROHIBITED</span>
- <h3>Afrika Kingdom - Olvgrn&Spgrn/Bck Multi | Cole & Son Ardmore-Jabula | Novelty Wallcovering</h3>
- <p class="sub">ID 7421498589235 · active · published · keyword: palm</p>
- <p class="gate">Part A: <b>true</b> (a1 true / a2 true / a3 true) · Part B: <b>true</b> · Birds</p>
- <p class="reason">Part A is satisfied by repeating foliage, negative space, and multiple colors. Part B is satisfied by the presence of birds.</p>
- <a href="https://admin.shopify.com/store/designer-laboratory-sandbox/products/7421498589235" target="_blank">Open in Shopify admin →</a>
- </div></div>
\ No newline at end of file
diff --git a/report.js b/report.js
index 9b98070..2294602 100644
--- a/report.js
+++ b/report.js
@@ -2,10 +2,11 @@
/* DW settlement audit — report generator.
*
* Reads verdicts.jsonl and produces:
- * - report.md : human-readable sign-off report, PROHIBITED + BORDERLINE first
+ * - report.md : human-readable sign-off report, PROHIBITED + NEEDS_REVIEW first
* - report.html : same, with thumbnails + Shopify admin deep-links
*
- * Report-only. Nothing is unpublished or deleted — that is Steve's call after review.
+ * Report-only. This is a SCREENING TRIAGE, not a legal adjudication. Nothing is
+ * unpublished or deleted — that is Steve's call after review.
*
* node report.js
*/
@@ -21,9 +22,12 @@ const lines = (() => {
})();
const recs = lines.map(l => { try { return JSON.parse(l); } catch { return null; } }).filter(Boolean);
+let manifest = {};
+try { manifest = JSON.parse(fs.readFileSync('run-manifest.json', 'utf8')); } catch {}
+
const by = v => recs.filter(r => r.verdict === v);
const prohibited = by('PROHIBITED');
-const borderline = by('BORDERLINE');
+const needsReview = by('NEEDS_REVIEW');
const permitted = by('PERMITTED');
const noImage = by('NO_IMAGE');
const errors = by('ERROR');
@@ -34,17 +38,30 @@ const esc = s => String(s == null ? '' : s)
.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
.replace(/"/g, '"');
+const DISCLAIMER = [
+ '**This is a screening triage, not a legal adjudication.** Verdicts come from Gemini',
+ 'vision against the verbatim settlement binding text — they flag candidates for human',
+ 'review, they do not decide settlement compliance.',
+ '',
+ '- **NEEDS REVIEW items are currently PERMITTED** under the settlement until a human',
+ ' re-evaluates them. The settlement has two legal states (PROHIBITED / PERMITTED);',
+ ' NEEDS REVIEW is a review-queue bucket, not a third legal state.',
+ '- **Primary image only.** Only each product\'s first image was checked. Multi-image',
+ ' products (see `images: N`) may hide a Part B element in image 2+ — re-check by hand.',
+ '- **Report-only.** No product has been unpublished, edited, or deleted.',
+].join('\n');
+
// ---- markdown ----
let md = `# DW Settlement Audit — Verdict Report\n\n`;
-md += `Generated ${new Date().toISOString()} · ${recs.length} candidates verified\n\n`;
-md += `| Verdict | Count |\n|---|---|\n`;
+md += `Generated ${new Date().toISOString()} · ${recs.length} candidates verified\n`;
+if (manifest.bindingSha256) md += `Binding vault SHA256: \`${manifest.bindingSha256}\`\n`;
+md += `\n| Verdict | Count |\n|---|---|\n`;
md += `| 🔴 PROHIBITED | ${prohibited.length} |\n`;
-md += `| 🟡 BORDERLINE | ${borderline.length} |\n`;
+md += `| 🟡 NEEDS REVIEW | ${needsReview.length} |\n`;
md += `| 🟢 PERMITTED | ${permitted.length} |\n`;
md += `| ⚪ NO_IMAGE | ${noImage.length} |\n`;
md += `| ⚠️ ERROR | ${errors.length} |\n\n`;
-md += `**Report-only — no product has been changed.** Review the PROHIBITED and BORDERLINE\n`;
-md += `lists below; unpublish/edit decisions are yours.\n\n`;
+md += DISCLAIMER + `\n\n`;
function mdSection(title, arr) {
if (!arr.length) return '';
@@ -52,8 +69,9 @@ function mdSection(title, arr) {
for (const r of arr) {
s += `### ${r.title || r.handle}\n`;
s += `- Product ID: \`${r.id}\` · handle: \`${r.handle}\` · status: ${r.status}, published: ${r.published}\n`;
- s += `- Part A: ${r.partA} (a1=${r.a1} a2=${r.a2} a3=${r.a3}) · Part B: ${r.partB} · elements: ${els(r)}\n`;
- s += `- Stage-1 keyword hit: \`${r.match}\`\n`;
+ s += `- Part A: ${r.partA} (a1=${r.a1} a2=${r.a2} a3=${r.a3}) · Part B: ${r.partB} · elements: ${els(r)}`;
+ s += ` · acceptable: ${r.acceptable}${r.uncertain ? ' · UNCERTAIN' : ''}\n`;
+ s += `- Stage-1 keyword hit: \`${r.match}\` · images on product: ${r.imageCount != null ? r.imageCount : '?'}\n`;
s += `- Reason: ${r.reason || '—'}\n`;
s += `- Admin: ${adminUrl(r.id)}\n`;
if (r.imageUrl) s += `- Image: ${r.imageUrl}\n`;
@@ -62,30 +80,32 @@ function mdSection(title, arr) {
return s;
}
md += mdSection('🔴 PROHIBITED — recommend unpublish pending review', prohibited);
-md += mdSection('🟡 BORDERLINE — needs Steve\'s eyes', borderline);
+md += mdSection('🟡 NEEDS REVIEW — currently permitted, needs Steve\'s eyes', needsReview);
if (errors.length) md += mdSection('⚠️ ERROR — re-run verify for these', errors);
fs.writeFileSync('report.md', md);
// ---- html ----
function card(r) {
- const c = r.verdict === 'PROHIBITED' ? '#b3261e' : r.verdict === 'BORDERLINE' ? '#b58a00' : '#888';
+ const c = r.verdict === 'PROHIBITED' ? '#b3261e' : r.verdict === 'NEEDS_REVIEW' ? '#b58a00' : '#888';
+ const multi = r.imageCount > 1 ? ` · <b>${r.imageCount} images — primary only checked</b>` : '';
return `<div class="card" style="border-left:5px solid ${c}">
${r.imageUrl ? `<img src="${esc(r.imageUrl)}" loading="lazy">` : '<div class="noimg">no image</div>'}
<div class="meta">
<span class="badge" style="background:${c}">${esc(r.verdict)}</span>
<h3>${esc(r.title || r.handle)}</h3>
- <p class="sub">ID ${esc(r.id)} · ${esc(r.status)}${r.published ? ' · published' : ''} · keyword: ${esc(r.match)}</p>
- <p class="gate">Part A: <b>${r.partA}</b> (a1 ${r.a1} / a2 ${r.a2} / a3 ${r.a3}) · Part B: <b>${r.partB}</b> · ${esc(els(r))}</p>
+ <p class="sub">ID ${esc(r.id)} · ${esc(r.status)}${r.published ? ' · published' : ''} · keyword: ${esc(r.match)}${multi}</p>
+ <p class="gate">Part A: <b>${r.partA}</b> (a1 ${r.a1} / a2 ${r.a2} / a3 ${r.a3}) · Part B: <b>${r.partB}</b> · ${esc(els(r))} · acceptable: ${r.acceptable}${r.uncertain ? ' · <b>UNCERTAIN</b>' : ''}</p>
<p class="reason">${esc(r.reason)}</p>
<a href="${esc(adminUrl(r.id))}" target="_blank" rel="noopener noreferrer">Open in Shopify admin →</a>
</div></div>`;
}
-const flagged = [...prohibited, ...borderline];
+const flagged = [...prohibited, ...needsReview];
const html = `<!doctype html><meta charset=utf-8><title>DW Settlement Audit</title>
<style>
body{font:15px/1.5 -apple-system,system-ui,sans-serif;background:#faf8f4;color:#1a1710;margin:0;padding:32px}
-h1{margin:0 0 4px}.summary{color:#555;margin-bottom:24px}
+h1{margin:0 0 4px}.summary{color:#555;margin-bottom:10px}
.summary b{color:#b3261e}
+.note{background:#fff8e1;border:1px solid #e8d9a0;border-radius:6px;padding:10px 14px;font-size:13px;color:#5a4a1a;margin-bottom:22px}
.card{display:flex;gap:16px;background:#fff;border-radius:8px;padding:14px;margin-bottom:14px;box-shadow:0 1px 4px #0001}
.card img{width:160px;height:160px;object-fit:cover;object-position:center 12%;border-radius:6px;flex:none}
.noimg{width:160px;height:160px;background:#eee;display:flex;align-items:center;justify-content:center;color:#999;border-radius:6px;flex:none}
@@ -97,10 +117,13 @@ a{color:#0b6}
</style>
<h1>DW Settlement Audit — Verdict Report</h1>
<p class="summary">Generated ${new Date().toISOString()} · ${recs.length} verified ·
-<b>${prohibited.length} PROHIBITED</b> · ${borderline.length} BORDERLINE ·
-${permitted.length} PERMITTED · ${errors.length} errors.
-Report-only — no product changed.</p>
-${flagged.length ? flagged.map(card).join('\n') : '<p>No PROHIBITED or BORDERLINE designs found.</p>'}`;
+<b>${prohibited.length} PROHIBITED</b> · ${needsReview.length} NEEDS REVIEW ·
+${permitted.length} PERMITTED · ${errors.length} errors.</p>
+<div class="note"><b>Screening triage, not a legal adjudication.</b>
+NEEDS REVIEW items are currently PERMITTED until a human re-evaluates them.
+Primary product image only — multi-image products may hide a Part B element in image 2+.
+Report-only: no product has been changed.${manifest.bindingSha256 ? ` Binding vault SHA256: ${esc(manifest.bindingSha256)}.` : ''}</div>
+${flagged.length ? flagged.map(card).join('\n') : '<p>No PROHIBITED or NEEDS REVIEW designs found.</p>'}`;
fs.writeFileSync('report.html', html);
-console.log(`report.md + report.html written — ${prohibited.length} PROHIBITED, ${borderline.length} BORDERLINE, ${errors.length} ERROR (of ${recs.length})`);
+console.log(`report.md + report.html written — ${prohibited.length} PROHIBITED, ${needsReview.length} NEEDS_REVIEW, ${errors.length} ERROR (of ${recs.length})`);
diff --git a/report.md b/report.md
deleted file mode 100644
index dc4b1bb..0000000
--- a/report.md
+++ /dev/null
@@ -1,33 +0,0 @@
-# DW Settlement Audit — Verdict Report
-
-Generated 2026-05-19T03:09:09.869Z · 23 candidates verified
-
-| Verdict | Count |
-|---|---|
-| 🔴 PROHIBITED | 2 |
-| 🟡 BORDERLINE | 0 |
-| 🟢 PERMITTED | 21 |
-| ⚪ NO_IMAGE | 0 |
-| ⚠️ ERROR | 0 |
-
-**Report-only — no product has been changed.** Review the PROHIBITED and BORDERLINE
-lists below; unpublish/edit decisions are yours.
-
-## 🔴 PROHIBITED — recommend unpublish pending review (2)
-
-### Afrika Kingdom - Olgreen & Spgreen/Cream Green | Cole & Son Ardmore-Jabula | Novelty Wallcovering
-- Product ID: `7421498490931` · handle: `dwkk-gcbf5e7ff` · status: active, published: true
-- Part A: true (a1=true a2=true a3=true) · Part B: true · elements: Birds
-- Stage-1 keyword hit: `palm`
-- Reason: Part A is satisfied by repeating foliage, open space, and multiple colors. Part B is satisfied by the presence of birds.
-- Admin: https://admin.shopify.com/store/designer-laboratory-sandbox/products/7421498490931
-- Image: https://cdn.shopify.com/s/files/1/0015/4117/7456/files/119_5026_CS_adf49c63-9746-4d3a-a08f-a309c13aaabd.jpg?v=1753304804
-
-### Afrika Kingdom - Olvgrn&Spgrn/Bck Multi | Cole & Son Ardmore-Jabula | Novelty Wallcovering
-- Product ID: `7421498589235` · handle: `dwkk-ga5aa713d` · status: active, published: true
-- Part A: true (a1=true a2=true a3=true) · Part B: true · elements: Birds
-- Stage-1 keyword hit: `palm`
-- Reason: Part A is satisfied by repeating foliage, negative space, and multiple colors. Part B is satisfied by the presence of birds.
-- Admin: https://admin.shopify.com/store/designer-laboratory-sandbox/products/7421498589235
-- Image: https://cdn.shopify.com/s/files/1/0015/4117/7456/files/119_5027_CS_0d775841-54b1-4b05-a798-343e3662f7ad.jpg?v=1753304801
-
diff --git a/verdicts.jsonl b/verdicts.jsonl
deleted file mode 100644
index 2186ccf..0000000
--- a/verdicts.jsonl
+++ /dev/null
@@ -1,23 +0,0 @@
-{"id":7817258696755,"handle":"a-s-creation-design-panel-anna-d-andrea-beige-wallcovering-as-creation","title":"A.s. Creation Design Panel Anna D Andrea Beige Wallcovering | AS Creation","status":"active","published":true,"match":"tropical","a1":true,"a2":true,"a3":true,"partA":true,"partB":false,"partBElements":[],"verdict":"PERMITTED","reason":"Part A is satisfied with repeating foliage, open space, and multiple colors. Part B is not satisfied as no prohibited elements are present.","imageUrl":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/8348bc1084c67499b5d3b4d1699d6a98.jpg?v=1776041200"}
-{"id":7245733724211,"handle":"dwbm-260072","title":"Abstract Jungle Leaf Green - Pale Beige Wallcovering | Brand McKenzie","status":"active","published":true,"match":"jungle","a1":true,"a2":true,"a3":true,"partA":true,"partB":false,"partBElements":[],"verdict":"PERMITTED","reason":"Part A is satisfied with repeating foliage, open space, and multiple colors. Part B is not satisfied as no bananas, grapes, birds, or butterflies are present.","imageUrl":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/abstract-jungle-putty-grey_5688f46a-4b40-4931-94bb-98c445bce471.jpg?v=1763083476"}
-{"id":7245733593139,"handle":"dwbm-260071","title":"Abstract Jungle Putty Grey - Beige Wallcovering | Brand McKenzie","status":"active","published":true,"match":"jungle","a1":true,"a2":true,"a3":true,"partA":true,"partB":false,"partBElements":[],"verdict":"PERMITTED","reason":"Part A is satisfied. Part B is not satisfied as no bananas, grapes, birds, or butterflies are present.","imageUrl":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/abstract-jungle-leaf-green_2_dc10d8c4-9e74-451e-8058-7465bdbd5d04.webp?v=1749758553"}
-{"id":7245733822515,"handle":"dwbm-260073","title":"Abstract Jungle Teal Blue (Multicolour) | Brand McKenzie","status":"active","published":true,"match":"jungle","a1":true,"a2":true,"a3":true,"partA":true,"partB":false,"partBElements":[],"verdict":"PERMITTED","reason":"Part A is satisfied, but no bananas, grapes, birds, or butterflies are present, so Part B is not satisfied.","imageUrl":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/abstract-jungle-teal-blue_7_fe9c5a52-57be-4da2-a967-0268a89e83db.webp?v=1749758551"}
-{"id":4523159683123,"handle":"schumacher_wallpaper_dwsw_5007531-jpg","title":"Abstract Leaf - Dove Wallcoverings Wallcovering | Schumacher","status":"active","published":true,"match":"tropical","a1":true,"a2":true,"a3":true,"partA":true,"partB":false,"partBElements":[],"verdict":"PERMITTED","reason":"Part A is satisfied (repeating directional foliage, open space, multiple colors). Part B is not satisfied as no prohibited elements are present.","imageUrl":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/5007531-1.jpg?v=1770837562"}
-{"id":4523159650355,"handle":"schumacher_wallpaper_dwsw_5007530-jpg","title":"Abstract Leaf - Linen Wallcoverings Wallcovering | Schumacher","status":"active","published":true,"match":"tropical","a1":true,"a2":true,"a3":true,"partA":true,"partB":false,"partBElements":[],"verdict":"PERMITTED","reason":"Part A is satisfied (repeating directional foliage, open space, multiple colors). Part B is not satisfied as no prohibited elements are present.","imageUrl":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/5007530-1.jpg?v=1770837551"}
-{"id":4523159945267,"handle":"schumacher_wallpaper_dwsw_5007534-jpg","title":"Abstract Leaf - Metallic Slate Wallcoverings Wallcovering | Schumacher","status":"active","published":true,"match":"tropical","a1":true,"a2":true,"a3":true,"partA":true,"partB":false,"partBElements":[],"verdict":"PERMITTED","reason":"Part A is satisfied (repeating directional foliage, negative space, multiple colors). Part B elements (banana, grape, bird, butterfly) are not present.","imageUrl":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/5007534-1.jpg?v=1770837594"}
-{"id":4523159781427,"handle":"schumacher_wallpaper_dwsw_5007532-jpg","title":"Abstract Leaf - Mocha Wallcoverings Wallcovering | Schumacher","status":"active","published":true,"match":"tropical","a1":true,"a2":true,"a3":true,"partA":true,"partB":false,"partBElements":[],"verdict":"PERMITTED","reason":"Part A is satisfied (repeating foliage, open space, multiple colors). Part B is not satisfied as no prohibited elements (banana, grape, bird, butterfly) are present.","imageUrl":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/5007532-1.jpg?v=1770837572"}
-{"id":4523159846963,"handle":"schumacher_wallpaper_dwsw_5007533-jpg","title":"Abstract Leaf - Navy Wallcoverings Wallcovering | Schumacher","status":"active","published":true,"match":"tropical","a1":true,"a2":true,"a3":true,"partA":true,"partB":false,"partBElements":[],"verdict":"PERMITTED","reason":"Part A is satisfied (repeating directional foliage, negative space, multiple colors). Part B is not satisfied as no prohibited elements are present.","imageUrl":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/5007533-1.jpg?v=1770837583"}
-{"id":7421468737587,"handle":"dwkk-g49e57902","title":"Acacia - Charcoal & Silver Charcoal | Cole & Son Ardmore | Wallcovering Print","status":"active","published":true,"match":"tropical","a1":true,"a2":true,"a3":true,"partA":true,"partB":false,"partBElements":[],"verdict":"PERMITTED","reason":"Part A is satisfied. Part B is not satisfied as monkeys are not a listed element.","imageUrl":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/109_11055_CS_8948869f-5403-4483-aa31-aeed8bc25a77.jpg?v=1753305876"}
-{"id":7421468508211,"handle":"dwkk-g1c5dafe9","title":"Acacia - Green & Coral Berries Multi | Cole & Son Ardmore | Wallcovering Print","status":"active","published":true,"match":"tropical","a1":true,"a2":true,"a3":true,"partA":true,"partB":false,"partBElements":[],"verdict":"PERMITTED","reason":"Part A is satisfied. Part B is not satisfied as monkeys are not a listed element.","imageUrl":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/109_11051_CS_7a36c06f-6338-44a1-80ee-c4f0b029b345.jpg?v=1753305886"}
-{"id":7421468606515,"handle":"dwkk-ge57b09f1","title":"Acacia - Grey & White Grey | Cole & Son Ardmore | Wallcovering Print","status":"active","published":true,"match":"tropical","a1":true,"a2":true,"a3":true,"partA":true,"partB":false,"partBElements":[],"verdict":"PERMITTED","reason":"Part A is satisfied. Part B is not satisfied as monkeys are not a listed element.","imageUrl":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/109_11053_CS_8ef2fa48-d5cf-4c21-a217-2ebf31bfb8c0.jpg?v=1753305881"}
-{"id":7421468639283,"handle":"dwkk-gebdfbf65","title":"Acacia - Stone & White Berries Neutral | Cole & Son Ardmore | Wallcovering Print","status":"active","published":true,"match":"tropical","a1":true,"a2":true,"a3":true,"partA":true,"partB":false,"partBElements":[],"verdict":"PERMITTED","reason":"Part B elements (banana, grape, bird, butterfly) are not present. Monkeys are not a Part B element.","imageUrl":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/109_11054_CS_69527df8-f25d-4ea0-953b-47eedd0b37a5.jpg?v=1753305878"}
-{"id":7774610456627,"handle":"acanthus-stripe-sisal-fog-chalk-schumacher-wallcoverings","title":"Acanthus Stripe Sisal Fog & Chalk - Fog & Chalk Wallcoverings Natural Wallcovering | Schumacher","status":"active","published":true,"match":"palm","a1":true,"a2":true,"a3":true,"partA":true,"partB":false,"partBElements":[],"verdict":"PERMITTED","reason":"Part A is satisfied (repeating foliage, open space, multiple colors). Part B is not satisfied as no prohibited elements are present.","imageUrl":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/5006052.jpg?v=1770676874"}
-{"id":6679742775347,"handle":"dwrw-76336","title":"Acapulco | Rebel Walls","status":"active","published":true,"match":"tropical","a1":true,"a2":true,"a3":true,"partA":true,"partB":false,"partBElements":[],"verdict":"PERMITTED","reason":"Part A is satisfied, but no Part B elements (bananas, grapes, birds, butterflies) are present in the design.","imageUrl":"https://cdn.shopify.com/s/files/1/0015/4117/7456/products/RS16011_image1.jpg?v=1756312560"}
-{"id":6962212503603,"handle":"dwhf-70210-sample-designer-wallcoverings-los-angeles","title":"Acropora - Brazilian Rosewood/Nectar/Tree Canopy Wallcovering | Harlequin","status":"active","published":true,"match":"tropical","a1":false,"a2":true,"a3":true,"partA":false,"partB":false,"partBElements":[],"verdict":"PERMITTED","reason":"The design depicts coral and other marine life, not leaves, palm fronds, or similar foliage. Therefore, A1 is not satisfied.","imageUrl":"https://cdn.shopify.com/s/files/1/0015/4117/7456/products/HTEW112779.jpg?v=1739492973"}
-{"id":7421498490931,"handle":"dwkk-gcbf5e7ff","title":"Afrika Kingdom - Olgreen & Spgreen/Cream Green | Cole & Son Ardmore-Jabula | Novelty Wallcovering","status":"active","published":true,"match":"palm","a1":true,"a2":true,"a3":true,"partA":true,"partB":true,"partBElements":["Birds"],"verdict":"PROHIBITED","reason":"Part A is satisfied by repeating foliage, open space, and multiple colors. Part B is satisfied by the presence of birds.","imageUrl":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/119_5026_CS_adf49c63-9746-4d3a-a08f-a309c13aaabd.jpg?v=1753304804"}
-{"id":7421498392627,"handle":"dwkk-gc9c6a35a","title":"Afrika Kingdom - Olgrn/Spgrn/Mt Bronz Green | Cole & Son Ardmore-Jabula | Novelty Wallcovering","status":"active","published":true,"match":"palm","a1":true,"a2":true,"a3":true,"partA":true,"partB":false,"partBElements":[],"verdict":"PERMITTED","reason":"Part A is satisfied. Part B is not satisfied as no bananas, grapes, birds, or butterflies are present.","imageUrl":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/119_5025_CS_d9fc60dd-1ffb-4d1d-819a-ee07532d4264.jpg?v=1753304806"}
-{"id":7421498589235,"handle":"dwkk-ga5aa713d","title":"Afrika Kingdom - Olvgrn&Spgrn/Bck Multi | Cole & Son Ardmore-Jabula | Novelty Wallcovering","status":"active","published":true,"match":"palm","a1":true,"a2":true,"a3":true,"partA":true,"partB":true,"partBElements":["Birds"],"verdict":"PROHIBITED","reason":"Part A is satisfied by repeating foliage, negative space, and multiple colors. Part B is satisfied by the presence of birds.","imageUrl":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/119_5027_CS_0d775841-54b1-4b05-a798-343e3662f7ad.jpg?v=1753304801"}
-{"id":6604487000115,"handle":"dwcw-700221","title":"Aga Jungle Green on Off White Screen Printed - Off-White Wallcovering | China Seas","status":"active","published":true,"match":"jungle","a1":false,"a2":false,"a3":true,"partA":false,"partB":false,"partBElements":[],"verdict":"PERMITTED","reason":"The pattern is geometric, not foliage. Therefore, A1 and A2 are not satisfied.","imageUrl":"https://cdn.shopify.com/s/files/1/0015/4117/7456/products/CHINA_SEAS_WALLPAPER_DWC_700200_Aga-Jungle-Green-on-Off-White-6340-06WP_jpg_18d60d3f-e2cd-4dad-9c3b-87b8fb699504.jpg?v=1748372958"}
-{"id":6604439289907,"handle":"dwcs-886522","title":"Aga Jungle Green on Tint Screen Printed - Off-White Fabric | China Seas","status":"active","published":true,"match":"jungle","a1":false,"a2":false,"a3":true,"partA":false,"partB":false,"partBElements":[],"verdict":"PERMITTED","reason":"The pattern is geometric, not foliage. Therefore, A1 and A2 are not satisfied. Part A is not fully satisfied.","imageUrl":"https://cdn.shopify.com/s/files/1/0015/4117/7456/products/China_Seas_DWC_Aga-Jungle-Green-On-Tint-6340-06_jpg_e30ee067-2d28-4e92-8dfb-f696996cd6f8.jpg?v=1632157442"}
-{"id":6604487032883,"handle":"dwcw-700321","title":"Aga Jungle Green on White Screen Printed - Off-White Wallcovering | China Seas","status":"active","published":true,"match":"jungle","a1":false,"a2":false,"a3":true,"partA":false,"partB":false,"partBElements":[],"verdict":"PERMITTED","reason":"The design is geometric, not foliage. Therefore, A1 and A2 are not satisfied, making Part A false.","imageUrl":"https://cdn.shopify.com/s/files/1/0015/4117/7456/products/CHINA_SEAS_WALLPAPER_DWC_700300_Aga-Jungle-Green-on-White-6340-06WWP_jpg_c881753f-2753-4eee-973e-79889983438f.jpg?v=1748372956"}
-{"id":7813808422963,"handle":"agra-langsat-arte","title":"Agra Langsat Wallcovering | Arte International","status":"active","published":true,"match":"tropical","a1":true,"a2":true,"a3":true,"partA":true,"partB":false,"partBElements":[],"verdict":"PERMITTED","reason":"Part A is satisfied (repeating palm fronds, visible negative space, multiple colors). Part B is not satisfied as no prohibited elements are present.","imageUrl":"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/Indienne_Agra_18310_Roomshot_Web_LR-og.jpg?v=1775600124"}
diff --git a/verify-candidates.js b/verify-candidates.js
index 3987661..cf8dcbb 100644
--- a/verify-candidates.js
+++ b/verify-candidates.js
@@ -2,8 +2,21 @@
/* DW settlement audit — stage 2: vision verify.
*
* Reads candidates.jsonl (stage-1 keyword hits), fetches each product's primary
- * image, and runs it through Gemini vision against the verbatim settlement gate.
- * Writes verdicts.jsonl. Resumable — skips products already in verdicts.jsonl.
+ * image, and runs it through Gemini vision against the settlement gate.
+ *
+ * GATE FAITHFULNESS (best-practices fix 2026-05-18):
+ * - The settlement constraint set is NOT paraphrased here. It is read VERBATIM
+ * at runtime from the SHA-locked binding vault
+ * (~/.claude/skills/settlement/binding/SETTLEMENT-BINDING-TEXT.md) and the
+ * BINDING-START..BINDING-END block is embedded directly in the prompt.
+ * - Gemini reports only the 5 ATOMIC detector booleans (a1,a2,a3,partB,acceptable)
+ * plus an `uncertain` flag. It does NOT decide the verdict. The verdict is
+ * computed deterministically in JS by the combinator (combine()), matching
+ * the canonical 5-detector + settlement-verdict architecture.
+ * - Each run is SHA-stamped to the vault version it used (run-manifest.json).
+ *
+ * Gemini vision is the canonically-correct model for image-side detection — the
+ * settlement-post-gen-vision skill uses Gemini for exactly this.
*
* NEVER deletes or unpublishes anything. Output is a report for Steve's sign-off.
*
@@ -11,6 +24,8 @@
*/
'use strict';
const fs = require('fs');
+const os = require('os');
+const crypto = require('crypto');
const SHOP = 'designer-laboratory-sandbox.myshopify.com';
const STOKEN = process.env.SHOPIFY_ADMIN_TOKEN;
@@ -20,37 +35,54 @@ if (!STOKEN || !GKEY) { console.error('need SHOPIFY_ADMIN_TOKEN + GEMINI_API_KEY
const CAND = 'candidates.jsonl';
const VERD = 'verdicts.jsonl';
const PROG = 'progress2.txt';
+const VAULT = os.homedir() + '/.claude/skills/settlement/binding/SETTLEMENT-BINDING-TEXT.md';
+
+// --- pull the binding text VERBATIM from the SHA-locked vault ---------------
+const vaultRaw = fs.readFileSync(VAULT, 'utf8');
+const m = vaultRaw.match(/<!-- BINDING-START[\s\S]*?BINDING-END[^>]*-->/);
+if (!m) { console.error('could not locate BINDING block in vault — aborting'); process.exit(1); }
+const BINDING = m[0];
+const BINDING_SHA = crypto.createHash('sha256').update(BINDING).digest('hex');
+fs.writeFileSync('run-manifest.json', JSON.stringify({
+ startedAt: new Date().toISOString(),
+ vault: VAULT,
+ bindingSha256: BINDING_SHA,
+ note: 'verdicts.jsonl was produced against this exact binding-vault version',
+}, null, 2) + '\n');
-// Verbatim settlement gate — combined Part A + Part B test.
-const GATE = `You are auditing a wallcovering product image against a binding legal settlement. Apply it literally and narrowly.
+// The detector prompt embeds the binding text verbatim. Gemini reports atomic
+// observations only — it must NOT decide the verdict (combine() does that).
+const PROMPT = `You are auditing a wallcovering product image against a binding legal settlement.
+The settlement constraint set is reproduced VERBATIM below, between the BINDING markers.
+Do not reinterpret, soften, or "improve" it. Read it literally and narrowly.
-PART A is satisfied ONLY IF ALL THREE are present together:
- A1. A repeating pattern with directional variation amongst leaves, palm fronds, or similar foliage.
- A2. Visible open/negative space between the leaves (not edge-to-edge coverage).
- A3. More than one ink/color in the design.
+${BINDING}
-PART B is satisfied ONLY IF one or more of these EXACT elements appears. This is a CLOSED list — nothing else counts:
- - Bananas or banana pods
- - Grapes
- - Birds (any species)
- - Butterflies (any species)
-CRITICAL: No other element satisfies Part B. Monkeys and all other animals, all other fruit,
-flowers, insects other than butterflies, tree trunks, branches — NONE are Part B elements.
-If the only creature you see is an animal that is not a bird or butterfly, partB is FALSE.
+Evaluate the image against each ATOMIC condition independently. Report ONLY what you
+observe — do NOT decide the final PROHIBITED/PERMITTED verdict, that is computed elsewhere.
-A design is PROHIBITED if and only if BOTH Part A is fully satisfied AND Part B is satisfied.
-- Part A satisfied but Part B NOT satisfied -> PERMITTED.
-- A Part B element present but Part A NOT fully satisfied (single color, edge-to-edge, no
- foliage, or non-leaf substrate like trellis / cane / geometric / mural) -> PERMITTED.
-Use the defendant-favorable reading. Only return BORDERLINE if you genuinely cannot tell
-whether a specific Part B element (banana, grape, bird, or butterfly) is present.
+Notes for accurate observation:
+- Part B is a CLOSED list: bananas/banana pods, grapes, birds, butterflies. NOTHING else
+ satisfies Part B. Monkeys and all other animals, other fruit, flowers, and insects that
+ are not butterflies are NOT Part B elements — for those, partB is false.
+- "acceptable" is true if the image shows tree trunks, clearly represented branches, OR a
+ fruit/animal element that is NOT one of the four Part B elements.
Reply with ONLY a compact JSON object, no prose, no markdown fence:
-{"a1":bool,"a2":bool,"a3":bool,"partA":bool,"partB":bool,"partBElements":["..."],"verdict":"PROHIBITED|PERMITTED|BORDERLINE","reason":"<=30 words"}`;
+{"a1":bool,"a2":bool,"a3":bool,"partB":bool,"partBElements":["..."],"acceptable":bool,"uncertain":bool,"reason":"<=30 words"}`;
const sleep = ms => new Promise(r => setTimeout(r, ms));
const readLines = f => { try { return fs.readFileSync(f, 'utf8').split('\n').filter(Boolean); } catch { return []; } };
+// --- deterministic verdict combinator (canonical defendant-favorable reading) ---
+function combine(o) {
+ if (o.uncertain) return { verdict: 'NEEDS_REVIEW', partA: null };
+ const partA = !!(o.a1 && o.a2 && o.a3);
+ if (partA && o.partB && !o.acceptable) return { verdict: 'PROHIBITED', partA };
+ if (partA && o.partB && o.acceptable) return { verdict: 'NEEDS_REVIEW', partA }; // A∧B∧Acceptable
+ return { verdict: 'PERMITTED', partA };
+}
+
async function shopify(path) {
for (let a = 0; a < 5; a++) {
const r = await fetch(`https://${SHOP}/admin/api/2024-01/${path}`,
@@ -62,10 +94,10 @@ async function shopify(path) {
return null;
}
-async function geminiVerify(imgB64, mime, ctx) {
+async function geminiObserve(imgB64, mime, ctx) {
const body = {
contents: [{ parts: [
- { text: GATE + '\n\nProduct title: ' + ctx },
+ { text: PROMPT + '\n\nProduct title: ' + ctx },
{ inline_data: { mime_type: mime, data: imgB64 } },
] }],
generationConfig: {
@@ -80,48 +112,60 @@ async function geminiVerify(imgB64, mime, ctx) {
if (r.status === 429 || r.status >= 500) { await sleep(3000); continue; }
const j = await r.json();
const txt = j?.candidates?.[0]?.content?.parts?.[0]?.text || '';
- const m = txt.match(/\{[\s\S]*\}/);
- if (m) { try { return JSON.parse(m[0]); } catch {} }
- return { verdict: 'ERROR', reason: 'unparseable: ' + txt.slice(0, 80) };
+ const mm = txt.match(/\{[\s\S]*\}/);
+ if (mm) { try { return JSON.parse(mm[0]); } catch {} }
+ return { _err: 'unparseable: ' + txt.slice(0, 80) };
}
- return { verdict: 'ERROR', reason: 'gemini unavailable' };
+ return { _err: 'gemini unavailable' };
}
(async () => {
const cands = readLines(CAND).map(l => JSON.parse(l));
const done = new Set(readLines(VERD).map(l => { try { return JSON.parse(l).id; } catch { return null; } }));
const todo = cands.filter(c => !done.has(c.id));
- let n = 0, prohibited = 0, borderline = 0, err = 0;
+ let n = 0, prohibited = 0, needsReview = 0, err = 0;
const out = fs.createWriteStream(VERD, { flags: 'a' });
for (const c of todo) {
n++;
let rec = { id: c.id, handle: c.handle, title: c.title, status: c.status,
- published: c.published, match: c.match };
+ published: c.published, match: c.match, bindingSha256: BINDING_SHA };
try {
const imgs = await shopify(`products/${c.id}/images.json`);
- const src = imgs?.images?.[0]?.src;
+ const all = imgs?.images || [];
+ const src = all[0]?.src;
+ rec.imageCount = all.length; // panel flagged: only primary image is checked
if (!src) { rec.verdict = 'NO_IMAGE'; rec.reason = 'product has no image'; }
else {
const ir = await fetch(src);
const buf = Buffer.from(await ir.arrayBuffer());
- const mime = ir.headers.get('content-type') || 'image/jpeg';
- const v = await geminiVerify(buf.toString('base64'), mime.split(';')[0], c.title || '');
- rec = Object.assign(rec, v, { imageUrl: src });
+ const mime = (ir.headers.get('content-type') || 'image/jpeg').split(';')[0];
+ const o = await geminiObserve(buf.toString('base64'), mime, c.title || '');
+ rec.imageUrl = src;
+ if (o._err) { rec.verdict = 'ERROR'; rec.reason = o._err; }
+ else {
+ const v = combine(o);
+ rec = Object.assign(rec, {
+ a1: !!o.a1, a2: !!o.a2, a3: !!o.a3, partA: v.partA,
+ partB: !!o.partB, partBElements: o.partBElements || [],
+ acceptable: !!o.acceptable, uncertain: !!o.uncertain,
+ verdict: v.verdict, reason: o.reason || '',
+ });
+ }
}
} catch (e) { rec.verdict = 'ERROR'; rec.reason = e.message; }
if (rec.verdict === 'PROHIBITED') prohibited++;
- if (rec.verdict === 'BORDERLINE') borderline++;
+ if (rec.verdict === 'NEEDS_REVIEW') needsReview++;
if (rec.verdict === 'ERROR') err++;
out.write(JSON.stringify(rec) + '\n');
if (n % 10 === 0 || n === todo.length) {
fs.writeFileSync(PROG, `verified ${n}/${todo.length} (of ${cands.length} total) | ` +
- `PROHIBITED ${prohibited} | BORDERLINE ${borderline} | ERROR ${err} | ${new Date().toISOString()}\n`);
+ `PROHIBITED ${prohibited} | NEEDS_REVIEW ${needsReview} | ERROR ${err} | ${new Date().toISOString()}\n`);
}
await sleep(700); // pace Shopify + Gemini
}
out.end();
fs.writeFileSync(PROG, `DONE | verified ${n}/${todo.length} | PROHIBITED ${prohibited} | ` +
- `BORDERLINE ${borderline} | ERROR ${err} | ${new Date().toISOString()}\n`);
- console.log(`stage 2 done — ${n} verified, ${prohibited} prohibited, ${borderline} borderline, ${err} errors`);
+ `NEEDS_REVIEW ${needsReview} | ERROR ${err} | ${new Date().toISOString()}\n`);
+ console.log(`stage 2 done — ${n} verified, ${prohibited} prohibited, ${needsReview} needs-review, ${err} errors`);
})();
← 9ff2b92 report.js: escape all Shopify-sourced fields in HTML output
·
back to Dw Settlement Audit
·
snapshot — gitify backup 2026-05-19 b39103a →