Zum Hauptinhalt springen

agents.md — Konventionen für KI-Agenten und Coding-Agenten

Dieses Dokument beschreibt, wie ein KI-Agent (Claude, Codex, Cursor, Continue, etc.) in diesem Repo arbeitet. Es ist verbindlich für jede Session und sollte beim Start jeder neuen Konversation mitgelesen werden — typischerweise zusammen mit HANDOFF.md. Es ist unsere "Way of Working" und wird laufend aktuell gehalten: ändert sich, wie wir zusammenarbeiten, landet es hier (kein paralleles Prozess-Doc — Decision-Sprawl vermeiden).


1. Repo-Philosophie: "Everything as Code"​

Alle Artefakte des Projekts leben im Repo: Spezifikation, Entscheidungen, Architektur, Code, Diagramme, Konventionen. Nichts Überlebenswertes verbleibt im flüchtigen Konversations-Verlauf oder im Session-Memory einer einzelnen Agenten-Instanz.

Konsequenzen:

  • GitHub drkv-com/medidentas ist die einzige Quelle der Wahrheit.
  • Eine neue Session startet nicht "bei null" — sie liest HANDOFF.md, docs/fachlich/Lastenheft.md und dieses Dokument und ist sofort im Kontext.
  • Wenn etwas entschieden wird, landet es als Commit im Repo, bevor die Konversation endet.

2. Doku-Format: Markdown + Mermaid (kein .docx, kein .pdf)​

Regel: Alle versionierten Dokumente sind .md mit Inline-Mermaid für Diagramme. Keine binären Formate (.docx, .pdf, .pptx, .xlsx) als Master-Quelle. Falls ein externer Stakeholder PDF/Word braucht, kann es bei Bedarf aus dem .md exportiert werden (pandoc, Mermaid-CLI für SVG).

Begründung: Git-diffbar, reviewable, mergeable; Diagramme als Code (Mermaid) sind genauso versioniert wie der Prosa-Text; Coding-Agenten können .md direkt lesen, ändern und Diffs erzeugen; keine Tooling-Abhängigkeit.

Mermaid-Typen, die wir im Repo verwenden:

TypWofür
flowchartUse-Cases, Architektur, Prozess-Logik
erDiagramDatenmodell, Entitäts-Beziehungen
stateDiagram-v2Lifecycle (Mandant, Dokument, Unterschrift)
sequenceDiagramInteraktionen (NextCloud-Upload, Signatur-Webhook)
ganttzeitliche Abläufe (Wiedervorlagen, Fristen)

