ClientsFlow · Email-System Overhaul · W5 · EBO
FINAL · owner comments applied · 2026-07-12. W5 is a verification-only workstream: features that were built in past sessions but ended up stranded, reverted, or only claimed done get settled live — clicked on the real app, not just found in the code. W5 builds nothing, merges nothing, deploys nothing: it proves, then routes. Scenarios S1 … S5, covering findings F10 · F6 · F8 · F3 + the mandatory cleanup close-out.
DECISIONS_FINAL.md). Nothing here is open; the run never guesses, defaults or flags amber outside the one deliberate AMBER below.ZZ… sentinel deals and is purged afterwards (S5). Staging is the default surface; S3 (Fireflies) must run on production because staging's crons are inert and the auto-dispatch poll therefore never fires there — it uses a ZZ-tagged calendar event with no lead invited, purged in S5. Q27=A rules the proposal workbench IN (one-page inline workbench: edit any text/price inline, one button sends + schedules follow-ups) — that build is W2's; S4 only confirms live that nothing of it exists today, so W2 starts from an honest baseline. F8 is not stranded: it already has an owner (plans/meet-recorder-autojoin-5s/) — S3 is one confirm-not-regress check and a hand-off, nothing more.ZZ sentinel and is purged; Notion cleanup is archive-only, never a permanent delete; nothing is ever sent to a real lead; each verdict lands as an explicit ✅ CONFIRMED LIVE / ❌ GAP CONFIRMED + owner in the findings log the moment it is decided (never batched in memory).57723d9da370c5ff3afcd52e; if it returns 403 it has rotated again — pull the current FORM_TOKEN_SECRET from the clientsflow Modal secret store. Never a locally computed token (the local secret is stale and always 403s). No live access = no W5 run.ZZ-W5-SIGN Kft / [email protected] (S1, staging) · ZZ-W5-PROP Kft / [email protected] (S4, staging) · calendar event ZZ-W5-MEET (S3, production, no lead invited).| # | You do | You should see | Element that changes copy · look · where |
What changes underneath | Must NOT happen | 🕓 Touchpoint history |
|---|---|---|---|---|---|---|
| 1 | Seed the staging deal ZZ-W5-SIGN Kft up to the awaiting-signature stage, then bring it to "both signed" by replaying the DocuSeal "both signed" webhook against it (D3; the existing backup-poll reconciliation path is the only permitted fallback) — never by actually signing the contract |
Within the normal processing window the ZZ-W5-SIGN Kft card leaves the awaiting-signature column and sits in the post-signing / payment column — the signed-contract flow has fired | Copy: the card still reads ZZ-W5-SIGN Kft; its stage label advances · Look: the card moved columns, no error ring · Where: the staging board | The existing post-signing flow runs: signed document fetched, Stripe deposit link ensured (proposal_link_stripe), the client email composed and sent, signed_doc_emailed_at stamped on the deal — all pre-existing behavior, W5 only triggers it on a sentinel deal |
Must NOT reach "both signed" by hand-signing the ZZ contract as either party (D3: webhook replay only); must NOT run against a real lead's deal; must NOT run on production (staging + ZZ only); must NOT leave the card stuck in awaiting-signature with the flow half-fired | The signing event lands in the ZZ card's history per the existing rules; the outgoing client email lands as one outbound touchpoint — checked in step 2. |
| 2 | Open the sentinel inbox for [email protected] and count the client-facing emails this signing event produced |
Exactly ONE client email — subject "Aláírt szerződés - ClientsFlow" — carrying all three payloads in one body: the signed-contract download link, the Stripe payment link, and the bank-transfer details with the exact amount | Copy: one Hungarian email; signed-doc link + fizetési link + átutalási adatok (számlaszám + összeg) · Look: a single message in the thread · Where: the ZZ sentinel inbox | Verdict recorded: F10 ✅ CONFIRMED LIVE if one email carries all three; ❌ GAP if a second client email arrived or a payload is missing | Must NOT find two separate client emails (the original bug); must NOT find the Stripe link or the amount missing; must NOT show a raw {{greeting}} token; must NOT count the internal rep-copy as a client email (it is a separate, clearly-labeled internal message — expected) |
EXISTING ENTRY — verify parity The ZZ card's history shows this send as ONE outbound touchpoint whose stored copy matches the email in the inbox word-for-word (the 100% history↔sent parity rule, Q7). |
| 3 | Check the internal side of the same event: the rep-copy notification | One clearly-labeled internal notification — subject "Signed contract — ZZ-W5-SIGN Kft", in English, to the rep — separate from the client email, so the owner learns the contract closed without the client seeing a second message | Copy: English internal notification with the signed-doc link · Look: owner-side inbox, not the client thread · Where: the rep mailbox | Nothing new — confirming the shipped design (one client email + a separate internal copy) is intact as a pair | Must NOT find the internal copy addressed to the client; must NOT find it missing entirely (the owner would be blind to closings); must NOT find Hungarian client copy inside the internal notification | — |
| # | You do | You should see | Element that changes copy · look · where |
What changes underneath | Must NOT happen | 🕓 Touchpoint history |
|---|---|---|---|---|---|---|
| 1 | Run the fixed reply set through the classifier that is live today and read off the count of wrong "not interested" calls | A concrete printed number: "X of N interested replies were called not-interested" — plus the pass rate (positive recall). No adjectives, a number | Copy: a single result line beginning F6_EVAL with false_negatives, positive_recall, n · Look: terminal output, copied verbatim into the W5 findings log · Where: offline run against the live prompt |
Read-only evaluation over the fixed labelled set; the live prompt is not touched. The number + timestamp become F6's evidence | Must NOT edit or "quickly improve" the live prompt during the run (W5 is verify-only); must NOT let the run send anything or touch real lead data; must NOT report a verdict without the number | — |
| 2 | Write the verdict into the findings log: the miss-count, and the verdict AMBER (D1 — the only permitted outcome) | Exactly one shape, always: AMBER — "F6: X of N interested replies were called not-interested (positive_recall = …). Verdict AMBER by owner ruling — Mátyás decides whether this closes F6 or routes to prompt iteration." No CLOSE, no self-declared ROUTE, no threshold invented by the run | Copy: the F6 AMBER verdict line, quoting the number · Look: — · Where: the W5 findings log | Nothing in the product — one number, handed to the owner with the decision left to him | Must NOT record F6 as CLOSE/GREEN/PASS under any count (including 0 false negatives — even a perfect score stays AMBER); must NOT invent an acceptance threshold; must NOT route F6 to another owner on the run's own authority; must NOT retune the classifier inside W5; must NOT close F6 without the number as evidence; must NOT flag this AMBER as an open decision needing an answer — it IS the answer | — |
| # | You do | You should see | Element that changes copy · look · where |
What changes underneath | Must NOT happen | 🕓 Touchpoint history |
|---|---|---|---|---|---|---|
| 1 | Run THREE separate live test Google Meets on ZZ-W5-MEET (each: the owner account + one test account, no lead), each time waiting through a full poll cycle — three distinct calls, not one call observed three times |
On each of the three calls the recorder joins on its own, within the ~10-second poll cadence — the notetaker appears in the participant list exactly as it would after clicking the manual dispatch button. Three joins out of three | Copy: the Fireflies notetaker in the Meet participant list of ZZ-W5-MEET, on all three calls · Look: a new participant joins the call, three times · Where: the test Meet window | The merged auto-dispatch path fires on each live-call signal and prints its signal->ack latency; nothing is configured or changed — pure observation. All three latency deltas are copied into the findings log so the recorder plan's owner accumulates real datapoints instead of pass/fail bits |
Must NOT stop at one call and call it done (D2: three calls, three deltas — a single-call run is incomplete, never "GREEN with a single-sample caveat"); must NOT declare S3 GREEN if the notetaker failed to auto-join on any one of the three; must NOT invite a real lead to a test call; must NOT treat a signal missed outside the poll window as a new bug to fix here (that is the documented architectural ceiling, owned by the recorder plan); must NOT change any recorder code or config during the run | The call's transcript/archive entries follow the existing call-layer rules once the recorder joins — W5 writes nothing to history itself. |
| 2 | Record the hand-off in the findings log | F8 marked NOT STRANDED with all three dispatch latencies (call 1 / 2 / 3) attached and a pointer: all further latency/reliability work belongs to plans/meet-recorder-autojoin-5s/ + its meet-recorder-qa checks — not to this overhaul |
Copy: the routing line in the findings log · Look: — · Where: findings log | A recorded routing decision; prevents duplicate ownership of the same feature area | Must NOT record fewer than three latency deltas; must NOT attach a "single-sample" caveat to the verdict (that caveat is dead — D2 replaced it with three calls); must NOT leave F8 listed as an open recovery item after this run; must NOT scope any recorder work inside W5 or the overhaul | — |
| # | You do | You should see | Element that changes copy · look · where |
What changes underneath | Must NOT happen | 🕓 Touchpoint history |
|---|---|---|---|---|---|---|
| 1 | On the staging dash, walk the proposal path for ZZ-W5-PROP Kft to the proposal preview step and inspect every control on it; screenshot the screen |
Today's proposal preview for ZZ-W5-PROP Kft, with whatever inline editing exists today noted exactly as found — and no editable system/user prompt pair, no regenerate-with-edited-prompt control, no single send-and-schedule button anywhere on it | Copy: today's proposal-step controls, listed as found · Look: the existing preview screen, captured as W2's before-picture · Where: the proposal step on the staging dash | Nothing — observation only. Verdict recorded: F3 ❌ CONFIRMED NEVER BUILT (the live look matches the code audit); the screenshot is attached to the findings log as W2's baseline | Must NOT "find" the workbench by generously reading an existing edit box as one (the claim is specific: editable prompts + regenerate + one send-and-schedule button); must NOT start building any part of it here; must NOT send the ZZ proposal to anyone | — |
| 2 | Record the routing: F3's rebuild = the Q27=A one-page inline workbench, owned by W2 | The findings log states it plainly: the old handoff said "owner-decide-priority"; round 3 decided — build it (Q27=A), in W2; W5 contributes the confirmed-clean baseline + screenshot and nothing else | Copy: routing + supersede note · Look: — · Where: findings log + W2's queue | A routing decision with the round-3 anchor and the baseline screenshot attached | Must NOT leave two contradictory verdicts alive (the handoff's "if still wanted" vs Q27's "wanted") — the log must state round 3 wins; must NOT scope or design the workbench here | — |
| # | You do | You should see | Element that changes copy · look · where |
What changes underneath | Must NOT happen | 🕓 Touchpoint history |
|---|---|---|---|---|---|---|
| 1 | Purge every ZZ sentinel artifact the round created: the ZZ deals (incl. ZZ-W5-SIGN Kft, ZZ-W5-PROP Kft), their scheduled AND already-sent test emails, the calendar events (incl. ZZ-W5-MEET on production), and any DocuSeal test submission |
Each purge step reports done, surface by surface; Notion-side removals are archive operations (reversible), never permanent deletes | Copy: — · Look: ZZ artifacts gone from every surface they touched · Where: staging store, production calendar, Notion (archived), sentinel inbox, DocuSeal | Sentinel records removed/archived across every system the round touched; the findings log lists what was purged, item by item | Must NOT permanently delete anything in Notion (archive only — standing invariant); must NOT purge anything lacking the ZZ sentinel; must NOT skip a surface — a leftover ZZ email or calendar event is a failed cleanup, not a detail | The ZZ cards' history disappears with the archived cards — no real lead's history is touched at any point. |
| 2 | Reload the board and sweep for leftovers; screenshot the clean board as the final attachment of the findings log | No ZZ card in any column, no ZZ calendar event left, and no test email left in the sentinel inbox or the outbox queue — and the findings log closes with the full verdict table (F3 · F6 · F8 · F10 outcomes + owners), the deliverable the next workstreams build on | Copy: a clean board · Look: no sentinel cards anywhere; the board screenshot is the last attachment in the log · Where: the staging board (+ production calendar checked empty of ZZ events) | Run closed; verdict table final; cleanup proven the same way the features were — by pixels, not by a log line | Must NOT close the run with any verdict still marked "pending"; must NOT report clean without the board screenshot; must NOT leave a ZZ calendar event or test email behind after reporting clean | — |
Each W5 verification work item (one per remaining stranded-feature candidate), and the scenario steps that settle it live. This table is the acceptance contract: an item is done when its steps are GREEN and their probes pass.
| Work item | What it delivers | Proven by (scenario · step) |
|---|---|---|
| WI-1 · F10 one-email consolidation, live | Both-signed event → exactly ONE client email carrying the signed-doc link + Stripe link + bank details, the internal rep-copy separate, history↔sent parity verified. | S1.1 · S1.2 · S1.3 |
| WI-2 · F6 classifier false-negative measurement | A measured count of interested replies wrongly called not-interested, on the frozen set, against the live prompt — recorded with a verdict of AMBER, always (D1: the run reports the number, the owner decides; CLOSE is not an outcome the run may reach). | S2.1 · S2.2 |
| WI-3 · F8 confirm-not-regress + hand-off | Three live production Meets confirm the recorder auto-joins within the ~10s cadence on every one of them, with all three latency deltas captured (D2); all further recorder work routed to its existing plan owner. | S3.1 · S3.2 |
| WI-4 · F3 clean baseline + Q27 routing | Live confirmation (with screenshot) that the proposal workbench was never built, plus the recorded supersede: round-3 Q27=A rules it IN, built by W2. | S4.1 · S4.2 |
| WI-5 · ZZ purge + closed verdict table | Every sentinel artifact archived/removed across all surfaces (deals, emails, calendar events, DocuSeal), a pixel-proven clean board, and the final F3/F6/F8/F10 verdict table as W5's deliverable. Runs last in the whole test round. | S5.1 · S5.2 |
DECISIONS_FINAL.md) — nothing in this EBO is open. The pass runs verify-only: gaps found are routed to their named owners (W2 · prompt-iteration · the recorder plan), never built inside W5. S2's F6 verdict closes as AMBER by design — that is the specified outcome, not a loose end. S5 runs last in the entire test round, so the round ends on a clean board.