Przejdź do głównej zawartości

Ograniczona pętla review-fix dla pull requestu to workflow agenta, który czyta nowe komentarze z review i nieudane checki CI, klasyfikuje każdą uwagę, odtwarza te wymagające działania, nakłada najmniejszą poprawkę w zatwierdzonym zakresie, ponawia wymagane bramki i zatrzymuje się przed imiennie wskazanym człowiekiem. Kluczowe jest ograniczenie: rejestr, limit prób i jawne warunki stopu.

Pytanie scorecardu (Q19): Jak rozwiązywane są uwagi z review i nieudane checki CI na pull requestach?

Odpowiedź za maksimum punktów: Ograniczona pętla triaguje nowe uwagi, naprawia potwierdzone przyczyny, ponawia wymagane checki i kończy pracę gotowa do akceptacji przez imiennie wskazanego człowieka.

Ta strona jest dla deweloperów odpowiedzialnych za pull requesty pisane przez agentów oraz dla tech leadów, którzy ustalają reguły działania takich pętli. Twój PR ma 11 komentarzy od bota review i dwóch kolegów, job integracyjny jest czerwony, a połowa uwag dotyczy kodu, który ostatni push już zmienił. Kopiowanie każdego komentarza do czatu działa przy jednym PR. Nie przetrwa tygodnia takich PR-ów, a nieograniczona pętla @bot fix this chętnie przepisze test, aż ten przejdzie.

  • Plik rejestru, który zapisuje każdą uwagę, jej klasę, commit (head), względem którego ją sprawdzono, i sposób rozwiązania.
  • Skrypt snapshotu, który zbiera nierozwiązane wątki review i wymagane checki przez GitHub CLI (gh).
  • Trzy prompty do skopiowania: triaż, poprawka i raport końcowy.
  • Wywołania headless dla Claude Code i Codex oraz odpowiednik w Cursorze.
  • Sposób sprawdzenia wyniku pętli na podstawie dowodów, bez ponownego czytania całego diffa.

Jeden przebieg obsługuje każdą nową uwagę raz, a potem się zatrzymuje. Pętla nigdy sama nie zaczyna nowego projektu rozwiązania; uwaga, która go wymaga, wraca do planowania.

snapshot (head SHA, wątki, checki)
→ klasyfikuj każdą nową uwagę
→ odtwórz defekty do naprawy
→ popraw w zatwierdzonym zakresie
→ ponów bramki dotknięte zmianą + wymagane
→ jedna odpowiedź na uwagę, aktualizacja rejestru
→ stop: wszystko czyste | potrzebna decyzja człowieka | limit prób

Stan pętli żyje w pliku w kopii roboczej gałęzi PR, a nie w pamięci agenta. Nie commituj go (dodaj .pr-loop/ do .gitignore), a jego podsumowanie wklej do PR:

{
"pr": 412,
"base_sha": "9c1e4d2",
"items": [
{
"id": "thread:PRRT_kwDOA1b2c3",
"source": "review-thread",
"checked_at_sha": "4f7a0b1",
"class": "defect",
"repro": "npm test -- tests/billing/proration.test.ts",
"status": "fixed",
"attempts": 1,
"fix_sha": "a81c9e0"
},
{
"id": "check:integration",
"source": "required-check",
"checked_at_sha": "4f7a0b1",
"class": "needs-human",
"reason": "Fix requires a schema migration, outside plan.md",
"status": "escalated",
"attempts": 0
}
]
}

Całą pracę wykonują trzy pola. Stabilne id (node ID wątku review albo nazwa checka) chroni przed dwukrotną odpowiedzią na ten sam komentarz. checked_at_sha oznacza uwagi jako nieaktualne, gdy nowszy push zmienił cytowany kod. attempts egzekwuje limit dla każdej uwagi osobno, więc jeden uparty błąd nie zużyje całego budżetu.

Co agent może zmieniać i kiedy musi się zatrzymać?

Dział zatytułowany „Co agent może zmieniać i kiedy musi się zatrzymać?”

Wpisz tę tabelę do AGENTS.md albo CLAUDE.md, żeby pętla czytała ją w każdym przebiegu.

