The goal was reasonable

The first customer message should not wait behind work that has no effect on that message. CRM synchronisation, internal email, extended audit data, and cleanup are sensible candidates to move after the send.

That led me to think about a fast path:

receive submission
→ store essential lead identity
→ send first message
→ enrich non-critical data asynchronously

The danger appears when “non-critical” quietly expands to include data required to operate the conversation.

The boundary I now care about

Before sending a message, the record must contain enough durable identity to understand a quick reply: campaign, external lead identifier, normalised contact channel, core contact data, source, and an initial conversation state.

If that material waits for asynchronous enrichment, a later failure can leave a message in the world without a dependable record behind it. That is a poor trade for shaving work from the visible path.

The other risk is changing too many connections at once. Moving sends, reservations, audit paths, cleanup, and post-send processing together makes a failure hard to locate. A faster design is not useful if it becomes too opaque to repair.

What I learned

Performance work is not mainly about moving nodes later. The important question is: which information must already be durable if the very next step fails?

Measure first, then change one boundary at a time. The fastest path is only valuable when it preserves the state needed for the next customer response.

What should happen next

I want timing around campaign lookup, runtime loading, lead writes, submission recording, and message delivery before making another optimisation decision. Measurement should explain the trade-off instead of letting assumptions drive it.