> For the complete documentation index, see [llms.txt](https://ascribed-dev.com/docs/llms.txt). This documentation describes Ascribe 0.4.4. Anything marked in main, not yet released isn't in that release yet.

# Diagnostics: content checks of outputs and the site

> Reference · The checks of a project's outputs, prose, external links, published site, and tested examples, which it can set the level of or turn off.

The content checks of what a build writes, the prose through Vale, the external links, the published site, and the tested examples. The checks of the project as a whole are on [Diagnostics: content checks across the project](https://ascribed-dev.com/docs/checks/diagnostics/project-checks.md), and those of pages on [Diagnostics: content checks](https://ascribed-dev.com/docs/checks/diagnostics/content-checks.md), which says how a project sets a check's level or turns it off in [`[checks]`](https://ascribed-dev.com/docs/content-model/checks.md#22-checks). Part of the [diagnostics reference](https://ascribed-dev.com/docs/checks/diagnostics.md), which says what an entry's severity, level, and next step mean, and has an index of every diagnostic.

## Outputs

### ASC163 `description-too-long`

[Advice](https://ascribed-dev.com/docs/checks/diagnostics.md#severity) · [file level](https://ascribed-dev.com/docs/checks/diagnostics.md#file-level-and-page-level) · next step: [write](https://ascribed-dev.com/docs/checks/diagnostics.md#what-to-do-next) · [configurable](https://ascribed-dev.com/docs/checks/diagnostics.md#setting-a-checks-level) in `[checks]` · [SPEC §9.4](https://github.com/ascribed-dev/ascribe/blob/main/SPEC.md#94-outputs)

**When:** The project publishes `llms.txt` (`[consumer] agents = true`), and a page's description, or a content type's default for its description field, is longer than 300 characters as `llms.txt` writes it.

**Message:** this description is {length} characters, and its line in llms.txt reads best under {limit}; shorten it to one sentence

**Fix:** Shorten the description to one sentence that says what the page is for. It's the page's line in `llms.txt`, which an agent reads to choose a page, so the whole index should stay short.

**Read more:** [Field roles](https://ascribed-dev.com/docs/content-model.md#54-field-roles) in the `ascribe.toml` reference.

### ASC164 `llms-section-large`

[Advice](https://ascribed-dev.com/docs/checks/diagnostics.md#severity) · [page level](https://ascribed-dev.com/docs/checks/diagnostics.md#file-level-and-page-level) · next step: [write](https://ascribed-dev.com/docs/checks/diagnostics.md#what-to-do-next) · [configurable](https://ascribed-dev.com/docs/checks/diagnostics.md#setting-a-checks-level) in `[checks]` · [SPEC §9.4](https://github.com/ascribed-dev/ascribe/blob/main/SPEC.md#94-outputs)

**When:** The project publishes `llms.txt` (`[consumer] agents = true`), and one of a build's `llms.txt` files is longer than 50,000 characters even with the index split by folder. Reported at the page the file is about.

**Message:** {file} is {size} characters in build `{build}`, over the {limit} an agent reads in one fetch; move some of its pages into folders of their own, or shorten their descriptions

**Fix:** Each folder of pages gets its own `llms.txt` once the index is too long for one file, so a file this long is one folder, or the pages outside any folder, with more pages than an agent reads in one fetch. Move some of them into subfolders of their own, or shorten their descriptions. It's the delivery spec's `llms-txt-size` check, made from the build before a deploy; `ascribe report delivery` names this check for it.

**Read more:** [`[consumer]`](https://ascribed-dev.com/docs/content-model/output.md#15-consumer) in the `ascribe.toml` reference.

### ASC184 `listing-disallowed`

[Advice](https://ascribed-dev.com/docs/checks/diagnostics.md#severity) · [file level](https://ascribed-dev.com/docs/checks/diagnostics.md#file-level-and-page-level) · next step: [fix](https://ascribed-dev.com/docs/checks/diagnostics.md#what-to-do-next) · [configurable](https://ascribed-dev.com/docs/checks/diagnostics.md#setting-a-checks-level) in `[checks]` · [SPEC §2.1](https://github.com/ascribed-dev/ascribe/blob/main/SPEC.md#21-files)

**When:** A page is `unlisted`, and what the project says in `[crawlers]` keeps a search crawler from fetching it: its own lines, for every crawler or in a group that names the crawler, or a disallowed purpose.

**Message:** this page is unlisted, and `{line}` in `[crawlers] lines` disallows its address, so a crawler never fetches it to read that it isn't to be listed; a search engine can still list the address alone

**Fix:** Remove one of the two. A crawler reads `noindex` only on a page it may fetch, so to keep a page out of search results, let crawlers fetch it: remove the `Disallow` line, or narrow it so it doesn't cover the page, or allow the purpose. If the page only needs to stay out of what crawlers fetch, remove `listing: unlisted`. The editor's quick fix removes `listing`.

**Read more:** [`[crawlers]`](https://ascribed-dev.com/docs/content-model/output.md#18-crawlers) in the `ascribe.toml` reference.

### ASC190 `crawlers-disallowed`

[Advice](https://ascribed-dev.com/docs/checks/diagnostics.md#severity) · [file level](https://ascribed-dev.com/docs/checks/diagnostics.md#file-level-and-page-level) · next step: [choose](https://ascribed-dev.com/docs/checks/diagnostics.md#what-to-do-next) · [configurable](https://ascribed-dev.com/docs/checks/diagnostics.md#setting-a-checks-level) in `[checks]` · [SPEC §7.2](https://github.com/ascribed-dev/ascribe/blob/main/SPEC.md#72-declarations)

**When:** `[crawlers]` disallows `search` or `on-request`, and the site's pages are listed unless they say otherwise.

**Message:** `{purpose} = "disallow"` keeps AI search products from indexing the site, so its pages aren't in their answers, while the pages are listed for every other search engine

**Fix:** Choose what the site wants. To be in AI search answers, and fetched when a person asks, `allow` the purpose or remove it. To keep it, turn this check off in `[checks]`, saying so in a comment: the choice is the project's, and this only says what it costs. A purpose's group asks only the crawlers Ascribe knows, and some of them say they may not follow `robots.txt`.

**Read more:** [`[crawlers]`](https://ascribed-dev.com/docs/content-model/output.md#18-crawlers) in the `ascribe.toml` reference.

## Prose, through Vale

### ASC165 `prose`

[Advice](https://ascribed-dev.com/docs/checks/diagnostics.md#severity) · [file level](https://ascribed-dev.com/docs/checks/diagnostics.md#file-level-and-page-level) · next step: [write](https://ascribed-dev.com/docs/checks/diagnostics.md#what-to-do-next) · [configurable](https://ascribed-dev.com/docs/checks/diagnostics.md#setting-a-checks-level) in `[checks]` · Ascribe's own, not in SPEC

**When:** The project has `[checks.vale]`, and Vale reports an alert about the prose of a page or a [fragment](https://ascribed-dev.com/docs/glossary.md#fragment), or of a phrase's text. Reported where the alert is in the source, or at the phrase.

**Message:** {rule}: {message}

**Fix:** Vale reported this about the prose, under the rule the message starts with. Change the text, or take the replacement the editor offers when the rule gives one; for text from a phrase, change the phrase's value in `ascribe.toml`. A rule that's wrong for the project is turned off in Vale's configuration, or, for the `quiet` preset, in `[checks.vale] off`; one place is quieted with Vale's own comments (`<!-- vale Rule = NO -->`). See [Prose, through Vale](https://ascribed-dev.com/docs/checks/vale.md).

**Read more:** [`[checks.vale]`](https://ascribed-dev.com/docs/content-model/checks.md#checksvale) in the `ascribe.toml` reference.

### ASC166 `prose-not-checked`

[Advice](https://ascribed-dev.com/docs/checks/diagnostics.md#severity) · [file level](https://ascribed-dev.com/docs/checks/diagnostics.md#file-level-and-page-level) · next step: [outside](https://ascribed-dev.com/docs/checks/diagnostics.md#what-to-do-next) · [configurable](https://ascribed-dev.com/docs/checks/diagnostics.md#setting-a-checks-level) in `[checks]` · Ascribe's own, not in SPEC

**When:** The project has `[checks.vale]`, and Vale couldn't be run, failed, or didn't finish in time, or the tool checking the project doesn't start it, as the agents' tools don't. Reported once, at `[checks.vale]`.

**Message:** the prose wasn't checked: `{command}` couldn't be run ({reason}). Install Vale, or set `[checks.vale] command` to where it is

**Fix:** Install [Vale](https://vale.sh) 3.16 or later so that the command `[checks.vale] command` names (`vale` by default) runs, or fix what Vale's own message says about its configuration. Nothing else is checked differently while it can't run. A project that checks prose only in CI can turn this off on other machines with `prose-not-checked = "off"` in `[checks]`. The agents' tools never start Vale; the agents' hook never starts a `command` that's a program in the project, and the editor asks before it does. Run `ascribe check --vale` in a terminal to check the prose then.

**Read more:** [`[checks.vale]`](https://ascribed-dev.com/docs/content-model/checks.md#checksvale) in the `ascribe.toml` reference.

## External links

### ASC168 `link-external-broken`

[Advice](https://ascribed-dev.com/docs/checks/diagnostics.md#severity) · [file level](https://ascribed-dev.com/docs/checks/diagnostics.md#file-level-and-page-level) · next step: [review](https://ascribed-dev.com/docs/checks/diagnostics.md#what-to-do-next) · [configurable](https://ascribed-dev.com/docs/checks/diagnostics.md#setting-a-checks-level) in `[checks]` · [acknowledged](https://ascribed-dev.com/docs/glossary.md#acknowledgement) with `@intended` above the block, or under the heading for a heading · [SPEC §5.2](https://github.com/ascribed-dev/ascribe/blob/main/SPEC.md#52-links)

**When:** `ascribe report links`: the link checker found that an external link answers with an error, doesn't answer in time, or can't be reached. An address that answers with a server error (`5xx`) is asked about again after a short wait, and reported only when it fails again. A host `[checks.links] ignore` names isn't checked.

**Message:** `{url}` answered {status}, so the link is broken for readers

**Fix:** Open the address. When the page is gone, link to where its content went, or remove the link. A site that turns link checkers away, or one that's down for a while, may be fine as it is: acknowledge the link with `@intended {check=link-external-broken}: <why>` directly above its block, or leave the whole host out with `[checks.links] ignore`. Only `ascribe report links` checks external links; `ascribe check` never reaches the network.

**Read more:** [`[checks.links]`](https://ascribed-dev.com/docs/content-model/checks.md#checkslinks) in the `ascribe.toml` reference.

### ASC169 `link-external-moved`

[Advice](https://ascribed-dev.com/docs/checks/diagnostics.md#severity) · [file level](https://ascribed-dev.com/docs/checks/diagnostics.md#file-level-and-page-level) · next step: [choose](https://ascribed-dev.com/docs/checks/diagnostics.md#what-to-do-next) · [configurable](https://ascribed-dev.com/docs/checks/diagnostics.md#setting-a-checks-level) in `[checks]` · [SPEC §5.2](https://github.com/ascribed-dev/ascribe/blob/main/SPEC.md#52-links)

**When:** `ascribe report links`: an external link's address redirects permanently (`301` or `308`) to another one that answers. A site's root that redirects to another of its own pages, a landing page, hasn't moved.

**Message:** `{url}` moved permanently to `{to}`; link to the new address

**Fix:** Link to the address it redirects to; the fix writes it. Check first that it's the page you meant: some sites send every old address to their home page, and then the link needs a new target, not this one. Only `ascribe report links` checks external links.

**Read more:** [`[checks.links]`](https://ascribed-dev.com/docs/content-model/checks.md#checkslinks) in the `ascribe.toml` reference.

## The published site

### ASC170 `delivery-hosting`

[Advice](https://ascribed-dev.com/docs/checks/diagnostics.md#severity) · [file level](https://ascribed-dev.com/docs/checks/diagnostics.md#file-level-and-page-level) · next step: [outside](https://ascribed-dev.com/docs/checks/diagnostics.md#what-to-do-next) · [configurable](https://ascribed-dev.com/docs/checks/diagnostics.md#setting-a-checks-level) in `[checks]` · [SPEC §9.5](https://github.com/ascribed-dev/ascribe/blob/main/SPEC.md#95-consumer-profile)

**When:** `ascribe report delivery`: the published site fails, or warns on, a check of the Web Documentation Delivery Spec that its hosting decides, such as status codes, caching, or content negotiation.

**Message:** the site fails the delivery spec's `{check}` check: {result}. {setting}

**Fix:** Change the setting the message names where the site is hosted; no page needs editing. [Serve the Markdown versions](https://ascribed-dev.com/docs/astro/serve-markdown.md) says what to set on the hosts it names. Only `ascribe report delivery` checks a published site.

**Read more:** [`[consumer]`](https://ascribed-dev.com/docs/content-model/output.md#15-consumer) in the `ascribe.toml` reference.

### ASC171 `delivery-output`

[Advice](https://ascribed-dev.com/docs/checks/diagnostics.md#severity) · [file level](https://ascribed-dev.com/docs/checks/diagnostics.md#file-level-and-page-level) · next step: [outside](https://ascribed-dev.com/docs/checks/diagnostics.md#what-to-do-next) · [configurable](https://ascribed-dev.com/docs/checks/diagnostics.md#setting-a-checks-level) in `[checks]` · [SPEC §9.5](https://github.com/ascribed-dev/ascribe/blob/main/SPEC.md#95-consumer-profile)

**When:** `ascribe report delivery`: the published site fails, or warns on, a check of the Web Documentation Delivery Spec that `llms.txt`, the Markdown pages, or the pointer on each page should pass, which Ascribe writes with `[consumer] agents = true`.

**Message:** the site fails the delivery spec's `{check}` check, which what Ascribe writes should pass: {result}. Report it at {issues}

**Fix:** First check that the site publishes what the build wrote, as it wrote it: `llms.txt` and the Markdown pages from the plain output, and each page's pointer from the site output. When it does, this is a bug in Ascribe: report it at the issue tracker the message names, with the report's output. No page needs editing. When the message says an address couldn't be fetched, the checker got no answer, which may be the network's doing: run the report again, and look into the address only when it keeps failing.

**Read more:** [`[consumer]`](https://ascribed-dev.com/docs/content-model/output.md#15-consumer) in the `ascribe.toml` reference.

## Tested examples

### ASC199 `example-stale`

[Warning](https://ascribed-dev.com/docs/checks/diagnostics.md#severity) · [file level](https://ascribed-dev.com/docs/checks/diagnostics.md#file-level-and-page-level) · next step: [outside](https://ascribed-dev.com/docs/checks/diagnostics.md#what-to-do-next) · [configurable](https://ascribed-dev.com/docs/checks/diagnostics.md#setting-a-checks-level) in `[checks]` · [SPEC §4.8](https://github.com/ascribed-dev/ascribe/blob/main/SPEC.md#48-snippet)

**When:** A `@snippet` shows a file that its source's `ascribe.examples.toml` makes an example, and the file has changed since the observation that lists it was made. For a source in another repository, the config, the observation, and the file are the copies `ascribe sources fetch` made. Reported once for each snippet of the file, whichever region it shows.

**Message:** `{path}` changed after its last test run, so the page doesn't say what it was tested with; run `ascribe observe` in `{folder}` to test it again

**Fix:** Run `ascribe observe` in the folder named, where `ascribe.examples.toml` is, and commit the observation it writes. It runs the folder's test command, and writes the observation only when the command passes. An observation covers a whole file: an edit anywhere in it, even outside the region a page shows, needs a new test run. For a source in another repository, that's done in the code's repository, and `ascribe sources update` copies the new observation here; nothing in this repository runs the test.

**Read more:** [`@snippet`](https://ascribed-dev.com/docs/writing/directives.md#snippet) in the directive reference.

### ASC200 `example-unobserved`

[Advice](https://ascribed-dev.com/docs/checks/diagnostics.md#severity) · [file level](https://ascribed-dev.com/docs/checks/diagnostics.md#file-level-and-page-level) · next step: [outside](https://ascribed-dev.com/docs/checks/diagnostics.md#what-to-do-next) · [configurable](https://ascribed-dev.com/docs/checks/diagnostics.md#setting-a-checks-level) in `[checks]` · [SPEC §4.8](https://github.com/ascribed-dev/ascribe/blob/main/SPEC.md#48-snippet)

**When:** A `@snippet` shows a file that its source's `ascribe.examples.toml` makes an example, and no observation lists the file. For a source in another repository, the config and the observation are the copies `ascribe sources fetch` made. Reported once for each snippet of the file.

**Message:** `{path}` is an example, and no test run has covered it, so the page doesn't say what it was tested with; run `ascribe observe` in `{folder}`

**Fix:** Run `ascribe observe` in the folder named, where `ascribe.examples.toml` is, and commit the observation it writes. When the file isn't meant to be an example, add it to the config's `ignore`, or narrow its `include`. For a source in another repository, both are done in the code's repository, and `ascribe sources update` copies the result here.

**Read more:** [`@snippet`](https://ascribed-dev.com/docs/writing/directives.md#snippet) in the directive reference.

### ASC201 `examples-config-invalid`

[Warning](https://ascribed-dev.com/docs/checks/diagnostics.md#severity) · [file level](https://ascribed-dev.com/docs/checks/diagnostics.md#file-level-and-page-level) · next step: [outside](https://ascribed-dev.com/docs/checks/diagnostics.md#what-to-do-next) · [configurable](https://ascribed-dev.com/docs/checks/diagnostics.md#setting-a-checks-level) in `[checks]` · [SPEC §7.3](https://github.com/ascribed-dev/ascribe/blob/main/SPEC.md#73-sources)

**When:** A source has an `ascribe.examples.toml`, or an observation beside it, that can't be read: in its folder, or, for a source in another repository, in its copies. Reported at the source in ascribe.toml, once for each problem in each file.

**Message:** the examples of source `{source}` can't be checked: `{file}` can't be read: {detail}

**Fix:** Fix the file named, in the source's folder: `ascribe.examples.toml` is written by the code's owners, and an observation by `ascribe observe`, which writes it again when it's run there. Until it can be read, no snippet of the source says what it was tested with.

**Read more:** [`[sources.<name>]`](https://ascribed-dev.com/docs/content-model/sources.md#20-sourcesname) in the `ascribe.toml` reference.

### ASC202 `observation-file-missing`

[Advice](https://ascribed-dev.com/docs/checks/diagnostics.md#severity) · [file level](https://ascribed-dev.com/docs/checks/diagnostics.md#file-level-and-page-level) · next step: [outside](https://ascribed-dev.com/docs/checks/diagnostics.md#what-to-do-next) · [configurable](https://ascribed-dev.com/docs/checks/diagnostics.md#setting-a-checks-level) in `[checks]` · [SPEC §7.3](https://github.com/ascribed-dev/ascribe/blob/main/SPEC.md#73-sources)

**When:** An observation beside the `ascribe.examples.toml` of a source in the same repository lists a file that isn't in the source's folder. Reported at the file's line in the observation, once for each file.

**Message:** `{observation}` lists `{path}`, which isn't in `{folder}`; run `{command}` there to write the observation again

**Fix:** The example was usually deleted or renamed without a second test run. Run the command named, in the folder named, and commit the observation it writes, which lists the examples as they are. When nothing writes the observation any more, delete its file.

**Read more:** [`[sources.<name>]`](https://ascribed-dev.com/docs/content-model/sources.md#20-sourcesname) in the `ascribe.toml` reference.

### ASC285 `examples-config-unread`

[Warning](https://ascribed-dev.com/docs/checks/diagnostics.md#severity) · [file level](https://ascribed-dev.com/docs/checks/diagnostics.md#file-level-and-page-level) · next step: [write](https://ascribed-dev.com/docs/checks/diagnostics.md#what-to-do-next) · [configurable](https://ascribed-dev.com/docs/checks/diagnostics.md#setting-a-checks-level) in `[checks]` · [SPEC §7.3](https://github.com/ascribed-dev/ascribe/blob/main/SPEC.md#73-sources)

**When:** An `ascribe.examples.toml` is in the folder of a source in the same repository, below its root, in a folder the source may read files from, and no source's root holds it, so no source reads it. Reported at the file, once for each.

**Message:** `{file}` is below the root of source `{source}`, `{root}`, and only the `ascribe.examples.toml` at a source's root is read, so no page says what its examples were tested with; declare a source with `path = "{folder}"`, or move the file to `{root}`

**Fix:** Ascribe reads a source's tested examples from the `ascribe.examples.toml` at the root of its `path`, and the observations beside it. To keep the config beside the tests it runs, declare a source whose `path` is the config's folder, and write the snippets of its files with that source's name; the folder can stay inside the other source's too. Or move the config, and its `examples.observations/`, to the root of the source the snippets name, with its `include` and `test` written from there, and run `ascribe observe` there. A folder that holds an `ascribe.toml` is a project of its own, and isn't looked in.

**Read more:** [`[sources.<name>]`](https://ascribed-dev.com/docs/content-model/sources.md#20-sourcesname) in the `ascribe.toml` reference.
