Praktischer Teil 5. Mutationstesten von Spezifikationen
Status: Frontier. Mutationstesten (mutation testing) für Spezifikationen und der Immunitäts-Score-Vektor (immunity score) — eine noch nicht standardisierte Praxis. Die Idee „ein Mutant — ein erwarteter Fehlschlag" ist eine Empfehlung. Die Operator-Sets und Schwellenwerte müssen projektspezifisch konfiguriert werden.
Für das Lernprogramm genügt es, examples/stress-mutator/ auszuführen und zu sehen, dass ein Mutant einen erwarteten Fehlschlag verursacht. Die Auswahl der Operatoren, die Kalibrierung der Schwellenwerte und das CI-Gate sind der vollständige Production-Track.
Führen wir die Grundbegriffe ein. Mutationstesten ist eine Technik, bei der ein Referenzartefakt kontrolliert „beschädigt" wird und der Testkontur verpflichtet ist, diesen Defekt zu erfassen. Immunitätsmetrik — ein vektorieller Wert für die Robustheit des Validators, bestehend aus drei Komponenten:
strict_reject_rate— Anteil der Fälle, die streng am erwarteten Schritt abgelehnt werden;depth_of_diagnostics— nützliche Diagnosetiefe vor dem Fehlschlag;recovery_time— Zeit bis zur Rückkehr eines stabilen Verdikts.
Die bildliche Bezeichnung „Validator-Vakzinierung" bedeutet einfach das übliche Mutationstesten von Spezifikationen. Der Validator erhält kontrolliert beschädigte Eingaben und muss sie am erwarteten Schritt ablehnen.
Die Grenze zu benachbarten Mechanismen ist folgende. In Kapitel 2 erstellen Sie einen manuellen Defekt, um Symptome lesen zu lernen. In diesem Kapitel erstellen Sie eine Serie maschineller Mutanten, um die Robustheit des Validators zu messen. In Kapitel 4 sucht der Verifikator ein minimales Gegenbeispiel zu einer Regel, anstatt einen Katalog von Mutationsoperatoren durchzugehen. In Kapitel 8 kann das Ergebnis solcher Prüfungen zum Beweis für ein Verdikt werden, aber die Datei-Schiedsrichterfunktion selbst ersetzt nicht den Mutantengenerator.
Das Kapitel stützt sich auf die Fakten-Disziplin aus Teil 9 des ersten Bandes. Ohne sie haben Mutationen keinen Sinn. Ein Mutant prüft genau die Tatsache des Fehlschlags am erwarteten Given/When/Then-Schritt. Das einfachste Beispiel dieser Disziplin wurde bereits in der Lernumgebung AgentClinic gezeigt: Ein leerer Rezensionstext aus Teil 12 muss abgelehnt werden. Hier wird dieselbe Logik auf einen Satz von Mutationsoperatoren verallgemeinert, die an den Katalog klassischer Fehler aus Teil 20. SDD-Antipatterns gebunden sind.
Vor dem Lesen
- Bezug aus dem ersten Band: Teil 9 führt Prüffakten ein, Teil 20 — Fehlerklassen des Prozesses.
- Lokaler Lernfall:
appointment_latency_spike(minimales Incident-Payload, darauf basiertbase/base_spec.jsonim ausführbaren Beispiel). - Spur für
capstone/: Seed, Operator-Liste, drei Immunitätsmetriken und Verdikt als Zeichenkette invalidation.mdfürhigh_memory_usage. - Hauptbegriffe für den ersten Durchlauf: Mutationstesten (Einstieg in das Kapitel) und Immunitätsmetrik (Ausgang — drei Vektorkomponenten). Alle anderen — Mutationsoperatoren, Mutationsfabrik, „Validator-Vakzinierung" — sind Nachschlagewerke, die erst bei der Konfiguration des CI-Gates geöffnet werden.
- Was zurückzustellen ist: Operator-Auswahl, Schwellenwertkalibrierung und CI-Gate für Mutationen.
Ziel
Nach diesem Kapitel wird der Leser einen Generator für ausgeartete Spezifikationen für ein Projekt zur automatisierten Incident-Steuerung zusammenstellen und den Validatorkontur so konfigurieren, dass er drei Dinge tut: absurde Fälle mit präziser Diagnostik ablehnt, die Beweiskette in SDD speichert und die Immunitätsmetrik vor dem Merge berechnet. Der Validator hört auf, ein Syntax-Wächter zu sein, und wird zu einem Werkzeug der anatomischen Diagnostik: Er zeigt den Fehlschlagsfakt, das Feld, den Given/When/Then-Schritt, die JSON-Schema-Regel, die Absturzroute und das Regressionsrisiko. Dies ist konsistent mit dem „Spezifikation zuerst"-Ansatz (spec-first) — der Vertrag geht der Planung und Implementierung des Codes voraus (GitHub Spec Kit).
Minimaler Lernszenario
Lernfall
Production-Incident appointment_latency_spike (abgeleitet von der Lernfunktion /agents aus book/part-11-second-feature-phase.md): SLA 10 Minuten, Eskalation von appointments_oncall zu sre_lead. Die Mutation Nullify setzt severity auf Null. Erwartung — der Validator stoppt vor When:evaluate_sla_window mit dem Code EMPTY_REQUIRED_FIELD, vor der SLA-Berechnung und vor der Besitzerwahl.
Vorbereitung
book2/examples/stress-mutator/base/base_spec.json— korrekte Quelldatei.book2/examples/stress-mutator/expected/expected_failures.json— erwartete(diagnostic_code, halt_before)unter dem Schlüsselby_operatorund Immunitätsschwellenwerte inthresholds.book2/examples/stress-mutator/scripts/mutate_specs.py,fake_validator.py,immunity_score.py.book2/examples/stress-mutator/manifest.example.json— Determinismus-Etalon.
Schritte
cd book2/examples/stress-mutator. Erwartung: Sie befinden sich im Beispielverzeichnis, keine zusätzlichen Abhängigkeiten.python3 scripts/mutate_specs.py --base base/base_spec.json --seed 20260517 --operators Nullify,FutureTime,EscalationCycle,PriorityContradiction --out out/mutations. *Erwartung:out/mutations/manifest.jsonwird erstellt und je eine JSON-Datei pro Mutant.*- Determinismuskontrolle — Schritt 2 wiederholen. *Erwartung: Die Liste
mutation_idund die Reihenfolge stimmen mit dem vorherigen Lauf überein.*
Schlecht: ein einzelner Lauf ohne Wiederholung — es ist unmöglich, einen deterministischen Generator von zufälligem Rauschen zu unterscheiden. Gut: zwei aufeinanderfolgende Läufe, identische Reihenfolge der mutation_id, reproduzierbare Regressionsbasis.
out/mutations/manifest.jsonmitmanifest.example.jsonüberdiffvergleichen. Erwartung: 0 Zeilen Unterschied.python3 scripts/fake_validator.py --mutations out/mutations --out out/validator_results.json. *Erwartung: Für jedesmutation_idgibt es im Ergebnis ein Paardiagnostic_code+halt_before.*python3 scripts/immunity_score.py --validator-results out/validator_results.json --expected expected/expected_failures.json. *Erwartung:strict_reject_rate >= 0.98,depth_of_diagnostics >= 3,recovery_time_p95_ms <= 1200.*- Für das Lernminimum an dieser Stelle stoppen: Das ausführbare Beispiel hat Determinismus der Mutanten, erwartete Fehlschläge und Immunitätsberechnung bewiesen.
Wenn Qwen Code installiert ist und Sie eine zusätzliche Erklärung wünschen, führen Sie den separaten optionalen Schritt aus:
qwen -p "Lies @out/validator_results.json und @expected/expected_failures.json. Welche Mutanten werden nicht am erwarteten Schritt abgelehnt? Ändere die Dateien nicht." --approval-mode plan
Diese Anfrage ersetzt keine ausführbare Prüfung. Ihr Ergebnis kann als Review-Kommentar verwendet werden, aber nicht als alleiniger Fakt der Fertigstellung.
Der vollständige Production-Track fügt ein separates CI-Gate hinzu. In Ihrem Projekt ist dies üblicherweise python3 scripts/ci_gate.py --strict-reject-min 0.98 --diag-depth-min 3 --recover-ms-p95 1200 --fail-on-regression — drei Schwellenwerte, jede Verletzung blockiert den Merge. Ein ausführbares Äquivalent speziell für stress-mutator gibt es im Lehrbuch nicht; ein ähnliches Konzept zeigt examples/goodhart-validator/scripts/ci_gate.py in Teil 10.
Kontrollfakt
Die drei Metriken aus Schritt 6 erfüllen gleichzeitig die Schwellenwerte. manifest.json stimmt bitweise mit manifest.example.json überein. Wenn der optionale Qwen-Aufruf ausgeführt wurde, darf seine Ausgabe den ausführbaren Fakten nicht widersprechen. Ohne Determinismus, erwartete Fehlschläge und grüne Immunitätsmetrik gilt der Lernpipeline nicht als grün.
Wie es in capstone/ übernommen wird
Übertragen Sie in capstone/validation.md oder ein kurzes capstone/README.md nur das Ergebnis des Smoke-Laufs: Seed, Operatoren, drei Immunitätsmetriken und Verdikt. Übertragen Sie nicht das Verzeichnis out/mutations: Es sollte ein reproduzierbarer lokaler Verbleib bleiben, kein reviewfähiger Artefakt.
Minimaler Fragment:
stress_run:
seed: 20260517
operators: [Nullify, FutureTime, EscalationCycle, PriorityContradiction]
strict_reject_rate: "1.0 >= 0.98"
depth_of_diagnostics: "4.0 >= 3"
recovery_time_p95_ms: "850 <= 1200"
verdict: PASS
Reviewfähiger Verbleib
Das Verzeichnis out/ ist das Ergebnis eines lokalen Laufs und wird in book2/examples/.gitignore ignoriert. Committen Sie es nicht als Lernartefakt und machen Sie keinen Commit nur für eine Markierung. Für den ersten Durchlauf genügt eine Zeile in capstone/validation.md: Seed, Operatoren, drei Metriken und Verdikt.
In Ihrem Production-Repository können Sie einen kurzen Bericht outputs/immunity.last-run.json speichern, wenn er vom CI erstellt wird und am Review teilnimmt. Im Lernpfad bleibt die Quelle der Wahrheit die reproduzierbare Befehlszeile und das minimale capstone-Fragment oben.
Schlüsselideen
Teilen Sie ausgeartete Incident-Prozess-Szenarien in vier Klassen. Leere Felder — das ist nicht nur null: Hierher gehören auch leere Zeichenketten, leere Besitzer-Arrays, fehlende severity, service_id oder runbook_ref — jede Leere, ohne die keine sichere Aktion gewählt werden kann. Zeitliche Anomalien sehen formal korrekt aus: Es gibt eine ISO-Marke, aber response_timestamp liegt vor event_received_at oder nach dem vereinbarten now. Umkehrbare Eskalationszyklen und rekursive Abhängigkeiten sind gefährlicher als gewöhnliche Auslassungen — sie können den Ausführungskontur in eine endlose Neuzuweisung von Besitzer, Priorität oder nächster Aktion schicken.
Führen wir einen weiteren Begriff ein. Mutationsfabrik — kein zufälliger Rauschgenerator, sondern ein deterministischer Mutator über einem korrekten base_spec.json. Die Basisspezifikation wird in einen abstrakten Syntaxbaum (AST) mit expliziten Given/When/Then-Knoten, einer SLA-Matrix, Eskalationsregeln und JSON-Schema-Fragmenten zerlegt. Darauf werden Operatoren angewendet:
Nullify— Feld auf Null setzen;FutureTime— Zeitmarke in die Zukunft verschieben;EscalationCycle— Rückwärtskante im Eskalationsgraphen hinzufügen;
PriorityContradiction— gegensätzliche Prioritätsregeln einführen.
In zukünftigen Erweiterungen wird RecursiveDependency für indirekte Rekursion zwischen berechneten Feldern hinzugefügt.
Das Prinzip „ein Mutant — ein erwarteter Fehlschlag" ist die Hauptregel der Fabrik. Zeigen wir den Kontrast.
Schlecht:
> Ein Mutant setzt gleichzeitig service_id auf Null, dreht den Eskalationsgraphen um und invertiert die Prioritäten; expected_failure ist nicht definiert.
Problem: Bei einem Fehlschlag kann die Ursache nicht lokalisiert werden. Der Validator kann bei jedem der drei Defekte stoppen, die Regression ist an ein zusammengesetztes Artefakt gebunden.
Gut:
> Ein Mutator Nullify setzt nur severity auf Null; expected_failure.code = EMPTY_REQUIRED_FIELD, halt_before = When:evaluate_sla_window.
Jeder Lauf erhält einen festen Seed (seed). Derselbe Eingang erzeugt dieselbe Liste mutation_id in stabiler Reihenfolge. Dies ist kritisch für das Duell zwischen Verifikator und Implementor: Der strittige Fall kann reproduziert, beiden Rollen übergeben und geprüft werden, wer genau den Vertrag verletzt hat.
> [runnable] — Die minimale Implementierung dieser Schnittstelle findet sich in examples/stress-mutator/README.md.
cd book2/examples/stress-mutator
python3 scripts/mutate_specs.py \
--base base/base_spec.json \
--seed 20260517 \
--operators Nullify,FutureTime,EscalationCycle,PriorityContradiction \
--out out/mutations
python3 scripts/fake_validator.py \
--mutations out/mutations \
--out out/validator_results.json
#### KONTROLLE: Wiederholter Lauf mit demselben Seed muss dieselbe Liste mutation_id und dieselbe Reihenfolge liefern
Kombinatorische Explosion tritt bereits bei Tiefe 2–3 auf. Geben Sie dem Generator eine Auswahlpolitik, keine vollständige Aufzählung: Mindestens ein Mutant pro Klasse (Pflichtfeld, Zeitfenster, Eskalationsgraph, rekursive Abhängigkeit, Prioritätskonflikt). Verknüpfen Sie die Operator-Priorität mit der Incident-Historie: Wenn Post-Mortems häufiger fehlerhafte Zeitfenster zeigen, geben Sie FutureTime und NegativeLag höheres Gewicht in der Warteschlange. Gerichtetes Fuzzing-Testen prüft historisch brüchige Stellen des Vertrags, anstatt das Token-Budget auf gleichmäßiges Chaos zu verschwenden.
flowchart TD A[Datei base_spec.json] --> B[AST-Normalisierer] B --> C[Mutationsfabrik] C --> C1[Nullify] C --> C2[FutureTime] C --> C3[EscalationCycle] C --> C4[PriorityContradiction] C1 --> D[Duell Verifikator/Implementor mit Schrittbindung Given/When/Then] C2 --> D C3 --> D C4 --> D D --> E[Diagnostik und Stapelroute] E --> F[mutation_id und validation.md] F --> G[CI-Gate]
Binden Sie jeden Mutanten an einen konkreten Given/When/Then-Schritt und eine konkrete JSON-Schema-Regel. Andernfalls bleibt die Diagnostik zu allgemein für eine Korrektur. Die Bindungen müssen explizit sein: Die Mutation Nullify(service_id) gehört zu Given:incident_received und der Regel required.service_id, die Mutation FutureTime(response_timestamp) zu When:evaluate_sla_window und der Einschränkung format + maximum(now).
Wenn ein Mutant Then:notify_primary_owner bricht, muss der Bericht das Kernproblem zeigen. Es geht nicht um die Benachrichtigung als Aktion. Es geht um die Unmöglichkeit, einen zulässigen Besitzer nach der Beschädigung der Route zu berechnen. Eine solche Ablaufverfolgung verkürzt die manuelle Fehlersuche: Der Ingenieur sieht den Stockpunkt, nicht nur das endgültige VALIDATION_FAILED.
{
"mutation_id": "m_20260517_0009",
"operator": "EscalationCycle",
"target_step": "When:route_escalation",
"json_schema_rule": "$defs.escalation_graph.no_cycles",
"failed_step": "Verifier::GraphCheck::Escalation",
"stack_route": [
"schema.normalize",
"step.when.prepare",
"graph.build",
"graph.detect_cycle",
"halt"
]
}
Die Zyklusdiagnostik erfordert einen separaten Graph-Durchlauf. Der Grund ist, dass JSON Schema die Datenform gut prüft, aber nicht immer das topologische Verhalten der Route ausdrückt. Für EscalationCycle baut der Validator einen gerichteten Graphen von Besitzern oder Warteschlangen auf und startet eine Tiefensuche (DFS) mit Zuständen white/gray/black. Die Entdeckung eines gray-Knotens liefert einen minimalen Zyklus, zum Beispiel primary_oncall → sre_lead → primary_oncall.
Für umkehrbare Prioritätsübergänge wird eine ähnliche Kontrolle verwendet. Wenn P1 nach einer Regel auf P2 herabgestuft wird und dann eine andere Regel P2 ohne Entscheidungsregel (tie_breaker) zurück in P1 bringt, muss der Validator vor der Ausführungsphase stoppen. Der Diagnosecode muss CYCLE_ESCALATION von PRIORITY_REVERSAL unterscheiden. Ersteres wird durch den Routengraphen korrigiert. Letzteres durch die Konfliktlösungspolitik.
Prüfen Sie zeitliche Anomalien vor der Routenbildung. Falsche Zeit verzerrt SLA, Severity und die Wahl des Reaktionskanals. Geben Sie dem Validator mindestens drei Anker — event_detected_at, event_received_at, vereinbartes now aus einer kontrollierten Zeitquelle — und eine Politik max_reaction_lag. Entsprechend erhält der Fehlschlag einen von drei Codes: INVALID_TIME_ANCHOR (wenn response_timestamp in der Zukunft liegt — Problem in der Eingabelast), NEGATIVE_RESPONSE_LAG (negative Reaktionsverzögerung — Problem in der Zeitnormalisierung) oder STALE_INCIDENT_WINDOW (Ereignis älter als zulässiges Fenster — Problem in der SLA-Regel). Unterschiedliche Codes sind wichtig für das SDD-Journal: Sie zeigen, wo genau der Vertrag geschwächt ist.
Rekursive Abhängigkeiten unterscheiden sich von Zyklen dadurch, dass sie nicht wie ein kurzer Graphkreislauf aussehen müssen. Typische Kette: owner wird aus priority berechnet, priority hängt von blast_radius ab, blast_radius fragt owner_group an, und owner_group erfordert wieder den bereits berechneten owner.
Für solche Fälle legen Sie eine Auflösungsgrenze fest, zum Beispiel max_resolution_depth = 8. Bewahren Sie die Spur der Abhängigkeitsauflösungsversuche auf. Wenn die Grenze überschritten wird, liefert der Validator RECURSION_LIMIT zusammen mit der Feld-Kette, anstatt das Problem unter einem Timeout zu verbergen. Dies schützt den LLM-Ausführer vor endloser Bedingungsverfeinerung und macht die Fehlerkaskade beobachtbar.
Nun zur Immunitätsmetrik (Komponenten des Vektors — am Kapitelanfang). Führen Sie sie als Vektor ein, nicht als einzelne Gesamtbewertung. Wenn strict_reject_rate steigt, aber depth_of_diagnostics auf eins fällt, wurde der Kontur strenger, aber blinder. Wenn recovery_time_p95_ms das Limit überschreitet, beginnt selbst ein korrekter Validator, den CI zu verlangsamen und Umgehungspraktiken zu provozieren.
Bauen Sie die Blockierung im CI auf Immunitätsschwellenwerten und Regressionsvergleich mit dem vorherigen Lauf auf. Für den Lernkontur beginnen Sie mit folgenden Werten:
strict_reject_rate >= 0.98,depth_of_diagnostics >= 3,recovery_time_p95_ms <= 1200.
Kalibrieren Sie dann die Werte nach tatsächlicher Last und Mutantenanzahl.
Der Merge wird blockiert, wenn eine neue Änderung mindestens eines der drei bewirkt:
- Einen alten
mutation_idüberspringt, - Die diagnostische Tiefe verschlechtert,
- Das Wiederherstellungszeitlimit überschreitet.
Ein solches Gate schützt nicht nur das JSON Schema, sondern den gesamten Validatorkontur: Normalisierer, Graph-Prüfungen, Given/When/Then-Regeln und Berichtsformat.
> [runnable] — Der Befehl unten entspricht book2/examples/stress-mutator.
cd book2/examples/stress-mutator
python3 scripts/immunity_score.py \
--validator-results out/validator_results.json \
--expected expected/expected_failures.json
In Ihrem Projekt sieht dieses Gate üblicherweise so aus: python3 scripts/ci_gate.py --strict-reject-min 0.98 --diag-depth-min 3 --recover-ms-p95 1200 --fail-on-regression. Ein fertiges Skript speziell für stress-mutator gibt es im Lehrbuch nicht; die Idee „ein nicht bestandener Schwellenwert = Block" ist in dem ähnlich geformten examples/goodhart-validator/scripts/ci_gate.py (Teil 10) erhalten.
Fixieren Sie Laufergebnisse im SDD als Beweiskette, nicht als einmaliger Testlog: mutation_id, Spezifikationsdiff, Original- und mutierter Fragment, Ablehnungsjournal, Diagnosecode, stack_route, Verweis auf JSON-Schema-Regel und Endeintrag in validation.md. Für das Review ist es besonders nützlich, expected_failure und actual_failure zu speichern: Wenn sie abweichen, lehnt der Validator den Fall möglicherweise zufällig oder zu spät ab. Eine solche Struktur verwandelt den Mutantenkatalog in einen Präzedenzfallkatalog, wo jede neue Regel mit einer konkreten Blindstelle und einer prüfbaren Begründung verknüpft ist.
Vollständiger Track: Schwellenwertkalibrierung
Die Tabelle „Niedrig / Standard / Hoch" für strict_reject_rate, depth_of_diagnostics, recovery_time_p95_ms und Mutantenanzahl pro Klasse, die Übung zur Schwellenwertverschiebung und Signale zur Überprüfung sind in Anhang D, Abschnitt D.1 ausgelagert. Für den ersten Durchlauf ist der Abschnitt nicht nötig.
Beispiele und Anwendung
Beispiel: Eine korrekte Spezifikation beschreibt den Incident appointment_latency_spike. Das SLA verlangt eine Reaktion innerhalb von 10 Minuten. Die Eskalationsroute geht von appointments_oncall zu sre_lead.
Der Mutator erzeugt m_20260517_nullify_855e4297f7. Darin ist das Feld severity durch eine leere Zeichenkette ersetzt. Der Mutant ist mit Given:incident_received und der Regel severity.minLength verknüpft. Erwarteter Fehlschlag — EMPTY_REQUIRED_FIELD. Die Pipeline muss vor When:evaluate_sla_window stoppen, vor der SLA-Berechnung und vor der Besitzerwahl.
Wenn der Validator stattdessen bis Then:notify_owner kommt, bedeutet dies, dass das leere Feld severity zu tief durchgesickert ist und möglicherweise eine falsche Benachrichtigung über einen nicht klassifizierten Incident erzeugt.
{
"mutation_id": "m_20260517_nullify_855e4297f7",
"base_case": "appointment_latency_spike",
"operator": "Nullify",
"target_step": "Given:incident_received",
"json_schema_rule": "$.properties.severity.minLength",
"diff_spec": {
"before": { "severity": "P1" },
"after": { "severity": "" }
},
"expected_failure": {
"code": "EMPTY_REQUIRED_FIELD",
"halt_before": "When:evaluate_sla_window"
}
}
Das zweite Beispiel prüft den Eskalationsgraphen für den Incident cdn_error_budget_burn. Besitzer edge_oncall übergibt P1 an traffic_sre. Der Mutator fügt eine Rückwärtskante traffic_sre → edge_oncall hinzu.
Was der Verifikator tun muss. CYCLE_ESCALATION zurückgeben, den minimalen Zyklus anzeigen und den Fehlschlag an When:route_escalation binden. Der Implementor darf dabei keine Umgehung wie „wähle den ersten Besitzer aus der Liste" vorschlagen. Nach der Korrektur im JSON Schema oder in einer zusätzlichen Graph-Regel wird derselbe mutation_id wiederholt gestartet, um zu beweisen, dass der Patch genau den gefundenen Defekt schließt.
Der Eintrag in validation.md muss Diff, Verdikt, Wiederherstellungszeit und Verweis auf den CI-Lauf enthalten. Andernfalls ist die Entscheidung bei der nächsten Routenänderung nicht überprüfbar.
Zusammenfassung
Der Stress-Spezifikationsgenerator verwandelt die Validator-Prüfung in einen steuerbaren Ingenieurzyklus: Er klassifiziert ausgeartete Szenarien, erzeugt reproduzierbare Mutationen, bindet jeden Defekt an einen Given/When/Then-Schritt und eine JSON-Schema-Regel, misst die Immunität durch drei Vektorkomponenten und speichert Beweise im SDD über mutation_id, Spezifikationsdifferenzen, Ablehnungsjournal und validation.md. Ein solcher Kontur verwandelt absurde Fälle in einen Regressionssatz gegen zukünftige toxische Anforderungen und verborgene Fehlerkaskaden. Das nächste Kapitel geht über zum Auktionierungsverfahren für Schattenspezifikationen.
Artefakte und Fertigstellungskriterien
| Artefakt | Fertig, wenn |
|---|---|
base/base_spec.json | Beschreibt ein korrektes Incident-Szenario, auf dem Mutationen aufgebaut werden |
Lokaler out/mutations/ (4 Mutanten) | Wiederholter Lauf mit demselben seed liefert dieselbe Reihenfolge mutation_id; Verzeichnis wird nicht committet |
out/validator_results.json | Jeder Mutant hat einen gebundenen Given/When/Then-Schritt und eine JSON-Schema-Regel; es gibt diagnostic_code, halt_before, Tiefe (depth) |
| Minimaler Immunitätsbericht | Drei Vektorkomponenten sind ausgefüllt — strict_reject_rate, depth_of_diagnostics, recovery_time_p95_ms; ausführbares Beispiel besteht Smoke-Pass |
Der vollständige Track fügt expected/expected_failures.json als Regressionsbasis für CI hinzu, einen kurzen reviewfähigen Bericht oder Eintrag in validation.md und ein CI-Gate, das einen neuen Lauf mit einem alten mutation_id vergleicht. Betrachten Sie es als fertig, wenn der Validator Zyklen und zeitliche Anomalien vor der Ausführungsphase stoppt und das CI eine Regression durch mindestens einen alten mutation_id blockiert.
Praxis
cd book2/examples/stress-mutator && python3 scripts/mutate_specs.py --base base/base_spec.json --seed 20260517 --out out/mutations— *Erwartung: Inout/mutations/genau 4 Dateien mitmutation_idm_20260517_nullify_855e4297f7,m_20260517_futuretime_…,m_20260517_escalationcycle_…,m_20260517_prioritycontradiction_…;diff out/mutations/manifest.json manifest.example.jsonliefert 0 Zeilen Unterschied.*python3 scripts/fake_validator.py --mutations out/mutations --out out/validator_results.json && python3 scripts/immunity_score.py --validator-results out/validator_results.json --expected expected/expected_failures.json --out out/immunity.json— *Erwartung:strict_reject_rate >= 0.98,depth_of_diagnostics >= 3,recovery_time_p95_ms <= 1200.*- Übertragen Sie in
capstone/validation.mdeine Zeile: „Immunität (seed=20260517):<n>/4Mutanten am erwarteten Schritt abgelehnt; Fehlschlag —<mutation_id>, zusätzlicher Guard nötig". *Erwartung: Bei der nächsten Regression erfolgt der Vergleich gegen den festenseed, nicht gegen „alles grün".*
Kontrollfragen
- Warum ist JSON Schema für die Prüfung von Zyklen und rekursiven Abhängigkeiten unzureichend?
- Was zeigt
strict_reject_rate, und was verbirgt er? - Wann wird zunehmende Validator-Strenge schädlich?
- Der Validator hat einen Smoke-Lauf mit 50 Mutanten übersprungen und zeigte
strict_reject_rate=0.95,depth_of_diagnostics=2.4,recovery_time_p95_ms=900. Alle drei Skalare liegen innerhalb der Standard-Schwellenwerte. Nennen Sie mindestens ein Szenario, unter dem dieser Lauf als fehlgeschlagen gelten sollte, und welche zusätzlichen Felder von manifest.json geprüft werden müssen, damit ein solcher Fehlschlag für den nächsten Reviewer sichtbar ist.