<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Erik Rekola</title>
    <description>The latest articles on DEV Community by Erik Rekola (@erekola).</description>
    <link>https://dev.to/erekola</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3994164%2F3ba59e95-e771-458f-80bf-209fc1acd1b0.jpg</url>
      <title>DEV Community: Erik Rekola</title>
      <link>https://dev.to/erekola</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/erekola"/>
    <language>en</language>
    <item>
      <title>I thought it was a small job</title>
      <dc:creator>Erik Rekola</dc:creator>
      <pubDate>Sun, 16 Aug 2026 20:55:55 +0000</pubDate>
      <link>https://dev.to/turva-dev/i-thought-it-was-a-small-job-2md7</link>
      <guid>https://dev.to/turva-dev/i-thought-it-was-a-small-job-2md7</guid>
      <description>&lt;p&gt;I set out to read my own workspace file by file. The idea was that it would take an evening. It took seven days, and it produced 367 findings across nine packages.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was actually read
&lt;/h2&gt;

&lt;p&gt;The workspace holds 2 307 text files and 28 826 789 bytes, which is roughly 8 million tokens. Another 441 files are binaries such as images and PDFs. They were counted but not read line by line, because reading a JPEG line by line means nothing. The nine packages split that by surface: the Worker source, the rest of the site repo, the MCP server and the validator package, the tools, the two large decision logs, the knowledge base, the agent memory, the docs and cross-post trees, and the scratch folder.&lt;/p&gt;

&lt;p&gt;Seven days of that produced 69 recorded decisions and 50 new entries in the trap log. It produced no invoice, no proposal and no sent message.&lt;/p&gt;

&lt;p&gt;That is the honest ledger. A week of work with nothing billable in it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it bought
&lt;/h2&gt;

&lt;p&gt;The base is now audited file by file, and it is not audited by me remembering that I checked it. Seven deterministic gates run on my machine as editor hooks and block the action rather than warn about it. They stop the edit tool in this workspace, git in the agent shell, generated files written to the workspace root, and repo edits made before the trap log has been read. Two of them run after a write and check for NUL bytes, changed line endings and a size collapse.&lt;/p&gt;

&lt;p&gt;Twenty-three gate scripts sit in the toolchain and run on demand or on ship. Three of them run on every release, and between them they perform 314 mechanical checks with no network and 567 when the live URLs and the manifest signatures are included. None of those numbers is a target. They are just what the scripts count when they run.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a line-by-line read finds that a scan does not
&lt;/h2&gt;

&lt;p&gt;One measurement was written into two documents from the same run, one saying the worst overflow was 458 pixels and the other 514. Only 514 is internally consistent with the 139 pixel figure both texts also carry, so one of them had been wrong since the day it was written, and no gate could see it because both numbers were plausible.&lt;/p&gt;

&lt;p&gt;A dependency update moved a package to a new version, and the allow list that permits that package to run its install script was pinned to the old version by name. The install script stayed blocked. Nothing broke, which is why it would have kept not breaking until something did.&lt;/p&gt;

&lt;p&gt;A grid track refused to shrink below 412 pixels inside a 336 pixel row, because &lt;code&gt;1fr&lt;/code&gt; means &lt;code&gt;minmax(auto, 1fr)&lt;/code&gt; and &lt;code&gt;auto&lt;/code&gt; resolves to the widest unbreakable child. That one pushed the home page sideways at 200 percent text zoom, and I fixed the wrong cause three times before measuring instead of guessing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this does not prove
&lt;/h2&gt;

&lt;p&gt;It does not prove the workspace is correct. It proves that 367 specific things were read and classified. Each one was then either fixed or written down as a decision with a reason. A gate that is green tells you what it checked, and the useful question is always what it did not check.&lt;/p&gt;

&lt;p&gt;It also does not prove the week was worth it. That depends on whether the next audit I sell is better because of it, and I do not know that yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/measurement-led-agent-readiness" rel="noopener noreferrer"&gt;Measurement-led agent readiness&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/blog/checks-that-pass-for-the-wrong-reason" rel="noopener noreferrer"&gt;The checks that pass for the wrong reason&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/blog/my-gate-could-not-see-a-sixth" rel="noopener noreferrer"&gt;My gate could not see a sixth&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://turva.dev/blog/i-thought-it-was-a-small-job" rel="noopener noreferrer"&gt;https://turva.dev/blog/i-thought-it-was-a-small-job&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>webdev</category>
      <category>testing</category>
    </item>
    <item>
      <title>AI agent use cases</title>
      <dc:creator>Erik Rekola</dc:creator>
      <pubDate>Fri, 07 Aug 2026 09:00:00 +0000</pubDate>
      <link>https://dev.to/turva-dev/ai-agent-use-cases-4g6</link>
      <guid>https://dev.to/turva-dev/ai-agent-use-cases-4g6</guid>
      <description>&lt;p&gt;An AI agent is useful wherever data moves and a decision follows. It reads a machine-readable surface, decides inside the limits it was given, and acts on what it finds. The cases below are grouped by what the agent does, not by industry, because the same pattern repeats across all of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Commerce and transactions
&lt;/h2&gt;