Agent możeAgent musi się zatrzymać i zapytać, gdy
Czytać nierozwiązane wątki, wyniki checków i logi nieudanych jobówUwaga jest sprzeczna z intent.md, spec.md lub plan.md
Odtworzyć zgłoszony błąd lokalnieBłędu nie da się odtworzyć z dostępnych dowodów
Edytować pliki w zakresie zatwierdzonym przez plan.mdPoprawka wymaga migracji, nowej zależności, dostępu do produkcji lub plików spoza zakresu
Ponawiać udokumentowane komendy testów i linteraTa sama uwaga nie przechodzi po trzech próbach
Odpowiedzieć w wątku z dowodem poprawkiReviewer prosi o decyzję produktową, bezpieczeństwa, prawną lub architektoniczną
Pushować na gałąź PRCokolwiek innego: merge, deploy i zmiana ochrony gałęzi nigdy nie są w zakresie

Chroniona gałąź, wymagane review i akceptacja release’u pozostają poza pętlą. Zielony check to dowód dla reviewera, a nie zgoda na merge.

  1. Otwórz draft pull requestu, gdy lokalne bramki przejdą. Podlinkuj intent.md, spec.md i plan.md (łańcuch artefaktów) i dołącz dowody z testów. Strona o pakiecie dowodów definiuje, co musi zawierać opis takiego PR.

  2. Czekaj na wyniki zamiast odpytywać w pętli. gh pr checks 412 --watch --required blokuje do zakończenia wymaganych checków. Review pojawiają się, gdy ludzie lub boty je opublikują, więc uruchamiaj przebieg po złożeniu review, a nie według zegara.

  3. Zrób snapshot. Zapisz poniższy skrypt jako scripts/pr-loop-snapshot.sh i uruchom go z gałęzi PR. Zapisuje head commit, nierozwiązane wątki review i wymagane checki dla tego przebiegu:

    #!/usr/bin/env bash
    set -euo pipefail
    PR="${1:?usage: pr-loop-snapshot.sh PR_NUMBER}"
    OUT=".pr-loop/pass-$(date +%Y%m%dT%H%M%S)"
    mkdir -p "$OUT"
    gh pr view "$PR" --json headRefOid,url,reviews,comments > "$OUT/pr.json"
    # gh exits 1 when a check failed and 8 while checks are pending; keep the snapshot either way
    gh pr checks "$PR" --required --json name,bucket,link,workflow > "$OUT/checks.json" || true
    gh api graphql -F owner='{owner}' -F repo='{repo}' -F pr="$PR" -f query='
    query($owner: String!, $repo: String!, $pr: Int!) {
    repository(owner: $owner, name: $repo) {
    pullRequest(number: $pr) {
    # first 100 threads only; paginate with pageInfo/endCursor for more
    reviewThreads(first: 100) {
    nodes { id isResolved isOutdated path line
    comments(first: 20) { nodes { author { login } body } } }
    }
    }
    }
    }' > "$OUT/threads.json"
    echo "$OUT"

    isOutdated to informacja od GitHuba, że cytowane linie zmieniły się od czasu komentarza. Zapytanie czyta najwyżej 100 wątków; PR z większą liczbą wymaga pageInfo { hasNextPage endCursor }, zmiennej $endCursor: String przekazanej jako after: oraz gh api graphql --paginate, inaczej reszta wątków po cichu przepada. Pole bucket grupuje stany checków w pass, fail, pending, skipping i cancel.

  4. Klasyfikuj przed edycją. Uruchom na snapshocie prompt triażu z sekcji niżej. Każda uwaga dostaje dokładnie jedną klasę: defect, question, duplicate, stale, note lub needs-human. Dalej idą tylko uwagi defect.

  5. Odtwórz każdy defekt. Agent pisze najwęższą komendę, która kończy się błędem z powodu zgłoszonej przyczyny, na przykład jeden plik testów albo jedną regułę lintera, i zapisuje ją w polu repro rejestru. Uwaga, której nie da się odtworzyć, staje się needs-human, a nie spekulatywnym patchem.

  6. Nałóż najmniejszą poprawkę w zakresie. Jeden commit na uwagę, z jej id w komunikacie commita. Poprawka nigdy nie edytuje testu, żeby przeszedł, nie obniża progu pokrycia i nie dodaje wyciszenia lintera.

  7. Ponów bramki na nowym head. Najpierw komenda repro, która teraz musi przejść, potem każda wymagana bramka repozytorium. Zapisz w rejestrze komendę, kod wyjścia i nowy head SHA.

  8. Odpowiedz raz i się zatrzymaj. Opublikuj jedną odpowiedź na każdy naprawiony wątek, z commitem i przechodzącą komendą. Rozwiązanie wątków zostaw reviewerowi. Zakończ przebieg raportem końcowym, a kolejny uruchom dopiero po nowych uwagach.

