[object Object]

← back to Sample Followup Sweep

sample-followup: chase today's 10-day cohort today; Tue folds in Sat/Sun/Mon

f546361a9f518c73b7a0732ee2abcb5071b37b83 · 2026-09-01 10:43:11 -0700 · Steve

Revised weekday rule (Steve 9/01): a memo is chased the day it turns exactly 10
days old (entered today-10), chased TODAY not deferred. Wed/Thu/Fri = single day
today-10. Tuesday = one letter per vendor covering Sat/Sun/Mon+Tue = entered
[today-13..today-10]. Shifts the band forward one day vs the prior commit
(hi today-11->today-10, lo prevRun-10->(prevRun+1)-10). Verified gapless +
non-overlapping over 2 weeks; live dry-run today=Tue -> 08/19..08/22.

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

Files touched

Diff

commit f546361a9f518c73b7a0732ee2abcb5071b37b83
Author: Steve <steve@designerwallcoverings.com>
Date:   Tue Sep 1 10:43:11 2026 -0700

    sample-followup: chase today's 10-day cohort today; Tue folds in Sat/Sun/Mon
    
    Revised weekday rule (Steve 9/01): a memo is chased the day it turns exactly 10
    days old (entered today-10), chased TODAY not deferred. Wed/Thu/Fri = single day
    today-10. Tuesday = one letter per vendor covering Sat/Sun/Mon+Tue = entered
    [today-13..today-10]. Shifts the band forward one day vs the prior commit
    (hi today-11->today-10, lo prevRun-10->(prevRun+1)-10). Verified gapless +
    non-overlapping over 2 weeks; live dry-run today=Tue -> 08/19..08/22.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 scripts/scheduled-run.mjs | 38 ++++++++++++++++++++------------------
 1 file changed, 20 insertions(+), 18 deletions(-)

diff --git a/scripts/scheduled-run.mjs b/scripts/scheduled-run.mjs
index 0c02de6..1c48a39 100644
--- a/scripts/scheduled-run.mjs
+++ b/scripts/scheduled-run.mjs
@@ -41,16 +41,17 @@ const FIELD_SENT = 'Date Email Sent to Vendor after 10 Days';
 const FIELD_2ND_DATE = 'Date Sample Request Letter Sent';
 const MIN_AGE_DAYS = 10;
 // Steve 9/01 (FINAL RULE — weekday-aware catch-up): the schedule is Tue–Fri (Mon/Sat/Sun never run).
-// Each run chases the memos that turned exactly 10 days old on the days SINCE the last run — i.e. the
-// cohorts for [previous-scheduled-run-day .. yesterday]. Today's own cohort (entered today-10) is
-// ALWAYS deferred to the next run, so the newest day is never chased prematurely.
-//   • Tuesday: last run was Friday, and Sat/Sun/Mon didn't run → cover Fri, Sat, Sun, Mon → 10 days
-//     before EACH → entered band [Mon-10 .. Fri-10] = [today-11 .. today-14]. (Steve, verbatim:
-//     "on tuesday we go back to the last day, friday and add friday, saturday, sunday, monday
-//      then 10 days before each.")
-//   • Wed/Thu/Fri: last run was yesterday → cover just yesterday → single day entered today-11.
-// Coverage is gapless and non-overlapping week-to-week (verified). The old code IGNORED the weekday
-// and applied a flat CATCHUP_DAYS band every run — that's the bug this replaces.
+// A memo is chased on the day it turns EXACTLY 10 days old (entered today-10) — chased TODAY, not
+// deferred. The only wrinkle is the weekend: Sat/Sun/Mon have no run, so their turns-10 cohorts wait
+// and get folded into the following TUESDAY's single letter per vendor.
+//   • Wed/Thu/Fri: chase the one cohort that turns 10 today → entered today-10 (single day). (Steve:
+//     "Run ... to include wed, th, friday 10 days back.")
+//   • Tuesday: the last run was Friday and Sat/Sun/Mon didn't run → ONE letter covering Sat, Sun, Mon
+//     AND today (Tue) → entered band [Sat-10 .. Tue-10] = [today-13 .. today-10]. (Steve, verbatim:
+//     "on tuesday send letter for sat, sun, monday, and today tuesday in 1 letter to vendors.")
+// General form: cover the turns-10 cohorts for the days (previous-scheduled-run .. today] inclusive of
+// today. Coverage is gapless and non-overlapping week-to-week (verified over 2 weeks). The old code
+// IGNORED the weekday and applied a flat CATCHUP_DAYS band every run — that's the bug this replaces.
 // Env CATCHUP (manual override): if set, revert to the old fixed rolling band [today-10-(N-1)..today-10]
 // as an explicit wide recovery net (e.g. after a silently-missed run). Dedup makes the overlap safe.
 const RUN_WEEKDAYS = new Set([2, 3, 4, 5]);   // Tue(2) Wed(3) Thu(4) Fri(5)
