Awesome Testing

Markdown document

Podsumowanie sesji Codex

Lekcja 17: Równoległe pokrycie admin i non-admin

Historical artifacts may name disposable training credentials and environments. Do not reuse credentials, target course systems, or execute archived prompts without authorization.

Podsumowanie sesji Codex

Zakres sesji

Materiał obejmuje trzy powiązane ze sobą taski Codex:

  1. sesję koordynującą, w której przeanalizowano plan testów, przygotowano dwa prompty do pracy równoległej, a po zakończeniu obu strumieni wykonano review i integrację,
  2. sesję nie-adminową rozwijającą testy użytkowników, odzyskiwania hasła i traffic logs na https://awesome.byst.re,
  3. sesję adminową rozwijającą testy zamówień na https://aitesters.byst.re.

Punktem startowym było 84 przechodzących testów w l14. W folderze istniały już dwa projekty Playwright: api dla zwykłych użytkowników oraz admin-api dla administracyjnego stagingu. Celem nie było jedynie rozdzielenie listy endpointów, ale zorganizowanie pracy tak, aby agenci:

  • nie edytowali tych samych klientów, fixture'ów i testów,
  • nie modyfikowali cudzych danych ani danych seedowanych,
  • wiedzieli o istnieniu drugiej sesji,
  • nie uruchamiali pełnych suite'ów równocześnie,
  • przekazali koordynatorowi osobne, gotowe do review branche.

Finalny rezultat obu strumieni został po review zintegrowany i zweryfikowany wspólnym uruchomieniem 101 testów.

Sesja 1: przygotowanie pracy równoległej

Prompt użytkownika

Pierwsza sesja rozpoczęła się od prośby o zaprojektowanie bezpiecznej pracy w dwóch oknach Codex. Użytkownik chciał zachować dużą autonomię agentów, ale jednocześnie uczynić ich świadomymi równoległego zadania:

