Przejdź do głównej zawartości

Jak silna jest twoja wyrocznia? Zaufanie do testów, których nie czytałeś

Siła wyroczni to prawdopodobieństwo, że zestaw testów nie przejdzie, gdy testowany kod jest błędny. Mierzy się ją na kodzie, którego dotyka zmiana, czterema liczbami: wynikiem mutacyjnym, pokryciem kryteriów akceptacji, pochodzeniem testów i odsetkiem testów niestabilnych. Pętla działa bez nadzoru dopiero wtedy, gdy wszystkie cztery przekraczają próg ustalony wcześniej przez zespół.

Agent otwiera pull request z eksportem faktur. Dodaje 38 testów, pokrycie linii modułu wynosi 96%, CI świeci na zielono. Ręcznie zamieniasz jedno >= na > w filtrze zakresu dat i uruchamiasz testy ponownie. Nadal zielono. Nikt tych 38 testów nie przeczytał, a teraz wiesz, że nie sprawdzają granicy, o którą chodziło w zgłoszeniu. Ta strona jest dla programisty, który zatwierdza pull requesty agentów na podstawie dowodów, i dla tech leada, który decyduje, które pętle mogą pracować w nocy.

  • Cztery definicje metryk (wynik mutacyjny, pokrycie zachowań, pochodzenie, niestabilność) z dokładnym poleceniem, które daje każdą z nich.
  • Próg dla każdego toru pracy (interaktywny, w tle, nocny), który pętla musi przejść, zanim dostanie mniej nadzoru.
  • Zadanie CI, które testuje mutacyjnie tylko pliki zmienione w pull requeście i nie przechodzi poniżej twojego progu.
  • Cztery prompty do skopiowania: audyt wyroczni, zabijanie ocalałych mutantów bez dotykania kodu produkcyjnego, kontrole negatywne i szukanie niestabilnych testów.
  • Różnice między narzędziami przy uruchamianiu audytu w Claude Code, Codex i Cursorze.

Test jest wyrocznią tylko wtedy, gdy może nie przejść. Zielony wynik mówi, że sprawdzenia się wykonały i przeszły, ale nie mówi, czy nie przeszłyby przy błędnej implementacji. Przy testach pisanych przez agenta ta luka rośnie z trzech powodów: ten sam agent często pisze kod i testy w jednym pull requeście, dąży do zieleni, bo zieleń jest warunkiem stopu, i pisze testy szybko, więc ich liczba wygląda jak rzetelność.

Pokrycie linii tej luki nie zamyka. Ten test wykonuje każdą linię inRange i niczego nie sprawdza w wyniku:

// 100% pokrycia linii, zerowa siła wyroczni
it('filters invoices by date range', () => {
const result = inRange(invoices, '2026-01-01', '2026-01-31');
expect(result).toBeDefined();
});

Przejdzie go każda implementacja, która zwraca tablicę. Pokrycie liczy linie, które się wykonały; siła wyroczni liczy zachowanie, które sprawdzono. Cztery miary poniżej pozwalają odróżnić jedno od drugiego bez czytania każdego testu.

To właśnie mechanizm kontrolny, o którym pisze zespół badawczy DORA. Raport DORA 2025 stwierdza „a positive relationship between AI adoption on both software delivery throughput and product performance” oraz że „AI adoption does continue to have a negative relationship with software delivery stability”. Wyjaśnienie: „Without robust control systems, like strong automated testing, mature version control practices, and fast feedback loops, an increase in change volume leads to instability” (blog Google Cloud, Nathen Harvey i Derek DeBellis, 23.09.2025).

MiaraDefinicjaSkąd ją wziąćCo ukrywa słaba wartość
Wynik mutacyjny zmienionego koduWykryte mutanty (zabite lub przekroczone limitem czasu) podzielone przez poprawne mutanty (wykryte, ocalałe lub niepokryte) w plikach, których dotknęła zmianaStryker (JS/TS), mutmut (Python), cargo-mutants (Rust), PIT (JVM)Asercje, które nie porównują wyniku, brak przypadków granicznych, martwe gałęzie
Pokrycie zachowańKryteria akceptacji z nazwanym testem, który nie przechodzi po złamaniu kryterium, podzielone przez wszystkie kryteria akceptacjiMapa kryterium → test w pull requeście i jedna zapisana kontrola negatywna na testZachowanie, którego nikt nie opisał testem; testy pokrywające kod, a nie wymagania
Pochodzenie testówDla każdego decydującego testu: czy istniał przed uruchomieniem, kto go zatwierdził i czy ta zmiana go edytowałagit log i git diff na ścieżkach wyroczniAgent oceniający własną pracę domową: testy napisane lub poluzowane w tej samej zmianie
Odsetek testów niestabilnychTesty bramkujące, które na tym samym commicie raz przeszły, a raz nie, w oknie pomiarowym, podzielone przez wszystkie testy bramkującePowtarzane uruchomienia z wyłączonymi ponowieniamiSprawdzenia, które losowo świecą na czerwono i uczą wszystkich, ludzi i agentów, uruchamiać ponownie zamiast czytać

