ClientsFlow · Email-System Overhaul · W6 · EBO

EBO — W6 · Copy QA & Trust

DRAFT for owner comments · 2026-07-12. The target state after W6 ships: every AI- or template-generated client-facing text is provably correct — canonical sign-off locked by a machine test, phone/bank details impossible to leak outside payment emails, every email's copy editable where the owner expects it (Templates) or visibly not, no raw {{variable}} ever reaching a client, and a written QA-trust gate + Codex second-model review plan that every other workstream's "done" claim must pass. Assembled from the W6 handoff, ANSWERS_ROUND3 (Q20/Q21 + Q1/Q4/Q7 copy anchors), the standing round-2 Q6 ruling, and the owner's W1 comment round. Scenarios W6-1 … W6-8.

What W6 owns
The proof layer for client-facing copy: the sign-off regression test, the phone/bank leak guard, the copy-drift detector (which email texts are Template-editable vs code-only), making the signed-contract + payment-reminder emails Template-editable with a locked payment-details block, the variable-leak ({{…}}) checks, the one-page QA-trust gate, and the 3-step Codex second-model review operating plan.
What W6 only verifies (owned elsewhere)
W1 owns what actually sends and when (auto-send whitelist, the automatic payment-reminder ladder). W2 owns the touchpoint-history UI, freeze-at-Send, and the AI-reply-on-card feature itself. W3 owns the Details panel where {{greeting}} is displayed. W6 never changes send behavior or history rendering — it proves the text those surfaces produce is correct, and it audits real sent mail. The Codex review process across the whole program is program-level; this EBO covers only the plan document and the copy surfaces it audits.
You do → click/action/command 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 —) 💡 UX critique + suggestion → genuine critique + concrete improvement (owner: comment "Apply" to keep)
Owner rulings folded inRound-2 Q6 (stands, never revisited): the signed-contract email and the payment-chase emails become Template-editable; the bank-details block stays locked inside (visible, never editable/removable). Q21=B: second-model (Codex) review on EVERYTHING; W6 delivers the exact-steps plan — (1) what prompts to give Codex, (2) how to give it access, (3) what to do with its handoff-back doc. Q20=B: live browser QA and second-model review are both required — neither substitutes for the other. Q4/Q7 (round 3): the AI reply on the card and every history row must carry a resolved {{greeting}} + the canonical sign-off, with 100% parity between shown and sent copy — W6 proves these properties; W2 builds the surfaces. W1 owner comments (newest, win on conflict): the failures list is dead (a failure = red dashed ring + banner, nothing more); the payment chase is a fully automatic daily reminder ladder (3–4 days, stops on payment or a logged phone call — no owner button); the signed-contract email already exists and works ("Don't try to fix what is working — you can test it however") — W6 verifies it, never redesigns it. Trust-crisis mandate (round-2 Q12, verbatim): "I can't really trust that if I say 'You go!' then it will refine the app to production grade" — everything below exists to convert that trust from vibes to proof.
Invariants that hold everywhere — the canonical sign-off is exactly the 4-line SIGNATURE_HU block (name / role line / company + address / email), no phone, no bank line; bank + phone details appear ONLY inside the three payment-instruction bodies (signed-contract delivery email, payment-reminder ladder, proposal footer); no client-facing text ever contains a raw {{token}}; W6 sends nothing new to anyone — it tests code, reads already-sent mail, and edits documents; all operator UI is English, Hungarian appears only inside client-facing copy; W6's regression test may never be disabled/skipped to make a run green — a red test is the feature working.

W6-1 — Canonical sign-off is locked by a regression test that actually has teeth (happy path / core build)

Who: Any agent/CI running the suite; Mátyás reads the outcome  ·  When: The sign-off already regressed once — the 2026-07-11 rogue-decoy incident sent a leaked phone/bank footer to 5 real leads, and nothing failed. After W6, any change that breaks the sign-off on ANY outbound email turns the test suite red before it can ship.