&lt;p&gt;An agent reads a product catalog, weighs the options against a buyer's constraints, and completes a checkout through a protocol rather than a form. The work is making the offer, the price, and the checkout legible and reliable enough for the agent to finish without a human in the loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring and response
&lt;/h2&gt;

&lt;p&gt;An agent watches an API, a feed, or a system and acts the moment a threshold is crossed, with no one having to be watching. The work is a clean data path so the signal arrives in time, and a tight envelope so the agent takes only the actions it is allowed to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Field and frontline support
&lt;/h2&gt;

&lt;p&gt;An agent guides a person doing physical work, drawing on the same data an expert would and answering from it in the moment. The agent extends the expert's reach instead of standing in for the person at the far end.&lt;/p&gt;

&lt;h2&gt;
  
  
  Operations under bad connectivity
&lt;/h2&gt;

&lt;p&gt;An agent runs a remote system over a link that drops, holding its last safe state and resuming cleanly when data returns. This is where the data path matters most, because one lost packet can stall every decision queued behind it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Back-office and data work
&lt;/h2&gt;

&lt;p&gt;An agent reconciles records across systems, flags only what does not match, and routes the rest. The value is consistency, a decision the agent makes the same way every time, with a trail you can audit afterwards.&lt;/p&gt;

&lt;h2&gt;
  
  
  Autonomy at the edge
&lt;/h2&gt;

&lt;p&gt;An agent makes a time-critical call locally, where the round trip to a human is too slow to matter. The decision has to sit inside rules agreed in advance, because there is no one to ask. The fields that already live with hard time limits learned that discipline early.&lt;/p&gt;

&lt;h2&gt;
  
  
  The common thread
&lt;/h2&gt;

&lt;p&gt;These are examples, not a closed list. The same discipline carries from one case to the next. The question is rarely whether an agent could do the work. It is whether the data reaching it is clean and the envelope around it is set, because those two decide whether the agent makes the right call or a fast wrong one.&lt;/p&gt;

&lt;p&gt;If you want an agent to do one of these reliably, or to measure how ready your site or API is for agents in the first place, contact &lt;a href="mailto:info@turva.dev"&gt;info@turva.dev&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/agentic-commerce-readiness" rel="noopener noreferrer"&gt;Agentic commerce readiness&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/letting-agents-act-on-data" rel="noopener noreferrer"&gt;Letting agents act on data: the decision envelope&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/agent-readiness-audit" rel="noopener noreferrer"&gt;What an agent-readiness audit is&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://turva.dev/guides/ai-agent-use-cases" rel="noopener noreferrer"&gt;https://turva.dev/guides/ai-agent-use-cases&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Common agent-readiness gaps on marketing sites</title>
      <dc:creator>Erik Rekola</dc:creator>
      <pubDate>Thu, 06 Aug 2026 09:00:00 +0000</pubDate>
      <link>https://dev.to/turva-dev/common-agent-readiness-gaps-on-marketing-sites-4l1e</link>
      <guid>https://dev.to/turva-dev/common-agent-readiness-gaps-on-marketing-sites-4l1e</guid>
      <description>&lt;p&gt;Most marketing sites are strong for people and weak for agents, and the gaps are predictable. A readiness review tends to find the same handful of misses, each of which quietly removes the site from an agent's view.&lt;/p&gt;

&lt;p&gt;The first is rendering. A site that builds its content with JavaScript returns an empty shell to an agent, so the content never arrives in the first response. The second is discovery. No llms.txt and a thin or missing sitemap, so an agent has nothing to read but rendered pages. The third is cost. Only HTML is offered, with no markdown form, so an agent spends its budget on markup and truncates the page.&lt;/p&gt;

&lt;p&gt;Beyond those, capability is usually undeclared. The site may have an API or a useful action, but with no server card or OAuth discovery, an agent cannot find or use it. Structured data is often missing too, so prices and facts are left for the agent to infer from layout.&lt;/p&gt;

&lt;p&gt;None of these are hard to fix, and that is the point. The work is mostly at the edge and in a few small files, and the result shows up immediately in a scanner. A site does not have to rebuild to become legible to agents, it has to publish what agents already look for.&lt;/p&gt;

&lt;p&gt;turva.dev runs this exact review and reports each gap with a concrete fix. For an audit, contact &lt;a href="mailto:info@turva.dev"&gt;info@turva.dev&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/agent-readiness-audit" rel="noopener noreferrer"&gt;What an agent-readiness audit is&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/prerendering-for-agents" rel="noopener noreferrer"&gt;Prerendering and why agents see empty pages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/choosing-an-agent-readiness-audit" rel="noopener noreferrer"&gt;Choosing an agent-readiness audit&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://turva.dev/guides/agent-readiness-gaps" rel="noopener noreferrer"&gt;https://turva.dev/guides/agent-readiness-gaps&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>webdev</category>
      <category>seo</category>
    </item>
    <item>
      <title>Why agent-readiness should be measured, not asserted</title>
      <dc:creator>Erik Rekola</dc:creator>
      <pubDate>Wed, 05 Aug 2026 09:00:00 +0000</pubDate>
      <link>https://dev.to/turva-dev/why-agent-readiness-should-be-measured-not-asserted-3o3c</link>
      <guid>https://dev.to/turva-dev/why-agent-readiness-should-be-measured-not-asserted-3o3c</guid>
      <description>&lt;p&gt;Agent-readiness is a property you can measure, so it should be measured rather than claimed. A checklist that a team fills in by hand records intentions. An independent scanner records what an agent actually finds when it reads the site, and those two often disagree.&lt;/p&gt;