Anführungszeichen: immer gerade ("/'), nie typografisch. Alle .md-Dokumente nutzen ausschließlich gerade Anführungszeichen ("…", '…') — kein deutsches „…", kein «…», keine kurvigen "…"/'…'. Grund: der historische Bestand mischte „…" (öffnend typografisch, schließend gerade) mit vereinzelt korrektem „…" und löste damit wiederholt CodeRabbits Typografie-Nitpicks aus (MED-D-145) — ein einheitliches, gerades Zeichen ist eindeutig zu matchen und tool-stabil. Ausnahme: technische Platzhalter-Notation wie ‹Variable› in Dentmarking-Excel-Logik.md (Excel-Formel-Konvention, kein Zitat) bleibt unangetastet. .coderabbit.yaml weist CodeRabbit über path_instructions explizit an, gerade Anführungszeichen nicht zu bemängeln.

3. Identifikator-System​

Jede Entscheidung, jedes Feld, jede Empfehlung, jeder offene Punkt hat eine kurze stabile ID. Diese IDs sind über das gesamte Repo durchsuchbar und werden in Commits, PRs, Issues, Chats referenziert.

PräfixBedeutungQuelle
G-nGlobales PrinzipCLAUDE.md / Lastenheft §3
RxModul (R1 Mandant, R2 Onboarding, …)Lastenheft §4–5
Rx-F##Feld einer EntitätLastenheft Tabellen
A-nArchitektur-EntscheidungLastenheft §9 / docs/architektur/
S-nVereinfachungLastenheft §10
UC-xKern-Use-CaseLastenheft §2
OP-<Thema>-nOffener Punkt (z. B. OP-SIGN-1, OP-STACK-1) — Alt-IDs; neu: GitHub-Issue #n (MED-D-359)Lastenheft §11 / GitHub-Issues
FR-nFuture-Release-NoteLastenheft §12
<TOOL>-nAnforderung eines Spezial-Tools (tool-scoped, z. B. DEX-n für Dexman)docs/spezialtools/<Tool>.md
D-nChronologische Entscheidung (Audit-Trail)docs/betrieb/Decision-Log.md
RISK-nRisiko (Technik/Sicherheit/Datenschutz/Regulatorik)docs/betrieb/Risikoregister.md
KB-nKunden-Besprechungspunkt (vor dem Bau zu klären) — Alt-IDs; neu: GitHub-Issue #n mit Label fachliche-bestätigung (MED-D-659)docs/betrieb/Kunden-Besprechungspunkte.md (eingefroren) / GitHub-Issues

Projekt-Kürzel MED (verbindlich, ab MED-D-51): neu vergebene IDs sowie Chat-/Session-Namen tragen das Präfix MED- (z. B. MED-D-51, MED-OP-<Thema>-n, Session-ID MED-<Datum>-<branch-slug>). Bestehende IDs werden nicht retroaktiv umbenannt — Alt- und Neu-Bestand koexistieren bewusst; eine Alt-ID wird erst mitgezogen, wenn ihre Zeile inhaltlich angefasst wird. (Beschlossen als MED-D-51.)

Repo-übergreifende IDs (Repo-Key-Registry, MED-D-57): Für repo-übergreifende Referenzen wird eine ID mit dem Repo-Key qualifiziert (analog GitHubs owner/repo#123): taktano → TKT (TKT-OP-CI-2) · medidentas → MED (MED-OP-SIGN-1) · gh-self-hosted-runners-director (gh-runner-manager) → GRM (GRM-OP-2). Der medidentas-Key MED ist zugleich das stehende Präfix neuer medidentas-IDs (MED-D-51 oben) — neue IDs sind hier ohnehin MED-…; die Registry ergänzt die Fremd-Repo-Keys TKT/GRM und hält die drei Keys projektweit konsistent. Bestehende bare Alt-IDs bleiben unverändert (keine Massen-Umbenennung); parallel verankert in taktano (docs/konventionen/IDs.md) und gh-runner-manager (docs/open-points.md).

Regel für Commits: Wenn ein Commit eine entscheidungs-relevante Änderung vornimmt, ID(s) in der Commit-Message nennen, z. B.:

Resolve OP-SIGN-1: E-Signatur-Provider = DocuSign (eIDAS-QES für Verträge)

ID-Vergabe = GitHub-Nummer (MED-D-359, ersetzt MED-D-110 „höchste + 1"). GitHub vergibt Issue- und PR-Nummern serverseitig aus einer Folge — zwei parallele Sessions können dieselbe nie ziehen (unter „höchste + 1" kollidierten trotz Regel MED-D-93/94/95). Verbindlich (Standard: drkv-com/everything-as-code-template docs/GitHub-Arbeitsweise.md §BP-1):

  • Offenes ist ein GitHub-Issue — jeder offene Punkt, jede Entscheidungsfrage, Empfehlung, jedes Feature und Feedback wird sofort als Issue angelegt (Vorlagen in .github/ISSUE_TEMPLATE/, Body: Befund · Optionen · Empfehlung · Bezug), nicht nur im Chat genannt. Die Issue-Nummer ist die ID. Neue MED-OP-…-Zeilen in HANDOFF §4/Lastenheft §11 entfallen. Der Altbestand ist migriert (MED-D-361): jeder offene OP-…/MED-OP-… hat ein Issue (Titel <Alt-ID> · <Thema>, → #n in der eingefrorenen Tabelle) — das Issue ist die Quelle. Ebenso die offenen Kunden-Besprechungspunkte KB-n/MED-KB-n (MED-D-659). Fachliche Bestätigung durch den Kunden = Label fachliche-bestätigung (Filter is:open label:"fachliche-bestätigung"); nach Klärung Ergebnis als Kommentar + MED-D-<nr>, Label entfernen bzw. Issue schließen. Abgrenzung: fachliche-bestätigung = der Kunde muss eine fachliche Frage entscheiden (Ablauf, Umfang, Datenzuschnitt); Tool-/Anbieterwahl und Compliance-Arbeit bleiben nur status: anreicherung.
  • Entscheidungs-ID = Nummer des auslösenden Issues (sonst des PR): MED-D-<nr>, mehrere je PR -2, -3. Die ID steht damit erst fest, wenn Issue oder PR existiert. Bereiche: MED-D-1…MED-D-331 historisch (bleiben gültig), alle nach dem alten Schema vergebenen MED-D-n bis zum Merge von MED-D-359 bleiben gültig (parallel entstanden u. a. MED-D-332…MED-D-336); danach werden Nummern unter 359 nicht mehr belegt, ab MED-D-359 gelten GitHub-Nummern.
  • Sperre gegen Doppelarbeit: Label in Bearbeitung + Kommentar mit Session/Branch (gilt 4 h).
  • Labels als Code: .github/labels.yml (Workflow labels.yml legt an, löscht nie).

4. Verbindliche Dokumente (lesen in dieser Reihenfolge)​

  1. HANDOFF.md — Wie ist der aktuelle Stand? Status, geparkte Fragen, nächste Schritte. Zuerst.
  2. docs/fachlich/Lastenheft.md — Was bauen wir? Vollständige fachliche Spezifikation. Master.
  3. docs/konventionen/agents.md — dieses Dokument.
  4. CLAUDE.md / README.md — gebündelte Leitplanke bzw. Setup/Orientierung.

Außerdem gepflegt: docs/betrieb/Timesheet.md — Arbeitszeit-Timesheet; am Session-Ende eine Session-Zeile als Fragment timesheet.d/<YYYY-MM-DD>-<branch-slug>.md anlegen (§6.4). Das KW-Aggregat ist abgeleitet und wird beim Bau von scripts/timesheet_summen.py erzeugt (#365, MED-D-365) — nie von Hand. Protokoll → §5.1 "Arbeitszeit erfassen".

5. Verhaltensregeln für Agenten​

5.1 Was tun​

  • IDs respektieren: Beim Verweis auf existierende Entscheidungen ID nennen.
  • Lastenheft und HANDOFF gemeinsam pflegen: Eine neue Entscheidung landet im Lastenheft (Kern-Spec) und in HANDOFF.md (kompakt für die nächste Session).
  • Markdown + Mermaid: Neue Dokumente in .md. Diagramme als Mermaid inline.
  • Single Source of Truth: Wenn ein Wert abgeleitet werden kann, wird er abgeleitet — nirgends doppelt gespeichert (z. B. "Onboarding vollständig?" aus den Pflicht-Items).
  • Standardwerkzeuge bevorzugen (G-1): Wo ein bewährtes Standard-Tool die Aufgabe löst, anbinden statt nachbauen (Dokumente → NextCloud, Unterschriften → DocuSign/PandaDoc, Kundenstamm → CRM). Eigenbau begründen (warum kein Standard).
  • Selbsterklärbarkeit (G-3): durchgängig sprechende, eindeutige Bezeichnungen (Beratungs-/ Back-office-Sprache statt technischer Labels; z. B. "Unterschrift ausstehend" statt "pending"). UI und Doku.
  • Rechtssichere, lückenlose Doku (G-4): Beratungsdoku, Unterschriften, Belege append-only + auditierbar.
  • Datenschutz by design (G-5): PII minimal, EU-/CH-Residenz, keine PII/Secrets im Klartext.
  • Jedes Feature wird dokumentiert (goldene Regel): Kein Feature ist "fertig", bevor die zuständige Produkt-/Architektur-Doku es beschreibt. HANDOFF ist das Arbeitslog, kein Ersatz für die Fach-Docs.
  • Doku-Konsistenz-Check (verbindlich, OP-DOCS-1): Die Doku muss in sich konsistent sein und (sobald Code existiert) zur Implementierung passen. Cadence: zu Session-Beginn sichten und vor jedem PR/Merge gegenprüfen. Zwei Achsen:
    • Doku↔Doku: IDs (G-/R-/A-/S-/OP-…) existieren & sind eindeutig, Glossar-Begriffe einheitlich, Modul-/Phasen-Liste und Status (✅/🟡/⛔) stimmen über HANDOFF.md · Lastenheft.md · CHANGELOG.md überein, Querverweise lösen auf, keine widersprüchlichen Aussagen.
    • Doku↔Implementierung: genannte Feldnamen/Enums/DTOs/Routen existieren im Code (und umgekehrt); beschriebene Features sind gebaut — und Gebautes ist beschrieben.
    • Mechanik: der maschinell prüfbare Teil läuft als bash scripts/check-doc-consistency.sh (tote Links/Bilder + Konflikt-Marker) — warnt, blockt nicht. Der semantische Teil ist Agenten-Pflicht. Bei Unklarheit/Widerspruch: nachfragen (nicht raten).
  • Audit-Trail: Entscheidungen + Diskussionsergebnisse festhalten: Jede Design-/Architektur-/Prozess- Entscheidung und jedes Diskussionsergebnis (auch verworfene Optionen mit Begründung) landet in der Doku — fachlich im Lastenheft, offene Punkte als GitHub-Issue (MED-D-359), Architektur in docs/architektur/, Guiding Principles in CLAUDE.md.
  • CHANGELOG pflegen (je PR): ein Eintrag pro PR als Fragment changelog.d/<YYYY-MM-DD>-<branch-slug>.md (- **{PR}** YYYY-MM-DD — Beschreibung (IDs).; {PR} wird beim Bau zum PR-Link) — inkl. getroffener Entscheidungen. CHANGELOG.md selbst ist erzeugt (§6.4).
  • Versionierung (je PR, MED-D-363): nur das PR-Label version:patch|minor|major setzen (ohne Label kein Bump) — nie APP_VERSION oder Stand-Stempel von Hand ändern; die Version stempelt app-deploy.yml beim Deploy (scripts/stamp-version.mjs: höchster Tag v<semver> + Label, Tag wird gesetzt).
  • Log-Hygiene: entfällt als Handarbeit — CHANGELOG/HANDOFF/Timesheet/Decision-Log sind aus Fragmenten erzeugt (MED-D-359, §6.4); check-doc-consistency.sh prüft weiter Konflikt-Marker (die union-Dubletten-Checks sind entfallen, #365).
  • Annahmen sichtbar machen + Optionen zuerst: Berührt eine Aufgabe versteckte Annahmen oder Produkt-/ Datenmodell-Entscheidungen, nicht drauflosbauen — Annahme explizit auflisten + begründen, Optionen mit Empfehlung vorlegen, entscheiden lassen, dann bauen + Entscheidung dokumentieren.
  • Verifizieren statt behaupten: Previewbare Änderungen live verifizieren (z. B. docs-site-Build) statt den User prüfen zu lassen.
  • Arbeitszeit erfassen: Fragment timesheet.d/<YYYY-MM-DD>-<branch-slug>.md anlegen — Start/Stop je Session, Gap-Regel (> 1 h seit letzter Interaktion → User nach Stop fragen, neue Session). Am Session-Ende.
  • Proaktives Compliance-Flagging: kritische/regulatorisch relevante Themen für DE/AT/CH (DSGVO/revDSG, eIDAS/ZertES, Aufbewahrungsfristen …) aktiv flaggen + Optionen zeigen; im Risikoregister eintragen.

5.2 Was NICHT tun​

  • ❌ Keine binären Dokumente als Master-Quelle.
  • ❌ Keine ungefragten Refactorings am Lastenheft oder Code. Erst klären, dann tun.
  • ❌ Kein Pushen ohne Confirm in main, wenn der Wert der Änderung unklar ist. Lieber Branch + PR.
  • ❌ Keine duplizierten Decision-Docs außerhalb von Lastenheft + HANDOFF (Decision-Sprawl vermeiden).
  • ❌ Kein Eigenbau, wo ein Standard-Werkzeug passt (G-1) — ohne begründete Ausnahme.
  • ❌ Keine PII / Passwörter / Secrets in Klartext committen.

5.3 Bei Unsicherheit​

  • Lieber eine kurze Frage stellen als annehmen.
  • Wenn nicht entscheidbar: Punkt sofort als GitHub-Issue anlegen (Befund · Optionen · Empfehlung · Bezug, Label offener-punkt; MED-D-359) und weitermachen. Alt-IDs OP-<Thema>-n nur noch als Verweis.

5.4 Kanonische Quellen — "eine Definition, ein Ort" (MED-D-110, aus Doku-Audit B16–B18)​

Jede wiederkehrende Regel hat genau eine maßgebliche Stelle (G-2, gilt auch für Meta-Doku). Andere Docs dürfen sie zusammenfassen und darauf verlinken, aber nicht divergierend neu formulieren — sonst driften sie (Beleg: G-8 fehlte nach MED-D-85 in fünf Docs). Bei Widerspruch gilt die kanonische Stelle.

RegelKanonische QuelleWer verweist
Leitprinzipien G-1…G-n (Volltext)CLAUDE.md §LeitprinzipienEntwicklungsansatz, Lastenheft §3, agents.md (nur Kurzform + Link)
Session-Start-Lesereihenfolgeagents.md §4CLAUDE.md, HANDOFF, README (Kurzform + Link)
ID-System + ID-Vergabe (parallel)agents.md §3CLAUDE.md, Entwicklungsansatz, README
Draft-PR-/Review-Workflow (MED-D-60/100)agents.md §7CLAUDE.md, Entwicklungsansatz
CI-Gate / Branch-Protection (MED-D-59/109)agents.md §6.5 + §7HANDOFF §6
Prozessphasen-/Lifecycle-Achsen + -Diagrammdocs/architektur/Prozessmodell.md §2/§3System-Charakter §1, Lastenheft §5
Pflege-Pflichtsatz je PRhier, §5.4 (Liste unten)CLAUDE.md, Entwicklungsansatz
Weltmodell / Wertobjekte (G-8)docs/architektur/Weltmodell-Data-Dictionary.mdCLAUDE.md G-8, Lastenheft

Pflege-Pflichtsatz je PR — kanonische Liste (nur die betroffenen führen, nicht mechanisch alle):

  • immer (nur Fragmente, MED-D-359): changelog.d/ (ein Eintrag, {PR}) · timesheet.d/ (Session-Zeile) · handoff.d/ (§2-Block; Stand-Absatz/§3–§6 in handoff.d/_fuss.md nur bei echter Änderung). Neue offene Punkte → GitHub-Issue, nicht HANDOFF §4.
  • bei Test-Änderung (MED-D-701): test.d/<YYYY-MM-DD>-<branch-slug>.md (Verlaufs-Absatz) — Zahlen nicht von Hand, die werden gemessen.
  • bei Entscheidung: entscheidungen.d/<nr>-<slug>.md (MED-D-<nr>, Nummer = Issue/PR) — und die kanonische Regel-Quelle oben.
  • bei neuem/geändertem Feature: Issue (Label Feature-Liste) + Fragment feature.d/<Position>-<Schlagwort>.md (MED-D-362; Status nur im Issue) · docs/fachlich/Lastenheft.md.
  • Tests immer aktuell halten (verbindlich, MED-D-290): neue/erweiterte Funktion → Tests auf allen betroffenen Wegen mitliefern — Server-Logik → Vitest (server/); neue/geänderte UI-Fläche → Playwright-Spec in client/e2e/ (gemockt); neuer durchgehender Fach-Flow (Persistenz, Signatur/ DocuSign, Ablage, Onboarding-Strecke) → Spec in client/e2e-fullstack/ (echter Worker). Kein Feature-PR ohne passende Test-Aktualisierung. Danach ein Fragment test.d/<YYYY-MM-DD>-<branch-slug>.md anlegen (neue/entfernte Dateien; Zahlen nicht von Hand — sie werden gemessen, MED-D-701) und die Tabellen in test.d/_fuss.md fortschreiben. Beide Playwright-Suiten sind Teil des Pflicht-Checks checks (ein Job client, der einmal baut und beide Suiten gegen denselben Build fährt, MED-D-336).
  • bei Kundenklärung: GitHub-Issue mit Labels offener-punkt · status: anreicherung · fachliche-bestätigung (MED-D-659; Kunden-Besprechungspunkte.md ist eingefroren).
  • bei Code mit Versionssprung: PR-Label version:patch|minor|major (MED-D-363) — keine Datei.

Last-Kritik (B18). Die Liste wirkt lang, ist aber bedingt: ein reiner Fix berührt oft nur CHANGELOG + Timesheet + HANDOFF. Die Fragment-Ordner (MED-D-359) machen die append-only Logs konfliktfrei; der Aufwand liegt in den lebenden Übersichten (Feature-Liste/Test-Übersicht), die nur bei echten Feature-/Test-Änderungen anzufassen sind. Nicht jeder PR fasst "~10 Docs" an.

6. Workflow für Änderungen​

6.1 Eine Entscheidung treffen​

  1. ID = Nummer des auslösenden Issues (sonst des PR) → MED-D-<nr> (§3, MED-D-359); Zeile als entscheidungen.d/<nr>-<slug>.md.
  2. Lastenheft (passender Abschnitt) updaten.
  3. Zugehöriges Issue per Closes #n im PR schließen (auch für Alt-OPs — deren Tabellenzeile bleibt eingefroren).
  4. Commit-Message: Resolve <ID>: <kurz>.

6.2 Eine offene Frage aufnehmen​

  1. GitHub-Issue anlegen (Vorlage „Offener Punkt"; Befund · Optionen · Empfehlung · Bezug) — die Issue-Nummer ist die ID (MED-D-359). Keine neue OP-<Thema>-n-Zeile in HANDOFF §4.
  2. Fachliches Detail bei Bedarf im Lastenheft, mit Verweis #<nr>.

6.3 Doku-Konsistenz prüfen (Session-Start + vor jedem PR)​

  1. Session-Start: HANDOFF.md → Lastenheft.md → agents.md lesen; relevante Docs sichten.
  2. Vor dem PR: beide Achsen prüfen (§5.1); bash scripts/check-doc-consistency.sh laufen lassen; docs-site baut durch.
  3. Drift gefunden? Doku (oder Code) angleichen, bei Unklarheit nachfragen; im PR/CHANGELOG vermerken.

6.4 Fragmente statt gemeinsamer Log-Dateien (MED-D-359, löst OP-PM-1 merge=union ab)​

Standard: drkv-com/everything-as-code-template docs/GitHub-Arbeitsweise.md §BP-2. merge=union half nur lokal — Merge Queue und GitHub-Server-Merge ignorieren den Treiber. Deshalb gilt: ein Eintrag = eine Datei, gebaut wird nach dem Merge.

Erzeugtes DokumentQuelle (je PR eine Datei)Ordnung
CHANGELOG.mdchangelog.d/<YYYY-MM-DD>-<branch-slug>.md — eine Zeile - **{PR}** YYYY-MM-DD — …neueste zuerst
HANDOFF.mdhandoff.d/<YYYY-MM-DD>-<branch-slug>.md — ein §2-Blockneueste zuerst
docs/betrieb/Timesheet.mdtimesheet.d/<YYYY-MM-DD>-<branch-slug>.md — eine Tabellenzeileneueste zuerst
docs/betrieb/Decision-Log.mdentscheidungen.d/<nr>-<slug>.md — eine Tabellenzeile MED-D-<nr>aufsteigend
docs/betrieb/Test-Uebersicht.mdtest.d/<YYYY-MM-DD>-<branch-slug>.md — ein Verlaufs-Absatz (neue/entfernte Testdateien); Tabellen in test.d/_fuss.mdneueste zuerst
  • _kopf.md/_fuss.md = fester Rahmen, 0000-bestand.md = einmalig migrierter Altbestand. Konfiguration: fragmente.json; Builder scripts/fragmente_bauen.py ist eine unveränderte Kopie aus dem Template.
  • Gemessene Zahlen statt gepflegter (MED-D-701): die Kopfzeile der Test-Übersicht ist ein Ist-Stand, kein Verlauf — sie lässt sich nicht aus Fragmenten addieren. scripts/testzahlen_messen.py zählt die drei Suiten statisch (ohne Testlauf) und stempelt den Block zwischen <!-- testzahlen:anfang/ende -->; es läuft im Nachzieh-Ablauf nach fragmente_bauen.py (gleiches Muster wie scripts/timesheet_summen.py).
  • Nie die erzeugten Dateien im PR editieren oder committen. .github/workflows/dokumente-nachziehen.yml baut nach jedem Merge auf main und trägt das Ergebnis per Bot-PR mit Auto-Merge nach. Lokal zeigt python3 scripts/fragmente_bauen.py das Ergebnis (danach git checkout -- <ziele>); die CI prüft im PR nur --gelesen (Job doc-consistency).
  • Seit MED-D-701 ist auch docs/betrieb/Test-Uebersicht.md migriert (test.d/): Verlauf als Fragment, Tabellen im _fuss.md, Gesamtzahlen gemessen. Damit bleibt kein handgepflegter Log übrig. Die Feature-Liste ist seit MED-D-362 aus feature.d/ + Issues gebaut (scripts/feature_liste_bauen.py).
  • Historisch (bis MED-D-359): merge=union für CHANGELOG.md, HANDOFF.md, docs/betrieb/Timesheet.md.
  • Session-ID sprechend & branch-abgeleitet — ab MED-D-51 mit Projekt-Kürzel MED-<Datum>-<branch-slug> (Bestandszeilen bleiben ohne Präfix) → git-weit eindeutig; bei mehreren Sessions je Branch am selben Tag ein Zähl-Suffix -2/-3 anhängen (z. B. …-gkedy6-2), sonst kann die ID kollidieren.
  • Branch aktualisieren: git fetch origin main → git merge origin/main (Fragmente kollidieren nicht).
  • Doku-Check: bash scripts/check-doc-consistency.sh prüft die erzeugten Dateien (Duplikate, Konflikt-Marker) und die Fragmente (--gelesen); die *.d/-Quellen selbst sind von den Link-/Spannen-Checks ausgenommen (ihre Links gelten im gebauten Ziel).

6.5 Nicht-automatisierbare Checks (Agenten-Pflicht)​

Einige Setup-Kontrollen lassen sich nicht per CI-Skript/MCP prüfen — dann per gh api (falls Token-Scope) oder den Nutzer fragen/hinweisen. Abweichungen melden, nie still übergehen. Setzen (die konkreten gh api-Kommandos für Merge-Regeln, Auto-Merge/Auto-Delete & Branch-Protection/Ruleset): Runbook docs/architektur/Deploy.md §7c — nur manuell/mit eigenem Admin-PAT, da der MCP-/Agenten-Token bewusst kein Administration-Recht trägt.

  1. Merge-Methoden = nur Squash aktiv. — gh api repos/<o>/<r> --jq '.allow_squash_merge,.allow_merge_commit,.allow_rebase_merge'
  2. allow_auto_merge = true (OP-PM-1). — gh api repos/<o>/<r> --jq '.allow_auto_merge'
  3. delete_branch_on_merge = true. — gh api repos/<o>/<r> --jq '.delete_branch_on_merge'
  4. Branch-Protection auf main (erforderliche Checks checks und CodeRabbit, MED-D-59; "require branches up to date" bewusst AUS, MED-D-109 — sonst Rate-Limit-Treadmill bei Parallel-Merges). — prüft alle drei Invarianten (strict=false und beide Required-Contexts vorhanden): gh api repos/<o>/<r>/branches/main/protection --jq 'if .required_status_checks.strict==false and (.required_status_checks.contexts|index("checks")) and (.required_status_checks.contexts|index("CodeRabbit")) then "ok" else error("branch-protection-Vertrag unvollständig") end'
  5. Merge-Queue auf main ist PFLICHT (MED-D-313, verbindlich seit MED-D-327): im main-Ruleset „Require merge queue" aktiv, Required-Check der Queue = checks (läuft via merge_group-Trigger im Queue-Ref), CodeRabbit bleibt PR-Eintritts-Gate (Status auf dem PR-Head). Warum Pflicht: ci.yml hat seit MED-D-327 keinen push: main-Trigger mehr (BM-9) — der Queue-Lauf ist die einzige Voll-Validierung vor main. Ist die Queue aus, landet Code ungetestet auf main → sofort melden. Nach einem Admin-Bypass: CI manuell starten (Actions → CI → Run workflow, workflow_dispatch). — Settings → Rules (main-Ruleset) verifizieren oder beim Nutzer nachfragen (Stand 2026-09-26: vom Nutzer aktiviert).
  6. Semantische Doku-Konsistenz (§5.1) — ohnehin Agenten-Pflicht.

6.6 CI-Pipelines: Concurrency (überholte Läufe abbrechen)​

Regel: Jede Workflow-Pipeline bekommt einen concurrency-Block, wo er Nutzen bringt — überall, wo mehrere Läufe desselben Kontexts (PR/Branch, Deploy-Ziel) überlappen können und der ältere Lauf durch den neueren überflüssig wird. Das spart Runner-Minuten und liefert schneller ein aktuelles Ergebnis. Gemeint ist das GitHub-Actions-Schlüsselwort concurrency: (Läufe gruppieren/canceln), nicht die Job-Parallelität (die regelt der Job-Graph über needs).

Muster (je Pipeline-Typ):

  • CI / PR-Pipelines → neuer Push auf denselben PR/Branch bricht den vorherigen Lauf ab:
    concurrency:
    group: ci-${{ github.workflow }}-${{ github.ref }}
    cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
    Nicht auf main abbrechen (dort liefe sonst ein Deploy ins Leere). Umgesetzt in ci.yml.
  • Deploy-/Ressourcen-Pipelines (genau ein Ziel, z. B. der Worker) → überlappende Deploys verhindern: group: <deploy-ziel> (fixer Name), cancel-in-progress: true. Umgesetzt in app-deploy.yml.
  • Serielle Jobs, die nicht abgebrochen werden dürfen (z. B. Migrationen) → nur serialisieren, nicht canceln: cancel-in-progress: false.

Faustregel cancel-in-progress: true für idempotente/überholbare Läufe (PR-CI, Deploy); false, wenn jeder Lauf zu Ende laufen muss. Ergänzend wirkt die Trigger-Hygiene gegen Doppelläufe (CI: pull_request + merge_group, kein push — seit MED-D-327 auch nicht mehr auf main, weil der Queue-Lauf denselben Stand schon voll testet; Deploys: push nur auf main) — Concurrency und Event-Trigger greifen zusammen.

actions/setup-node-cache: npm ist konditional — nur auf GH-hosted, nicht auf self-hosted (MED-D-225). Der npm-Cache von setup-node ist für ephemere Runner gedacht: dort ist kaltes npm ci (voller Download) der Hauptkostenpunkt, den der Actions-Cache-Service abfängt. Auf dem persistenten self-hosted hot-Runner ist ~/.npm zwischen Läufen ohnehin warm; dort würde cache: npm nur ein großes Archiv (100en MB) langsam durch den Cache-Service schaufeln (Timeout-Risiko). Deshalb wird der Cache je Runner-Modus geschaltet: cache: ${{ (github.event.pull_request.head.repo.fork || vars.CI_RUNNER == 'ubuntu-latest') && 'npm' || '' }} (leerer String = kein Cache). Analog cached der Job client .angular/cache per actions/cache nur auf GH-hosted (self-hosted hält ihn via clean:false). So ist jeder Modus optimal, ohne den anderen zu regressieren. Gilt in ci.yml (docs-build/server-test/client), app-deploy.yml (inkl. SBOM, MED-D-327), docs-deploy.yml.

Pipeline-Geschwindigkeit (weitere Hebel, in ci.yml umgesetzt):

  • Pfad-Filter (changes-Job, dorny/paths-filter): jeder schwere Job (server/client/docs) läuft nur, wenn sein Bereich geändert wurde — Doku-only-PRs überspringen Server/Client, Code-only die Doku-Site. Geteilte Dateien (ci.yml, scripts/**) triggern alle Bereiche; im Merge-Queue-Lauf (merge_group) und bei manuellem Start läuft immer alles voll (Validierung vor main, MED-D-327). Übersprungene Jobs zählen im Pflicht-Check checks als bestanden (skipped ≠ failure).
  • Schnelle Installs: npm ci --prefer-offline --no-audit --fund=false — nutzt das warme lokale ~/.npm ohne Audit-/Funding-Netz-Calls.
  • Flacher Checkout in der CI: fetch-depth: 1 (shallow) → schnellerer Checkout; die CI-Build-Nummer ist irrelevant (nicht deployt). Volle History (fetch-depth: 0) nur im App-Deploy (Build-Nummer = Commit-Count).
  • Angular-Build-Cache (beide Runner-Modi, je nach Herkunft, MED-D-225): .angular/cache beschleunigt Folge-Builds inkrementell — angular.json → cli.cache.environment: "all" (Angular deaktiviert den Cache in CI sonst per Default). Wie er zwischen Läufen überlebt, hängt vom Runner-Modus ab: auf self-hosted hot via actions/checkout mit clean: false (der gitignorierte Cache übersteht den git clean -ffdx); auf GH-hosted (fork oder CI_RUNNER == 'ubuntu-latest') via actions/cache@v4 im Job client (Key aus Client-Lockfile+sha, restore-keys-Fallback). Content-adressiert (selbst-invalidierend) → unbedenklich. Auf ephemeral self-hosted (frisch je Lauf, kein actions/cache-Guard) bleibt er wirkungslos.

Runner-Labels hot vs. ephemeral (wichtig): Die self-hosted Runner tragen ein Label — hot = persistent (Arbeitsordner + ~/.npm + Build-Caches überleben zwischen Läufen), ephemeral = frisch je Lauf. CI pinnt auf hot (runs-on: … || 'hot'), weil alle obigen Cache-/Offline-Hebel nur dort greifen (auf ephemeral wäre der entfernte setup-node-npm-Cache sogar nützlich). Fork-PRs bleiben über das Gate auf ubuntu-latest; Umschalten via Repo-Variable CI_RUNNER. Kapazität: die Zahl der hot-Runner ist damit die Parallelitäts-Obergrenze — genügend hot-Runner bereitstellen (≥ breitester Job-Fächer).

Auto-Rerun bei flakigem Runner (auto-rerun.yml, D-40): Ein separater, workflow_run-getriggerter Workflow stößt bei einem fehlgeschlagenen CI-Lauf die fehlgeschlagenen Jobs genau einmal neu an (run_attempt < 2 → 1 Retry, kein Loop). Das heilt die typische self-hosted-Flakiness (github.com:443- Timeout beim Checkout/setup-node, Runner mitten im Job gestorben), ohne dass jemand manuell "Re-run failed jobs" klicken muss. Bewusst nicht neugestartet: abgebrochene Läufe (der Concurrency-Cancel liefert cancelled ≠ failure) und Fork-PRs (head_repository ≠ repository → Sicherheits-Gate RISK-24 bleibt gewahrt). Dependency-frei via curl gegen die REST-API (rerun-failed-jobs, permissions: actions: write) — kein gh/Node-Action, also keine node20-Deprecation-Warnung. Deploys (app-deploy.yml/docs-deploy.yml) sind bewusst ausgenommen (ein halb-deployter Stand soll nicht blind wiederholt werden). Grenze: hängt der Runner permanent, hilft der Retry nicht — dann ist es kein Flake, sondern ein echter Ausfall (Runner prüfen).

6.7 Regelmäßige Meisterwerk-Audits (MED-D-97 / MED-OP-REVIEW-1) — kanonische Definition​

Der Anspruch "App und Doku sind ein Meisterwerk" wird nicht nur behauptet, sondern periodisch auditiert. Zwei Quality-Audits, beide als datierte Docs in docs/betrieb/ (append-only Historie — neue Audits ergänzen, alte bleiben als Zeitzeugen liegen):

AuditFrageDatei-MusterErstausgabe
App-AuditIst die App ein Meisterwerk? (UX/Prozess, True North, G-3)UX-Prozess-Review-<JJJJ-MM>.md2026-07 (v0.62.0)
Doku-AuditIst die Doku ein Meisterwerk? (pyramidal · zielgruppen-gerecht · visuell · konsistent)Doku-Review-<JJJJ-MM>.md2026-07 (v0.65.0)

Verbindliche Regeln:

  1. Bezugspunkt-Pflicht: Jeder Audit nennt in der Titelzeile seinen Stand als (Stand vX.Y.Z, JJJJ-MM-TT) und im Kopf/Fuß den Commit-SHA — ohne klaren Bezugspunkt ist ein Audit wertlos, weil niemand weiß, worauf sich die Befunde beziehen.
  2. Kadenz: mindestens alle ~10 Minor-Versionen oder alle 3 Monate (was zuerst eintritt), zusätzlich nach jedem Meilenstein (z. B. 1.0.0) und nach Abschluss einer aus dem Audit abgeleiteten Maßnahmen-Serie (UX-Wellen / Doku-Wellen) — dann als Wirksamkeits-Kontrolle.
  3. Stale-Regel: Liegt der Bezugspunkt des jüngsten Audits ≥10 Minor-Versionen hinter APP_VERSION oder ist er >90 Tage alt, gilt der Audit als veraltet. Dann gilt: aktiv anregen, den Audit zu aktualisieren — der Agent flaggt das bei der Session-Start-Sichtung (§4) gegenüber dem Nutzer; mechanisch warnt scripts/check-doc-consistency.sh (warnt, blockt nicht).
  4. Folge-Arbeit als OPs: Audit-Befunde werden nicht im Audit "abgearbeitet", sondern als GitHub-Issues überführt (MED-D-359; früher MED-OP-…-Zeilen in HANDOFF.md §4, Vorbild: MED-OP-UX-1..4 aus dem App-Audit, MED-OP-DOKU-1..3 aus dem Doku-Audit) — der Audit bleibt unverändertes Zeitdokument.

7. Branch- und Push-Konventionen​

  • Default-Branch: main.
  • GitHub-Operationen über die GitHub-API/MCP, nicht über lokales git/gh für Remote-Writes (verbindlich, v. a. in der Remote-/Cloud-Session): PR anlegen/mergen, Review-/Issue-Kommentare, Commits/Pushes auf Remote-Branches über die GitHub-MCP-Tools; CI-Status & Mergeability über pull_request_read prüfen, nicht erraten. Lokales git bleibt für lokale Arbeit ok (Branch, Merge/Rebase, Reads).
  • Neuer Code (KI) → immer zuerst einen neuen Branch anlegen und nur dort arbeiten. Merge nach main nur via PR (mit grüner CI). Niemals Code direkt auf main.
  • Doku-Fast-Track: Auch reine Doku-Änderungen laufen über Branch + PR (nie Direkt-Push auf main) — der Audit-/PR-Nummern-Trail bleibt lückenlos. Reine-Doku-PRs dürfen per Auto-Merge (Squash) durch. Required Checks (Branch-Protection main): checks und der CodeRabbit-Commit-Status CodeRabbit (MED-D-59) — der Merge wartet auf "Review lief" (nicht "keine Findings"). "Require branches up to date" ist bewusst AUS (MED-D-109): ein einmal grüner PR mergt auch, wenn main inzwischen weitergezogen ist (behind blockt nicht) — sonst entsteht bei Parallel-Merges eine Rate-Limit-Treadmill (jedes Pflicht-Branch-Update triggert eine neue CodeRabbit-Review). Die Qualitätssicherung bleibt: CI + Review sind weiter Pflicht.
  • EIN Review je PR — Config + Draft-Workflow (verbindlich, MED-D-60 + MED-D-100): Zwei Hebel gegen Rate-Limit-Spend, die zusammenwirken:
    • Config (MED-D-100): .coderabbit.yaml auto_incremental_review: false → CodeRabbit reviewt genau einmal je PR (beim Umschalten auf "ready for review"), keine inkrementellen Re-Reviews je Folge-Push — unabhängig davon, wie oft gepusht wurde.
    • Verhalten (MED-D-60): Feature-PRs als Draft öffnen und im Draft frei bepushen (CodeRabbit reviewt Drafts nicht, drafts: false → kein Kontingent/Rauschen); erst wenn die Arbeit fertig ist auf "ready for review" schalten und Auto-Merge (Squash) scharfstellen. Preis (MED-D-100): ein Push nach dem Ready-Review bekommt keinen frischen CodeRabbit-Status → der Required-Check auf dem neuen Head bleibt offen und Auto-Merge wartet, bis manuell @coderabbitai review gepostet wird. Konsequenz: PR erst komplett (alle Commits, lokal grün) auf "ready" schalten; muss nach dem Review doch noch ein Fix gepusht werden, danach @coderabbitai review posten, damit der Check auflöst. Der Normalfall "ready → 1 Review → Merge" ohne Folge-Push löst ganz normal auf. Gilt für alle Agenten/Sessions. Bot-PRs (z. B. dependabot[bot]) werden mitreviewt (bewusst keine ignore_usernames-Ausnahme, MED-D-60): ein ausgenommener Bot-PR bekäme nie den CodeRabbit-Status und bliebe als Required Check dauerhaft am Gate hängen.
  • "go"-Gate: Commit, Push und Merge erfolgen nur auf explizites "go" des Users. Branch anlegen + Dateien im Arbeitsbaum vorbereiten ist ok; das Schreiben in die Historie / nach außen wartet auf "go". (Der Draft-PR-Workflow ändert das "go"-Gate nicht — auch das Öffnen des Draft-PR wartet auf "go".)
  • Immer Auto-Merge — stehende Regel (MED-D-313, Nutzer „immer automerge"): Für den Merge-Schritt gilt Standing Consent — ein fertiger PR wird direkt auf „ready for review" + Auto-Merge (Squash) geschaltet, ohne Pro-PR-Rückfrage (das „go"-Gate für Commit/Push bleibt unberührt). Ausnahme bleibt, wo ausdrücklich anders angewiesen.
  • Merge-Queue (MED-D-313, verbindlich seit MED-D-327): die GitHub-Merge-Queue auf main ist Pflicht — die CI läuft nicht mehr auf push: main (BM-9, spart den doppelten Voll-Lauf je Merge), der Queue-Lauf ist die Voll-Validierung vor main. Die Queue testet jeden Kandidaten auf einem temporären gh-readonly-queue/main/…-Ref über das merge_group-Event — ci.yml triggert deshalb auch auf merge_group, der dorny/paths-filter-Schritt läuft nur auf pull_request, und die schweren Job-Gates stehen auf != 'pull_request' (Queue und manueller Start laufen voll). Required-Check der Queue = checks; CodeRabbit postet seinen Status auf den PR-Head (nicht auf den merge_group-Commit) und bleibt damit PR-Eintritts-Gate, nicht Queue-Gate. Bootstrap-Falle (falls die Queue wieder aktiviert wird und der merge_group-Trigger fehlte): eine Änderung, die den Trigger erst auf main bringt, kann nicht durch die Queue — dafür die Queue kurz deaktivieren (oder Admin-Bypass); der Trigger ist jetzt aber bereits auf main.
  • Branch laufend auf main aktuell halten: zu Beginn und in Abständen git fetch origin main → rebase/merge — zur Konflikt-/Drift-Vermeidung, nicht als Merge-Gate. Ein grüner, konfliktfreier PR darf behind mergen (MED-D-109 — "require branches up to date" ist AUS); ein Branch-Update vor dem Merge ist nur nötig, wenn main Konflikte bringt oder ein konkretes Risiko es rechtfertigt (z. B. Änderung an derselben Datei/Logik). Kein Update allein deshalb, weil der PR behind ist.
  • Branch nach Merge schließen: Sobald ein PR gemergt ist, wird der Feature-Branch gelöscht (remote + lokal); bevorzugt GitHub "Automatically delete head branches". Wirkung auf Stacking (MED-D-65): das Setting löscht nur den Head-Branch eines gemergten PRs (nicht unmerged/lokale Branches, nichts Rekursives) → stört Stacking nicht.
  • Stacked / Child-Branches bei komplexen Changes (MED-D-65): Getrennt reviewbare Teilschritte dürfen als Stack laufen (main ← feature-basis ← feature-child, Child-PR-Base = feature-basis). Regeln: (a) bottom-up mergen — erst feature-basis → main; GitHub retargetet offene Child-PRs dann automatisch auf main (der Child-Branch überlebt, weil er Head seines eigenen PRs ist). (b) Squash-Reibung einplanen: weil wir Squash-only mergen (OP-PM-1), ist der Squash-Commit auf main ≠ die Original-Basis- Commits im Child → nach jedem Parent-Merge das Child rebasen: git rebase --onto main <alte-basis> <child> + git push --force-with-lease. (c) Draft bis rebased: Child-PR als Draft halten (MED-D-60), bis Parent gemergt und Child rebased ist → CodeRabbit reviewt nur den finalen, korrekten Diff. Default bleibt "ein Branch, mehrere Commits, ein PR" (Squash faltet sie ohnehin) — Stacking nur, wenn die Teilschritte wirklich getrennt review-/mergebar sein müssen.
  • Doku-Pflicht je PR & Merge: Jeder PR legt seine Fragmente in handoff.d/ und timesheet.d/ (plus changelog.d/, ggf. entscheidungen.d/) an (§6.4) und pflegt die fachlich betroffenen Docs.
  • CI & Drafts (MED-D-359, BP-4): ci.yml läuft nicht auf Draft-PRs (ready_for_review startet sie) — im Draft frei pushen kostet keine Runner-Minuten; jeder Job trägt timeout-minutes.
  • Push-Integrität — nie auf detached HEAD committen (verbindlich, MED-D-255). Auslöser: PR #288 mergte ein Duplikat und der eigentliche Fix erreichte nie main/Prod, weil ein Commit auf einem losgelösten (detached) HEAD entstand (git checkout origin/main zum Lesen) und git push -u origin <branch> dann die stale Branch-Referenz hochschob statt des neuen Commits. Verbindliche Disziplin:
    1. Vor jeder Änderung git checkout -B <branch> origin/main — HEAD ist dann immer ein echter Branch. Zum reinen Lesen von main nicht auschecken, sondern git show origin/main:<pfad>.
    2. Nach jedem Push verifizieren: git rev-parse HEAD == git rev-parse origin/<branch>. Weicht es ab → nicht mergen, Ursache klären.
    3. Vor dem (Auto-)Merge den PR-Diff sichten: die geänderten Dateien müssen zur Absicht passen; ein leerer oder falscher Diff (wie #288) = sofortiger Stopp.
    4. Nach dem Merge den Deploy verifizieren: Worker-modified_on muss nach der Merge-Zeit liegen (Cloudflare workers_list) bzw. der App-deploy_status den neuen Commit zeigen — fängt „gemergt, aber nicht live" ab. Guardrail (eingecheckt): .githooks/pre-push bricht einen Push aus detached HEAD (bzw. mit Spitze ≠ HEAD) ab; aktiviert via git config core.hooksPath .githooks (in scripts/session-start-hook.sh je Session automatisch gesetzt).

7a. Design-Sync aus Claude Design (MED-D-193)​

Beim Übernehmen eines Designs/Design-Systems aus Claude Design (via DesignSync-MCP) gilt eine feste Regel (Nutzer-Vorgabe 2026-07-23):

  • Bei Diskrepanzen oder Konflikten mit früheren Entscheidungen (Wording, Enums, Datenmodell, IA, bereits getroffene MED-D-Entscheidungen …) wird der Konflikt dem Nutzer zur Klärung vorgelegt (AskUserQuestion oder kurze Prosa-Rückfrage) — nicht einseitig aufgelöst. Erst nach Klärung bauen.
  • Die Klärungs-Entscheidung wird als MED-D-Zeile im Decision-Log festgehalten (Everything-as-Code, G-2).
  • Reversible Defaults bevorzugen: wo eine risikoarme, umkehrbare Variante existiert (z. B. UI-Mapping statt Server-Enum-Umbau), diese als Default wählen und benennen; irreversible/breaking Änderungen (Migrationen, Enum-Renames) nie ohne ausdrückliche Zustimmung.
  • Präzedenz: die drei Weggabelungen aus MED-D-188 (Plan-first · Assistent gegen die Fakes · 1:n-Bankkonten) und die S2-Enum/Wording-Frage (MED-D-192, per UI-Mapping) wurden so entschieden.

8. Was nicht in dieses Repo gehört​

  • Personendaten realer Kunden / Mitarbeiter (auch nicht in Beispielen — Beispiele sind synthetisch).
  • Secrets, API-Keys, Tokens (für CI: GitHub Encrypted Secrets nutzen).
  • Generierte Build-Artefakte (build/, .docusaurus/, node_modules/ — siehe .gitignore).
  • Binär-Exporte als "Master" (.docx, .pdf).

Letztes Update: 2026-07-23 (S2 Dokument-Zustandsmaschine MED-D-192 + Design-Sync-Konvention §7a MED-D-193; zuvor 2026-07-14 Doku-Welle 4c, MED-D-133-Folge: ID-System-Tabelle §3 um D-n/RISK-n/ KB-n ergänzt — diese Präfixe waren live im Einsatz, aber in der kanonischen Quelle nicht gelistet). Repo-Init (27.06.2026): Way-of-Working für Medidentas etabliert — übernimmt die bewährten Taktano-Konventionen [ID-System · md+mermaid · union-Merge-Logs · Branch-first · GitHub-MCP für Remote-Writes] und ergänzt G-1 Standardwerkzeuge-bevorzugen als domänenspezifisches Leitprinzip; seither laufend fortgeschrieben (u. a. §5.4 "eine Definition, ein Ort", MED-D-110).