AutomationJuly 27, 20269 min read

We Rebuilt Our Own Audit Engine. Version One Would Have Told 42 Businesses They Had No Website. The Real Number Was 24.

A teardown of Avalon's own automation, with before-and-after numbers from the code and from the 182 businesses it has since measured. Four bugs shipped. Here is what each one would have cost, and the free five-minute fix a Providence convenience store can do on Monday.

By Joshua Amado

Share
The bark of an old street tree, close up — decades of growth in a city park.
The bark of an old street tree, close up — decades of growth in a city park.

Every week I publish numbers about local businesses. Load times, review counts, whether the phone number on the website matches the one on the Google listing. Those numbers get read by the owners. Sometimes they get read out loud on a phone call, by me, to the person who owns the shop.

So the machine that produces them has to be right. Not roughly right. Right.

This article is a teardown of that machine. Not a client's site, not a competitor's. Ours. It shipped with four bugs, and I want to show you exactly what each one would have published if I had not caught it, because the lesson underneath is the whole reason automation is worth doing at all, and the exact reason it is dangerous.

What the machine has actually done#

Numbers first, because the criticism only counts if the thing is real.

182
Businesses measured
Across 17 category briefs, 8 towns
65,293
Google reviews represented
The demand is not in question
24
Sites we could not read
Recorded as UNMEASURED, never as a finding

Seventeen briefs, thirteen categories, eight towns across the South Coast and into Rhode Island. Every one of those 182 businesses is a real place with a real door. Most of them are very good at the thing they sell. That is the whole point of the exercise: the demand is already there, and it is leaking out through problems nobody told them about.

Version one, version two#

The engine was first committed on 11 July 2026 at 462 lines. By the next day it had grown to 570. Then, in a single commit on 12 July, it went to 1,293 lines. It sits at 1,384 today.

StageDateLines of code
First commit2026-07-11462
v1 final2026-07-12570
v2 rewrite2026-07-121,293
Today2026-07-271,384

That +723 line jump in one day was not a feature release. It was a rewrite, and every one of the additions exists because version one was quietly producing a wrong answer.

Grand Victorian houses and stone gateposts along a tree-lined Fall River street.
Grand Victorian houses and stone gateposts along a tree-lined Fall River street.Fall River, MA

Bug one: it called a locked door an empty lot#

This is the worst one, and it is the headline.

Some websites refuse automated requests. A firewall sees a script, returns a 403, and hangs up. The site is perfectly fine. A human with a phone would load it without noticing anything.

Version one counted total businesses, subtracted the ones it had successfully read, and published the remainder as "no website." One line of arithmetic:

no_website = len(results) - len(live)

Across the 17 briefs we have run since, 18 businesses blocked our checker and 24 genuinely have no website at all. Version one would have published 42. That is a 75% overstatement of the single most quotable finding in every brief, and each of those 18 wrong entries is a real business in a real town being told, in public, that it does not exist online.

The fix is in the code as a comment, because I wanted the next person to see the scar:

# THE BUG THAT ONCE SHIPPED: this was `len(results) - len(live)`, which
# counted every bot-blocked site as having no website and published it.
# "No website" now means ONLY: no URL exists anywhere.

A related version of the same mistake lived in the scoring: an unreadable site was being scored zero out of thirty-five, which turned a firewall into a fabricated letter grade F. Now an unmeasured component is None, and it is excluded from the score rather than counted against the business.

Bug two: expired certificates read as healthy#

Version one disabled certificate checking so it could fetch pages that would otherwise fail. Convenient, and wrong. An expired certificate is not a technicality. It is a full-screen red browser warning that stops most visitors dead before they see a single word.

Version two does a separate strict TLS handshake. Across the 136 sites where we could complete one, 13 had an invalid or expired certificate. Version one scored all 13 as healthy.

Bug three: the schema check matched almost anything#

Structured data tells Google your hours, address and phone in a format it does not have to guess at. Version one checked for the string localbusiness or schema.org anywhere in the HTML, which meant any WordPress theme emitting any JSON-LD at all scored the points.

That bug ran in our favour, which is why it took longer to notice. It understated the problem. Version two parses the JSON-LD properly and checks the type. Real figure across the dataset: 75 of the 140 live sites have no LocalBusiness schema. The denominator is 140, not 182, because the other 42 either have no site or would not let us read one, and we do not test what we cannot open.

Bug four: we had both numbers and never compared them#

The engine was already pulling the phone number and address from the Google Business Profile, and already pulling them off the website. It never checked whether they matched.

