{"slug":"sample-followup-sweep","total":256,"limit":100,"offset":0,"since":null,"commits":[{"hash":"3951f3f","date":"2026-09-26 19:22:52 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T19:22:47 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"44a501a","date":"2026-09-26 18:52:19 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T18:52:13 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"4a1b0c2","date":"2026-09-26 18:21:37 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T18:21:31 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"3866478","date":"2026-09-26 17:51:01 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T17:50:54 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"3b74eb7","date":"2026-09-26 17:20:29 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T17:20:23 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"3922937","date":"2026-09-26 16:49:40 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T16:49:35 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"24363fb","date":"2026-09-26 16:19:11 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T16:19:05 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"96007d0","date":"2026-09-26 15:48:39 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T15:48:33 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"9eef1f6","date":"2026-09-26 15:18:11 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T15:18:06 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"8ce0936","date":"2026-09-26 14:47:41 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T14:47:36 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"b1007c1","date":"2026-09-26 14:17:12 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T14:17:06 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"65202c7","date":"2026-09-26 13:46:41 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T13:46:36 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"4eb4951","date":"2026-09-26 13:16:24 -0700","author":"Steve Abrams","subject":"stamp_aliases: drop unverified RBL rebelwalls alias (RS13181 already stamped via gimmersta 09-04; Cody #3), document WQ alias evidence (TK-12351)","body":""},{"hash":"d8151a8","date":"2026-09-26 13:16:09 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T13:16:02 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"d7b4973","date":"2026-09-26 13:10:29 -0700","author":"Steve Abrams","subject":"stamp_aliases: stamp-only recipient aliases (WQ contract@/lindsaydetwiler@, RBL support@rebelwalls.com); send routing unaffected + test (TK-12351)","body":""},{"hash":"5b98d5b","date":"2026-09-26 13:06:23 -0700","author":"Steve Abrams","subject":"Sent-stamp watcher: dead-letter heartbeat + vid-keyed pull-forward (TK-12351)","body":"Heartbeat to ~/.claude/skills/sample-followup/data/latest.json after each live pass\n(PASS/WARN/FAIL): WARN on unresolved sends within 5d of aging out of the 21d search or\naged out in the last 7d, or when the pass could not measure; FAIL when a pass throws.\n--dry prints it and never writes. Pull-forward date ownership now keys on any shared\nresolved vid (Lincrusta sample vs main email), address fallback when unmapped. Unreadable\nledger now fails closed instead of overwriting it. Skip entries record sent_on.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01NDCCv6ZcKPKfWxof41UzvC"},{"hash":"60334c7","date":"2026-09-26 12:47:11 -0700","author":"Steve Abrams","subject":"5x report: sweep 5 + Cody findings (TK-12320)","body":""},{"hash":"5181a26","date":"2026-09-26 12:46:59 -0700","author":"Steve Abrams","subject":"5x sweep 5 (Cody FIX FIRST #2): refuse empty follow-up letters — compose() throws on 0 rows, send-one 409s a 0-item vendor, no send button on empty rows (TK-12320)","body":""},{"hash":"18d9697","date":"2026-09-26 12:45:04 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T12:44:57 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"0403496","date":"2026-09-26 12:14:24 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T12:14:18 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"744ed80","date":"2026-09-26 11:43:46 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T11:43:40 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"1e71744","date":"2026-09-26 11:13:14 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T11:13:09 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"a6df529","date":"2026-09-26 10:42:30 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T10:42:21 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"02ec413","date":"2026-09-26 10:11:52 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T10:11:45 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"197cbae","date":"2026-09-26 09:22:27 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T09:21:27 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"f5257c2","date":"2026-09-26 09:11:42 -0700","author":"Steve Abrams","subject":"5x report (TK-12320)","body":""},{"hash":"a4ab269","date":"2026-09-26 09:08:43 -0700","author":"Steve Abrams","subject":"5x sweep 2: console sort/render no longer crash on vendors with 0 outstanding items (TK-12320)","body":""},{"hash":"32af305","date":"2026-09-26 08:58:28 -0700","author":"Steve Abrams","subject":"5x sweep 1: npm test runs .cjs suites and fails on any failing file (TK-12320)","body":""},{"hash":"d523fb1","date":"2026-09-26 08:56:41 -0700","author":"Steve Abrams","subject":"sent-stamp watcher: fold review findings (never overwrite a chase date)","body":"- covered-only is no longer terminal: a sibling item in the same letter\n  may not be in FileMaker yet, so the send keeps retrying.\n- per-record read-before-write: skip any record that already carries a\n  chase date, independent of the already-stamped set; refuse to stamp a\n  send if that set hit its 800-row cap.\n- an older unfinished send in backoff is pulled forward when a newer send\n  to the same recipient is due, so the older letter keeps its date.\nTests extended; negative fault injection still goes red. TK-12320\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01NDCCv6ZcKPKfWxof41UzvC"},{"hash":"523a32c","date":"2026-09-26 08:52:37 -0700","author":"Steve Abrams","subject":"watch-sent-stamp: refuse unknown args instead of running a live pass (TK-12320)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01TbUKLFLXi7LEQcGyGeYqp9"},{"hash":"a884b80","date":"2026-09-26 08:50:38 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T08:50:16 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"a6b53a0","date":"2026-09-26 08:38:29 -0700","author":"Steve Abrams","subject":"sent-stamp watcher: retry skipped/zero sends, stamp the real send date","body":"A ledger entry now only suppresses re-processing once the send actually\nstamped (or found its letter items already stamped) with no failed commit.\nskip / stamped:0 sends are retried (15 min backoff) inside a 21-day Sent\nscan, so sends that landed before their email->vid mapping existed are no\nlonger poisoned forever. The chase date is the message's send date\n(internalDate), sends are processed oldest-first so the first letter owns\nthe date, FM/George lookup errors no longer masquerade as 'nothing to\nstamp', and contact-only vendors (Phillip Jeffries) map via the\nslug-derived vid. Pure logic moved to sent-stamp-core.mjs with a negative\ntest. TK-12320\n\nCo-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01NDCCv6ZcKPKfWxof41UzvC"},{"hash":"f631b44","date":"2026-09-26 08:19:22 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-26T08:19:11 (1 data files) — data/resend-queue.json","body":""},{"hash":"c07d434","date":"2026-09-25 13:57:36 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-25T13:56:04 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"5843b22","date":"2026-09-25 08:13:15 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-25T08:13:10 (1 data files) — data/resend-queue.json","body":""},{"hash":"a03c8b7","date":"2026-09-25 07:12:19 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-25T07:12:13 (2 data files) — data/outstanding-snapshot.json data/reconciled-draft-ledger.json","body":""},{"hash":"b95d293","date":"2026-09-24 12:49:31 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-24T12:49:23 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"17e8c13","date":"2026-09-24 12:18:43 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-24T12:18:37 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"ae3a82b","date":"2026-09-24 09:44:19 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-24T09:44:11 (3 data files) — data/coverage-reconcile/latest.json data/draft-ledger.json data/runs/scheduled-09-24-2026.json","body":""},{"hash":"616e3a8","date":"2026-09-24 09:36:47 -0700","author":"Steve Abrams","subject":"sample-followup: fix TK-12091 window regression + shared window + canary tripwire","body":"Part 1 (DTD panel verdict A): restore the FULL active [today-60..today-10] query\nwindow every run. TK-12091 (a11a644) had narrowed scheduled-run.mjs to a\nday-of-week band, silently reopening TK-12013/14's permanent-hole bug — a live\ncanary found 15 outstanding stragglers (some 56d old, incl. DWTT70793) never\ndrafted. Dedup (Sent-stamp + draft-ledger) makes the wide re-query a safe no-op.\n\nPart 2 (Cody's co-required fix): single source of truth for the window —\nfollowupWindow() in lib/sweep.js, called by BOTH scheduled-run.mjs and the\ncoverage canary, so production and audit can never drift again. Canary now runs\nwindowCoversActiveBand() as a TK-12091-regression tripwire: if production's\nwindow is ever re-narrowed below the full active band, the canary goes FAIL\ninstead of silently auditing a wider window than production chases. Ships a\nnegative test (test 8) proving the tripwire goes red on an injected narrow window.\n\nVerified: window now 07/26..09/14; DWTT70793/Thibaut back in candidate set;\ncanary leaked=0, band covers=true; 8/8 tests pass. sweep()'s orphaned DOW logic\nis dead code (nothing calls it) — left untouched, noted.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"9f289bf","date":"2026-09-24 09:12:32 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-24T09:12:24 (1 data files) — data/coverage-reconcile/latest.json","body":""},{"hash":"83b47fa","date":"2026-09-24 08:59:12 -0700","author":"Steve Abrams","subject":"sample-followup: LA Walls/DWLC1059 tracked as known-unresolvable (TK-12119)","body":"Add DWLC1059 (LA Walls pattern 23003) to known-unresolvable set — vendor has\nno vid anywhere in the fleet, so sweep can't chase it. Bucket it as\nnoVendorMap (accounted/WARN) instead of leaked (FAIL). Canary verdict:\nFAIL → WARN, leaked 1→0. Reversible: remove SKU from set or delete set entry.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"b9a4f66","date":"2026-09-24 08:40:59 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-24T08:40:54 (2 data files) — data/coverage-reconcile/latest.json data/tk12118-vid-backfill-restore-map.json","body":""},{"hash":"8c3b575","date":"2026-09-24 08:29:04 -0700","author":"Steve Abrams","subject":"sample-followup: fix tk12118 SKU guard to verify on REPORT ON SAMPLES ORDERED (TK-12118)","body":"'combo sku' is findable but does not serialize into fieldData on the write layout\n(Report for old memo samples), so the SKU-match guard always saw \"\" and skipped.\nVerify the SKU on REPORT ON SAMPLES ORDERED (same base table, same recordId space,\nfield reads correctly); write vid on the write layout; verify the write via the\ncanary leaked-count (vid does not read back on either layout). Backfill landed:\ncanary leaked 4->1.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"d70e93d","date":"2026-09-24 08:09:28 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-24T08:09:22 (3 data files) — data/coverage-reconcile/latest.json data/resend-queue.json data/tk12109-stamp-restore-map.json","body":""},{"hash":"32a76cf","date":"2026-09-24 08:00:53 -0700","author":"Steve Abrams","subject":"sample-followup: canary no longer counts deferred recipient-busy rows as covered (TK-12119)","body":"Split the recipient-busy suppression by age: a fresh batching deferral (<=24d =\n10-day trigger + one 14-day window) counts as covered, but a row deferred past\nthat window escalates to recipientBusyStale -> uncovered -> WARN. Closes the\nfalse-green where a perpetually-recontacted vendor's never-chased sku hid as\n\"covered.\" First live run surfaced 33 real stale-deferred rows. Ships a negative\ntest proving the aged row flips from the old covered/PASS to WARN.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"4b93811","date":"2026-09-24 07:06:32 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-24T07:06:26 (2 data files) — data/outstanding-snapshot.json data/reconciled-draft-ledger.json","body":""},{"hash":"367e1e4","date":"2026-09-23 18:30:34 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-23T18:30:30 (1 data files) — data/coverage-reconcile/latest.json","body":""},{"hash":"5b5b893","date":"2026-09-23 17:33:14 -0700","author":"Steve Abrams","subject":"sample-followup: draft gated vid-backfill for 3 verified leaked SKUs (TK-12118)","body":""},{"hash":"b9f7fd7","date":"2026-09-23 16:24:40 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-23T16:24:32 (2 data files) — data/contacts.json.bak-20260923-160215-TK-MAJBRAND data/coverage-reconcile/latest.json","body":""},{"hash":"1d2b680","date":"2026-09-23 16:20:15 -0700","author":"Steve Abrams","subject":"sample-followup: coverage-reconciliation canary (silent-skip false-green safety net) — TK-12117","body":"READ-ONLY scripts/coverage-reconcile.mjs queries live FileMaker for the true\noutstanding population (two-read vid+letterSent join) and reconciles it against\nthe sweep's own bucketing (lib/sweep.js reconcileCoverage). A row outstanding in\nFM but in NO sweep bucket = LEAKED = FAIL; never PASS on 'it ran'. Emits\nPASS/WARN/FAIL + latest.json. Ships test/coverage-reconcile.test.cjs (5 asserts,\nincl injected-leak FAIL) + a --self-test seam. First live run FOUND 4 real\nempty-vid silent skips (FAIL). launchd install drafted to pending-approval (gated).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"473c034","date":"2026-09-23 16:09:36 -0700","author":"Steve Abrams","subject":"sample-followup: resolve MAJ (Majilite) + BRAND (Brand McKenzie) vendor-map holes (TK-12114)","body":"MAJ = Majilite -> jabshire@majilite.com (James Abshire), confirmed by DW's own\nrepeated 'New Sample Request' outbound (2026-09-10/21/22) + replies. BRAND =\nBrand McKenzie -> sales@sancarwallcovering.com (Sancar acct 1674444, its US\ndistributor; replies to our sample requests/follow-ups), needs_confirm w/ direct\nrichard@brandmckenzie.com as documented alternate. no-vendor-map count 2 -> 0.\nDRAFT/dry-run only, nothing sent.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"ab598e5","date":"2026-09-23 15:52:46 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-23T15:52:37 (3 data files) — data/reconciled-draft-ledger.json.bak-20260923-153620-TK12107 data/runs/scheduled-09-23-2026.json data/stamp-ledger.json","body":""},{"hash":"05177f2","date":"2026-09-23 15:47:37 -0700","author":"Steve Abrams","subject":"sample-followup: record 3 manually-sent 10-day letters + gated FM-stamp script (TK-12109)","body":"Steve sent FABR/WAT/GRD 10-day letters manually from info@ (verified in Sent).\nrecently-contacted.json += the 3 recipients (14-day anti-dup now reflects it).\nAdded scripts/tk12109-stamp-letter-sent.mjs (+ --rollback) to stamp FM\nDate Sample Request Letter Sent=09/23/2026 on the 3 outstanding records\n(541857/541215/541860) with a restore-map — gated to Steve (classifier blocks\nthe FM write). BAR held (not sent), REID arrived, MDCKEN no-chase — not stamped.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"6c9b709","date":"2026-09-23 15:40:04 -0700","author":"Steve Abrams","subject":"sample-followup: draft the 5 verified-owed 10-day SKUs + CONFIRM-RECIPIENT banner/ledger mark (TK-12107)","body":"send-reconciled.mjs draft() now returns the George draftId; needs_confirm vendors\nget an INTERNAL 'CONFIRM RECIPIENT' body banner + a '⚠ CONFIRM RECIPIENT' ledger\nmark so Steve fixes To: before send. Created 4 drafts (5 SKUs): FABR customers@\nfabricut.com, WAT sophie@watts1874.co.uk [confirm], BAR studio@/alice@barnebygates.com\nx2 [confirm], GRD orders@graduatecollection.co.uk [confirm]. REID guard-suppressed\n(arrived), MDCKEN no-chase. Drafts only — nothing sent, no FM write.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"d04d106","date":"2026-09-23 15:10:44 -0700","author":"Steve Abrams","subject":"sample-followup: two-part never-false-chase guard (arrival-dedup + already-sent) — TK-12105","body":"Before chasing a sku, pull ALL FileMaker records ('Report for old memo samples')\nfor that combo sku and suppress if EITHER (a) a sibling with the SAME entered date\nalready has Date WP Sample Sent (arrived on a duplicate record — catches REID\nDWRW210156, spares GRD8806 2024-vs-2026), or (b) any record has Date Sample\nRequest Letter Sent (Steve's authoritative 10-day-letter stamp). Pure suppressChase()\nin lib/sweep.js (+4 unit tests), wired into scheduled-run.mjs + send-reconciled.mjs\nwith a new guard-suppressed bucket. Fail-open; 14-day Gmail anti-dup kept. Nothing sends.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"0269ad6","date":"2026-09-23 14:49:22 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-23T14:48:42 (2 data files) — data/reconciled-draft-ledger.json.bak-20260923-142139-TK12087 data/runs/scheduled-09-23-2026.json","body":""},{"hash":"7534717","date":"2026-09-23 14:48:18 -0700","author":"Steve Abrams","subject":"sample-followup: exclude MDCKEN as non-vendor no-chase (TK-12101)","body":"Steve 2026-09-23: MDCKEN is not a vendor. Added contacts.json disposition\nno-chase entry (same mechanism as SPN/Spoonflower) so MDCKEN (DWPP rows)\nresolves as no-chase BEFORE the 'no vendor map' path — never chased, never\ndrafts, never surfaces as blocked/unresolved. Verified in both scheduled-run.mjs\nand send-reconciled.mjs.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"a11a644","date":"2026-09-23 14:36:55 -0700","author":"Steve Abrams","subject":"sample-followup: day-of-week-aware window (Tue 4-day catch-up, Wed-Fri strict) — TK-12091","body":"Replaces the pure single-day filter (e3a7a73). windowRange (scheduled-run.mjs),\nWIN (send-reconciled.mjs), and lib/sweep.js now: hi=today-10 always; TUE widens\nlo to today-13 (covers Sat/Sun/Mon/Tue 10th-day landings), Wed/Thu/Fri (+manual\noff-days) strict single day. New test/sweep-dow.test.cjs asserts (a) Tue picks\nSat/Sun/Mon/Tue cohorts, (b) Wed/Thu/Fri pick only today-10, (c) Fri->Tue->Wed\nselects every Entered date exactly once (no gap/dup). WIN/CATCHUP/WIDEN_DAYS kept\nas manual recovery nets. pre-send-gate + human batch-send untouched.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"e3a7a73","date":"2026-09-23 14:17:05 -0700","author":"Steve Abrams","subject":"sample-followup: single-day rolling window (Entered==today-10), revert >10d backlog (TK-12087)","body":"scheduled-run.mjs windowRange, send-reconciled.mjs WIN, and lib/sweep.js now\nchase ONLY the cohort entered EXACTLY minAgeDays(10) calendar days ago instead\nof the [10..60] cumulative backlog introduced by TK-12013/12014. WIDEN_DAYS/\nCATCHUP/WIN remain as explicit manual recovery nets.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"04e0986","date":"2026-09-23 14:17:05 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-23T14:17:00 (2 data files) — data/outstanding-snapshot.json data/runs/scheduled-09-23-2026.json","body":""},{"hash":"20ca7a9","date":"2026-09-23 13:45:27 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-23T13:45:21 (2 data files) — data/contacts.json.bak-20260923-131934-TK12085 scripts/send-reconciled.mjs.bak-20260923-131934-TK12085","body":""},{"hash":"7394a41","date":"2026-09-23 13:25:02 -0700","author":"Steve Abrams","subject":"sample-followup: resolve 68 blocked overdue rows (TK-12085)","body":"send-reconciled.mjs now falls back to contacts.json via slugForVid (single\nsource of truth) + strips \\r from vids (KRA\\r bug); adds fabr/wat/reid/grd,\ncorrects ftr->shafik@futuretextiles.com, 1838 email confirmed. 19 vendor\ndrafts created (DRAFT-only); MDCKEN(8) unresolved, SPN(2) no-chase.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"0c365b7","date":"2026-09-23 11:38:33 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-23T11:38:28 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"23a8301","date":"2026-09-23 11:06:52 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-23T11:06:44 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"f562332","date":"2026-09-23 08:28:14 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-23T08:28:09 (1 data files) — data/resend-queue.json","body":""},{"hash":"176ecba","date":"2026-09-23 07:25:25 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-23T07:25:20 (2 data files) — data/outstanding-snapshot.json data/reconciled-draft-ledger.json","body":""},{"hash":"62f2d0f","date":"2026-09-22 15:00:19 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-22T15:00:06 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"bf91abd","date":"2026-09-22 12:16:05 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-22T12:15:47 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"99d3128","date":"2026-09-22 11:31:34 -0700","author":"Steve Abrams","subject":"fix(fleet): fall back to contacts.json vendor name before the (vid X) placeholder","body":"Display-only. build-fleet.js name expressions (both the group row and the\nalias-stub map) rendered '(vid GREEN)' because GREEN isn't in the NAME map,\neven though contacts.json has green -> 'Greenland (bmwallpaper)'. Now falls\nback to the contacts name keyed by slug. Helps any vendor with a contacts\nname. Regenerated fleet.json: GREEN row label fixed, its 13 items / vid /\nslug / aliasVids UNCHANGED. No send, no FileMaker write, no re-attribution.\n\nTK-12013\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01UBN9bgoXhsUaDnGkXU1T6m"},{"hash":"89f8650","date":"2026-09-22 11:19:39 -0700","author":"Steve Abrams","subject":"refresh fleet.json from live FM sweep + declare 1838 WALLCOVERINGS slug alias","body":"fleet.json (the :64845 console's vendor-row source) was 28 days stale\n(Aug 25). Rebuilt from a fresh 10-60d outstanding sweep so all current due\nvendors render as approvable rows. Added the '1838 WALLCOVERINGS' -> 1838-\nwallcoverings alias the build-fleet dup-slug guard required (same vendor).\n\nTK-12013\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01UBN9bgoXhsUaDnGkXU1T6m"},{"hash":"14acdb8","date":"2026-09-22 11:11:07 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-22T11:11:00 (3 data files) — data/resend-queue.json data/runs/scheduled-09-22-2026.json data/stamp-ledger.json","body":""},{"hash":"5374f08","date":"2026-09-22 11:07:18 -0700","author":"Steve Abrams","subject":"fix(window): query full active [today-60..today-10] cohort every run","body":"The auto-widen anchor only reached back to the last SUCCESSFUL run\n(lastCoveredHi=09/02 -> lo 09/03), so older still-outstanding, still-unchased\nmemos (07/24-09/02) fell outside the window and were never chased; a run of\nmissed days made the hole permanent. send-reconciled used a today-16..today-10\nband with the same defect. Both now query the full active window; the FileMaker\nSent-stamp set-difference (scheduled-run) / draft-ledger (send-reconciled) is the\ndedup, so re-covering already-chased memos is a no-op and a missed run day can\nnever drop the older cohort.\n\nTK-12014 / TK-12013\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01UBN9bgoXhsUaDnGkXU1T6m"},{"hash":"fcd34dc","date":"2026-09-22 11:07:09 -0700","author":"Steve Abrams","subject":"fix(sweep): include exactly-10-day-old requests (age < minAge, was <=)","body":"The >10-day rule excluded requests aged exactly 10 days (a 9/12 request due\ntoday was skipped until age 11). Steve: exactly-10 must be INCLUDED.\nlib/sweep.js:36 and build-fleet.js:41 both had the age<=10 off-by-one.\n\nTK-12014 / TK-12013\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01UBN9bgoXhsUaDnGkXU1T6m"},{"hash":"685de6e","date":"2026-09-22 08:41:53 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-22T07:25:22 (2 data files) — data/outstanding-snapshot.json data/resend-queue.json","body":""},{"hash":"afaa0cf","date":"2026-09-21 08:49:34 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-21T08:49:26 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"60018de","date":"2026-09-21 08:17:34 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-21T08:17:25 (1 data files) — data/resend-queue.json","body":""},{"hash":"6ae2a22","date":"2026-09-20 08:22:17 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-20T08:21:12 (1 data files) — data/resend-queue.json","body":""},{"hash":"b79d516","date":"2026-09-19 08:24:21 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-19T08:23:45 (1 data files) — data/resend-queue.json","body":""},{"hash":"4ff6d05","date":"2026-09-18 08:23:42 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-18T08:22:45 (1 data files) — data/resend-queue.json","body":""},{"hash":"fb0d872","date":"2026-09-18 07:18:18 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-18T07:17:32 (2 data files) — data/outstanding-snapshot.json data/reconciled-draft-ledger.json","body":""},{"hash":"a8c84d6","date":"2026-09-17 08:17:23 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-17T08:16:42 (1 data files) — data/resend-queue.json","body":""},{"hash":"6fd2357","date":"2026-09-17 07:13:31 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-17T07:12:37 (1 data files) — data/outstanding-snapshot.json","body":""},{"hash":"80f93b7","date":"2026-09-16 08:25:09 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-16T08:24:08 (2 data files) — data/resend-queue.json data/stamp-ledger.json","body":""},{"hash":"dfa0103","date":"2026-09-16 07:20:43 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-16T07:20:09 (1 data files) — data/outstanding-snapshot.json","body":""},{"hash":"f0ebc1f","date":"2026-09-15 12:01:38 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-15T12:00:25 (2 data files) — data/draft-ledger.json data/runs/scheduled-09-15-2026.json","body":""},{"hash":"8cc7756","date":"2026-09-15 11:30:52 -0700","author":"Steve Abrams","subject":"Add Barneby Gates (vid=bar) sample contact: studio@+alice@barnebygates.com, acct On File","body":""},{"hash":"e471097","date":"2026-09-15 11:26:56 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-15T11:25:48 (1 data files) — data/runs/scheduled-09-15-2026.json","body":""},{"hash":"6bd9e4c","date":"2026-09-15 10:21:37 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-15T10:20:50 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"f203816","date":"2026-09-15 09:49:31 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-15T09:48:56 (2 data files) — data/draft-ledger.json data/runs/scheduled-09-15-2026.json","body":""},{"hash":"a1ea8e6","date":"2026-09-15 08:13:23 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-15T08:12:49 (1 data files) — data/resend-queue.json","body":""},{"hash":"3e1a4cd","date":"2026-09-15 07:09:50 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-15T07:09:15 (2 data files) — data/outstanding-snapshot.json data/reconciled-draft-ledger.json","body":""},{"hash":"a7dec51","date":"2026-09-14 08:22:19 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-14T08:21:43 (1 data files) — data/resend-queue.json","body":""},{"hash":"d56b7a2","date":"2026-09-13 08:08:34 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-13T08:07:44 (1 data files) — data/resend-queue.json","body":""},{"hash":"924ba34","date":"2026-09-13 00:22:29 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-13T00:21:19 (1 data files) — data/stamp-ledger.json","body":""},{"hash":"be622a9","date":"2026-09-12 20:07:28 -0700","author":"Steve Abrams","subject":"TK-11524: close sample-followup no-email gap (item d)","body":"- lib/slug-aliases.cjs: add SCHUMACHER->sch to the single-source-of-truth\n  SLUG_ALIASES. The merge previously lived only in build-fleet.js's local\n  VID_ALIAS, so scheduled-run.mjs's runtime contact bridge mapped raw vid\n  SCHUMACHER->slug 'schumacher' (no contact) -> CONFIRM-SAMPLE-EMAIL skip-gap\n  (the two-copies-diverge class the file header warns about, cf SAND->Sandberg).\n- data/contacts.json ulr: resolve Ulrich Welter -> info@welter-wandunikate.de\n  (Welter Wandunikate; verified via Gmail two-way order thread msg 17e4fa0f0ecd5b7d),\n  HIGH confidence, held needs_confirm:true pending Steve confirm (no auto-send).\n- data/contacts.json tbd: disposition no-chase (FileMaker placeholder vid, not a\n  real vendor; real fix = correct the source memo vid in FileMaker, gated).\n\nVerified: contacts.json valid, build-fleet.js parses, slugForVid(SCHUMACHER)=sch,\n0 undispositioned no-email slugs remain (was 6).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01R3SgrKtLCZRzmFK5fp9qy8"},{"hash":"319610c","date":"2026-09-12 10:09:48 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-12T10:01:53 (2 data files) — data/draft-ledger.json data/runs/scheduled-09-12-2026.json","body":""},{"hash":"e97b899","date":"2026-09-12 08:22:34 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-09-12T08:20:59 (5 data files) — data/contacts.json.bak-1789224232 data/contacts.json.bak-1789224483 data/resend-queue.json data/runs/scheduled-09-12-2026.json package-lock.json","body":""},{"hash":"8e1807b","date":"2026-09-12 08:13:05 -0700","author":"Steve Abrams","subject":"lib/slug-aliases.cjs: one source of truth for slug routing — the two copies had already diverged (TK-11255)","body":"The alias table lived in TWO hand-maintained places: scripts/build-fleet.js\n(grouping) and scripts/scheduled-run.mjs (the vid->contact bridge). They had\nALREADY drifted apart — only the bridge knew that bare vid '1838' is the same\nvendor as '1838 Wallcoverings'. Two copies of one routing table is precisely the\nfailure mode that produced SAND->'Sandberg' and sent Sanderson memo chases to\nGimmersta, an unrelated company, earlier in this ticket. Flagged it as a smell in\n6771f15; the drift was already there when I looked.\n\nNow exactly one definition exists in the repo (verified by grep), exporting\nSLUG_ALIASES, normVid and slugForVid.\n\nTwo real bugs fixed by consolidating rather than by intent:\n  - build-fleet.js never stripped CR/whitespace from vid either, so a record with\n    vid \"kra\\r\" grouped under its own bogus slug. It now shares normVid() with\n    scheduled-run, which got that fix in e343b5f.\n  - build-fleet.js lacked the '1838' alias, so the bare vid grouped separately\n    from '1838 Wallcoverings'. Both now converge on '1838-wallcoverings'.\n\nRe-tested after the change, not assumed — including the negative test, because a\nconsolidation that quietly disarms the guard is the worst outcome here:\n  T1 distinct vids          -> writes\n  T2 ANNA FRENCH with items -> merges into thib, no stray anna-french slug\n  T3 'FOO BAR' + 'FOO-BAR'  -> exit 1, fleet.json NOT written (guard still reddens)\n  ESM -> CJS import proven at RUNTIME, not just by node --check, since\n  scheduled-run.mjs is ESM and this module is CJS.\nLive re-verification through the REAL shared module (not a reimplementation of\nits logic): 27 of 28 live vendors routable, 129 overdue records, only FUT\nunresolved — unchanged, so consolidation regressed nothing.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>"},{"hash":"5c0d68e","date":"2026-09-12 07:48:51 -0700","author":"Steve Abrams","subject":"contacts.json: route VAH + BRU + bare-1838 — 27 of 28 live vendors now reachable (TK-11255)","body":"Closes most of the silent-skip gap measured today: of 129 live overdue sample\nrecords, 11 across 7 vendor codes resolved to NO contact and were dropped with no\nerror and no log line.\n\n  vah  Vahallan -> info@vahallan.com, acct \"On File\"\n       Verified live before adopting: Annie Kaufman, Senior Sales Coordinator,\n       replied \"Thank you for your sample request. We will get these sent out\"\n       to our own request YESTERDAY (2026-09-11) and again 2026-09-03.\n  bru  Brunschwig & Fils (@ Kravet) -> matt.schoffman@kravet.com, acct 10087117\n       Canonical says \"Brunswig and fils @ Kravet\" and Brunschwig is a Kravet\n       house, so it shares Kravet's desk and account. Held to the same bar\n       rather than assumed: Matt Schoffman replies to our sample requests with\n       UPS tracking, most recently 2026-09-10.\n  1838 bare vid routed to the existing 1838-wallcoverings contact via\n       SLUG_ALIASES — same vendor (Scott Myer), so this is a routing alias\n       rather than a duplicated contact record.\n\nMeasured effect, live: routable vendors 24 -> 27 of 28; unroutable records\n8 -> 2.\n\nNOT adopted: FUT (2 records). Canonical has no FUT row. It is probably the same\nvendor as FTR (\"future Textile\", ftg1@futuretextiles.com) on a name-shaped hunch,\nand that is exactly the kind of guess that put Sanderson memos at Gimmersta\nearlier in this ticket. It stays unroutable until something confirms it.\n\nBoth new accounts use the house \"On File\"/inherited-account convention rather\nthan an invented number, and the scheduled job runs --draft, so the effect is a\nreviewable draft per vendor, never an automatic send.\n\nUndo: restore data/contacts.json.bak-1789224483\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>"}]}