Pokrycie linii i gałęzi zostaje jako minimum. Utrzymuj próg, żeby nieprzetestowany kod był widoczny, ale nigdy nie traktuj wysokiej liczby jako dowodu siły.

Zmierz wynik mutacyjny kodu, którego dotknęła zmiana

Dział zatytułowany „Zmierz wynik mutacyjny kodu, którego dotknęła zmiana”

Narzędzie mutacyjne wprowadza drobne, celowe błędy (odwrócone porównanie, usunięte wywołanie, zmieniona stała) i uruchamia twoje testy na każdym z nich. Mutant, przy którym jakiś test nie przechodzi, jest zabity; taki, który przechodzi wszystkie testy, ocalał. Stryker liczy wynik jako wykryte mutanty podzielone przez poprawne, gdzie wykryte to zabite plus przekroczone limitem czasu, a poprawne to dodatkowo ocalałe i niepokryte; mutanty, które się nie kompilują, są pomijane (sprawdzone w mutation-testing-metrics dołączonym do @stryker-mutator/core 10.0.0, 26.09.2026).

Mierz zmieniony kod, a nie całe repozytorium. Wynik dla całego repozytorium rozmywa słaby nowy moduł w latach dobrze przetestowanego kodu, a pełne uruchomienie jest zbyt wolne, by bramkować każdy pull request. Opcja --mutate w Strykerze przyjmuje listę plików rozdzieloną przecinkami, a nawet zakresy linii (src/index.js:1:3-1:5), więc możesz mutować dokładnie to, co zmienił pull request:

// stryker.config.json (Stryker 10.0.0)
{
"testRunner": "vitest",
"coverageAnalysis": "perTest",
"reporters": ["clear-text", "progress", "json"],
"thresholds": { "high": 80, "low": 60, "break": 60 },
"incremental": true
}

thresholds.break to bramka: gdy końcowy wynik spada poniżej tej wartości, Stryker zapisuje błąd w logu i ustawia kod wyjścia 1. Bez break (domyślnie null) Stryker nigdy nie zatrzymuje builda, niezależnie od wyniku. Wartości high i low powyżej to domyślne progi Strykera do kolorowania raportu, a nie wynik badań; wartość break to polityka twojego zespołu. incremental zapisuje wyniki w reports/stryker-incremental.json i wykorzystuje je przy kolejnym uruchomieniu, a reporter json zapisuje reports/mutation/mutation.json, który może odczytać twój pakiet dowodów. Wtyczka runnera to osobny pakiet: npm i -D @stryker-mutator/core @stryker-mutator/vitest-runner.

Odpowiedniki w innych ekosystemach, sprawdzone 26.09.2026:

  • Python: mutmut 3.8.0. Ustaw source_paths (i opcjonalnie only_mutate) w sekcji [tool.mutmut] pliku pyproject.toml, uruchom mutmut run, przeglądaj wyniki przez mutmut results i mutmut show <nazwa>, a liczby dla CI zapisz przez mutmut export-cicd-stats (do mutants/mutmut-cicd-stats.json).
  • Rust: cargo-mutants 27.1.0. git diff origin/main... > pr.diff && cargo mutants --in-diff pr.diff testuje tylko mutanty nachodzące na diff. Jego własna dokumentacja ostrzega, że diff zmieniający wyłącznie kod testów nie uruchamia żadnych mutantów, więc pull request osłabiający testy wymaga sprawdzenia pochodzenia opisanego niżej.
  • JVM: PIT (pitest) to sprawdzone narzędzie; użyj jego wtyczki do Mavena lub Gradle’a.

