# Aligning an agent surface: every row we measure, and what to do about it

The assessment behind https://kya.trulioo.com/readiness, in full, as markdown. It reads only what your host serves an anonymous caller - one vantage, one moment - and it stores none of what it read.

**Nothing here adds up to a single number, and none is planned.** Each row gets a reason code and a residual: one sentence naming what stays unknown. A number assembled over rules that are not all ratified is a number that would be wrong in public, about somebody else's system, under our name.

**A row that could not be checked is not a shortfall and not a pass.** It is the third thing, and the assessment says which of the two it is not.

**Which rows even apply to you is decided by what answered.** A host running only an MCP server is not asked for an agent card, and a host that publishes nothing agent-shaped is told that rather than assessed as an agent.

**Read the maturity before you act on a row.** Where it says a rule is not citable as a requirement, publishing the document is a choice you are making about being found - not a conformance obligation, and not something anybody can hold you to.

Run it: https://kya.trulioo.com/readiness

The register behind every row - each document, what we do with it, and when it was last read: https://kya.trulioo.com/standards

## The origin itself

These rows are about the host rather than about anything running on it. Every artifact below is reached over this origin, so an origin that refuses anonymous callers makes all of them unreadable.

### Does the host answer an anonymous caller at all?

- id: `anonymous_root`
- standard: No standard - this is the baseline every row above depends on
- how settled: No standard - there is no document to cite, so nothing here is a conformance obligation
- why it matters: Everything else on this page was read by an anonymous caller, so a host that answers none of them has no readable surface at all.
- what to do: Answer an anonymous GET at the origin root with something other than a challenge. A surface reachable only from an allowlisted network is a private surface, whatever it publishes.

### Does the host's own crawl policy permit the agent surface it publishes?

- id: `robots`
- standard: RFC 9309 Robots Exclusion Protocol
- how settled: IETF standard - citable as a requirement
- specification: https://datatracker.ietf.org/doc/html/rfc9309
- why it matters: A crawl policy that excludes the agent surface tells every well-behaved reader to skip the documents above.
- what to do: Allow /.well-known/ explicitly. A blanket Disallow with an agent card behind it asks readers to choose between your policy and your documents, and the ones that honour the policy are the ones you wanted.

### Does the crawl policy state what the host permits its content to be used for?

- id: `content_signal`
- standard: Content-Signal, in robots.txt (RFC 9309 extension, proposed 2025)
- how settled: Emerging - NOT citable as a requirement, so a host that does not publish it has fallen short of nothing
- why it matters: States what an automated reader may do with what it fetches, in the one file every crawler already reads.
- what to do: Add a Content-Signal line to robots.txt declaring your position on search, training and inference. Put it near the top: a reader that caps how much of the file it reads will not find a directive at the bottom, which is also why this check can report a miss but never a denial.

### Is there a published way to report something wrong with this agent surface?

- id: `security_txt`
- standard: RFC 9116 security.txt, at /.well-known/security.txt
- how settled: IETF standard - citable as a requirement
- specification: https://datatracker.ietf.org/doc/html/rfc9116
- why it matters: A reader who finds something wrong with an agent surface needs somewhere to send it that is not a sales form.
- what to do: Serve /.well-known/security.txt as text/plain with a Contact field and an Expires field, and put the same address behind a mailbox somebody reads. An expired document is worse than none, because it names a channel a reporter will trust and then wait on.

### Is there a human-readable page saying how to authenticate here?

- id: `auth_md`
- standard: auth.md (convention, not a specification)
- how settled: Convention - NOT citable as a requirement, so a host that does not publish it has fallen short of nothing
- why it matters: Gives a reader a readable account of how to authenticate here, next to the machine metadata rather than instead of it.
- what to do: Publish a short /.well-known/auth.md naming the authorization server, the grants you accept and the scopes you issue. Keep it in step with the protected resource metadata - this check reads one path and never the pair, so a contradiction between them is invisible here and expensive at runtime.

### Is there a plain-text index pointing a reader at the machine-readable documents?

