Key takeaways
- Our meeting recorder files a call's action items as tasks on the right client's record, automatically.
- It nearly filed them on the wrong client, by asking who is in a meeting right now when the meeting had ended an hour earlier.
- The fix is one word in a function signature: the lookup takes the meeting's own start time, never the current time.
- Two identity signals, ranked. An email match is proof of who. A calendar slot is proof that somebody had that slot, which is not the same thing.
- Could not find them and could not reach the CRM are different answers, and treating them alike is how a client's follow ups quietly disappear.
We built our own meeting recorder. It captures the call, transcribes it, writes the notes, pulls the action items out and creates them as real tasks in the CRM, on the contact the meeting was actually with.
That last part is the whole value. Notes nobody reads are worthless. Tasks on the right person's timeline are what makes the next call good. It is also where the interesting bug lives, and we found it before it shipped.
The sync does not run when the meeting does
Here is the shape of it. A call ends at eleven. Transcription runs. The notes get written. The sync fires after that, maybe minutes later, maybe an hour.
The obvious way to work out who the meeting was with is to ask the calendar who has an appointment right now. It is the first thing anyone writes, and it works perfectly every time you test it, because when you test you are sitting there right after the call.
Then it runs on a real day. The eleven o'clock ran long, transcription took a while, and by the time the sync asks who is on right now, the answer is the noon client. Every action item from the first call lands on the second client's record.
Nothing errors. Nothing looks broken. There is a contact, there are tasks, the tasks are wrong, and the only way anybody finds out is when a client gets asked about something they never said.
The fix is a parameter, and the comment matters more than the code
The lookup now takes the moment to resolve as of, and the caller passes the meeting's own start time. The window is twenty minutes either side of that, not either side of now.
Written down like that it is barely a change. The reason it stays fixed is the comment above it, which says in plain language that this must never be the current time, and why. The next person to touch that function, including a future version of me, reads the reason before the code.
The general rule is worth stealing whole. Any automation that runs after the thing it describes has to resolve identity as of the event, not as of the run. It sounds obvious stated like that, and it is not obvious at all while you are writing it, because the current time is always right there and always free.
Two signals, and only one of them is proof
The system has two ways to work out who a meeting is with, and they are deliberately not equal.
- An email address that matches a contact. This is direct proof. That person was in the meeting, and that person is this record.
- A booked appointment covering the slot. This is strong, and it is positional. It says somebody had that time, not that the call you just recorded was that meeting.
So when the two disagree the email wins, and the disagreement gets recorded rather than discarded. A conflict between two identity signals is information about your data, and throwing it away throws away the only warning you were going to get.
The calendar is still worth having in its own right, because a booking that never syncs anywhere else would otherwise be invisible. A weak signal is not a useless signal. It just has to know it is weak.
Not found and not reachable are different answers
The third piece is the one I would most want a business owner to take away. When the lookup identifies nobody there is a fallback: file the tasks on a general internal board so the work is not lost. Sensible.
But there are two ways to end up with no contact. Either it genuinely was an internal meeting with nobody in the CRM, or the CRM was unreachable for thirty seconds. The naive version treats those identically, and the second is a disaster: a real client's follow ups get filed somewhere nobody will look for them.
So the resolver returns an error distinct from a miss. On a miss the fallback runs. On an error with real attendees present, the meeting is left unsynced and the hourly retry picks it up later. Doing nothing is correct there. Doing something confident is the failure.
The same discipline shows up in the tests. The automated end to end test pins its target to the internal board, so a test run can never attach fake tasks to a real client even if a genuine appointment sits in the detection window while it runs.
Where this bites a marketing automation San Jose setup
You almost certainly have this bug somewhere, because it is a shape rather than a mistake. Anything that runs on a delay and then decides who something belongs to is exposed. A nightly job that emails everyone who booked today. An attribution rule reading whatever tags a contact has now rather than the ones they had when they converted. A report on which salesperson owns a deal, run a month after the deal moved.
Three things worth checking this week:
- List every automation that runs later than the event it describes. Overnight jobs, hourly syncs, anything with a queue.
- For each, ask what timestamp it uses to decide who. If the answer is now, and the event was not now, you have this bug whether or not it has fired yet.
- Make failure look different from emptiness. Zero results and could not connect must never produce the same behaviour.
The honest lesson is that this never reached a customer, and that was luck as much as care. It got caught by writing down what the function was actually promising, in a comment, and noticing the promise and the code disagreed.
If you want your automations checked for the failures that never throw an error, that is most of what we do. Have a look at optechsol.llc.