#You doYou should see Element that changes
copy · look · where
What changes underneathMust NOT happen 🕓 Touchpoint history💡 UX critique + suggestion
1 Run the email-copy test: pytest tests/test_signoff_footer_regression.py -v The test passes green and its output names every outbound email it checked — signed-contract delivery, payment reminders, booking confirmation, pre-call reminders, proposal, no-show ladder, first reply, negative follow-ups — each one confirmed to end with the canonical 4-line sign-off Copy: test output = one named line per checked email body · Look: terminal, green · Where: new file tests/test_signoff_footer_regression.py Every outbound-email-composing function is rendered with sample lead data and asserted to end with SIGNATURE_HU (an optional "Üdv,\n" immediately before it is allowed); rep-only internal notification bodies are explicitly excluded, not silently skipped Must NOT skip any client-facing send site (a body not in the walk is a hole, exactly how the incident escaped); must NOT pass if even one body ends with anything other than the canonical block; must NOT need network/Notion to run — (a test run touches no lead) Critique: A test that names 15 functions is proof to a developer, but the owner can't read pytest output — his trust needs a surface he can see.
Suggestion: Have the test also write a one-line dated stamp ("Sign-off check: 15/15 emails canonical — 2026-07-12") that the Health tab shows, so the owner sees the lock is on without reading a terminal.
2 Run the documented "teeth check": temporarily swap the sign-off constant to the OLD leaked 4-line footer (the one with "Phone (used in CTAs): +36 70 …" + "Bank: 1260…") and re-run the test The suite goes RED and the failure message names each affected email function and quotes the offending leaked line — the exact 2026-07-11 incident is now impossible to ship silently Copy: failure text = function name + the leaked string found · Look: terminal, red · Where: same test file (the swap recipe lives in its docstring as a manual step, never a permanent fixture) Nothing persists — the swap is reverted immediately after the check; the point is a recorded proof that the test catches the historical incident, not a shipped state Must NOT leave the leaked footer in the working tree after the check; must NOT encode the teeth check as an always-on expected-failure that could mask a real regression Critique: A manual teeth check done once and forgotten decays — in a year nobody will remember whether the test still bites.
Suggestion: Record the teeth-check date + result inside the test file's docstring each time it's performed, so "when was the lock last proven" is answerable in one glance.
3 Later, any workstream edits an email body and (accidentally) drops or mangles its sign-off, then runs the suite The suite fails loudly, naming exactly which email lost its sign-off and what its last lines actually were — the fix is obvious from the message alone Copy: "email_signed_document body does not end with SIGNATURE_HU — got: '…'" · Look: red test, precise message · Where: CI / local suite No code merges through the Ship pipeline with this test red; the failing function is fixed, never the test loosened Must NOT be "fixed" by disabling, skipping, or weakening the test (the EBO sign-off requires an explicit "this test was NOT disabled" statement from whoever runs it); must NOT pass because the body merely contains the sign-off somewhere — it must END with it Critique: "Ends with" is strict and right, but future bodies might legitimately add a P.S. line under the signature and the test would block a wanted change.
Suggestion: Keep strict "ends with" as the default; if a P.S.-after-signature is ever wanted, that's a deliberate one-line allowlist entry in the test with a comment — a visible decision, never a silent loosening.

W6-2 — Phone/bank details can only ever appear in the three payment-instruction bodies (leak guard / failure path)

Who: The same regression test; Mátyás trusts the outcome  ·  When: Bank details are legitimate in exactly three places (the signed-contract delivery email, the payment-reminder ladder, the proposal footer) — the client genuinely needs to pay there. Anywhere else, a phone/bank line in an email is the incident happening again.

#You doYou should see Element that changes
copy · look · where
What changes underneathMust NOT happen 🕓 Touchpoint history💡 UX critique + suggestion
1 Run the same regression test (it carries the leak guard as its second half) Green, plus an explicit printed allowlist: bank/phone literals found ONLY at the three verified payment-instruction sites (signed-contract client body · payment-reminder bank lines · proposal footer bank block) and in the contract's legal block — nowhere else in any rendered email Copy: the allowlist is spelled out in the test as three named sites, not a blanket skip · Look: terminal · Where: same test file Every rendered body is scanned for the phone number, the bank account number, the "Bank:" footer prefix, and the historical "Phone (used in CTAs)" marker; hits outside the allowlist are hard failures Must NOT allowlist by whole file (a whole-file skip would let a new leak into an allowed file pass); must NOT treat the DocuSeal contract legal block as a leak (it is a contract field, not an email) Critique: Literals drift — if the bank account number ever changes, a stale literal in the test silently guards the wrong string.
Suggestion: Make the test read the phone/bank strings from the single config constants it guards, so the guard always chases the real values, never a copy of them.
2 Simulate the failure: a change adds a bank-transfer line to a non-payment email (e.g. a booking confirmation), suite runs Hard RED — the failure names the email and quotes the leaked line: payment details in a non-payment email cannot reach staging, let alone a lead Copy: "bank literal found outside allowlist in email_booking_confirmation: 'Bank: 1260…'" · Look: red test · Where: CI / local suite The offending body is fixed; the allowlist grows only by a deliberate, commented decision (a fourth legitimate payment body would be an owner-visible change) Must NOT resolve the red by adding the leaking site to the allowlist as a reflex; must NOT average/soften the verdict (one leak = red, no partial credit)