&lt;p&gt;The difference shows up the moment something changes. A header gets dropped in a deploy, or a manifest starts returning the wrong content type. A self-assessment still reads as done, because nobody re-ticked the box. A scan reads the live site and the category drops, which is the only signal that matches what an agent experiences.&lt;/p&gt;

&lt;p&gt;Measurement also makes a result legible to a buyer. A claim that a site is agent-ready is an assertion. A score from an independent scanner, with a category breakdown and a date, is evidence that can be checked. The honest version of the claim is the number, and the number can be re-run by anyone.&lt;/p&gt;

&lt;p&gt;This is the standard turva.dev applies to its own site and to client sites. An audit reports the exact checks that pass or fail, each failure comes with a concrete fix, and the next scan reads higher in the categories the report named. Measured by an independent scanner, turva.dev reaches 100/100 and Level 5, Agent-Native, on isitagentready.com. Measured 2026-07-28.&lt;/p&gt;

&lt;p&gt;For an audit that reports measured results rather than a checklist, contact &lt;a href="mailto:info@turva.dev"&gt;info@turva.dev&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/agent-readiness-audit" rel="noopener noreferrer"&gt;What an agent-readiness audit is&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/choosing-an-agent-readiness-audit" rel="noopener noreferrer"&gt;Choosing an agent-readiness audit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/agent-readiness-gaps" rel="noopener noreferrer"&gt;Common agent-readiness gaps on marketing sites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/letting-agents-act-on-data" rel="noopener noreferrer"&gt;Letting agents act on data: the decision envelope&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>webdev</category>
      <category>seo</category>
    </item>
    <item>
      <title>My gate could not see a sixth</title>
      <dc:creator>Erik Rekola</dc:creator>
      <pubDate>Tue, 04 Aug 2026 11:36:22 +0000</pubDate>
      <link>https://dev.to/turva-dev/my-gate-could-not-see-a-sixth-428d</link>
      <guid>https://dev.to/turva-dev/my-gate-could-not-see-a-sixth-428d</guid>
      <description>&lt;p&gt;I built a gate that checks that the five agent readiness categories are declared the same way on six surfaces. It went green and it stayed green. 79 static checks with no failures, 212 checks against the live site with no failures, and 53 mutation cases across three runners that all reported no holes. Then I had a hostile reader go through the gate itself, and it came back with three holes. All three were one defect in three shapes.&lt;/p&gt;

&lt;p&gt;The two posts before this one came at the same thing from other sides. The first was about a check that keeps passing after it has stopped measuring the right thing. The second was about a red reading that turned out to be about my own client rather than the server. This one is neither. The gate measured what it measured correctly, and it was blind by construction to everything it did not measure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gate asked the wrong question
&lt;/h2&gt;

&lt;p&gt;On every surface the gate asked whether these five were present. It never asked what else was there. That is the whole finding, and it is worth putting plainly. A check that asks whether these five are present is not a check of the set. It is a check of a list you wrote yourself, and it is blind to every element you did not know to write down.&lt;/p&gt;

&lt;p&gt;A sixth category went through three of the four static surfaces untouched. I measured each one by running it rather than by reading the code, because reading my own code is how I ended up here. Add a sixth category to the surface, run the gate, read the output. RESULT: OK, zero failures, sixth category sitting on the page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three shapes of one defect
&lt;/h2&gt;

&lt;p&gt;The first was a filter that ran before the count. The table rows in the README are collected, filtered down to the ones that resolve to a known category, and only then counted. A row whose name the fact file does not recognise disappeared in the filter, so the counter never went up. The filter is there to keep unrelated rows out of the count, and it kept the finding out with them.&lt;/p&gt;

&lt;p&gt;The second was a span that ends on the last element's own sentence. The gate lifts a paragraph out of the audit guide by anchoring on the first category and the last one, and the closing anchor is commerce's own sentence. That is exactly where a sixth gets appended. Anything added after it falls outside the span the gate is reading.&lt;/p&gt;

&lt;p&gt;The third was a substring test standing in for an equality test. One surface carries a twin sentence built entirely from the fact file, and the gate compared the page against it with includes. A sixth appended to the end of the list was caught. A sixth inserted at the front was not, because the string the gate wanted was still in there. It just was not the whole of it any more.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fourth one was in the tool doing the checking
&lt;/h2&gt;

&lt;p&gt;There was a fourth, and it sat in the thing I was using to prove the other three. One of the mutation runners reported no holes across ten cases. Seven of those ten had come back with applied=0 and HTTP 429, which means the rate limit refused the request and the mutation was never in place at all. The runner counted a case that never ran as a case with nothing wrong. It read a red run as a pass.&lt;/p&gt;

&lt;p&gt;That is the same defect one level up, and it is the one I would rather report than the three below it. The runner asked whether the failures it knew to look for had appeared, and it never asked whether the run had happened. A tool that certifies the other tools is where this class of mistake does the most damage, and a green summary sitting on top of seven refused requests is exactly what it looks like from the outside.&lt;/p&gt;

