Przejdź do głównej zawartości

Debugowanie z AI w Cursorze

Polowanie na błędy w Cursorze ma trzy fazy i osobny tryb dla każdej: tryb Ask bada objawy i porządkuje hipotezy, tryb Debug oprzyrządowuje kod i zbiera dowody z czasu wykonania, a tryb Agent nanosi jedną celowaną poprawkę wraz z testem regresyjnym. Ta kolejność istnieje po to, żeby nie wpaść w pętlę napraw-zepsuj-napraw, którą produkuje zgadywanie.

Produkcja zwraca 500 przy 15% żądań do kasy. Na dev działa bez zarzutu. Zaczęło się po wtorkowym wdrożeniu, ale diff wygląda niewinnie — drobny refaktor logiki płatności — a komunikat błędu brzmi wybitnie bezużytecznie: “Transaction failed”. Prezes prosi o aktualizację co pół godziny.

Kuszące jest wkleić błąd do trybu Agent i napisać “napraw to”. Zmienia trzy pliki, twój przypadek testowy przechodzi, a teraz inna grupa użytkowników dostaje 403. Każesz naprawić i to. Kolejne dwa pliki. Pierwotne 500 wraca, a po dwudziestu minutach jesteś dalej od rozwiązania niż na początku.

Problemem nie jest Cursor. Problemem jest traktowanie debugowania jako “każ AI naprawić i licz na szczęście”. Debugowanie to problem przeszukiwania, a AI przeszukuje bardzo dobrze — pod warunkiem, że każesz mu szukać, zanim zacznie edytować.

  • Trzyfazowy przepływ, w którym tryby Ask, Debug i Agent robią to, w czym każdy jest naprawdę dobry
  • Prompt generujący hipotezy, który zamienia objawy w uszeregowane, sprawdzalne teorie
  • Przepływ w trybie Debug, który oprzyrządowuje kod, zbiera dane z czasu wykonania i wyprowadza przyczynę z dowodów
  • Prompt do testu obciążeniowego odtwarzającego sporadyczną awarię lokalnie
  • Prompty copy-paste do błędów typów, wyścigów i kaskady błędów builda
  • Szablon post-mortem dokumentujący błąd, poprawkę i zapobieganie

Każda faza ma swój tryb, a tryb ma znaczenie, bo ogranicza to, co AI wolno zrobić:

  1. Badaj w trybie Ask. Tylko do odczytu. Budujesz obraz awarii i nic nie powinno się w tym czasie zmienić.
  2. Zbieraj dowody w trybie Debug (albo ręcznym logowaniem). Wyłącznie oprzyrządowanie, żadnych zmian zachowania.
  3. Naprawiaj w trybie Agent. Jedna celowana zmiana plus test regresyjny, który to potwierdza.

Przeskok od razu do trzeciej fazy to właśnie źródło pętli napraw-zepsuj-napraw.

Najpierw zbierz wszystkie obserwowalne fakty, a potem poproś o teorie, które da się sprawdzić:

Spodziewaj się odpowiedzi w rodzaju wyczerpania puli połączeń, wyścigu, źle ustawionego timeoutu albo brakującej obsługi błędu na jednej ze ścieżek. Kolejność liczy się mniej niż punkty drugi i trzeci: hipoteza, której nie umiesz potwierdzić ani odrzucić, to teoria, która zje ci popołudnie.

Gdy zamiast listy objawów masz stack trace, poproś o ścieżkę, a nie o teorię:

Fraza “Without making any changes” naprawdę tam pracuje. To różnica między obrazem sytuacji w głowie a niespodziewanym diffem.