- id: `llms_txt`
- standard: llms.txt (community convention, no standards body)
- how settled: Convention - NOT citable as a requirement, so a host that does not publish it has fallen short of nothing
- specification: https://llmstxt.org/
- why it matters: Gives a model a curated map of the domain instead of a crawl of the marketing site.
- what to do: Publish /llms.txt linking the documents you want read, and regenerate it on release so the links do not drift out of the build. A file listing pages that 404 is worse than no file.

### Does the host publish a catalog of the APIs it operates, for a caller to walk?

- id: `api_catalog`
- standard: RFC 9727 api-catalog, a linkset at /.well-known/api-catalog (RFC 9264)
- how settled: IETF standard - citable as a requirement
- specification: https://datatracker.ietf.org/doc/html/rfc9727
- why it matters: An agent that has to guess which APIs a host operates will either miss one or invent one.
- what to do: Serve /.well-known/api-catalog as an RFC 9264 linkset naming every API the host operates and the description document for each, generated from the same source as the deployments so a retired API leaves the catalog with it. Either linkset media type is conformant, so this run accepts both and demands neither.

### Does the host publish a machine-readable description of what it is for?

- id: `ard_manifest`
- standard: Agent-readable description (/.well-known/ard.json - a proposal we have not adopted)
- how settled: Proposed - NOT citable as a requirement, so a host that does not publish it has fallen short of nothing
- why it matters: A single manifest tells an agent what this domain is for and which surfaces it may use.
- what to do: Publish /.well-known/ard.json describing the domain, its agent surfaces and their entry points, generated from the same source as the cards.

### Was this surface's certificate submitted to the public logs anybody can audit?

- id: `certificate_transparency`
- standard: RFC 6962 Certificate Transparency, read off the TLS connection this run already opened (no request is sent for this row, and only the embedded channel of the three is visible)
- how settled: IETF standard - citable as a requirement
- specification: https://datatracker.ietf.org/doc/html/rfc6962
- why it matters: An agent surface whose certificate was never logged can be issued again, to somebody else, without anybody noticing.
- what to do: Nothing on the host, which makes this the one row here whose remediation is a purchasing decision: use a certificate authority that submits to the public logs, which every major one now does by default because the browsers require it. Absence usually means a private or internal CA, and the reason this is never a failure is that two of the three delivery channels RFC 6962 defines are invisible to an observer standing where this run stands.
- this row cannot report a shortfall: This row reads the connection rather than a document you publish, and what it can read depends on the certificate your own CA issued - so it reports what was observable and never a shortfall.

### Does the host publish an XML URL inventory at /sitemap.xml an agent can read to find its documents?

- id: `sitemap`
- standard: the sitemaps.org XML protocol, at /sitemap.xml (a convention, not an RFC)
- how settled: Convention - NOT citable as a requirement, so a host that does not publish it has fallen short of nothing
- specification: https://www.sitemaps.org/protocol.html
- why it matters: An agent that cannot enumerate a host's documents has to guess at them, and it will guess wrong.
- what to do: Publish /sitemap.xml at the origin root, listing the URLs you want read rather than every URL you serve - an inventory a reader can trust beats a complete one. Generate it from the same source that generates the pages, because a hand-maintained list goes stale silently and a stale entry points an agent at a 404 it will report as your outage. Declare it from robots.txt with a Sitemap line so a caller that starts at the policy finds it.

### Does the crawl policy speak to AI agents by name, or only to search engines?

- id: `robots_ai_rules`
- standard: RFC 9309 user-agent groups, read for which named agents appear (a wildcard group already binds every one of them, so naming one is a more specific policy and never a requirement)
- how settled: IETF standard - citable as a requirement
- specification: https://datatracker.ietf.org/doc/html/rfc9309
- why it matters: A policy written only for search engines leaves every AI caller guessing whether it was meant to be here.
- what to do: Add a user-agent group naming the AI crawlers you have an actual position on - GPTBot, ClaudeBot, Google-Extended, PerplexityBot and CCBot cover most of the traffic - and say what each may read. A named group is a MORE SPECIFIC statement and not a required one: the wildcard group already binds all of them, which is why nothing here can fail. Remember this file is a request rather than an access control, so put nothing behind it you would not put behind a door.
- this row cannot report a shortfall: This row reads which callers a policy document addresses, and a wildcard group already binds every one of them - so naming one is a more specific statement rather than a more conforming one, and there is no shortfall to report.

