In meiner Homelab-Dokumentation liegen neben den automatisch erzeugten Inventarseiten 242 handgeschriebene Markdown-Dateien. Lange galt für alle Seiten pauschal eine Frist von 30 Tagen, und das Prüfskript meldete null Warnungen, obwohl Dienste längst auf einen anderen Knoten umgezogen waren und in den Runbooks noch der alte Stand stand. Seit Mitte Oktober 2026 hat jeder Seitentyp eine eigene Frist zwischen 21 und 90 Tagen, und Änderungen im Asset-Register markieren verknüpfte Seiten sofort zur Nachprüfung.

Warum 30 Tage für alles nicht reichen
An der Dokumentation arbeiten mehrere Claude-Sitzungen und ich parallel. Als ich am 14. Oktober 2026 den Zustand der Dokumentation geprüft habe, stand der Zähler der Frische-Prüfung bei null Meldungen. Jede handgeschriebene Seite war innerhalb der letzten 30 Tage angefasst worden, also galt alles als aktuell.
In der Praxis stimmte das an mehreren Stellen nicht mehr. Die Verwaltungs-VM war auf Knoten 1 umgezogen und neue Dienste waren dazugekommen, doch die zugehörigen Wiederaufbau-Anleitungen galten weiter als frisch, weil ihre letzte Bearbeitung erst ein paar Tage zurücklag. Umgekehrt ändern sich Konzepte oder eine Zielarchitektur selten im Monatsrhythmus. Eine starre 30-Tage-Grenze führt dort entweder zu Dauerwarnungen oder zu sinnlosen Alibi-Änderungen im Git-Verlauf.
Einen Tag nach der Bestandsaufnahme, am 15. Oktober 2026, habe ich die Prüfung in frische.py umgebaut. Statt einer einzigen Grenze gibt es gestaffelte Fristen nach Verzeichnis und Funktion, ergänzt um einen Abgleich gegen das zentrale Asset-Register.
Vier Fristen nach Seitentyp
Wie schnell eine Seite veraltet, hängt davon ab, wofür ich sie brauche. Eine Einstiegsseite für den Störungsfall muss enger kontrolliert werden als ein abgeschlossenes Netzwerk-Konzept. Der Standard liegt weiter bei 30 Tagen, weicht aber je nach Bereich nach unten oder oben ab:
| Bereich / Dateipfad | Seitentyp | Frist | Begründung aus dem Betrieb |
|---|---|---|---|
betrieb/notfall*.md | Notfalleinstieg | 21 Tage | Erster Anlaufpunkt bei Ausfällen; verweist direkt in die Runbooks |
wiederaufbau/*.md, index.md | Runbooks, Startseite | 30 Tage | Befehle und Reihenfolgen für den Neuaufbau einzelner Systeme |
assets/*.md, betrieb/*.md, uebersicht/*.md | Systemseiten, Abläufe, Pläne | 45 Tage | Laufender Betrieb, Speicher- und Netzübersichten |
bereinigung/*.md, verbesserung/*.md | Konzepte, Umbaupläne, Architektur | 90 Tage | Hintergrund, Entwürfe und längerfristige Umbauten |
Für die beiden Notfallseiten (betrieb/notfall.md und betrieb/notfall-webdienste.md) kommt zur 21-Tage-Frist noch eine zweite Vorgabe aus inventory/fristen.yaml dazu. Auf Knoten 2 liegt zwar täglich eine Offline-Kopie der Dokumentation, aber als Webseite nützt sie nichts, wenn das Netz oder der Server selbst weg ist. Deshalb gibt es eine eigene Druckfassung der Notfallseiten, die vierteljährlich auf Papier ausgedruckt wird.
Nicht in die Frische-Übersicht gehören Seiten, die bei jedem Lauf ohnehin komplett aus Skripten entstehen: das automatische Inventar unter assets/auto/, der Erfassungsstand, die Kennzahlen, der Backup-Status, die Abweichungsseite und das Änderungslog. Beim Umbau am 15. Oktober 2026 ist mir dabei eine Unschärfe durchgerutscht: Weil das zentrale Änderungslog auf 300 KB angewachsen war, habe ich es in einzelne Dateien je Themenbereich unter betrieb/log/ aufgeteilt. Diese erzeugten Logseiten und die Ablage unter betrieb/erledigt/ liegen im Ordner betrieb/ und tauchen deshalb im Moment noch mit 45 Tagen Frist unter den 242 gezählten Seiten auf. Die Ausnahmeliste in frische.py muss ich für diese beiden Unterordner noch nachziehen.
Git-Datum, Prüfvermerk und die Kopplung an assets.yaml
Wenn eine Seite seit sechs Wochen keinen Git-Commit mehr gesehen hat, heißt das noch nicht, dass ihr Inhalt falsch ist. Manchmal lese ich ein Runbook oder eine Systemseite durch, gleiche die Befehle mit dem Server ab und stelle fest, dass jedes Wort stimmt. Früher hätte ich entweder einen künstlichen Commit erzeugen oder die Warnung ignorieren müssen.
Deshalb wertet frische.py für jede handgeschriebene Seite zwei Zeitstempel aus: das Datum der letzten Dateiänderung laut Git und das Datum der letzten inhaltlichen Prüfung aus inventory/seiten-geprueft.yaml. Wer eine Seite gegen das System prüft, ohne den Text zu ändern, trägt dort schlicht das Tagesdatum ein:
# inventory/seiten-geprueft.yaml (Auszug)
wiederaufbau/01-proxmox.md: 2026-10-08
wiederaufbau/02-opnsense.md: 2026-10-08
wiederaufbau/05-haos.md: 2026-10-09
wiederaufbau/10-gitlab.md: 2026-10-09
assets/pbs.md: 2026-10-09
betrieb/notfall.md: 2026-10-08
uebersicht/netzplan.md: 2026-10-08
Für das Alter in Tagen zählt der jüngere der beiden Werte. Überschreitet dieses Alter die Frist des jeweiligen Seitentyps, landet die Seite als rote Zeile in der Frische-Übersicht und auf der Sammel-Seite abweichungen.md.
Das allein löst aber noch nicht den Fall, dass sich ein System ändert, während seine Seite rechnerisch noch jung ist. Dafür sorgt die dritte Quelle: das Asset-Register inventory/assets.yaml. Dort steht für jedes System die Soll-Konfiguration samt Verweis auf seine Dokumentationsseite. Wurde der Eintrag eines Systems in assets.yaml nach der letzten Änderung oder Prüfung der zugehörigen Seite angefasst, markiert frische.py die Seite sofort mit 🔎 Asset seit YYYY-MM-DD geändert und übernimmt sie ebenfalls in die Abweichungen.

In der erzeugten Datei betrieb/frische.md stehen die ältesten Seiten ganz oben. Der Auszug vom 20. Oktober 2026 zeigt, wie die Spalten zusammenwirken:
| Seite | Geändert | Geprüft | Alter (Tage) | Frist |
|------------------------------------|------------|------------|-------------------------------------|-------|
| bereinigung/netzwerkkarte.md | 2026-10-08 | – | 12 | 90 |
| betrieb/smart-selbsttest.md | 2026-10-08 | – | 12 | 45 |
| wiederaufbau/00-voraussetzungen.md | 2026-10-09 | 2026-10-08 | 11 | 30 |
| assets/serverbriga-staging.md | 2026-10-13 | – | 7 🔎 Asset seit 2026-10-18 geändert | 45 |
| wiederaufbau/08-pbs.md | 2026-10-13 | 2026-10-08 | 7 | 30 |
| assets/frigate.md | 2026-10-14 | – | 6 🔎 Asset seit 2026-10-18 geändert | 45 |
| betrieb/notfall.md | 2026-10-20 | 2026-10-08 | 0 | 21 |
242 Seiten, davon 0 über der Frist und 3 zu prüfen.
Obwohl assets/frigate.md und assets/serverbriga-staging.md erst sechs beziehungsweise sieben Tage alt sind und eine Frist von 45 Tagen haben, fallen sie sofort auf, weil sich ihr Registereintrag am 18. Oktober 2026 geändert hat. Ohne die Kopplung an assets.yaml wären beide Seiten noch fast sechs Wochen lang unauffällig geblieben.
Damit Seiten gar nicht erst wegen Zahlen veralten
Eine strenge Altersprüfung nervt schnell, wenn man auf zehn Seiten von Hand IP-Adressen, Gästezahlen oder Plattenbelegungen nachpflegen muss. Seit dem 9. Oktober 2026 gilt in der Dokumentation eine feste Hierarchie, woher Daten stammen dürfen:
- Live-Zustände wie laufende Gäste, Knoten, IP-Adressen, DHCP-Leases, DNS-Einträge und Monitoring-Status lesen ausschließlich die Inventarskripte aus den Systemen.
- Die Soll-Vorgabe (Rolle, Dienste, Soll-Adresse, Backup-Pflicht, Kritikalität, Doku-Link) steht nur einmal in
inventory/assets.yaml. - Jedes Thema hat genau eine Hauptseite; alle anderen Seiten verlinken dorthin, statt Zustände wie den Backup-Status zu kopieren.
- Handgeschriebene Zustandssätze müssen ein Datum tragen (zum Beispiel „Stand 2026-10-08“), während Aussagen ohne Datum nur für dauerhaften Aufbau und Zweck gedacht sind.
Wo im Fließtext oder in Codeblöcken trotzdem konkrete Adressen oder Kennzahlen gebraucht werden, stehen Platzhalter und Kommentar-Marken. Für Adressen und Namen aus dem Register nutzt der MkDocs-Hook hooks/register_platzhalter.py Ausdrücke wie {{ip:ASSET}}, im Fließtext ergänzt um Marken, die scripts/assets_marken.py setzt. Für laufende Zahlen aus dem Inventar schreibt scripts/fakten.py bei jedem Bau die aktuellen Werte in Kommentar-Marken:
<!-- Automatische Fakten-Marke im Markdown -->
Aktuell laufen <!--f:gaeste-->28<!--/f--> Gäste auf <!--f:knoten_online-->3<!--/f--> Knoten.
<!-- Adress-Marke und Platzhalter aus inventory/assets.yaml -->
Webdienst erreichbar unter <!--a:pbs.ip-->192.0.2.51<!--/a--> bzw. ssh root@{{ip:pbs}}
Verstöße gegen diese Regeln sucht scripts/konsistenz.py. Bei der Prüfung am 14. Oktober 2026 meldete das Skript elf Befunde: sieben Seiten hatten noch händische Erledigt-Vermerke im Text (Status gehört ausschließlich in die Doku-Datenbank), auf der Erklärseite zum Asset-Register stand noch eine abgetippte alte Gästezahl, und vier Anker-Links liefen ins Leere. Solche Konsistenzmeldungen erscheinen jetzt als Zähler direkt auf dem Lagebild der Startseite; bleibt eine Meldung zwei Nächte lang stehen, wird daraus eine Aufgabe.
Prüfvermerk und praktischer Test bei Runbooks
Bei den 13 Wiederaufbau-Runbooks hat die Bestandsaufnahme im Oktober eine Grenze von seiten-geprueft.yaml gezeigt: Ein Eintrag dort bestätigt nur, dass jemand den Text gelesen und mit der Konfiguration abgeglichen hat. Ob der Wiederaufbau nach Anleitung im Ernstfall durchläuft, weiß man erst nach einer Probe. Am 14. Oktober 2026 hatte noch keines der 13 Runbooks einen solchen Testvermerk.
Runbooks führen deshalb neben dem Frische-Datum einen eigenen Testvermerk in der Doku-Datenbank, der direkt oben im jeweiligen Runbook eingeblendet wird. Dazu kommt eine kleine monatliche Wiederherstellungsübung mit fester Frist.
Aktualisiert wird die Frische-Übersicht in zwei Takten: Der Nachtlauf (scripts/daily.sh) fragt alle Systeme ohne Zwischenspeicher frisch ab, prüft Fristen und Konsistenz und braucht dafür rund drei Minuten. Tagsüber sorgt seit dem 20. Oktober 2026 ein kleiner Build-Dienst (build_dienst.py per Cron) dafür, dass Änderungen in Git oder in der Datenbank entprellt nach höchstens zwei Minuten im gebauten HTML landen; ein manueller Schnelllauf per UPDATE_SCHNELL=1 scripts/update.sh nutzt das vorhandene Inventar und ist nach 40 bis 50 Sekunden fertig.
Die eigentliche Probe steht noch aus: Bis Mitte November soll das erste Runbook einmal praktisch durchgespielt sein. Erst dann zeigt sich, ob „frisch“ in der Übersicht auch „funktioniert“ bedeutet.
Schreibe einen Kommentar