Dw Pitch Followup
Search the build
-
3828ac02026-09-25 refresh.sh: retry build-lists up to 3x on transient Claris ID/Cognito 'Network error' FATAL (TK-12258) -
1989be52026-09-17 auto-data-snapshot: 2026-09-17T20:05:20 (1 data files) — data/suppress.json -
b5f12812026-09-15 security: add rel=noopener noreferrer to target=_blank links (yoloforever cycle 3) -
5f4bb6e2026-08-19 auto-data-snapshot: 2026-08-19T20:02:37 (1 data files) — data/suppress.json -
f8e1a7f2026-08-18 refresh.sh: network-readiness guard before Claris auth — kills the RunAtLoad boot-race FATAL (Cody, yoloforever c4) -
9f1d3782026-08-17 auto-data-snapshot: 2026-08-17T20:02:38 (1 data files) — data/suppress.json -
30bfd4f2026-08-17 Record pitch-site Basic-Auth rotation to fleet-standard cred -
32ac85c2026-08-06 chore: v0.6.0 (session close) — catch-all route, Gmail correspondence table, 2AM rebuild fix, plist-lint hook -
e26fbb52026-08-06 Pitch drawer: render all Gmail correspondence as a table -
705c7152026-08-06 Add repo-local pre-commit: lint staged launchd/*.plist -
264deba2026-08-06 Fix pitch-rebuild launchd: valid plist + once-daily 2:00 AM schedule -
fc4911d2026-08-06 Add catch-all: unknown non-api GETs redirect to / instead of raw Cannot GET 404 -
61ac5f62026-07-31 auto-save: 2026-07-31T20:00:42 (1 files) — data/suppress.json -
04dc7da2026-07-30 chore: lint ✓ + refactor ✓ (both clean, no code changes), v0.4.1 → v0.5.0 (session close) -
b50e31f2026-07-30 pitch: package.json description now reflects reality — notes write path + /api/send (with suppression, 30-day, external-send token, ALLOW_TUNNEL_SEND guards); drop stale 'No sends' -
56a35bd2026-07-30 pitch: enable Send-now over the public tunnel via ALLOW_TUNNEL_SEND flag (Steve-approved) + Send button now shows 'send cancelled' so a dismissed confirm never looks dead -
6330e752026-07-30 pitch: signpost 9768 (own listen port) vs 9850 (GEORGE client URL) — prevent the misread; keep PORT hardcoded to dodge pm2 stale-env -
1ffa37a2026-07-30 pitch: 30-day already-emailed guard now shows date AND time (server + confirm dialog) — completes the date+time-on-all-emails pass -
d3bd7eb2026-07-30 pitch: ✓ emailed card chip now stamps date AND time (fmtWhen), matching the send panel + admin-card rule -
dcb29c42026-07-15 chore: lint, refactor (dedup repaint per unique email), v0.4.1 (session close) -
229cd172026-07-15 fix(notes): FileMaker note-save silently no-op'd — write rep-1 bare key + read-back verify -
109d6a32026-07-15 Make invoice # on the note chip + notes editor clickable — opens the invoice in FileMaker Pro via fmp:// GotoInvoice -
a923a042026-07-15 fix: ✓ emailed date chip appears immediately after send — repaint live cards by DOM lookup (active.card was detached after board re-renders), update SENT_IDX in memory for same-client cards in other lists, and refresh sent-index on tab focus for cross-device visibility -
177117e2026-07-15 Show invoice # + current internal note on every pitch card — batched FM read (50/query, 10-min cache), chip updates live on save -
58c847e2026-07-15 Add Internal-notes editor to pitch cards — 🗒 Notes button next to Done reads/writes FileMaker Invoice::Internal notes with dated entries -
e35cf912026-07-15 auto-save: 2026-07-15T10:35:56 (2 files) — server.js lib/fm-notes.js -
e90255c2026-07-15 pitch: scheduled refresh now also pre-triages the whole board (build-lists → pretriage), so every card is Follow-up scored -
5e218be2026-07-15 pitch: Follow up? YES/NO chip on every card + per-column ⚡ Triage (batch, cached) -
8e921dc2026-07-15 pitch: auto follow-up triage — reads the email thread → Follow up? YES/NO + notes (delays, deadlines, status) -
e039b5a2026-07-15 pitch: click any email in the history to expand its full body -
8f32c4b2026-07-15 pitch: add 3x/day launchd rebuild so the board never goes stale (bootstrap = Steve paste) -
e592d472026-07-15 pitch: email history collapsed by default, lazy-loads on expand (George search only fires when opened) -
a4bc2e82026-07-15 pitch: Details drawer shows full email history with each client -
71574cf2026-07-14 5x: 2 clean sweeps (7/7 six-way + 51 controls, 0 defects) after card/UX + George + FM batch -
9aa4cdc2026-07-14 pitch: letter panel shows product thumbnails + DW product-page links -
c6994a42026-07-14 pitch: list2 letter follows up on the specific QUOTE (number, total, items) not generic samples -
f9b63232026-07-14 pitch: Sent log is now LIVE — merge Gmail Sent (recipient-enriched) with the tool log -
6c560f32026-07-14 pitch: FIX critical George 401 — resolve GEORGE_AUTH from secrets master (restores sends + threading + last-corr) -
c6d56092026-07-14 pitch: card/UX batch — dismiss-completed, park vendor memos, quote/order label fix, FM deep-links, live sent-index, expandable columns -
d4a8d302026-07-14 auto-save: 2026-07-14T11:00:40 (1 files) — public/index.html -
a59c63b2026-07-14 pitch: redefine "Invoiced · No Order" list as real quotes never booked (totals + details) -
395d98e2026-07-13 chore: lint (esc XSS autofix + enrich-disco psql guard), refactor, v0.4.0 (session close) -
4c403792026-07-13 auto-save: 2026-07-13T12:24:56 (1 files) — public/index.html -
0b342302026-07-13 auto-save: 2026-07-13T11:54:48 (2 files) — public/index.html scripts/enrich-disco.js -
a22a58a2026-07-13 auto-save: 2026-07-13T11:24:39 (2 files) — public/index.html scripts/build-lists.js -
93dde312026-07-12 chore: v0.3.0 (session close — public tunnel + auth hardening: lockout, socket-guard, cred rotation, headers) -
02b62f22026-07-12 yolo contrarian-gate fixes: socket-anchored /api/send guard (#1) + suppress audit log (#2) -
211aef32026-07-12 yolo: baseline security headers (nosniff, frame-DENY, no-referrer) on public endpoint — closes contrarian 'no helmet' gap -
09bfb882026-07-12 contrarian FIX FIRST #3: rotate public cred off shared DW2024! via app-local .env (envLocal reader) -
577f14f2026-07-12 contrarian FIX FIRST #2: per-IP brute-force lockout on public Basic Auth (10 fails/15m → 429) -
cf2ad962026-07-12 contrarian FIX FIRST #1: block /api/send for tunnel-origin requests (loopback-only mail send) -
10b262d2026-07-12 5x: REPORT.md — 2 sweeps, app clean, M3 networkidle proven CDN artifact -
d29d6ef2026-07-12 5x sweep 1: add auth-exempt /favicon.ico 204 route (kills per-load console 404) -
d6916492026-07-08 chore: syntax-verified session changes, v0.1.1 → v0.2.0 (session close) -
ee864df2026-07-08 Schedule unsubscribe scan (launchd com.steve.dw-pitch-unsub-scan, 8am+8pm) — auto-honors client opt-outs with ?apply=1, logs every run; plist versioned in repo -
e2ce4dc2026-07-08 auto-save: 2026-07-08T06:34:26 (1 files) — scripts/scan-unsubscribes.sh -
a9f7c6a2026-07-08 CAN-SPAM: compliant footer (physical address 15442 Ventura Blvd #102 + UNSUBSCRIBE) on every send; suppression list honored at send (not overridable); tightened unsubscribe scanner (to:info@ + opt-out-at-start, dry-run by default, ?apply=1 to suppress) -
cc4f4682026-07-08 Stop leaking internal 'From job: dw-pitch-followup' banner onto client emails (no_source_tag:true); verified sent body is clean -
ff195582026-07-07 yolo/contrarian fixes: build-time TODAY (fix aging bug) + 30-day double-email frequency guard at send (list1∩list2 dedup) with 'Send anyway' override -
d191c5c2026-07-07 Auto-swap to a thank-you letter when client has a BOOKED order since sampling (references the order + project); quote-since-sampling still gets the follow-up (chase the close) -
4f8a57a2026-07-07 Flag invoices placed SINCE samples sent (possible conversion): card banner + panel detail with #, total, sku/item, quote/booked, date -
b6e57372026-07-07 Fix sticking Send button (reset #pSend/#pRegen/#pCopy on panel open); stamp emailed date/time in panel+card+sendstat; keep permanent sent-log.jsonl of every email + /api/sent + 'Sent log' viewer -
a4a77d72026-07-07 Make panel 'Send now (info@)' prominent — filled gold, bold, right-aligned with divider (was subtle outline, easy to miss) -
b2b886f2026-07-07 Email: thumbnail + product-link gallery for recent samples (dw_unified sku→handle/image, dashed-sku match, ACTIVE-only links); panel shows thumbnails too; separate sample-reminder heading from list -
eb905c72026-07-07 Letter greeting uses FileMaker contact first name (Find-a-client Name field); block letter + red 'Reorder Samples??' when samples ordered but 0 shipped (panel Generate disabled too) -
2246a8e2026-07-07 Rewrite client letter to spec: ~3 sentences, client-type aware (designer/architect trade line), final-purchase ask, witty stock/samples ask, project-details line, ends w/ question, rotating Steve/Samantha/Marcus sign-off, sample list w/ dates, url+phone (HTML href on send), PS; no new-year/no mfr#; fix name parsing (parentheticals/ALL-CAPS) -
a350bea2026-07-07 Right-panel detail view (context+last-corresponded on click+letter); quote/booked per invoice; lifetime sales (booked-only) on card+panel; current project from invoice sidemark; lifetime-sales sort -
53052462026-07-07 Expand sort to all fields incl Invoice total (merch_total); add sort control to One-list view (defaults to invoice-total desc) -
e3aa21c2026-07-07 Revert invoice links to file-open (skip GotoInvoice deep-link for now) -
43c0d5a2026-07-07 Invoice links: enable fmp:// record-jump (USE_FM_SCRIPT=true → GotoInvoice script param) -
56b23812026-07-07 Enrich cards with samples sent/pending + merchandise invoices (>$250, real orders) w/ fmp links + total; MERCH_MIN=250; sample SKUs shown as-is in admin details -
28a382b2026-07-07 auto-save: 2026-07-07T14:31:09 (2 files) — public/index.html scripts/build-lists.js -
c660a282026-07-07 Compact cards + Columns/One-list layout toggle + ▸details expander (samples/merch/last-corresponded); lazy /api/lastcorr via George -
306b7912026-07-07 Add 'Send now (info@)' — emails generated letter via George info@ account with external-send approval token (Steve-authorized), confirm-guard + in-thread + persisted sent marker -
182e2a62026-07-07 auto-save: 2026-07-07T14:01:00 (2 files) — public/index.html server.js -
5d7759e2026-07-07 Redesign viewer: 3-column board (all lists at once) + List/Grid toggle + density scale; per-column sort, cross-column select/export -
8a5b1ac2026-07-07 Frontend: build API URLs from location.host so fetches work even when page opened with inline credentials -
0524e782026-07-07 Skip Basic Auth for direct-loopback access so the localhost viewer loads without inline creds (tunnel still gated) -
25071562026-07-07 chore: version bump (session close — anti-hallucination guardrails) -
9abe8a22026-07-07 pitch-followup: anti-hallucination guardrails + LLM reliability -
90270262026-07-03 chore: macstudio3 migration — reconcile from mac2 + repoint paths (stevestudio2→macstudio3, node/npm/npx→/opt/homebrew) -
d2a48d92026-06-30 ui: show last-sample-sent date as a chip on every card (uses existing when_iso; removed redundant .when line) -
351e8f92026-06-30 Pitch follow-up: hide mfr# from UI + client letters (toggle), LLM-customized letters, Generate/Regenerate buttons -
91a8b822026-06-30 auto-save: 2026-06-30T14:41:08 (1 files) — deploy/ -
a518ea62026-06-30 DW client/vendor follow-up pitch viewer: 3 read-only FileMaker lists + George-grounded letters + select/export (no sends)
Authors
- Steve77
- steve5
- auto-commit-fleet3
Agents used
- secrets-manager1
Skills used
- /index6
- /suppress4
- /send3
- /claude2
- /code2
- /followup-cache2
- /sent2
- /build-lists2
- /booked2
- /export2
- /dict1
- /path1
- /query1
- /writes1
- /fm-notes1
- /followup-batch1
- /followup-analysis1
- /deadlines1
- /promises1
- /status1
- /day1
- /emails1
- /from1
- /out1
- /url1
- /order1
- /sent-index1
- /shrink1
- /enrich-disco1
- /favicon1
Creative ideas + design notes
3828ac0 · 2026-09-25 · refresh.sh: retry build-lists up to 3x on transient Claris ID/Cognito 'Network error' FATAL (TK-12258)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7LB6rCwpA7ubJTqYzqXEX
b5f1281 · 2026-09-15 · security: add rel=noopener noreferrer to target=_blank links (yoloforever cycle 3)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UxvvaJ7p6VRZ4RzKDaBXqK
e26fbb5 · 2026-08-06 · Pitch drawer: render all Gmail correspondence as a table
The 'All emails with this client' drawer section now renders every message (both directions, deduped across info@ + steve-office, up to the API max of 50) as a fixed-layout table — Dir / Date / Subject / Preview — with sticky header. Each email is a <tbody class=em> (summary <tr> + hidden body <tr>), preserving the .em/.emrow/.embody/.emcaret structure so the existing click-a-row-to-read-full-body handler works with zero JS-handler changes. Relabeled the section header to 'All Gmail correspondence'. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
705c715 · 2026-08-06 · Add repo-local pre-commit: lint staged launchd/*.plist
Blocks any commit that stages a malformed plist (mismatched tags, bad schedule) via plutil -lint on the staged blob. Repo-scoped core.hooksPath =.githooks so it runs even though this machine's global core.hooksPath points at a non-existent dir. Prevents a repeat of the silent broken-plist that froze the pitch board for a week. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
264deba · 2026-08-06 · Fix pitch-rebuild launchd: valid plist + once-daily 2:00 AM schedule
Root cause of stale board (data frozen at Jul 30 build): this plist was malformed (opened <array>, closed </dict>) and was never installed in ~/Library/LaunchAgents, so the rebuild job never ran. Rewrote with valid tags and a single StartCalendarInterval at 02:00 per Steve's requirement (was 6:30/11:30/16:30). Installed + bootstrapped; RunAtLoad refreshed the board to today. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fc4911d · 2026-08-06 · Add catch-all: unknown non-api GETs redirect to / instead of raw Cannot GET 404
Stray deep-links / browser-autofilled paths now open the viewer instead of Express's raw 'Cannot GET /path'. Scoped so /api/* still returns JSON 404s (never redirect an API call — fetch() must see the real failure). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
229cd17 · 2026-07-15 · fix(notes): FileMaker note-save silently no-op'd — write rep-1 bare key + read-back verify
Root cause: repeating-field rep 1 must be written as the BARE field name ("Internal notes"), not "Internal notes(1)" — the Data API accepts the (1) form with success code 0 but silently ignores it, so notes logged as saved but never persisted (verified: a real save was empty on read-back). Also updateRecord reports committed:true after any non-erroring PATCH without confirming the field changed. Fix: write bare key AND read the record back, throwing if the note is not actually present — never report a save we cannot see.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
5e218be · 2026-07-15 · pitch: Follow up? YES/NO chip on every card + per-column ⚡ Triage (batch, cached)
Server keeps a persistent follow-up cache (data/followup-cache.json): analyzeFollowup writes each verdict; drawer opens + a new POST /api/followup-batch (concurrency 3, skips <24h-fresh) fill it. GET /api/followup-cache feeds card badges at boot. Cards show a green "Follow up" / tan "Hold" chip from cache; ⚡ Triage per column batches all un-cached clients with live progress; opening a drawer lights that card immediately. All local Ollama, $0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
8e921dc · 2026-07-15 · pitch: auto follow-up triage — reads the email thread → Follow up? YES/NO + notes (delays, deadlines, status)
New /api/followup-analysis reads the client thread via George and runs local Ollama (hermes3:8b, $0) to decide follow-up yes/no with a reason, concrete notes (delays/deadlines/promises/status), and a deadline date. Drawer shows a prominent Follow up? badge (green YES / red NO) auto-loaded on open, cached 6h per client, with a ↻ re-analyze. Deadline sanitized to real date-or-empty. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
e039b5a · 2026-07-15 · pitch: click any email in the history to expand its full body
New /api/email?id=&account= fetches the full message via George and strips HTML to readable text. Each email row is now clickable → lazy-loads + expands the body inline (caret ▸/▾), collapses on re-click, cached per message. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
a4bc2e8 · 2026-07-15 · pitch: Details drawer shows full email history with each client
New /api/emails?email= (George read-only) returns all emails to/from a client across info@ + steve-office, deduped, newest first, with in/out direction from the From header. Drawer renders the thread list (direction chip · date · subject · snippet), lazy-loaded on open alongside last-corresponded. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
9aa4cdc · 2026-07-14 · pitch: letter panel shows product thumbnails + DW product-page links
renderLetterGallery draws a small strip under the letter — 40px thumbnail + link to the DW product page for each referenced sampled item (image/url from dw_unified). Shown on panel open. 476/600 list1 clients have images. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
c6994a4 · 2026-07-14 · pitch: list2 letter follows up on the specific QUOTE (number, total, items) not generic samples
New quote-followup branch in composeDeterministic for list2: cites the actual quote #(s), total, and quoted items with amounts, and asks to convert to an order. Sanitizes leaked dimension strings out of the project ref and strips empty "(Ref.)" from item names. Verified against a real $6,693.60 two-quote client. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
f9b6323 · 2026-07-14 · pitch: Sent log is now LIVE — merge Gmail Sent (recipient-enriched) with the tool log
georgeSentLetters now fetches each sent letter full message for its `to` (Gmail search omits recipient), bounded to 60 newest, parallel. collectSent merges live+local, dedups by recipient+day, 60s cache. Sent log + per-card emailed chip now show through today (was frozen at the last tool-send). Verified newest = Jul 14. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
6c560f3 · 2026-07-14 · pitch: FIX critical George 401 — resolve GEORGE_AUTH from secrets master (restores sends + threading + last-corr)
The app resolved an empty George password, so every George call 401d — sends, reply-threading, and "last corresponded" were silently failing (and pm2 --update-env wiped the process-env cred on restart). Now resolves the canonical GEORGE_AUTH ("user:pass") from secrets-manager/.env, surviving restarts. Verified: lastcorr returns a real thread.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
c6d5609 · 2026-07-14 · pitch: card/UX batch — dismiss-completed, park vendor memos, quote/order label fix, FM deep-links, live sent-index, expandable columns
- Dismiss any card as ✓ Done: instant DOM removal + persisted, never re-shown (localStorage done: flag; filterSort/flatRows exclude) - Park Vendor Memos Overdue (list3): dropped from board + bucket via PARKED set (un-park = 1 line); grid tracks now match visible column count - Fix quote-vs-order contradiction: postFlag shows BOOKED orders only; drawer relabels "Quoted since we sent samples" when none booked - Per-invoice details: drawer splits Orders vs Quotes, each row shows item detail; goodLbl drops stripMfr punctuation-junk items - FileMaker deep-links: invoice# and client acct now Find the exact record (fmpInvoice/fmpClient script+param, USE_FM_SCRIPT on) — needs GotoInvoice/GotoClient scripts in FM - Real "emailed on <date>" chip from server /api/sent-index (cross-browser, 311 recipients from the send log) - /api/sent now merges the local log with a live Gmail Sent view (George), 60s cache, invalidated on send - Expand/shrink any board column (⤢ toggle, persisted) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
a59c63b · 2026-07-14 · pitch: redefine "Invoiced · No Order" list as real quotes never booked (totals + details)
- buildList2 candidate pool flipped from sample-only (maxTotal<=$50) to real-dollar invoices - main() keeps only accounts with an open merch quote (quoted_total>0) and NO booked order (lifetime_sales==0), deriving quote_total / quote_count / quote_items - cards show "$X quoted · no order" chip + quoted item details; sorts now quote-based - drawer reads "No orders booked · $X in open quotes" for these never-booked prospects - list2: 57 accounts (e.g. $92,250 Briseyda Garcia quote, never ordered) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
9abe8a2 · 2026-07-07 · pitch-followup: anti-hallucination guardrails + LLM reliability
- Whitelist product names: the writer may ONLY name a pattern that's in the client's actual sampled set (buildFacts now returns allowed[]); empty → model names nothing, speaks generically. Reject-guard throws on any ™/® or 'X Collection' name not on the whitelist → falls back to the accurate deterministic draft. No invented collection names can reach a client draft. - Fix subject-greeting leak (subject is now a standalone line) + guarantee the body opens with 'Hi <name>,'; strip stray ™/®. - Reliability: keep_alive 30m + widen Ollama timeout 30s→90s so drafts stop cold-timing-out to the generic fallback. Verified across seeds.
File tree
- .githooks/pre-commit
- .gitignore
- 5x/REPORT.md
- CHANGELOG.md
- data/suppress.json
- deploy/finish-tunnel.sh
- launchd/com.steve.dw-pitch-rebuild.plist
- launchd/com.steve.dw-pitch-unsub-scan.plist
- lib/fm-notes.js
- lib/fm.js
- package-lock.json
- package.json
- public/index.html
- scripts/build-lists.js
- scripts/enrich-disco.js
- scripts/pretriage.js
- scripts/refresh.sh
- scripts/scan-unsubscribes.sh
- server.js