[object Object]

← back to Sample Followup Sweep

sample-followup: coverage-reconciliation canary (silent-skip false-green safety net) — TK-12117

1d2b68097ad7d99518c6747a9595955a91f92718 · 2026-09-23 16:20:15 -0700 · Steve Abrams

READ-ONLY scripts/coverage-reconcile.mjs queries live FileMaker for the true
outstanding population (two-read vid+letterSent join) and reconciles it against
the sweep's own bucketing (lib/sweep.js reconcileCoverage). A row outstanding in
FM but in NO sweep bucket = LEAKED = FAIL; never PASS on 'it ran'. Emits
PASS/WARN/FAIL + latest.json. Ships test/coverage-reconcile.test.cjs (5 asserts,
incl injected-leak FAIL) + a --self-test seam. First live run FOUND 4 real
empty-vid silent skips (FAIL). launchd install drafted to pending-approval (gated).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit 1d2b68097ad7d99518c6747a9595955a91f92718
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Sep 23 16:20:15 2026 -0700

    sample-followup: coverage-reconciliation canary (silent-skip false-green safety net) — TK-12117
    
    READ-ONLY scripts/coverage-reconcile.mjs queries live FileMaker for the true
    outstanding population (two-read vid+letterSent join) and reconciles it against
    the sweep's own bucketing (lib/sweep.js reconcileCoverage). A row outstanding in
    FM but in NO sweep bucket = LEAKED = FAIL; never PASS on 'it ran'. Emits
    PASS/WARN/FAIL + latest.json. Ships test/coverage-reconcile.test.cjs (5 asserts,
    incl injected-leak FAIL) + a --self-test seam. First live run FOUND 4 real
    empty-vid silent skips (FAIL). launchd install drafted to pending-approval (gated).
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 data/coverage-reconcile/latest.json                |  52 +++++++++
 ....steve.sample-followup-coverage-reconcile.plist |  49 +++++++++
 lib/sweep.js                                       |  62 ++++++++++-
 scripts/coverage-reconcile.mjs                     | 118 +++++++++++++++++++++
 test/coverage-reconcile.test.cjs                   |  69 ++++++++++++
 5 files changed, 349 insertions(+), 1 deletion(-)

