COMPASS docs

Attach a check (Prüfweg)

A Prüfweg (check) is a read-only command COMPASS can run to see whether reality still matches a rule. It doesn't judge on its own — running it writes a fact, and if that fact contradicts the rule it's attached to, a deviation appears.

Create it

curl -sS -X POST "$COMPASS_URL/pruefwege" \
  -H "X-Compass-Key: $COMPASS_KEY_RW" -H "Content-Type: application/json" \
  -d '{"slug": "ci-timeout-grep", "typ": "grep",
       "befehl": "grep -r \"timeout-minutes: 20\" .github/workflows/",
       "erwartung": "mindestens ein Treffer",
       "laufumgebung": "host-ro"}'

typ is one of shell|sql|http|grep|mcp. laufumgebung is one of host-ro|wegwerf-container|backend-ro. 201 for a new slug; calling this again with the same slug upserts titel/typ/befehl/ erwartung/laufumgebung and returns 200 — it does not touch the last run result.

The command allow-list

befehl is checked against a fixed set of allowed prefixes before it's accepted, and rejected outright if it contains a writing pattern — this is what keeps a "check" from becoming a second way to change data:

Allowed prefixes: gh api, git ls-files, git rev-list, curl -s, psql -c "SELECT, grep, ls, cat, test -f, docker inspect, bash scripts/ops/, python3 scripts/ops/.

Rejected if present anywhere in the command: >, rm, DELETE, UPDATE, INSERT, -X POST, git push, docker push. Note there is no bare push on this list — blocking it would also block read-only scripts whose names contain the word (e.g. a pre-push-* gate script executed via the scripts/ops/ prefix).

A command that isn't on the allow-list, or that contains one of these patterns, is rejected with 422 before anything is stored.

Set pruefweg_slug when you write the Aussage, so GET /warum/{sache} and the deviation list can find it:

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": "your-name",
       "pruefweg_slug": "ci-timeout-grep"}'

Run it

curl -sS -X POST "$COMPASS_URL/pruefwege/ci-timeout-grep/run" -H "X-Compass-Key: $COMPASS_KEY_RW"

This runs with a 30-second timeout, stores letzter_lauf/letztes_ergebnis, writes a fact (herkunft=gemessen, quelle=pruefweg:<slug>), and determines abweichung (does the result match erwartung?). A clean run (abweichung=false) resolves any open deviation state for this check.

In the app

Under Prüfwege (sidebar, section “Projekt”) every check is in one place: what it checks, when it last ran, what came out, and which rules it is attached to. A “Jetzt ausführen” button calls the same POST /pruefwege/{slug}/run as above.

Above that is the list of unchecked rules: rules in force with no check, with an ended check, or with one that has never run. If the rule book cannot be fetched, the list says “unknown” — not “none”.

See what's deviating

curl -sS "$COMPASS_URL/abweichungen" -H "X-Compass-Key: $COMPASS_KEY_RO"

Each entry names a determined cause — never a guess:

  • verstoss — the check ran and genuinely disagreed with the rule.
  • werkzeug_fehlt — the result matches a known missing-tool pattern (gh fehlt, kein git-repo, command not found, permission denied, no such file or directory, timeout nach 30s). This pattern always wins over the raw pass/fail reading — a missing tool is not a violation.
  • unklar — the expectation text itself couldn't be evaluated as true or false from the result.

stumm=true after three consecutive werkzeug_fehlt runs of the same check — a check that keeps reporting a missing tool stops being surfaced as an active alert (it still appears in this list; it's dropped only from the GET /offen count, so it never disappears silently). Nothing here clears itself on a later green run except by explicitly resolving it — see the three resolution endpoints (verfolgen, regel-ueberholt, pruefweg-kaputt) in the REST reference.

Ending a check

A check that is no longer needed is ended — not deleted.

curl -sS -X POST "$COMPASS_URL/pruefwege/ci-timeout-grep/beenden" \
  -H "X-Compass-Key: $COMPASS_KEY_RW" -H 'Content-Type: application/json' \
  -d '{"grund": "The check now runs in CI.", "von": "your-name"}'

grund and von are required. A state without a reason is a riddle a month later, and a check that disappears without anyone standing behind it is the quiet way out.

From then on:

  • The nightly pass no longer triggers it.
  • It no longer appears under GET /abweichungen.
  • The round no longer counts it — not even in the denominator.
  • POST .../run answers 409 and names the reason.

The row stays. GET /pruefwege still returns it, with beendet_am, beendet_grund, beendet_von and an unchanged last run. Ending it twice is 409: the first reason is the one that holds.