DocsProducts / Reading your scan report

Reading your scan report

A scan report is one page about one website: what an AI assistant could do there, where the number came from, and what to change. This page walks the report top to bottom so nothing on it has to be guessed at — including the parts that are deliberately missing.

The report is generated, not written. Nothing on it is an opinion: every line is a check that passed, failed or warned, and every number comes from a committed file that can be re-read.

There are two kinds of report. A named one, handed to the business it is about. And a published one at /scan/<slug>, which is the same measurement with the business removed. This page describes both; the published ones are the fifteen you can read right now.

A score out of 100, a grade, and one sentence saying what the grade means for a customer sent here by an assistant. Underneath: when it was scanned, which version of the scanner did it, and where the site sits in the fifteen-site sample.

The grade bands are fixed at 70 and 40. agent-ready at 70 and above, partially ready from 40 to 69, invisible to agents below 40.

01 — What an agent can actually do here

Every way in the scanner found on the page it fetched, and whether software could drive it. This is the section that decides whether a customer sent by an assistant becomes a job.

Each row is one detected action. Its columns:

Columns on an action row
FieldWhat it holds
kindOne of booking, quote, contact, callback, phone or widget — rendered as "Booking", "Quote request", "Contact form", "Callback request", "Phone link", "Booking widget".
labelThe short name of the thing found — "booking form", "Cliniko booking widget".
detailFor a form, the number of fields on it. For a phone link, the link itself — which is why it is withheld on a published report.
agentCallableTrue only on positive evidence: a declared tool, an advertised endpoint, a published catalogue, a known booking widget, or a form complete enough to fill. There is no "nothing looked broken" route to true.
callableViaPresent only when callable. Which of the five routes earned it.
blockersPresent only when not callable. Exactly what is missing, in plain words. This is the free fix list at action level.
A tel: link is never agent-callable. It hands off to a human, which is a real customer path and not an action software can complete.

Source: packages/scanner/src/publish.ts · apps/web/components/scan/copy.ts

One action row from a published report

{
  "kind": "booking",
  "label": "booking form",
  "detail": "8 fields",
  "agentCallable": false,
  "blockers": [
    "a CAPTCHA on this page blocks legitimate agents"
  ]
}
Copied unchanged from packages/scanner/publish/public-reports.json, the report published at /scan/clinic-01. The bundle is already anonymised, so nothing is substituted here.

That row is worth reading twice. The form has eight fields, every one of them fine, and the action is still closed to agents — because a CAPTCHA sits in front of it. The score is not what stops a booking. The wall at the end of the form is.

If the section is empty, the scanner found no way in at all on the page it fetched: no form, no widget, no phone link. Two of the fifteen sampled sites are in that state — source: packages/scanner/benchmark/reports/summary.json, breakdown.overall.sitesWithNoAction.

02 — Where the score came from

Five categories, twenty points each, with every individual check listed underneath as a pass, a warning, a failure or a note. Each category also carries one sentence explaining what it is measuring, aimed at an owner rather than a developer.

The five categories on a report
CategoryWhat it measures
Crawlability and discoveryWhether an agent is allowed in at all, and whether the site tells it where things are.
Structured dataWhether the business facts — trade, hours, phone, address, services — are published in a form software can read, rather than only drawn on the page.
Action affordancesWhether there is anything on the page an agent could act on: a booking widget, a form, a number.
Form qualityWhether the forms are built so software knows what goes in each box and can press send.
Agent interfaceWhether the site publishes any of the 2026 agent standards — WebMCP, an MCP endpoint, an ARD catalogue — or leaves an agent to scrape and guess.
The full point allocation for each category is on the agent-readiness score page.

Source: apps/web/components/scan/copy.ts · packages/scanner/src/checks.ts

Findings carry a status and, where any tooling counts them, a stable code. The prose of a message is for humans and may be reworded; nothing should ever be tallied by matching message text.

03 — The fix list

Everything the scanner found that has a named remedy, in the order the score reads them. These are instructions for whoever maintains the site. They are free, and they are the whole list — nothing is held back for a paid tier.

On a published report the fix text is rewritten on the way out, and the reason is worth stating plainly. Six fix strings in the committed 25 August evidence are written in the first person and advertise a hosted layer, a snippet and verified actions that do not exist. On a private report handed over by a founder who explains the state of things, that is a sales conversation. On a public page it is a claim we cannot support. So the publication path rewrites all six into instruction-only text, and refuses to publish a report in which one survives.

