The server never fails on a bad bundle — it works around it and logs, which is easy
to miss (ADR-0029). This is the command that looks on purpose, and it exits non-zero
on anything that makes the site wrong rather than merely untidy.
Fatal: content the engine had to drop (unparseable frontmatter, a key two files
claim, an ignored slug or alias) and links that will 404 for a reader. Warnings:
no title, a figure with no alt text, a series where some members declare order and
others do not — that last one because unordered members sort last, so adding order
to one chapter silently moves every chapter that lacks it.
Two things this needed rather than invented. `Scan` and `Site` now *return* what they
worked around instead of only logging it: `ScanReport` and `Site.Problems`, with
`Scan` staying the logging wrapper so nothing else changed. And required-fields-per-type
is deliberately absent — `title` is the only field the engine requires today, so
checking more would mean inventing the type declaration that is still parked. Its
trigger stays where it was.
The link checker asks the same questions the resolver asks — bundle, alias, section
listing, file inside a bundle — because a checker that guesses differently from the
server is worse than no checker. Engine-owned paths are skipped: they are generated,
not authored.
It lives in internal/ext/check, so cmd/ stays wiring and the feature stays deletable.
Verified against the evidence site: clean before, and five findings across five fault
classes after I introduced them on purpose.