ClientsFlow · Email-System Overhaul · W2 · EBO
DRAFT for owner comments · 2026-07-12. The target touchpoint-history experience after W2 ships — the freeze model (Send generates copy for the whole sequence; the rest is scheduled frozen exactly as previewed), orange scheduled rows with the exact frozen copy, the amber drift-HOLD, the full modal editor reachable straight from history (armed steps AND already-sent records), auto-vs-owner-sent distinction, complete direction labels, full reminder bodies, the compose-AI-reply content, and the missing banner moments. Built from the W2 handoff + ANSWERS_ROUND3 (Q1/Q2/Q4/Q7/Q9/Q10) + the owner's W1 comment round (which overrides both). Scenarios W2-1 … W2-10.
{{tokens}}) and the exact Budapest send datetime; a send NEVER goes out with text differing from what history displayed; an amber row NEVER sends until re-approved; W2 never invents a new send — it edits/holds/records sends that W1 fires; Notion destructive ops stay archive-only.| # | You do | You should see | Element that changes copy · look · where |
What changes underneath | Must NOT happen | 🕓 Touchpoint history | 💡 UX critique + suggestion |
|---|---|---|---|---|---|---|---|
| 1 | Mátyás clicks "Send Emails" on a lead card | The existing sequence modal opens (existing flow, verify unchanged — owner: "the current UI is nice, don't fuck it up") with the copy for every email of the sequence already generated and readable — real name in the greeting, real booking/sign links, canonical sign-off, no raw tokens — and each step shows the exact date + time it is planned to send | Copy: full subject + body per step, e.g. "Kedves János, …" with the real link · Look: the current modal layout, untouched · Where: the Send-Emails modal | Every step's template is resolved against the lead's current data at modal-open; what is displayed IS the candidate frozen copy — no later re-resolution is planned | Must NOT show a raw {first_name}/{{greeting}} token anywhere in the preview; must NOT restyle or restructure the modal; must NOT show a body cut off mid-sentence |
— (nothing sent or scheduled yet; a preview is not a touchpoint) | Critique: If a lead field is empty (no first name yet), silent resolution produces an awkward greeting he might not notice among 5 steps. Suggestion: Highlight any step whose resolution used a fallback/empty value with a small inline marker in the modal, so he catches it before Send — not after the lead does. |
| 2 | He tweaks step 2's wording in the modal, then clicks "Send" | The modal closes immediately — he is free to do other work at once. No waiting screen, no confirmation step to click through | Copy: — · Look: modal gone, board usable instantly · Where: back on the board | In the background: email #1 dispatches now; steps 2+ are stored frozen exactly as previewed (a subject + body snapshot per step, including his tweak) with their send datetimes. The frozen snapshot is what will send — never a fresh re-render at send time | Must NOT keep the modal open waiting for the server; must NOT show a success toast as a required step; must NOT store the raw template instead of the previewed text; must NOT lose his step-2 tweak | NEW ENTRIES Within seconds: email #1 appears as an outbound sent row with the exact text that left; every remaining step appears as an orange "Scheduled" row (see W2-2) carrying its frozen copy + send datetime |
Critique: "Closes immediately + sends in background" means a first-send failure surfaces only later — he must be able to trust the background. Suggestion: Make the acceptance test itself the guarantee: the live QA probe verifies the mail truly left AND the history row matches it byte-for-byte, on every run — reliability proven by test, not by a toast. |
| 3 | Nothing — the background does its job (reliability probe) | A minute later the lead's history already tells the whole truth: one sent row (email #1) + orange scheduled rows for the rest; the sent row's text is identical to what the mail server actually delivered | Copy: sent row = the delivered email, character for character · Look: normal history · Where: Full-history drawer | Parity check passes: stored history body == dispatched mail body (the 100% parity bar, Q7). If the first send FAILED, W1 raises the failure and the card gets the red dashed ring + a banner (W8 styles it) — never a silent gap | Must NOT show a history row whose text differs in any character from the delivered email; must NOT let a failed first send leave history looking as if it sent | The sent row + orange rows from step 2 are now the durable record — the single source of truth for "what did/will this lead get" | — |
| 4 | Failure mode: a template is malformed and copy generation errors when the modal opens | The modal shows a clear plain-English error for the broken step ("This step's template could not be generated — fix it before sending") and Send is disabled until every step has clean copy | Copy: the error line on the affected step · Look: Send button disabled · Where: the modal | Nothing is armed, nothing is half-frozen — the sequence either freezes completely and cleanly, or not at all | Must NOT arm a sequence with one broken/half-frozen step; must NOT send email #1 while later steps failed to freeze; must NOT crash the modal | — (a failed generation writes nothing) | — |
| # | You do | You should see | Element that changes copy · look · where |
What changes underneath | Must NOT happen | 🕓 Touchpoint history | 💡 UX critique + suggestion |
|---|---|---|---|---|---|---|---|
| 1 | Mátyás opens the lead's Full-history drawer | Each not-yet-sent step is an ORANGE row labeled "Scheduled" showing the frozen subject and the FULL frozen body — greeting with the real name, complete text, sign-off — plus the exact Budapest send datetime ("Sends Jul 15, 09:00"). Orange is a genuinely distinct colour from the amber used for warnings/drift — at a glance he can tell "armed and fine" from "needs my re-approval" | Copy: "Scheduled · Sends Jul 15, 09:00" + full frozen subject/body · Look: orange row styling (new orange token — not the existing amber) · Where: top of the history timeline, one row per pending step | The row renders the stored frozen snapshot verbatim — never a live re-resolution of the template; the full body is shown (no 600-char cut) | Must NOT show a raw {first_name}/{booking_link} token; must NOT truncate the body; must NOT reuse the amber warning colour for a healthy scheduled row; must NOT show a send time in the wrong timezone |
Orange rows ARE the forward half of the history — the timeline reads as one continuous story: what happened, then what will happen | Critique: Five pending steps × full bodies makes the drawer very tall before the past events even start. Suggestion: Orange rows show subject + first line collapsed, expanding to the full body on click of a small expander (the row-click itself opens the editor per W2-3, so the expander must be a separate small control). Full body is always one click away, never hidden. |
| 2 | Nothing — a scheduled step's send time arrives and no data drifted | Next time he looks, that orange row has become a normal sent outbound row — same position in time order, same subject, and the body is character-for-character identical to what the orange preview showed | Copy: unchanged text, label flips "Scheduled" → sent · Look: orange → the normal sent-row styling + the Auto marker (W2-6) · Where: the same event, now in the past section | W1's sender dispatched the FROZEN text verbatim (no fresh re-resolve at send time); the history row and the delivered mail are the same bytes — the parity bar, again | Must NOT send re-resolved text that differs from the frozen preview; must NOT leave a ghost orange row after the send; must NOT double-show the event (one orange + one sent for the same step) | The orange row converts in place into the sent record — history never contradicts itself about what a step said | — |
| # | You do | You should see | Element that changes copy · look · where |
What changes underneath | Must NOT happen | 🕓 Touchpoint history | 💡 UX critique + suggestion |
|---|---|---|---|---|---|---|---|
| 1 | Mátyás clicks an orange "Scheduled" row in the history drawer | The full modal editor opens — the same rich editor UI as the Send-Emails modal, scoped to this ONE step: subject and body editable, the send datetime shown, the lead's name/links already resolved in the text | Copy: the step's frozen subject + body, editable · Look: the familiar full modal (not a cramped inline field) · Where: opens over the drawer | The editor loads the stored frozen snapshot for exactly this step; other steps and the schedule are not loaded for editing | Must NOT open a lighter inline-edit or a read-only preview (Q10 is explicit: the FULL modal editor); must NOT open the whole-sequence editor when one row was clicked | — (opening an editor is not an event) | Critique: Row-click = edit is powerful but easy to trigger while just reading. Suggestion: Cancel/Esc must always close the modal with zero side effects — a look costs nothing. (No extra confirm dialog: closing without saving simply discards.) |
| 2 | He edits the body, clicks "Save" | The modal closes immediately and the orange row in the drawer already shows the new text — what he reads there is what will send | Copy: the row's body = his edited text · Look: row stays orange · Where: the same history row, updated in place | The step's frozen snapshot is overwritten with his edit; the step is marked owner-edited — which is itself the "approved to auto-send" signal (pre-edited scheduled email = whitelisted, per the locked W1 contract); seq_armed_at/seq_next untouched — send time unchanged; any pending drift flag on this step clears (his fresh edit IS the re-approval) |
Must NOT change the send time or any other step; must NOT require redefining/re-arming the whole sequence; must NOT lose the edit if the drawer refreshes; must NOT leave the row showing the old text | ROW UPDATED The orange row now carries the edited frozen copy — still the single truth of what will send |
— |
| 3 | Nothing — that step's send time arrives | The email goes out with his edited text exactly, automatically (owner-edited = approved); the orange row converts to a sent row with the identical text | Copy: delivered email == edited frozen copy · Look: orange → sent · Where: history timeline | W1's gate reads the owner-edited flag and lets the send fire without further clicks; the frozen (edited) text is dispatched verbatim | Must NOT send the pre-edit text; must NOT hold an owner-edited step waiting for another approval; must NOT clear the owner-edited flag automatically | Sent row appears with the edited copy — parity holds through the edit path too | — |
| # | You do | You should see | Element that changes copy · look · where |
What changes underneath | Must NOT happen | 🕓 Touchpoint history | 💡 UX critique + suggestion |
|---|---|---|---|---|---|---|---|
| 1 | Mátyás corrects the lead's name in the Details panel (a W3 surface) — a sequence step is still scheduled | The affected scheduled row flips from orange to AMBER, labeled "On hold — lead data changed", with a one-line plain reason ("Lead name changed since this email was frozen") | Copy: "On hold — lead data changed" + the reason line · Look: orange → amber warning styling · Where: the affected row(s) in the history drawer | The drift check compares a fresh resolution of the raw template against the stored frozen text; on mismatch the step is flagged drifted and its send is blocked. Only genuinely affected steps flip — a step whose text doesn't use the changed field stays orange | Must NOT keep the row orange when its copy is stale; must NOT flip steps that don't use the changed field; must NOT silently re-resolve and send the NEW data either — nothing sends until he re-approves | ROW STATE The scheduled row itself carries the hold state — history is where he discovers AND fixes it |
Critique: He edits the name in the Details panel and walks away — the amber row sits in a drawer he may not open for days, while the send date passes. Suggestion: When a hold is created, surface it on the existing banner surface ("Scheduled email on hold — {lead}"), click-through to the card. Uses the banner system that already exists; no new UI. ❓ owner: apply? |
| 2 | Nothing — the held step's send time passes while it is still amber | Nothing is sent. The amber row stays put, its label now reading "On hold — send time passed"; the lead receives nothing | Copy: label gains "send time passed" · Look: still amber · Where: the held row | The sender skips held steps entirely — the HOLD is enforced at the send gate, not just cosmetically in the drawer | Must NOT send the frozen (stale) text; must NOT send a freshly re-resolved text; must NOT quietly drop/delete the step — it waits for him | The amber row remains the honest record: this step is overdue and waiting on a human | — |
| 3 | Mátyás clicks the amber row | The full modal editor opens on the frozen copy, with what changed stated plainly at the top (e.g. "Lead name: 'Janos' → 'János Kovács'"). He either fixes the text (or accepts it as-is) and clicks "Save & approve" — the row turns orange again and the hold lifts | Copy: the change note + editable frozen copy; button "Save & approve" · Look: modal over drawer; on save amber → orange · Where: the held row | Saving re-freezes the step to exactly the text in the editor, marks it owner-edited (auto-send-approved), and clears the drift flag. If the send time already passed, the step sends at the next dispatch tick with the re-approved text; otherwise it sends on schedule | Must NOT auto-apply the new data without showing him; must NOT lift the hold without an explicit save; must NOT lose the original send order when a late step catches up | ROW UPDATED The row returns to orange with the re-approved copy — and later converts to a sent row with that exact text |
Critique: The editor could pre-apply the fresh data or keep the frozen text — pre-applying is convenient but risks him approving text he didn't actually read. Suggestion: Keep the frozen text in the editor + show the old→new diff line; one optional "Update to new value" link per changed field applies it visibly in the editor. He always approves what he sees. ❓ owner: confirm this default. |
| 4 | Failure mode: the drift check itself errors (e.g. a deal field was deleted) | The row shows as amber "On hold — needs review" rather than a crash or a false-orange "all good"; the drawer still opens and everything else renders normally | Copy: "On hold — needs review" · Look: amber · Where: the affected row only | An erroring drift check defaults the step to held (safe direction: block, never send unverified text); the error is logged for W0's observability | Must NOT crash the history drawer; must NOT show orange (healthy) when the check couldn't run; must NOT send the step while the check is broken | The row's amber state IS the record of the problem | — |
| # | You do | You should see | Element that changes copy · look · where |
What changes underneath | Must NOT happen | 🕓 Touchpoint history | 💡 UX critique + suggestion |
|---|---|---|---|---|---|---|---|
| 1 | Mátyás clicks a past sent-email row in the history drawer | The same full modal editor opens, loaded with the recorded subject + body — clearly framed as a record edit ("Edit record — this email was already sent; changes fix the internal record only, nothing is re-sent") | Copy: the framing line + the recorded text, editable · Look: the familiar full modal · Where: over the drawer | The editor loads the stored touchpoint body; no send machinery is involved anywhere in this path | Must NOT present any button that could re-send; must NOT confuse this with the scheduled-row editor's "will send" semantics | — (opening is not an event) | — |
| 2 | He corrects the text, clicks "Save" | The modal closes immediately; the row now shows the corrected text and carries a small "edited" note with the edit date — visible whenever the row is read, so the record is honest about having been touched | Copy: corrected body + "edited · Jul 12" note · Look: normal sent row + the note · Where: the same row | The touchpoint record is overwritten with the correction and stamped edited; the lead's actual inbox is untouched — no network send of any kind fires | Must NOT resend or alter what the lead received; must NOT hide that the record was edited (the note is mandatory); must NOT change the row's timestamp/position in the timeline | RECORD FIXED The row = corrected text + "edited" note; the timeline order is unchanged |
Critique: Overwriting means the original wording is gone — if the record edit itself was a mistake there's no way back, and "what did the lead ACTUALLY receive" can no longer be answered from history. Suggestion: Keep the pre-edit text stored under the "edited" note (tap the note to see the original). Cheap, invisible until needed. ❓ owner: keep the original under the note, or plain overwrite? |
| # | You do | You should see | Element that changes copy · look · where |
What changes underneath | Must NOT happen | 🕓 Touchpoint history | 💡 UX critique + suggestion |
|---|---|---|---|---|---|---|---|
| 1 | Mátyás reads a history that contains both kinds of sent email | Every email the system sent on its own carries a small "Auto" marker on its row; emails he sent himself (manual replies, the first email of a Send-click, an AI reply he approved and sent) carry none — one glance separates "the machine kept going" from "I did this" | Copy: "Auto" chip on auto-sent rows · Look: a subtle but unmistakable marker, consistent everywhere · Where: every auto-sent outbound row, board-wide | Each outbound touchpoint records whether a human click gated it or the scheduler fired it; the row renders the marker from that recorded fact (not guessed later from the type name) | Must NOT mark an owner-clicked send as Auto; must NOT leave an auto-continuation looking identical to a hand-sent email; must NOT vary the marker's look between row types | ROW METADATA The sent-by fact becomes part of every outbound row — history now answers "who sent this, me or the machine" |
— |
| 2 | Nothing — both parties signed yesterday and no payment has landed; the automatic payment chase runs | The history shows today's payment-reminder email as an Auto sent row with its full real text, and the remaining chase days as orange Scheduled rows — same frozen-copy treatment as any sequence (this chase is fully automatic; there is no owner button — W1 owns the cadence and the stop conditions) | Copy: the chase email's full body (Stripe link + transfer details block) · Look: Auto sent rows + orange future rows · Where: the deal's history | The self-arming payment-reminder sequence freezes its copy at the moment it arms itself (no Send-click exists for it — the arm moment IS its freeze moment); each daily send dispatches the frozen text; payment or a logged phone call stops the chase and the remaining orange rows disappear with a plain "stopped — paid" style annotation from the stop event | Must NOT require an owner click to run the chase; must NOT keep showing orange chase rows after payment/stop; must NOT let a chase email's history text differ from what was delivered (parity applies to auto emails identically) | NEW ENTRIES One Auto sent row per chase day + orange rows for the days ahead; the stop event (payment / logged call) closes the story in the same timeline |
Critique: A drift-hold (W2-4) on an unattended chase email could silently stall the whole money chase. Suggestion: Holds on payment-chase steps matter more than any other hold — make sure the hold banner (W2-4·1's suggestion) fires for these too; money waiting on an unnoticed amber row is the worst version of the drift problem. |
| # | You do | You should see | Element that changes copy · look · where |
What changes underneath | Must NOT happen | 🕓 Touchpoint history | 💡 UX critique + suggestion |
|---|---|---|---|---|---|---|---|
| 1 | Mátyás scans a mature lead's full history | Every row that represents a real email carries a direction pill: sent on everything outbound (sequence emails, proposal, reminder emails, calendar invites, onboarding email, manual replies) and received on everything inbound (lead replies). Rows that have no direction by nature — stage changes, payments, notes, call logs, document events — show none, by design | Copy: "sent" / "received" pills · Look: the existing pill styling, now present wherever it belongs · Where: every directional row in the drawer | Every touchpoint type has an explicit direction classification (in / out / none) — no type falls through to blank by accident; a test guards that no directional type is unclassified | Must NOT leave a genuinely outbound email type with a blank direction; must NOT stick a direction on system/stage/payment rows; must NOT ever label an outgoing email as a received reply (the old bug class — its ingestion root cause is fixed; this closes the display side generally) | The whole timeline becomes consistently parseable — direction is information, and now it's never missing where it exists | — |
| 2 | He looks at a booked call's rows specifically | The booking-confirmation row and the pre-call-reminder rows are distinguishable at a glance — each with its own label and icon, not two identical generic system rows (owner approved this in the W1 comment round: "Apply") | Copy: distinct labels, e.g. "Booking confirmation sent" vs "Reminder sent (1 day before)" · Look: own icon per kind · Where: the call-related rows | Confirmation and reminder touchpoints render with their own type labels/icons instead of a shared generic treatment | Must NOT render confirmation and reminder as visually identical rows; must NOT change WHEN these emails send (existing flow — verify unchanged, W1 owns sending) | Call-related rows become self-explanatory without opening them | — |
| # | You do | You should see | Element that changes copy · look · where |
What changes underneath | Must NOT happen | 🕓 Touchpoint history | 💡 UX critique + suggestion |
|---|---|---|---|---|---|---|---|
| 1 | Mátyás opens the history of a lead with a freshly booked call | The "Reminders scheduled" row lists all three reminders (3d / 1d / 2h) each with its send datetime, subject, and the FULL resolved body — real name, real Meet link, complete text — not a truncated snippet | Copy: full reminder bodies · Look: same row, richer content · Where: the reminders-scheduled row | The reminder touchpoint stores/renders complete resolved bodies (reusing the same resolution treatment the orange rows got); the booking flow that writes it is unchanged | Must NOT show 90-char previews anymore; must NOT show raw tokens; must NOT alter when/whether reminders send (existing flow, verify unchanged — reminders are already auto-send-whitelisted) | ROW ENRICHED The reminders row becomes a complete answer to "what exactly will the lead get before the call" |
— |
| 2 | The call happens (or is cancelled) — the pending reminders stop | A "Reminders cancelled" row appears after the scheduled row; the earlier row stays in place — the history reads as "these were planned, then stopped", an honest audit trail rather than a vanished entry | Copy: "Reminders cancelled" · Look: grey annotation row · Where: after the reminders-scheduled row | The cancellation is appended as its own event; the original scheduled entry is never deleted (existing annotate behaviour — kept deliberately) | Must NOT delete the earlier scheduled row; must NOT send a reminder after the cancellation row exists | Planned → stopped, both visible — the timeline never rewrites its own past | Critique: Annotate-not-remove is the honest choice, but two adjacent rows ("scheduled" then "cancelled") can read as clutter on busy leads. Suggestion: Keep annotate (recommended — audit trail), but grey out / strike the superseded scheduled row so the eye instantly reads it as no-longer-live. ❓ owner: keep annotate style? |
| # | You do | You should see | Element that changes copy · look · where |
What changes underneath | Must NOT happen | 🕓 Touchpoint history | 💡 UX critique + suggestion |
|---|---|---|---|---|---|---|---|
| 1 | Mátyás looks at a card whose latest lead email is unreplied | The lead's message text is visible on the card itself (not hidden behind a click) together with a "Compose AI reply" button; once a reply goes out, this block disappears from the card | Copy: the lead's email text + button "Compose AI reply" · Look: per W8's card design · Where: the lead card, only while unreplied | The card reads the latest-inbound + replied-status straight from the touchpoint history — the same record the drawer shows, one source of truth | Must NOT show a stale/older email as "latest"; must NOT keep showing the block after a reply was sent (from ANY path — AI reply, Missive, manual); must NOT invent a second inbound record for displaying it | The inbound email is already a received row in history — the card surfaces it, nothing new is written | — |
| 2 | He clicks "Compose AI reply" | An editable field appears pre-filled with an AI-written reply that demonstrably knows this lead: it answers what the lead actually asked, references the real state of the deal (from the touchpoint history so far), opens with the proper resolved greeting ("Kedves János,") and closes with the canonical sign-off | Copy: the AI draft — greeting + on-topic body + canonical sign-off · Look: editable field + Send/Cancel · Where: on the card | The draft is generated from the lead's full touchpoint history (past emails both ways, calls, stage) — not from a generic template; the greeting variable resolves to the real name; nothing sends yet | Must NOT show a raw {{greeting}} token; must NOT produce a generic reply that ignores the lead's actual question; must NOT drop the canonical sign-off; must NOT auto-send the draft |
— (a draft is not a touchpoint; nothing is written until the send) | Critique: Generation takes a moment; a dead-looking button invites a double click and two competing drafts. Suggestion: Disable the button on click with a brief "drafting…" state, then reveal the field. One control, kills the double-generate. |
| 3 | He edits the draft as needed and clicks "Send" | The field closes immediately — he moves on; the reply goes out in the background; the card's unreplied block clears | Copy: card returns to normal · Look: field gone, block gone · Where: the card | The send fires through W1's send path (the click is the human gate); the exact text he sent — with his edits — is recorded. A background failure raises the red ring + banner (W1/W8), never a silent loss | Must NOT send without the explicit click; must NOT block him waiting for the server; must NOT record a draft version that differs from the sent version | NEW ENTRY An outbound sent row appears with the exact reply text — no Auto marker (he gated it) — and the inbound row now counts as replied, which is what clears the card block |
— |
| # | You do | You should see | Element that changes copy · look · where |
What changes underneath | Must NOT happen | 🕓 Touchpoint history | 💡 UX critique + suggestion |
|---|---|---|---|---|---|---|---|
| 1 | Nothing — a proposal goes out / a contract gets signed / a deposit or balance payment lands / a pre-call reminder sends | A live banner appears top-right naming the event with its own icon + label ("Contract signed — {lead}", "Payment received — {lead}"…), persists until dismissed, and clicking it jumps to the card — exactly like the existing booking/new-lead banners | Copy: event-specific label per kind · Look: the existing banner style with a proper icon per kind (not a generic bell) · Where: the existing banner stack | The already-built banner system gains the missing event kinds at their source moments; the banner mechanism itself is untouched | Must NOT rebuild/redesign the banner UI; must NOT fall back to a generic bell/raw-kind-name banner for the new kinds; must NOT fire duplicate banners for one event | Each of these moments is already (or becomes) its own history row on the card — the banner is the live echo, the history row is the durable record | — |
| 2 | Nothing — a scheduled/automated send FAILS in the background | A banner names the failure ("Email failed to send — {lead}") and the card wears the red dashed ring (W1 detects, W8 styles) — and that is the whole failure surface: no failures-list screen exists anywhere | Copy: the failure banner text · Look: banner + red dashed ring on the card · Where: banner stack + the card | The send failure raises a banner event; the failed step's history row shows a plain failed state (not orange "scheduled", not sent) so the drawer tells the truth too | Must NOT stay silent on a failed automated send; must NOT build a failures list / review queue (owner explicitly killed it); must NOT show the step as sent or still-scheduled in history when it failed | FAILED STATE The step's row flips to a failed state with the frozen copy it tried to send — recovery (retry) is W1's behavior; W2 records the truth |
— |
| 3 | Verify-only sweep (no build): book one test call end-to-end | Exactly ONE booking-notification email arrives for the booking (no duplicates), and Mátyás receives the real Meet invite as a named attendee in his own inbox — both behaviours are already shipped in code; this is a live re-check, not a rebuild | Copy: — · Look: — · Where: his inbox + calendar | Existing flow, verify unchanged: the once-per-booking guard and the both-parties invite are already on main — the EBO run proves them live and touches nothing | Must NOT receive two notification emails for one booking; must NOT "fix" or refactor these shipped paths as part of W2 | The booking rows appear as they already do (plus W2-7·2's clearer labels) | — |
Each build work item derived for W2, and the scenario steps that prove it works when clicked through on the staging board.
| Work item | What it delivers | Proven by (scenario · step) |
|---|---|---|
| WI-1 · Freeze at Send-click | Send generates + freezes the whole sequence's copy exactly as previewed (modal UI untouched, closes instantly); the frozen snapshot — not a re-resolve — is what sends; clean all-or-nothing failure if generation errors. Self-arming sequences (payment chase) freeze at their arm moment. | W2-1·1 · W2-1·2 · W2-1·3 · W2-1·4 · W2-2·2 · W2-6·2 |
| WI-2 · Orange scheduled rows | Full frozen subject+body (resolved, untruncated) + exact Budapest send datetime per pending step, in a genuine orange token distinct from amber; converts in place to a sent row with identical text. | W2-2·1 · W2-2·2 · W2-6·2 |
| WI-3 · Drift check + amber HOLD | Lead-data change before send-day flips affected rows amber and BLOCKS the send until re-approved; per-step, safe-by-default on check errors; overdue holds send on re-approval. | W2-4·1 · W2-4·2 · W2-4·3 · W2-4·4 |
| WI-4 · Full modal editor from history | Orange/amber rows open the full step editor (edit → save = owner-edited = auto-send-approved, schedule untouched); sent rows open the record editor (fix + mandatory "edited" note, never re-sends). | W2-3·1 · W2-3·2 · W2-3·3 · W2-4·3 · W2-5·1 · W2-5·2 |
| WI-5 · Auto vs owner-sent marker | Every outbound row records + shows who fired it — Auto chip on machine sends (sequence continuations, payment chase), nothing on human-gated sends. | W2-6·1 · W2-6·2 · W2-9·3 |
| WI-6 · Direction-label completion | Every touchpoint type explicitly classified in/out/none — sent/received pills wherever a real email direction exists, none where none exists; confirmation vs reminder rows distinguishable. | W2-7·1 · W2-7·2 |
| WI-7 · Full reminder bodies | Pre-call reminder rows carry complete resolved email bodies (3d/1d/2h) instead of 90-char snippets; cancellation stays an annotation. | W2-8·1 · W2-8·2 |
| WI-8 · AI reply on card (content + record) | History-aware AI draft with resolved greeting + canonical sign-off in an editable field; human-gated send recorded with exact parity; unreplied block clears on any reply path. | W2-9·1 · W2-9·2 · W2-9·3 |
| WI-9 · Banner coverage | Proposal-sent / contract-signed / payment / reminder-sent / send-failed banner kinds on the existing banner surface with proper icons — no failures list; B15/B16 verified live only. | W2-10·1 · W2-10·2 · W2-10·3 · W2-4·1 (hold banner, if approved) |