ClientsFlow · Email-System Overhaul · W0 · EBO · FINAL
FINAL — owner comments folded in · 2026-07-12. The alarm layer that ships FIRST, as the rider for the whole drop (Q24=A): from the moment W0 is live, a dead schedule, a duplicate send, an accidentally armed auto-send flag, or hosting spend drifting past its budget each rings a bell on its own, within minutes, with zero polling by you. And the one thing that caused the July incident — a second copy of the app — is not monitored, it is made impossible. Scenarios S1 … S7.
ZZ-W0-BASE Kft — the baseline lead card that must be visible on the staging board in every W0 frame (proves the walker is looking at the seeded staging board, not some other screen).ZZ-W0-DUP Kft — the lead seeded with the same email type sent exactly 2× in 24h — the threshold boundary itself (D4 = 2), so the seed proves the new line rather than merely clearing an old one (S6/S7: the duplicate alarm must name it and say "2×").ZZ-W0-REM Kft — the lead on the payment chase: one reminder per calendar day, on consecutive days — the single recognized cadence, exempt from the duplicate rule (S6.1: must NEVER be flagged as a duplicate, even though two of its sends fall inside one rolling 24h window).$BASE = the staging pipeline URL (https://matyas-staging--clientsflow-pipeline-web.modal.run), $DASH_TOKEN = the staging dash token. The only curly placeholder the walker binds is {lead_id}.| # | You do | You should see | Element that changes copy · look · where |
What changes underneath | Must NOT happen | 🕓 Touchpoint history |
|---|---|---|---|---|---|---|
| 1 | Mátyás opens the dashboard on a healthy day | No health banner anywhere — W0 adds nothing visible to a clean dash. (Whatever the dash looks like after the other workstreams land, W0's contribution on a clean day is zero pixels.) | Copy: — · Look: no banner rendered at all when every check is green · Where: top of the dash (the banner's slot stays empty) | The watchdog checks re-ran quietly in the background on their own schedules (all-5-schedule freshness, auto-send flag, hosting spend, duplicate-send scan) — all green, so the dash health payload's alerts list is empty and nothing renders |
Must NOT show a permanent "all systems OK" banner or badge (green noise trains him to ignore the slot); must NOT slow the dash load by even a beat — checks run on the server's own schedule, never on page-open | — (W0 never writes history) |
| # | You do | You should see | Element that changes copy · look · where |
What changes underneath | Must NOT happen | 🕓 Touchpoint history |
|---|---|---|---|---|---|---|
| 1 | Nothing — the build deletes every leftover copy of the app in the personal workspace, permanently | Nothing on screen. The old addresses stay dead forever: asking either of them anything gets no answer at all (they no longer exist, rather than "existing but stopped") | Copy: — · Look: — · Where: no UI change; the proof lives in the deploy log + the probe below | The duplicate pipeline app and duplicate booking app are deleted from the personal hosting workspace (not merely stopped — a stopped app can be revived by a stray deploy, a deleted one cannot be woken by accident). The deletion is recorded in the ship ledger | Must NOT leave a stopped-but-present copy behind (that is exactly what got revived in July); must NOT add any recurring "is the ghost back?" probe, banner, or Slack alarm — the owner cut that machinery; must NOT touch the real production apps | — |
| 2 | Nothing — someone (or some future agent) runs a deploy without the pinned production workspace credentials | The deploy refuses to run and says why, in English — it never falls back to whatever workspace happens to be configured in the shell. No second app is ever created | Copy: the deploy script's refusal message names the missing production credential · Look: the deploy stops with a non-zero exit · Where: the terminal / the agent's deploy step | The deploy script fails closed when the production workspace credentials are absent, so a bare or mis-configured deploy can no longer land in a personal workspace and mint a duplicate app — the exact 2026-07-06 mechanism. A regression test pins this behavior in the suite forever | Must NOT deploy "somewhere" as a fallback; must NOT print the credentials; must NOT be bypassable by an env var set in the calling shell | — |
| # | You do | You should see | Element that changes copy · look · where |
What changes underneath | Must NOT happen | 🕓 Touchpoint history |
|---|---|---|---|---|---|---|
| 1 | Nothing — one schedule (say the CRM sync) silently stops running | Once it has been quiet for 3× its normal interval, a Slack alert in the dedicated alerts channel names it precisely and spells out the consequence — "⚠️ Schedule stalled: CRM sync — last ran 22 min ago (normal: every 5). Leads' CRM data is going stale." — and the dash shows the same as an amber health banner | Copy: banner "⚠️ Schedule stalled: CRM sync" + the minutes + one plain consequence line · Look: amber banner strip at the dash top, above the tabs, on every tab · Where: dash top + the dedicated Slack alerts channel | Every schedule stamps a "last ran" mark when it completes; the 10-minute watchdog compares all five stamps (including the CRM sync, which today is stamped but never read — that gap closes here) against 3× each one's own interval. Every alarm carries its own consequence sentence, fixed per schedule ("reminder emails are not going out", "the board is going stale", …) | Must NOT watch only 4 of the 5 (today's bug); must NOT alert on a single slightly-late run (3× the interval is the line, so a busy cycle never cries wolf); must NOT say a vague "a cron is stale" — always the name + the minutes + the consequence line | — |
| 2 | The schedule recovers (on its own, or after a fix run from the alarm's paste-prompt) | The banner clears on its own within one watchdog cycle (≤10 min) and one recovery line lands in Slack — "✅ CRM sync running again (was quiet 41 min)." | Copy: banner removed; one Slack recovery line with the total quiet gap · Look: clean dash again · Where: dash + Slack | A fresh "last ran" stamp arrives; the stale signal clears; the alert de-dup marker resets so a FUTURE stall of the same schedule alarms again as a new episode | Must NOT keep alerting every 10 minutes while stalled (one alert per episode, the banner carries the ongoing state); must NOT stay silent if the same schedule stalls AGAIN next week (each episode is new); must NOT require a manual "dismiss" click to clear a resolved alarm | — |
| # | You do | You should see | Element that changes copy · look · where |
What changes underneath | Must NOT happen | 🕓 Touchpoint history |
|---|---|---|---|---|---|---|
| 1 | Nothing — a deploy or a settings change flips the auto-send master flag ON in production | Within 10 minutes: an urgent Slack alert — "🚨 Auto-send is ON in production. Emails can go out without your review. If this wasn't you, paste the prompt below into Claude Code." — plus a red dash banner saying the same, carrying the paste-prompt behind its "Details" link | Copy: banner "🚨 Auto-send is ON in production" + Details · Look: red banner at the dash top · Where: dash top + the dedicated Slack alerts channel | The 10-minute watchdog reads the flag's live production value each run; ON → one alert + banner, both carrying a paste-prompt composed from the live fact. W0 does not flip the flag back (it never intervenes) — it makes the state impossible to miss | Must NOT auto-flip the flag off (one day he may genuinely mean it — the alarm asks, never decides); must NOT alert repeatedly while it stays on (one alert + the persistent banner); must NOT take days to notice (the July 8 failure) | — |
| # | You do | You should see | Element that changes copy · look · where |
What changes underneath | Must NOT happen | 🕓 Touchpoint history |
|---|---|---|---|---|---|---|
| 1 | Nothing — a normal month, hosting spend tracking under the ~$30 budget | Nothing. No banner, no Slack line about money, all month. The app runs at full speed the entire time | Copy: — · Look: — · Where: — (spend detail stays where it already lives, on the Usage tab) | The 10-minute watchdog reads the hosting month-to-date figure (or, if it isn't readable live, a computed estimate — D5) and compares it with the ~$30 budget. Under budget → no signal. Separately, the hosting account's own billing limit is raised far above the budget, so the platform itself can never start rejecting work | Must NOT surface routine spend numbers as alarms; must NOT include AI/Gemini spend in this figure (hosting only — owner ruling); must NOT leave the hosting platform's own billing limit anywhere near $30, where it could reject a real lead's webhook | — |
| 2 | Nothing — hosting month-to-date drifts past the ~$30 budget | One Slack heads-up — "💸 Hosting spend passed the $30/month guide: $32.40 month-to-date (day 19, ≈ $51 at this pace). Nothing has been throttled — this is FYI." — and an amber note on the dash health banner. Everything keeps running at full speed | Copy: banner "💸 Hosting spend passed the $30/month guide" + the amount + the month-end pace projection · Look: amber banner · Where: dash + the dedicated Slack alerts channel | The threshold-crossing fires exactly once per month; the marker remembers it fired, and resets automatically on the 1st. If the figure is an estimate rather than a live reading, the message says so | Must NOT re-alert every 10 minutes while over budget; must NOT throttle, pause, block, degrade, or slow down ANY function, send, page or AI call to save money (owner ruling — the budget is a signal, never an enforcement); must NOT forget to reset the marker at month roll-over (or month 2 gets no heads-up) | — |
| # | You do | You should see | Element that changes copy · look · where |
What changes underneath | Must NOT happen | 🕓 Touchpoint history |
|---|---|---|---|---|---|---|
| 1 | Nothing — a normal day, including a lead legitimately in the daily payment-reminder chase | Nothing — the scan runs silently every 10 minutes and finds no repeats. The payment chase's one-reminder-per-calendar-day cadence is never flagged, even when two of its reminders land inside one rolling 24h window | Copy: — · Look: — · Where: — | Every 10 minutes the watchdog scans the sent-email record for the same email type going to the same lead 2+ times inside a rolling 24h window (D4 = 2, settled). The payment-chase reminder template is the ONE exempt cadence: at most one such send per calendar day is by design (W1's named 3-reminder constant) and never counts as a duplicate — none found here, no signal | Must NOT flag the payment chase's designed cadence (its exemption is what keeps this row green at a threshold of 2); must NOT widen that exemption to any other template — every other same-email repeat inside 24h rings, a manual resend included (owner-accepted) | — (W0 reads the send record; it never writes it) |
| 2 | Nothing — something sends the same email to the same lead a second time inside 24h (the seeded ZZ-W0-DUP lead: 2× the same template) | Within ~10 minutes a Slack alert naming both — "🚨 Duplicate sends: 'Follow-up #2' went to ZZ-W0-DUP Kft 2× in the last 24h. Possible retry bug or a second sender — open the lead's history." — plus a red dash banner with the lead's name, whose "Details" link carries the paste-prompt and a link straight to that lead's card | Copy: banner "🚨 Duplicate sends detected — ZZ-W0-DUP Kft got the same email 2×" + Details · Look: red banner at the dash top · Where: dash + the dedicated Slack alerts channel | The 10-minute scan found 2 sends of the same template to the same lead in a rolling 24h — the threshold (D4 = 2) — and raised one alert for the episode. Detection only — W0 does not retract, pause, or block anything (send gating is W1's territory) | Must NOT wait for a third copy before ringing (3+ was the old default; 2 is the settled line); must NOT block or delay the send pipeline in any way; must NOT report the duplicate anonymously ("duplicates found") — always the lead name + which email + how many times; must NOT re-alert every 10 minutes for the same episode | The duplicate rows are already in the lead's touchpoint history (written by the send path) — that history is exactly the evidence the alarm points him at. W0 adds nothing to it. |
| # | You do | You should see | Element that changes copy · look · where |
What changes underneath | Must NOT happen | 🕓 Touchpoint history |
|---|---|---|---|---|---|---|
| 1 | Mátyás reads any prod-misbehavior alarm (the Slack message, or the banner's "Details") | Below the plain-language description, a ready-to-copy block: "Paste this into Claude Code →" followed by a complete, self-contained prompt naming the actual thing that broke — e.g. "Duplicate emails are going out: 'Follow-up #2' reached ZZ-W0-DUP Kft 2× in 24h on production. Find what is sending them, stop the repeats, and tell me which leads were affected." | Copy: one copyable prompt block per alarm, in English, with no placeholders left unfilled · Look: a code block in the Slack message; a copy button in the banner's Details view · Where: inside every systemic alarm from S3 / S4 / S6 | Each check composes its paste-prompt from the live facts it just measured (which schedule, which lead, which email) at alarm time — not a generic template. Each prompt describes the problem and the desired end-state, never step-by-step commands — so it cannot rot as the codebase moves; Claude Code works out the current steps fresh each time | Must NOT execute any rollback, stop, or fix automatically (Q25 — the human fires the prompt, always); must NOT hand him a vague prompt ("something is wrong, investigate") — it names the exact object and the exact desired end-state; must NOT bake in step-by-step commands that go stale | — |
| 2 | Mátyás pastes the prompt into Claude Code and lets it run | Claude Code performs the fix; within one watchdog cycle the relevant banner clears itself and the recovery line lands in Slack — confirmation comes from the watchdog re-measuring reality, not from anyone declaring success | Copy: the standard recovery lines from S3 / S4 / S6 · Look: banner clears on its own · Where: dash + Slack | The watchdog keeps polling on its normal schedule; the all-clear appears only when the next real measurement is actually green | Must NOT clear the banner because a fix was attempted — only because the next check measured healthy (the "deploy said success but wasn't" lesson from July 6) | — |
Each build work item for W0, and the scenario steps that prove it works when exercised on staging (failure modes are forced with ZZ-sentinel fixtures on staging only — never against real prod alarms; the seeded identities are the constants ZZ-W0-DUP Kft and ZZ-W0-REM Kft, re-created verbatim on every reseed).
| Work item | What it delivers | Proven by (step ids) |
|---|---|---|
| WI-1 · Single-app guarantee | The leftover duplicate pipeline + booking apps are deleted from the personal workspace (not stopped); the deploy script fails closed without the pinned production workspace credentials, with a regression test locking it. No ghost probe, no ghost alarm, no ghost banner. | S2.1 · S2.2 |
| WI-2 · Full schedule-staleness watch | All FIVE schedules watched (closing the unwatched-CRM-sync gap); stale = quiet for 3× its own interval; the alert names the schedule + the minutes + a fixed plain-language consequence line; recovery auto-clears and re-arms per episode. | S3.1 · S3.2 · S1.1 |
| WI-3 · Auto-send flag sentinel | The production auto-send flag is read every 10 minutes; ON → one urgent alert + red banner + paste-prompt; never auto-flipped back. | S4.1 |
| WI-4 · Hosting-spend heads-up (soft budget) | Hosting month-to-date (AI spend excluded) vs the ~$30 soft budget → exactly one heads-up per month at the crossing, with the pace projection and an "estimated" caveat if the figure isn't live; the hosting account's own billing limit raised far above the budget so it can never reject a webhook; nothing is ever throttled. | S5.1 · S5.2 |
| WI-5 · Duplicate-send scan (10-minute) | Every 10 minutes, scan for the same email type reaching the same lead 2+ times in a rolling 24h window (D4 = 2, settled — the threshold lives in ONE named constant); the alert names lead + email + count and deep-links the card; the payment chase's one-per-calendar-day cadence is the single exemption and is never flagged; detection only. | S6.1 · S6.2 |
| WI-6 · Health banner + health-payload extension | The dash health payload gains an alerts list (staleness incl. CRM sync, auto-send flag, hosting spend, duplicates — each with severity, message, paste-prompt); one banner slot renders red/amber with the specific reason, renders nothing when the list is empty, and clears only by re-measurement. | S1.1 · S3.1 · S3.2 · S4.1 · S5.2 · S6.2 · S7.2 |
| WI-7 · Dedicated Slack alerts channel | Systemic alarms move out of the lead-followup channel into one dedicated alerts channel; one message per episode, one recovery line; no Slack for individual send failures. | S3.1 · S3.2 · S4.1 · S5.2 · S6.2 |
| WI-8 · Paste-prompt alarm payloads | Every prod-misbehavior alarm composes a specific, self-contained, end-state-phrased Claude Code prompt from the live facts; NO auto-rollback anywhere; the all-clear only ever comes from a fresh measurement. | S7.1 · S7.2 · S4.1 · S6.2 |