[object Object]

← back to Sample Followup Sweep

Sent-stamp watcher: dead-letter heartbeat + vid-keyed pull-forward (TK-12351)

5b98d5bffa85d2338a4d2da4656a6e3c55674851 · 2026-09-26 13:06:23 -0700 · Steve Abrams

Heartbeat to ~/.claude/skills/sample-followup/data/latest.json after each live pass
(PASS/WARN/FAIL): WARN on unresolved sends within 5d of aging out of the 21d search or
aged out in the last 7d, or when the pass could not measure; FAIL when a pass throws.
--dry prints it and never writes. Pull-forward date ownership now keys on any shared
resolved vid (Lincrusta sample vs main email), address fallback when unmapped. Unreadable
ledger now fails closed instead of overwriting it. Skip entries record sent_on.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NDCCv6ZcKPKfWxof41UzvC

Files touched

Diff

commit 5b98d5bffa85d2338a4d2da4656a6e3c55674851
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sat Sep 26 13:06:23 2026 -0700

    Sent-stamp watcher: dead-letter heartbeat + vid-keyed pull-forward (TK-12351)
    
    Heartbeat to ~/.claude/skills/sample-followup/data/latest.json after each live pass
    (PASS/WARN/FAIL): WARN on unresolved sends within 5d of aging out of the 21d search or
    aged out in the last 7d, or when the pass could not measure; FAIL when a pass throws.
    --dry prints it and never writes. Pull-forward date ownership now keys on any shared
    resolved vid (Lincrusta sample vs main email), address fallback when unmapped. Unreadable
    ledger now fails closed instead of overwriting it. Skip entries record sent_on.
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01NDCCv6ZcKPKfWxof41UzvC
---
 scripts/sent-stamp-core.mjs       |  95 +++++++++++++++++++++++++++++++---
 scripts/watch-sent-stamp.mjs      |  46 +++++++++++++++--
 test/sent-stamp-heartbeat.test.js | 105 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 233 insertions(+), 13 deletions(-)

