The Job That Looked Profitable and Was Not

Why this matters

A job cost record only measures what somebody coded to the job. Everything else - hours logged to a generic bucket, a return trip filed under warranty, a change performed and never invoiced - still hits the bank account and still hits the profit and loss statement, but it never touches the job. So the job record can show a healthy margin while the shop that ran it loses ground, and the owner reading job-level reports has no way to see the difference.

This walkthrough follows one shop from the first signal to the confirmed cause. The three wrong diagnoses they worked through first are the same three most shops try, and the reasoning that ruled each one out is worth more than the answer.

The first signal

The shop ran a quarterly review. The volume-weighted gross margin across their closed job records was 31 percent. The gross margin on the books for the same quarter was 19 percent.

Twelve percentage points of revenue, in a quarter, with no obvious cause. That gap is the signal, and it is worth naming precisely because it constrains the search immediately: the job records and the books disagree about the same quarter, so either the records are counting cost that the books do not, or the books are counting cost the records do not. Cost is not disappearing into the air. It is being counted in one place and not the other.

The owner's first instinct was to doubt the books. That is the wrong instinct almost every time. The books capture every dollar that left the account whether anyone coded it or not. The job records capture only what someone chose to attach to a job. When those two disagree, the incomplete one is nearly always the job records.

Wrong diagnosis one: overhead went up

The first theory was that overhead had grown - a new vehicle, higher insurance, more office time.

This was ruled out on definition rather than on data, which is why it took two minutes rather than two days. Gross margin is computed above overhead. It is revenue minus direct job cost: labor, materials, subcontract, and other costs attributable to specific jobs. Overhead sits below that line and reduces net profit, not gross margin. A rise in overhead cannot open a gap in gross margin, so the theory was structurally impossible before anyone pulled a number.

Worth knowing as a reflex. Before you investigate a discrepancy, check whether the proposed cause can even live at the line where the discrepancy appears. It eliminates a large share of plausible-sounding theories at no cost.

Wrong diagnosis two: material prices moved

The second theory had better standing. Supplier prices had risen, the estimates carried old allowances, and material overruns were eating the margin.

They tested it directly: the median ratio of actual material cost to allowance across the quarter's closed jobs was 1.04x. Materials were running 4 percent over allowance.

Then they sized it. Materials on these job types run at roughly a quarter of revenue. Four percent over on a quarter of revenue is about one percentage point of revenue. Real, worth fixing, and nowhere near twelve.

This is the step that gets skipped. A confirmed finding is not the same as a sufficient finding. The material overrun was genuinely there, and a shop that stopped here would have refreshed its allowances, felt like it had solved the problem, and watched the gap persist unchanged into the next quarter.

Whenever you find a cause, size it against the gap before accepting it. If it explains less than roughly a third of what you are looking for, keep going.

Wrong diagnosis three: a crew is running slow

The third theory was the human one. One crew was assumed to be running long and dragging the labor cost.

They broke labor variance out by crew across the quarter. Every crew sat within a couple of percentage points of the others. There was no outlier.

That result is more useful than it looks. It did not just eliminate a crew. It said the problem was not distributed like a people problem at all. People problems concentrate. This one was spread evenly across everybody, which points at a system, a process, or a definition rather than a person. That reframing is what pointed the investigation at the accounting for the hours rather than at the hours themselves.

The audit: one job, line by line

They picked the flagship job of the quarter - the one whose 34 percent recorded margin had been cited as evidence the job type was healthy - and reconciled it against every other source they had.

Source one, payroll. Across the calendar dates that job ran, the assigned crew was paid for 90.0 hours. The job record carried 68.0 hours. On those dates the crew was on that site and nowhere else.

The missing 22.0 hours had been logged to a generic shop code. Nobody had falsified anything. The code was the path of least resistance at end of day and it did not require picking a job from a list.

Source two, the warranty log. Two return visits to the same site, three weeks after completion, totalling 6.0 hours. Both were coded to a warranty bucket with no job attached. Warranty work is a real category, but coding it to a bucket that no job ever sees means the cost of fixing a job never lands on the job that caused it.

Source three, the change log. One change was performed on site and never invoiced. 9.0 hours of labor plus materials. There was a verbal agreement with the customer and no paperwork behind it, so it never became revenue, and because it was never a change order it never became a cost segment either.

What the numbers actually said

Work everything as a share of that job's invoiced revenue, which keeps the arithmetic clean.

The record showed labor at 40 percent of revenue for 68.0 hours. So one labor hour on this job is 40 divided by 68, about 0.59 percent of revenue.

  • The 22.0 unallocated hours: about 12.9 percent of revenue.
  • The 6.0 warranty return hours: about 3.5 percent of revenue.
  • The unbilled change: 9.0 hours is about 5.3 percent of revenue, plus its materials at roughly 2 percent, so about 7.3 percent.