Nie każdy ocalały mutant oznacza lukę. Mutant równoważny zmienia kod, ale nie zachowanie (na przykład zmieniony komunikat w logu, którego nikt nie sprawdza). Każdego ocalałego zaklasyfikuj na jeden z trzech sposobów: brakujący test, mutant równoważny albo zachowanie, którego świadomie nie przypinasz testem. Zapisz decyzję; ocalały mutant bez decyzji liczy się przeciwko pętli.

Zmierz pokrycie zachowań względem kryteriów akceptacji

Dział zatytułowany „Zmierz pokrycie zachowań względem kryteriów akceptacji”

Wynik mutacyjny mówi, czy testy zauważają zmianę. Pokrycie zachowań mówi, czy sprawdzają właściwe rzeczy. Zacznij od kryteriów akceptacji ze zgłoszenia (zobacz wykonywalne kryteria akceptacji) i wymagaj w pull requeście jednej linii na kryterium: kryterium, test, który go dowodzi, i kontrola negatywna, czyli wynik celowego złamania tego zachowania i obserwacji, że nazwany test świeci na czerwono.

AC-1 reversed range returns 400 -> tests/invoices/export.test.ts "rejects reversed range"
negative control: swapped the guard to `from < to`; check failed as expected
AC-2 amounts in invoice currency -> MISSING

Kontrola negatywna zamienia „test istnieje” na „test nie przechodzi, gdy zachowanie się psuje”. To celowana mutacja, którą wybierasz ty, a nie losowo narzędzie mutacyjne. MISSING jest dopuszczalną odpowiedzią: przekazuje kryterium człowiekowi i jest lepsze niż test wymyślony przez agenta tylko po to, żeby wypełnić wiersz.

Test dowodzi najwięcej, gdy istniał, zanim agent zaczął pracę, a agent nie mógł go edytować. Dwa polecenia odpowiadają na pytania o pochodzenie w pull requeście:

Okno terminala
# Terminal lub CI: których plików wyroczni dotknęła ta zmiana?
git diff --name-only origin/main...HEAD -- \
'*.test.*' '*.spec.*' '*__snapshots__*' '.github/workflows/*' \
'tsconfig*.json' 'vitest.config.*' 'stryker.config.*'
# Kiedy i przez kogo dodano decydujący test?
git log --diff-filter=A --format='%h %an %ad' --date=short -- tests/invoices/export.test.ts

Każdy decydujący test zaklasyfikuj jako istniejący wcześniej (dodany przed rozpoczęciem uruchomienia), zatwierdzony przez człowieka (napisany jako osobny wycinek pracy i zatwierdzony przed implementacją) albo z tej samej zmiany (napisany lub edytowany w tym pull requeście). Testy z tej samej zmiany mogą wspierać dowody, ale nie liczą się do progu dla pracy w tle ani nocnej. Egzekwowanie ścieżek, których agent nie może edytować, przez hooki, CODEOWNERS i sprawdzenia należące do CI, opisuje ochrona wyroczni.

Zmierz niestabilność testów z wyłączonymi ponowieniami

Dział zatytułowany „Zmierz niestabilność testów z wyłączonymi ponowieniami”

Niestabilny test osłabia wyrocznię w obie strony: zatrzymuje dobre zmiany i uczy ludzi oraz agentów, że czerwony znaczy „uruchom jeszcze raz”. Mierz go według harmonogramu, a nie w pull requeście, i z wyłączonymi ponowieniami, żeby nic się nie ukryło:

Okno terminala
# Co noc, z katalogu głównego repozytorium
npx playwright test --repeat-each 20 --retries 0 --reporter=json > flake-e2e.json
npx vitest run --repeats 10 --reporter=json --outputFile=flake-unit.json

Test, który nie przechodzi w powtarzanym uruchomieniu na commicie, na którym przechodzi też poprawnie, jest niestabilny. Wyłącz go ze zbioru testów bramkujących każdej pętli, która od niego zależy, napraw go albo usuń i przywróć dopiero wtedy, gdy przejdzie pełny pomiar. Jeśli w CI dla pull requestów zostawiasz ponowienia, uruchamiaj Playwrighta z --fail-on-flaky-tests, żeby test, który przechodzi dopiero przy ponowieniu, i tak zatrzymał uruchomienie (flagi sprawdzone w @playwright/test 1.63.0 i Vitest 5.0.2, 26.09.2026).

Jaki próg musi przejść pętla, zanim zacznie działać bez nadzoru?