&lt;p&gt;The same blindness turned up in a different gate a few hours later. Cases aimed at an agent skills file were matching any agent skills line instead of the one they named, so a digest check stood in for a content check and one real hole went through. The mutation had put a wrong business identifier in the declared field. The check passed because the correct identifier still appeared elsewhere in the same file, inside a registry link, and the check was searching the file rather than reading the field.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a set check has to do instead
&lt;/h2&gt;

&lt;p&gt;A check that watches a set must not search. Searching answers a question about one string at a time, and a set is not a bag of strings you happened to remember. The check has to enumerate what the surface actually contains, then compare that enumeration against the set. Three conditions, all of them at once.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The enumeration and the set are the same length.&lt;/li&gt;
&lt;li&gt;Every element found on the surface resolves to a member of the set.&lt;/li&gt;
&lt;li&gt;No member of the set is resolved twice.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The third condition earns its place. Without it a surface can carry the right number of rows with one member listed twice and another missing entirely, and the first two conditions are still satisfied.&lt;/p&gt;

&lt;p&gt;Then the part my original code had backwards. Every element that does not resolve is a finding. In the gate I wrote, an unresolvable row was a row to skip, and it was a row to skip because the code had been written to answer whether the known five were present. The question shapes the data structure, and the data structure then makes the other question impossible to ask.&lt;/p&gt;

&lt;h2&gt;
  
  
  The version that transfers
&lt;/h2&gt;

&lt;p&gt;None of this is new and none of it is rare. Anyone who has written against a schema has met it under the name additionalProperties, and the repair is the same repair. The reportable part is not the class of defect. It is that three instances of it were sitting in my own code, in a gate I had negative tested, on a day it reported green three separate ways.&lt;/p&gt;

&lt;p&gt;The version that transfers to anyone with a test suite: your test asserts that the fields you remembered are present in the response. It does not ask what else is in the response. Add a field to the payload and the test stays green, which is correct behaviour for a compatibility check and wrong for anything you believe is watching a set. If a test's name says it validates a schema or a contract, open it and check whether it enumerates or whether it searches.&lt;/p&gt;

&lt;h2&gt;
  
  
  About the hostile read
&lt;/h2&gt;

&lt;p&gt;It was a tool of mine in a session of mine. It is not an audit and I am not going to call it one. It produced 17 observations, 13 of them carrying evidence and 4 flagged as suspicion, and I verified the four most serious by running them myself before I believed any of them. A second reader's finding is a lead. It becomes a measurement when you run it, and until you run it you have only swapped one reader's confidence for another's.&lt;/p&gt;

&lt;h2&gt;
  
  
  What these gates still do not read
&lt;/h2&gt;

&lt;p&gt;The gates watch what they watch. The category set is now compared across six surfaces where it used to be compared across two. Two things they do not touch at all: the markdown twins on pages other than the homepage, and the values inside the well-known manifests. Nothing here says the site cannot drift. It says that one specific way of drifting now costs a red run, and that I know the names of the next two.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://turva.dev/blog/checks-that-pass-for-the-wrong-reason" rel="noopener noreferrer"&gt;The checks that pass for the wrong reason&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/blog/red-reading-that-measured-my-own-client" rel="noopener noreferrer"&gt;A red reading that measured my own client&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/measurement-led-agent-readiness" rel="noopener noreferrer"&gt;Measurement-led agent readiness&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Sitemaps, robots.txt and agent access</title>
      <dc:creator>Erik Rekola</dc:creator>
      <pubDate>Tue, 04 Aug 2026 09:00:00 +0000</pubDate>
      <link>https://dev.to/turva-dev/sitemaps-robotstxt-and-agent-access-4ibm</link>
      <guid>https://dev.to/turva-dev/sitemaps-robotstxt-and-agent-access-4ibm</guid>
      <description>&lt;p&gt;robots.txt and the sitemap are the oldest machine-readable files on the web, and they still decide whether an agent is allowed in and what it can find. An agent reads robots.txt to learn the rules and the sitemap to learn the map, before it reads any page.&lt;/p&gt;

&lt;p&gt;robots.txt does two jobs for agents. It sets crawl rules, and it can name AI crawlers explicitly, so a site states whether it welcomes GPTBot and similar clients rather than leaving them to guess. A Content-Signal directive can go further and declare how content may be used, separating ordinary search from AI input and training, which gives a site granular control instead of an all-or-nothing block.&lt;/p&gt;

&lt;p&gt;The sitemap answers the other question, which is what exists. A complete sitemap lists every canonical URL with a last-modified date, so an agent can find the real pages without inferring them from navigation. A page that is not in the sitemap is a page an agent may never reach.&lt;/p&gt;

&lt;p&gt;Getting these wrong is quietly expensive. A robots.txt that blocks an AI crawler by accident removes a site from that assistant's answers. A stale sitemap hides new pages. The files are small and the fix is fast, which is why they are the first thing a readiness review checks.&lt;/p&gt;

