Important release correction · 12 July 2026
This earlier GO report is superseded. Do not merge or deploy from it.
A fresh independent audit found application defects that the earlier review and green test suite missed. The database migrations passed a production-shaped MySQL rehearsal, but the branch is not release-ready because it can affect existing scheduled agent digests, wrongly suppress a vendor from an ordinary preference save, fail to enrol Rescue contacts, change an approved Utility audience, and stall a large launch.
Use the canonical replacement: Fresh Pre-Production Audit and Release Decision.
Executive Summary
The entire Email Nurture system is built and tested on an isolated branch. It includes the marketing safety layer, suppression register, Fast Rescue foundation, utility/nurture foundation, editable email library, shared header, footer and unsubscribe section, exact-recipient previews, owner-only tests, final review, controlled launch, monitoring and contact-level journey visibility.
- Nothing is live in production. No production database was changed, no customer was enrolled, and no customer email was sent.
- The base is ready. The installer creates a two-email Rescue draft, a one-email Nurture draft and 15 editable email ideas. Everything starts as a draft.
- The Test Send system worked. Three real tests went only to your two approved addresses. SendGrid accepted all three; the two sent to your personal Gmail were independently confirmed in the inbox.
- Superseded recommendation: do not merge or deploy. The complete local suite is still 605 tests / 1,832 assertions, but a fresh Codex and Claude audit found real scheduler, preference-form, audience-freeze and large-launch paths that the suite did not cover. Use the replacement audit linked above.
Latest safety and usability review
Exactly what changes for existing email
| Existing send | SendGrid IP | CRM purpose | New suppression applies? | What this means |
|---|---|---|---|---|
| Direct agent digest | Marketing | Intended operational | AT RISK | Direct calls are operational, but the normal scheduled queue-backed path is currently misclassified as marketing. Do not deploy until the scheduler-path regression passes. |
| Staff operational email | Marketing or transactional | Operational | NO | Invoice follow-up and genuine service communication remain available. The marketing-IP case is now regression-tested. |
| Vendor or partner digest | Marketing | Marketing | YES | Stops for valid marketing suppression evidence. Transactional messages are separate and continue. |
| Staff mass email | Marketing | Marketing | YES | Every recipient is checked before send and again when the queued job runs. |
| 36 active production workflow email actions | Currently transactional | Unclassified legacy | NO CHANGE | All 5,969 currently pending workflow rows retain existing behaviour. Seller Guide uses the transactional IP but is still technically unclassified. |
| New Campaign Studio campaigns | Marketing | Marketing | YES | Rescue and Nurture receive the full safety checks by design. |
What staff now see
The campaign page has a six-step assistant. Green means the CRM has evidence that the step is complete, blue is the next action, and grey comes later. A dedicated Nurture Email Library manages reusable emails plus the separately editable shared header, footer and unsubscribe section. Staff can change the unsubscribe wording and styling, but the CRM rejects a blank, missing, duplicated, unlinked or commented-out secure unsubscribe placeholder. The campaign list has a Duplicate button. Audience Preview has a View Email button beside each sample contact; it opens the exact subject and fully populated email for that person without sending anything. Final send still has one plain-English review page, and editing anything invalidates final approval.
Normal Nurture process
Yes: create one fresh draft for each monthly update or major event. Pick an existing library idea, update its facts, date and links, choose the CRM list and timing, preview, test, then send. Do not keep adding monthly emails to one old campaign. Rescue is different: set it up once and leave it active so qualifying recent enquiries enter automatically.
Production health observed read-only
The relevant default queue was healthy: zero ready, 39 intentionally delayed, zero buried and five workers. The global 1,175 ready count came from stale non-default tubes and is not the nurture queue. The application host had low load and about 5.75 GB memory available. The database averaged only 6.9% CPU across seven days, but had short peaks near 100% and periods of low free memory.
Your normal campaign workflow
The interface is designed around the job you are trying to do, not an internal policy system. Safety is still enforced underneath, but staff do not have to manage separate staged-audience records.
Create
Name the campaign and choose Rescue or Nurture. Saving creates a draft and cannot send.
Choose audience
Pick existing CRM marketing lists for Nurture, or enquiry source and current stage for Rescue.
Write
Start with an editable library idea or write your own subject and email. The CRM makes a private campaign copy.
Set timing
Choose date, local send time and hourly ceiling. Rescue remains fixed at +24 and +72 hours.
Preview and test
Calculate exactly who qualifies, then send a rendered example only to one of your approved inboxes.
Final send
Review the live count, audience, email, sender and timing together. Tick two clear confirmations, then start the campaign. You can see preparation, sends and results, or pause it.
What has been built