Dział zatytułowany „Jaki próg musi przejść pętla, zanim zacznie działać bez nadzoru?”

Pętla to powtarzalna klasa zmian z własnym wyzwalaczem, wyrocznią i warunkiem stopu, zgodnie z definicją z jednej mapy. Próg należy do pętli, a nie do repozytorium: aktualizacje zależności mogą go przejść, a prace nad funkcjami w module płatności jeszcze nie. Tory pracy poniżej odpowiadają tym z przygotowania backlogu dla agentów.

MiaraInteraktywnyW tleNocny (bez nadzoru)
Wynik mutacyjny zmienionego koduRaportowanyNa poziomie progu break zespołu lub wyżejNa poziomie progu break lub wyżej i decyzja dla każdego ocalałego mutanta
Pokrycie zachowańKażde kryterium ma test albo oznaczenie MISSING100% zmapowane, każde z kontrolą negatywną100% zmapowane, każde z kontrolą negatywną
PochodzenieZmienione pliki wyroczni czyta człowiekDecydujące testy istniejące wcześniej lub zatwierdzone przez człowieka; edycja wyroczni wymaga eskalacjiDecydujące testy istniejące wcześniej; zero zmienionych plików wyroczni, egzekwowane poza promptem
NiestabilnośćZnanaZero niestabilnych testów w zbiorze bramkującym pętliZero niestabilnych wyników w całym oknie pomiarowym, ponowienia wyłączone
Pokrycie linii i gałęziMinimumMinimumMinimum

Progi to polityka, którą ustalasz i zapisujesz, a nie benchmark. Zacznij od domyślnego dolnego progu Strykera (60) jako wartości break dla pracy w tle i od górnego (80) dla pracy nocnej, a potem koryguj je na podstawie własnych danych: błąd, który przeszedł przez pętlę na produkcję, to powód, by podnieść próg albo zdegradować pętlę, a długa seria czystych pull requestów bez ocalałych mutantów to powód, by go utrzymać. Organizacje, które uruchamiają agentów na dużą skalę, trzymają wyrocznię poza zasięgiem agenta i ograniczają uruchomienie. Agenci Stripe pracują na istniejącym zestawie „over three million” testów i zatrzymują się po „at most two rounds of CI” (blog inżynierski Stripe, Alistair Gray, luty 2026).

Audyt jednej pętli zajmuje popołudnie. Zrób go przed awansowaniem pętli i ponownie po każdym błędzie, który przedostał się na produkcję.

  1. Nazwij pętlę i ścieżki jej wyroczni. Zapisz wyzwalacz, warunek stopu oraz wzorce plików testów, snapshotów, CI i konfiguracji, które tworzą jej wyrocznię. Umieść te wzorce w CODEOWNERS, żeby każda ich zmiana wymagała wskazanego recenzenta.

  2. Zmapuj kryteria akceptacji na testy. Dla ostatnich pięciu pull requestów w pętli wypisz każde kryterium i jego test. Luki oznacz jako MISSING. Promptem do kontroli negatywnych poniżej zapisz jedną kontrolę na test.

  3. Zmierz bazowy wynik mutacyjny. Uruchom narzędzie mutacyjne na modułach pętli z --incremental, żeby kolejne uruchomienia były szybkie. Każdego ocalałego mutanta zaklasyfikuj jako brakujący test, mutanta równoważnego albo zaakceptowany.

  4. Zamknij luki w zadaniu dotyczącym wyłącznie testów. Przekaż agentowi ocalałe mutanty i kryteria MISSING, zabroń zmian w kodzie produkcyjnym, a nowe testy niech zatwierdzi człowiek. Od tej chwili są testami istniejącymi wcześniej dla każdego kolejnego uruchomienia.

  5. Włącz bramkę dla każdej zmiany. Dodaj zadanie CI poniżej, żeby każdy pull request w pętli testował mutacyjnie własne zmienione pliki i nie przechodził poniżej progu break.

  6. Uruchom nocny pomiar niestabilności. Uruchamiaj polecenia z powtórzeniami według harmonogramu, wyłączaj niestabilne testy i trzymaj pętlę poza torem nocnym, dopóki całe okno pomiarowe nie będzie czyste.

  7. Zapisz wynik w pakiecie dowodów. Każdy pull request niesie wynik mutacyjny, mapę kryteriów, listę zmienionych plików wyroczni i stan niestabilności w formacie z pakietu dowodów.