&lt;p&gt;turva.dev declares AI bot rules and Content Signals in robots.txt and keeps a complete sitemap. For an audit of a site's crawl and access surface, contact &lt;a href="mailto:info@turva.dev"&gt;info@turva.dev&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/well-known-for-agents" rel="noopener noreferrer"&gt;The /.well-known directory for agents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/response-headers-for-agents" rel="noopener noreferrer"&gt;Response headers that help agents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/get-cited-by-ai-assistants" rel="noopener noreferrer"&gt;How to get your site cited by AI assistants&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://turva.dev/guides/sitemaps-and-robots-for-agents" rel="noopener noreferrer"&gt;https://turva.dev/guides/sitemaps-and-robots-for-agents&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>seo</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Prerendering and why agents see empty pages</title>
      <dc:creator>Erik Rekola</dc:creator>
      <pubDate>Mon, 03 Aug 2026 09:00:00 +0000</pubDate>
      <link>https://dev.to/turva-dev/prerendering-and-why-agents-see-empty-pages-maa</link>
      <guid>https://dev.to/turva-dev/prerendering-and-why-agents-see-empty-pages-maa</guid>
      <description>&lt;p&gt;Many sites render their content with JavaScript in the browser, which means the first response an agent receives is an almost empty shell. A person waits a moment and the page fills in. An agent that reads the raw response sees a loading state and little else, and it judges the site on that.&lt;/p&gt;

&lt;p&gt;This is the single most common reason a capable site is invisible to agents. The content exists, but it arrives after the agent has already read and moved on. Search crawlers have partly adapted to this over years. Many AI agents and fetchers have not, and they take the first response at face value.&lt;/p&gt;

&lt;p&gt;The fix is to serve the real content in the first response for clients that need it. Prerendering renders the page on the server or at the edge and returns finished HTML, so an agent reads the content immediately. A cleaner option for agents is to serve a markdown version of the page on request, which skips the rendering question entirely and costs a fraction of the tokens.&lt;/p&gt;

&lt;p&gt;The decision is not all or nothing. A site can keep its interactive experience for people and serve prerendered or markdown content to agents and bots, deciding by the request. On turva.dev that decision lives in a Cloudflare Worker that detects the client and returns the right form.&lt;/p&gt;

&lt;p&gt;For an audit of how a site renders for agents, contact &lt;a href="mailto:info@turva.dev"&gt;info@turva.dev&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/markdown-for-agents" rel="noopener noreferrer"&gt;Serving markdown to agents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/response-headers-for-agents" rel="noopener noreferrer"&gt;Response headers that help agents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/agent-readiness-gaps" rel="noopener noreferrer"&gt;Common agent-readiness gaps on marketing sites&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://turva.dev/guides/prerendering-for-agents" rel="noopener noreferrer"&gt;https://turva.dev/guides/prerendering-for-agents&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How agents authenticate</title>
      <dc:creator>Erik Rekola</dc:creator>
      <pubDate>Sun, 02 Aug 2026 09:00:00 +0000</pubDate>
      <link>https://dev.to/turva-dev/how-agents-authenticate-982</link>
      <guid>https://dev.to/turva-dev/how-agents-authenticate-982</guid>
      <description>&lt;p&gt;Agent authentication is how an automated client proves who it is and gains scoped access to a site, without a human logging in first. It is the step that turns a read-only agent into one that can act on a user's behalf, and it has to be discoverable or the agent cannot begin.&lt;/p&gt;

&lt;p&gt;The pattern follows existing standards. OAuth discovery at a well-known path tells an agent where to request access and what scopes exist. An authorization server and a protected resource description let the agent ask for a token tied to a specific permission rather than a blanket login. When a site also advertises an agent registration flow, an agent can register and claim access on a user's behalf without someone provisioning credentials by hand.&lt;/p&gt;

&lt;p&gt;The reason this matters is trust and blast radius. A site that exposes capability without scoped, discoverable auth either stays closed to agents or invites unsafe workarounds. Proper discovery lets an agent request the least access it needs, and lets the site grant capability without handing over a password the agent should never see.&lt;/p&gt;

&lt;p&gt;A short auth description, sometimes published as an auth.md, gives an agent a human-readable entry point to the same flow. Together with OAuth discovery it answers the agent's first question about any action, which is how do I get permission to do this safely.&lt;/p&gt;

&lt;p&gt;turva.dev publishes OAuth discovery, a protected resource description, and an agent registration entry point, and it never requests production credentials in an engagement. For an audit of a site's authentication surface, contact &lt;a href="mailto:info@turva.dev"&gt;info@turva.dev&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/well-known-for-agents" rel="noopener noreferrer"&gt;The /.well-known directory for agents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/mcp-server-card" rel="noopener noreferrer"&gt;MCP server cards explained&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/agents-json" rel="noopener noreferrer"&gt;What agents.json is&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/letting-agents-act-on-data" rel="noopener noreferrer"&gt;Letting agents act on data: the decision envelope&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://turva.dev/guides/agent-authentication" rel="noopener noreferrer"&gt;https://turva.dev/guides/agent-authentication&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>api</category>
      <category>webdev</category>
    </item>
    <item>
      <title>x402 and agent payments</title>
      <dc:creator>Erik Rekola</dc:creator>
      <pubDate>Sat, 01 Aug 2026 09:00:00 +0000</pubDate>
      <link>https://dev.to/turva-dev/x402-and-agent-payments-56ne</link>
      <guid>https://dev.to/turva-dev/x402-and-agent-payments-56ne</guid>
      <description>&lt;p&gt;x402 is a way for a site to ask an agent to pay before it returns a resource, using the long-reserved HTTP 402 Payment Required status. It lets an automated client discover a price, pay, and continue, without a human stepping in to enter card details.&lt;/p&gt;