@@ -82,14 +83,15 @@ function windowRange(today = new Date()) {
     const lo = new Date(today); lo.setDate(lo.getDate() - MIN_AGE_DAYS - (CATCHUP_DAYS - 1));
     return `${fmtDate(lo)}...${fmtDate(hi)}`;
   }
-  // Default weekday-aware band: cover the 10-day cohorts for [prevScheduledRun .. yesterday].
-  //   hi = yesterday - 10           (= today - 11; today's own cohort is deferred to next run)
-  //   lo = prevScheduledRun - 10
-  // Tue → prevRun=Fri → [today-14 .. today-11] (Fri/Sat/Sun/Mon each -10).
-  // Wed/Thu/Fri → prevRun=yesterday → single day today-11.
+  // Default weekday-aware band: cover the turns-10 cohorts for the days (prevScheduledRun .. today],
+  // inclusive of today — today's cohort is chased TODAY, and the weekend's cohorts fold into Tuesday.
+  //   hi = today - 10                    (today's turns-10 cohort — always chased today)
+  //   lo = (prevScheduledRun + 1) - 10   (first turns-10 cohort the last run didn't already cover)
+  // Tue → prevRun=Fri → [today-13 .. today-10] = Sat/Sun/Mon/Tue each -10, one letter per vendor.
+  // Wed/Thu/Fri → prevRun=yesterday → single day today-10.
   const prev = prevScheduledRun(today);
-  const hi = new Date(today); hi.setDate(hi.getDate() - (MIN_AGE_DAYS + 1));
-  const lo = new Date(prev);  lo.setDate(lo.getDate() - MIN_AGE_DAYS);
+  const hi = new Date(today); hi.setDate(hi.getDate() - MIN_AGE_DAYS);
+  const lo = new Date(prev);  lo.setDate(lo.getDate() + 1 - MIN_AGE_DAYS);
   return `${fmtDate(lo)}...${fmtDate(hi)}`;
 }
 const norm = (s) => String(s || '').toLowerCase().trim();
@@ -230,7 +232,7 @@ const run = async () => {
   mkdirSync(join(ROOT, 'data', 'runs'), { recursive: true });
   writeFileSync(join(ROOT, 'data', 'runs', `scheduled-${today.replace(/\//g, '-')}.json`), JSON.stringify(report, null, 2));
 
-  const bandDesc = CATCHUP_DAYS > 0 ? `${CATCHUP_DAYS}-day manual catch-up band` : 'weekday-aware band (Tue covers Fri–Mon)';
+  const bandDesc = CATCHUP_DAYS > 0 ? `${CATCHUP_DAYS}-day manual catch-up band` : 'weekday-aware band (Tue covers Sat/Sun/Mon+Tue)';
   console.log(`Scheduled follow-up — ${mode} · window ${win} (>=${MIN_AGE_DAYS}d, ${bandDesc})\n`);
   if (DRAFT) {
     console.log(`Created ${drafted.length} draft(s) in info@ Drafts for review:`);

← c1ce8fa sample-followup: make Tuesday window weekday-aware (cover Fr  ·  back to Sample Followup Sweep  ·  sample-followup: auto-widen window to last successful run (b 38d86d1 →