Anwendungsteil 5. Mutationstests von Spezifikationen
Status: Frontier. Mutationstests (mutation testing) für Spezifikationen und der Vektor der Immunitätsmetrik (immunity score) sind eine Praxis, die noch nicht standardisiert ist. Die Idee „eine Mutation – ein erwarteter Ausfall" gehört zu einer Empfehlung. Die Operatorsätze und Schwellenwerte selbst müssen projektspezifisch angepasst werden.
Für den Lerndurchlauf reicht es aus, examples/stress-mutator/ zu starten und zu sehen, dass eine Mutation einen erwarteten Ausfall liefert. Die Auswahl der Operatoren, der Schwellenwerte und des CI-Gateways ist der vollständige Produktions-Track.
Führen wir die Grundbegriffe ein. Mutationstests sind eine Technik, bei der das Referenz-Artefakt kontrolliert „verfälscht" wird und der Test-Kreislauf diesen Defekt fangen muss. Immunitätsmetrik ist eine vektorielle Metrik für die Robustheit des Validierers, bestehend aus drei Komponenten:
strict_reject_rate– Anteil der Fälle, die streng im erwarteten Schritt zurückgewiesen werden;depth_of_diagnostics– nützliche Diagnosetiefe bis zum Ausfall;recovery_time– Zeit bis zur Rückkehr zu einem stabilen Urteil.
Der bildliche Name „Impfung der Validierer" bedeutet gewöhnliche Mutationstests von Spezifikationen. Der Validierer erhält kontrolliert verfälschte Eingaben und muss diese im erwarteten Schritt zurückweisen.
Die Abgrenzung zu benachbarten Mechanismen ist folgende. In Kapitel 2 erzeugen Sie einen einzelnen manuellen Defekt, um das Lesen von Symptomen zu lernen. In diesem Kapitel erzeugen Sie eine Serie maschineller Mutationen, um die Robustheit des Validierers zu messen. In Kapitel 4 sucht der Verifier einen minimalen Gegenbeispiel zur Regel, anstatt einen Katalog von Mutationsoperatoren durchzugehen. In Kapitel 8 kann das Ergebnis solcher Prüfungen zum Beweis für das Urteil werden, ersetzt aber nicht die schiedsrichterliche Dateiprüfung selbst durch den Mutationsgenerator.
Das Kapitel stützt sich auf die Fakten-Disziplin aus Teil 9 des ersten Bandes. Ohne sie haben Mutationen keinen Sinn. Eine Mutation prüft gerade die Tatsache eines Ausfalls im erwarteten Schritt Given/When/Then. Das einfachste Beispiel dieser Disziplin tauchte bereits in der Lern-AgentClinic auf: ein leerer Bewertungstext aus Teil 12 muss zurückgewiesen werden. Hier wird dieselbe Logik zu einem 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(minimale Incident-Payload, auf derbase/base_spec.jsonim ausführbaren Beispiel aufbaut). - Spur für
capstone/: Seed, Operatorliste, drei Immunitätsmetriken und Urteil als Zeichenkette invalidation.mdfürhigh_memory_usage. - Hauptbegriffe des ersten Durchlaufs: Mutationstests (Einstieg ins Kapitel) und Immunitätsmetrik (Ausgang – drei Vektorkomponenten). Die übrigen – Mutationsoperatoren, Mutationsfabrik, „Impfung der Validierer" – sind nachschlagbar und werden erst bei der Einrichtung des CI-Gateways geöffnet.
- Was zurückzustellen ist: Auswahl der Operatoren, Kalibrierung der Schwellenwerte und CI-Gateway für Mutationen.
Ziel
Nach diesem Kapitel baut der Leser einen Generator entarteter Spezifikationen für das Incident-Management-Projekt und richtet einen Validierer-Kreislauf ein, der drei Dinge tut: absurd Fälle mit präziser Diagnostik zurückweist, die Beweiskette in SDD aufbewahrt, die Immunitätsmetrik vor dem Merge berechnet. Der Validierer hört auf, ein Syntax-Wächter zu sein, und wird zum Werkzeug anatomischer Diagnostik: Er zeigt die Tatsache des Ausfalls, das Feld, den Schritt Given/When/Then, die JSON-Schema-Regel, die Absturzsroute und das Regressionsrisiko. Dies stimmt mit dem „Spec-first"-Ansatz überein – der Vertrag geht der Planung und der Code-Implementierung voraus (GitHub Spec Kit).
Minimales Lernszenario
Lernfall
Produktions-Incident appointment_latency_spike (abgeleitet vom Lern-Feature /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 Validierer stoppt vor When:evaluate_sla_window mit dem Code EMPTY_REQUIRED_FIELD, vor der SLA-Berechnung und vor der Eigentümerauswahl.
Vorbereitung
book2/examples/stress-mutator/base/base_spec.json– korrekte Quelle.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-Referenz.
Schritte
cd book2/examples/stress-mutator. Erwartung: Sie befinden sich im Beispielverzeichnis, es gibt 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.jsonund je eine JSON-Datei pro Mutation werden erstellt.*- Determinismus-Kontrolle – Schritt 2 wiederholen. *Erwartung: Die Liste der
mutation_idund die Reihenfolge stimmen mit dem vorherigen Lauf überein.*
Schlecht: Ein einziger Lauf ohne Wiederholung – es ist unmöglich, einen deterministischen Generator von zufälligem Rauschen zu unterscheiden. Gut: Zwei aufeinanderfolgende Läufe, gleiche Reihenfolge der mutation_id, Regressionsbasis ist reproduzierbar.
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 jedemutation_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 hier aufhören: Das ausführbare Beispiel hat Determinismus der Mutationen, erwartete Ausfälle und Berechnung der Immunität bewiesen.
Wenn Qwen Code installiert ist und Sie eine zusätzliche Erklärung wünschen, führen Sie einen separaten optionalen Schritt aus:
qwen -p "Lies @out/validator_results.json und @expected/expected_failures.json. Welche Mutationen wurden nicht im erwarteten Schritt zurückgewiesen? Ändere die Dateien nicht." --approval-mode plan
Diese Anfrage ersetzt die ausführbare Prüfung nicht. Ihr Ergebnis kann als Kommentar für das Review verwendet werden, aber nicht als einziger Bereitschaftsnachweis.
Der vollständige Produktions-Track fügt ein separates CI-Gateway 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 das Merge. Ein lauffähiges Analogon speziell für stress-mutator gibt es im Lehrbuch nicht; ein ideennahes examples/goodhart-validator/scripts/ci_gate.py wird in Teil 10 gezeigt.
Kontrollnachweis
Die drei Metriken aus Schritt 6 erfüllen gleichzeitig die Schwellenwerte. manifest.json stimmt bitweise mit manifest.example.json überein. Falls Sie die optionale Qwen-Anfrage ausgeführt haben, darf ihre Ausgabe den ausführbaren Fakten nicht widersprechen. Ohne Determinismus, erwartete Ausfälle und grüne Immunitätsmetrik gilt die Lern-Pipeline nicht als grün.
Wie dies in capstone/ landet
Übertragen Sie in capstone/validation.md oder eine kurze capstone/README.md nur das Ergebnis des Smoke-Laufs: Seed, Operatoren, drei Immunitätsmetriken und Urteil. Übertragen Sie nicht das Verzeichnis out/mutations: Es soll eine reproduzierbare lokale Spur bleiben, kein prüfbares Artefakt.
Minimales 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
Prüfbare Spur
Das Verzeichnis out/ ist das Ergebnis eines lokalen Laufs und wird in book2/examples/.gitignore ignoriert. Committen Sie es nicht als Lern-Artefakt und machen Sie keinen Commit nur der Markierung halber. Für den ersten Durchlauf reicht eine Zeile in capstone/validation.md: Seed, Operatoren, drei Metriken und Verdict.
In Ihrem Produktions-Repository können Sie einen kurzen Bericht outputs/immunity.last-run.json speichern, falls er von CI erzeugt wird und am Review teilnimmt. Im Lern-Pfad bleibt die reproduzierbare Befehlskette und das obige minimale capstone-Fragment die Quelle der Wahrheit.
Schlüsselideen
Teilen Sie entartete Szenarien des Incident-Prozesses in vier Klassen. Leere Felder sind nicht nur null: Hierzu gehören auch leere Zeichenketten, leere Eigentümer-Arrays, fehlende severity, service_id oder runbook_ref – jede Leere, ohne die keine sichere Handlung gewählt werden kann. Zeitliche Anomalien sehen formal korrekt aus: ISO-Zeitstempel vorhanden, 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ührungskreislauf in endlose Neu-Definition von Eigentümer, Priorität oder nächster Aktion schicken.
Führen wir einen weiteren Begriff ein. Mutationsfabrik ist kein zufälliger Rauschgenerator, sondern ein deterministischer Mutator über der korrekten base_spec.json. Die Basisspezifikation wird in einen Syntaxbaum (AST) mit expliziten Given/When/Then-Knoten, SLA-Matrix, Eskalationsregeln und JSON-Schema-Fragmenten zerlegt. Dann werden Operatoren darauf angewendet:
Nullify– Nullsetzen eines Felds;FutureTime– Verschieben des Zeitstempels in die Zukunft;EscalationCycle– Hinzufügen einer Rückwärtskante im Eskalationsgraphen;
PriorityContradiction– Einführen sich gegenseitig widersprechender Prioritätsregeln.
In künftigen Erweiterungen kommt RecursiveDependency für indirekte Rekursion zwischen berechneten Feldern hinzu.
Das Prinzip „eine Mutation – ein erwarteter Ausfall" ist die Hauptregel der Fabrik. Zeigen wir den Kontrast.
Schlecht:
> Eine Mutation setzt gleichzeitig service_id auf null, kehrt den Eskalationsgraphen um und invertiert die Prioritäten; expected_failure ist nicht definiert.
Problem: Bei einem Fehlschlag kann die Ursache nicht lokalisiert werden. Der Validierer kann bei einem 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. Dieselbe Eingabe erzeugt dieselbe Liste von mutation_id in stabiler Reihenfolge. Dies ist entscheidend für das Duell zwischen Verifier und Implementor: Der strittige Fall kann reproduziert, beiden Rollen übergeben und geprüft werden, wer den Vertrag verletzt hat.
> [runnable] – Eine 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
#### CONTROL: Ein erneuter Lauf mit demselben Seed muss dieselbe Liste der mutation_id und dieselbe Reihenfolge liefern
Die kombinatorische Explosion tritt bereits bei Tiefe 2–3 auf. Geben Sie dem Generator eine Selektionspolitik vor, nicht die vollständige Aufzählung: Mindestens eine Mutation pro Klasse (Pflichtfeld, Zeitfenster, Eskalationsgraph, rekursive Abhängigkeit, Prioritätskonflikt). Verknüpfen Sie die Priorität der Operatoren mit der Incident-Historie: Falls Post-Mortems häufiger fehlerhafte Zeitfenster zeigen, geben Sie FutureTime und NegativeLag ein höheres Gewicht in der Warteschlange. Gezieltes Fuzzing-Testing prüft historisch anfällige Stellen des Vertrags, anstatt das Token-Budget für gleichmäßiges Chaos zu verbrauchen.
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 Verifier/Implementor mit Bindung an Given/When/Then-Schritte] C2 --> D C3 --> D C4 --> D D --> E[Diagnostik und Stack-Route] E --> F[mutation_id und validation.md] F --> G[CI-Gateway]
Binden Sie jede Mutation an einen konkreten Schritt Given/When/Then und eine konkrete JSON-Schema-Regel. Sonst 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, während die Mutation FutureTime(response_timestamp) zu When:evaluate_sla_window und der Einschränkung format + maximum(now) gehört.
Wenn eine Mutation Then:notify_primary_owner bricht, soll der Bericht das Wesen des Problems zeigen. Es geht nicht um die Benachrichtigung als Aktion. Es geht um die Unmöglichkeit, einen zulässigen Eigentümer nach Beschädigung der Route zu berechnen. Eine solche Rückverfolgung verkürzt die manuelle Fehlersuche: Der Ingenieur sieht den Punkt des Hängenbleibens, nicht nur das abschließende 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 Diagnostik von Zyklen erfordert einen separaten Graphen-Durchlauf. Der Grund ist, dass JSON Schema die Form der Daten gut prüft, aber nicht immer das topologische Verhalten der Route ausdrückt. Für EscalationCycle baut der Validierer einen gerichteten Graphen der Eigentümer oder Warteschlangen und startet eine Tiefensuche (DFS) mit Zuständen white/gray/black. Das Auffinden eines gray-Knotens liefert den minimalen Zyklus, z. B. primary_oncall → sre_lead → primary_oncall.
Für umkehrbare Prioritätsübergänge wird eine ähnliche Prüfung verwendet. Wenn P1 nach einer Regel auf P2 herabgestuft wird und dann eine andere Regel P2 ohne Tie-Breaker-Regel zurück auf P1 bringt, muss der Validierer vor der Ausführungsphase stoppen. Der Diagnosecode muss CYCLE_ESCALATION von PRIORITY_REVERSAL unterscheiden. Ersteres wird durch den Routengraphen behoben. Letzteres durch die Politik zur Konfliktlösung.
Prüfen Sie zeitliche Anomalien vor der Routenwahl. Falsche Zeit verzerrt SLA, Schweregrad und Wahl des Reaktionskanals. Geben Sie dem Validierer mindestens drei Anker – event_detected_at, event_received_at, vereinbartes now aus einer kontrollierten Zeitquelle – und eine Politik max_reaction_lag. Dementsprechend erhält ein Ausfall einen von drei Codes: INVALID_TIME_ANCHOR (wenn response_timestamp in der Zukunft liegt – Problem in der Eingabepayload), NEGATIVE_RESPONSE_LAG (negative Reaktionsverzögerung – Problem in der Zeitynormalisierung) oder STALE_INCIDENT_WINDOW (Ereignis älter als das zulässige Fenster – Problem in der SLA-Regel). Unterschiedliche Codes sind wichtig für das SDD-Log: Sie zeigen, wo genau der Vertrag geschwächt ist.
Rekursive Abhängigkeiten unterscheiden sich von Zyklen darin, dass sie nicht wie eine kurze Schleife im Graphen 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 erneut den bereits berechneten owner.
Für solche Fälle legen Sie ein Auflösungslimit fest, z. B. max_resolution_depth = 8. Speichern Sie die Spur der Auflösungsversuche. Wenn das Limit überschritten wird, gibt der Validierer RECURSION_LIMIT zusammen mit der Feldkette zurück, anstatt das Problem als Timeout zu tarnen. Dies schützt den LLM-Ausführer vor endloser Bedingungspräzisierung und macht Ausfallkaskaden beobachtbar.
Nun zur Immunitätsmetrik (Vektorkomponenten – zu Beginn des Kapitels). Führen Sie sie als Vektor ein, nicht als einzelne Gesamtnote. Wenn strict_reject_rate steigt, aber depth_of_diagnostics auf eins fällt, ist der Kreislauf strenger, aber blinder geworden. Wenn recovery_time_p95_ms das Limit überschreitet, beginnt selbst ein korrekter Validierer CI auszubremsen und provoziert Umgehungspraktiken.
Bauen Sie die Blockierung in CI auf Immunitätsschwellenwerten und Regressionsvergleich mit dem vorherigen Durchlauf auf. Beginnen Sie für den Lernkreislauf mit folgenden Werten:
strict_reject_rate >= 0.98,depth_of_diagnostics >= 3,recovery_time_p95_ms <= 1200.
Kalibrieren Sie die Werte dann anhand der tatsächlichen Last und Anzahl der Mutationen.
Das Merge wird blockiert, wenn eine neue Änderung eines von drei Dingen tut:
- eine alte
mutation_iddurchlässt, - die Diagnosetiefe verschlechtert,
- das Wiederherstellungszeitlimit überschreitet.
Ein solches Gateway schützt nicht nur JSON Schema, sondern den gesamten Validierer-Kreislauf: Normalisierer, Graphenprüfungen, Given/When/Then-Regeln und Berichtsformat.
> [runnable] – Der folgende Befehl 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 Gateway üblicherweise wie python3 scripts/ci_gate.py --strict-reject-min 0.98 --diag-depth-min 3 --recover-ms-p95 1200 --fail-on-regression aus. Ein fertiges Skript speziell für stress-mutator gibt es im Lehrbuch nicht; die Idee „ein nicht bestandener Schwellenwert = Block" bleibt im formähnlichen examples/goodhart-validator/scripts/ci_gate.py (Teil 10) erhalten.
Halten Sie die Laufergebnisse in SDD als Beweiskette fest, nicht als einmaliges Testlog: mutation_id, Unterschied (diff) der Spezifikation, ursprüngliches und mutiertes Fragment, Zurückweisungsjournal, Diagnosecode, stack_route, Verweis auf die JSON-Schema-Regel und abschließender Eintrag in validation.md. Für das Review ist es besonders nützlich, expected_failure und actual_failure zu speichern: Wenn sie abweichen, verwirft der Validierer den Fall möglicherweise zufällig oder zu spät. Eine solche Struktur verwandelt den Mutationskatalog in einen Präzedenzkatalog, in dem jede neue Regel mit einer konkreten blinden Zone 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 die Anzahl der Mutationen pro Klasse, die Übung zur Schwellenwertverschiebung und die Signale für eine Überprüfung sind in Anhang D, Abschnitt D.1 ausgelagert. Im ersten Durchlauf wird der Abschnitt nicht benötigt.
Beispiele und Anwendung
Beispiel: Eine korrekte Spezifikation beschreibt den Incident appointment_latency_spike. SLA verlangt Reaktion innerhalb 10 Minuten. Die Eskalationsroute führt von appointments_oncall zu sre_lead.
Der Mutator erzeugt m_20260517_nullify_855e4297f7. Darin ist das Feld severity durch eine leere Zeichenkette ersetzt. Die Mutation ist an Given:incident_received und die Regel severity.minLength gebunden. Der erwartete Ausfall ist EMPTY_REQUIRED_FIELD. Die Pipeline muss vor When:evaluate_sla_window stoppen, vor der SLA-Berechnung und vor der Eigentümerauswahl.
Wenn der Validierer stattdessen Then:notify_owner erreicht, bedeutet dies, dass das leere Feld severity zu tief durchgedrungen ist und eine falsche Benachrichtigung über einen nicht klassifizierten Incident erzeugen kann.
{
"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"
}
}
Ein zweites Beispiel prüft den Eskalationsgraphen für den Incident cdn_error_budget_burn. Der Eigentümer edge_oncall gibt P1 an traffic_sre weiter. Der Mutator fügt die Rückwärtskante traffic_sre → edge_oncall hinzu.
Was der Verifier tun soll. CYCLE_ESCALATION zurückgeben, den minimalen Zyklus zeigen und den Ausfall an When:route_escalation binden. Der Implementor darf dabei keine Umgehung vorschlagen wie „ersten Eigentümer aus der Liste wählen". Nach der Korrektur in JSON Schema oder in einer zusätzlichen Graphenregel wird dieselbe mutation_id erneut ausgeführt, um zu beweisen, dass der Patch genau den gefundenen Defekt schließt.
Der Eintrag in validation.md muss den Unterschied (diff), das Urteil, die Wiederherstellungszeit und den Verweis auf den CI-Lauf enthalten. Sonst kann die Entscheidung bei der nächsten Routenänderung nicht überprüft werden.
Zusammenfassung
Der Generator für Stress-Spezifikationen verwandelt die Validierer-Prüfung in einen steuerbaren Ingenieurkreislauf: Er klassifiziert entartete Szenarien, erzeugt reproduzierbare Mutationen, verknüpft jeden Ausfall mit einem Given/When/Then-Schritt und einer JSON-Schema-Regel, misst die Immunität über drei Vektorkomponenten und speichert Beweise in SDD über mutation_id, Spezifikationsunterschiede, Zurückweisungsjournal und validation.md. Ein solcher Kreislauf verwandelt absurde Fälle in einen Regressionssatz gegen künftige toxische Anforderungen und versteckte Ausfallkaskaden. Das nächste Kapitel geht zur Auktion von Schattenspezifikationen über.
Artefakte und Bereitschaftskriterien
| Artefakt | Bereit, wenn |
|---|---|
base/base_spec.json | beschreibt ein korrektes Incident-Szenario, auf dem die Mutationen aufgebaut werden |
Lokales out/mutations/ (4 Mutationen) | ein erneuter Lauf mit demselben seed liefert dieselbe Reihenfolge der mutation_id; das Verzeichnis wird nicht committed |
out/validator_results.json | jede Mutation ist mit einem Given/When/Then-Schritt und einer JSON-Schema-Regel verknüpft; es gibt diagnostic_code, halt_before, Tiefe (depth) |
| Minimaler Immunitätsbericht | die drei Vektorkomponenten sind ausgefüllt – strict_reject_rate, depth_of_diagnostics, recovery_time_p95_ms; das ausführbare Beispiel besteht den Smoke-Pass |
Der vollständige Track fügt expected/expected_failures.json als Regressionsbasis für CI hinzu, einen kurzen prüfbaren Bericht oder Eintrag in validation.md und ein CI-Gateway, das den neuen Lauf mit der alten mutation_id vergleicht. Betrachten Sie es als bereit, wenn der Validierer Zyklen und zeitliche Anomalien vor der Ausführungsphase stoppt und CI die Regression an mindestens einer 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): zurückgewiesen<n>/4Mutationen im erwarteten Schritt; Fehlschlag –<mutation_id>, zusätzlicher Guard nötig". *Erwartung: Bei der nächsten Regression wird gegen den fixiertenseedverglichen, nicht gegen „alles grün"*.
Kontrollfragen
- Warum reicht JSON Schema für die Prüfung von Zyklen und rekursiven Abhängigkeiten nicht aus?
- Was zeigt
strict_reject_rate, und was verbirgt er? - Wann wird wachsende Strenge des Validierers schädlich?
- Der Validierer hat den Smoke-Lauf mit 50 Mutationen bestanden und zeigte
strict_reject_rate=0.95,depth_of_diagnostics=2.4,recovery_time_p95_ms=900. Alle drei Skalare liegen innerhalb der Standardschwellenwerte. Nennen Sie mindestens ein Szenario, in 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 wird.