ClientsFlow · Email-System Overhaul · W5 · EBO

EBO — W5 Recover Stranded Features

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.

✅ Owner decisions — ALL SETTLED (2026-07-12, DECISIONS_FINAL.md). Nothing here is open; the run never guesses, defaults or flags amber outside the one deliberate AMBER below.
✔ D1 F6 (S2) — the classifier eval reports its miss-count and the verdict STAYS AMBER. S2 prints the false-negative number, records it, and closes as AMBER by design: it may never self-declare CLOSE, and never route on its own authority — Mátyás reads the number and decides. This single AMBER is a deliberate, permanent verdict, not an unanswered question — do not "fix" it, do not upgrade it to GREEN, do not re-open it as a decision. A run that returns S2 as GREEN/CLOSE has broken the rule.
✔ D2 F8 (S3) — THREE live test calls, not one. The recorder confirm-not-regress runs three separate ZZ-W5-MEET calls and records three latency deltas. There is no "single-sample" caveat anywhere: a one-call run is an incomplete run, and S3 is only GREEN when all three calls saw the notetaker auto-join.
✔ D3 Signing (S1) — replay the DocuSeal "both signed" webhook. The ZZ contract is never hand-signed by either party; the "both signed" state is reached exclusively by webhook replay (or the existing backup-poll reconciliation), which is reversible and leaves no real signature artifact.
What W5 owns
The live verdicts: for each remaining stranded candidate, one clean click-through on the real app that upgrades a code-grep verdict to a seen-it-work verdict — plus the recover-or-route call per item, and the ZZ test-data cleanup that closes the entire overhaul test round.
What W5 only routes (owned elsewhere)
Anything found missing is routed, never built here: the proposal workbench (Q27=A) → W2's one-page inline workbench; a classifier retune (if the eval says so) → the Templates/prompt-iteration owner; Fireflies dispatch latency → its existing plans/meet-recorder-autojoin-5s/ plan. W5 hands over verdicts with exact anchors; it writes zero product code.
You do → click/action/hover You should see → on-screen result Element changes → copy · look · where What changes underneath → data/state Must NOT happen → bug guard 🕓 Touchpoint history → impact on the card's history (or —)
Owner rulings folded into this final (comments > ANSWERS_ROUND3 > handoff)Signing is settled by the owner, not by this run: the DocuSeal signing flow (rep's own signing link, the client's link, draw-only signatures) "works perfectly based on prior tests" — F7(a) and F7(c) are CLOSED on the owner's word; the draft's signing-button scenario is deleted, not tested. The tax-number (adószám) validation check is removed from this EBO entirely on owner instruction — see the cross-workstream note below. The token-access gate is removed as a tested scenario: it is a plain precondition (below), not a behavior worth a verdict. Cleanup (S5) runs LAST in the whole test round — after every workstream's EBO has been walked — so the big round finishes on a clean board.
Ground rulesQ22=A: every verification that creates data runs live-fire with 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.
Invariants that hold everywhere — W5 changes no product code and deploys nothing; every created artifact carries the 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).
Access precondition (not a tested scenario): use the current dash token 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.
Stable sentinel identities (re-created verbatim on every replay): 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).

S1 — F10: both parties signed → exactly ONE client email (existing flow, verify unchanged)

Who: System (signing completes) + Verifier watching the ZZ inbox  ·  Where: staging, sentinel deal ZZ-W5-SIGN Kft ([email protected])  ·  When: The old complaint: after both parties signed, the client got two separate emails (one with the signed document, one with the payment link). The code says this was consolidated into one email long ago — this scenario proves it live, end to end. Existing flow, verify unchanged. Owner ruling (D3): the "both signed" state is reached by replaying the DocuSeal "both signed" webhook against the ZZ deal — the contract is never hand-signed by either party.

#You doYou should see Element that changes
copy · look · where
What changes underneathMust 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

S2 — F6: is the reply-classifier still burying interested leads? (one measured run · no board click)