Cursor ma do tego osobny tryb Debug. Przełączysz się na niego w wyborze trybu albo skrótem Cmd+. / Ctrl+.. W odróżnieniu od trybu Agent prowadzi ustrukturyzowane śledztwo:

  1. Przegląda istotne pliki i generuje hipotezy
  2. Dokłada oprzyrządowanie (instrukcje logowania) raportujące do lokalnego serwera debugowania
  3. Prosi cię o odtworzenie błędu
  4. Analizuje zebrane dane z czasu wykonania
  5. Proponuje celowaną poprawkę opartą na dowodach, a nie na zgadywaniu
The checkout endpoint at POST /api/checkout is returning "Transaction failed"
for ~15% of requests under load. The error happens in the payment processing
step. I can reproduce it locally using a load testing tool (k6 or similar)
that sends 200 concurrent requests.
Find the root cause using instrumentation.

Tryb Debug dokłada logi w miejscach, które mają znaczenie — pobranie połączenia z bazą, wywołania API płatności, granice transakcji — i prosi o wywołanie błędu. Mając dane z czasu wykonania, zwykle wskazuje problem w kilka minut.

Gdy tryb Debug jest niedostępny albo chcesz mieć ściślejszą kontrolę, zrób to samo ręcznie. Najpierw oprzyrządowanie:

Potem odtwórz błąd i przynieś dwa przebiegi, nie jeden. To porównanie umożliwia postawienie diagnozy:

Jeśli nie umiesz wywołać błędu ręcznie, niech tryb Agent zbuduje coś, co umie:

Test obciążeniowy odtwarzający awarię jest wart więcej niż diagnoza, którą przyniesie, bo to nim później zweryfikujesz poprawkę.

@logs/debug-output.log @src/payment/processor.ts
Here are the debug logs from the load test. Analyze them and answer:
1. Which requests failed and what do they have in common?
2. What is the timing pattern? Do failures cluster at specific intervals?
3. Is there a resource that's being exhausted (connections, file handles, memory)?
4. Can you identify the exact line where the failure originates?
5. What is the root cause?
Show me the specific code that needs to change and explain why.

Typowe ustalenie w takim scenariuszu: procesor płatności pobiera połączenie z bazą i nie zwalnia go na części ścieżek błędu. Pod obciążeniem pula się wyczerpuje, a wynikły timeout zostaje opakowany w ogólny komunikat “Transaction failed” — i dlatego treść błędu nigdy nie wskazywała prawdziwego problemu.

Dopiero teraz przełącz się na tryb Agent i nałóż na niego ograniczenia. Szablon poniżej warto zachować:

Wypełniony pod opisany wyciek połączeń ten sam szkielet staje się konkretem — zwróć uwagę, jak duża jego część dotyczy tego, by następny taki przypadek dało się zdiagnozować, a nie samego wycieku:

Każda poprawka dostaje test, który wyłapałby ten błąd:

Add a regression test for the bug we just fixed.
The test should:
1. Set up the exact conditions that caused the failure (user with [specific condition])
2. Call the endpoint with the same request that was failing
3. Assert that it succeeds with the correct response
4. Also test the edge case where [related condition]
Put the test in @src/routes/__tests__/orders.test.ts following existing patterns.
Run the test to confirm it passes.

Jeśli test upada, poprawka była niepełna. Jeśli przechodzi, masz coś, co nie pozwoli błędowi wrócić.

Gdy błąd zaczął się po konkretnym wdrożeniu, a ty masz wiarygodny test, niech szuka git:

The checkout load test passes on commit abc123 (Monday) but fails on HEAD (Tuesday).
There are 12 commits between them. Help me set up a git bisect:
1. Create a script that runs the load test and returns exit code 0 if fewer than 1% of
requests fail, exit code 1 otherwise
2. Show me the git bisect commands to find the exact commit that introduced the regression

Dwanaście commitów zawęża się do jednego w mniej więcej cztery iteracje.

