Human overview · for understanding

Every email → Notion, every draft checked

Plan: fix the stale-draft blind spot + prove email→CRM linking is 100% — email-notion-touchpoint-sync · 2026-07-21

Plan: fix the stale-draft blind spot + prove email→CRM linking is 100% — email-notion-touchpoint-sync

Master summary — the gist in 30 seconds

TL;DRThe 'Kedves Orsi' draft happened because the reply-drafter never looks at your Notion CRM — which already knew the meeting was over (10 touchpoints logged!). The plan: make the drafter read each lead's touchpoint history before writing a word, auto-link every incoming email to a CRM contact, and run a nightly proof-check so a single missed email turns the board RED.

Input: every incoming email in Missive. Output: a CRM contact + touchpoint entry in Notion for each one, drafts that know the lead's full history, and a daily '📬 14/14 linked, 0 gaps' receipt.

Why this mattersYour CRM already had the truth — the drafter just never asked. Connecting the two makes stale drafts structurally impossible, and the nightly reconciliation means you never have to *trust* it works: it proves it every morning.
flowchart LR
  A["📧 Incoming email<br/>(Missive)"] --> B{"Known<br/>contact?"}
  B -- yes --> C["🗂️ Notion CRM<br/>contact"]
  B -- new human --> D["➕ Auto-create<br/>(flagged)"] --> C
  C --> E["📒 Touchpoint logged<br/>Activity Log"]
  E --> F["✍️ Drafter reads<br/>FULL history first"]
  F --> G["📝 Unsent draft<br/>(human gate)"]
  E -.-> H["🌙 Nightly proof:<br/>every email linked?"]
  H -. gap .-> I["🔴 RED alert"]

1 · Why the Orsi draft went wrong

TL;DRThe pipeline's only 'is this fresh?' check was 'did the thread have activity in the last 60 days'. Orsi's was 33 days old — so it passed — and no rule anywhere asks 'has the meeting mentioned in this email already happened?'

Input: a 33-day-old thread saying 'see you at the meeting'. Output: a cheerful confirmation of a meeting that was long over.

Why it mattersPainful part: Notion knew. Orsi (contact 'Ablakdoki') had 10 logged touchpoints — missed-meeting radar, scheduling mixup, contract sent. One lookup would have killed the draft. The same defect was even caught once during the run (another thread) but never turned into a rule.
flowchart TD
  A["Thread: 33 days old"] --> B{"Only check:<br/>under 60 days?"}
  B -- "yes ✅ passed" --> C["Drafter: 'see you<br/>at the meeting!'"]
  D["🗂️ Notion: 10 touchpoints,<br/>meeting already handled"] -. "never consulted ❌" .-> C

2 · The fix: drafter must ask Notion first

TL;DRBefore drafting a single word, the pipeline fetches the lead's touchpoint history from Notion and passes it to the writer AND the QA auditor — plus new date-sanity rules in both. No history available → that lead is blocked, not guessed.

Input: lead's email address. Output: their full CRM story (stage, past meetings, contracts) attached to the drafting context — or a hard stop.

Why it mattersThis turns 'the AI should be careful' into a structural guarantee: a draft physically cannot be written without the lead's history in front of the writer. The 51 drafts already sitting unsent get re-audited through the same checks before you review them.
flowchart LR
  A["Lead email"] --> B["Fetch Notion<br/>touchpoint history"]
  B -- ok --> C["✍️ Draft with<br/>full context"] --> D["🕵️ QA: date-sanity<br/>+ history match"] --> E["📝 Unsent draft"]
  B -- fails --> F["⛔ Lead blocked"] --> G["🤖 Repair agent<br/>on devbox (Opus)"] -- fixed --> B

3 · The proof framework: trust nothing, verify nightly

TL;DREvery night, the system compares the day's incoming Missive emails against Notion's Activity Log — every single email must have a matching touchpoint row. Any gap → RED alert naming the exact missing email. Plus a one-time audit of the past 90 days, and a daily '📬 14/14 linked, streak: 12 days' line in your morning report.

Input: today's inbox + Notion's log. Output: a match receipt — or a red flag pointing at exactly what slipped through.

Why it mattersYou asked for a way to PROVE it's 100% right, not hope. This is an accountant's reconciliation, not a vibe: two independent lists compared line by line, every day, with a visible streak so silent breakage is impossible.
flowchart LR
  A["📬 Today's Missive<br/>inbound list"] --> C{"Compare<br/>line by line"}
  B["📒 Notion Activity Log<br/>rows today"] --> C
  C -- all matched --> D["✅ '14/14 linked,<br/>streak: 12' in report"]
  C -- gap --> E["🔴 RED alert:<br/>exact missing email"]

4 · Self-healing: the 3am run never just dies

TL;DRYour design: if the overnight run can't load a lead's history, it doesn't guess and doesn't quit — it wakes an Opus agent on your Linux devbox that keeps working the problem until history loads, then tells the Modal app to continue.

Input: 'history fetch failed at 3am'. Output: a repair agent that retries until it's fixed, then the run resumes — you find a finished run in the morning, not a crashed one.

Why it mattersThe failure mode of a hard gate is stalling; this keeps the guarantee (never draft blind) without the cost (mornings lost to stuck runs). If the box is offline, the lead simply stays blocked and you get the RED alert — safe either way.

⏭️ Next steps

TL;DRThis was the intent-locking phase. Next: paste the prepared prompt into a FRESH Claude Code chat — Instance 2 researches the technical details (the 5 deferred decisions) and writes the step-by-step build checklist; Instance 3 then executes it.

You: copy one prompt block → new chat. Claude: everything else. Separately, a browser agent is auditing your Notion connections and removing n8n's API access.

Why it mattersFresh contexts keep each phase sharp — the plan is fully written down, so nothing lives only in this chat's memory.

💡 Fun facts & practical stuff

TL;DRFindings worth keeping from today's investigation.

1) You already OWN 80% of this: the app has a webhook that logs every inbound email to Notion with a CRM relation — the drafting skill just never used it. 2) Orsi's contact had a touchpoint literally called 'missed-meeting radar' — the answer was one query away. 3) The identical stale-date bug was caught on another thread DURING the July 19 run and noted in the log, but never became a rule — proof that rules must live in files, not in run notes. 4) Your Modal free tier is at its 5-cron cap, so the nightly proof-check will ride inside an existing job instead of adding a new one. 5) Your CRM's 'Last contact' date already auto-bumps on every touchpoint — the streak counter gets that for free.

Why it mattersThe cheapest reliability wins come from wiring together what already exists — this whole plan adds almost no new infrastructure.
Full handoff (technical) →Prompt for Instance 2 →