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.