diff --git a/data/coverage-reconcile/latest.json b/data/coverage-reconcile/latest.json
new file mode 100644
index 0000000..9b68ae3
--- /dev/null
+++ b/data/coverage-reconcile/latest.json
@@ -0,0 +1,52 @@
+{
+  "verdict": "FAIL",
+  "status": "FAIL",
+  "window": "07/25/2026...09/13/2026",
+  "population": 98,
+  "accounted": 94,
+  "covered": 81,
+  "uncovered": 13,
+  "leakedCount": 4,
+  "reconciles": true,
+  "runStale": false,
+  "buckets": {
+    "chaseable": 0,
+    "suppressed14d": 59,
+    "needsConfirm": 13,
+    "guardSuppressed": 14,
+    "noVendorMap": 0,
+    "noChase": 8
+  },
+  "leaked": [
+    {
+      "vid": "",
+      "sku": "DWTT70793",
+      "entered": "07/30/2026",
+      "mfr": "T10973",
+      "why": "empty vid — sweep drops it before grouping (silent skip)"
+    },
+    {
+      "vid": "",
+      "sku": "DWLC1059",
+      "entered": "08/21/2026",
+      "mfr": "23003",
+      "why": "empty vid — sweep drops it before grouping (silent skip)"
+    },
+    {
+      "vid": "",
+      "sku": "GLM9116",
+      "entered": "09/08/2026",
+      "mfr": "SLO1-White Iris",
+      "why": "empty vid — sweep drops it before grouping (silent skip)"
+    },
+    {
+      "vid": "",
+      "sku": "DWPN100994",
+      "entered": "09/08/2026",
+      "mfr": "PI-KOTOR-SPRUCE",
+      "why": "empty vid — sweep drops it before grouping (silent skip)"
+    }
+  ],
+  "ts": "2026-09-23T23:18:45.212Z",
+  "skill": "sample-followup-coverage-reconcile"
+}
\ No newline at end of file
diff --git a/launchd/com.steve.sample-followup-coverage-reconcile.plist b/launchd/com.steve.sample-followup-coverage-reconcile.plist
new file mode 100644
index 0000000..0d0909c
--- /dev/null
+++ b/launchd/com.steve.sample-followup-coverage-reconcile.plist
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<!--
+  TK-12117 — Coverage-reconciliation canary (READ-ONLY). Runs `node scripts/coverage-reconcile.mjs`
+  daily at 07:45 (just AFTER the 7:00 Tue-Fri sweep) so the run-marker freshness check is meaningful.
+  Writes latest.json to a fleet-health skill dir so fleet-health-rollup globs it.
+  READ-ONLY: FileMaker reads only (FM_READONLY=1), no send, never passes --self-test.
+
+  Install (Steve — GATED, scheduled-job install):
+    mkdir -p ~/.claude/skills/sample-followup-coverage-reconcile/data
+    cp ~/Projects/sample-followup-sweep/launchd/com.steve.sample-followup-coverage-reconcile.plist ~/Library/LaunchAgents/
+    launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.steve.sample-followup-coverage-reconcile.plist
+  Uninstall:
+    launchctl bootout gui/$(id -u)/com.steve.sample-followup-coverage-reconcile
+-->
+<plist version="1.0">
+<dict>
+  <key>Label</key>
+  <string>com.steve.sample-followup-coverage-reconcile</string>
+  <key>ProgramArguments</key>
+  <array>
+    <string>/opt/homebrew/bin/node</string>
+    <string>/Users/macstudio3/Projects/sample-followup-sweep/scripts/coverage-reconcile.mjs</string>
+  </array>
+  <key>WorkingDirectory</key>
+  <string>/Users/macstudio3/Projects/sample-followup-sweep</string>
+  <key>EnvironmentVariables</key>
+  <dict>
+    <key>PATH</key>
+    <string>/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
+    <key>COVERAGE_DATA_DIR</key>
+    <string>/Users/macstudio3/.claude/skills/sample-followup-coverage-reconcile/data</string>
+  </dict>
+  <key>StartCalendarInterval</key>
+  <array>
+    <dict><key>Weekday</key><integer>2</integer><key>Hour</key><integer>7</integer><key>Minute</key><integer>45</integer></dict>
+    <dict><key>Weekday</key><integer>3</integer><key>Hour</key><integer>7</integer><key>Minute</key><integer>45</integer></dict>
+    <dict><key>Weekday</key><integer>4</integer><key>Hour</key><integer>7</integer><key>Minute</key><integer>45</integer></dict>
+    <dict><key>Weekday</key><integer>5</integer><key>Hour</key><integer>7</integer><key>Minute</key><integer>45</integer></dict>
+    <dict><key>Weekday</key><integer>6</integer><key>Hour</key><integer>9</integer><key>Minute</key><integer>0</integer></dict>
+  </array>
+  <key>RunAtLoad</key>
+  <false/>
+  <key>StandardOutPath</key>
+  <string>/Users/macstudio3/Projects/sample-followup-sweep/out/coverage-reconcile.log</string>
+  <key>StandardErrorPath</key>
+  <string>/Users/macstudio3/Projects/sample-followup-sweep/out/coverage-reconcile.log</string>
+</dict>
+</plist>
diff --git a/lib/sweep.js b/lib/sweep.js
index 21c2a8d..ce118ce 100644
--- a/lib/sweep.js
+++ b/lib/sweep.js
@@ -1,4 +1,5 @@
 'use strict';
+const { slugForVid, normVid } = require('./slug-aliases.cjs');   // TK-12117 coverage reconciliation
 // Phase 1 — Sweep.
 // Given a vendor's requested-sample rows, split them into the follow-up set,
 // an escalation set (already 2nd-requested), and skipped (with reasons).
@@ -81,4 +82,63 @@ function suppressChase(enteredDate, siblings = []) {
   return { suppress: false, reason: null };
 }
 
