Regel setzen und ablösen
Die erste Regel schreiben
Eine Sache ohne Aussage hat nichts, das gilt. Eine mit art=regel
schreiben:
curl -sS -X POST "$COMPASS_URL/aussagen" \
-H "X-Compass-Key: $COMPASS_KEY_RW" -H "Content-Type: application/json" \
-d '{"sache": "ci-timeout-minuten", "art": "regel",
"text": "CI-Jobs brechen nach 20 Minuten ab.",
"herkunft": "entschieden", "angelegt_von": "euer-name"}'
201 mit der neuen id. Gilt für diese Sache und dieses Subjekt bereits
eine Regel und ersetzt wurde nicht mitgeschickt, kommt 409 mit der
geltenden Aussage im Klartext — dieselbe Information, die auch
GET /gilt/{sache} geliefert hätte, ohne einen zweiten Aufruf:
{"detail": "es gilt bereits eine Regel für diese Sache",
"geltende": {"id": 41, "text": "CI-Jobs brechen nach 30 Minuten ab.",
"gilt_seit": "2026-08-01T09:00:00Z", "quelle": null}}
Ablösen
ersetzt auf die id aus der 409-Antwort setzen (oder aus einem
früheren GET /gilt/{sache}/GET /sachen/{slug}-Aufruf):
curl -sS -X POST "$COMPASS_URL/aussagen" \
-H "X-Compass-Key: $COMPASS_KEY_RW" -H "Content-Type: application/json" \
-d '{"sache": "ci-timeout-minuten", "art": "regel",
"text": "CI-Jobs brechen nach 20 Minuten ab.",
"herkunft": "entschieden", "angelegt_von": "euer-name", "ersetzt": 41}'
Im selben Aufruf bekommt die Vorgängerin (41) status=abgeloest und
gilt_bis = gilt_seit der neuen Aussage — ein Schreibvorgang, zwei
geänderte Zeilen, nichts gelöscht. GET /sachen/ci-timeout-minuten zeigt
41 jetzt unter aussagen.abgeloest, die neue id unter aussagen.gilt.
Das ist auch unterhalb der API erzwungen: uq_aussagen_eine_geltende_regel
ist ein partieller Unique-Index auf (kunde_slug, sache, subjekt_id)
WHERE art='regel' AND status='gilt'. Selbst ein Fehler, der die eigene
409-Prüfung der API überspringt, könnte keine zweite gleichzeitig
geltende Regel einfügen — Postgres würde das INSERT verweigern.
Eine Regel ohne Nachfolger beenden
Manchmal soll eine Regel einfach nicht mehr gelten, ohne dass etwas an ihre Stelle tritt — „wir machen keine CI-Timeouts mehr" ist nicht dieselbe Aussage wie „CI bricht jetzt nach N Minuten ab". Dafür keine neue Aussage schreiben, sondern die geltende direkt beenden:
curl -sS -X POST "$COMPASS_URL/aussagen/43/beenden" \
-H "X-Compass-Key: $COMPASS_KEY_RW" -H "Content-Type: application/json" \
-d '{"grund": "CI-Timeouts werden pro Job im Workflow selbst gesetzt.", "angelegt_von": "euer-name"}'
200, setzt status=abgeloest und gilt_bis=now(), protokolliert ein
Ereignis. 409, wenn die Aussage gerade nicht gilt ist — zweimal
beenden geht nicht, und eine bereits abgelöste Aussage auch nicht.
Eine Hypothese beenden, andere Status
POST /aussagen/{id}/status ändert den Status für Hypothesen und für
offen/vorlaeufig-Aussagen ({"status": "widerlegt"|"offen"|
"vorlaeufig"|"gilt", "grund": "...", "angelegt_von": "..."}). Er gilt
nicht für eine gerade geltende regel oder entscheidung — dafür
ersetzt oder beenden wie oben.
Regeln über die Zeit
Um zu sehen, was an einem vergangenen Datum galt statt was jetzt gilt:
curl -sS "$COMPASS_URL/gilt-am/ci-timeout-minuten?datum=2026-08-15" \
-H "X-Compass-Key: $COMPASS_KEY_RO"
Das liefert jede Aussage jeder Art, die an diesem Datum galt, mit Status — nützlich, um zu rekonstruieren, was man glaubte, als eine Entscheidung fiel, unabhängig davon, was sich seither geändert hat.
Die Auswahl läuft allein über das Zeitfenster, ohne Status-Filter: eine
Zeile, die inzwischen abgelöst wurde, erscheint hier weiterhin, statt
still zu verschwinden — Geschichte wird nicht gelöscht, auch nicht zur
Lesezeit. Ob eine Zeile heute noch gilt, sagt allein ihr status. Lies
ihn mit.
Warum es kein Löschen gibt
Die häufigste Frage zu diesem Leitfaden: „Kann ich eine Regel nicht einfach löschen?“ Nein, und das ist Absicht.
COMPASS soll sagen können, was noch gilt. Dazu muss es auch wissen, was vorher galt und wann es aufgehört hat:
- Ein Agent hat die alte Regel vielleicht schon gelesen. Hat er
gestern danach gehandelt, lässt sich das nur nachvollziehen, wenn die
Regel noch da ist, mit
status=abgeloestundgilt_bis. Eine gelöschte Regel hinterlässt eine Handlung ohne Grund. - Entscheidungen stützen sich auf Regeln. Eine Begründung, die auf eine gelöschte Regel verweist, verweist ins Leere.
- „Was galt am 15. August?“ beantwortet
GET /gilt-am/{sache}nur, wenn die Geschichte vollständig ist.
Deshalb verweigert die Datenbank selbst ein DELETE auf Aussagen. Kein
Aufrufer kann daran vorbei, auch nicht über einen zweiten Weg.
Was man sich unter „löschen“ meist vorstellt, ist beenden: Die Regel
verschwindet aus dem, was gilt (GET /gilt/{sache} liefert sie nicht
mehr), bleibt aber mit Grund und Zeitpunkt lesbar. Soll etwas anderes an
ihre Stelle treten, ist es ablösen.
Bekommt die Regel dabei eine neue Nummer?
Jede Fassung ist eine eigene Aussage mit eigener id. Die id ändert sich
also bei jeder Änderung, und das ist gewollt: Sie bezeichnet genau diesen
Wortlaut. Wer sie zitiert hat, findet über ersetzt den Weg zur aktuellen
Fassung.
Die Nummer, unter der eure Leute eine Regel kennen (etwa R12), gehört
dagegen zur Sache, nicht zur Fassung. Gebt sie beim Anlegen der Sache
mit (POST /sachen mit nummer). Sie bleibt stehen, wenn die Regel
dahinter abgelöst wird. GET /sachen/{slug} zeigt sie zusammen mit der
geltenden und den abgelösten Fassungen.
Und personenbezogene Daten?
Steht in einer Regel eine Angabe über eine Person, und diese verlangt die Löschung, reicht „beenden“ nicht: Der Wortlaut bliebe in der Geschichte lesbar. Ein Weg, solche Angaben unkenntlich zu machen und die Geschichte selbst zu erhalten (Fassung, Zeitpunkt, Kette), gibt es heute noch nicht. Bis dahin: Personenangaben nach Möglichkeit nicht in den Wortlaut von Regeln schreiben, und im Einzelfall den Betreiber eurer Installation ansprechen.