&lt;p&gt;When an agent requests a paid resource, the server responds with 402 and a manifest that states what is being sold and how to pay. The agent reads the terms, signs a payment payload for a supported method, and retries the request with the payload attached; the server or its facilitator settles the payment. The transaction happens in the protocol, not in a checkout page built for human eyes.&lt;/p&gt;

&lt;p&gt;This matters because agent commerce is held back by payment, not by capability. An agent can find a product and compare options, then stall at a checkout flow designed for a person with a browser. A declared payment surface such as x402, paired with structured pricing in the page data, lets the agent complete the purchase the same way it completed the search.&lt;/p&gt;

&lt;p&gt;x402 belongs to a small family of agent payment standards, alongside authorization layers such as AP2. A site that publishes these signals tells agents that it is open for automated business, and in the case of the open peer pricelist model, it can be shown alongside other options at the moment an agent decides where to spend.&lt;/p&gt;

&lt;p&gt;turva.dev publishes an x402 endpoint and manifest. For an audit of a site's commerce surface for agents, contact &lt;a href="mailto:info@turva.dev"&gt;info@turva.dev&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/agent-commerce-discovery" rel="noopener noreferrer"&gt;Agent commerce discovery: A2A, AP2, and ACP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/well-known-for-agents" rel="noopener noreferrer"&gt;The /.well-known directory for agents&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://turva.dev/guides/x402-agent-payments" rel="noopener noreferrer"&gt;https://turva.dev/guides/x402-agent-payments&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>api</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Agentic commerce readiness: selling to AI shopping agents</title>
      <dc:creator>Erik Rekola</dc:creator>
      <pubDate>Fri, 31 Jul 2026 09:00:00 +0000</pubDate>
      <link>https://dev.to/turva-dev/agentic-commerce-readiness-selling-to-ai-shopping-agents-1g9p</link>
      <guid>https://dev.to/turva-dev/agentic-commerce-readiness-selling-to-ai-shopping-agents-1g9p</guid>
      <description>&lt;p&gt;An AI shopping agent buys on a person's behalf. It reads a catalog, compares options, and completes a checkout without a human filling in a form. Agentic commerce readiness is the work of making a site one of those agents can actually transact with, rather than one it skips because the path is unclear or blocked.&lt;/p&gt;

&lt;h2&gt;
  
  
  What an agent needs to buy
&lt;/h2&gt;

&lt;p&gt;An agent needs three things in machine-readable form. It needs to find the offer, with a price and currency it can parse rather than infer from a layout. It needs a checkout it can drive through a protocol, not a page built for a mouse. And it needs the purchase to behave predictably, so the same call produces the same result every time. A catalog that looks perfect to a person can still be opaque to an agent on all three counts.&lt;/p&gt;

&lt;h2&gt;
  
  
  The protocols in play
&lt;/h2&gt;

&lt;p&gt;Checkout is becoming a protocol rather than a page. Stripe and OpenAI shipped Instant Checkout inside ChatGPT in 2025. Google and Shopify introduced a universal commerce protocol in early 2026. The discovery layer is settling on a small set of standards. An A2A Agent Card describes the interface, AP2 authorizes agent payments, ACP carries the checkout, and x402 lets an agent meet a price with HTTP 402 and continue. A site does not need all of them, but it needs the ones its buyers' agents speak, declared where an agent looks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where sites fail the agent
&lt;/h2&gt;

&lt;p&gt;Most catalogs lose the agent before checkout. A price that lives only in rendered HTML, a CAPTCHA wall, a maintenance interstitial, or a discovery file that claims a capability the endpoint does not answer. Each one ends the purchase silently. The agent does not complain, it moves to a competitor whose path resolves. The failure looks like no traffic rather than a broken page, which is why it goes unmeasured.&lt;/p&gt;

&lt;h2&gt;
  
  
  Readiness is testable
&lt;/h2&gt;

&lt;p&gt;Whether an agent can buy is observable, the same way agent-readiness is. Declare the offer as structured data, expose a checkout an agent can call, publish the discovery files the protocols define, and back every claim with an endpoint that answers. Then test it the way an agent would, by driving the path end to end and watching where it stops. turva.dev built and verified its own agent commerce surface this way, across A2A, AP2, ACP and x402, checked by an independent scanner.&lt;/p&gt;