W6-3 — Signed-contract + payment-reminder emails become Template-editable, with the payment-details block locked inside (happy path / the one UI change W6 makes)

Who: Mátyás  ·  When: Today these two highest-stakes emails are hardcoded — if he edits them in the Templates tab, the edit silently does nothing and nothing tells him so. Round-2 Q6 (standing ruling): make them editable; the bank-details block stays locked inside. The signed-contract email's content itself is already right ("We already have an email set up for it") — this scenario changes where its text LIVES, never what it says or when it sends.

#You doYou should see Element that changes
copy · look · where
What changes underneathMust NOT happen 🕓 Touchpoint history💡 UX critique + suggestion
1 Mátyás opens the Templates tab (Sablonok) on the dashboard The signed-contract delivery email and each step of the payment-reminder ladder now appear in the template list as editable entries, alongside the existing templates — previously they were simply absent, with no hint they were code-only Copy: new list entries "Signed contract — delivery email" · "Payment reminder — day 1…4" · Look: same template list style as existing entries · Where: Templates tab The two bodies move from hardcoded Python literals into the owner-editable copy layer; their send timing and triggers stay exactly as they are (W1's automatic flow — auto-send on client signature, then one reminder a day for 3–4 days until payment or a logged phone call) Must NOT change what these emails currently say (migration is verbatim — the current live text becomes the initial template text); must NOT alter when/whether they send (that is W1's, untouched); must NOT list them as editable while edits still silently do nothing (the whole point) Critique: After migration, an owner edit here changes real money-path emails with no preview of a rendered result — a typo in the day-2 reminder goes to every future signer.
Suggestion: Show a rendered preview (sample lead data, greeting + amounts resolved) beside the editor before Save — the same "read what will actually go out" habit the Send-Emails modal already trains.
2 Mátyás edits the signed-contract email's wording (e.g. rewrites the opening sentence in Hungarian), saves, then a ZZ-sentinel staging contract-signing test fires the email The staging test email arrives with his edited opening — proof the edit is LIVE, not decorative; the email still carries everything the flow promises: confirmation, the signed-contract download link, the Stripe link, and the transfer details, ending with the canonical sign-off Copy: his edited Hungarian text, e.g. "Kedves Anna, örömmel jelezzük, hogy a szerződés létrejött…" · Look: real received email (staging, ZZ lead) · Where: the ZZ test inbox + the lead card's history The send site now reads the body through the owner-editable copy layer (live override → baked default), interpolating the deal's Stripe link/amount into the edited text; the regression test from W6-1/W6-2 still passes against the edited copy Must NOT send the old hardcoded text after a save succeeded (the silent-no-op bug this exists to kill); must NOT let an edit strip the sign-off or the payment block (the test + locked block guard this); must NOT run this against a real lead — ZZ sentinel only, purged after The staging ZZ card's history logs the sent email with the edited text — 100% parity between the history row and the received email (W2's parity bar, verified here on W6's migrated copy). Critique: These bodies interpolate live deal data (amount, Stripe link) — an owner edit that deletes the amount placeholder would send a reminder that never says how much to pay.
Suggestion: On Save, validate that the required placeholders (amount, payment links) are still present and refuse the save with a plain-English message naming the missing piece ("The payment amount is missing from this template") instead of saving a broken money email.
3 Mátyás looks at the payment-details part inside the template editor and tries to change or delete it The bank-transfer + Stripe details render as a visibly locked block inside the template — readable in place so he sees the full email, marked "Locked — payment details", and not editable or deletable; his cursor edits flow around it Copy: locked-block label "Locked — payment details" (English UI); the block's content stays the Hungarian bank/Stripe lines · Look: the block is visually set off (muted background, lock icon) from the editable text · Where: template editor for the two payment emails The payment-details block stays sourced from the single code-side constant — owner edits can reposition text around it but the block's content is not part of the editable template body Must NOT allow the locked block to be edited, emptied, or removed through any editor path (including select-all-delete — the saved template must still render the block); must NOT hide the block from the editor view (invisible-but-sent text is a parity violation) Critique: A locked block the owner can't move at all may fight him — maybe he wants the payment details above his closing paragraph, not below.
Suggestion: Keep content locked but allow the block to be repositioned as a unit within the body (drag or a position marker). Content integrity is the invariant; position is taste.