To zadanie testuje mutacyjnie tylko pliki produkcyjne zmienione w pull requeście. O wyniku decyduje thresholds.break w stryker.config.json:

.github/workflows/oracle-strength.yml
name: oracle-strength
on: pull_request
jobs:
mutation:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version-file: .node-version
- run: npm ci
- name: Mutation-test the files this pull request changed
run: |
FILES=$(git diff --name-only --diff-filter=AM "origin/${{ github.base_ref }}...HEAD" -- 'src/*.ts' \
| grep -vE '\.(test|spec)\.ts$' | paste -sd, -)
if [ -z "$FILES" ]; then echo "No production files changed"; exit 0; fi
npx stryker run --mutate "$FILES"
- uses: actions/upload-artifact@v4
if: always()
with:
name: mutation-report
path: reports/mutation/

W pathspecu Gita * dopasowuje także /, więc 'src/*.ts' wybiera pliki TypeScript na dowolnej głębokości pod src/.

Miary, polecenia i prompty są takie same we wszystkich trzech narzędziach, bo mierzą narzędzia mutacyjne i testowe. Różni się to, jak uruchomić audyt bez interakcji, jak powstrzymać agenta przed edycją wyroczni w trakcie pracy i gdzie działa zadanie poprawiające same testy. Polecenia sprawdzono w Claude Code 2.1.283 i Codex CLI 0.157.1 26.09.2026; funkcje Cursora sprawdzono na cursor.com 28.08.2026.

Zapisz pierwszy prompt powyżej, „audyt wyroczni tego pull requesta”, jako prompts/oracle-audit.md; polecenia bez interakcji poniżej czytają go z tego pliku. Krok 2 tego promptu czyta powiązane zgłoszenie, więc uruchomienie bez interakcji potrzebuje dostępu do gh (lista dozwolonych narzędzi Claude Code poniżej zawiera gh issue view) albo kryteriów akceptacji wklejonych do pliku z promptem.

Audyt bez interakcji w CI. Sesje -p startują w trybie uprawnień Manual, więc przyznaj tylko to, czego audyt potrzebuje. Poniższe polecenie pozwala czytać pliki, historię Gita i powiązane zgłoszenie oraz uruchamiać Strykera, ale nie pozwala niczego edytować:

Okno terminala
# CI lub terminal, z katalogu głównego repozytorium
claude -p "$(cat prompts/oracle-audit.md)" \
--allowedTools "Read,Grep,Glob,Bash(git diff:*),Bash(git log:*),Bash(npx stryker run:*),Bash(gh issue view:*)" \
--max-budget-usd 3 --output-format json > oracle-audit.json

Dodaj --json-schema ze schematem tabeli PASS/FAIL, jeśli kolejny krok CI parsuje wynik.