### Will the host serve a plain-text reading of its front page to an agent that asks?

- id: `markdown_alternate`
- standard: RFC 9110 proactive content negotiation, plus RFC 8288 link relations as the second way to answer (an origin may disregard an Accept it will not honour, so this is never a shortfall)
- how settled: IETF standard - citable as a requirement
- specification: https://datatracker.ietf.org/doc/html/rfc9110#section-12.5.1
- why it matters: Every agent stack reads plain text better than it reads a rendered page, and most hosts make it parse the page anyway.
- what to do: Answer an `Accept: text/markdown` request with the markdown source of the page, or - just as good - keep serving HTML and add a Link header with `type="text/markdown"` pointing at the .md twin. Either answers the question; neither is obliged by anything, which is why this row cannot fail. The one thing to avoid is negotiating on the root and nowhere else, since a caller that succeeds once will assume the rest of the site behaves the same way.
- this row cannot report a shortfall: RFC 9110 lets an origin server disregard an Accept it will not honour and send another representation, so the answer that is not markdown is conforming behaviour and this row reports no shortfall for it.

## An agent

Something at this domain that acts on a principal's behalf - named by the host, reachable, and signing for itself.

**What a relying party expects.** A relying party needs to know who operates it before it will accept a call: the operator named at a machine-readable path, the keys that sign for it fetchable, and terms it will transact under stated rather than negotiated.

**What the best one looks like.** The best is named in an index that says who operates it, points at its surface from the domain itself, publishes the keys a verifier needs and a signature directory to check a bot against, signs its public responses recently enough to mean something, and states the payment mandates and rails it will accept instead of leaving an agent to guess.

**Where we hold ourselves to it.** Ours is the surface this page is served from, and it is the reason the row that fails is visible here rather than hidden: an agent index that named nobody would be our gap on our own page.

**What makes this section apply to you.** The assessment decides from what your host actually answered, never from the domain you typed: `ai_catalog`, `tool_provider_attribution`, `dns_agent_record`. Publish none of those and these rows are reported as not applicable rather than held against you.

### Does the host publish an AI catalogue naming its agents?

- id: `ai_catalog`
- standard: /.well-known/ai-catalog.json (draft convention)
- how settled: Convention - NOT citable as a requirement, so a host that does not publish it has fallen short of nothing
- why it matters: Lets a reader enumerate what a domain publishes for agents instead of guessing at paths.
- what to do: Publish /.well-known/ai-catalog.json listing every agent surface on the domain and the document that describes each one. Generate it from the same source as the cards, so a retired agent leaves the catalogue at the same time it leaves the fleet.

### Does the host name who operates the tools it exposes, at a machine-readable path?

- id: `tool_provider_attribution`
- standard: /.well-known/agents.json (Trulioo convention - a JSON assertion, not a signature)
- how settled: Convention - NOT citable as a requirement, so a host that does not publish it has fallen short of nothing
- our side of it: https://agents.trulioo.com/.well-known/agents.json
- why it matters: Naming who operates the tools is the difference between a surface a counterparty can escalate to and one they can only stop using.
- what to do: Publish /.well-known/agents.json naming the operator of each agent surface and the issuer behind it. It is a JSON assertion and not a signature, so keep it modest about what it establishes.

### Does the domain itself point at the agent surface, above the web server?