&lt;p&gt;For an audit of whether AI shopping agents can discover and complete a purchase on your site, contact &lt;a href="mailto:info@turva.dev"&gt;info@turva.dev&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/agent-commerce-discovery" rel="noopener noreferrer"&gt;Agent commerce discovery: A2A, AP2, and ACP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/x402-agent-payments" rel="noopener noreferrer"&gt;x402 and agent payments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/well-known-for-agents" rel="noopener noreferrer"&gt;The /.well-known directory for agents&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://turva.dev/guides/agentic-commerce-readiness" rel="noopener noreferrer"&gt;https://turva.dev/guides/agentic-commerce-readiness&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>ecommerce</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Agent commerce discovery: A2A, AP2, and ACP</title>
      <dc:creator>Erik Rekola</dc:creator>
      <pubDate>Thu, 30 Jul 2026 09:00:00 +0000</pubDate>
      <link>https://dev.to/turva-dev/agent-commerce-discovery-a2a-ap2-and-acp-5ddg</link>
      <guid>https://dev.to/turva-dev/agent-commerce-discovery-a2a-ap2-and-acp-5ddg</guid>
      <description>&lt;p&gt;Before an AI agent can transact with a site, it has to discover what the site supports and how to reach it. Three machine-readable surfaces carry that information: an A2A Agent Card, an AP2 declaration, and an ACP discovery document. Each answers a different question, and an agent reads them before it sends a single commerce request.&lt;/p&gt;

&lt;h2&gt;
  
  
  The A2A Agent Card
&lt;/h2&gt;

&lt;p&gt;An A2A Agent Card is a JSON file, usually at /.well-known/agent-card.json, that describes an agent interface. It states the agent's name, version, and description, the interfaces it exposes, each with a service URL and a protocol binding, the capabilities it declares, and the skills it offers, each skill carrying an id, a name, and a description. The Agent2Agent protocol uses the card so one agent can discover another and know how to reach it.&lt;/p&gt;

&lt;p&gt;The card is most useful when its skills mirror surfaces an agent can already reach, such as a service catalog or contact information. A skill that points nowhere is worse than no skill at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  AP2 and the version that matters
&lt;/h2&gt;

&lt;p&gt;AP2 is the Agent Payments Protocol. Under the v0.1 specification, which is what deployed sites and scanners still validate against, a merchant declares support not as a separate file but as an extension entry inside the A2A Agent Card. The entry carries the extension URI, a role such as merchant, and a flag marking it required.&lt;/p&gt;

&lt;p&gt;The detail that trips people up is the URI. Some helper guides write it as github.com/google-agentic-commerce/AP2/tree/v0.1.0, with an uppercase name and a three-part version. The v0.1 specification uses github.com/google-agentic-commerce/ap2/tree/v0.1, lowercase, version v0.1. A scanner that validates against that specification rejects the uppercase form even when everything else is correct. Copy the URI from the spec, not from a fix message.&lt;/p&gt;

&lt;p&gt;Note that the current AP2 specification, v0.2 from April 2026, restructures the protocol around checkout and payment mandates and drops the Agent Card extension entirely. The deployed discovery convention and the scanners still follow v0.1, so publish the v0.1 declaration for discoverability today and expect this surface to change as v0.2 adoption arrives.&lt;/p&gt;

&lt;h2&gt;
  
  
  ACP discovery and checkout
&lt;/h2&gt;

&lt;p&gt;ACP is the Agentic Commerce Protocol, and it has two parts that are easy to confuse. The first is a discovery document at /.well-known/acp.json, which started as a proposal-stage RFC and entered the released specification with the 2026-04-17 snapshot. The second is the checkout API the document points to.&lt;/p&gt;

&lt;p&gt;The discovery document is small and strict. It states the protocol name acp and a version, the api_base_url, a transports array, and a capabilities.services array. The services value is a closed set of strings such as checkout, not a list of product objects. Sending the wrong type is the most common reason an otherwise complete document fails validation.&lt;/p&gt;

&lt;p&gt;A discovery check usually reads only the document, not the checkout endpoint behind it. That makes it tempting to declare a service the site does not implement, because the check passes either way. An agent that trusts the document and calls the checkout URL would then reach nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  A minimal honest checkout
&lt;/h2&gt;

&lt;p&gt;A checkout endpoint does not have to support instant payment to be real. The ACP checkout session carries a status field, and one of its values is not_ready_for_payment. A site that sells through a written quote can create a genuine session, return it in that state, and attach a message that the engagement is confirmed in writing first. The agent receives a well-formed session that reflects how the business actually works, and the discovery claim holds because the endpoint behind it answers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Publish what is true
&lt;/h2&gt;

&lt;p&gt;These surfaces exist so an agent can act without guessing, which only holds when every claim resolves to something real. A card whose skills lead nowhere breaks the same way a checkout that never responds does, because the agent follows the signal and finds nothing. Publish what is true, and back each declaration with a surface that answers.&lt;/p&gt;

&lt;p&gt;turva.dev publishes an A2A Agent Card, an AP2 merchant declaration, and an ACP discovery document with a working checkout endpoint, verified by an independent scanner. For an audit of a site's agent commerce surface, contact &lt;a href="mailto:info@turva.dev"&gt;info@turva.dev&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/x402-agent-payments" rel="noopener noreferrer"&gt;x402 and agent payments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/well-known-for-agents" rel="noopener noreferrer"&gt;The /.well-known directory for agents&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://turva.dev/guides/agent-commerce-discovery" rel="noopener noreferrer"&gt;https://turva.dev/guides/agent-commerce-discovery&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>ecommerce</category>
      <category>webdev</category>
    </item>
    <item>
      <title>A red reading that measured my own client</title>
      <dc:creator>Erik Rekola</dc:creator>
      <pubDate>Thu, 30 Jul 2026 05:52:00 +0000</pubDate>
      <link>https://dev.to/turva-dev/a-red-reading-that-measured-my-own-client-1le5</link>
      <guid>https://dev.to/turva-dev/a-red-reading-that-measured-my-own-client-1le5</guid>
      <description>&lt;p&gt;I posted yesterday about checks that keep passing after they have stopped measuring the right thing. The next reading I took was the same defect turned around. A request against my own MCP server came back red, and the red was about my request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two responses that agreed on the wrong story
