From 242e839eb67a8c6cb7fd4e67e1db7956e602f8db Mon Sep 17 00:00:00 2001 From: Thore Cimbal Date: Thu, 20 Aug 2026 12:00:00 +0000 Subject: [PATCH] AARs nachgeholt: vier Pflichtfaelle, die ich uebergangen habe roadmap.md verlangt einen AAR nach jedem Deploy mit Uebergabe und nach Incidents. Gestern und heute gab es vier solche Ereignisse - Produktionsausfall durch rc.2, Verlust der DKIM-Eintraege, Game-Host-Deploy ueber zwei Uebergaben, volle Wurzelpartition auf rohana mit gerissenem Spiegel. Geschrieben wurde zunaechst keiner. Der letzte AAR im Repo stammte vom 16.08. Dokumentiert habe ich stattdessen ausfuehrlich IN den Issues. Das ist nicht wertlos, aber es ist nicht der Ort, an dem AGENTS.md die Lehren sucht - und die Folge war messbar: dieselben Fallen wurden an einem Tag mehrfach neu entdeckt. #0040 um eine Rueckmeldung ans Framework ergaenzt: Die Vorgaben wurden dort eingehalten, wo ein Werkzeug widerspricht (validate, gen_status, Spiegel), und uebergangen, wo nur Prosa sie verlangt. Mit Vorschlaegen fuers Refinement - einschliesslich der ehrlichen Alternative, die Definition von Vorfall enger zu fassen statt strenger zu kontrollieren. --- STATUS.md | 7 +- .../2026-08-19-rc2-raumliste-produktion.md | 81 +++++++++++++++++ .../2026-08-20-dkim-verlust-zonenaenderung.md | 72 ++++++++++++++++ docs/aar/2026-08-20-game-host-anbindung.md | 86 +++++++++++++++++++ ...-20-rohana-platte-voll-spiegel-gerissen.md | 84 ++++++++++++++++++ ...040-neckbeard-rueckmeldungen-einreichen.md | 48 +++++++++++ 6 files changed, 376 insertions(+), 2 deletions(-) create mode 100644 docs/aar/2026-08-19-rc2-raumliste-produktion.md create mode 100644 docs/aar/2026-08-20-dkim-verlust-zonenaenderung.md create mode 100644 docs/aar/2026-08-20-game-host-anbindung.md create mode 100644 docs/aar/2026-08-20-rohana-platte-voll-spiegel-gerissen.md diff --git a/STATUS.md b/STATUS.md index 3890c6e..0fab378 100644 --- a/STATUS.md +++ b/STATUS.md @@ -119,6 +119,9 @@ _none active_ | [0022](docs/adr/0022-upstream-anschluss-durch-einmaligen-merge.md) | accepted | ADR-0022: Anschluss an Upstream durch einen einmaligen Merge, nicht durch einen geteilten Graft | | [0023](docs/adr/0023-fremdhistorie-von-der-git-hygiene-ausnehmen.md) | accepted | ADR-0023: Fremde Historie von der Git-Hygiene ausnehmen — erklärt, nicht global | -## Open AARs (0) +## Open AARs (4) -_none — nothing awaiting harvest_ +- [AAR — `v0.6.0-rc.2` brach die Raumliste in Produktion](docs/aar/2026-08-19-rc2-raumliste-produktion.md) +- [AAR — Drei DKIM-Einträge verschwanden bei der DMARC-Härtung](docs/aar/2026-08-20-dkim-verlust-zonenaenderung.md) +- [AAR — Game-Host-Anbindung: Deploy über zwei Übergaben, Ursache war nie die Firewall](docs/aar/2026-08-20-game-host-anbindung.md) +- [AAR — rohana lief voll, der ThreadNet-Web-Spiegel riss](docs/aar/2026-08-20-rohana-platte-voll-spiegel-gerissen.md) diff --git a/docs/aar/2026-08-19-rc2-raumliste-produktion.md b/docs/aar/2026-08-19-rc2-raumliste-produktion.md new file mode 100644 index 0000000..0ff9001 --- /dev/null +++ b/docs/aar/2026-08-19-rc2-raumliste-produktion.md @@ -0,0 +1,81 @@ +--- +type: aar +status: open +date: 2026-08-19 +related: + - "docs/issues/0099-threadnet-web-12-upstream-sicherheitsfixes-lassen-sich-nicht-m.md" + - "docs/adr/0022-upstream-anschluss-durch-einmaligen-merge.md" +--- + +# AAR — `v0.6.0-rc.2` brach die Raumliste in Produktion + +## 1. Was geplant war + +Den Upstream-Anschluss (ADR-0022) an einem echten Client abnehmen. Der Merge war gebaut, +die CI grün, das Image lag in der Registry. Erwartet war: Tag-Bump, sorb prüft ClamAV und +die Call-Teilnehmerliste, fertig. + +## 2. Was geschah + +| Zeit (2026-08-19) | | +|---|---| +| 15:13 | `v0.6.0-rc.2` ausgerollt, `/version` bestätigt | +| ~15:17 | sorb meldet Rageshake, `label = react-soft-crash` | +| 15:2x | Ursache gefunden, Rückrollung auf `v0.5.4` | +| 15:3x | Produktion wieder gesund | + +`RoomListItemViewModel.ts` rief `SettingsStore.getValue("feature_room_list_sections")` auf +einen Labs-Schalter, den Upstream **entfernt** hatte. `getValue` wirft bei unbekanntem +Schlüssel — und zwar bei **jedem** Raumlisteneintrag. Der Client war unbenutzbar. + +Die Zeile war ein Rest meiner Konfliktauflösung: Upstream hatte das Feature samt +`canMoveToSection` gestrichen, ich hatte überall korrekt Upstreams Seite genommen — Menü, +View, Snapshot, Typen — und diese eine `const`-Zeile stehen lassen. Sie wurde tree-weit +von niemandem gelesen. + +## 3. Warum der Unterschied + +**Spec issue, nicht code issue.** Der Fehler war statisch sichtbar: `tsc` meldete ihn +zweifach (`TS2345` unbekannter Schlüssel, `TS6133` ungenutzte Konstante). Er ist nur nie +gefragt worden — der CI-Job `web` führt ausschließlich `pnpm --dir apps/web build` aus. +webpack entfernt Typen, ohne sie zu prüfen; ein unbekannter Einstellungsschlüssel ist zur +Bauzeit bloß ein String. + +Die eigentliche Fehlleistung liegt davor: **Ich habe einen grünen Build als +Korrektheitsaussage weitergegeben.** Er war eine Aussage über Baubarkeit, mehr nicht. + +Dazu eine Blindstelle in ADR-0022 selbst: Sie begründet den Merge damit, dass Git künftig +meldet, wenn Upstream unsere Zeilen wegschiebt. Das hat gehalten. Ein Drei-Wege-Merge +meldet aber **nicht** den umgekehrten Fall — beide Seiten überleben die Auflösung, und nur +eine ergibt noch Sinn. + +## 4. Lehren + +- **Ein grüner Build sagt nichts über Korrektheit**, solange niemand typprüft. Das gilt + für jedes Repo, in dem Bau und Prüfung getrennt sind. +- **Nach einer Konfliktauflösung auf *überlebende* Reste prüfen, nicht nur auf verlorene + Zeilen.** Der billigste Hebel ist die Typprüfung; sie fand beide Reste sofort. +- **Wo Zeichenketten statt Typen im Spiel sind** — Einstellungsschlüssel, Feature-Namen, + Übersetzungs-IDs — reicht die Typprüfung nicht. Dort braucht es einen Abgleich gegen die + jeweilige Registry. Einmalig gefahren: 135 abgefragte gegen 152 registrierte + Einstellungen, genau eine Leiche. +- **Beim Bau einer Prüfung fast derselbe Fehler:** Das erste `grep "error TS"` hätte nie + gegriffen, weil nx auch in der Pipe färbt und zwischen `error` und `TS` eine + Escape-Sequenz steht. Ein Tor, das immer grün ist, ist schlimmer als keines. + +## 5. Maßnahmen + +| Maßnahme | Stand | +|---|---| +| Job `typecheck`, den `docker_web` als `needs` führt | erledigt (`ThreadNet-Web:8ca03fe`) | +| Auf den ganzen Baum ausgeweitet, auch die Desktop-Jobs | erledigt (`ac343e9`) | +| Tor in beide Richtungen belegt (mit Fehler rot, ohne grün, bei leerer Ausgabe rot) | erledigt | +| Verlauf und Lehre in #0099 festgehalten | erledigt | +| `docs/axion1337-fork.md`: Abschnitt „Upstream-Update seit dem Anschluss" | erledigt (`6632ad5`) | + +## 6. Offen + +- Der Maßstab des Tores ist „kein Fehler außerhalb von `node_modules`", weil Upstream + v1.12.26 selbst nicht typrein ist (`matrix-js-sdk@42.2.0`, drei Fehler in der eigenen + Quelle). Fällt das bei einem Upstream-Wechsel weg, verschärft sich der Job von allein. +- Unit-Tests laufen weiterhin in **keiner** Pipeline. Das Tor prüft Typen, nicht Verhalten. diff --git a/docs/aar/2026-08-20-dkim-verlust-zonenaenderung.md b/docs/aar/2026-08-20-dkim-verlust-zonenaenderung.md new file mode 100644 index 0000000..e427701 --- /dev/null +++ b/docs/aar/2026-08-20-dkim-verlust-zonenaenderung.md @@ -0,0 +1,72 @@ +--- +type: aar +status: open +date: 2026-08-20 +related: + - "docs/issues/0102-dmarc-und-mail-haertung-der-zone-axion1337-chat.md" +--- + +# AAR — Drei DKIM-Einträge verschwanden bei der DMARC-Härtung + +## 1. Was geplant war + +`_dmarc.axion1337.chat` vom geteilten IONOS-CNAME (`p=none`) auf einen eigenen TXT-Record +mit `p=quarantine` umstellen und die sieben Service-Namen mit Null-MX und `-all` +stilllegen (#0102). Erwartete Wirkung: gefälschte Mail wird abgewiesen, echte nicht. + +## 2. Was geschah + +Die Einträge wurden gesetzt und waren korrekt. Bei der Gegenprobe fehlten jedoch **alle +drei DKIM-Selektoren** der Zone (`s1-ionos`, `s2-ionos`, `s42582890`) — NXDOMAIN bei zwei +unabhängigen DoH-Anbietern, für CNAME und TXT. Vierzig Minuten zuvor waren sie noch +gemessen worden. + +Nach erneutem Aktivieren lösen `s1-ionos` und `s2-ionos` wieder bis zum Schlüssel auf +(403 Zeichen). Der dritte zeigt auf ein Ziel, das IONOS selbst nicht veröffentlicht — +folgenlos, weil mit `s1`/`s2` signiert wird. + +## 3. Warum der Unterschied + +**Intent issue.** Bei der Bearbeitung der Zone gingen Einträge verloren, die niemand +anfassen wollte. Die Auftragsbeschreibung nannte vier Einträge; dass eine Zonen-Bearbeitung +benachbarte Records mitnehmen kann, stand nirgends — und es gab kein Werkzeug, das +widersprochen hätte. + +Verschärfend: **Der Verlust wäre nicht aufgefallen.** Direkte Zustellung besteht DMARC über +SPF-Ausrichtung — Authentik sendet über IONOS-SMTP, Absender- und Header-Domain stimmen +überein. Erst bei **Weiterleitungen** bricht SPF, und ohne DKIM gibt es keinen Rückfall. +Mit `p=quarantine` landet solche Mail dann im Spam: kein Ausfall, keine Fehlermeldung, nur +Nutzer, die nichts bekommen. + +## 4. Lehren + +- **Nach jeder Zonen-Bearbeitung die ganze Zone gegenprüfen, nicht nur die geänderten + Einträge.** Derselbe Vorfall in anderer Form: `mrtc`-A-Record, 2026-08-16 (eigener AAR). + Zweimal dieselbe Klasse in vier Tagen. +- **Ein vorhandener CNAME belegt nichts.** `s42582890` zeigt ins Leere. Prüfungen müssen + bis zum **Schlüssel** auflösen. +- ⚠️ **Im Lab wird Port 53 abgefangen.** Eine Anfrage an `192.0.2.99` (TEST-NET, kann nicht + antworten) liefert ein Ergebnis. Vier vermeintlich autoritative `dig`-Messungen zeigten + deshalb einen längst überholten Stand — beinahe wäre daraus die Meldung „der Record ist + gar nicht angekommen" geworden. **Belastbar ist von innen nur DoH über HTTPS.** +- **Berichtsadressen gehören in dieselbe Zone.** Ein `rua=` auf eine fremde Domain braucht + zusätzlich `._report._dmarc.`; ohne den senden die meisten Empfänger + stillschweigend gar nichts — und ausbleibende Berichte sehen aus wie „keine Probleme". + +## 5. Maßnahmen + +| Maßnahme | Stand | +|---|---| +| DKIM wieder aktiviert, `s1`/`s2` lösen bis zum Schlüssel auf | erledigt | +| `pruefe-dns.sh` prüft DKIM — bis zum Schlüssel, nicht bis zum CNAME | erledigt (`notfallhandbuch:b6ee7fd`) | +| `pruefe-dns.sh` warnt **vor** seinen Messungen, wenn Port 53 abgefangen wird | erledigt | +| `dns-soll.md`: Soll-Stand für DMARC und die sieben Service-Namen | erledigt (`91d7106`) | +| `dns-soll.md`: Falschangabe korrigiert (Wartungsmeldungen senden unter `.de`) | erledigt | +| Abnahme: Authentik-Testmail kam nachweislich an | erledigt | + +## 6. Offen + +- `fo=1` im DMARC-Record ist wirkungslos, weil kein `ruf=` gesetzt ist. +- `axion1337.de` trägt `p=reject` **ohne `rua=`** — dort greift die Regel, aber niemand + sieht ihre Wirkung. +- Nach Auswertung der ersten Berichte: `p=quarantine` → `p=reject`. diff --git a/docs/aar/2026-08-20-game-host-anbindung.md b/docs/aar/2026-08-20-game-host-anbindung.md new file mode 100644 index 0000000..23112fb --- /dev/null +++ b/docs/aar/2026-08-20-game-host-anbindung.md @@ -0,0 +1,86 @@ +--- +type: aar +status: open +date: 2026-08-20 +related: + - "docs/issues/0002-game-01-host-von-cfgmon-aus-nicht-erreichbar-2.md" + - "docs/issues/0083-gitops-50-monitoring-deploy-geaenderte-configs-greifen.md" +--- + +# AAR — Game-Host-Anbindung: Deploy über zwei Übergaben, Ursache war nie die Firewall + +## 1. Was geplant war + +Zwei Scrape-Targets waren seit dem ersten Scrape nie `up` (#0002, seit 2026-08-01). Das +Issue nannte die Hetzner-Cloud-Firewall als wahrscheinliche Ursache und empfahl, den Host +in den vSwitch aufzunehmen. Geplant war: Targets auf die private Adresse umstellen, fertig. + +## 2. Was geschah + +Der Host **war** längst im vSwitch (`10.0.0.4`, Ports 22/80/443 offen). Trotzdem +antworteten die Exporter nicht. `docker ps` zeigte den Grund: + +``` +node-exporter … 9100/tcp ← kein 0.0.0.0-Mapping +cadvisor … 8080/tcp ← ebenso +``` + +**Die Ports waren gar nicht veröffentlicht** — die Exporter waren nur im Docker-Netz +erreichbar. Über die öffentliche IP hätten sie nie geantwortet, mit oder ohne Firewall. + +Nebenbefund: Auf dem Host liefen **zwei** Sammler-Sätze und ein vollständiger eigener +Prometheus/Grafana/Loki-Stack, in den niemand hineinsah. + +Der Deploy lief über **zwei Übergaben in beide Richtungen**: eine an den +Game-Host-Betreiber (Rückbau auf reine Sammler), eine zurück (zentrale Seite). Beide nach +`.gitlab/issue_templates/Deploy-Übergabe.md`. + +## 3. Warum der Unterschied + +**Spec issue.** Die Vermutung „Firewall" stand seit dem 01.08. unwidersprochen im Issue +und wurde nie gegen den Host geprüft — es hatte niemand `docker ps` gelesen. Die +Eingrenzung von damals (Ports 22/8080/9100 im Timeout, kein Refused) war korrekt gemessen, +aber falsch gedeutet: Ein Paketfilter *und* ein nicht veröffentlichter Port sehen von +außen gleich aus. + +Zweiter Fund derselben Klasse: Der Exporter auf `9531` hat **drei Monate lang nie eine +Metrik geliefert** (Client-API mit Application-Key über http). Das zugehörige Dashboard war +seit jeher leer — und niemandem ist es aufgefallen, weil niemand geprüft hat, ob seine +Metriken überhaupt existieren. + +## 4. Lehren + +- **Ein leeres Dashboard ist ein Befund, kein Zustand.** Wer eines anlegt, prüft seine + Queries gegen die laufende Instanz — sonst steht dort jahrelang nichts, ohne dass es + jemand merkt. +- **Von außen gemessene Symptome erlauben mehrere Ursachen.** „Port antwortet nicht" + unterscheidet nicht zwischen Filter, fehlender Veröffentlichung und totem Dienst. Erst + ein Blick auf den Host trennt das. +- **`metric_relabel_configs` gehören dem scrapenden Prometheus.** Baut man einen lokalen + Stack zurück, wandert dessen Label-Konzept mit — sonst fällt es ersatzlos weg. +- ⚠️ **Der Entwicklungstunnel führt bei `cfgmon.lab:9090` und `:3100` auf eine ANDERE + Maschine.** Der operating-Stack ist von außen nur aus dem matrix-Cluster über + `10.0.0.3` erreichbar. Das hat an diesem Tag zwei Diagnosen ins Leere laufen lassen, + einmal beim Monitoring und einmal beim DNS. +- **`--force-recreate` ist für Prometheus überholt** — das Verzeichnis wird gemountet. + Beide Übergaben trugen die Anweisung aus #0083 veraltet weiter. + +## 5. Maßnahmen + +| Maßnahme | Stand | +|---|---| +| Targets auf `10.0.0.4`, cadvisor auf 8081 (8080 von coolify-proxy belegt) | erledigt (`threadnet-operating:a07c6ed`) | +| `gameserver-rules.yml`: Join Container-UUID → Klarname | erledigt | +| Dashboard neu gebaut, alle 11 Queries vorab gegen Prometheus geprüft | erledigt (`fa26393`) | +| Die letzten fünf Einzeldatei-Mounts auf Verzeichnisse (#0083) | erledigt (`7b25b6e`) | +| #0002 geschlossen, #0083 mit dem tatsächlichen Reststand fortgeschrieben | erledigt | + +## 6. Offen + +- `matrix/flux2.json` ist teilweise leer: Es nutzt `gotk_reconcile_condition` und + `gotk_suspend_status`, die es in dieser Flux-Fassung nicht mehr gibt. Unabhängig von + diesem Vorgang, eigener Befund. +- Der `ptla_`-Key des alten Exporters kann rotiert und gelöscht werden — er wird nirgends + mehr gebraucht. Liegt beim Game-Host-Betreiber. +- Einmalig nötig auf CFGMON: `docker compose up -d --force-recreate loki alloy + matrix-alerts release-watch cve-exporter`, damit die neuen Verzeichnis-Mounts greifen. diff --git a/docs/aar/2026-08-20-rohana-platte-voll-spiegel-gerissen.md b/docs/aar/2026-08-20-rohana-platte-voll-spiegel-gerissen.md new file mode 100644 index 0000000..da00557 --- /dev/null +++ b/docs/aar/2026-08-20-rohana-platte-voll-spiegel-gerissen.md @@ -0,0 +1,84 @@ +--- +type: aar +status: open +date: 2026-08-20 +related: + - "docs/issues/0099-threadnet-web-12-upstream-sicherheitsfixes-lassen-sich-nicht-m.md" + - "docs/adr/0023-fremdhistorie-von-der-git-hygiene-ausnehmen.md" +--- + +# AAR — rohana lief voll, der ThreadNet-Web-Spiegel riss + +## 1. Was geplant war + +Nach dem Upstream-Merge sollte der Push-Mirror den neuen Stand nach Gitea tragen — ein +Vorgang, der bis dahin unbemerkt lief. + +## 2. Was geschah + +Der Spiegel scheiterte reproduzierbar. Der Erstschub trägt **70.269 Commits und rund +600 MB**; der Worker bricht mit `HTTP 499` ab. Ich habe daraufhin von Hand in Etappen +gepusht — mit sorbs ausdrücklicher Freigabe, weil „nie direkt nach Gitea" sonst gilt. + +Der Verlauf war zäh und meine Diagnosen zweimal falsch: + +| Annahme | Widerlegt durch | +|---|---| +| „zu große Pakete, also stückeln" | ein Push mit **6 Objekten** scheiterte ebenfalls | +| „festes Zeitlimit von ~60 s" | ein Push über **95 s** lief durch | + +Die tatsächliche Ursache: **Das Ziel-Repo war auf 9,6 GB aufgebläht** (lokal 649 MB), voll +mit Rückständen jedes abgebrochenen Pushs — meine eingeschlossen. Jeder Push zahlte die +Erreichbarkeitsprüfung über diesen Haufen, unabhängig von seiner Nutzlast. + +Verschärfend: Die **Wurzelpartition von rohana war zu 100 % voll** (37 GB von 39 GB, 262 MB +frei). Damit konnte auch `git gc` nicht mehr durchlaufen — die Reparatur scheiterte an dem +Zustand, den sie beheben sollte. + +Nach Aufräumen und sauberem Repack (Repo auf 451 MB) liefen die Etappen durch. Auffällig +dabei: Derselbe Schritt scheiterte im ersten Versuch nach 3.734 Sekunden und gelang im +zweiten in **einer** Sekunde. + +## 3. Warum der Unterschied + +**Intent issue.** ADR-0022 hat die Folgen des Merges für die *Historie* durchdacht, nicht +die für die *Infrastruktur*. Dass ein Spiegel 70.000 fremde Commits in einem Zug +übertragen muss und dass das Ziel-Repo dafür in gutem Zustand sein muss, stand in keiner +Entscheidung. + +Mein eigener Beitrag: Ich habe nach dem ersten Fehlschlag **dreimal mit großen Paketen +weiterprobiert**, statt zuerst den Zustand der Gegenseite zu messen. Jeder dieser Versuche +hat den Müllberg vergrößert. + +## 4. Lehren + +- **Vor einem großen Push den Zustand des Ziels messen**, nicht nur die eigene Seite: + `count-objects -vH`, freier Platz. Ein Spiegel, der seit Monaten nie repackt wurde, ist + kein passives Ziel. +- **Bei sporadischer Serverlast ist wiederholen die richtige Antwort, nicht verkleinern.** + Mit Halbieren wäre der Lauf nie fertig geworden. +- **Wiederholte Fehlschläge hinterlassen Spuren.** Ein abgebrochener Git-Push ist nicht + folgenlos — er lädt Objekte hoch, die niemand referenziert und niemand aufräumt. +- **`git gc` braucht freien Platz.** Auf einer vollen Platte ist es kein Ausweg. +- ⚠️ **rohana trägt Gitea UND die Container-Registry.** Eine volle Platte dort heißt: kein + neues Image, kein Release. Dass währenddessen nichts ausfiel, war Glück — die Images + wurden vorher gepusht. + +## 5. Maßnahmen + +| Maßnahme | Stand | +|---|---| +| Platte aufgeräumt, Repo repackt (9,6 GB → 451 MB) | erledigt (sorb) | +| Spiegel wieder gleichauf, `main` = `8ca03fe`, gegengeprüft | erledigt | +| Spiegel-Worker trägt seither wieder von selbst nach | belegt am Doku-Push `6632ad5` | +| ADR-0023: fremde Historie von der Git-Hygiene ausnehmen | erledigt | + +## 6. Offen + +- **Kein Alarm auf freien Plattenplatz von rohana.** Der Host wird nicht überwacht — die + Fülle fiel nur auf, weil ein Push scheiterte. `HostLowDisk` existiert in + `alerts.yml`, deckt aber nur die Hosts ab, die Metriken liefern. +- Ob weitere Repos auf rohana in schlechtem Pack-Zustand sind, ist ungeprüft. +- Die Frage, ob der Spiegel die **volle** Upstream-Historie tragen muss oder ein + Stand ab dem Merge-Commit genügt, ist offen. Sie entscheidet, ob dieser Vorfall + wiederkommt. diff --git a/docs/issues/0040-neckbeard-rueckmeldungen-einreichen.md b/docs/issues/0040-neckbeard-rueckmeldungen-einreichen.md index 50e91d4..7c66cf6 100644 --- a/docs/issues/0040-neckbeard-rueckmeldungen-einreichen.md +++ b/docs/issues/0040-neckbeard-rueckmeldungen-einreichen.md @@ -33,3 +33,51 @@ mit Feldtest-Evidenz aus Gate 2 des Design-Dokuments: 10. ADR-Pflicht bei dauerhaften Ausnahmen fehlt upstream 11. Stillstandsprüfungs-Prinzipien als Muster für eine Laufzeit-Prüf-Familie neben validate.py + +## Rückmeldung 2026-08-20 — der Prozess hält nicht von allein + +Aus einer langen Arbeitssitzung (Upstream-Anschluss, Game-Host-Anbindung, DMARC-Härtung, +Egress-Rückbau). Sorbs Beobachtung, und sie trifft zu: **Die Vorgaben wurden eingehalten, +wo ein Werkzeug sie erzwingt, und übergangen, wo nur Prosa sie verlangt.** + +### Der Befund + +`roadmap.md` schreibt vor: *„AAR nach jedem Deploy mit Übergabe und nach Incidents."* +An diesem und dem Vortag gab es **vier** AAR-pflichtige Ereignisse — ein +Produktionsausfall, ein Verlust von DKIM-Einträgen, ein Deploy über zwei Übergaben und +eine volle Wurzelpartition mit gerissenem Spiegel. Geschrieben wurde zunächst **keiner**. +Nachgeholt erst auf Zuruf. + +Dagegen wurde **kein einziges Mal** vergessen: Frontmatter nach `schema.yaml`, `STATUS.md` +neu erzeugen, Issues spiegeln, Commit-Konvention. Der Unterschied ist nicht Sorgfalt, +sondern **wer widerspricht**: `validate.py` und `gen_status.py --check` färben die Pipeline +rot. Der AAR-Pflicht widerspricht niemand. + +### Warum das mehr als Buchhaltung ist + +AGENTS.md sagt: *„Before proposing options, read the relevant ADRs and AARs first — past +decisions and learnings are input, not trivia."* Wenn Erkenntnisse nur als Anhänge in +einzelnen Issues liegen, stehen sie nicht dort, wo das Verfahren sie sucht. + +Die Folge war an diesem Tag messbar: Dieselben Fallen wurden **mehrfach neu entdeckt** — +dass der Entwicklungstunnel bei `cfgmon.lab` auf eine andere Maschine zeigt (zweimal), und +dreimal ein eigenes Messwerkzeug, das stillschweigend Unsinn lieferte (`grep` gegen +Farbcodes, `/dev/tcp` in dash, `dig` gegen einen abgefangenen Port 53). Zeit, die zweimal +bezahlt wurde. + +### Vorschläge fürs Refinement + +1. **`gen_status.py` zeigt offene AARs bereits an** — aber nichts prüft, ob es *fehlende* + gibt. Denkbar: eine Prüfung, die Deploy-Übergabe-Issues und geschlossene Vorfälle ohne + zugehörigen AAR meldet. Sie bräuchte eine Kennzeichnung, was als Vorfall gilt. +2. **Vorfall als eigener Status oder eigenes Feld am Issue.** Heute lässt sich nicht + maschinell erkennen, dass #0099 einen Produktionsausfall enthielt. +3. **Die Kadenz-Regel steht in `roadmap.md`, nicht in AGENTS.md.** Wer AGENTS.md liest — + und darauf verweist jedes `CLAUDE.md` — findet die AAR-Pflicht nicht. +4. **Ehrliche Alternative:** Wenn eine Regel dauerhaft nur bei Nachfrage befolgt wird, ist + auch zu prüfen, ob sie in dieser Form richtig ist. Vier AARs an einem Tag sind viel; + vielleicht braucht es eine engere Definition von „Vorfall" statt strengerer Kontrolle. + +⚠️ Diese Rückmeldung stammt von der Seite, die den Prozess gebrochen hat. Sie ist kein +Beleg dafür, dass die Regel schlecht ist — nur dafür, dass sie sich ohne Werkzeug nicht +durchsetzt.