COMPASS-Doku

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=abgeloest und gilt_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.