&lt;/h2&gt;

&lt;p&gt;I was working on the README for that server and sent a request at the endpoint to see what it was serving. The first was server/discover, which the 2026-07-28 revision of the Model Context Protocol requires every server to implement. It answered -32601 Method not found. So I sent initialize with protocol version 2025-06-18, the handshake that revision removes, and it answered 200 with the server's identity.&lt;/p&gt;

&lt;p&gt;Taken at face value that is a server that never migrated. The required new request is missing and the removed handshake still works. The migration had gone out that morning.&lt;/p&gt;

&lt;h2&gt;
  
  
  The server was right and my request was not
&lt;/h2&gt;

&lt;p&gt;Reaching the new lane takes three things at once, and I had none of them. The request has to carry the header MCP-Protocol-Version: 2026-07-28. It has to carry an Mcp-Method header naming the same method as the body. And params._meta has to carry the keys io.modelcontextprotocol/protocolVersion and io.modelcontextprotocol/clientCapabilities. Send none of that and the request is not malformed. It is a legacy request, and the library's compatibility lane answers it correctly, because answering it correctly is what the lane exists to do.&lt;/p&gt;

&lt;p&gt;That is the part worth stopping on. A compatibility lane is built to be invisible, which is right for a client and wrong for anyone taking a measurement. When the old lane answers politely, "this server does not implement the new revision" and "my client did not ask for the new revision" arrive looking the same. Neither response carries the thing that would separate them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The cheap test
&lt;/h2&gt;

&lt;p&gt;There is one and it costs a single request. If initialize answers, you are on the legacy lane, and whatever you conclude next is a statement about your client. A server serving 2026-07-28 does not offer initialize on the new lane at all, so a working handshake is evidence about the caller.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the four requests returned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Without the version header, server/discover returns HTTP 200, framed as an event stream, carrying -32601 Method not found. The same request sent as initialize with protocol version 2025-06-18 returns 200 and the server's identity.&lt;/li&gt;
&lt;li&gt;With the version header and no _meta, HTTP 400 and -32602, and the message says the header names revision 2026-07-28 while the request is missing the required per-request envelope key _meta.&lt;/li&gt;
&lt;li&gt;With the header and a _meta whose keys are spelled protocol-version and client-capabilities, HTTP 400 and -32602 again, and this time the message lists the two names the server does want.&lt;/li&gt;
&lt;li&gt;With all three in place, HTTP 200, supportedVersions holding 2026-07-28 alone, capabilities.tools.listChanged true, resultType complete, ttlMs 3600000, cacheScope public, and the server identity in result._meta.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What this is not
&lt;/h2&gt;

&lt;p&gt;This is not a defect in the SDK and not a gap in the spec. The compatibility lane is a deliberate decision and the right one, and being invisible is the whole point of it. The trap is downstream, in what a reader does with a response that arrives clean.&lt;/p&gt;

&lt;p&gt;It is also not a story where the information was missing. Read the second and third rows again. The server named the envelope key I had left out, then the two keys I had misspelled. The correct request was written inside the failures from the moment the version header went on, and I read the first response as a verdict instead of reading the rest as instructions.&lt;/p&gt;

&lt;p&gt;Rechecking all of this turned up one more of my own. A note of mine says this endpoint refuses anything that does not accept both JSON and an event stream. That holds on the legacy lane. On the new one a plain JSON Accept is answered, and so is a request with no Accept header at all. I had written down the behaviour of the lane I happened to be standing in and filed it as the rule.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shape, both times
&lt;/h2&gt;

&lt;p&gt;Yesterday it was a green check reading a lane the server no longer serves. Today it was a red reading of a lane my client never asked for. A response tells you what happened and you supply what it means, and the supplying is where it goes wrong. It goes wrong quietly, because a clean status code and a well-formed error object look like a measurement.&lt;/p&gt;

&lt;p&gt;So the habit, for anything with a compatibility layer beneath it. Before reading the result, work out which lane answered. If the protocol will not tell you, put the discriminator in the request yourself and check that the answer moves.&lt;/p&gt;

&lt;p&gt;None of this is visible to an agent-readiness scanner. Scanners do not speak MCP, so a passing readiness level says nothing about whether an MCP endpoint serves the current revision. That one belongs to whoever runs the server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://turva.dev/blog/checks-that-pass-for-the-wrong-reason" rel="noopener noreferrer"&gt;The checks that pass for the wrong reason&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/mcp-server-card" rel="noopener noreferrer"&gt;MCP server card&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/measurement-led-agent-readiness" rel="noopener noreferrer"&gt;Measurement-led agent readiness&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
