Praxis Teil 7. Specification CI: Spezifikation als ausführbares Artefakt
Status: Empfehlung. Spezifikationsprüfungen in CI auszuführen ist eine bewährte Praxis. Die konkrete Menge an Gates (Coverage, Scope, Schema, Spec_Gate) und das Format der JSON-Diagnostik sind ein empfohlener Rahmen, den die meisten Teams anpassen. Die JSON-Schema-Prüfung von Fixtures aus validation.md ist eine Standardnutzung des Werkzeugs.
In diesem Kapitel ist „Spezifikations-Gate“ die Kurzbezeichnung für den Prozess, der die Spezifikation genauso prüft wie normalerweise CI den Code. Die Prüfung selbst besteht aus gewöhnlichen Schritten: Parsen von requirements.md und plan.md, Validierung von Beispielen gegen JSON Schema, Prüfung der Übereinstimmungen zwischen Dateien. Alle weiteren Begriffe — gate, fixture, schema-check, coverage-check — werden unten an den Stellen eingeführt, wo sie tatsächlich im Team oder Skript auftauchen; sie müssen nicht in eine einleitende Zeile zusammengefasst werden.
Das Spezifikations-Gate ist die Automatisierung genau jenes Verfahrens, das Teil 9 des ersten Bandes manuell durchgeführt hat und Teil 16 im Team im Pull-Request. Im Lernprojekt AgentClinic konnten REQ-Identifikatoren und Nutzlastschemata für Reviews aus Teil 12 noch als informelle Vereinbarung bestehen. In der Produktion gibt es keinen solchen Vertrauenspuffer. Dieselben Verknüpfungen müssen in ein obligatorisches Gate umgewandelt werden, das grüne Unit-Tests nicht umgehen können.
Vor dem Lesen
- Bezug aus dem ersten Band: Teil 9 verknüpft
validation.mdmit Fakten, Teil 16 zeigt das Review des Nachweispakets. - Lokaler Lernfall:
incident payload, da Coverage und JSON Schema lokal ohne CI geprüft werden können. - Spur für
capstone/: eine Zeile Spec CI fürhigh_memory_usage: Befehl, nachgewiesener Fakt und negatives Beispiel. - Hauptbegriff beim ersten Durchgang: Spec CI.
gate,fixture,schema-check,coverage-check— nachschlagewürdig, erscheinen direkt im Befehl und Skriptkommentar. - Was zurückzustellen ist: GitHub Actions Workflow, Scope-Gate und Extraktion von Fixtures aus beliebigem
validation.md.
Ziel
In diesem Kapitel wird das Spezifikations-Gate von der Idee „Dokumente prüfen“ zu einem funktionierenden GitHub Actions-Prozess für das Incident-Projekt. Jeder push und jeder Pull-Request durchläuft ein obligatorisches Gate. Das Gate blockiert das Mergen bei drei Klassen von Verstößen:
- Nichterfüllung von Anforderungen,
- Überschreitung der Grenzen (out-of-scope),
- JSON-Schema-Fehler.
Der Leser erhält ein praktisches Repository-Schema, in dem requirements.md, plan.md, validation.md und API-Verträge als ausführbare Artefakte und nicht als Nachschlagdokumentation geprüft werden.
Der Hauptgewinn: Das Team erhält einen reproduzierbaren Blockiermechanismus in CI. Ein Streit über die Spezifikationsqualität reduziert sich auf eine konkrete Zeile, Regel und Korrekturmaßnahme.
Minimaler Lernszenario
Lernfall
incident payload: Prüfen, dass requirements.md mit plan.md verknüpft ist und JSON-Fixtures (Beispieleingabedaten, die wir aus validation.md extrahieren) die obligatorische incident_id enthalten. Ziel — Spec CI als kleines lokales Gate (obligatorische Prüfung, ohne die das Mergen blockiert wird) zu sehen, nicht als großer GitHub Actions-Prozess.
Vorbereitung
book2/examples/spec-ci/requirements.md.book2/examples/spec-ci/plan.md.
book2/examples/spec-ci/fixtures/valid-incident.json.book2/examples/spec-ci/fixtures/invalid-missing-incident-id.json.- Skripte
check_coverage.pyundvalidate_schema.py.
Schritte
cd book2/examples/spec-ci. Erwartung: Sie befinden sich im Verzeichnis des ausführbaren Beispiels.python3 scripts/check_coverage.py --requirements requirements.md --plan plan.md. *Erwartung: Rückgabecode 0, alleREQ-*haben eine Verknüpfung mit dem Plan.*python3 scripts/validate_schema.py --schema schemas/incident_payload.schema.json --fixtures fixtures. Erwartung: Valides Fixture besteht, Negativbeispiel fällt vorhersehbar durch.- Öffnen Sie die Fehlermeldung für das Negativbeispiel. Erwartung: Verständlich, welches Feld fehlt und welche Datei zu korrigieren ist.
- Notieren Sie in
validation.md, was genau das Gate blockiert: Coverage, Scope oder Schema.
Kontrollfakt
Ein lokaler Durchlauf zeigt zwei Arten von Wahrheit: Anforderung ist mit Plan verknüpft, Daten entsprechen dem Vertrag. Wenn ein CI-Fehler nicht Datei, Regel und Maßnahme angibt, ist er nicht teamreif.
Wie es in capstone/ übernommen wird
Übertragen Sie in capstone/validation.md eine Zeile Spec CI: Welcher Befehl ausgeführt wurde, was er bewies, welches Negativbeispiel blockiert wurde. Übertragen Sie keinen vollständigen GitHub Actions Workflow, falls er nicht erstellt wurde; für das Lernminimum genügt das ausführbare Analogon aus examples/spec-ci.
Minimaler Fragment:
| Spec CI | `python3 scripts/check_coverage.py ...` | alle REQ-* mit plan verknüpft | PASS |
| Schema negative | `python3 scripts/validate_schema.py ...` | missing incident_id blockiert | PASS |
Übertragung auf high_memory_usage
Das Lernbeispiel arbeitet mit incident payload, aber in capstone/ wird eine Zeile für high_memory_usage benötigt. Wenden Sie dieselben beiden Prüfklassen auf Ihre Anforderungen an:
| Was geprüft wird | Befehl (Lernversion) | Was es für high_memory_usage beweist |
|---|---|---|
| Coverage | check_coverage.py --requirements requirements.md --plan plan.md | Anforderung REQ-HM-01 „pod nicht ohne bestätigten RSS > 90% über 5 Minuten neustarten“ ist mit Aufgabe in plan.md verknüpft |
| Schema negative | validate_schema.py --schema schemas/incident_payload.schema.json --fixtures fixtures | Fixture ohne incident_id oder mit severity: "P0" ohne backup_verified wird blockiert |
Wenn die Zeilen Coverage und Schema negative für high_memory_usage nicht geschrieben werden können — dann gibt es in requirements.md noch keine prüfbare Anforderung oder das Schema unterscheidet P0 ohne Backup noch nicht.
Reviewbare Spur
Im Lernpaket behalten Sie Änderungen in requirements.md, plan.md, validation.md oder Schema bei. Temporäre Fixtures, die nur für lokale Diagnostik erstellt wurden, sind nicht nötig, falls sie nicht Teil der Regressionsmenge geworden sind.
Kernideen
Hier bedeutet „ausführbares Artefakt“ nicht das Ausführen von Markdown als Programm. Es geht um die Prüfung von Anforderungen, Plan und Beispielen mit gewöhnlichen CI-Skripten.
Führen Sie ein obligatorisches GitHub Actions-Gate sowohl bei pull_request als auch bei push in den geschützten Branch aus. Warum beide Trigger. Ein Spezifikationsverstoß kann auf zwei Wegen eintreten: durch gewöhnlichen Pull-Request oder durch direktes Update von Service-Dateien.
Minimale Menge überwachter Artefakte:
requirements.md,plan.md,validation.md,contracts/**,
constitution.md— bei Bedarf, falls darin Domänenbeschränkungen des Incident-Pipelines festgelegt sind.
In den Branch-Schutzeinstellungen markieren Sie genau die Endaufgabe spec_gate als obligatorisch. Sonst können grüne Unit-Tests die inhaltliche Prüfung umgehen. Dieses Schema entspricht dem SDD-Ansatz, bei dem Anforderungen, Plan und Aufgaben zu prüfbaren Schichten und nicht zu statischem Text werden (GitHub Spec Kit).
> [project script] — .github/workflows/spec-ci.yml ruft Projektskripte scripts/spec_ci/*.py auf.
name: spec-ci
on:
pull_request:
paths:
- 'requirements.md'
- 'plan.md'
- 'validation.md'
- 'contracts/**'
- 'constitution.md'
push:
branches: [main]
paths:
- 'requirements.md'
- 'plan.md'
- 'validation.md'
- 'contracts/**'
- 'constitution.md'
jobs:
coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: python3 scripts/spec_ci/check_coverage.py --requirements requirements.md --plan plan.md --out out/spec-ci/coverage-report.json
scope:
runs-on: ubuntu-latest
needs: [coverage]
steps:
- uses: actions/checkout@v4
- run: python3 scripts/spec_ci/check_scope.py --domain models/incident-response.yaml --plan plan.md --contracts contracts/api.md --out out/spec-ci/scope-violations.ndjson
schema:
runs-on: ubuntu-latest
needs: [coverage, scope]
steps:
- uses: actions/checkout@v4
- run: python3 scripts/spec_ci/extract_fixtures.py --from validation.md --out out/spec-ci/fixtures
- run: python3 scripts/spec_ci/validate_schema.py --schemas schemas --fixtures out/spec-ci/fixtures --out out/spec-ci/schema-audit.json
spec_gate:
runs-on: ubuntu-latest
needs: [coverage, scope, schema]
steps:
- run: echo "Specification gate passed"
Die Coverage-Prüfung beginnt mit dem Graphen requirements → plan, nicht mit der Suche nach übereinstimmenden Wörtern. Wir führen Traceability-Regeln ein:
- jede User Story aus
requirements.mderhält einen stabilen IdentifikatorREQ-*; - jede Aufgabe oder jeder Schritt in
plan.mdmuss über ein Feld wieimplements: [REQ-014]auf einen oder mehrere solcher Identifikatoren verweisen.
Was als Fehler gilt. Wenn eine Story keine tracebare Aufgabe hat, beenden Sie den Prozess mit fail: Das Team hat dem Nutzer ein Versprechen bereits vor Beginn der Implementierung verloren. Die umgekehrte Verletzung ist ebenso wichtig. Eine Aufgabe ohne implements wird zu einer herrenlosen (rogue task) Aufgabe. Das bedeutet, der Plan hat begonnen, Funktionalität hinzuzufügen, die von Anforderungen nicht bestätigt ist.
> [project script] — scripts/spec_ci/check_coverage.py; ausführbares Analogon — [examples/spec-ci/scripts/check_coverage.py](examples/spec-ci/).
python3 scripts/spec_ci/check_coverage.py \
--requirements requirements.md \
--plan plan.md \
--out out/spec-ci/coverage-report.json
Der Scope-Drift-Detektor ist für Fälle gedacht, wo die formale Traceability besteht, aber der Inhalt des Schritts die Grenzen der Incident-Domäne überschreitet. Gleichen Sie Aktionen aus plan.md mit dem Domänenmodell incident-response ab. Zulässige Operationen, zum Beispiel:
acknowledge,escalate,annotate,rollback,notify_on_call.
Beliebige Geschäftsaktionen (wie notify_finance, close_customer_contract oder force_resolve_without_operator) gehören hier nicht dazu.
Berücksichtigen Sie nicht nur das Verb. Prüfen Sie auch:
- den Akteur,
- den Endpunkt (endpoint),
- die Auslösebedingung.
Warum so. resolve incident kann dem manuellen Bereitschaftsoperator erlaubt und dem autonomen Agenten verboten sein. Die praktische Regel ist einfach: Wenn ein Schritt nicht durch das Incident-Modell und den erlaubten API-Vertrag erklärt werden kann, blockiert er den Pull-Request.
> [project script] — scripts/spec_ci/check_scope.py. Fertiges Analogon gibt es nicht; implementieren Sie selbst auf Basis des Domänenmodells und API-Vertrags.
python3 scripts/spec_ci/check_scope.py \
--domain models/incident-response.yaml \
--plan plan.md \
--contracts contracts/api.md \
--out out/spec-ci/scope-violations.ndjson
JSON Schema-Prüfungen schließen die Fixture- und Nutzlastbeispielschicht ab, wo oft stille Integrationsregressionen entstehen. Was zu tun ist:
- extrahieren Sie alle JSON-Blöcke aus
validation.md; - wandeln Sie sie in separate Fixtures um;
- validieren Sie gegen Schemata aus
schemas/**— zum Beispielincident_payload.schema.json,pagerduty_webhook.schema.jsonodergrafana_alert.schema.json.
Achten Sie auf zwei Richtungen. Valide Beispiele müssen fehlerfrei bestehen. Speziell negative Beispiele müssen vorhersehbar durchfallen. Wenn eine negative Nutzlast besteht, ist das Schema zu schwach und schützt den Vertrag nicht.
Vor dem Mergen in den geschützten Branch wird dies ebenso streng geprüft wie Anwendungstests. Eine falsche incident_id, ein inkorrekter severity oder eine leere source können den gesamten Remediation-Prozess zerstören.
> [project script] — scripts/spec_ci/extract_fixtures.py und scripts/spec_ci/validate_schema.py; ausführbares Analogon der Schema-Prüfung — [examples/spec-ci/scripts/validate_schema.py](examples/spec-ci/). Den Extraktionsschritt implementieren Sie selbst für das Format von validation.md Ihres Projekts.
python3 scripts/spec_ci/extract_fixtures.py \
--from validation.md \
--out out/spec-ci/fixtures
python3 scripts/spec_ci/validate_schema.py \
--schemas schemas \
--fixtures out/spec-ci/fixtures \
--out out/spec-ci/schema-audit.json
Gestalten Sie das Diagnoseformat für CI-Ablehnungen so, dass es zur schnellen Korrektur und nicht zur Untersuchung von Prozesslogs dient.
Schlecht: > Coverage failed: missing REQ
Problem: Der Reviewer weiß nicht, welche Anforderung verwaist ist und wo nachzusehen. Der Fehler lässt sich nicht ohne separate Untersuchung beheben.
Gut: > requirements.md:42: REQ-014 hat keine Verknüpfung in plan.md. Fügen Sie in plan.md eine Aufgabe mit implements: REQ-014 hinzu oder entfernen Sie die Anforderung.
Geben Sie in jedem Fehler vier Elemente an:
- verständliche Ursache,
- Verweis auf Datei und Zeile,
- Identifikator der verletzten Regel,
- konkrete Maßnahme für das Spezifikationsteam.
Fehlertypen sehen so aus. Für Coverage kann das sein: REQ-021 has no implementing plan item; add implements: [REQ-021] to plan.md or remove the requirement. Für Scope — plan.md:48 uses force_resolve without domain permission. Für Schema — validation.md:72 missing required property incident_id.
Dieses Format reduziert die Belastung des Reviewers. Die Person prüft den Sinn der Änderung und muss nicht rekonstruieren, was genau CI zerstört hat.
{
"status": "failed",
"check": "scope",
"file": "plan.md",
"line": 48,
"rule": "IR-SCOPE-007",
"reason": "Autonomous force resolve is outside the incident-response domain model",
"action": "Replace with POST /incidents/{id}/ack or add an approved requirement and domain rule"
}
Beispiele und Anwendung
flowchart LR A[pre-commit hook] B[lokaler Schnelldurchlauf und leichter Zweikampf vor push] C[PR push] D[Änderungsdateien auswählen] E[check_coverage Anforderungen Plan Aufgaben Graph] F[check_scope Domänenmodell und contracts/api] G[check_schema validation und Gegenbeispiele] H[Gate-Bericht und PR-Status] A --> B --> C --> D --> E --> F --> G --> H
Ein typischer Pull-Request im Lern-Incident-Repository ändert drei Dateien:
requirements.md,plan.md,validation.md.
Der Autor beschreibt die Story REQ-014: als Bereitschaftsingenieur (on-call) möchte ich eine Eskalationsbestätigung erhalten. Dann fügt er im Plan die Aufgabe TASK-033 mit implements: [REQ-014] hinzu. Und in validation.md legt er ein Nutzlastbeispiel für den Webhook mit den Feldern incident_id, severity, source und escalation_target ab.
Was geprüft wird. Die Coverage-Prüfung besteht, wenn die Verknüpfung REQ-014 → TASK-033 existiert. Die Scope-Prüfung besteht, wenn die Aktion dem Domänenmodell entspricht. Die Schema-Prüfung besteht, wenn die Nutzlast dem Vertrag entspricht. Wenn einer der drei Schichten bricht, gibt spec_gate einen roten Status zurück und GitHub erlaubt kein Mergen.
Aufschlussreicher Fehler: Der Autor versucht, die Bearbeitung zu „beschleunigen“ und fügt in plan.md den Schritt POST /pagerduty/force-resolve ohne separate Anforderung und ohne Erlaubnis im Domänenmodell hinzu. Die Coverage kann grün bleiben, wenn der Schritt formal an eine bestehende Story gebunden ist. Aber die Scope-Prüfung blockiert den Pull-Request: Autonomes Schließen eines Incidents ohne Bestätigung durch den Bereitschaftsoperator gehört nicht zu den vereinbarten Operationen.
Wenn derselbe Pull-Request in validation.md eine Nutzlast mit event_code statt der obligatorischen incident_id hinzufügt, gibt die Schema-Prüfung einen unabhängigen Blocker aus. Das Team erhält zwei verschiedene Fehlerklassen:
- inhaltlicher Scope-Verstoß,
- Datenstrukturverletzung.
Der lokale Schnelldurchlauf vor dem Push spart Zeit und macht das Spezifikations-Gate zum gewohnten Teil des Arbeitszyklus. Im pre-commit führen Sie nur geänderte Dateien aus. Den vollständigen Prozess überlassen Sie GitHub Actions, damit der Entwickler nicht durch lange Prüfung aller Fixtures ausgebremst wird.
Für das Incident-Projekt genügt ein Befehl, der drei Dinge tut:
- Coverage-Graphen aufbauen,
- Scope anhand von Differenzen (diff) prüfen,
- betroffene JSON-Blöcke validieren.
Wenn der lokale Bericht bereits orphan requirement, rogue task oder schema mismatch zeigt, korrigiert der Autor die Spezifikation vor Erstellung des Pull-Requests und nicht nach Erhalt des roten Status im Remote-CI.
> [project script] — Beispiel einer lokalen Wrapper für scripts/spec_ci/*.py.
#!/usr/bin/env bash
set -euo pipefail
python3 scripts/spec_ci/check_coverage.py \
--requirements requirements.md \
--plan plan.md \
--out out/spec-ci/coverage-report.json
python3 scripts/spec_ci/check_scope.py \
--domain models/incident-response.yaml \
--plan plan.md \
--contracts contracts/api.md \
--out out/spec-ci/scope-violations.ndjson
python3 scripts/spec_ci/extract_fixtures.py \
--from validation.md \
--out out/spec-ci/fixtures
python3 scripts/spec_ci/validate_schema.py \
--schemas schemas \
--fixtures out/spec-ci/fixtures \
--out out/spec-ci/schema-audit.json
Zusammenfassung
Das Spezifikations-Gate macht die Spezifikation zum ausführbaren Schiedsrichter des Repositorys. GitHub Actions blockiert den Pull-Request bei drei Klassen von Verstößen:
- ungedeckte User Stories,
- fremde Szenarien im Plan,
- JSON-Schema-Fehler in Validierungsbeispielen.
Für das Team ändert dies die Art des Reviews. Statt subjektiver Streit über die Vollständigkeit der Anforderungen erscheint ein Diagnosebericht mit Datei, Zeile, Regel und Maßnahme.
In der Incident-Automatisierung ist diese Strenge besonders wichtig. Falsche Scope-Grenzen oder schwache Nutzlastverträge können zu drei Folgen führen:
- falsche Eskalationen,
- gefährliche Autooperationen,
- Vertrauensverlust in die Remediation.
Als Nächstes wird dieser Prozess zur Grundlage für den Datei-Schiedsrichter bei strittigen Änderungen.
Das minimale ausführbare Set für dieses Kapitel liegt in examples/spec-ci/. Durchlaufen Sie es vor Einführung des vollständigen GitHub Actions-Prozesses. Erreichen Sie zuerst ein grünes lokales Gate. Dann übertragen Sie dieselben Befehle in CI.
> [runnable] — ausführbares Beispiel: examples/spec-ci/scripts/check_coverage.py und examples/spec-ci/scripts/validate_schema.py.
cd book2/examples/spec-ci
python3 scripts/check_coverage.py --requirements requirements.md --plan plan.md
python3 scripts/validate_schema.py --schema schemas/incident_payload.schema.json --fixtures fixtures
Artefakte und Fertigkeitskriterien
| Artefakt | Fertig, wenn |
|---|
| Lokaler Durchlauf book2/examples/spec-ci | Smoke-Pass ohne externe Abhängigkeiten | | Coverage-Prüfung requirements → plan | jede REQ-* hat eine realisierende Aufgabe, jede Aufgabe hat implements | | JSON Schema-Prüfung | Valides Fixture besteht, Negativbeispiel fällt vorhersehbar durch | | Eintrag in validation.md | Gate-Fehlermeldung gibt Datei, Regel und Korrekturmaßnahme an |
Der vollständige Track fügt .github/workflows/spec-ci.yml oder sein Projektanalogon, out/spec-ci/coverage-report.json für den Graphen requirements → plan, out/spec-ci/scope-violations.ndjson mit Domänenmodellverstößen, out/spec-ci/schema-audit.json für Fixtures aus validation.md und einen lokalen Schnelllauf-Wrapper hinzu. Betrachten Sie ihn als fertig, wenn die Scope-Prüfung autonome Aktionen außerhalb des Incident-Response-Modells blockiert, die Aufgabe spec_gate in der geschützten Branch obligatorisch ist und das CI-Diagnoseformat Datei, Zeile, Regelidentifikator und Maßnahme angibt.
Praxis
cd book2/examples/spec-ci && python3 scripts/check_coverage.py --requirements requirements.md --plan plan.md— *Erwartung: Code 0, stdout — eine Zeilecoverage ok: 3 requirements covered.*
python3 scripts/validate_schema.py --schema schemas/incident_payload.schema.json --fixtures fixtures— *Erwartung: Code 0; stdout enthältvalid-incident.json: validundinvalid-missing-incident-id.json: expected invalid, rejected: missing required property incident_id(Negativbeispiel ist mit_expected_invalid: truemarkiert und daher als erfolgreich abgelehnt zu betrachten).*- Übertragen Sie in
capstone/validation.mdeine Zeile Spec CI: „coverage ok: 3/3, schema ok: 2/2 (Negativbeispiel abgelehnt wegenmissing required property incident_id)“. Erwartung: Bei der nächsten Regression ermöglicht die Zeile die Rekonstruktion, was genau das Mergen blockiert, ohne Log-Lektüre.
Kontrollfragen
- Warum ist Wort-Coverage schwächer als der Graph
requirements → plan? - Welche Verstöße soll die Scope-Prüfung erkennen und welche nicht?
- Was macht einen CI-Fehler ohne Untersuchung behebbar?
- Das Spezifikations-Gate blockiert das Mergen wegen Nichtübereinstimmung der
REQ-ID. Der Programmierer möchteREQ-IDzu einem bestehenden Planpunkt hinzufügen und den Pull-Request mergen. Was ist an diesem Ansatz gefährlich?