An HVAC company running a mixed team of install and service technicians almost let a payroll rule bug slip through, crediting one technician with 71 hours of non-job paid time before anyone caught it. Here is how a same-day catch corrected that number to 48, reassigned misattributed sales credit to the technician who actually sold the job, and left the company with a repeatable payroll audit instead of a one-time setup.
Picture an HVAC company running a mixed team of install and service technicians, the kind of shop where install crews chase new equipment sales while service techs work the maintenance and repair calls that keep the phones ringing. Pay here isn't just an hourly rate. Non-job paid time, sales credit on installs, and a handful of adjustment categories all feed into what each technician actually takes home, and all of it has to reconcile before payroll can run.
The trouble showed up during a routine payroll cycle, the kind that's supposed to be uneventful. Someone reviewing the pay calculations for that pay period noticed a technician's non-job paid time read 71 hours. That's a number that doesn't happen by accident and doesn't look right for a normal two-week stretch, so it got a second look before anyone signed off on it.
What they found was a rule bug sitting quietly in the pay-calculation logic. Technicians' schedules include a mix of paid working time and unpaid, non-working calendar events, things like time off requests, blocked-out non-billable blocks, and other entries that exist on the calendar but were never meant to carry pay. The rule that was supposed to separate the two wasn't doing its job. It was counting some of those unpaid, non-working events as though they were paid non-job time, quietly inflating the hours that fed into that technician's pay. Left unchecked, it would have meaningfully overpaid him had it gone through to that day's payroll run.
That wasn't the only thing wrong with the numbers. Separately, sales credit for completed installs was landing on the wrong technician. The HVAC company's field service software has a "sold by" field on every job, and in theory it should always match the technician the company itself considers the salesman on that job. In practice, the two didn't always line up. Some installs were closing out with a "sold by" value that pointed to a different technician than the one who actually walked the customer through the sale, which meant commission and sales credit were being calculated against the wrong name.
On top of both of those, the company had a set of pay adjustment tags for situations that come up constantly in HVAC work: warranty callbacks, recalls, and a catch-all miscellaneous category. Each of those is supposed to translate into a defined plus or minus adjustment to a technician's pay. But the tags themselves were ambiguous enough that two people entering the same situation could reasonably tag it differently, and each tag choice changed the math. A recall handled one way added money. Logged as something else, it subtracted. Nobody had set out to make the rule inconsistent. It had just never been pinned down tightly enough to survive different people using their own judgment on the same afternoon.
A Number That Looked Wrong Because It Was
What made this catchable wasn't luck. It was that 71 hours of non-job paid time in a single pay period was implausible enough on its face that it triggered a second look before the check ever got cut. That's the pattern worth sitting with: the bug had presumably been running for longer than one pay period, but this was the first time the output was extreme enough, and someone was paying close enough attention, for it to get flagged before money moved.
Three Separate Problems, One Payroll Cycle
Taken individually, none of these three issues, the paid-time rule bug, the sold-by mismatch, and the ambiguous adjustment tags, would necessarily have been catastrophic on their own. Together, in the same pay period, they added up to a payroll run that could not be trusted to go out as calculated. The company's next move wasn't to patch the one number that looked obviously wrong and call it done. It was to go after the rule itself, and then check how far back its effects reached.
Fixing a single technician's number wasn't the goal. The team needed the underlying rule to stop miscounting for everyone, on every future pay period, not just for the one case that happened to get caught. That meant going back into the pay-calculation rule that classified non-job paid time and rewriting the logic so it only counted genuinely paid events. Unpaid, non-working calendar entries, time off, blocked non-billable time, and anything else that was never meant to carry pay, stopped being swept into the non-job paid time total. Going forward, that number would only reflect hours the company actually intended to pay.
A rule fix by itself only protects the future. It says nothing about what already happened under the broken version. So the next step was a historical audit: re-syncing and reviewing past pay periods against the corrected rule to see how much overpayment exposure had existed before anyone caught it. That's a different kind of work than fixing a bug. It's forensic. The company needed to know not just that the rule had been wrong, but for how long, how many technicians it had touched, and how much had moved as a result, so leadership could decide what, if anything, needed to be reconciled after the fact.
That kind of audit isn't a single query you run once and trust. It means pulling the historical pay data pay period by pay period, re-running it against the corrected rule, and flagging every case where the old rule and the new rule would have produced a different number for a technician. For a mixed team of install and service technicians working overlapping schedules and a rotating mix of paid and unpaid calendar events, that's methodical work, not a quick pass, and it has to hold up if anyone ever asks how the company arrived at its numbers.
Fixing Sold-By, Job By Job
The sold-by mismatch needed a more manual fix. There was no single rule to patch, because the underlying issue was a data quality problem: the field service software's "sold by" value and the company's own internal salesman designation were two separate fields that didn't have a reliable process keeping them in sync. So the company went through the specific jobs where the two disagreed and corrected the "sold by" field on each one, one job at a time, so it matched who actually sold the work. It's not a glamorous fix, but it's the only one that actually gets commission and sales credit landing on the right technician instead of whoever the software defaulted to.
The longer-term fix was standardizing how the ambiguous adjustment tags translated into pay. Warranty, recall, and miscellaneous had all been judgment calls up to that point, the same situation could get logged as a plus or a minus depending on who was entering the data and how they happened to interpret the category that day. The team defined a specific plus or minus amount per category so the decision was baked into the tag itself instead of left to whoever was at the keyboard. A recall now means a defined adjustment, every time, regardless of who's entering it. Warranty and miscellaneous work the same way. That doesn't just make the numbers more consistent, it makes them auditable, because anyone reviewing a pay period later can see exactly which tag was applied and know precisely what it should have done to the number.
Why The Order Of Operations Mattered
None of these three fixes depended on the others, but doing them in this order mattered. Fixing the rule first stopped the bleeding going forward. Auditing the history next quantified what had already happened, so nobody was guessing at the scope of the exposure. Correcting the specific misattributed jobs and standardizing the adjustment tags closed the two remaining gaps that had nothing to do with the paid-time bug but were sitting in the same pay period, waiting to be found. A company that only fixed the most visible problem, the 71-hour number, would have shipped a payroll run that still had two other quiet errors baked into it, just quieter ones that hadn't produced a number extreme enough to get noticed yet.
Profit sharing
made simple.
Give your team a stake in the company’s success. ShareWillow helps you create and manage profit-sharing programs that motivate employees and drive business results.
By the time that pay period's payroll went final, the technician's non-job paid time had been corrected from 71 hours down to 48. That's not a rounding adjustment. It's a 23-hour gap between what the rule was about to pay out and what the technician had actually earned, caught and corrected the same day, before the checks were cut rather than after. The misattributed installs got reassigned to the technicians who actually sold them, so sales credit and commission lined up with who did the work instead of whoever the software happened to default to. And the warranty, recall, and miscellaneous tags stopped being a judgment call, because each one now maps to a specific, defined adjustment no matter who's entering the data.
The most valuable outcome wasn't any single number. It was the fact that the company now has a repeatable audit step built into every payroll cycle: review non-job paid time and sold-by attribution before the run goes final, not after. That's a meaningful shift. Before this, a rule bug could run quietly for an unknown number of pay periods before anything looked wrong enough to investigate. Now there's a standing check that catches exactly the kind of anomaly that flagged this one in the first place.
It's worth sitting with what almost happened here. Had that pay period closed without a second look, the technician would have been paid against a non-job paid time total that didn't reflect real hours, and the company would have had no way of knowing until the next time the same bug produced a number extreme enough to raise a flag. Catching it same-day instead of after the fact isn't just cleaner bookkeeping. It's the difference between fixing a number before it becomes real money in someone's account and trying to claw back an overpayment after the fact, which is a far more uncomfortable conversation to have with a technician.
What This Means For Other HVAC Owners
Most HVAC businesses running a mix of install and service technicians have some version of this exposure sitting in their pay calculations right now, whether or not it's ever surfaced. Non-job paid time, sales attribution, and adjustment tags are exactly the kind of categories that get set up once, mostly correctly, and then never get a second look until a number is extreme enough to catch someone's eye. The uncomfortable truth is that 71 hours was an unusually visible mistake. A smaller version of the same bug, one that overpays a technician by two or three hours instead of twenty-three, could run for months without anyone noticing, simply because it never produces a number extreme enough to trigger a manual review.
What To Check Before Your Next Payroll Run
A few habits would have caught this sooner, and they're worth building into any HVAC company's payroll process regardless of what system runs it. Look at non-job paid time on its own, separate from job hours, for every technician, every pay period, and ask whether the number makes sense for the actual time off and non-billable entries on that person's calendar. Spot-check the "sold by" field against your own internal sales designation on a sample of recently closed installs rather than assuming the two fields have stayed in sync. And write down, in plain language, exactly what dollar amount each pay adjustment tag is supposed to trigger, so two different people entering the same situation land on the same number instead of two different ones. If you run a mixed crew of install and service technicians, treat that mix as a reason to check more often, not less, since install sales attribution and service non-job time behave differently and can each break in their own way.
None of that requires new software. It requires treating pay rules the way you'd treat any other part of the business that touches money, with a standing audit instead of a one-time setup you trust indefinitely. The company in this story didn't get lucky because their system was perfect. They got lucky because someone looked at a number before the payroll run went final and asked why it looked wrong. That's a habit any incentive pay program can build in, and it's a lot cheaper than finding the same bug after the checks are already in technicians' hands.
Conclusion
Before the fix, a rule bug was quietly counting unpaid, non-working calendar events as paid non-job time, and one technician's total read 71 hours for a single pay period before anyone caught it. After the fix, that same number came back to 48, misattributed sales credit was reassigned to the technicians who actually sold the work, and the ambiguous warranty, recall, and miscellaneous tags were standardized into defined dollar adjustments. The company now runs a repeatable audit on non-job paid time and sold-by attribution before every payroll cycle instead of discovering gaps after the checks are already cut.
Create incentives
that
drive results
You shouldn't need complex equity plans to align your team. ShareWillow makes it simple to create transparent profit-sharing programs that motivate employees and grow your business.

Incentive plans to help
small businesses thrive.
.png)
"I was able to leverage the knowledge of the ShareWillow team to learn how other companies were designing their bonus plans. The template was extremely helpful."