TypeScript reports this error at build time:
[PASTE TSC ERROR]
Trace the types involved. Show me:
1. Where the type is defined
2. How it flows through the code to this point
3. Why the types are incompatible
4. The minimal fix that maintains type safety
Do not use `any` or type assertions to fix this. Find the real type issue.
This code has a race condition -- when two requests arrive simultaneously
for the same user, the second request overwrites the first one's data.
Relevant code: @src/services/user-service.ts
Analyze the concurrent execution paths and identify:
1. Which operation is not atomic
2. Where the race window exists
3. The best fix (optimistic locking, database transaction, or mutex)
Show me the fix with before/after code comparison.

Przy wielu błędach builda poprawianie ich po kolei to droga najwolniejsza — większość jest skutkiem jednego prawdziwego problemu:

Przy włączonym auto-run agent uruchamia build, czyta błędy, poprawia je i iteruje, aż przejdzie — pętla, którą spopularyzował Steve Sewell z Builder.io.

Krok, który większość zespołów pomija, i ten o najdłuższym zwrocie. Napisz szkic w trybie Ask, póki sesja jest jeszcze w kontekście:

Based on this debugging session, write a post-mortem document covering:
1. Summary: what broke, who was affected, how long it lasted
2. Timeline: when it started, when detected, when fixed
3. Root cause: the connection leak in payment processing
4. Fix: what changed and why
5. Detection gap: why our monitoring didn't catch this sooner
6. Prevention: what we will do to prevent similar bugs (connection pool alerting, code review checklist for resource cleanup)
7. Action items with owners and deadlines
Save to docs/postmortems/2026-02-checkout-connection-leak.md

Utknąłeś w pętli napraw-zepsuj-napraw. Faza pierwsza została pominięta. Wróć do trybu Ask, zbuduj obraz systemu, a potem wprowadź dokładnie jedną celowaną zmianę.

Oprzyrządowanie zmienia zachowanie błędu. Instrukcje logowania przesuwają czasy na tyle, że wyścig znika — klasyczny heisenbug. Sięgnij po lżejsze oprzyrządowanie: inkrementuj liczniki atomowe zamiast logować napisy albo zbieraj znaczniki process.hrtime(), które nie wymagają wejścia/wyjścia.

AI podaje wiarygodną, ale błędną przyczynę. Modele dobrze dopasowują wzorce i potrafią mylić się z pełnym przekonaniem. Zweryfikuj przed wdrożeniem: jeśli diagnoza jest trafna, poprawka powinna zbić odsetek błędów w teście obciążeniowym prawie do zera.

Poprawka zamiata objaw pod dywan. Klasyczna zła poprawka to opakowanie awaryjnej operacji w ponowienia zamiast zatkania wycieku. Ponowienia na chwilę maskują wyczerpanie puli, a przy dłuższym obciążeniu pogarszają sprawę. Nie zgadzaj się i poproś o przyczynę.

Agent “naprawia” test zamiast kodu. Powiedz to wprost: “The test is correct. The implementation is wrong. Fix the implementation to make the test pass.”

Oprzyrządowanie nie łapie problemu. Błąd siedzi w innym miejscu łańcucha wywołań, niż zakładałeś. Rozszerz logowanie albo odtwórz awarię kilka razy — zachowanie sporadyczne potrzebuje więcej niż jednej próbki.

Nic nie odtwarza się lokalnie. Część błędów potrzebuje produkcyjnych wolumenów danych, prawdziwych opóźnień sieci albo konkretnego sprzętu. Oprzyrząduj produkcję logowaniem strukturalnym i analizuj je w trybie Ask, a agentowi każ poszukać znanych problemów w bibliotece albo usłudze, która zawodzi.

Ślad prowadzi do node_modules. Sprawdź przez @Docs zgłoszenia i changelog biblioteki, a potem zapytaj wprost: “Has this library been reported to have connection leaks or timeout issues in recent versions?”

Błędów jest za dużo, żeby je posegregować. Najpierw napraw błędy kompilacji, bo blokują wszystko inne, potem błędy czasu wykonania, a na końcu błędy logiki — z użyciem promptu na kaskadę builda powyżej.