-module.exports = { sweep, ageDays, suppressChase };
+// TK-12117 (Steve false-green doctrine): COVERAGE RECONCILIATION. Pure function — given ALL
+// in-window 'Report for old memo samples' records + the contacts map + the recently-emailed set,
+// bucket EVERY outstanding row (Date WP Sample Sent empty, non-empty entered) into exactly one
+// disposition and ASSERT the sweep would account for all of them. A row that is outstanding in
+// FileMaker but would appear in NO sweep bucket (e.g. the sweep drops empty-vid rows before
+// grouping) = LEAKED = a silent skip = FAIL. This makes "ran successfully while chasing only a
+// fraction" impossible: PASS requires the FM population to be fully accounted AND every row in an
+// actioned bucket — never PASS merely because the script ran.
+//   buckets: chaseable | suppressed14d | needsConfirm | guardSuppressed | noVendorMap | noChase
+//   actioned (covered) = chaseable + suppressed14d + guardSuppressed + noChase
+//   uncovered (accounted but NOT actually chased) = noVendorMap + needsConfirm  -> WARN
+//   leaked (outstanding but in no bucket) -> FAIL
+// records: array of { fieldData: {...} } (FileMaker shape) OR plain field objects (fixtures).
+function reconcileCoverage(records, { contacts = {}, recentSet = new Set(), runStale = false } = {}) {
+  const norm = (v) => String(v == null ? '' : v).replace(/[\r\n]/g, '').trim();
+  const fd = (r) => (r && r.fieldData) ? r.fieldData : (r || {});
+  // siblings by sku (all in-window records) for the never-false-chase guard
+  const siblings = {};
+  for (const r of records) {
+    const d = fd(r); const sku = norm(d['combo sku']); if (!sku) continue;
+    (siblings[sku] = siblings[sku] || []).push({ entered: norm(d['today for client']), wpSampleSent: norm(d['Date WP Sample Sent']), letterSent: norm(d['Date Sample Request Letter Sent']) });
+  }
+  const b = { chaseable: [], suppressed14d: [], needsConfirm: [], guardSuppressed: [], noVendorMap: [], noChase: [] };
+  const leaked = [];
+  let population = 0;
+  for (const r of records) {
+    const d = fd(r);
+    const wp = norm(d['Date WP Sample Sent']);
+    const entered = norm(d['today for client']);
+    if (wp !== '' || entered === '') continue;                 // only OUTSTANDING in-window rows are the denominator
+    population++;
+    const sku = norm(d['combo sku']);
+    const vid = normVid(d.vid);
+    const tag = { vid, sku, entered, mfr: norm(d['Mfr Pattern']) };
+    if (!vid) { leaked.push({ ...tag, why: 'empty vid — sweep drops it before grouping (silent skip)' }); continue; }
+    const g = suppressChase(entered, siblings[sku] || []);
+    if (g.suppress) { b.guardSuppressed.push({ ...tag, reason: g.reason }); continue; }
+    const c = contacts[slugForVid(vid)];
+    if (!c) { b.noVendorMap.push(tag); continue; }
+    if (c.disposition === 'no-chase') { b.noChase.push(tag); continue; }
+    const email = c.sample_email || c.main_email;
+    if (!email || !c.account_number) { b.noVendorMap.push({ ...tag, why: 'incomplete contact (no email/account)' }); continue; }
+    const recips = String(email).toLowerCase().split(/[,;]\s*/).map((s) => s.trim()).filter(Boolean);
+    if (recips.some((e) => recentSet.has(e))) { b.suppressed14d.push(tag); continue; }
+    if (c.needs_confirm) { b.needsConfirm.push(tag); continue; }
+    b.chaseable.push(tag);
+  }
+  const counts = Object.fromEntries(Object.entries(b).map(([k, v]) => [k, v.length]));
+  const accounted = Object.values(counts).reduce((s, n) => s + n, 0);
+  const covered = counts.chaseable + counts.suppressed14d + counts.guardSuppressed + counts.noChase;
+  const uncovered = counts.noVendorMap + counts.needsConfirm;
+  const reconciles = (accounted + leaked.length === population);
+  let verdict;
+  if (leaked.length > 0 || !reconciles) verdict = 'FAIL';       // silent-skip / reconciliation broke
+  else if (uncovered > 0 || runStale) verdict = 'WARN';         // real outstanding not actually chased, or run missed
+  else verdict = 'PASS';                                        // fully accounted + every row actioned
+  return { verdict, status: verdict, population, accounted, covered, uncovered, leaked, reconciles, counts, buckets: b };
+}
+
+module.exports = { sweep, ageDays, suppressChase, reconcileCoverage };
diff --git a/scripts/coverage-reconcile.mjs b/scripts/coverage-reconcile.mjs
new file mode 100644
index 0000000..bd8a9f0
--- /dev/null
+++ b/scripts/coverage-reconcile.mjs
@@ -0,0 +1,118 @@
+#!/usr/bin/env node
+// TK-12117 — COVERAGE-RECONCILIATION CANARY (READ-ONLY).
+// Steve's false-green doctrine: never PASS on "it ran" — assert coverage against an INDEPENDENT
+// source. This queries LIVE FileMaker for the true outstanding population in the active window and
+// reconciles it against the sweep's own bucketing (lib/sweep.js reconcileCoverage). A row that is
+// outstanding in FileMaker but would appear in NO sweep bucket = LEAKED (silent skip) = FAIL.
+//   PASS  = population fully accounted AND every outstanding row in an ACTIONED bucket + run fresh
+//   WARN  = uncovered-but-accounted rows (no-vendor-map / needs-confirm) > 0, OR the Tue-Fri run missed
+//   FAIL  = FM unreadable / reconciliation broke / leaked rows
+// Writes data/latest.json every run (fleet-health-rollup vocab: top-level verdict AND status).
+// Usage:
+//   node scripts/coverage-reconcile.mjs           # live run
+//   node scripts/coverage-reconcile.mjs --self-test   # injected-leak fixture must go FAIL (never in the plist)
+import { readFileSync, writeFileSync, mkdirSync, existsSync, statSync, readdirSync } from 'node:fs';
+import { homedir } from 'node:os'; import { join, dirname } from 'node:path'; import { fileURLToPath } from 'node:url';
+import { createRequire } from 'node:module'; import http from 'node:http';
+const require = createRequire(import.meta.url);
+const __dir = dirname(fileURLToPath(import.meta.url)); const ROOT = join(__dir, '..');
+const { reconcileCoverage } = require(join(ROOT, 'lib', 'sweep.js'));
+
+const SELF_TEST = process.argv.includes('--self-test');
+const MIN_AGE = 10, MAX_AGE = Number(process.env.MAX_AGE) || 60;
+const DATA_DIR = process.env.COVERAGE_DATA_DIR || join(ROOT, 'data', 'coverage-reconcile');
+const pad = (n) => String(n).padStart(2, '0');
+const fmt = (d) => `${pad(d.getMonth() + 1)}/${pad(d.getDate())}/${d.getFullYear()}`;
+const readJSON = (f, d) => { try { return JSON.parse(readFileSync(f, 'utf8')); } catch { return d; } };
+
+function writeLatest(obj) {
+  mkdirSync(DATA_DIR, { recursive: true });
+  writeFileSync(join(DATA_DIR, 'latest.json'), JSON.stringify({ ...obj, ts: new Date().toISOString(), skill: 'sample-followup-coverage-reconcile' }, null, 2));
+}
+
+// --- SELF-TEST seam (guarded; the launchd plist must NEVER pass --self-test) ---
+if (SELF_TEST) {
+  const contacts = { fabr: { sample_email: 'customers@fabricut.com', account_number: 'On File' } };
+  const row = (vid, sku) => ({ fieldData: { vid, 'combo sku': sku, 'today for client': '09/10/2026', 'Date WP Sample Sent': '', 'Date Sample Request Letter Sent': '', 'Mfr Pattern': 'P' } });
+  const r = reconcileCoverage([row('FABR', 'A'), row('', 'LEAK')], { contacts });
+  console.log(`[SELF-TEST] injected empty-vid leak -> verdict=${r.verdict} leaked=${r.leaked.length} (expect FAIL/>=1)`);
+  process.exit(r.verdict === 'FAIL' && r.leaked.length >= 1 ? 0 : 1);
+}
+
+// --- recently-emailed set: recently-contacted.json (<=14d) + best-effort live Gmail (read-only) ---
+function recentSet() {
+  const set = new Set();
+  const raw = readJSON(join(ROOT, 'data', 'recently-contacted.json'), {});
+  const cutoff = new Date(Date.now() - 14 * 864e5);
+  if (!Array.isArray(raw)) for (const [addr, when] of Object.entries(raw)) { const d = new Date(when); if (!isNaN(d) && d >= cutoff) set.add(String(addr).toLowerCase().trim()); }
+  return set;
+}
+async function mergeGmailRecent(set) {
+  try {
+    const g = (k) => { for (const f of ['/Users/macstudio3/Projects/Designer-Wallcoverings/DW-MCP/.env', '/Users/macstudio3/Projects/george-gmail/.env']) { try { const m = readFileSync(f, 'utf8').match(new RegExp('^' + k + '=(.+)$', 'm')); if (m) return m[1].trim(); } catch {} } return ''; };
+    let auth = g('GEORGE_BASIC_AUTH'); if (!auth.includes(':')) auth = 'admin:' + g('GEORGE_BASIC_AUTH_PASS');
+    auth = 'Basic ' + Buffer.from(auth).toString('base64');
+    const q = encodeURIComponent('in:sent subject:"Sample Follow-Up — Outstanding Memos" -subject:"Re:" newer_than:14d');
+    await new Promise((res) => { const req = http.request({ host: '127.0.0.1', port: 9850, path: `/api/messages?account=info&maxResults=100&q=${q}`, method: 'GET', headers: { Authorization: auth } }, (r) => { let b = ''; r.on('data', (d) => b += d); r.on('end', () => { try { const j = JSON.parse(b); for (const m of (j.messages || [])) for (const e of String(m.to || '').match(/[\w.+-]+@[\w.-]+\.\w+/g) || []) set.add(e.toLowerCase()); } catch {} res(); }); }); req.on('error', () => res()); req.end(); });
+  } catch {}
+  return set;
+}
+
+// --- run-marker freshness: on a Tue-Fri, a REAL scheduled run (mode DRAFT/SEND) must have a marker today ---
+function runStaleToday() {
+  const now = new Date(); const dow = now.getDay();
+  if (![2, 3, 4, 5].includes(dow)) return false;             // not a scheduled run-day -> not stale
+  const marker = join(ROOT, 'data', 'runs', `scheduled-${fmt(now).replace(/\//g, '-')}.json`);
+  const rep = readJSON(marker, null);
+  if (rep && (rep.mode === 'DRAFT' || rep.mode === 'SEND')) return false;   // real run fired today
+  // fallback: scheduled-send.log written today
+  try { const s = statSync(join(ROOT, 'out', 'scheduled-send.log')); const d = new Date(s.mtime); if (d.toDateString() === now.toDateString()) return false; } catch {}
+  return true;
+}
+
+async function main() {
+  // FileMaker read-only — ALL in-window 'Report for old memo samples' records (independent denominator).
+  let records;
+  try {
+    const cfg = JSON.parse(readFileSync(join(homedir(), '.claude.json'), 'utf8'));
+    const fenv = cfg?.mcpServers?.filemaker?.env || {};
+    for (const k of ['FM_CLOUD_HOST', 'FM_CLARIS_EMAIL', 'FM_CLARIS_PASSWORD']) process.env[k] = fenv[k];
+    process.env.FM_READONLY = '1';
+    const fm = await import('/Users/macstudio3/Projects/filemaker-mcp/src/fm-client.js');
+    const hi = new Date(); hi.setDate(hi.getDate() - MIN_AGE);
+    const lo = new Date(); lo.setDate(lo.getDate() - MAX_AGE);
+    const win = `${fmt(lo)}...${fmt(hi)}`;
+    // Two-read join (recordId is stable across layouts, one WALLPAPER2 table): A = 'REPORT ON SAMPLES
+    // ORDERED' has vid + combo sku + entered + Date WP Sample Sent; B = 'Report for old memo samples'
+    // has Date Sample Request Letter Sent. Neither has BOTH, so join B's letterSent onto A by recordId.
+    const A = (await fm.findRecords('WALLPAPER', 'REPORT ON SAMPLES ORDERED', { 'today for client': win }, { limit: 3000 })).records || [];
+    const B = (await fm.findRecords('WALLPAPER', 'Report for old memo samples', { 'today for client': win }, { limit: 3000 })).records || [];
+    const letterByRid = {}; for (const r of B) letterByRid[String(r.recordId)] = (r.fieldData['Date Sample Request Letter Sent'] || '');
+    records = A.map((r) => ({ fieldData: { ...r.fieldData, 'Date Sample Request Letter Sent': letterByRid[String(r.recordId)] || '' } }));
+    var window = win;
+  } catch (e) {
+    writeLatest({ verdict: 'FAIL', status: 'FAIL', error: `FileMaker unreadable: ${e.message}`, population: null, note: 'NOT-MEASURED — cannot verify coverage' });
+    console.error(`FAIL — FileMaker unreadable: ${e.message}`);
+    process.exit(1);
+  }
+  const contacts = readJSON(join(ROOT, 'data', 'contacts.json'), {});
+  const set = await mergeGmailRecent(recentSet());
+  const runStale = runStaleToday();
+  const r = reconcileCoverage(records, { contacts, recentSet: set, runStale });
+
+  const out = { verdict: r.verdict, status: r.status, window, population: r.population, accounted: r.accounted,
+    covered: r.covered, uncovered: r.uncovered, leakedCount: r.leaked.length, reconciles: r.reconciles,
+    runStale, buckets: r.counts, leaked: r.leaked.slice(0, 20) };
+  writeLatest(out);
+
+  console.log(`Coverage reconciliation — window ${window}`);
+  console.log(`  population (outstanding in FM): ${r.population}`);
+  console.log(`  covered/actioned: ${r.covered}  (chaseable ${r.counts.chaseable} + suppressed14d ${r.counts.suppressed14d} + guardSuppressed ${r.counts.guardSuppressed} + noChase ${r.counts.noChase})`);
+  console.log(`  uncovered (accounted, NOT chased): ${r.uncovered}  (noVendorMap ${r.counts.noVendorMap} + needsConfirm ${r.counts.needsConfirm})`);
+  console.log(`  leaked (outstanding, NO bucket): ${r.leaked.length}`);
+  if (r.leaked.length) r.leaked.slice(0, 10).forEach((x) => console.log(`     ⚠ LEAK vid=${JSON.stringify(x.vid)} sku=${x.sku} — ${x.why}`));
+  console.log(`  reconciles (accounted+leaked==population): ${r.reconciles}   run-stale: ${runStale}`);
+  console.log(`  VERDICT: ${r.verdict}`);
+  process.exit(r.verdict === 'FAIL' ? 1 : 0);
+}
+main();
diff --git a/test/coverage-reconcile.test.cjs b/test/coverage-reconcile.test.cjs
new file mode 100644
index 0000000..065195e
--- /dev/null
+++ b/test/coverage-reconcile.test.cjs
@@ -0,0 +1,69 @@
+'use strict';
+// TK-12117 coverage-reconciliation negative test (ship-with-a-negative-test doctrine).
+// Proves the canary goes RED on an injected fault (an outstanding row in NO bucket = silent skip)
+// and GREEN only when the population is fully accounted + actioned.
+const assert = require('node:assert');
+const { reconcileCoverage } = require('../lib/sweep');
+
+// A resolvable vendor (chaseable) + a no-chase vendor as the "known good" contacts.
+const contacts = {
+  fabr: { name: 'Fabricut', sample_email: 'customers@fabricut.com', account_number: 'On File' },
+  spn: { name: 'Spoonflower', disposition: 'no-chase' },
+  wat: { name: 'Watts 1874', sample_email: 'sophie@watts1874.co.uk', account_number: 'On File', needs_confirm: true },
+};
+const row = (vid, sku, entered, wp = '', letter = '') => ({ fieldData: {
+  vid, 'combo sku': sku, 'today for client': entered, 'Date WP Sample Sent': wp, 'Date Sample Request Letter Sent': letter, 'Mfr Pattern': 'P-' + sku } });
+
+// 1. NEGATIVE — inject an outstanding row with EMPTY vid (the sweep drops it before grouping) → LEAKED → FAIL
+{
+  const recs = [ row('FABR', 'DWFC1', '09/10/2026'), row('', 'DWLEAK1', '09/11/2026') ];
+  const r = reconcileCoverage(recs, { contacts });
+  assert.equal(r.verdict, 'FAIL', `1 injected empty-vid leak must FAIL, got ${r.verdict}`);
+  assert.ok(r.leaked.length >= 1, '1 leaked row must be reported');
+  assert.equal(r.population, 2, '1 population must count both outstanding rows');
+  console.log(`(1) PASS — injected empty-vid leak -> FAIL (leaked=${r.leaked.length}, pop=${r.population})`);
+}
+
+// 2. CLEAN — a single resolvable, not-recently-emailed, not-needs-confirm row → PASS
+{
+  const recs = [ row('FABR', 'DWFC2', '09/10/2026') ];
+  const r = reconcileCoverage(recs, { contacts, recentSet: new Set() });
+  assert.equal(r.verdict, 'PASS', `2 clean must PASS, got ${r.verdict}`);
+  assert.equal(r.counts.chaseable, 1, '2 must be chaseable');
+  assert.equal(r.leaked.length, 0, '2 no leak');
+  console.log(`(2) PASS — clean chaseable row -> PASS (chaseable=${r.counts.chaseable})`);
+}
+
+// 3. UNCOVERED — an outstanding row whose vid has NO contact (no-vendor-map) → accounted but not chased → WARN
+{
+  const recs = [ row('NOSUCHVID', 'DWX3', '09/10/2026') ];
+  const r = reconcileCoverage(recs, { contacts });
+  assert.equal(r.verdict, 'WARN', `3 no-vendor-map must WARN, got ${r.verdict}`);
+  assert.equal(r.counts.noVendorMap, 1, '3 must be noVendorMap');
+  assert.equal(r.leaked.length, 0, '3 accounted, not leaked');
+  console.log(`(3) PASS — no-vendor-map row -> WARN (uncovered=${r.uncovered})`);
+}
+
+// 4. RUN-STALE — clean population but the scheduled run did not fire on a run-day → WARN
+{
+  const recs = [ row('FABR', 'DWFC4', '09/10/2026') ];
+  const r = reconcileCoverage(recs, { contacts, runStale: true });
+  assert.equal(r.verdict, 'WARN', `4 run-stale must WARN, got ${r.verdict}`);
+  console.log('(4) PASS — clean population but run missed on run-day -> WARN');
+}
+
+// 5. GUARD/RECENT reconcile — arrived-dup guard + recently-emailed both count as ACTIONED (covered) → PASS
+{
+  const recs = [
+    row('FABR', 'DWFC5', '09/08/2026'),                 // outstanding
+    row('FABR', 'DWFC5', '09/08/2026', '09/14/2026'),   // arrived same-date twin -> guard suppress
+    row('WAT', 'DWW5', '09/10/2026'),                   // needs_confirm vendor BUT recently emailed -> suppressed14d (covered)
+  ];
+  const r = reconcileCoverage(recs, { contacts, recentSet: new Set(['sophie@watts1874.co.uk']) });
+  assert.equal(r.counts.guardSuppressed, 1, '5 arrived twin -> guardSuppressed');
+  assert.equal(r.counts.suppressed14d, 1, '5 recently-emailed -> suppressed14d (covered, not needsConfirm WARN)');
+  assert.equal(r.verdict, 'PASS', `5 all actioned must PASS, got ${r.verdict}`);
+  console.log('(5) PASS — guard-suppressed + recently-emailed both actioned -> PASS');
+}
+
+console.log('\nALL COVERAGE-RECONCILE ASSERTIONS PASSED');

← 473c034 sample-followup: resolve MAJ (Majilite) + BRAND (Brand McKen  ·  back to Sample Followup Sweep  ·  auto-data-snapshot: 2026-09-23T16:24:32 (2 data files) — dat b9f7fd7 →