Was der Build prüft
Die stillen Fehlschläge dieser Ebene, in Meldungen verwandelt.
Jeder Fehler, den diese Ebene tatsächlich hatte, war lautlos: eine Collection, die Content verwarf, weil ihr Name kein JavaScript-Bezeichner war; eine Seite, die 404te, weil ein Link veraltet war; eine Navigation, die leer zurückkam. Keiner der drei sagte etwas — der Build war grün und die Seite falsch. Also laufen nach dem Build Prüfungen, die alle dasselbe lesen: den Parse-Cache, den Content hinterlässt.
| Prüfung | Schweregrad |
|---|---|
| Eine Collection ohne Seiten | Fehler |
| Ein Ordner, der mit einem URL-Segment kollidiert | Fehler |
Ein fehlender title oder description | Warnung |
| Ein toter interner Link oder Anker | Warnung |
| Was eine generierte Sektion nicht lesen konnte | Warnung |
| Was jede Sprache trägt und was stehen geblieben ist | Hinweis |
Warum der Schweregrad nicht einheitlich ist
Ein Fehler kostet eine Seite, die niemand erreichen kann und die nichts auf der Website je erklären würde — eine leere Collection ist ein 404 auf jeder Seite einer Version. Eine Warnung kostet Qualität: Die Seite rendert weiterhin, und eine entfernte Quelle kann zwischen zwei Releases veralten, ohne dass das die Schuld dieses Builds wäre. Den Build scheitern zu lassen, weil das Repository eines anderen weitergezogen ist, würde einen grünen Build von einem Dritten abhängig machen.
Ein Hinweis kostet gar nichts: Er ist ein Zustand der Website, kein Mangel an ihr. Eine unübersetzte Seite ist kein Fehler, und sie als Warnung zu melden würde allen beibringen, über die Warnungen hinwegzulesen.
Generierte Sektionen
Eine generierte Sektion wird geprüft wie jede andere Collection, in ihren eigenen Worten. Was in diesem Bericht landet, ist eines von drei Dingen:
- Das Artefakt war an diesem Ref nicht da, die Sektion wurde also nicht gebaut;
- der Typ hat nichts daraus gelesen, die Sektion beansprucht also URLs und liefert keine aus;
- der Typ ist über etwas hinweggegangen — ein nicht auflösbares
$refin einem OpenAPI-Dokument, eine Changelog-Überschrift, die wie ein Release aussieht, sich aber nicht als eines parsen lässt und deshalb Teil des Releases darüber wurde.
Alle drei sind Warnungen, und das ist kein Kompromiss. Alles, was ein lokales Artefakt falsch machen kann — ein Pfad, der nicht da ist, eine Datei, die der Typ überhaupt nicht lesen kann, eine Option, die er nicht kennt —, lässt den Build bereits beim Laden der Konfiguration scheitern, lange bevor es diesen Bericht gibt: Die eigene Konfiguration der Website ist ein Fehler, den der Build nicht mittragen darf. Was hier übrig bleibt, ist entweder ein entferntes Artefakt, das zwischen zwei Releases legitim veraltet sein kann, oder eine Seite, die gerendert wurde und in der etwas fehlt.
Ein Artefakt wird beim Laden der Konfiguration geparst, eine Warnung über ein
verworfenes $ref wurde also gedruckt, bevor der Dev-Server fertig gestartet
war, und war weggescrollt, wenn jemand hinsah — während jeder andere Befund
dieser Ebene in einem Bericht wartete. Sie kommen jetzt über den Bericht, und mit
ihm über das Panel Prüfungen.
Der Übersetzungsbericht
Eine Zeile je Sprache, in jedem Build:
[duxt] translations
[duxt] de: 118/121 pages, 3 behind the original
[duxt] "docs/guides/deploying.md" has no de translation.
[duxt] "docs/de/concepts/sources.md" has not moved since the original changed.
Die zweite Zahl braucht history: true an der Quelle — die Daten kommen aus
git, und eine Quelle, die ihre Historie nicht angefordert hat, hat keine. Ohne
sie zählt der Bericht die Abdeckung und sagt nichts über Veralten, statt aus
dem Fehlen zu raten.
Es gibt ihn wegen eines konkreten Fehlschlags. OpenCode übersetzte seine Dokumentation mit einem Agenten in CI in siebzehn Sprachen, schaltete den Workflow ab, und nirgends stand, dass die Übersetzungen sich nicht mehr bewegten. Die Ebene weiß pro Seite ohnehin, welche Sprachen sie tragen und wann jede Datei sich zuletzt geändert hat; ein Bericht macht daraus etwas, das jemand sieht.
Derselbe Bericht als Befehl
Die Befunde liegen an zwei Orten, die sich schlecht jemandem in die Hand drücken
lassen: in einem Build-Log, das weggescrollt ist, und in Devtools-Panels, die es
nur in einem laufenden Dev-Server gibt. duxt-report ist der dritte — dieselben
Daten als Markdown auf stdout. Er kommt mit dem Paket, die Ebene zu erweitern
ist also alles, was es dafür braucht.
pnpm exec duxt-report # Markdown
pnpm exec duxt-report --json # the same data, unrendered
Er liest die app.config.ts der Website, die Artefakte daneben und die Seiten
aus dem Parse-Cache von Content — kein Server, er läuft also in CI und in
einer Pipe. Er endet mit 1 bei einem Fehler und mit 0 bei Warnungen, also
nach derselben Schweregradregel, der auch der Build folgt.
Drei Panels haben hier keine Entsprechung, und das mit Absicht: Der Suchindex, der Pfad-Debugger und die Cache-Auflistung sind Fragen an einen laufenden Prozess, und sie von außen zu beantworten hieße raten.
Die Seiten kommen aus dem Cache von Content, eine Seite, die seit dem letzten Build- oder Dev-Lauf geschrieben wurde, steht also nicht darin. Lass zuerst einen von beiden laufen — der Bericht sagt das deutlich, wenn er gar keinen Cache findet, statt jede Collection als leer zu melden.
Was die Prüfungen wissen und du nicht
- Eine Ordnerkollision ist nur ein Problem, solange ein Präfix aktiv ist. Ein
Doku-Ordner namens
v2ist auf einer unversionierten Seite in Ordnung und auf einer versionierten unerreichbar, weil das Präfix gewinnt. Der Build weiß, welcher Fall vorliegt, und die Meldung benennt die Datei und bietet die Lösung an. - Ein Link wird so aufgelöst, wie das Theme ihn auflöst. Ein absoluter Pfad in einer Seite ist relativ zur eigenen Quelle dieser Seite, wird also zuerst unter dem Präfix der Quelle probiert und danach nackt. Eine Prüfung, die nur die nackte Form kennt, würde auf einer Multi-Repo-Seite jeden korrekten Link melden.
- Ein Link wird in seiner eigenen Sprache aufgelöst. Jede Sprache einer Quelle liefert identische Inhaltspfade — die Locale steht vor der URL, nicht im Inhaltsbaum —, und Anker werden aus dem Überschriftentext abgeleitet, eine deutsche Überschrift hat also einen deutschen Anker. Eine Prüfung, die nur über den Pfad auflöst, würde einen deutschen Link gegen englische Überschriften prüfen und auf einer übersetzten Seite jeden korrekten Anker melden. Ein Link auf eine Seite, die eine Sprache nicht trägt, fällt auf das Original zurück — genau wie die Website selbst.
- Externe URLs werden nicht geprüft. Eine zu verifizieren hieße, das Netz in den Build zu holen, und ein nicht erreichbarer fremder Host ist kein Grund, warum deine Dokumentation nicht ausgeliefert wird.
Schreibe Links als absolute Dokumentationspfade
/concepts/sources, nicht ../2.concepts/2.sources.md. Unter welchem Präfix
eine Seite ausgeliefert wird, entscheidet sich zur Build-Zeit — Pfade ohne
Präfix zu schreiben ist deshalb genau das, was dasselbe Markdown auf einer Seite
/guides/deploying und auf einer anderen /acme/v2.0.0/guides/deploying
bedienen lässt. Es ist außerdem die einzige Form, die die Linkprüfung sieht.