[object Object]

← back to Claude Webdev Accelerator

chore: session-close hardening — atomic writeProcessed, (no timestamp) fallback, oneLine note in list

0f1dbb8002dd59e754ca3ce33da0666455ae1073 · 2026-08-12 06:57:40 -0700 · steve@designerwallcoverings.com

Files touched

Diff

commit 0f1dbb8002dd59e754ca3ce33da0666455ae1073
Author: steve@designerwallcoverings.com <steve@designerwallcoverings.com>
Date:   Wed Aug 12 06:57:40 2026 -0700

    chore: session-close hardening — atomic writeProcessed, (no timestamp) fallback, oneLine note in list
---
 scripts/bounce-intake.js | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/scripts/bounce-intake.js b/scripts/bounce-intake.js
index bd50434..69fdd3e 100644
--- a/scripts/bounce-intake.js
+++ b/scripts/bounce-intake.js
@@ -63,7 +63,12 @@ function readProcessed() {
 }
 function writeProcessed(map) {
   if (!fs.existsSync(CLIENTS)) fs.mkdirSync(CLIENTS, { recursive: true });
-  fs.writeFileSync(PROCESSED, JSON.stringify(map, null, 2) + '\n');
+  // atomic write: a kill mid-write would otherwise corrupt the marker, and the
+  // readProcessed catch would then return {} → every lead re-scaffolds (dup
+  // folders + dup gated replies). tmp + rename is atomic on POSIX.
+  const tmp = PROCESSED + '.tmp';
+  fs.writeFileSync(tmp, JSON.stringify(map, null, 2) + '\n');
+  fs.renameSync(tmp, PROCESSED);
 }
 
 // Collapse untrusted free text to a single safe line before embedding it in a
@@ -95,8 +100,10 @@ function slugFor(lead, taken) {
 }
 
 function fmtDate(iso) {
-  const d = iso ? new Date(iso) : new Date('2026-01-01T00:00:00Z');
-  return d.toLocaleString('en-US', { year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' });
+  // explicit placeholder over a fake sentinel date — a missing ts should read as
+  // "(no timestamp)" in the BRIEF, not a misleading "Jan 1, 2026".
+  if (!iso) return '(no timestamp)';
+  return new Date(iso).toLocaleString('en-US', { year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' });
 }
 
 // ---------- brief + reply templates ----------
@@ -209,7 +216,7 @@ function cmdList(showAll) {
     const ref = extractRef(lead);
     console.log(`  ${flag} #${idx}  ${lead.email || '(no email)'}  [${lead.budget || '—'}]  ${fmtDate(lead.ts)}`);
     if (ref) console.log(`        ref: ${ref}`);
-    if (lead.note) console.log(`        note: ${String(lead.note).slice(0, 120)}`);
+    if (lead.note) console.log(`        note: ${oneLine(lead.note).slice(0, 120)}`);
   });
   console.log('\nTriage one: node scripts/bounce-intake.js scaffold <n|email>');
 }

← e9af9dd bounce: intake engine (waitlist -> engagement + gated reply)  ·  back to Claude Webdev Accelerator  ·  preview-tunnel: repoint from dead dw-followup (0e1edf5a) to 2476d9a →