- id: `dns_agent_record`
- standard: A TXT record at _agent (a convention with no RFC and no IANA registration - read through ONE resolver over DNS-over-HTTPS, so the answer is that resolver's at one moment and never a fail)
- how settled: Emerging - NOT citable as a requirement, so a host that does not publish it has fallen short of nothing
- why it matters: Lets a resolver find the agent surface from DNS alone, before any HTTP request is made.
- what to do: Publish a TXT record at _agent naming the agent card URL and the issuer, with a TTL short enough to retire a record you no longer control. This run reads the label through ONE resolver over DNS-over-HTTPS when the caller names one, and never fails you for an absent record: no RFC and no IANA registration stands behind _agent, so an absent record is conformance to everything there is to conform to.
- this row cannot report a shortfall: The answer here is our resolver's, about a name you control, and no RFC and no IANA registry obliges anybody to publish the record - so this row reports what was resolvable and never a shortfall.

### Do the host's own response headers point a caller at the agent surface?

- id: `link_header_agent`
- standard: RFC 8288 Web Linking, in a Link header on the root response
- how settled: IETF standard - citable as a requirement
- specification: https://datatracker.ietf.org/doc/html/rfc8288
- why it matters: A caller that lands on any page can follow a header to the card instead of guessing at a well-known path.
- what to do: Emit a Link header on the root response pointing at the agent card, and add a describedby relation for the API description if you publish one. This run reads the header on an anonymous GET of the root, and an absent header is reported as not observed rather than as a failure, because RFC 8288 registers relations and obliges nobody to send one.

### Can a verifier fetch the keys needed to check the host's signatures?

- id: `jwks`
- standard: RFC 7517 JSON Web Key Set
- how settled: IETF standard - citable as a requirement
- specification: https://datatracker.ietf.org/doc/html/rfc7517
- our side of it: https://identity.trulioo.com/.well-known/jwks.json
- why it matters: Without published keys, nothing this agent signs can be checked by a third party.
- what to do: Publish the signing keys, and keep each kid equal to its RFC 7638 thumbprint so a verifier never has to trust an algorithm claimed on the wire. Keep a retired key in the set for as long as anything it signed is still in flight.

### Does the host publish a signature directory an origin can verify a bot against?

- id: `wba_directory`
- standard: Web Bot Auth, over RFC 9421 HTTP Message Signatures
- how settled: Emerging - NOT citable as a requirement, so a host that does not publish it has fallen short of nothing
- specification: https://datatracker.ietf.org/doc/draft-meunier-webbotauth-httpsig-protocol/
- our side of it: https://identity.trulioo.com/.well-known/http-message-signatures-directory
- why it matters: Lets an origin authenticate an automated caller instead of guessing from a user agent string.
- what to do: Publish the signature directory with Ed25519 keys and key ids that are JWK thumbprints. Give each key an nbf, and retire a key by removing it rather than by rotating around it.

### Are the host's public responses signed, and signed recently enough to mean anything?

- id: `signed_response_freshness`
- standard: RFC 9421 HTTP Message Signatures, in a Signature-Input header on the root response
- how settled: IETF standard - citable as a requirement
- specification: https://datatracker.ietf.org/doc/html/rfc9421
- why it matters: A signature that verifies but is stale proves the key, not the request.
- what to do: Sign per request, reject a created value older than your stated ceiling, and do not cache a signed response at the edge - a cached signature is a replayable one. This run records whether a Signature-Input header travelled on an anonymous GET of the root, which a host that signs only credentialed responses will legitimately not send.

### Does the host publish a commerce profile an agent could shop against?

- id: `ucp_profile`
- standard: Universal Commerce Protocol (vendor proposal, early)
- how settled: Open protocol - citable as a requirement
- specification: https://ucp.dev/
- why it matters: Describes what an agent may buy here and under whose terms.
- what to do: Publish /.well-known/ucp.json with the catalogue endpoints, the supported currencies, the checkout terms and a returns policy reference. Omit the file rather than publishing terms the checkout does not honour.

### Does the host say what kind of payment mandate it will accept from an agent?

- id: `ap2_mandates`
- standard: Agent Payments Protocol (AP2) mandates (vendor proposal, early)
- how settled: Emerging - NOT citable as a requirement, so a host that does not publish it has fallen short of nothing
- specification: https://ap2-protocol.org/
- why it matters: An accountable transaction needs a mandate stating what a person actually authorized.
- what to do: Accept mandates with key possession bound into them, and reject any mandate whose agent key is not bound to a verified operator. A mandate from an unbound key records intent without recording accountability.

### Is there a checkout an agent can drive without a browser?

- id: `acp_checkout`
- standard: Agentic Commerce Protocol checkout (vendor proposal, early)
- how settled: Emerging - NOT citable as a requirement, so a host that does not publish it has fallen short of nothing
- why it matters: Describes the checkout an agent can drive end to end, including what a person must approve.
- what to do: Publish the checkout endpoints, the mandate you require and the approval step a person has to complete. Name the profile that covers refunds, or a counterparty has to assume none exists.

### Does the host declare a rail it will settle an agent's payment over?

- id: `mpp_profile`
- standard: Machine Payments Protocol (Tempo Labs, IETF-track draft)
- how settled: Emerging - NOT citable as a requirement, so a host that does not publish it has fallen short of nothing
- why it matters: Tells a paying agent which rails you accept before it starts a checkout it cannot finish.
- what to do: Publish the accepted rails, the settlement currencies and any per-transaction limits. Omit the file rather than advertising a rail your checkout does not settle on.

### Does a metered route tell an agent what it costs, instead of just refusing it?

- id: `x402_payment_requirements`
- standard: HTTP 402 with payment requirements (x402, a revival rather than a ratified spec - and derived: the route is whatever the subject's own documents declare, because x402 defines a response and no discovery path)
- how settled: Emerging - NOT citable as a requirement, so a host that does not publish it has fallen short of nothing
- specification: https://www.x402.org/
- why it matters: Machine-mediated payment needs the price and the rail in the response, not on a pricing page.
- what to do: On a metered route return 402 with the scheme, the network, the amount and the address to pay, and keep the unpaid body machine-readable so an agent can decide without rendering a page. Then NAME that route in a document you already publish - an x402 resource on your agent card is enough - because x402 defines a response and no discovery path, so a route nobody declares is one this run will not go looking for. It reads a route you declared and nothing else: no path is guessed, nothing is paid, and no X-PAYMENT header is ever constructed.

## An agent card

An A2A card at a well-known path describing one agent - its skills, its endpoint, and the attestation behind it.

**What a relying party expects.** A card is the document a marketplace reads first, so what it says has to be true of the endpoint it names. A card that advertises a skill the endpoint cannot dispatch is worse than no card, because it is actionable and wrong.

**What the best one looks like.** The best card is fetchable without a credential, validates against the schema it claims, advertises only skills the endpoint can actually dispatch, points at an attestation that resolves to a signed record, and names a log where a third party can confirm that record was not quietly changed.

**Where we hold ourselves to it.** Our card is checked against a published schema on a Trulioo host, and the divergence row compares its skills against what the endpoint answers - a card we edited without shipping the skill reds on our own surface. The last clause of that bar is where we are honest about ourselves: the issuer behind our card publishes a signed tree head, witness cosignatures and an inclusion proof for any leaf, all fetchable by a stranger holding no credential - and the card itself names none of them, so a verifier that follows it gets a leaf index and has to already know where a leaf index is redeemed.

**What makes this section apply to you.** The assessment decides from what your host actually answered, never from the domain you typed: `agent_card`. Publish none of those and these rows are reported as not applicable rather than held against you.

### Does the agent publish a card a relying party can fetch without a credential?

- id: `agent_card`
- standard: A2A Agent Card, at /.well-known/agent-card.json
- how settled: Open protocol - citable as a requirement
- specification: https://a2aproject.github.io/A2A/
- our side of it: https://identity.trulioo.com/a2a/kya/v1/schema.json
- why it matters: Names the agent, its interfaces and its operator before a single call is made.
- what to do: Keep the card in step with the deployed interface. A stale card is worse than no card, because a caller will act on it: every skill it advertises has to be one the endpoint can dispatch today.

### Does the published card match the schema it claims?

- id: `card_schema_valid`
- standard: The card's own declared schema
- how settled: Open protocol - citable as a requirement
- our side of it: https://identity.trulioo.com/a2a/kya/v1/schema.json
- why it matters: A card missing a part a reader needs is worse than an absent card: the reader parses it, gets nothing where it looked, and cannot tell your host from a broken one.
- what to do: Carry every member a reader needs to act - a name, a description, an endpoint, a version, capabilities, skills, and the input and output modes - and give each one a usable type rather than null. Generate the card in the build that publishes it and validate it there against the full schema: a card written by hand and validated by a reader is a card validated in production.

### Do the skills the card advertises match what the endpoint can actually dispatch?

- id: `card_runtime_divergence`
- standard: The card's skills[] against the endpoint's own tool list
- how settled: Open protocol - citable as a requirement
- why it matters: A skill on the card that the endpoint cannot dispatch is a promise a caller will act on and a failure it cannot attribute.
- what to do: Generate the card's skills[] from the same source the endpoint dispatches from. Where they cannot share a source, gate the release on comparing them.

### Does the attestation the card points at resolve to a signed record?

- id: `attestation_resolves`
- standard: Trulioo DAP, resolved at the issuer
- how settled: Standard plus KYA profile - NOT citable as a requirement, so a host that does not publish it has fallen short of nothing
- our side of it: https://kya.trulioo.com/portal/
- why it matters: The card names the agent; only a signed, scoped, revocable profile names the organisation behind it, and no self-published document can assert that for itself.
- what to do: Verify the organisation and the domain, register the agent so it mints its own key and a Digital Agent Profile bound to the published card, then carry the handle on the card. A reader can resolve it against the issuer's keys with no credential of their own.

## An agent plugin

A bundle of skills a caller can read before invoking any of them - the instructions, the scripts, and what they reach for.

**What a relying party expects.** A caller decides whether to run a plugin from what it declares, so the declaration has to be readable without executing anything in it. A skills index is that declaration.

**What the best one looks like.** The best publishes an index a caller can read before calling anything, and ships as a package whose every delivered file is sealed, so somebody re-installing it later gets the bytes that were reviewed.

**Where we hold ourselves to it.** Our plugin is sealed by a profile that hashes every delivered regular file and refuses a release whose coordinate does not match the sealed manifest - held by a test, not by a release note, and the seal flips on a one-byte change to a file nobody thought was part of the package.

**What makes this section apply to you.** The assessment decides from what your host actually answered, never from the domain you typed: `skills_index`. Publish none of those and these rows are reported as not applicable rather than held against you.

### Is there a skills index a caller can read before calling anything?

- id: `skills_index`
- standard: /.well-known/skills
- how settled: Emerging - NOT citable as a requirement, so a host that does not publish it has fallen short of nothing
- specification: https://agentskills.io/home
- why it matters: A skills catalogue is one hop from the card, but only if it parses as a catalogue.
- what to do: Serve /.well-known/skills as application/json, or as a directory of signed skill manifests. An HTML fallback makes the path indistinguishable from a soft 404, so it cannot be read as evidence either way.

## An MCP server

An endpoint that answers Model Context Protocol calls - tools an agent can invoke, and the authorization needed to invoke them.

**What a relying party expects.** An agent needs to learn what a server offers and how to get a token for it without a human reading documentation. Both halves have to be published anonymously, because a caller that must already hold a credential to discover how to get one cannot start.

**What the best one looks like.** The best publishes a server card at the anonymous well-known path, declares its in-page tools in a manifest rather than only in script, says which authorization server issues tokens for it and how to reach that server, accepts a client identified by a URL instead of a shared secret, and names who operates the tools it exposes.

**Where we hold ourselves to it.** Ours does not answer an anonymous caller with its tool list - an unauthenticated call is refused. What it does publish to a caller holding nothing is the protected-resource metadata naming the authorization server that issues its tokens, and a challenge on the refusal that points back at that metadata, which is the half of this bar a caller needs to be able to start. The server-card row reds on us: there is no card at our anonymous well-known path yet, and saying so here is cheaper than being found out by a reader running this page against us.

**What makes this section apply to you.** The assessment decides from what your host actually answered, never from the domain you typed: `mcp_server_card`, `webmcp_manifest`. Publish none of those and these rows are reported as not applicable rather than held against you.

### Does the host publish an MCP server card at the anonymous well-known path?

- id: `mcp_server_card`
- standard: MCP SEP-2127 server card, at /.well-known/mcp.json (proposed, not ratified)
- how settled: Proposed - NOT citable as a requirement, so a host that does not publish it has fallen short of nothing
- specification: https://modelcontextprotocol.io/
- why it matters: The anonymous well-known path is where a client with no credential looks first, and a credential-gated card cannot be read before a connection is made.
- what to do: Publish /.well-known/mcp.json unauthenticated, carrying the transport, the endpoint, the authorization servers and a tools[] summary. Note that the location is a proposal, so serve the recommended path too rather than instead.

### Does the host declare its in-page tools in a manifest, rather than only in script?

- id: `webmcp_manifest`
- standard: WebMCP manifest (W3C incubation - the declarative half of the same proposal)
- how settled: Emerging - NOT citable as a requirement, so a host that does not publish it has fallen short of nothing
- why it matters: A manifest is the half of WebMCP a fetch can read; tools registered in script are invisible to anything that does not execute the page.
- what to do: Declare the page's tools in a manifest as well as registering them at runtime. Keep the two generated from one source, or the manifest becomes a description of a previous release.

### Does the page's own markup declare any in-page tool an agent could call?

- id: `webmcp_declared_tools`
- standard: WebMCP declarative form attributes (W3C incubation, nothing shipped stable)
- how settled: Emerging - NOT citable as a requirement, so a host that does not publish it has fallen short of nothing
- why it matters: Declares the tools a browsing agent may call on a page, rather than leaving it to infer them from the DOM.
- what to do: Declare each page-level tool with its name, its input schema and the origin allowed to call it. Only declare tools that are safe to invoke without a person present - a declaration is an invitation.

### Does the resource say which authorization server issues tokens for it?

- id: `oauth_protected_resource`
- standard: RFC 9728 OAuth 2.0 Protected Resource Metadata
- how settled: IETF standard - citable as a requirement
- specification: https://datatracker.ietf.org/doc/html/rfc9728
- why it matters: Tells a caller which token to obtain and exactly which resource that token is for.
- what to do: Publish resource metadata naming the resource identifier and the authorization servers for it, and confirm each named server publishes matching issuer metadata. A resource pointing at a server that does not claim it is a loop a caller cannot close.

### Does the host advertise how to obtain a token?

- id: `oauth_metadata`
- standard: RFC 8414 OAuth 2.0 Authorization Server Metadata
- how settled: IETF standard - citable as a requirement
- specification: https://datatracker.ietf.org/doc/html/rfc8414
- why it matters: Tells a caller how to obtain a token without a support ticket or a shared secret out of band.
- what to do: Publish authorization server metadata naming the issuer, the endpoints and the grant types you actually accept. A document advertising a grant the server refuses is a contradiction a caller finds at runtime.

### Can a client identify itself by a URL a server can fetch, instead of a shared secret?

- id: `client_id_metadata`
- standard: Client ID Metadata Document (OAuth draft, incubating)
- how settled: Incubating - NOT citable as a requirement, so a host that does not publish it has fallen short of nothing
- specification: https://datatracker.ietf.org/doc/draft-ietf-oauth-client-id-metadata-document/
- why it matters: A client identified by a URL is a client a server can look up, but on its own the identifier proves control of a URL and nothing more.
- what to do: Publish the client metadata document and populate its signed statement with a JWT whose key resolves in a published key set. Until that slot is filled a relying party cannot distinguish the identifier from any other self-asserted URL.

## Named while inferring, and measured against nobody

These documents are cited by the assessment's analyzers and no row measures a subject against them. Each was a candidate check that could not be established as truth from an anonymous vantage, so the surface says what it is doing with the document instead of implying a measurement. They are listed because a reader who found the name in our output deserves to know which of the two it was.

### RFC 9264 linksets

- id: `rfc9264`
- how settled: IETF standard
- who moves it: IETF
- specification: https://datatracker.ietf.org/doc/html/rfc9264
- what a change to it would move here: Either serialization changes, or one of them is deprecated. It is registered separately from RFC 9727 because it is a different document with its own clock: RFC 9727 says WHERE a catalog lives and RFC 9264 says what a catalog IS, and the two conformance findings a reader gets - a JSON document with no linkset member, a link target with no href - are RFC 9264's rules and not RFC 9727's. It carries no check of its own on purpose; the api-catalog fetch is the only thing that reads it.

### CORS, in the WHATWG Fetch standard

- id: `cors-fetch`
- how settled: Open protocol
- who moves it: WHATWG
- specification: https://fetch.spec.whatwg.org/
- what a change to it would move here: A living standard, so it moves continuously rather than in versions. It matters here because a browser-side resolution that a header refuses is our reader's browser being told no - not the subject's document being absent - and an insight already says so.

### X-Robots-Tag

- id: `x-robots-tag`
- how settled: Convention
- who moves it: none
- no document to cite: A convention with no document behind it: it is what crawlers implemented and what operators copied. Nothing to cite, which is exactly what the readiness surface has to say about it rather than dressing the practice up as a rule.
- what a change to it would move here: Practice moves. An insight reads this header alongside a robots document, and the two disagreeing is a real finding about a subject - so what to watch is whether the header keeps meaning what the insight assumes.

### RFC 6797 HTTP Strict Transport Security

- id: `rfc6797`
- how settled: IETF standard
- who moves it: IETF
- specification: https://datatracker.ietf.org/doc/html/rfc6797
- what a change to it would move here: Rarely. It is here because an insight cites it, and an insight citing a document nothing in this registry knows about is the gap this file closes.

## What a readiness run cannot answer

Every row above reads a document a host published to a stranger. That is a fact about documents, and there are questions it cannot reach at all - not because a host fell short on them, but because no published document is evidence of them. This is what a Digital Agent Profile carries, and what each answer's limit is.

### Who is accountable for this agent?

- from published documents alone: Whatever the host's own documents say, which is a claim by the party being asked about. A readiness run can confirm a name is published; it has nothing to compare the name against.
- from a profile: A named operator with a kind, a jurisdiction and a date, present only once the credential names a verified operator, and carried inside a signature. On the live issuance route the name is still the requester's - so the credential moves the accountability question from unanswerable to auditable, not to settled.
- carried by: `operator.legal_name`, `operator.jurisdiction`, `assurance.identity_basis`

### Is the thing calling me the thing that was described?

- from published documents alone: Nothing connects a published card to a caller. Any client can copy an agent's card and present its own request.
- from a profile: The caller signs a challenge the verifier issued, with the key the credential is bound to. This is the one claim in the suite that is proven at the moment of use rather than at issuance.
- carried by: `cnf.jwk`, `Holder-binding proof`

### Can what I was told be withdrawn?

- from published documents alone: Only by editing a document, which a relying party would have to re-fetch to notice and cannot distinguish from an outage.
- from a profile: A status list entry the issuer serves and signs, checked on every presentation, refusing the credential when the list cannot be verified.
- carried by: `status_reference`, `Revocation, fail-closed`

### What was actually checked, and by whom?

- from published documents alone: Nothing was checked. A readiness run observes what a host serves an anonymous caller and says so per row, which is a fact about documents rather than about an actor.
- from a profile: Every claim carries a recorded basis, including the ones nothing assesses, and the basis distinguishes a Trulioo outcome from a value the requester sent. The absences are part of the answer.
- carried by: `principal_assertion`, `rail_endorsements[]`, `behavior_credential`

### Can two counterparties both verify me without being able to compare notes?

- from published documents alone: No. A published card is one document for everybody, and every relying party sees the same identifiers.
- from a profile: The per-relying-party profile replaces the shared holder key with a relationship key and signs the audience, so a credential shown to one party cannot be replayed at another and the subject identifier differs between them.
- carried by: `sub`, `Relationship-key audience binding`

### How much of this could change without anyone noticing?

- from published documents alone: A document can change between two runs, and a run reports the moment it measured. That is the whole of the guarantee.
- from a profile: The credential is signed over a fixed expiry, and the claim basis for every path is written down in a ledger a test holds the issuer to - so a producer that starts emitting a stronger value without a stronger basis is a red build rather than a quiet upgrade.
- carried by: `exp`, `assurance.trust_tier`

The operator behind a profile is verified as a business, by the same KYB the rest of Trulioo runs - registry lookup, jurisdiction, and the people accountable for it - which is why the accountability question above moves from unanswerable to auditable rather than to settled. The rung a profile reaches is named, never numbered: see https://kya.trulioo.com/standards.

## How this file was made

Generated, not written. Every question, standard, maturity and remediation above is read out of the vocabulary the assessment itself runs on, so a row we stop checking or a document that moves changes this file in the same commit:

- apps/kya-portal/src/model/hostRootDocs.ts
- apps/kya-portal/src/model/readinessPage.ts
- apps/kya-portal/src/model/readinessLedger.ts
- apps/kya-portal/src/model/subjectArtifacts.ts
- apps/kya-portal/src/model/dapDepth.ts
- commerce/halo/docs/execution/schemas/kya-readiness-standards-registry.json

Regenerate with `cd apps/kya-portal && node scripts-emit-host-root-docs.mjs`. `src/model/hostRootDocs.test.ts` fails if the committed file differs from what the generator produces.