W6-4 — Copy-drift detector: "where does this email's text live?" is answerable for every send site (happy path / audit tool, no UI)

Who: Any agent (and Mátyás reads the resulting table)  ·  When: The "guide says editable, code says hardcoded" drift was identified 3+ times before W6. The detector makes it a re-runnable fact table instead of a rediscovered surprise — run it after ANY workstream's changes to catch new drift.

#You doYou should see Element that changes
copy · look · where
What changes underneathMust NOT happen 🕓 Touchpoint history💡 UX critique + suggestion
1 Run python3 scripts/detect_copy_drift.py A table of EVERY client-facing email/SMS body in the app — one row each, tagged EDITABLE (reachable from the Templates layer) or HARDCODED (code-only), with file:line — and the script exits clean. After W6-3 lands, the signed-contract + payment-reminder rows read EDITABLE Copy: table columns = email name · source file:line · Editable/Hardcoded · which template key edits it · Look: terminal table · Where: new file scripts/detect_copy_drift.py The script walks all email-body constants and inline body literals across the send-site inventory and cross-checks each against the owner-editable copy layer's reference list (the ~25 existing wrapped sites are the positive baseline) Must NOT miss inline body literals that never got a named constant (the strongest form of hardcoded — must be flagged, not skipped); must NOT report a body as editable when the Templates edit would actually be ignored Critique: A terminal table is invisible to the owner — the person whose Templates edits silently failed is the last to see this output.
Suggestion: If any body is HARDCODED, surface that same fact in the Templates tab as a small read-only entry marked "Code-only — editing requires a code change", so the tab never again implies an editability it doesn't have.
2 Later, some workstream adds a new email body as a raw Python string (no Templates wiring), then the detector re-runs The new body appears in the table tagged HARDCODED with its file:line — the drift is a visible, reviewable fact within one detector run, not a surprise months later when an owner edit does nothing Copy: new HARDCODED row · Look: terminal table diff · Where: same script output Nothing auto-fixes — the detector reports; whether the new body should be wired into Templates is a per-case owner/reviewer call made ON the report Must NOT auto-rewrite code (report-only tool); must NOT go stale — it derives from the live code on every run, never from a saved snapshot Critique: Report-only tools get ignored unless something makes people run them.
Suggestion: Fold the detector into the QA-trust gate (W6-7): a workstream that added/changed any email body must attach a fresh detector run to its GREEN claim. One line in the gate, and the tool can't be forgotten.

W6-5 — No raw {{variable}} ever reaches a client; greetings resolve correctly everywhere (happy path + guard / cross-surface verification)

Who: Mátyás (reading previews) + the test suite (proving it)  ·  When: A lead receiving "{{greeting}}" instead of "Kedves János," is the single most trust-destroying copy bug possible. W6 proves resolution on every surface where generated copy is shown or sent: the Send-Emails modal previews, the on-card AI-reply draft, the touchpoint-history rows, and the actually-sent mail. The surfaces belong to W1/W2 — existing/parallel flows, verify, don't redesign; W6 owns the correctness proof.

