Revenue assurance for a managed services provider
This business runs on recurring service agreements. Renewals, churn reporting and the at-risk register all read from one derived field — and that field was wrong on six customers, including at least one paying client that the CRM believed had no contract at all.
- The goal
- Make the recurring-revenue picture trustworthy: every active agreement visible with the right expiry, so renewals fire on time and the at-risk register means something.
- What it was costing
- A managed services business is a renewal business. A contract flag that reads false on a live customer feeds renewals, churn reporting and the at-risk register — so the failure is not a blank field, it is a customer nobody is scheduled to renew.
Client anonymised — a managed IT services provider, delivered under another company. Company names, staff names and record identifiers are withheld or changed. Every figure below is real.
- Won deals audited
- 23 closed-won agreements cross-checked
- Propagating correctly
- 17 of 23
- Customers misreported
- 6, reduced to 4 with a named owner
- Duplicate internal alerts
- Roughly 4 per account, now 1
The report that started it, and what it actually meant
An account manager noticed a contract expiry date sitting on a won deal that had not appeared on the matching company record, and said so. The record had been modified about ninety seconds before her email — she was looking straight at it.
Investigated read-only, every closed-won agreement since June carrying an expiry date was cross-checked against its company: 23 agreements, 17 propagating correctly, 2 missing entirely, 4 disagreeing with the company record.
The more important finding was the one nobody had reported. A maintenance workflow derives an active-agreement flag from the company-level expiry date, so where the date was blank the flag had been set to false. A paying customer under a live contract was reading, in the system, as a customer with no agreement — feeding renewals, churn reporting and the at-risk register.
That is the difference between a data-quality ticket and a revenue-assurance problem. The blank field is annoying. Everything downstream treating the blank as a fact is the exposure.
Ruling things out before touching anything
Two plausible causes were eliminated with evidence rather than assumption. A duplicate-record hypothesis was closed by confirming an older identifier now redirects to the surviving record. A missing association was ruled out by confirming the relevant association type was present on every single failure.
An earlier fix was also confirmed working — three customers whose agreements had been touched in the preceding days had all propagated correctly. That reframed the job entirely: this was a backlog to clear, not an ongoing leak to plug, and those need different responses.
The six affected customers split cleanly. Two had the date available on a won agreement and could be recovered by copying it. Four had no date anywhere in the system, which no automation can fix — they need a person and the signed contract.
Fixing only what could be fixed safely
Two company records were backfilled from their own won agreements. Both fields were empty beforehand so nothing was overwritten, the before-state was recorded anyway, and the derived flag flipped to true on both within seconds — verified by reading the records back rather than trusting the write response.
Three mismatches were deliberately left alone. Where an agreement and a company record disagree on a date, the CRM cannot tell you which is true; only the signed contract can. Overwriting blind would have replaced a visible disagreement with an invisible wrong answer.
One of those three is the most dangerous record in the set, and it is worth describing. A company date years earlier than its agreement date. It is not blank, so nobody reviewing the record flags it, the renewal will fire against the wrong year, and the derived flag reads false while the customer is plainly active. A stale value is harder to catch than a missing one and does more damage.
The operating rule that came out of it: the flag is derived, so it must never be set by hand. If it reads false on a live customer, the date is the thing to fix — writing the flag directly would mask the fault while appearing to resolve it.
Then the alerting, which was training people to ignore it
The same engagement surfaced a second problem in the layer above: internal notifications arriving roughly four times per account.
The cause was a mismatch of levels. The condition that fires the alert is a property of the company — a milestone the account reached. The workflow was enrolling contacts. Every contact on the account satisfied a condition that was never about them individually, so every one enrolled and every one sent.
The standard remedy is a latch: stamp a marker on the parent the first time it runs and exclude everyone else. That was built, with the race condition it depends on losing written down as a known risk rather than assumed away. Three days later the race fired for real — a live account with three contacts sent three emails inside one evaluation window, because all three were evaluated concurrently and all three read the marker as unset before any had written it.
A latch cannot work here, and that is structural rather than unlucky. Nothing serialises records entering the same evaluation window. The rule is short enough to keep: if the truth lives on the account, enrol the account. Rebuilt at company level, the duplication became impossible rather than merely improbable.
With the pattern named, a second false alert reported the same week was recognisable immediately — same class, truth on the deal, enrolling contacts — and was rebuilt at deal level with a date guard preventing thirty-nine historical records from replaying on enable.
Proving it quiet, and refusing to delete
Seventy-three companies were backfilled with the latch property, each sourced in a defined order of preference and audited as a mapping before it was applied rather than generated on the fly.
Verification was the point. After enabling, companies still eligible came to zero and enrolments on the rebuilt workflow came to exactly one — a deliberate live test, whose marker was restored afterwards. The second workflow correctly enrolled nobody, because it is not meant to touch history.
Three deletions requested during the same period were held rather than actioned. Each destroys data irreversibly — stage-timing history that does not survive even un-deleting a record, and form submissions with no recycle bin — and the exports that would make them safe did not exist yet. Holding a requested deletion is not obstruction; it is the difference between a reversible engagement and an unrecoverable one.
What changed
- Two paying customers that the CRM reported as having no active agreement now read correctly, and are visible to renewals again.
- The misreported population fell from six customers to four, and the remaining four are identified individually with a named owner and a defined recovery path rather than sitting undetected.
- Three date conflicts are held for a human decision against the signed contracts instead of being overwritten blind — including one stale date that looks populated and would have fired a renewal against the wrong year.
- Internal alerts went from roughly four per account to one, removing the noise that teaches a team to ignore its own notifications.
- A second alert with the same defect was found and rebuilt in the same session, with a guard preventing thirty-nine historical records from replaying on enable.
- An operating rule now exists in writing: the active-agreement flag is derived and must never be hand-set — if it reads false on a live customer, fix the date.
Where it stands
Delivered. The four dateless customers are folded into an existing contract audit with the client, and three date conflicts await the signed contracts. The only real proof the propagation is fixed is watching the next agreement close end to end — that was said plainly rather than declaring victory on a backfill.
Questions people ask about this
What is revenue assurance in a CRM context?
Checking that the data your renewal, churn and at-risk reporting depends on is actually true. In a recurring-revenue business those reports are usually driven by a derived field, and a derived field is only as good as the input behind it — so the audit works backwards from the report to the field to the source record.
Why would a paying customer show as having no active contract?
Usually because an expiry date failed to copy from the closed deal to the company record, and a maintenance workflow derives the active-agreement flag from that date. The flag is not broken; it is correctly reporting a blank input. The customer is live, the CRM says otherwise, and renewals, churn reporting and the at-risk register all read the CRM.
Should you overwrite a CRM field when the deal and company records disagree?
No. When two records disagree on a contract date, the CRM cannot tell you which is true — only the signed contract can. Overwriting blind replaces a visible disagreement with an invisible wrong answer. The dangerous case is a stale date rather than a blank one, because it looks populated, so nobody reviewing the record flags it and the renewal fires against the wrong year.
Why do internal CRM alerts fire multiple times for the same account?
Because the condition lives on the company but the workflow enrols contacts. Every contact on the account satisfies a condition that was never about them individually, so each one enrols and each one sends. Four contacts produce four emails.
Can a latch property stop duplicate workflow enrolments?
Not reliably. A latch assumes records are evaluated in sequence — first one through stamps a marker, the rest are excluded — and the platform evaluates many records concurrently. All of them read the marker as unset before any has written it. The only structural fix is to change the object the workflow enrols so it matches the object the condition describes.
In a recurring-revenue business, the field somebody noticed is rarely the problem. What matters is everything downstream that has been quietly treating the gap as a fact.
RevOps Diagnostic Audit