Lead-to-Pipeline Systems
Synthetic benchmark Synthetic data: Ledgerly
A Salesforce lead lifecycle and routing design, shipped the way a GTM Systems team would: discovery brief, requirements, SFDX metadata, a replay simulator, UAT tests in CI and release notes.
- Status
- Write-up ready, code not public yet
- Relevant to
- GTM Systems
Results · Synthetic data: Ledgerly
- Synthetic benchmarkSynthetic data: Ledgerly. Measured against a hidden answer key in that data. It shows the method works there, not a production result.open leads owned by a rep who had left, down to 0 in the replaySynthetic benchmark
- Synthetic benchmarkSynthetic data: Ledgerly. Measured against a hidden answer key in that data. It shows the method works there, not a production result.leads that skipped their account’s active owner, down to 0Synthetic benchmark
- Synthetic benchmarkSynthetic data: Ledgerly. Measured against a hidden answer key in that data. It shows the method works there, not a production result.duplicate leads caught at entry, where there had been noneSynthetic benchmark
- Implementation factA fact about what was built and tested, not a business outcome.each named by its UAT ID and acceptance criterionImplementation fact
At a glance
- Question
- Why do leads end up with reps who left or skip the account’s owner, and what routing design fixes it?
- Data
- 29,447 historical Ledgerly leads (synthetic), replayed in time order.
- Compared with
- The routing outcomes recorded in the data.
- How it was tested
- Run every lead through the new rules in time order, with reps joining and leaving on their real dates, and recount from SQL independently.
- Result
- In the replay, open leads owned by a departed rep went from 2,658 to 0, and leads that skipped their account owner from 965 to 0.
- What it doesn’t show
- Not deployed to a Salesforce org, so the Apex and flows haven’t been compiled there. The replay shows the rules, not adoption by a sales team.

The problem
Open leads sat with reps who had left, leads from existing accounts skipped the account’s owner, and only 3.1% of MQLs became an opportunity within 48 hours.
What I built, in detail
- A discovery brief measured from the data, requirements with acceptance criteria, and a field dictionary.
- SFDX source: 28 custom fields, 6 validation rules, 2 record-triggered flows, 3 Apex classes with tests, queues, territory metadata and permission sets.
- A TypeScript simulator that replays 29,447 historical leads in time order through the same rules, with reps joining and leaving on their real dates.
- Metadata checks that need no org, including parity checks so the simulator and the metadata can’t drift apart.
How I checked it
- Every number came from the data twice: SQL during discovery, then independently from the simulator’s replay.
- Tests were checked by breaking the code. Reversing the account tie-break and the backward-move rule made the matching UAT tests fail.
Limitations
- Not deployed to a Salesforce org yet, so the Apex and flows haven’t been compiled there. The metadata converts cleanly with the Salesforce CLI.
Where it came from
My website routes every lead by type, area, language and agent into my CRM with the right campaign. This is the Salesforce version, designed for scale. Read the AI CRM case study.
Stack
Salesforce DX, Flow, Apex, TypeScript, DuckDB, GitHub Actions