Those three total about 23.7 percent of revenue. Against a recorded gross margin of 34 percent, the job's real gross margin was about 10 percent.

Not a loss. Worse than a loss in one specific way: a job that loses money gets noticed and investigated. A job that returns 10 percent while reporting 34 percent gets held up as the model, and the shop bids more of them.

The real cause

Not three problems. One.

The shop had no reconciliation between paid hours and job-coded hours. Every hour a tech did not voluntarily attach to a job silently left the job-costing system while remaining fully present in payroll and on the profit and loss statement. The warranty bucket and the uninvoiced change were the same failure wearing different clothes: cost with no job attached.

They checked it at the shop level. For the quarter, paid field hours were 1,240 and job-coded hours were 940. The gap was 300 hours, which is 24 percent of the 1,240 paid hours.

Then they sized it against the original signal, which is the step that turns a plausible cause into a confirmed one. If job-level records show labor at 40 percent of revenue but only 940 of 1,240 paid hours ever reach a job, then true labor is 40 percent multiplied by 1,240 over 940, which is about 52.8 percent of revenue. The hidden labor is the difference, about 12.8 percentage points of revenue.

The observed gap between the job records and the books was 12 percentage points. The cause accounts for essentially all of it. That closure is what separates the real diagnosis from the three that came before, each of which explained a point or two at most.

Note that the individual job matched the shop pattern rather than being special: 68.0 coded of 90.0 paid is about 76 percent, against the shop-wide 940 of 1,240, which is also about 76 percent. The flagship job was not unusually badly coded. It was ordinary. Every job in the quarter carried the same distortion, which is precisely why the job-level rollup looked so consistently healthy.

Why it hid so well

Three properties made this nearly invisible, and each one is worth recognizing on sight.

It was uniform. A leak that hits every job equally never produces an outlier, and outlier detection is how most shops find problems. The job-type rollups looked tidy. The variance reports looked calm. Nothing was flagged because nothing was unusual.

It biased in the flattering direction. Missing cost always makes margin look better. A shop is far less likely to audit a number that pleases it, and this one pleased everybody every month for as long as it ran.

Each individual behaviour was reasonable. No tech was trying to hide anything. A generic code existed and was easier to pick. Warranty work genuinely is its own category. The change genuinely was agreed verbally with a customer who was going to pay for something else anyway. Every step made local sense and the aggregate was a 12-point misstatement.

The fix, and how they confirmed it

Three changes, in order of how much they returned.

A monthly reconciliation, non-negotiable. Paid field hours against job-coded hours, every month, with the difference explained by category. The generic shop code stayed available - removing it just produces hours coded to the wrong job, which is worse than hours coded to nothing - but any month where the unallocated share exceeded a set ceiling triggered a review. They set the ceiling at 15 percent of paid field hours initially, intending to tighten it as coding improved.

Warranty hours attach to the originating job. The warranty bucket still exists for reporting, but every warranty entry now requires the job that caused it, so callback cost lands on the job type that generates it. This changed which job types looked profitable, which was the point.

No work performed without a written change. The uninvoiced change was a revenue failure rather than a costing failure, but the costing fix surfaces it: a zero-revenue change segment on a job is now visible on the record instead of dissolving into the original scope.

Confirmation. The following quarter, unallocated hours fell to 11 percent of paid field hours, and the gap between volume-weighted job-level gross margin and book gross margin narrowed to 3 percentage points. A gap that small is the ordinary residue of timing differences and allocation conventions rather than a defect, so they stopped chasing it.

What would have changed the conclusion

If the unallocated share had been small. Had the reconciliation shown 5 percent of paid hours unallocated rather than 24, the same three symptoms would have needed a different explanation. The most likely candidate then is revenue-side: invoices that never went out, discounts applied at billing and never fed back to the job record, or credits issued after close. Run the same reconciliation on the revenue side, comparing invoiced revenue against the revenue recorded on job records.

If the gap had appeared suddenly rather than gradually. A margin gap that opens in one specific month usually has one specific cause: a supplier change, a large job costed wrong, a change in how someone codes. This one had been widening slowly for over a year, which is the signature of a systemic allocation problem rather than an event.

If crew variance had shown a real outlier. Had one crew sat well outside the others, the investigation would have gone to method and supervision first, and correctly so. The uniformity of the variance was the strongest single clue that this was structural.

If the shop paid piece rate rather than hourly. The payroll reconciliation would not work, because paid amounts would not correspond to hours. The equivalent check is comparing scheduled field time against job-coded time, using dispatch records as the denominator. Less precise, and it still would have caught a 24 percent gap.

References

  • U.S. Small Business Administration (SBA), gross margin and job cost analysis for small business
  • Generally Accepted Accounting Principles (GAAP), direct cost allocation and revenue recognition
  • See related: The Job Costing SOP; The Hidden Costs That Never Make It Into an Estimate; Cash vs Profit - Why They're Different