Poprawa samych testów. W sesji interaktywnej ustaw warunek ukończenia przez /goal, na przykład /goal every survivor in reports/mutation/mutation.json under src/invoices is killed or listed as EQUIVALENT, and no file under src/ is modified. Claude pracuje, dopóki warunek nie zostanie spełniony, model nie uzna go za niemożliwy albo błąd nie wyczyści celu. Zabroń edycji src/** w ustawieniach uprawnień, zamiast ufać promptowi, i przed przyjęciem wyniku sprawdź, że git diff --name-only -- src/ jest puste.

Skille do testów mutacyjnych. Trail of Bits publikuje wtyczkę mutation-testing (1.9.2), która konfiguruje kampanie mewt lub muton i analizuje ocalałe mutanty: claude plugin marketplace add trailofbits/skills, a potem claude plugin install mutation-testing@trailofbits.

Nikt nie czyta każdego testu, więc sam pomiar musi dać się sprawdzić:

  • Liczby wylicza CI. Wynik mutacyjny, lista zmienionych plików wyroczni i stan niestabilności pochodzą z wyjścia narzędzi dołączonego do pull requesta, a nigdy ze streszczenia agenta.
  • Człowiek zatwierdza każdy nowy decydujący test, zanim zacznie się on liczyć jako istniejący wcześniej. To jedyne miejsce, w którym człowiek celowo czyta kod testów.
  • Tech lead odpowiada za progi i wzorce ścieżek wyroczni, przegląda decyzje o ocalałych mutantach w awansowanych pętlach i degraduje pętlę, gdy przejdzie przez nią błąd. Zasady awansu opisuje strona jak pomóc zespołowi przestać czytać każdy diff.
  • Każdy błąd, który przeszedł na produkcję, staje się testem. Napisz test, który by go złapał, potwierdź go kontrolą negatywną i dodaj do wyroczni, zanim pętla znów zacznie działać bez nadzoru.

Agent zabija mutanty testami-detektorami zmian. Sprawdza liczbę wywołań, prywatne funkcje pomocnicze albo dokładne komunikaty w logach, wynik rośnie, a testy psują się przy każdym refaktorze i nie łapią niczego nowego. Naprawa: wymagaj asercji na obserwowalnym zachowaniu (robi to drugi prompt) i odrzucaj każdy nowy test, który może się zepsuć tylko przez nieszkodliwy refaktor.

Wynik jest naginany przez zakres. Lista mutate się kurczy, pliki trafiają do wzorca ignorowania albo thresholds.break spada, żeby CI przeszło. Naprawa: traktuj konfigurację Strykera jako plik wyroczni z właścicielem w CODEOWNERS i wyliczaj listę mutowanych plików w CI z diffa, tak jak robi to powyższe zadanie, a nie z listy, którą pull request może edytować.

Testy mutacyjne są zbyt wolne, żeby na nich bramkować. Pełne uruchomienie na każdym pull requeście trwa zbyt długo, więc zespół je wyłącza. Naprawa: w pull requestach mutuj tylko zmienione pliki, używaj --incremental, a pełny wynik licz raz w tygodniu według harmonogramu.

Przekroczenia czasu liczą się jako zabicia. Stryker liczy mutanta, który przekroczył limit czasu, jako wykrytego. To poprawne przy nieskończonej pętli, ale może ukryć wolny, niestabilny test. Naprawa: jeśli w jednym pliku wiele mutantów kończy się przekroczeniem czasu, poszukaj testów z długim oczekiwaniem, zanim zaufasz wynikowi.

Ponowienia ukrywają niestabilność. Ponowienie zamienia niestabilną porażkę w sukces i odsetek wynosi zero. Naprawa: mierz niestabilność tylko w nocnym pomiarze z wyłączonymi ponowieniami i używaj --fail-on-flaky-tests wszędzie tam, gdzie ponowienia zostają.

Testy z tej samej zmiany liczą się jako dowód. Agent pisze kod i testy, które go błogosławią, a wszystkie liczby wyglądają zdrowo. Naprawa: o tym, co się liczy, decyduje klasyfikacja pochodzenia; testy z tej samej zmiany nigdy same nie przechodzą progu dla pracy w tle ani nocnej.

Najczęstsze pytania

Czym jest siła wyroczni?

Siła wyroczni to prawdopodobieństwo, że zestaw testów nie przejdzie, gdy kod jest błędny. Mierzy się ją czterema liczbami na kodzie, którego dotyka zmiana: wynikiem mutacyjnym, pokryciem kryteriów akceptacji, pochodzeniem testów i odsetkiem testów niestabilnych. Pokrycie linii to minimum, a nie miara siły.

Dlaczego pokrycie linii nie wystarcza przy testach pisanych przez agenta?

Pokrycie linii liczy kod, który się wykonał, a nie kod, który sprawdzono. Test bez asercji wykonuje każdą linię i przechodzi przy dowolnej implementacji. Testy mutacyjne celowo psują kod i liczą, ile tych zmian testy zauważyły, a to jest właściwość, na której naprawdę polegasz.

Jaki próg musi przejść pętla, zanim zacznie działać bez nadzoru?

Każde kryterium akceptacji ma przypisany test z zapisaną kontrolą negatywną, decydujące testy istniały przed uruchomieniem i leżą poza ścieżkami, które agent może edytować, wynik mutacyjny zmienionego kodu przekracza próg zespołu, a każdy ocalały mutant ma decyzję. Testy bramkujące nie dały żadnego niestabilnego wyniku w oknie pomiarowym przy wyłączonych ponowieniach.

Czy agent może sam podnieść wynik mutacyjny?

Tak, w osobnym zadaniu, które dotyczy wyłącznie testów. Agent pisze testy zabijające ocalałe mutanty, nie może zmieniać kodu produkcyjnego, a człowiek zatwierdza nowe testy, zanim zaczną się liczyć do wyroczni. Testy napisane w tym samym pull requeście co oceniany kod się nie liczą.