Zamień npm run lint i npm test na udokumentowane bramki swojego repozytorium. Prompty zakładają, że rejestr leży w .pr-loop/ledger.json. Zapisz trzy prompty jako .pr-loop/prompts/triage.txt, fix.txt i report.txt; poniższe komendy czytają je stamtąd.

Kontrakt pętli, rejestr i prompty są takie same w każdym narzędziu. Różni się sposób uruchomienia przebiegu bez nadzoru i bot review, który dostarcza uwagi.

Uruchom przebieg headless z gałęzi PR. claude -p startuje w trybie uprawnień Manual (od v2.1.285 w trybie auto u zewnętrznych dostawców lub z wyłączoną telemetrią), więc nazwij tryb i dozwolone narzędzia jawnie, a do tego ogranicz wydatki:

Okno terminala
SNAP=$(scripts/pr-loop-snapshot.sh 412)
[ -f .pr-loop/ledger.json ] || echo '{"items":[]}' > .pr-loop/ledger.json
# Triage: no Bash, so no commits and no test runs; it may write only files
claude -p "$(cat .pr-loop/prompts/triage.txt)" \
--permission-mode manual \
--allowedTools "Read,Grep,Glob,Edit,Write" \
--max-budget-usd 2 \
--output-format json > "$SNAP/triage.json"
test -z "$(git status --porcelain -- . ':!.pr-loop')" || { echo "triage edited source files; stop" >&2; false; }
# Fix: runs only after you have read the ledger diff
claude -p "$(cat .pr-loop/prompts/fix.txt)" \
--permission-mode acceptEdits \
--allowedTools "Read,Grep,Glob,Edit,Bash(npm test *),Bash(npm run lint),Bash(gh run view *),Bash(git add *),Bash(git commit *)" \
--max-budget-usd 5 \
--output-format json > "$SNAP/result.json"

Zacznij od czystego drzewa roboczego. Linia z rejestrem tworzy pusty rejestr przy pierwszym przebiegu. Triaż nie dostaje Bash, więc nie uruchomi testów ani nie zrobi commita; nadal może zapisywać pliki, bo musi zaktualizować rejestr, i dlatego tryb plan nie pasuje do tego kroku. Właściwym zabezpieczeniem jest linia z git status: zgłasza błąd, jeśli triaż zmienił cokolwiek poza .pr-loop/. Przeczytaj diff rejestru, zanim uruchomisz przebieg naprawczy. git push celowo nie ma na liście dozwolonych narzędzi, więc pushujesz sam, po przeczytaniu raportu końcowego. Przed pierwszym pushem /code-review w sesji interaktywnej wykonuje lokalny przegląd.

Na GitHubie anthropics/claude-code-action@v1 odpowiada na komentarz z frazą wyzwalającą (domyślnie @claude). Domyślnie ignoruje autorów komentarzy bez prawa zapisu; w jobie, który może pushować, zostaw allowed_non_write_users nieustawione. Przewodnik CI/CD dla Claude Code opisuje plik workflow. Zarządzany Code Review (Team i Enterprise, research preview) publikuje uwagi jako komentarze inline, a jego check run Claude Code Review zawsze kończy się wynikiem neutral, więc nigdy nie zatwierdza ani nie blokuje PR. Traktuj jego komentarze jako kolejne wejście tej pętli, a nie jej zamiennik. Odpowiedź na jego komentarz nie wywołuje reakcji. Jeśli repozytorium uruchamia review po każdym pushu (@claude review always), kolejny przebieg rozwiązuje wątek, gdy problem zniknie; w przeciwnym razie skomentuj @claude review.

Jeśli agent ma czytać stan PR przez połączenie narzędziowe zamiast gh, serwer GitHub MCP udostępnia pull requesty i logi Actions, a jego URL przyjmuje sufiks /readonly dla każdego zestawu narzędzi. W Claude Code dodaje go claude mcp add --transport http github https://api.githubcopilot.com/mcp/ -H "Authorization: Bearer $GITHUB_PAT_TOKEN"; powłoka podstawia token w chwili uruchomienia komendy. W Codex codex mcp add github --url https://api.githubcopilot.com/mcp/ --bearer-token-env-var GITHUB_PAT_TOKEN trzyma token w zmiennej środowiskowej. CLI gh zużywa mniej tokenów przy tych samych odczytach.

Jak sprawdzić wynik pętli bez czytania całego diffa?