#You doYou should see Element that changes
copy · look · where
What changes underneathMust NOT happen 🕓 Touchpoint history💡 UX critique + suggestion
1 Mátyás clicks Send Emails on a (ZZ staging) lead card and reads the generated sequence in the modal Every email in the modal opens with the lead's real resolved greeting — "Kedves Anna," — correct name, correct Hungarian form; nowhere in any preview does a raw {{greeting}}, {{name}}, or any other {{…}} token show (existing flow, verify unchanged) Copy: resolved Hungarian greeting per email · Look: the Send-Emails modal previews · Where: lead card → Send Emails modal (W1/W2's surface) Copy is generated at Send-click from the templates + touchpoint history (Q1's confirmed model); variable resolution happens at generation, so what he reads IS what will be sent/frozen Must NOT show a resolved preview but send an unresolved body (preview↔send parity); must NOT fall back to an empty greeting ("Kedves ,") when a name field is missing — a missing input must surface as a visible problem in the modal, not ship as broken Hungarian On Send, the frozen scheduled rows in history carry the same resolved text as the modal showed (W2's parity bar — W6 checks the copy half of it). Critique: "Kedves ," (missing name) is worse than a raw token — it looks like carelessness in fluent Hungarian, and no scanner keyed on "{{" catches it.
Suggestion: Extend the guard beyond "{{" to malformed-greeting shapes (greeting line with no name, doubled spaces, lowercase name) — a tiny list of Hungarian-specific tripwires alongside the token check.
2 Mátyás clicks the compose-AI-reply button on a card with an unreplied lead email and reads the AI draft (W2's new feature) The draft opens with the proper resolved Hungarian greeting, its body draws on this lead's actual history, and it ends with the exact canonical sign-off — the three properties Q4 names, all present before he edits a word Copy: "Kedves János," + contextual Hungarian body + the 4-line canonical sign-off · Look: the editable AI-reply field on the card · Where: lead card (W2/W8's surface) The AI generation path runs the same greeting-resolution and sign-off rules as template emails — one copy-rule set, not a separate AI-path approximation Must NOT show a raw token in an AI draft (AI output passes the same guard as template output); must NOT let the AI improvise its own sign-off variant (extra titles, different address, added phone) — the canonical block is appended by rule, not by the model's memory — (a draft is not a send; the send that may follow is W1/W2's, and its history row must match what left — parity again) Critique: The model can produce a perfect sign-off AND a redundant home-grown one above it ("Üdvözlettel, Mátyás"), reading as a double goodbye.
Suggestion: The guard should also fail on duplicate closings — if the body already contains a closing formula right before the appended canonical block, flag the draft for one-click cleanup before send.
3 Run the automated variable-leak check (part of W6's test layer) across all rendered bodies + audit the recent real sent mail in Missive for the same Zero {{ occurrences in any renderable body, and zero in the last weeks' actually-sent client emails — the guard holds in code and in reality Copy: test output + a short audit note (which sent emails were read, result) · Look: terminal + audit note in the run report · Where: test suite + Missive read-only audit The suite renders every body with sample data and greps the OUTPUT (not the templates — templates legitimately contain tokens pre-resolution); the Missive audit is read-only history, no new sends Must NOT grep template source and call it a pass (tokens belong in templates; the crime is tokens in rendered output); must NOT send anything as part of the audit

W6-6 — Codex second-model review: the 3-step operating plan exists and one full pass runs over the copy surfaces (deliverable / process artifact)

Who: Mátyás (approves the plan) + an agent (runs the pass)  ·  When: Q21=B — a second model (Codex) reviews EVERYTHING in this program; that program-wide process is not this EBO's to spec. What W6 owns and this scenario proves: the exact-steps operating plan document exists with its three required parts, and one real Codex pass over W6's own copy surfaces (templates, Hungarian quality, sign-off/leak rules) runs through that plan end-to-end, proving the plan works as written.

#You doYou should see Element that changes
copy · look · where
What changes underneathMust NOT happen 🕓 Touchpoint history💡 UX critique + suggestion
1 Open the Codex operating plan document W6 delivers One document with exactly the three parts the ruling names: (1) the prompts to give Codex, written out verbatim and ready to paste; (2) how to give Codex access to the code/copy under review, as concrete steps; (3) what to do with Codex's handoff-back doc — where it lands, who triages, how a finding becomes a fix or a recorded won't-fix Copy: plan doc, three numbered parts · Look: a readable document, exact steps (no "figure out access") · Where: plans/email-system-overhaul-2026-07-11/ A new document only — no code, no sends; this is the deliverable Q21=B names Must NOT be a vague intention doc — every step must be executable by a fresh agent with no extra context; must NOT expose live secrets in the access recipe (the repo is private with committed keys — access instructions must not widen that) Critique: Second-model review fails quietly when the reviewer is handed too much — Codex given the whole repo produces shallow everything-comments instead of deep copy findings.
Suggestion: The plan's prompt section should scope each pass (e.g. "review ONLY the client-facing email bodies + greeting/sign-off rules against these invariants") — one focused prompt per review target, listed as a menu.
2 Run one full Codex pass over W6's copy surfaces exactly by the plan: paste the plan's copy-review prompt, grant access per its steps, receive the handoff-back doc A Codex handoff-back doc listing its findings on the Hungarian client copy (grammar, tone, formality consistency, greeting forms), the sign-off/leak invariants, and the template texts — each finding triaged per the plan into fix / won't-fix-with-reason, and the fixes applied show up as normal branch changes Copy: the handoff-back doc + a triage note per finding · Look: document + resulting diffs · Where: plan folder + branches The pass proves the plan is executable as written; any step that didn't work as documented is corrected in the plan itself (the plan is the deliverable, the pass is its test) Must NOT count the pass as done with zero findings AND zero evidence Codex actually read the material (an empty review of 20+ Hungarian templates is a broken pass, not a clean bill); must NOT auto-apply Codex suggestions to client copy without the normal branch→staging path Critique: Codex reviewing Hungarian copy is a real risk — a second model can be confidently wrong about Hungarian register (tegezés/magázás) and "fix" copy into the wrong formality.
Suggestion: The copy-review prompt must state the house register explicitly (the leads are addressed formally-friendly, consistent with the existing templates) so Codex reviews against the house voice, not its own taste; formality-change suggestions are always owner-gated.

W6-7 — The QA-trust gate: one page every other workstream's GREEN must pass through (process glue / the anti-false-green gate)

Who: Every workstream's QA runner; Mátyás holds any "done" claim against it  ·  When: The trust crisis in one sentence (owner, verbatim): "I can't really trust that if I say 'You go!' then it will refine the app to production grade." Past runs reported green from phrase-greps, DOM proxies, and rollup inflation. The gate makes GREEN mean one thing only: a real browser drove it and a vision model confirmed the pixels.

#You doYou should see Element that changes
copy · look · where
What changes underneathMust NOT happen 🕓 Touchpoint history💡 UX critique + suggestion
1 Open QA_TRUST_GATE.md in the overhaul's plan folder One page, six plain rules: ① verdicts are GREEN/AMBER/RED only (no "adapted"/"pending"); ② GREEN requires a live browser run + a vision-judge pass on real screenshots (+ probes may only veto, never manufacture a green); ③ a blank/failed screenshot = RED, hard stop — never retried-and-averaged, never downgraded to a DOM check; ④ verdicts exist only as checkpoint files — no in-memory tallies or inflatable rollups; ⑤ pre-2026-07-06 "QA green" claims are UNVERIFIED until re-checked live; ⑥ every workstream's verification section must name the actual staging URL clicked and the actual prod probe run Copy: the six rules, no jargon a reviewer can't apply · Look: ≤1 page markdown · Where: new file plans/email-system-overhaul-2026-07-11/QA_TRUST_GATE.md Condensed from the hardened global QA skill's verdict rules with inline citations back to it (so the page tracks the source rather than forking it); sibling workstream docs link to it from their verification sections Must NOT fork/paraphrase the verdict rules into a drifting second truth (cite, don't copy); must NOT exceed a page (an unread gate gates nothing) Critique: A checklist nobody is forced through is decoration — the historical false-greens happened WITH good rules existing in a skill file.
Suggestion: Give the gate a fill-in stub (workstream · staging URL clicked · screenshot ledger path · vision verdict · date) that must be pasted, completed, into each EBO's sign-off area — an empty stub is itself the visible failure.
2 A workstream claims a scenario GREEN with full evidence: live-tagged browser run, real screenshots, vision-judge pass, checkpoint files on disk The claim passes the gate — anyone (including Mátyás) can follow the named staging URL + ledger path and see the same evidence; GREEN now means "proven on pixels", nothing weaker Copy: the completed gate stub in that workstream's EBO · Look: verifiable references, not prose confidence · Where: that workstream's EBO/run report Checkpoint files are the single verdict source; the rollup only ever reflects them Must NOT accept a GREEN whose screenshots can't be found on disk; must NOT let a confident narrative substitute for the ledger
3 A workstream claims GREEN with prose only — "QA passed, everything works" — no live tag, no vision verdict, no checkpoint files The claim is rejected as UNVERIFIED at the gate: the scenario is recorded AMBER/RED until real evidence exists, regardless of how confident the reporting agent sounds — and the same rejection applies to citing any pre-2026-07-06 session's "green" as proof a feature works today Copy: "UNVERIFIED — no live evidence (QA_TRUST_GATE rule ②/④)" recorded on the claim · Look: the scenario stays un-green in the run ledger · Where: the claiming workstream's ledger/EBO Nothing ships on the rejected claim; the workstream re-runs QA properly and only then flips the verdict Must NOT split the difference (a "probably fine" middle verdict that unblocks shipping); must NOT let the rejected workstream re-label the same evidence-free claim and pass on the second try Critique: Gate rejections can turn adversarial between agents — endless relitigating of what counts as evidence.
Suggestion: The gate's answer to any dispute is mechanical: "produce the checkpoint file or the verdict stands." No judgment calls at the gate; judgment lives in the vision judge, once, upstream.

W6-8 — Live-truth audit: what prod ACTUALLY sent matches every W6 invariant (verification / reads reality, sends nothing)

Who: An agent (read-only) + Mátyás (sees the one-line result)  ·  When: Tests prove the working tree; the incident lived in PROD. This closes the loop against reality: real recently-sent client emails are read from Missive and checked against the same invariants the tests enforce. Read-only — no ZZ send is needed, W6 audits history.

#You doYou should see Element that changes
copy · look · where
What changes underneathMust NOT happen 🕓 Touchpoint history💡 UX critique + suggestion
1 Probe prod is alive (curl …/health), then open the last week's real sent client emails in Missive — at least one signed-contract delivery and one payment-chase send among them — and read each against the invariants Every audited email ends with the exact canonical 4-line sign-off; bank/phone details appear only in the payment-instruction emails; no raw {{token}} and no broken greeting anywhere; the audit closes as a short dated note listing which emails were read and the per-invariant result Copy: audit note — emails read · invariants · pass/fail each · Look: a few lines in the W6 run report · Where: Missive (read-only) + prod health endpoint Nothing changes — pure read; a discrepancy between live-sent text and what the working tree would render is itself a finding (deployed code drift), escalated rather than papered over Must NOT send, draft, or modify anything in Missive during the audit; must NOT audit only warmup/internal mail and call it done (client-facing sends are the subject); must NOT skip the audit because the tests are green — tests and reality are checked separately, that separation is the lesson of every past false-green The audit READS history as ground truth — the touchpoint rows for the audited sends must match the Missive-visible sent text word-for-word (the parity bar checked against production reality). Critique: A one-time audit proves last week; the next silent regression starts the week after.
Suggestion: Fold a lightweight recurring version into W0's watchdog surface — e.g. the daily poll spot-checks the newest sent client email against the sign-off + leak rules and raises the standard banner on mismatch. One more tripwire on the existing alarm channel, no new UI.
🕓 Touchpoint-history note for W6:
W6 is a proof workstream — it never authors a touchpoint. Its tests render bodies in memory, its detector reads code, its audits read already-written history and already-sent mail. The history column matters in exactly three places, all as verification targets: the frozen scheduled rows must carry the same resolved copy the Send-Emails modal showed (W6-5·1), the staging ZZ signed-contract send must log with the owner-edited text at 100% parity (W6-3·2), and the prod audit must find the history rows word-for-word identical to the Missive-visible sent mail (W6-8·1). Parity itself is W2's bar; W6 supplies the copy-correctness half of the evidence.
💡 UX themes across all W6 scenarios:
(1) Trust needs a surface the owner can see — green terminals are invisible to him; the sign-off lock, the drift table, and the gate stubs each want one owner-visible line (Health tab stamp, Templates "code-only" marker, filled gate stub). (2) Guard rendered output, not source — tokens belong in templates; every check runs on what a lead would actually receive. (3) Broken Hungarian is a leak too — "Kedves ," and double closings destroy trust as surely as a raw token; the guards cover shape, not just syntax. (4) Locks over habits — the payment block is locked in the editor, the allowlist is named site-by-site in the test, the gate answers disputes mechanically ("produce the checkpoint file"); nothing relies on someone remembering the rule. (5) A red test is the feature working — the only forbidden fix is loosening the guard.

Work-item → scenario-step mapping

Each build work item derived for W6, and the scenario steps that prove it works when run/clicked through.

Work itemWhat it deliversProven by (scenario · step)
WI-1 · Sign-off regression testHermetic test walking every client-facing send site: each rendered body ends with the canonical SIGNATURE_HU block; documented teeth check proves it catches the 2026-07-11 incident footer.W6-1·1 · W6-1·2 · W6-1·3
WI-2 · Phone/bank leak guardSame test's second half: bank/phone literals allowed only at the three named payment-instruction sites (+ contract legal block); any other hit is a hard red.W6-2·1 · W6-2·2
WI-3 · Templates migration + locked payment blockSigned-contract delivery + payment-reminder ladder bodies become owner-editable in the Templates tab (verbatim migration, send behavior untouched — W1's); the payment-details block renders as a locked, non-editable unit inside the editor.W6-3·1 · W6-3·2 · W6-3·3
WI-4 · Copy-drift detectorscripts/detect_copy_drift.py: re-runnable table of every email/SMS body tagged EDITABLE/HARDCODED with file:line; catches future drift after any workstream's changes.W6-4·1 · W6-4·2
WI-5 · Variable-leak + greeting guardAutomated check that no rendered body (template or AI path) contains a raw {{token}} or a malformed greeting; verified on the Send-Emails modal, the AI-reply draft, and sent history.W6-5·1 · W6-5·2 · W6-5·3
WI-6 · Codex operating plan + proving passThe Q21=B deliverable: exact-steps doc (prompts / access / handoff-back handling) + one full Codex pass over W6's copy surfaces run through it, findings triaged.W6-6·1 · W6-6·2
WI-7 · QA-trust gate docQA_TRUST_GATE.md: the one-page six-rule gate + fill-in evidence stub; evidence-backed GREENs pass, prose-only claims are rejected as UNVERIFIED.W6-7·1 · W6-7·2 · W6-7·3
WI-8 · Live prod copy auditRead-only audit of real recently-sent client mail in Missive against all W6 invariants + prod health probe + history↔sent parity spot-check; dated audit note.W6-8·1
❓ Open design decisions I made myself — please comment (keep / change) in this round:
❓ D1 Templates migration = editable (W6-3): the handoff left "make them editable" vs "mark them code-only" as an open call; I resolved it by your standing round-2 Q6 ruling ("signed-contract + payment-chase copy becomes Sablonok-editable; bank-details block stays locked inside") — so W6 migrates both into the Templates tab. Confirm that ruling still stands?
❓ D2 Locked block can move, not change (W6-3·3): I ruled the payment-details block's content is locked but it can be repositioned as a unit inside the body. OK, or fully fixed in place?
❓ D3 Placeholder-save guard (W6-3·2 suggestion): refusing a template save that removed the payment amount/link placeholders, with a plain-English message. Apply?
❓ D4 Owner-visible trust stamps (W6-1·1, W6-4·1 suggestions): a one-line sign-off-check stamp on the Health tab + "Code-only" read-only entries in the Templates tab for any still-hardcoded body. Apply either/both?
❓ D5 Greeting-shape tripwires (W6-5): I extended the leak guard beyond raw {{tokens}} to malformed Hungarian greetings ("Kedves ,", double closings). Keep?
❓ D6 Recurring mini-audit via W0 (W6-8 suggestion): daily watchdog spot-checks the newest sent client email against the sign-off/leak rules, standard banner on mismatch — no new UI. Apply (needs one line in W0's scope)?
Sign-off — acceptance oracle. By signing, Sarudi Mátyás locks scenarios W6-1 … W6-8 and the invariants above as the acceptance answer key for W6 Copy QA & Trust, and records his keep/change verdict on the ❓ open decisions D1–D6. The W6 run's own final report must include the explicit statement "the sign-off regression test was NOT disabled or weakened to make this run green." No W6 code is built or deployed before this signature.
Sarudi Mátyás  ✔ Draft · 2026-07-12 · awaiting sign-off