The wording was corrected at source in the scanner on 26 August 2026, so any scan run after that date produces instruction-only text directly. The fifteen committed reports were produced the day before and still carry the old wording, because regenerating them would mean re-fetching fifteen live sites that never asked to be scanned twice.

04 — How this compares

The same scanner, the same day, run over a sample of Sydney service businesses found the way a customer’s agent would find them: plain searches for a plumber, a physio and a real estate agent. Nobody was screened for looking bookable.

The section shows this site against the sample mean, the best and the lowest score in the sample, and a per-vertical table of mean score and how many sites had an action an agent could complete.

The sample this compares against
VerticalSitesMeanAgent can complete
Trades558.01
Clinics547.60
Real estate531.40
All1545.71

Source: packages/scanner/publish/public-reports.json · aggregates

05 — What this report is, and what it is not

This block is on every report and it does not get softened. It is reproduced here because it is the most important part of the page and the part a reader skimming a number will skip.

  • It measures one page, fetched once, read-only. The scanner requested the page and read the HTML it was handed. It did not run scripts, click anything, fill a field or submit a form, and it did not crawl the rest of the site. A site with a booking flow two clicks deep scores as if it were not there — because that is what an agent reading the fetched page gets.
  • It understates most sites, and we know by how much. Opening the same sample in a real browser — rendering, waiting for scripts, clicking, following a link — reached actions a fetch of the entry page could not see, on almost every site in it. Discovery is not the wall. The wall is the CAPTCHA and the consent tick at the end of the form.
  • It is version 0.1 of an instrument, not an audit. The scanner is early and its known defects are recorded in the repository rather than in a footnote. Treat a category score as a direction, not a verdict, and treat the fix list as the useful part.
  • Frontlatch cannot fix this site today. The hosted layer that would make these actions callable is being built and is not running. What exists is the measurement you are reading.
  • No action would ever fire without the owner turning it on. When that layer does exist, no live action runs on a business that has not verified that action type itself, set its own limits and connected its own notifications. Test mode is the default. That is a design rule, not a policy page.

What was removed, and why nobody is named

Every published report states its own redactions rather than leaving a reader to wonder. Three lines, on every one of the fifteen: the business name and website address are withheld; phone numbers and booking-widget URLs are withheld; and the raw page markup — the scanner’s evidence trail — is withheld.

The businesses in the sample are real trading companies. They did not ask to be scanned, they have no right of reply on these pages, and the instrument that scored them is early enough that we publish its defects. A named low score would allege something about a business that has done nothing wrong, and the argument does not need it: a real estate agency in Sydney scoring twelve out of a hundred says exactly as much without a name on it. The only report that carries a name is one handed to the business it is about.

That twelve is the lowest score in the sample and it is real. Source: packages/scanner/publish/public-reports.json, the report published at /scan/real-estate-05.

The removal is structural rather than a find-and-replace pass. Identifying fields are rebuilt from a safe vocabulary instead of filtered, and any free-text field that does not match a known-safe shape is replaced wholesale. A final check throws on a surviving hostname, business-name token or phone number before anything can be published, and the test suite greps the generated bundle for every one of those and fails if a single one survives.

The subject a reader sees is an editorial descriptor and a placeholder host — "Sydney plumber", <sydney-plumber>.com.au — and descriptors are deliberately shared by more than one site in the sample. A descriptor that narrowed to one business would be a name with extra steps. Slugs are assigned by score rank within a vertical, deliberately not by the order of the site list.

Where the numbers came from

The report pages render a committed file; they never re-score anything. That file carries its own provenance, so a claim on a page can always be walked back to the run that produced it.

The bundle describing itself

{
  "experiment": "Experiment 1 — technical spike: can we map real sites? (docs/02-validation-sprint.md)",
  "scanner": "agent-readiness-scanner v0.1.0",
  "scannedAt": "2026-08-25T10:42:04.906Z",
  "sites": 15,
  "scanned": 15,
  "failed": 0,
  "politeness": "Read-only. Sequential, 2000ms between sites, 45000ms per-site timeout. No form was filled and nothing was submitted.",
  "artefact": "packages/scanner/benchmark/reports/"
}
Copied unchanged from the generatedFrom block of packages/scanner/publish/public-reports.json.

Written from

  • The public report type and the redaction pathpackages/scanner/src/publish.ts
  • The bundle builder and the anonymisation keypackages/scanner/src/build-public.ts
  • The published bundle the pages render frompackages/scanner/publish/public-reports.json
  • Every string on the report surfaceapps/web/components/scan/copy.ts
  • The scanner explainerpackages/scanner/README.md