Open the latest library and recipient-preview walkthrough · Open the assistant walkthrough · Open the original full Studio walkthrough
The starting campaigns and content
Fast Rescue
Email 1, +24 hours: “Still looking for the right local agent?”
Email 2, +72 hours: one practical question to ask before choosing an agent. The phrase “This is the final rescue email” has been removed.
Seller Nurture
One useful issue at a chosen date and local time. It starts with the monthly local-market context email, but you can replace that issue with any library idea or your own email.
15 editable ideas in the Nurture Library
| Group | Ideas ready to edit | How to use them |
|---|---|---|
| Rescue | Still looking for the right agent; one useful question before choosing | Already connected to the two-email Rescue draft. |
| Repeatable context | Monthly local-market update; major interest-rate or market event | Add two or three current, dated facts before sending. |
| Seasonal property moments | Spring; end of year; start of year; autumn before winter | Choose the relevant issue rather than running an automatic sequence. |
| Decision insights | Highest appraisal trap; commission versus net result; comparable sales; marketing spend; local track record; auction versus private sale; exclusive agency agreement | Evergreen education that helps sellers make a better agent decision. |
What the real test proved
The two personal-Gmail messages were found in the inbox immediately after SendGrid accepted them. The work-address message was accepted by SendGrid, but that separate mailbox is not connected for independent inbox reading in this session.
trpersonal@gmail.com and thomasroberts@whichrealestateagent.com.au; it adds [TEST], sends no CC, creates no customer journey, creates no normal CRM email activity and uses only a campaign-owned template.Will deployment disrupt existing CRM email?
I cannot honestly promise zero deployment risk. The code has been designed so installing it does not start a campaign, but the complete branch also adds the Phase 0 marketing-safety layer. The correct answer is therefore “low and controlled risk”, not “nothing could possibly happen”.
| Event | What happens | Existing email impact | Release position |
|---|---|---|---|
| Deploy code and migrations | Adds new screens/tables, suppression capture, marketing send checks, journey panels and an idle 10-minute campaign worker. | Transactional email and direct agent digests remain operational and ungated. Vendor digests and mass emails classified as marketing can now stop for a real unsubscribe, complaint, bounce, blacklist or frequency cap. That is intended. | STAGED DEPLOY |
| Run starter installer | Creates 15 library templates and two draft campaigns. | No enrolments, queue rows or sends. Exact CRM list/source names must resolve or the whole setup stops. | SAFE AFTER DEPLOY |
| Send internal test | Sends one rendered example to an owner allowlist address. | No customer, CC, normal CRM email record or campaign journey. | OWNER ONLY |
| Activate final campaign | Freezes the previewed audience and permits scheduled sends. | This is the first point at which customer campaign email can occur. | SEPARATE APPROVAL |
The main deployment risk is database load, not accidental sending
The current production email-history table has about 1.11 million rows, a four-column full-text search index and roughly 514 MiB of data plus indexes. The corrected release does not alter that table at all. It creates a separate attribution table for Campaign Studio metadata. The only sizeable existing-table change left is one non-blocking search index on entity_tags, currently about 924,000 rows, to keep large audience previews efficient.
entity_tags index is created.Remaining operational checks before the first customer activation
- Completed read-only: production is MySQL 8.0.44; the email-history and
entity_tagsschemas, sizes and existing indexes have been checked. Run CI and apply the corrected migrations on the normal shared test environment before production. - Completed read-only: live workflow inventory found 36 active unclassified email actions. Seller Guide uses the transactional IP and remains outside marketing suppression. Classify legacy workflows separately later; do not bundle that behaviour change into this release.
- Run and reconcile the suppression backfill; review counts and samples before using it.
- Partly completed read-only: scheduler and the relevant queue workers are healthy. Confirm the production SendGrid webhook signature.
- Install the starter campaigns as drafts, then repeat one production internal test to the two approved owner addresses.
- Only after that, separately approve a small Rescue pilot or one Nurture issue. Treat the first Nurture edition as a CRM load validation at 500–1,000/hour before increasing the ceiling.
The exact path from here to live and operational
The path is now a controlled release sequence, not more product design. Merge and CI first; staged deployment switches on the protections but creates no campaign audience; operational gates then prove production data and delivery; only after those gates do you use the Studio to start a campaign.
| Order | Action | Owner | Proof required before continuing | Can customers receive email? |
|---|---|---|---|---|
| 1 | Review the open PR, run normal CI and merge only when it is green. | Felix + reviewer | CI green; corrected companion-table migrations and classification boundaries reviewed; no unresolved PR finding. | NO |
| 2 | Deploy code and migrations off-peak. Do not run the starter installer yet. | Felix | Migration completes without lock/latency incident; CRM, existing workflow email, direct agent digests and queue workers remain healthy. | NO CAMPAIGN |
| 3 | Re-run the production workflow inventory and compare it with the known baseline of 36 active unclassified actions and 5,969 pending rows. | Felix | No unexpected marketing classification; no legacy workflow silently moved behind suppression. | NO |
| 4 | Run suppression backfill in preview mode, reconcile totals and samples, then execute the controlled backfill. | Felix, reviewed by Thomas | Unsubscribe, complaint, bounce and invalid-address counts make sense; suppression register is visible in CRM. | NO CAMPAIGN |
| 5 | Confirm SendGrid webhook signature, sender/from/reply-to settings, scheduler and queue-worker health. | Felix | Signed event path works; five workers healthy; default queue below the 500-job nurture brake. | NO |
| 6 | Install the 15 library ideas and two starter campaigns as drafts. | Felix | Two drafts, zero enrolments, zero send attempts, zero queued nurture email. | NO |
| 7 | Thomas edits Rescue and the first Nurture issue in Campaign Studio, previews the exact audience and opens named-contact email previews. | Thomas | Content, personalisation, audience, exclusions, date, sender and local timing look correct. | NO |
| 8 | Send internal tests only to the two approved owner addresses and test Gmail/Outlook, links and unsubscribe end to end. | Thomas + Felix | Every current campaign email has a successful test matching its latest fingerprint. | OWNER ONLY |
| 9 | Open Final Review, confirm the recalculated count and email/sender/timing, then tick the two informed checkboxes. | Thomas | The final page states exactly which email, audience, volume and time will run. Any drift forces refresh. | AFTER FINAL ACTION |
| 10 | Start with the small Rescue pilot; run the first large Nurture issue at 500–1,000/hour and monitor CRM/RDS before increasing later issues. | Thomas + Felix | Delivery, unsubscribe, complaint, queue, CRM latency and conversion results remain within agreed limits. | YES |
Felix: cold-start feature and PR brief
What is in the branch
Phase 0: safety layer
Central communication-purpose classification; address-level suppression register; SendGrid event projection; one-click unsubscribe; pre-send and queued-job rechecks; configurable marketing frequency cap; audit/backfill commands; transactional/operational exclusions.
Phase 1: Fast Rescue
Recent stalled enquiry cohort, +24h and +72h messages, 20% stable measurement holdout, 14-day staff-touch protection, live relevance recheck, 07:00–21:00 property-local window, journey status and campaign reporting.
Phase 2 foundation
Named CRM marketing-list audience, zero utility holdout, one issue per campaign, current-information date, local send time, hourly throttle, shared-queue brake, 15 starter ideas and a draft-only installer.
Campaign Studio and Library
Six-step assistant; campaign create/edit/duplicate; independently owned template copies; editable shared header/footer/unsubscribe snapshot; exact audience and recipient previews; owner-only tests; two-checkbox final review; launch retry; pause/resume; results and journey visibility.
Core architecture and invariants
| Area | Implementation shape | Invariant Felix should verify |
|---|---|---|
| Purpose boundary | EmailSendContext classifies marketing versus operational/unclassified independently of SendGrid IP pool. | Marketing IP never implies marketing purpose. Direct agent digest and staff operational paths remain ungated. |
| Eligibility and suppression | One suppression service normalises addresses and checks unsubscribe, complaint, bounce, invalid, blacklist, frequency and campaign-specific context. | Campaign Studio checks before preparation and again immediately before provider send; transactional/operational email is not blocked. |
| Audience | Rescue and Utility audience services build bounded cohorts in bulk. Preview explains receive, holdout and exclusion outcomes. | No N+1 contact preview path; launch freezes the same recalculated cohort and fails on count/fingerprint drift. |
| Content ownership | Library templates are starting points. Campaign creation/selection makes a campaign-owned copy. | Editing/deleting a library idea cannot mutate an existing campaign or legacy workflow template. |
| Layout rendering | NurtureEmailLayoutService snapshots header, footer, unsubscribe HTML and checksum. NurtureEmailRenderer is shared by preview, test and delivery. | Legacy SimpleBody callers retain the original fallback. The editable section must contain exactly one visible linked @UNSUBSCRIBE_URL@; the real signed URL is escaped and inserted after merge-tag parsing. |
| Test evidence | Each successful internal test stores campaign, step, template, recipient, rendered body and a full campaign fingerprint. | Any audience, settings, template or layout change invalidates the old test and final review. |
| Launch | Final review stores attributed audience/count/content evidence. Preparation is transactional and retry-safe; activation follows completed preparation. | No draft, test send, deployment or installer operation can create a customer send. Retry does not duplicate enrolments. |
| Runtime | email-nurture:tick wakes every ten minutes, finds due work and honours local send windows, per-hour limits and queue capacity. | “Every ten minutes” is a scheduler check, not a ten-minute email cadence. Provider-boundary ambiguity stops for reconciliation instead of blind retry. |
| Attribution | Campaign/step/enrolment/attempt metadata is stored in the new email_message_attributions companion table and custom arguments round-trip through SendGrid events; rendered HTML remains in normal CRM email history. | msg_emails is never altered. Reporting can still connect send, delivery/event evidence and campaign journey without subject-line parsing. |
Locked product assumptions
- A seller requesting help accepts WREA communication under the existing terms; Rescue uses recent service-request context.
- Rescue is +24h and +72h, only for enquiries up to seven days old, with a 20% stable holdout and a 14-day recent-staff-touch block.
- Utility/Nurture uses directly approved CRM marketing audiences, has no holdout, and is one fresh campaign per issue or major event.
- Normal send hours are 07:00–21:00 in the property's local timezone. The existing workflow “Correct time” control is not reused because this engine owns campaign scheduling.
- Only WREA-domain sender/reply-to addresses are accepted. Test Send remains hard-allowlisted to Thomas's two addresses.
- The marketing-IP ceiling is configurable up to 10,000/hour, but the first large CRM edition must validate application capacity at 500–1,000/hour.
- The existing 36 active workflow email actions remain unclassified and retain legacy behaviour. Classification is a later, separate decision.
PR review checklist for Felix
- Confirm the branch is based on
pre_production, the implementation is split into clear atomic commits, and generated review artifacts are absent from the product repository. - Inspect every changed legacy send call site and confirm direct agent digest/operational classification tests match its real business purpose.
- Review the MySQL 8.0.44 correction: no Email Nurture migration may alter
msg_emails; attribution belongs in the companion table; all DDL uses the 60-second metadata-lock guard; theentity_tagsindex remains online and off-peak. - Trace one Rescue and one Utility message through preview → test → final review → launch → tick → SendGrid event → report.
- Verify the unsubscribe webhook/signature route, list-unsubscribe headers, suppression backfill idempotence and lift-suppression audit trail.
- Verify no installer, migration, scheduler tick or deployment path creates enrolments for a draft campaign.
- Run full CI in addition to the green local result of 605 tests / 1,832 assertions. The formerly missing local scraper fixture was restored and the complete feature suite now passes without an exclusion.
- Do not combine workflow reclassification, copy approval or customer campaign activation into this PR/deployment decision.
Deployment and rollback notes
Deploy application code and migrations off-peak, then stop before the starter installer. If migration or smoke evidence is unhealthy, roll back the application release before any drafts or enrolments exist; do not run destructive down-migrations against large production tables as the first response. Once the safety layer is healthy, use email-nurture:audit-workflows --production --dry-run, run email-nurture:backfill-suppressions without --execute, reconcile, then execute in a controlled run. The starter installer must use exact production names and --execute; it fails closed and creates drafts only.
Recommended next steps
- Recommended now: complete PR and CI review only. The branch and production-compatibility correction are pushed to the open PR. This does not approve merge, deployment or customer email.
- After CI and Felix's cold-start review are green, approve the off-peak staged deployment. Stop after smoke checks.
- Complete the workflow audit, suppression backfill reconciliation, webhook/sender verification and queue-health gates.
- Install only the draft library and starter campaigns. Thomas then reviews content and exact audience previews inside the CRM.
- Run owner-only Test Sends, verify rendering and unsubscribe, then return to Final Review for the separate first-pilot decision.
Caveats and assumptions
The screenshots use a sanitised isolated test database and deliberately fake names. The personal Gmail receipt check covers the two messages sent there, not the separate WREA inbox. The production infrastructure figures are point-in-time and recent-window observations, not a load test. The complete local result is 605 tests / 1,832 assertions: 357 unit tests / 948 assertions and 248 feature tests / 884 assertions. The MySQL migration was also rolled back and reapplied against a production-shaped local MySQL 8.0.45 schema with the full-text email index intact and none of the rejected columns present. The earlier Claude GO applied before the fresh release audit and is withdrawn; the current joint Codex and Claude verdict is NO-GO. The branch and correction are pushed to PR #4464, but nothing has been merged or deployed; no production database write or customer send occurred.