They often do not. 29 of the 123 businesses where we could measure both had a mismatch. That is roughly one in four. Google reads a conflict as a signal that it is not sure which listing is correct, and a customer who dials the old number gets a dead line.

The part I cannot automate away#

This isn't new. Automation has always been about eliminating work that is repetitive, and often dangerous or boring.
Ethan Mollick Business school professor and author of the One Useful Thing newsletter Source

Mollick is right, and the sentence carries a hidden condition. Automation eliminates repetitive work. It does not evaluate that work. It will repeat a flawed judgement with total consistency and no fatigue, which is precisely what makes it more dangerous than doing the job by hand. Doing it by hand, you would have noticed on the third business that something looked off.

Two things came out of this that have nothing to do with code:

Measure the thing, not a proxy for it. The engine exists because a naive HTML-fetch timer reported 0.54 seconds for a site whose real mobile load was over eight. HTML delivery is not load time. If you take one habit from this piece, take that one.

Say "unmeasured" out loud. Facebook returns an identical error for a page that exists and one that does not. Instagram returns success for any handle you invent. So our social tool reports both as unmeasurable and refuses to guess. That is less impressive than a full score, and it is the only version I am willing to read to somebody over the phone.

The Walnut Street sign, with a Victorian tower behind it.
The Walnut Street sign, with a Victorian tower behind it.Fall River, MA

So what does a Providence convenience store do on Monday#

Plainly: we do not yet have a convenience store brief for Providence. A run is underway. Google Places returns 19 convenience stores for Providence, and as of this writing 3 of the 19 have been audited. Three is not a sample, so there are no convenience store numbers in this article and I am not going to invent any for the sake of a tidy ending. When the run finishes, the brief goes up like the others.

What we do have is measured data from other Providence categories, and the failure patterns hold across every category we have run.

Providence restaurants, measured 19 July: 8 businesses, 16,657 Google reviews between them, 4.61 stars average, and a median mobile load of 1.4 seconds from real visitor field data. Genuinely fast. And still, 4 of 8 had no contact form, 5 of 8 had no LocalBusiness schema, and 3 of 8 had no analytics at all.

Providence veterinarians, measured 20 July: 20 businesses, median mobile load 11.1 seconds, slowest 28.3 seconds, and 18 of 18 with no way to book anything online.

A corner store has less to lose from a slow site than a vet does, because nobody browses for a gallon of milk. But a corner store lives entirely on two questions: are you open, and where are you. Both of those are answered by your Google listing, not your website, and both are trivially easy to get wrong.

The free fix, five minutes, do it today#

Open your Google Business Profile on a phone. Now open your own website on the same phone. Compare four things, character by character:

  1. The phone number. Same digits, same order. One in four businesses we measured failed this.
  2. The street address, including the suite number and the abbreviation.
  3. The hours. Especially the holiday and Sunday hours you changed two summers ago.
  4. Whether the phone number on the website is tappable. Tap it. If it does not start a call, it is text, not a link. 50 of the 140 live sites we measured failed this. For a convenience store, where most searches happen on a phone within a mile of your door, this is the single highest-value thirty seconds you will spend this year.

Fix any mismatch on the website side, since that is the one you control directly, then update the Google listing to match. Cost: nothing. Time: five minutes. No developer required.

The teardown, in one line#

We shipped four bugs, and every one of them made the tool sound more confident than it had any right to be. That is the failure mode of automation generally, and it is the one to watch for in whatever you are automating in your own shop, whether that is invoicing, scheduling or a spreadsheet somebody built in 2019 that nobody has opened the formulas of since.

A system that says "I do not know" is worth more than a system that is confidently wrong. That is true of an audit engine, and it is true of the process you use to order stock.

If you want the numbers for your own category and town, or you want somebody to look at the thing you have been meaning to automate, I am in Fall River and I answer my own phone.

774.559.8992 · Joshua.Amado@AvalonPartner.com


Method note: line counts are from the repository's own git history. Business counts are summed across the 17 briefs in our audit state directory as of 27 July 2026. Sites that refused our checker are recorded as unmeasured and excluded from every count, never counted as a finding against the business. Where a count applies only to live, readable sites, the denominator says 140 rather than 182. No business is named. The Providence convenience store run is partial (3 of 19 audited) and no figure from it appears above.

Want help putting this into practice?

Avalon Partner helps Fall River and South Coast businesses fix the gaps that cost them leads. Call 774.559.8992 or email Joshua.Amado@AvalonPartner.com.

Keep reading