# Sample audit report: Northwind Fasteners Oy

2026-09-08

This is a synthetic sample of the agent-readiness audit report. The company, the domain northwind-fasteners.example, every reading and every date are invented to show the format, the depth and the wording a paying client receives. Nothing on this page describes a real client, and no figure here has been measured on a real site. A real report carries the raw scanner output and the request logs as an appendix, which this sample leaves out.

## Contents

- [Engagement record](#engagement-record)
- [Summary](#summary)
- [Scope and method](#scope-and-method)
- [Scanner readings, check by check](#scanner-readings-check-by-check)
- [Manual review](#manual-review)
- [AI visibility today](#ai-visibility-today)
- [Published security scans](#published-security-scans)
- [Findings, in fix order](#findings-in-fix-order), F1 to F8
- [Fix order and effort](#fix-order-and-effort)
- [What happens next](#what-happens-next)
- [What this report is not](#what-this-report-is-not)

## Engagement record

| Field | Value |
| --- | --- |
| Client | Northwind Fasteners Oy, industrial fastener wholesaler, invented |
| Surface audited | The public site northwind-fasteners.example and its REST API at /wp-json/ |
| Kickoff, scope agreed in writing | 2026-08-25 |
| Scanner run | 2026-09-03, isitagentready.com, default profile, three serial runs, all three identical |
| Manual review | 2026-09-03 and 2026-09-04 |
| AI visibility run | 2026-09-04, 15 questions to four assistants, one anonymous run per question |
| Report delivered | 2026-09-08, fourteen days after the kickoff |
| Written follow-up round | Open until 2026-09-22 |
| Re-scan | One, included, within 30 days of the report, by 2026-10-08, on the day the company names |
| Access used | Public surfaces only. No login, no credentials, no code repository |

## Summary

The site reads Level 1 of 5 on isitagentready.com, with 2 of the 21 scored checks passing. The two that pass are robots.txt and sitemap.xml, and both exist because the content management system ships them. Everything an agent would use on purpose is missing: no markdown form of any page, no llms.txt, no Link relations, no discovery file for the REST API that already runs, and no named rules for AI crawlers.

The most expensive finding scores no points at all. Every one of the 138 product pages publishes structured data with a price of 0,00 EUR and an availability of InStock, while the visible page shows a real price and, for 41 products, a six week lead time. An agent that trusts the data tells a buyer the whole catalog is free and in stock. This is fixed first, before anything that moves the score.

The eight findings below flip six scored checks and correct two findings outside the scored set. Seven of the eight are edge or configuration work of about one working day in total. The eighth is a decision to leave the five commerce checks red on purpose, because a commerce declaration that points at a checkout an agent cannot complete would be a false claim.

The report names the checks it moves, not a level it promises. The level moves with the check set the scanner runs on the day, and 22 checks were in the set on 2026-09-03.

## Scope and method

What was measured, in this order.

- The independent scanner. isitagentready.com was run three times in series against the origin with the default profile, and the three runs agreed. The denominator on the day was 22 checks, 21 scored and one informational, webBotAuth. Every check is recorded below individually rather than as one headline number.
- A manual review of what the scanner does not score. JSON-LD on the home page, one category page and five product pages. Head metadata and Open Graph on the same seven pages. HTTP response headers on the home page and one product page. The /.well-known/ directory. robots.txt, sitemap.xml, ai.txt and llms.txt against the current norms. The first response of each page fetched as a bot, to see whether the content arrives or a script shell does.
- AI visibility today. A fixed set of 15 questions, 12 that describe the category without naming the company and 3 that name it, put once to four AI assistants in anonymous sessions on 2026-09-04. Recorded per answer: whether the company is named, whether the answer is correct where it names it and which sources the assistant cites.
- Published security scans. internet.nl website and mail tests and Hardenize, run on 2026-09-04, so the report rests on measurements the client can re-run without turva.dev.

What was not measured. No code was read, no credentials were used, no penetration test was run and no traffic analytics were seen. The REST API was read through its public routes only. Rankings on any AI platform were not measured and are not promised anywhere in this report.

## Scanner readings, check by check

isitagentready.com on 2026-09-03. PASS and FAIL are the scanner's words. INFO marks the one check the scanner reports without scoring. The fix column points at the finding that moves the check, or says why the check stays as it is.

| Category | Check | Reading | What the scanner saw | Fix |
| --- | --- | --- | --- | --- |
| Discoverability | robotsTxt | PASS | /robots.txt exists and parses. One wildcard group. | F5 changes its content, the check stays green |
| Discoverability | sitemap | PASS | /sitemap.xml exists and parses, 14 URLs. | F4, a manual finding, the check stays green |
| Discoverability | linkHeaders | FAIL | No Link header on any response. | F3 |
| Discoverability | dnsAid | FAIL | No _index._agents record under the domain, DNSSEC not enabled. | F7 |
| Content | markdownNegotiation | FAIL | Accept: text/markdown returns text/html, 212 kB on the home page. | F2 |
| Bot access control | robotsTxtAiRules | FAIL | No AI crawler named in robots.txt. | F5 |
| Bot access control | contentSignals | FAIL | No Content-Signal line in robots.txt. | F5 |
| Bot access control | webBotAuth | INFO | No Web Bot Auth directory. Informational, not scored. | None. The company operates no bots that would sign requests |
| API, auth, MCP and A2A | apiCatalog | FAIL | /.well-known/api-catalog returns the HTML 404 page. | F6 |
| API, auth, MCP and A2A | oauthDiscovery | FAIL | No /.well-known/oauth-authorization-server or openid-configuration. | Waits, see F6 |
| API, auth, MCP and A2A | oauthProtectedResource | FAIL | No /.well-known/oauth-protected-resource. | Waits, see F6 |
| API, auth, MCP and A2A | authMd | FAIL | No /auth.md and no agent_auth metadata. | Waits, see F6 |
| API, auth, MCP and A2A | mcpServerCard | FAIL | No /.well-known/mcp/server-card.json. | Waits, see F6 |
| API, auth, MCP and A2A | a2aAgentCard | FAIL | No /.well-known/agent-card.json. | Waits, see F6 |
| API, auth, MCP and A2A | agentSkills | FAIL | No /.well-known/agent-skills/index.json. | Waits, see F6 |
| API, auth, MCP and A2A | webMcp | FAIL | No navigator.modelContext tools on the home page. | Waits, see F6 |
| API, auth, MCP and A2A | ard | FAIL | No capability manifest at the well-known path. | Waits, see F6 |
| Commerce | x402 | FAIL | No 402 challenge on any route. | Stays red on purpose, F8 |
| Commerce | mpp | FAIL | No payment discovery document. | Stays red on purpose, F8 |
| Commerce | ucp | FAIL | No /.well-known/ucp. | Stays red on purpose, F8 |
| Commerce | acp | FAIL | No ACP discovery document. | Stays red on purpose, F8 |
| Commerce | ap2 | FAIL | No AP2 declaration. | Stays red on purpose, F8 |

Category totals: Discoverability 2 of 4, Content 0 of 1, Bot access control 0 of 2, API, auth, MCP and A2A 0 of 9, Commerce 0 of 5. Overall 2 of 21 scored checks, Level 1 of 5.

After the seven fixes below: Discoverability 4 of 4, Content 1 of 1, Bot access control 2 of 2, API, auth, MCP and A2A 1 of 9, Commerce 0 of 5. Overall 8 of 21, and the report does not translate that into a level, because the level on the retest day depends on the check set the scanner runs that day.

## Manual review

The surfaces the scanner does not score, read by hand on 2026-09-03 and 2026-09-04.

| Surface | Reading | Finding |
| --- | --- | --- |
| First response as a bot | Every page returns its full HTML on the first response. No script shell, no prerender. | No finding. The content is there, it is only expensive to read. |
| JSON-LD, product pages | Product node on all 138 pages: price 0.00, priceCurrency EUR, availability InStock. | F1 |
| JSON-LD, home and category pages | Organization node with name and logo, no address, no taxID, no sameAs. WebSite node present. No BreadcrumbList. | Recorded, no fix in this round. Completeness, not correctness. |
| Head metadata and Open Graph | Title and description present on all seven pages read. og:image missing on the five product pages. | Recorded, no fix in this round. |
| HTTP response headers | Content-Type correct. No Link, no RateLimit-Policy, no security headers except HSTS. | F3 adds the Link relations. Security headers are in the internet.nl reading below. |
| /.well-known/ | Empty. Every path under it returns the HTML 404 page with status 200. | F3, F6 and F7 populate it. The soft 404 is F6's first line. |
| robots.txt | The CMS default. One wildcard group, Disallow: /wp-admin/, no Sitemap line, no AI crawler, no Content-Signal. | F5 |
| sitemap.xml | 14 URLs. The front page, eleven content pages and two template pages titled Sample Page and Privacy Policy Draft. No product page. | F4 |
| ai.txt and llms.txt | Neither exists. | F3 publishes llms.txt. ai.txt is not published: the norm it followed has merged into robots.txt Content Signals. |
| REST API | /wp-json/wc/store/v1/products answers publicly with the catalog, price fields empty, purchasable true. | F1 corrects the data, F6 declares the API. |

## AI visibility today

Fifteen questions, four assistants, one anonymous run per question on 2026-09-04, 60 answers in all. The question set is fixed so that the same run can be repeated after the fixes and the two runs compared.

| Question group | Questions | Answers | Northwind named | Correct where named | What the assistants did instead |
| --- | --- | --- | --- | --- | --- |
| Category, no company name. "Where can a Finnish workshop buy DIN 933 bolts in bulk online" and eleven like it | 12 | 48 | 0 | Not applicable | Named three national distributors and two marketplaces. Two answers cited a competitor's price list page as markdown. |
| Company by name. "What does Northwind Fasteners sell" and two like it | 3 | 12 | 12 | 9 | Two answers gave a Tampere address the company left in 2023. One answer said the catalog is free, citing the structured data F1 corrects. |

What this measures. Whether an assistant names the company when a buyer describes the need, and whether it gets the facts right when it does. It does not measure ranking, and nothing in this report predicts how the run reads after the fixes. The same 15 questions are run again at the retest, and the two tables are printed side by side.

## Published security scans

Run on 2026-09-04, recorded so that the client can re-run them without turva.dev.

| Scan | Reading | What it means for agents |
| --- | --- | --- |
| internet.nl website test | 64 of 100. IPv6 absent, DNSSEC absent, HTTPS configuration passes, security headers partial. | DNSSEC is a prerequisite of the dnsAid check, so F7 moves this reading too. |
| internet.nl mail test | 55 of 100. SPF present, DKIM present, DMARC policy none. | Not an agent surface. Recorded because a buyer checks it. |
| Hardenize | 17 of 24 categories passed. CAA, DNSSEC, HSTS preload, CSP, Referrer-Policy, security.txt and cookies did not. | security.txt is a five line file the same edge worker serves. It is listed under F3 as a same-day addition. |

## Findings, in fix order

Eight findings. Each carries the evidence as read, what it costs the company, the change, who does it and roughly how long, and the test that proves it done. The order is by impact on a buyer first and on the score second, and the effort figures are estimates scoped to these findings, not a quote.

## F1. Every product page publishes a price of 0 and an availability of InStock

**Category.** Structured data. Manual review, not scored.

**Evidence.** GET /products/din-933-m12x40-a2/ on 2026-09-03 returns a JSON-LD Product node with "price": "0.00", "priceCurrency": "EUR" and "availability": "https://schema.org/InStock". The visible page shows 0,42 EUR per piece and a lead time of six weeks. The same node shape appears on all 138 product pages, checked by fetching every product URL from the REST API and reading the price field of each. The API itself, /wp-json/wc/store/v1/products, returns "price": "" and "is_purchasable": true for the same products.

**Impact.** No scanner points, and the highest impact in this report. An agent that trusts the structured data tells a buyer the whole catalog is free and in stock, and one of the 12 by-name answers on 2026-09-04 already did. Wrong data is worse than missing data: missing data makes an agent guess, wrong data makes it confident.

**Change.** Feed the Product node from the same price and stock fields the page renders, and map the six week lead time to a PreOrder or BackOrder availability instead of InStock. This is a data mapping in the catalog plugin, not new markup. Until it is fixed, removing the price and availability fields is the safer state, and that removal is a one line template change the company can make the same day.

**Owner and effort.** The surface belongs to the company's web agency, which owns the catalog plugin configuration, and the permanent fix is theirs: about two hours. If turva.dev implements the list, the two fields are corrected at the edge on the way through, from the same price and stock fields the page renders, so the served data is right from the day the worker goes live, and the plugin mapping is still corrected by the agency for the origin itself. The report names both and the acceptance test covers both.

**Acceptance test.** Read the JSON-LD of any product page next to the page. The price and the availability match what the page shows. Repeat for three products with a lead time. No scanner check flips, and the manual review closes.

**Guide.** [JSON-LD and structured data for agents](/guides/json-ld-structured-data).

## F2. Serve markdown next to HTML

**Category.** Content accessibility. Scored check markdownNegotiation.

**Evidence.** GET / with Accept: text/markdown on 2026-09-03 returns Content-Type text/html and a 212 kB body. The same request to /products/ and to a product page returns HTML of 340 kB and 188 kB. No .md address exists for any page.

**Impact.** One scored check, and the largest token saving on the site. The home page is 212 kB as HTML and about 9 kB as markdown, so an agent that reads it as HTML spends its budget on markup and truncates the page before the catalog link.

**Change.** Put an edge worker in front of the origin that answers a text/markdown request with the markdown form of the page at the same address, and publishes each page at its .md address as well. The origin is not touched. The worker converts the rendered HTML on the way through and caches the result per URL.

**Owner and effort.** turva.dev or the company's developer, at the edge. About three hours including the cache rules. This is the worker every other edge finding in this report also lives in, so its cost is paid once.

**Acceptance test.** curl -H "Accept: text/markdown" https://northwind-fasteners.example/ returns Content-Type: text/markdown and a body that starts with the page title as a heading. markdownNegotiation reads PASS on the next scan.

**Guide.** [Serving markdown to agents](/guides/markdown-for-agents).

## F3. Publish llms.txt and announce it in the Link header

**Category.** Discoverability. Scored check linkHeaders.

**Evidence.** GET /llms.txt on 2026-09-03 returns the HTML 404 page with status 200. No response on the site carries a Link header. GET /.well-known/security.txt returns the same soft 404.

**Impact.** One scored check, and the file agents fetch first when they want to know what a site is about. Without it an agent has the navigation menu and nothing else, and the navigation menu does not mention the catalog API or the delivery terms.

**Change.** Write /llms.txt by hand: the company name, a four line summary, and the pages that matter grouped as products, delivery terms, technical documents and contact, each as an absolute link to the page's markdown form from F2. Announce it with Link: rel="describedby" on every response and add rel="alternate" type="text/markdown" pointing at the page's own .md twin. Serve /.well-known/security.txt from the same worker with a contact address and an expiry date, which closes one Hardenize category the same day.

**Owner and effort.** turva.dev or the company's developer, at the edge. About 90 minutes. The content of llms.txt is reviewed by the company before it goes live, because it is the company's own description of itself.

**Acceptance test.** linkHeaders reads PASS on the next scan. The free validator at [turva.dev/llms-txt-validator](/llms-txt-validator) reads the file as valid with every link resolving. GET /.well-known/security.txt returns text/plain with status 200.

**Guides.** [llms.txt explained](/guides/llms-txt) and [Response headers that help agents](/guides/response-headers-for-agents).

## F4. The sitemap lists two template pages and misses the catalog

**Category.** Discoverability. Manual review, not scored. The sitemap check passes and stays green.

**Evidence.** GET /sitemap.xml on 2026-09-03 lists 14 URLs: the front page, eleven content pages and two CMS template pages titled Sample Page and Privacy Policy Draft. None of the 138 product URLs is in it. robots.txt carries no Sitemap line, so an agent that starts from robots.txt does not find the sitemap at all.

**Impact.** No scanner points. An agent that follows the rules gets a list of 14 pages to read and never learns that the catalog exists. The two template pages are also indexed by search engines today.

**Change.** Let the catalog plugin generate a product sitemap, reference it from a sitemap index, remove the two template pages from the site or from the sitemap, and add one Sitemap line to robots.txt. Four settings, no code.

**Owner and effort.** The surface belongs to the company's web agency, and the four settings are theirs: about half an hour. If turva.dev implements the list, the edge serves a product sitemap generated from the REST API and a sitemap index in front of the CMS one, and the robots.txt line comes with F5, so the acceptance test passes without waiting for the agency.

**Acceptance test.** The sitemap index references a product sitemap that lists every product URL, no template page appears, and robots.txt names the index. The scored check stays green either way, which is why this is a manual finding.

**Guide.** [Sitemaps, robots.txt and agents](/guides/sitemaps-and-robots-for-agents).

## F5. Name the AI crawlers and declare Content Signals in robots.txt

**Category.** Bot access control. Scored checks robotsTxtAiRules and contentSignals.

**Evidence.** /robots.txt on 2026-09-03 is the CMS default: User-agent: *, Disallow: /wp-admin/, Allow: /wp-admin/admin-ajax.php. No AI crawler is named and no Content-Signal line exists.

**Impact.** Two scored checks. Today the file says nothing about AI agents, so every assistant guesses, and the guess is not always in the site's favour: one assistant on 2026-09-04 declined to cite the site at all and cited a distributor's copy of the same product data instead.

**Change.** Add named groups for the crawlers the company wants to allow, and one Content-Signal line that states search yes, ai-input yes, ai-train no, or whichever preference the company holds. The line is a stated preference and not an enforcement mechanism, and the report says so where it appears. The company decides the preference, the report only records what the file says today.

**Owner and effort.** The company decides, the edge worker serves the file. About half an hour once the preference is decided.

**Acceptance test.** robotsTxtAiRules and contentSignals read PASS on the next scan, and the file names the crawlers the company chose.

**Guide.** [Sitemaps, robots.txt and agents](/guides/sitemaps-and-robots-for-agents).

## F6. Tell agents that the REST API exists

**Category.** API, auth, MCP and A2A. Scored check apiCatalog.

**Evidence.** The site runs a public read-only REST API at /wp-json/ with the product catalog behind it at /wp-json/wc/store/v1/products, and no discovery file names it. GET /.well-known/api-catalog on 2026-09-03 returns the HTML 404 page with status 200, as does every path under /.well-known/. The scanner reads apiCatalog as failing along with the eight other checks in the category.

**Impact.** One scored check now, and the cheapest step in the category. An agent that finds the API reads the catalog as data instead of scraping HTML. The soft 404 under /.well-known/ has a cost of its own: an agent that probes for a manifest receives a 200 with an HTML body and has to parse it to learn there is nothing there.

**Change.** Publish /.well-known/api-catalog, one JSON linkset that names the /wp-json/ base URL and its description, with the content type application/linkset+json. Make every other path under /.well-known/ return a real 404. The other eight checks in the category need an authentication story or an MCP server and are not worth declaring until one exists: a server card that points at no server is a false claim, and this report does not recommend one.

**Owner and effort.** turva.dev or the company's developer, at the edge. About half an hour.

**Acceptance test.** apiCatalog reads PASS on the next scan. The category reads 1 of 9, and the retest report says which eight are left and why they wait. GET /.well-known/nothing returns 404.

**Guide.** [The /.well-known directory for agents](/guides/well-known-for-agents).

## F7. Publish a DNS-AID record once the discovery files exist

**Category.** Discoverability. Scored check dnsAid.

**Evidence.** No _index._agents HTTPS record exists under northwind-fasteners.example, and DNSSEC is not enabled at the registrar, which internet.nl also reports.

**Impact.** One scored check. This is the check that needs the company's DNS rather than the edge worker, which is why it is last among the scored fixes. DNSSEC also moves the internet.nl website reading.

**Change.** After the files above are live, add the _index._agents HTTPS record pointing at the site and enable DNSSEC at the registrar. Both are DNS changes the company's own IT does, and the report carries the exact record in its appendix.

**Owner and effort.** The surface belongs to the company's IT, at the registrar. About half an hour, plus the DNSSEC propagation wait. If turva.dev implements the list, the access arranged in writing before the work covers the DNS zone as well, and both records are added from the exact text in the appendix. Without that access this is the one item that stays with the company, and the report says so before the work starts.

**Acceptance test.** dnsAid reads PASS on the next scan, once DNSSEC validates. internet.nl website test shows DNSSEC as passing.

**Guide.** [The /.well-known directory for agents](/guides/well-known-for-agents), which covers the discovery index the record points at.

## F8. Declare no agent commerce surface until a checkout can back it

**Category.** Commerce. Scored checks x402, mpp, ucp, acp and ap2.

**Evidence.** The store checks out through a browser form with a card payment page. None of the five agent commerce surfaces the scanner reads is declared: an x402 payment challenge, an MPP payment discovery document, a UCP profile, an ACP discovery document or an AP2 declaration. All five commerce checks read FAIL.

**Impact.** Five scored checks, and none of them is worth flipping this quarter. A commerce declaration that points at a checkout an agent cannot complete is a false claim, and the scanner cannot tell the difference between a declaration and a working checkout.

**Change.** No change now. When the company decides that agents may buy, the first honest step is an ACP discovery document whose checkout session returns not_ready_for_payment with a message, which is real and scores. Everything else follows a payment decision, not a readiness one.

**Owner and effort.** The company's management, as a decision. No hours in this round.

**Acceptance test.** The five checks stay red on the next scan, on purpose, and the retest report repeats this entry so that nobody reads the red as an oversight.

**Guides.** [Agent commerce discovery](/guides/agent-commerce-discovery) and [Agentic commerce readiness](/guides/agentic-commerce-readiness).

## Fix order and effort

| Order | Finding | Checks moved | Owner | Effort estimate |
| --- | --- | --- | --- | --- |
| 1 | F1 structured data | None, manual | Web agency owns the plugin. Edge corrects the served fields | 2 hours |
| 2 | F2 markdown | markdownNegotiation | Edge | 3 hours |
| 3 | F3 llms.txt, Link header, security.txt | linkHeaders | Edge, content reviewed by the company | 90 minutes |
| 4 | F4 sitemap content | None, manual | Web agency owns the settings. Edge serves the product sitemap | Half an hour |
| 5 | F5 robots.txt | robotsTxtAiRules, contentSignals | Company decides, edge serves | Half an hour |
| 6 | F6 api-catalog and real 404s | apiCatalog | Edge | Half an hour |
| 7 | F7 DNS-AID and DNSSEC | dnsAid | Company IT owns the zone. Done with DNS access arranged | Half an hour plus propagation |
| 8 | F8 commerce | None, on purpose | Management decision | 0 |

Total for F1 to F7: about eight and a half hours, which is the one implementation day the services page describes. The figure is an estimate scoped to these findings.

## What happens next

Three routes, and the report is written so that any of them works.

- The company's team does the work from this report. Every finding carries its change and its acceptance test, and the guides linked above carry the patterns.
- turva.dev implements exactly the fixes this report lists for the fixed price on the services page, bought together with the audit. That price needs an edge runtime in front of the origin where the fixes are applied and the access to deploy there, plus any other access a listed fix needs, here the DNS zone for F7, all arranged in writing before the work starts. With those in place every one of F1 to F7 is implemented for the fixed price: F2, F3, F5 and F6 live in the worker, F1 and F4 are corrected at the edge while the agency fixes the origin, and F7 is done with the DNS access that the written arrangement includes. What the company still does itself is name the crawler preference for F5, review the llms.txt text and let its agency correct the plugin mapping behind F1.
- Nothing is done, and the report stands as a dated record of where the site was on 2026-09-03.

In every case the retest is the same, and it is included in the audit price: once within 30 days of this report, so by 2026-10-08, on the day the company names, the scanner is run again with the same profile, the 15 questions are put to the same four assistants, and the two readings are printed next to the ones above. One round of written follow-up questions is open until 2026-09-22.

## What this report is not

It is not a penetration test, a certification, an SEO audit or a promise of ranking on any AI platform. It reads what the site publishes and records what four assistants said on one day. It does not read the organisation's readiness to adopt agents, which is a different question that often goes by the same name.

## About this sample

Every figure on this page is invented. The check names, the categories and the statuses are the scanner's real vocabulary as it stood on 2026-09-03, so that the sample shows how a real report reads, and the site, the readings, the assistants' answers and the security scores are fiction. A real report carries the raw scanner output, the request and response logs and the 60 AI answers as an appendix.

The audit is described on the [services page](/services). To start one, [email info@turva.dev](mailto:info@turva.dev?subject=Agent-readiness%20audit&body=Site%20or%20API%20URL%3A%20%0AWhat%20the%20audit%20should%20answer%3A%20%0A) with the site or API URL and what the audit should answer. The Shopify agent storefront check has its own [sample report](/samples/shopify-agent-storefront-check).