diff --git a/scripts/sent-stamp-core.mjs b/scripts/sent-stamp-core.mjs
index 9da40e8..60dd4cb 100644
--- a/scripts/sent-stamp-core.mjs
+++ b/scripts/sent-stamp-core.mjs
@@ -100,31 +100,39 @@ export async function runPass({ msgs, ledger, now, dry, retrySecs, minAgeDays, m
   const ordered = msgs.filter(m => m && m.id && !m.error)   // metadata fetch failed — try again next pass
     .sort((a, b) => sendDateOf(a, now).date - sendDateOf(b, now).date);
   const decision = new Map(ordered.map(m => [m.id, shouldProcess(seen[m.id], { now, retrySecs, dry })]));
-  // An older non-terminal send in backoff must not let a newer send to the same recipient take the
+  // An older non-terminal send in backoff must not let a newer send to the same VENDOR take the
   // chase date first: if any newer send is due, pull every older unfinished one forward with it.
-  const recip = m => (String(m.to || '').toLowerCase().match(/[\w.+-]+@[\w.-]+\.\w+/g) || []).sort().join(',');
-  const dueRecips = new Set(ordered.filter(m => decision.get(m.id).go).map(recip));
+  // TK-12351: "same vendor" = any shared resolved vid, not the literal to: address — one vendor can
+  // be written to at two addresses (Lincrusta sample_email vs main_email). Address set is the
+  // fallback only when the recipient resolves to no vid.
+  const ownerKeys = m => {
+    const vids = vidsForRecipient(deps.emailVid, m.to);
+    if (vids.length) return vids.map(v => `vid:${v}`);
+    return [`to:${(String(m.to || '').toLowerCase().match(/[\w.+-]+@[\w.-]+\.\w+/g) || []).sort().join(',')}`];
+  };
+  const dueOwners = new Set(ordered.filter(m => decision.get(m.id).go).flatMap(ownerKeys));
   for (const m of ordered) {
     const d = decision.get(m.id);
-    if (!d.go && d.why === 'backoff' && dueRecips.has(recip(m))) decision.set(m.id, { go: true, why: 'retry-ahead-of-newer' });
+    if (!d.go && d.why === 'backoff' && ownerKeys(m).some(k => dueOwners.has(k))) decision.set(m.id, { go: true, why: 'retry-ahead-of-newer' });
   }
   for (const m of ordered) {
     const prev = seen[m.id];
     const d = decision.get(m.id);
     if (!d.go) continue;
     const vids = vidsForRecipient(deps.emailVid, m.to);
+    const sd = sendDateOf(m, now);
+    const sentOn = fmt(sd.date);
     if (!vids.length) {
       unmapped.add(String(m.to || '(no to)'));
-      if (!dry) { seen[m.id] = mergeEntry(prev, { skip: 'no vid for recipient', to: m.to || '', subject: m.subject || '' }, now); changed = true; }
+      // sent_on kept on skips too, so the dead-letter heartbeat can age an entry after it leaves the search.
+      if (!dry) { seen[m.id] = mergeEntry(prev, { skip: 'no vid for recipient', to: m.to || '', subject: m.subject || '', sent_on: sentOn, sent_on_source: sd.source }, now); changed = true; }
       results.push({ id: m.id, why: d.why, skip: 'no vid for recipient', to: m.to || '' });
       continue;
     }
-    const sd = sendDateOf(m, now);
-    const sentOn = fmt(sd.date);
     if (sd.source === 'fallback-today') log(`  ⚠ ${m.id}: no internalDate/Date header — stamping today ${sentOn}`);
     const win = chaseWindow(sd.date, minAgeDays, maxAgeDays);
     const body = await deps.getBody(m.id);
-    if (body == null) continue;                            // body fetch failed — not an outcome, try next pass
+    if (body == null) { results.push({ id: m.id, why: d.why, bodyFailed: true, to: m.to || '' }); continue; }   // not an outcome — retried next pass
     const r = await deps.stamp(vids, body, win, sentOn);
     const stamped = r.stamped || [], failed = Number(r.failed) || 0, covered = Number(r.covered) || 0;
     if (!dry) {
@@ -136,3 +144,74 @@ export async function runPass({ msgs, ledger, now, dry, retrySecs, minAgeDays, m
   }
   return { ledger: seen, changed, acted, unmapped: [...unmapped].sort(), results };
 }
+
+// ── Dead-letter heartbeat (TK-12351) ────────────────────────────────────────────────────────────
+// A send is only retried while the George search (newer_than:SEARCH_DAYS) still returns it. A
+// non-terminal entry that ages out is dropped silently — so this reports, for the fleet-health
+// rollup, which unresolved sends are about to fall off (or just did), and refuses PASS whenever the
+// pass could not see the whole population. Three states, never two: an unmeasured pass is WARN.
+const DAY = 86400e3;
+const parseSentOn = s => { const m = /^(\d{2})\/(\d{2})\/(\d{4})$/.exec(String(s || '')); return m ? new Date(+m[3], +m[1] - 1, +m[2]).getTime() : NaN; };
+const entryState = e => !e ? 'unprocessed' : isTerminal(e) ? 'terminal' : e.skip ? 'skip' : Number(e.failed) > 0 ? 'failed' : 'stamped:0';
+
+// graceMs: a partial pass (Gmail quota 500s hit this watcher several times an hour) is WARN only when no
+// FULLY-measured pass has completed within graceMs — the loop re-measures every 30s, so a lone transient
+// miss inside the grace is not a finding, while a persistent one (no full measure for 30 min) is.
+// Grace covers only the George/Gmail-side misses (search, metadata, body). FileMaker errors, an empty
+// population and an unreadable ledger get none: those are not the known-transient quota class.
+export function buildHeartbeat({ ledger = {}, msgs = [], results = [], now, searchDays, nearDays = 5, recentDays = 7, searchErr = null, ledgerErr = null, dry = false, lastFullMeasureAt = null, graceMs = 30 * 60e3 }) {
+  const good = msgs.filter(m => m && m.id && !m.error);
+  const metaFailed = msgs.filter(m => m && m.error).length;
+  const seenIds = new Set(good.map(m => m.id));
+  const pop = { sends_seen: good.length, terminal: 0, non_terminal: 0, unprocessed: 0, ledger_entries: Object.keys(ledger).length };
+  const near_expiry = [];
+  for (const m of good) {
+    const e = ledger[m.id], state = entryState(e);
+    if (state === 'terminal') { pop.terminal++; continue; }
+    pop.non_terminal++; if (state === 'unprocessed') pop.unprocessed++;
+    const sd = sendDateOf(m, now);
+    const daysLeft = searchDays - (now - sd.date.getTime()) / DAY;
+    if (daysLeft <= nearDays) near_expiry.push({ id: m.id, to: m.to || e?.to || '', vids: e?.vids || [], sent_on: fmt(sd.date), days_left: +daysLeft.toFixed(1), state, attempts: Number(e?.attempts) || (e ? 1 : 0) });
+  }
+  const not_measured = [], hard = [];
+  if (searchErr) not_measured.push(`George search: ${searchErr}`);
+  if (metaFailed) not_measured.push(`${metaFailed} message metadata fetch(es) failed`);
+  const bodyFailed = results.filter(r => r.bodyFailed).length;
+  if (bodyFailed) not_measured.push(`${bodyFailed} letter body fetch(es) failed`);
+  const fmFailed = results.filter(r => Number(r.failed) > 0).length;
+  if (fmFailed) hard.push(`${fmFailed} send(s) hit a FileMaker lookup/commit error`);
+  if (ledgerErr) hard.push(`stamp-ledger unreadable: ${ledgerErr}`);
+  if (!searchErr && good.length === 0) hard.push(`search returned 0 sends in ${searchDays}d — empty population, query or mailbox suspect`);
+  const fullMeasure = !not_measured.length && !hard.length;
+  const lastFull = fullMeasure ? now : lastFullMeasureAt;
+  const withinGrace = lastFull != null && now - lastFull <= graceMs;
+  not_measured.push(...hard);
+  // Just-expired: only knowable when the search was complete (else "not returned" means nothing).
+  const recently_expired = [];
+  if (!searchErr && !metaFailed) {
+    for (const [id, e] of Object.entries(ledger)) {
+      if (seenIds.has(id) || isTerminal(e)) continue;
+      const t = Number.isFinite(parseSentOn(e.sent_on)) ? parseSentOn(e.sent_on) : Date.parse(e.first_try || e.at || '');
+      if (!Number.isFinite(t)) continue;                   // legacy undated entry — can't age it
+      const age = (now - t) / DAY;
+      if (age > searchDays && age <= searchDays + recentDays) recently_expired.push({ id, to: e.to || '', vids: e.vids || [], sent_on: e.sent_on || fmt(new Date(t)), state: entryState(e), attempts: Number(e.attempts) || 1 });
+    }
+  }
+  const unmeasuredWarn = hard.length > 0 || (!fullMeasure && !withinGrace);
+  const verdict = (unmeasuredWarn || near_expiry.length || recently_expired.length) ? 'WARN' : 'PASS';
+  const bits = [`${pop.terminal}/${pop.sends_seen} sends in ${searchDays}d resolved`];
+  if (near_expiry.length) bits.push(`${near_expiry.length} unresolved within ${nearDays}d of aging out`);
+  if (recently_expired.length) bits.push(`${recently_expired.length} aged out unresolved in last ${recentDays}d`);
+  if (not_measured.length) bits.push(`${unmeasuredWarn ? 'NOT MEASURED' : 'partial pass (full measure ' + Math.round((now - lastFull) / 1000) + 's ago)'}: ${not_measured.join('; ')}`);
+  return {
+    skill: 'sample-followup', source: 'watch-sent-stamp', generated_at: new Date(now).toISOString(), dry,
+    verdict, status: verdict, summary: bits.join(' · '),
+    full_measure: fullMeasure, last_full_measure_at: lastFull == null ? null : new Date(lastFull).toISOString(),
+    search_days: searchDays, near_days: nearDays, population: pop, near_expiry, recently_expired, not_measured,
+  };
+}
+
+export function failHeartbeat(err, now) {
+  return { skill: 'sample-followup', source: 'watch-sent-stamp', generated_at: new Date(now).toISOString(), dry: false,
+    verdict: 'FAIL', status: 'FAIL', summary: `pass threw: ${err}`, error: String(err) };
+}
diff --git a/scripts/watch-sent-stamp.mjs b/scripts/watch-sent-stamp.mjs
index 641d694..c360598 100644
--- a/scripts/watch-sent-stamp.mjs
+++ b/scripts/watch-sent-stamp.mjs
@@ -4,10 +4,16 @@
 // vendor's outstanding memos. Drafting never stamps — only a real send does. Idempotent via a ledger.
 //   node scripts/watch-sent-stamp.mjs           # one pass
 //   node scripts/watch-sent-stamp.mjs --loop    # poll every POLL_SECS (default 45s)
-import { readFileSync, writeFileSync } from 'node:fs'; import { homedir } from 'node:os'; import { join } from 'node:path'; import http from 'node:http';
+import { readFileSync, writeFileSync, mkdirSync, renameSync } from 'node:fs'; import { homedir } from 'node:os'; import { join } from 'node:path'; import http from 'node:http';
 const ROOT = join(homedir(), 'Projects/sample-followup-sweep');
 const LEDGER = join(ROOT, 'data/stamp-ledger.json');
-import { chaseWindow, buildEmailVid, runPass } from './sent-stamp-core.mjs';
+import { chaseWindow, buildEmailVid, runPass, buildHeartbeat, failHeartbeat } from './sent-stamp-core.mjs';
+// TK-12351: fleet-health heartbeat (fleet-health-rollup globs ~/.claude/skills/*/data/latest.json).
+// Written only by a LIVE pass, after its ledger write. A --dry pass prints what it would say and
+// never writes, so a dry/manual run can never masquerade as the live watcher's heartbeat.
+const HB_DIR = join(homedir(), '.claude/skills/sample-followup/data');
+const HB = join(HB_DIR, 'latest.json');
+const NEAR_DAYS = 5;
 import slugAliases from '../lib/slug-aliases.cjs';
 const DB = 'WALLPAPER', LAYOUT = 'Report for old memo samples';
 const FIELD_SENT = 'Date Email Sent to Vendor after 10 Days';
@@ -119,9 +125,31 @@ async function stampVids(vids, bodyText, win, sentOn) {
   return { stamped, failed, covered };
 }
 
+function emitHeartbeat(hb) {
+  if (hb.dry) { console.log(`  [heartbeat · dry — NOT written] ${hb.verdict}: ${hb.summary}`); return; }
+  try {
+    mkdirSync(HB_DIR, { recursive: true });
+    const tmp = `${HB}.tmp-${process.pid}`;
+    writeFileSync(tmp, JSON.stringify(hb, null, 2)); renameSync(tmp, HB);   // atomic: rollup never reads a torn file
+  } catch (e) { console.warn(`  ⚠ heartbeat write failed: ${e.message}`); }
+}
+function readLedger() {
+  try { return { ledger: JSON.parse(readFileSync(LEDGER, 'utf8')) }; }
+  catch (e) { return { ledger: {}, err: e.code === 'ENOENT' ? null : e.message }; }
+}
+
 let lastUnmappedKey = '';
+let lastHeartbeat = null, lastFullMeasureAt = null;
 async function pass() {
-  const ledger = readJSON(LEDGER, {});
+  const { ledger, err: ledgerErr } = readLedger();
+  if (ledgerErr) {
+    // Fail closed: an empty stand-in ledger would re-process every send and then OVERWRITE the real
+    // (merely unreadable) ledger, destroying its attempt history. Report, don't act.
+    console.warn(`  ⚠ stamp-ledger unreadable (${ledgerErr}) — skipping this pass, ledger left untouched`);
+    lastHeartbeat = buildHeartbeat({ ledger: {}, msgs: [], now: Date.now(), searchDays: SEARCH_DAYS, nearDays: NEAR_DAYS, ledgerErr, dry: DRY_RUN, lastFullMeasureAt });
+    emitHeartbeat(lastHeartbeat);
+    return 0;
+  }
   // NB: the em-dash in the full subject breaks Gmail matching over HTTP — match the ASCII prefix.
   const { msgs, err } = await gsearch(`in:sent subject:"Outstanding Memos" newer_than:${SEARCH_DAYS}d`);
   if (err) console.warn(`  ⚠ George search: ${err} (${msgs.length} msg(s) read)`);
@@ -136,10 +164,18 @@ async function pass() {
   lastUnmappedKey = key;
   if (r.changed) writeFileSync(LEDGER, JSON.stringify(r.ledger, null, 2));
   if (!r.acted) console.log(`  (no ${DRY_RUN ? 'stampable' : 'new sent'} follow-ups) — ${new Date().toLocaleTimeString()}`);
+  lastHeartbeat = buildHeartbeat({ ledger: r.ledger, msgs, results: r.results, now: Date.now(), searchDays: SEARCH_DAYS, nearDays: NEAR_DAYS, searchErr: err || null, dry: DRY_RUN, lastFullMeasureAt });
+  if (lastHeartbeat.full_measure) lastFullMeasureAt = Date.parse(lastHeartbeat.last_full_measure_at);
+  emitHeartbeat(lastHeartbeat);
   return r.acted;
 }
 
 const LOOP = process.argv.includes('--loop');
 console.log(`watch-sent-stamp — chase window ${chaseWindow(new Date(), MIN_AGE_DAYS, MAX_AGE_DAYS)} (per-send, from its send date) · Sent scan ${SEARCH_DAYS}d — ${LOOP ? `LOOP every ${POLL_SECS}s` : 'one pass'}`);
-if (!LOOP) { await pass(); process.exit(0); }
-for (;;) { try { await pass(); } catch (e) { console.error('pass err:', e.message); } await new Promise(r => setTimeout(r, POLL_SECS * 1000)); }
+const failed = e => { console.error('pass err:', e.message); if (!DRY_RUN) emitHeartbeat(failHeartbeat(e.message, Date.now())); };
+if (!LOOP) {
+  try { await pass(); } catch (e) { failed(e); process.exit(1); }
+  if (DRY_RUN) console.log(JSON.stringify(lastHeartbeat, null, 2));
+  process.exit(0);
+}
+for (;;) { try { await pass(); } catch (e) { failed(e); } await new Promise(r => setTimeout(r, POLL_SECS * 1000)); }
diff --git a/test/sent-stamp-heartbeat.test.js b/test/sent-stamp-heartbeat.test.js
new file mode 100644
index 0000000..a418b00
--- /dev/null
+++ b/test/sent-stamp-heartbeat.test.js
@@ -0,0 +1,105 @@
+'use strict';
+// TK-12351: dead-letter heartbeat + vid-keyed pull-forward. Negative tests: each check must go RED
+// on its injected fault. No FM, no network, no fs.
+const assert = require('node:assert/strict');
+const path = require('node:path');
+const { pathToFileURL } = require('node:url');
+
+(async () => {
+  const core = await import(pathToFileURL(path.join(__dirname, '../scripts/sent-stamp-core.mjs')).href);
+  const DAY = 86400e3;
+  const NOW = new Date(2026, 8, 26, 9, 0, 0).getTime();
+  const at = daysAgo => String(NOW - daysAgo * DAY);
+  const base = { now: NOW, searchDays: 21, nearDays: 5 };
+
+  // ── (a) heartbeat ──────────────────────────────────────────────────────────────────────────
+  const msgs = [
+    { id: 'fresh', to: 'a@v.com', internalDate: at(2) },
+    { id: 'old-done', to: 'b@v.com', internalDate: at(19) },
+    { id: 'old-stuck', to: 'Lin <samples@lincrusta.com>', internalDate: at(18) },   // 3d left
+  ];
+  const clean = { fresh: { stamped: 1, failed: 0 }, 'old-done': { stamped: 2, failed: 0 }, 'old-stuck': { stamped: 1, failed: 0 } };
+  const hbClean = core.buildHeartbeat({ ...base, ledger: clean, msgs });
+  assert.equal(hbClean.verdict, 'PASS', 'clean → PASS');
+  assert.equal(hbClean.status, 'PASS');
+  assert.deepEqual(hbClean.population, { sends_seen: 3, terminal: 3, non_terminal: 0, unprocessed: 0, ledger_entries: 3 });
+  console.log('(a1) PASS — clean ledger → PASS, population carried beside observed');
+
+  const stuck = { ...clean, 'old-stuck': { vids: ['LIN'], stamped: 0, failed: 0, attempts: 40, to: 'samples@lincrusta.com' } };
+  const hbStuck = core.buildHeartbeat({ ...base, ledger: stuck, msgs });
+  assert.equal(hbStuck.verdict, 'WARN', 'near-expiry non-terminal → WARN');
+  assert.equal(hbStuck.near_expiry.length, 1);
+  assert.equal(hbStuck.near_expiry[0].id, 'old-stuck');
+  assert.equal(hbStuck.near_expiry[0].state, 'stamped:0');
+  assert.equal(hbStuck.near_expiry[0].days_left, 3);
+  assert.equal(hbStuck.near_expiry[0].sent_on, '09/08/2026');
+  // a non-terminal entry with plenty of runway is NOT a dead-letter warning (no nagging on normal retries)
+  const young = { ...clean, fresh: { skip: 'no vid for recipient' } };
+  assert.equal(core.buildHeartbeat({ ...base, ledger: young, msgs }).verdict, 'PASS', 'non-terminal with 19d left is not near expiry');
+  console.log('(a2) PASS — non-terminal within 5d of aging out → WARN; far from expiry stays PASS');
+
+  const hbSearchErr = core.buildHeartbeat({ ...base, ledger: clean, msgs, searchErr: 'HTTP 502' });
+  assert.equal(hbSearchErr.verdict, 'WARN', 'search error must never be PASS');
+  assert.match(hbSearchErr.not_measured.join(), /HTTP 502/);
+  assert.equal(core.buildHeartbeat({ ...base, ledger: clean, msgs, searchErr: 'truncated at 10 pages' }).verdict, 'WARN');
+  assert.equal(core.buildHeartbeat({ ...base, ledger: {}, msgs: [] }).verdict, 'WARN', '0 of 0 is NOT-MEASURED, not PASS');
+  assert.equal(core.buildHeartbeat({ ...base, ledger: clean, msgs, results: [{ id: 'x', failed: 1 }] }).verdict, 'WARN', 'FM lookup error → WARN');
+  assert.equal(core.buildHeartbeat({ ...base, ledger: clean, msgs, results: [{ id: 'x', bodyFailed: true }] }).verdict, 'WARN', 'body fetch fail → WARN');
+  assert.equal(core.buildHeartbeat({ ...base, ledger: clean, msgs: [...msgs, { id: 'e', error: 'fetch-failed' }] }).verdict, 'WARN', 'metadata fail → WARN');
+  assert.equal(core.buildHeartbeat({ ...base, ledger: clean, msgs, ledgerErr: 'Unexpected token' }).verdict, 'WARN', 'unreadable ledger → WARN');
+  // transient-miss grace: a partial pass right after a FULL measure is not a finding; a persistent one is
+  const partial = { ...base, ledger: clean, msgs, results: [{ id: 'x', bodyFailed: true }] };
+  assert.equal(core.buildHeartbeat({ ...partial, lastFullMeasureAt: NOW - 60e3 }).verdict, 'PASS', 'lone transient miss inside grace');
+  assert.equal(core.buildHeartbeat({ ...partial, lastFullMeasureAt: NOW - 31 * 60e3 }).verdict, 'WARN', 'no full measure for >30 min → WARN');
+  assert.equal(core.buildHeartbeat({ ...base, ledger: clean, msgs, searchErr: 'HTTP 500', lastFullMeasureAt: NOW - 31 * 60e3 }).verdict, 'WARN');
+  assert.equal(core.buildHeartbeat({ ...base, ledger: {}, msgs: [], lastFullMeasureAt: NOW - 60e3 }).verdict, 'WARN', 'empty population gets no grace');
+  assert.equal(core.buildHeartbeat({ ...base, ledger: clean, msgs, ledgerErr: 'bad', lastFullMeasureAt: NOW - 60e3 }).verdict, 'WARN', 'unreadable ledger gets no grace');
+  assert.equal(core.buildHeartbeat({ ...partial, lastFullMeasureAt: NOW - 60e3, ledger: stuck }).verdict, 'WARN', 'grace never hides a near-expiry finding');
+  assert.equal(core.buildHeartbeat({ ...base, ledger: clean, msgs, results: [{ id: 'x', failed: 1 }], lastFullMeasureAt: NOW - 60e3 }).verdict, 'WARN', 'FileMaker errors get no grace');
+  assert.equal(hbClean.full_measure, true); assert.equal(hbClean.last_full_measure_at, new Date(NOW).toISOString());
+  console.log('(a3) PASS — unmeasured (search error / truncated / empty / FM error / body / metadata / ledger) → WARN, never PASS');
+
+  // just-aged-out unresolved entry (no longer returned by the search) → WARN; undated legacy / long-gone → no nag
+  const expired = { ...clean, gone: { skip: 'no vid for recipient', sent_on: core.fmt(new Date(NOW - 23 * DAY)) } };
+  const hbExp = core.buildHeartbeat({ ...base, ledger: expired, msgs });
+  assert.equal(hbExp.verdict, 'WARN'); assert.equal(hbExp.recently_expired[0].id, 'gone');
+  assert.equal(core.buildHeartbeat({ ...base, ledger: expired, msgs, searchErr: 'x' }).recently_expired.length, 0, 'incomplete search cannot claim expiry');
+  const ancient = { ...clean, legacy: { stamped: 0 }, long: { skip: 'x', sent_on: '06/01/2026' } };
+  assert.equal(core.buildHeartbeat({ ...base, ledger: ancient, msgs }).verdict, 'PASS', 'decays: undated/long-expired entries do not pin amber forever');
+  console.log('(a4) PASS — aged out unresolved in last 7d → WARN; decays after');
+
+  const hbFail = core.failHeartbeat('boom', NOW);
+  assert.equal(hbFail.verdict, 'FAIL'); assert.equal(hbFail.status, 'FAIL');
+  console.log('(a5) PASS — a pass that threw → FAIL');
+
+  // skips now carry sent_on so they can be aged after leaving the search
+  const rs = await core.runPass({ msgs: [{ id: 'u', to: 'x@nowhere.example', internalDate: at(4) }], ledger: {}, now: NOW, dry: false, retrySecs: 900, minAgeDays: 10, maxAgeDays: 60,
+    deps: { emailVid: {}, getBody: async () => '', stamp: async () => ({ stamped: [] }) } });
+  assert.equal(rs.ledger.u.sent_on, core.fmt(new Date(NOW - 4 * DAY)));
+
+  // ── (b) vid-keyed pull-forward (Lincrusta: sample_email ≠ main_email, one vendor) ──────────
+  const ev = core.buildEmailVid([{ slug: 'lincrusta', vid: 'LIN' }], { lincrusta: { sample_email: 'samples@lincrusta.com', main_email: 'info@lincrusta.com' } });
+  const older = { id: 'old', to: 'Samples <samples@lincrusta.com>', internalDate: at(13) };
+  const newer = { id: 'new', to: 'info@lincrusta.com', internalDate: at(2) };
+  const led = { old: { vids: ['LIN'], stamped: 0, last_try: new Date(NOW - 60e3).toISOString() } };   // older is in backoff
+  const order = [];
+  await core.runPass({ msgs: [newer, older], ledger: led, now: NOW, dry: false, retrySecs: 900, minAgeDays: 10, maxAgeDays: 60,
+    deps: { emailVid: ev, getBody: async id => id, stamp: async (v, body, w, sentOn) => { order.push(`${body}@${sentOn}`); return { stamped: [] }; } } });
+  assert.deepEqual(order, [`old@${core.fmt(new Date(NOW - 13 * DAY))}`, `new@${core.fmt(new Date(NOW - 2 * DAY))}`],
+    'older send to a DIFFERENT address of the same vid must run first and own the chase date');
+  // unrelated vendor in backoff is NOT pulled forward
+  const ev2 = core.buildEmailVid([{ slug: 'lincrusta', vid: 'LIN' }, { slug: 'k', vid: 'KRA' }], { lincrusta: { main_email: 'info@lincrusta.com' }, k: { sample_email: 'k@kravet.com' } });
+  const order2 = [];
+  await core.runPass({ msgs: [{ id: 'new', to: 'info@lincrusta.com', internalDate: at(2) }, { id: 'kold', to: 'k@kravet.com', internalDate: at(13) }],
+    ledger: { kold: { vids: ['KRA'], stamped: 0, last_try: new Date(NOW - 60e3).toISOString() } }, now: NOW, dry: false, retrySecs: 900, minAgeDays: 10, maxAgeDays: 60,
+    deps: { emailVid: ev2, getBody: async id => id, stamp: async (v, body) => { order2.push(body); return { stamped: [] }; } } });
+  assert.deepEqual(order2, ['new'], 'a different vendor in backoff stays in backoff');
+  // address fallback when nothing resolves: same unmapped address still pulls forward (reaches the skip path)
+  const r3 = await core.runPass({ msgs: [{ id: 'n', to: 'z@x.example', internalDate: at(2) }, { id: 'o', to: 'Z <z@x.example>', internalDate: at(13) }],
+    ledger: { o: { skip: 'no vid for recipient', last_try: new Date(NOW - 60e3).toISOString() } }, now: NOW, dry: false, retrySecs: 900, minAgeDays: 10, maxAgeDays: 60,
+    deps: { emailVid: {}, getBody: async () => '', stamp: async () => ({ stamped: [] }) } });
+  assert.equal(r3.results.find(x => x.id === 'o')?.why, 'retry-ahead-of-newer', 'address fallback keeps unmapped pull-forward');
+  console.log('(b) PASS — pull-forward keyed on resolved vid (Lincrusta alias), unrelated vendor untouched, address fallback kept');
+
+  console.log('sent-stamp-heartbeat: ALL PASS');
+})().catch(e => { console.error('FAIL:', e.message); process.exit(1); });

← 60334c7 5x report: sweep 5 + Cody findings (TK-12320)  ·  back to Sample Followup Sweep  ·  stamp_aliases: stamp-only recipient aliases (WQ contract@/li d7b4973 →