work in l14, use english (i'll speak polish)

Chciałbym zacząć pracować równolegle nad dwoma osobnymi wątkami, czyli
chciałbym część testów napisać do wątku admina, a część napisać do wątku
nie-admina. Zastanów się, co moglibyśmy zrobić, żeby było bezpiecznie.
Napisz mi prompty do Kodeksa, prompty dosyć wysokopoziomowe, żeby dać
autonomię agentom w Kodeksie, ale napisz mi prompty do jednego okna, do
drugiego okna i wspomnij o tym, że będzie też drugi wątek.

Analiza przed przygotowaniem promptów

Codex przeczytał l14/api-test-plan.md, strukturę testów, istniejące fixture'y, konfigurację dwóch projektów Playwright oraz listę niepokrytych endpointów. Najważniejsze ryzyko dotyczyło zamówień: testy admina potrzebowały zamówienia utworzonego przez zwykłego użytkownika, a więc potencjalnie wspólnych klientów, typów i danych testowych.

Zaproponowany podział odpowiedzialności był celowo oparty na plikach i obszarach domenowych:

  • agent nie-adminowy otrzymał użytkowników, auth, email events i traffic,
  • agent adminowy otrzymał adminowe zamówienia oraz pierwszą infrastrukturę cart/order potrzebną do utworzenia własnego zamówienia testowego,
  • wspólnym plikiem pozostał api-test-plan.md, ale każdy agent miał zmieniać wyłącznie własną, wyraźnie nazwaną sekcję,
  • żaden agent nie miał scalać, przełączać ani resetować brancha drugiego agenta.

Codex zalecił dwa osobne worktree utworzone z tego samego czystego commita. Było to ważniejsze niż samo użycie dwóch branchy, ponieważ dwa branche otwarte w tym samym fizycznym checkoutcie nadal współdzielą pliki robocze.

Prompt dla agenta nie-adminowego

Przygotowany prompt dawał agentowi autonomię w wyborze stabilnego pokrycia, ale nie pozwalał zamieniać niezweryfikowanych błędów serwera w oczekiwania regresyjne:

$api-testing-skill

Work only in l14 and communicate in English.

You are the non-admin half of two concurrent Codex tasks. The sibling task is
titled “L14 Admin Order Coverage” and is working on admin order coverage
against the dedicated staging backend. Assume both tasks started from the same
clean commit but use separate Codex worktrees and branches.

Your goal is to autonomously improve non-admin API coverage against the
authoritative course API, https://awesome.byst.re.

Start with the independent items in the Thread A section of
l14/api-test-plan.md:

- GET /api/v1/users/me/email-events
- GET /api/v1/traffic/logs/{correlationId}
- POST /api/v1/users/password/forgot
- POST /api/v1/users/password/reset

Treat these as an ordered investigation backlog, not a requirement to force
all four into regression tests. Explore first and implement only behavior that
is verified, stable, and safe to lock down. If token access, asynchronous
behavior, or missing observability prevents reliable assertions, document the
exact evidence and blocker instead of creating a flaky or speculative test.

You own non-admin users, authentication, email-event, and traffic tests and
their directly related clients, DTOs, and support code. Do not modify admin,
cart, or order-owned paths. Do not merge, rebase, reset, or edit the sibling
branch or worktree.

Stay aware of the sibling task. Prefer Codex task-list/read tools. If those
tools are unavailable, inspect only the relevant sibling session information
under ~/.codex in read-only mode. Never expose secrets from logs.

Run newly added tests first. Then run the complete l14 suite, but never while
the sibling is running a full suite.

Prompt dla agenta adminowego

Drugi prompt wymagał, aby każdy test operował wyłącznie na zamówieniu utworzonym przez własny fixture:

$api-testing-skill

Work only in l14 and communicate in English.

You are the admin half of two concurrent Codex tasks. The sibling task is
titled “L14 Non-Admin Coverage” and is covering users/auth/email-events/traffic
against https://awesome.byst.re. Assume both tasks started from the same clean
commit but use separate Codex worktrees and branches.

Your goal is to autonomously add safe admin order coverage against the
dedicated staging backend, https://aitesters.byst.re, using the existing
admin-api Playwright project and configured admin credentials.

Focus on:

- an endpoint-specific disposable order setup,
- GET /api/v1/orders/admin,
- PUT /api/v1/orders/{id}/status.

Never mutate an arbitrary or pre-existing order returned by the admin list.
Status changes must target an order created by this task's own setup. Use
unique generated data and clean up generated users/products whenever
supported. If safe isolation or cleanup is impossible, document the blocker
instead of altering shared staging data unpredictably.

You own admin order tests, cart/order clients, order DTOs and disposable order
fixtures. Do not modify the sibling's users/password, email-event, or traffic
paths. Do not merge, rebase, reset, or edit the sibling branch or worktree.

Run the changed tests, then the admin project, then the complete l14 suite.
Never run the full suite while the sibling is running it.

Oba prompty wskazywały też wspólne reguły repozytorium: obowiązkowe discovery przez curl, sprawdzenie api-docs.json i kodu backendu, inicjalizowanie klientów w beforeEach, sekcje given, when, then, osobny spec dla każdej operacji i kolejność testów według rosnących kodów odpowiedzi.

Sesja 2: agent nie-adminowy

Discovery i pierwszy ważny blocker

Agent utworzył branch codex/l14-non-admin-coverage i przed zmianami uruchomił pełny baseline: 84 testy przeszły.

Następnie przygotował jednego tymczasowego użytkownika i rozpoczął obowiązkową eksplorację live API. Pierwszy skrypt zatrzymał się, gdy okazało się, że POST /api/v1/users/password/forgot nie udostępnia reset tokenu. Agent nie próbował zgadywać dalszego scenariusza. Najpierw posprzątał użytkownika, a następnie sprawdził OpenAPI i dostępne endpointy mail/outbox.

Eksploracja wykazała:

  • znany i nieznany użytkownik otrzymują identyczny status 202 i komunikat,
  • właściwość token jest obecna, ale ma wartość null,
  • pusty identifier zwraca 400,
  • brak publicznego tokenu lub udokumentowanego outboxa blokuje stabilny test poprawnego resetu hasła,
  • błędny payload resetu i nieznany token dają stabilne odpowiedzi 400.

Email events

Agent potwierdził, że nowy użytkownik otrzymuje pustą listę email events, a wywołanie forgot-password tworzy zdarzenie PASSWORD_RESET_REQUESTED. Ponieważ zapis jest asynchroniczny, test nie zakłada natychmiastowej dostępności. Używa ograniczonego czasowo pollingu i wyszukuje zdarzenie po typie.

Test sprawdza sam fakt zapisania i udostępnienia zdarzenia, a nie powodzenie zewnętrznego dostarczenia wiadomości. Dlatego status jest sprawdzany względem udokumentowanego zbioru, a pola czasowe strukturalnie.

Traffic logs i wykryty błąd 500

Agent wysłał kontrolowany request z unikalnym X-Client-Session-Id, odnalazł go przez GET /api/v1/traffic/logs, a następnie pobrał szczegóły po otrzymanym correlationId.

Pierwsza analiza ujawniła dodatkową rozbieżność: api-docs.json opisywał clientSessionId jak query parameter, natomiast kod backendu odczytywał X-Client-Session-Id z nagłówka. Agent powtórzył całą próbę z właściwym nagłówkiem. Wynik się nie zmienił:

  • lista zwracała dokładnie kontrolowany wpis,
  • szczegóły tego samego, świeżo zwróconego correlationId dawały 500 {"message":"Internal server error"},
  • losowy, nieistniejący identyfikator dawał poprawne, puste 404.

Agent nie dodał testu oczekującego 500. Pokrył tylko stabilną ścieżkę 404, a udokumentowane 200 oznaczył jako zablokowane błędem backendu.

Implementacja

Powstały cztery nowe specyfikacje:

  • tests/api/users/email-events.get.spec.ts,
  • tests/api/users/password-forgot.post.spec.ts,
  • tests/api/users/password-reset.post.spec.ts,
  • tests/api/traffic/logs-correlation-id.get.spec.ts.

Rozszerzono klientów auth, users i traffic oraz odpowiadające im DTO. Zakres pozostał zgodny z ustalonym ownershipem: agent nie dotknął adminowych testów, fixture'ów zamówień ani klientów cart/order.

Pierwsze uruchomienie nowych testów dało 5 zaliczonych i 3 niezaliczone testy. Nie był to błąd serwera, lecz zbyt luźne podsumowanie wcześniejszej eksploracji: testy zakładały brak pola token, podczas gdy live API serializowało token: null. Agent poprawił DTO, asercje i opis discovery, po czym ten sam zestaw zakończył się wynikiem 8/8.

Po skoordynowaniu okna testowego z agentem adminowym pełny suite tego brancha zakończył się wynikiem 92/92. Branch został zapisany w commicie 79602c8.

Sesja 3: agent adminowy

Sprawdzenie bezpiecznego cyklu życia zamówienia

Agent adminowy przeanalizował OpenAPI, kontrolery, serwisy, encje i testy backendu. Musiał odpowiedzieć na kluczowe pytanie: jak utworzyć zamówienie do testu i jak je później usunąć, skoro API nie udostępnia endpointu kasowania zamówień.

Potwierdzony cykl setupu wyglądał następująco:

  1. logowanie admina,
  2. utworzenie unikalnego klienta stagingowego,
  3. logowanie tego klienta,
  4. utworzenie unikalnego produktu przez admina,
  5. dodanie produktu do koszyka klienta,
  6. utworzenie zamówienia z koszyka.

Kod backendu i live API potwierdziły, że usunięcie wygenerowanego klienta transakcyjnie usuwa jego koszyk i zamówienia. Dopiero potem można bezpiecznie usunąć produkt. Agent sprawdził ten porządek na danych wygenerowanych wyłącznie na potrzeby własnej eksploracji.

Pierwszy pomocniczy skrypt eksploracyjny nie wykonał scenariusza, ponieważ została w nim użyta nazwa status, zarezerwowana w zsh jako zmienna read-only. Cleanup trap nadal wykonał bezpieczną próbę sprzątania. Agent zmienił nazwę zmiennej i powtórzył cały scenariusz, zamiast pomijać discovery.

Implementacja adminowa

Powstały:

  • fixtures/disposable-order.ts,
  • generator/order-generator.ts,
  • httpclients/orders-client.ts,
  • types/orders.ts,
  • tests/api/admin/orders/admin.get.spec.ts,
  • tests/api/admin/orders/id-status.put.spec.ts.

Rozszerzono także klienta i typy koszyka. Fixture tworzył pełny, unikalny łańcuch user → product → cart item → order. Test listy adminowej nie zakładał określonej zawartości stagingu: wyszukiwał własne zamówienie po dynamicznym id. Każdy test zmiany statusu, również 401, 403 i 404, używał id zamówienia utworzonego przez własny fixture.

Pokrycie GET /api/v1/orders/admin objęło 200, 400, 401 i 403. Pokrycie PUT /api/v1/orders/{id}/status objęło 200, niedozwolone przejście statusu jako 400, a także 401, 403 i 404.

Agent zauważył dwie niestandardowe obserwacje:

  • wysłanie nieznanej wartości enuma statusu z poprawnym tokenem admina zwracało 401, chociaż ten sam token działał bezpośrednio przed i po requestcie; podejrzenie dotyczyło obsługi błędu deserializacji lub zabezpieczonego error dispatchu,
  • updatedAt nie zawsze zmieniał się przy natychmiastowej aktualizacji statusu, dlatego test nie porównuje timestampów na nierówność.

Niepoprawnego 401 dla nieznanego enuma nie zapisano jako oczekiwania regresyjnego.

Nowe specyfikacje zakończyły się wynikiem 9/9, pełny projekt admin-api wynikiem 34/34, a pełny suite brancha adminowego wynikiem 93/93. Branch został zapisany w commicie 49cb383.

Jak agenci komunikowali się podczas pracy?

Prompty zakładały osobne worktree, ale po uruchomieniu okazało się, że oba taski początkowo pracowały w tym samym fizycznym checkoutcie. Agent adminowy zauważył nieśledzony skrypt eksploracyjny utworzony przez agenta nie-adminowego. Nie usunął go ani nie kontynuował pracy w ryzykownym stanie.

Przez mechanizm wiadomości między taskami wysłał ostrzeżenie:

The tasks are not actually isolated despite the prompt assumption. I will not
touch your file. I am moving my admin branch/work into a separate Git worktree.
Please avoid l14/api-test-plan.md until you are on your own branch/worktree,
and re-check git status before edits or test runs.

Agent nie-adminowy natychmiast wstrzymał implementację, sprawdził branch i worktree, a po rozdzieleniu checkoutów potwierdził:

This checkout is now safely on codex/l14-non-admin-coverage with only my
Thread A/non-admin changes. I confirmed your admin branch is isolated. Please
continue there; do not restore or switch this checkout.

Drugi etap komunikacji dotyczył testów. Oba branche tworzyły użytkowników na żywych środowiskach, a plan zawierał wcześniejsze dowody rate limitu przy uruchomieniach wykonywanych zbyt blisko siebie. Agent nie-adminowy zakończył 8 testów celowanych, ale wstrzymał pełny suite. Agent adminowy przekazał wynik 9/9 oraz 34/34 i zarezerwował okno na własny pełny suite.

Po wyniku 93/93 agent adminowy wysłał wiadomość, że okno jest wolne. Dopiero wtedy agent nie-adminowy uruchomił pełny suite i uzyskał 92/92. Na końcu przekazał ten wynik z powrotem agentowi adminowemu. Dzięki temu dwa niezależne taski nie wykonywały równocześnie najcięższego zestawu requestów.

Komunikacja nie służyła do współdzielenia niezatwierdzonych zmian. Agenci przekazywali wyłącznie stan, ownership, wyniki testów i moment zwolnienia wspólnego zasobu.

Review w sesji koordynującej

Prompt do review

Po zakończeniu obu tasków użytkownik wrócił do pierwszej sesji:

check changes from both of these agents and let me know what should I review.

Additionally I'd like to have a bug report ready to investigate the error
returned by one of the agents

Koordynator odczytał oba taski Codex, porównał branche z punktem startowym, sprawdził historię commitów, komplet zmienionych plików, git diff --check oraz rzeczywiste komendy testowe agentów. Review potwierdziło poprawny podział ownershipu, kolejność testów, beforeEach, sekcje given/when/then, brak sekretów w zmianach oraz używanie wyłącznie wygenerowanych rekordów.

Problemy znalezione w review

Review wykryło trzy konkretne problemy wymagające korekty:

  1. Fixture zamówienia akceptował 404 przy sprzątaniu użytkownika i produktu w każdym teście. Mogło to ukryć nieoczekiwane wcześniejsze usunięcie rekordu.
  2. Jeżeli request usuwający użytkownika rzuciłby wyjątek sieciowy, wykonanie nie doszłoby do cleanupu produktu, co mogło pozostawić dane na stagingu.
  3. Oba branche poprawnie edytowały własne sekcje api-test-plan.md, ale po integracji tabela blockerów nadal zawierałaby nieaktualne wpisy o email events i sposobie uzyskania correlation id.

Dodatkowo review wskazało dwa świadome punkty do oceny:

  • test email events dopuszcza status FAILED, ponieważ bada zapis zdarzenia, a nie skuteczne dostarczenie maila,
  • nieznany enum statusu zamówienia zwracający 401 wygląda na osobny błąd backendu, prawdopodobnie w obsłudze HttpMessageNotReadableException lub error dispatchu chronionym przez security.

Niezależne odtworzenie błędu traffic detail

Koordynator nie poprzestał na opisie agenta. Utworzył nowy, unikalny X-Client-Session-Id, wywołał /api/v1/traffic/info, odnalazł request na liście i ponownie pobrał szczegóły z tym samym nagłówkiem. Live API znów zwróciło 500 {"message":"Internal server error"}.

Na tej podstawie powstał osobny raport bug-reports/traffic-log-detail-returns-500.md, zawierający środowisko, kroki reprodukcji, wynik oczekiwany i rzeczywisty, wpływ na użytkownika oraz sugerowane miejsca dochodzenia w backendzie. Raport wyraźnie zabrania zmiany testu tak, aby oczekiwał 500.

Korekty po review i integracja

Po poleceniu:

ok, apply the fixes and merge into main

koordynator połączył oba branche. Git nie zgłosił konfliktu tekstowego w planie, ale Codex nadal potraktował go jak konflikt semantyczny i ręcznie zachował oba opisy discovery, usuwając nieaktualne blockery.

Fixture disposableOrder został wzmocniony:

  • test, który celowo usuwa właściciela zamówienia, jawnie oznacza ten fakt przez markDeletedByTest,
  • 404 jest akceptowane tylko po takim oznaczeniu,
  • w pozostałych przypadkach cleanup użytkownika i produktu wymaga 204,
  • błędy cleanupu są zbierane, a usuwanie produktu jest wykonywane również wtedy, gdy cleanup użytkownika rzuci wyjątek,
  • wiele błędów cleanupu jest raportowanych przez AggregateError.

Po integracji uruchomiono jeden wspólny zestaw wszystkich 17 nowych testów. Wynik: 17/17. Następnie uruchomiono pełny suite obu projektów Playwright. Wynik: 101/101.

Commit integracyjny dc2812b zachował historię obu branchy i zawierał poprawki z review oraz raport błędu.

Wynik testów

Pełna sekwencja walidacji wyglądała następująco:

  • baseline przed równoległą implementacją: 84 testy zaliczone,
  • pierwszy target agenta nie-adminowego: 5 zaliczonych, 3 niezaliczone z powodu błędnego założenia o braku pola token,
  • poprawiony target nie-adminowy: 8 testów zaliczonych,
  • pełny suite brancha nie-adminowego: 92 testy zaliczone,
  • target adminowych zamówień: 9 testów zaliczonych,
  • cały projekt admin-api: 34 testy zaliczone,
  • pełny suite brancha adminowego: 93 testy zaliczone,
  • wspólny target po review i integracji: 17 testów zaliczonych,
  • pełny suite po integracji: 101 testów zaliczonych,
  • git diff --check: bez błędów.

Znalezione błędy i świadome ograniczenia

Sesje pozostawiły dwa podejrzane zachowania backendu i jeden brak obserwowalności:

  1. GET /api/v1/traffic/logs/{correlationId} zwraca 500 dla istniejącego id otrzymanego chwilę wcześniej z listy. Ścieżka 200 pozostaje zablokowana.
  2. PUT /api/v1/orders/{id}/status z nieznanym enumem zwraca 401 mimo poprawnego JWT admina. Zachowanie nie zostało zapisane jako kontrakt testowy.
  3. Produkcyjne forgot-password zwraca token: null i nie udostępnia udokumentowanego outboxa. Można pokryć walidację oraz anti-enumeration, ale nie stabilny sukces resetu hasła.

Znaleziono też rozbieżności OpenAPI: clientSessionId jest opisany jako query parameter zamiast nagłówka, a 404 traffic detail ma w schemacie body, mimo że live API zwraca pustą odpowiedź.

Finalny efekt trzech sesji

Praca równoległa dostarczyła dwa niezależne zestawy zmian bez nadpisania plików drugiego agenta. Ścieżka nie-adminowa pokrywa email events, forgot-password, negatywne przypadki resetu i stabilne 404 traffic detail. Ścieżka adminowa ma bezpieczny fixture pełnego zamówienia oraz pokrycie listy adminowej i zmiany statusu.

Najważniejszym rezultatem organizacyjnym jest sprawdzony wzorzec współpracy: jasny ownership plików, osobne worktree, komunikaty o stanie, serializacja kosztownych suite'ów, niezależne branche oraz osobna sesja review przed integracją. Finalny snapshot rozwiązania znajduje się w l15, natomiast l14 zachowuje stan startowy sprzed pracy równoległej.