Dział zatytułowany „Jak sprawdzić wynik pętli bez czytania całego diffa?”

Weryfikuj przebieg na podstawie jego dowodów, a kod czytaj tylko tam, gdzie wskazują dowody.

  • Każda poprawka ma stan „przed” i „po”. Każda uwaga fixed wskazuje komendę repro. Uruchom sam jedną lub dwie na rodzicu commita z poprawką i na head: najpierw musi zakończyć się błędem, a potem przejść.

  • Wymagane checki są zielone na head wskazanym w raporcie. Porównaj SHA z raportu z gh pr view 412 --json headRefOid. Raport o starszym SHA jest nieaktualny.

  • Nic nie wyszło poza zatwierdzony zakres. Wypisz pliki zmienione przez commity pętli i porównaj je z plan.md:

    Okno terminala
    git log --format=%H --grep='^fix(review):' origin/main..HEAD \
    | xargs -r git show --name-only --format= | sort -u

    Każdą ścieżkę spoza zakresu planu, każdy plik testów i każdą konfigurację CI z tej listy czytasz linia po linii.

  • Wyrocznia się nie przesunęła. Poprawka, która dotknęła testu, snapshotu lub progu, z definicji jest needs-human, nawet jeśli agent sklasyfikował ją jako defekt.

  • Imiennie wskazany człowiek akceptuje. Pętla kończy się na READY FOR REVIEW. Reviewer zatwierdza, a release przechodzi przez bramkę akceptacji produkcyjnej.

Pełny protokół triażu, którym reviewer przechodzi PR napisany przez agenta, opisuje strona o review PR agenta bez czytania każdej linii.

Co psuje się w pętli review-fix i jak z tego wyjść?

Dział zatytułowany „Co psuje się w pętli review-fix i jak z tego wyjść?”

Pętla odpowiada na ten sam komentarz w każdym przebiegu. Rejestr nie ma stabilnego id albo agent identyfikuje uwagi po treści komentarza. Naprawa: kluczuj po node ID wątku lub nazwie checka, usuń zduplikowane odpowiedzi i ponów triaż na aktualnym rejestrze.

Poprawka celuje w kod, który poprzedni push już zmienił. Uwagę sprawdzono względem starszego head. Naprawa: oznacz jako stale uwagi, których checked_at_sha różni się od bieżącego headRefOid, zrób nowy snapshot i ponów triaż.

Niestabilny (flaky) test zostaje „naprawiony”. Repro przeszło za pierwszym razem, a agent i tak nałożył patch albo dodał retry. Naprawa: wymagaj, żeby repro zawiodło przed jakąkolwiek edycją, zrób revert commita i przekaż test właścicielowi niestabilnych testów jako needs-human.

Checki są czerwone po trzech próbach. Przyczyna leży poza zakresem, który dostał agent, albo środowisko różni się od CI. Naprawa: zatrzymaj tę uwagę, dołącz ostatni log błędu (gh run view RUN_ID --log-failed) i eskaluj. Nie podnoś limitu prób dla tej uwagi.

Patch odpływa od planu. Kontrola zakresu pokazuje pliki spoza plan.md albo poprawka wprowadza nową abstrakcję. Naprawa: zrób revert commita i odeślij uwagę do planowania. Komentarz z review, który wymaga zmiany projektu, to nowy plan, a nie poprawka.

Zielone checki uruchamiają merge lub deploy. Ktoś podpiął auto-merge pod wynik pętli. Naprawa: usuń auto-merge z workflow pętli, trzymaj merge za ochroną gałęzi i wymaganym review człowieka, a rollback traktuj jako siatkę bezpieczeństwa.

  • Każda przetworzona uwaga ma stabilne id, jedną klasę i head SHA, względem którego ją sprawdzono.
  • Każdy naprawiony defekt ma komendę repro, która zawiodła przed poprawką i przechodzi po niej.
  • Poprawki mieszczą się w zakresie plan.md i nigdy nie osłabiają testu, progu ani reguły lintera.
  • Wymagane checki przeszły na head SHA wskazanym w raporcie końcowym.
  • Każda uwaga ma limit prób, a pętla zatrzymuje się z raportem zamiast ponawiać bez końca.
  • Pętla nie może zrobić merge ani deployu, a akceptuje imiennie wskazany człowiek.

Pętla przyjmuje uwagi z warstwowego review PR i przekazuje czysty PR do bramki release’u. Klucz odpowiedzi dla dewelopera przypisuje każde pytanie scorecardu do jego strony.