Who: Verifier runs it; Mátyás decides on the number  ·  Where: offline — no emails, no leads, no board  ·  In plain terms: every reply that comes in is read by the AI, which decides "interested" or "not interested". When it wrongly calls an interested lead "not interested", that lead quietly disappears from the pipeline — the expensive mistake. There is already a fixed set of ~20 real Hungarian replies with the right answer written next to each. This scenario feeds that set to the classifier that is live today and counts how many interested ones it got wrong. That count is the whole scenario. Nothing is sent, nothing is changed — a number comes out, and Mátyás decides whether it is good enough. Owner ruling (D1): the eval reports its miss-count and the verdict STAYS AMBER — permanently, by design. S2 may never self-declare CLOSE and never route on its own authority; the number is the deliverable, the decision is the owner's. This AMBER is the specified outcome, not an unanswered question — nobody should "fix" it into a GREEN.

#You doYou should see Element that changes
copy · look · where
What changes underneathMust 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

S3 — F8: Fireflies recorder auto-joins a live Meet — three test calls (not stranded / confirm-not-regress)

Who: Verifier (starts the test Meets)  ·  Where: production — staging's crons are inert, so the auto-dispatch poll never fires there; ZZ-tagged calendar event ZZ-W5-MEET, no lead invited, purged in S5  ·  How many: THREE separate live test calls (owner ruling D2) — one call is not a sample, it is luck. All three must see the notetaker auto-join; three latency deltas are recorded. There is no "single-sample" caveat: a one-call run is an incomplete run, not a passing one  ·  When: F8 turned out NOT to be stranded — every related branch is merged, newer tightening landed 07-08, and an active plan bundle owns the remaining latency work. W5's only job: confirm the live behavior has not regressed across three calls, then point anyone chasing latency at the existing owner.

#You doYou should see Element that changes
copy · look · where
What changes underneathMust 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

S4 — F3: the proposal workbench was never built — confirm live, route to W2 (confirmed-missing / routing)

Who: Verifier  ·  Where: staging, sentinel deal ZZ-W5-PROP Kft ([email protected])  ·  When: The stranded claim was a proposal-regeneration workbench with editable prompts. The code audit found it was never built — a deliberate exclusion, no branch holds it. Round 3 settles what happens next: Q27=A rules the workbench IN (one-page inline proposal workbench — edit any text/price inline, one button sends + schedules follow-ups), owned by W2. W5's job here: one honest live look confirming nothing of it exists today, with a screenshot, so W2 builds against a real before-picture instead of a stale "reported shipped" claim.

#You doYou should see Element that changes
copy · look · where
What changes underneathMust 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

S5 — Cleanup: purge every ZZ artifact — the LAST scenario of the entire test round (guardrail / mandatory close-out, Q22)

Who: Verifier  ·  When: Dead last — after every workstream's EBO has been walked (owner ruling: the big test round must finish on a clean board), and after all W5 verdicts are recorded. Q22=A: live-fire ZZ tests, purge after. Everything the round created — ZZ deals, their scheduled and sent test emails, the calendar events (incl. ZZ-W5-MEET), the DocuSeal test submissions — is removed, and the clean board is proven with pixels, not with a "purge succeeded" line.

#You doYou should see Element that changes
copy · look · where
What changes underneathMust 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
🕓 Touchpoint-history note for W5:
W5 is a verification workstream — it never authors a touchpoint on any real lead. The only history it touches belongs to ZZ sentinel deals, and even there it only triggers existing flows (the post-signing email in S1) and then reads the resulting entries to check the history↔sent parity rule (Q7). All sentinel history is archived away in S5. Every real lead's history is untouched by design — a W5 run that wrote to a real card's history would itself be a red-verdict finding.

Work-item → scenario-step mapping

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 itemWhat it deliversProven by (scenario · step)
WI-1 · F10 one-email consolidation, liveBoth-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 measurementA 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-offThree 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 routingLive 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 tableEvery 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
Sign-off — acceptance oracle. By signing, Sarudi Mátyás locks scenarios S1 … S5 and the invariants above as the acceptance answer key for the W5 Recover Stranded Features verification pass. All owner decisions are settled (D1 · D2 · D3, 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.
Sarudi Mátyás  ✔ Final · 2026-07-12 · awaiting sign-off