Detalii importante
- Scrierea codului nu mai este partea lentă. În 31 de zile depozitul nostru principal a fuzionat 473 de cereri de extragere. 130 din ele au necesitat ca cineva să se întoarcă și să fuzioneze main în ramură, 239 de commit-uri de fuzionare în total, și 238 din ele au fost realizate de o persoană.
- PR-urile care necesitau asta au durat o mediană de 44 de ore de la deschidere la fuzionare. Cele care nu, au durat 2. Din cele 60 de PR-uri care au rămas deschise mai mult de trei zile, 51 au necesitat cel puțin o fuzionare din main.
- babysit-pr împarte munca la o etichetă:
LGTM, „arată bine pentru mine", pe care autorul o adaugă când munca este finalizată. Înainte de asta, o abilitate păstrează agentul pe PR până când CI este verde și fiecare bot de revizuire a răspuns. După asta, un flux de lucru GitHub Actions păstrează PR integrabil până când o persoană îl fuzionează, și adaugăRTM, „gata de fuzionare", odată ce cineva altcineva decât autorul aprobă. - Fluxul de lucru nu fuzionează niciodată, nu închide niciodată și nu schimbă nicio linie pe care a scris-o autorul. Un conflict pe care nu îl poate rezolva în jurul codului autorului se întoarce la autor ca
REWORK. - Abilitatea este publică, sub licență MIT: babysit-pr-skill pe GitHub , cu scriptul observator și designul fluxului de lucru. Fluxul de lucru în sine se află încă în modul de probă pe depozitul nostru, și spun mai jos de ce.
De ce cererile de extragere finalizate devin expirate?
Scrierea codului a încetat să mai fie partea lentă. Cu modelul arhitectului și agenți care fac cea mai mare parte din dactilografiere, depozitul nostru acceptă aproximativ 13 commit-uri pe zi în main. Aceasta este bună pentru lansare și rău pentru fiecare cerere de extragere deschisă, deoarece fiecare din acele commit-uri poate pune un PR în conflict sau pune CI-ul roșu.
Am tras ultimele 31 de zile de PR-uri fuzionate pentru a vedea unde s-a dus vremea.
Cei 44 față de 2 este o corelație, nu o cauză. Un PR care rămâne deschis mai mult timp îi dă lui main mai mult timp să se mute sub el, deci este mai probabil să aibă nevoie de o fuzionare. Dar fuzionările în sine sunt munca reală pe care cineva a făcut-o 239 de ori într-o lună. Cinci persoane au făcut 238 din ele manual. Un PR a necesitat opt fuzionări din main pe parcursul celor șapte zile în care a fost deschis.
Aprobarea în sine a fost rapidă. Odată ce un PR a primit prima sa aprobare, timp mediu până la fuzionare a fost zero ore. Așteptarea s-a întâmplat înainte de asta: autorul a terminat, apoi PR-ul a stat până când un reviuzitor a ajuns la el, și în timp ce stătea, main s-a mișcat. Am început să etichetez PR-uri finalizate cu LGTM pe 20 octombrie. Cele 20 care s-au fuzionat de atunci au așteptat o mediană de 38 de ore între LGTM și fuzionare, și unu din patru a așteptat mai mult de 78.
Aceasta este golul pentru care este. Nimeni nu este neglijent aici. Autorul crede că a terminat, reviuzitorul nu l-a deschis încă, și ramura se descompune între timp.
De ce nu să închid cererile de extragere expirate cu actions/stale?
Răspunsul obișnuit la cererile de extragere expirate este actions/stale : o Acțiune GitHub care adaugă o etichetă expirată problemelor și cererilor de extragere după un număr stabilit de zile de inactivitate, și le închide automat câteva zile mai târziu decât cineva comentează sau împinge.
Asta se potrivește cu o cerere de extragere pe care nimeni nu lucrează. Nu face nimic pentru cele pe care le aveam. Ale noastre era munca finalizată care a expirat în timp ce așteptau un reviuzitor, deoarece main s-a mișcat sub ele. Închiderea lor aruncă munca, și o etichetă expirată spune autorului ceea ce deja știe. Ceea ce PR-ul are nevoie este ca cineva să fuzioneze main, să re-execute sarcina CI roșie și să o păstreze verde până când o persoană o aprobă. Deci în loc să închid cererile de extragere expirate, le păstrăm integrabile.
Cum păstrează babysit-pr cererile de extragere integrabile
Diviziunea urmează pe cine așteptă. Înainte de LGTM, autorul este încă pe PR, de obicei o sesiune de agent, și abilitatea păstrează acea sesiune făcând munca utilă în loc de a declara victorie când codul se compilează. După LGTM, autorul a mers mai departe, deci munca merge la ceva care nu are nevoie de ei: un flux de lucru care rulează indiferent dacă cineva se uită sau nu.
LGTM este prescurtarea pentru „arată bine pentru mine". Pe cele mai multe echipe un reviuzitor spune asta despre codul cuiva altcuiva. Aici autorul o pune pe propriul PR ca o etichetă care înseamnă „am terminat, nu mi-a mai rămas nimic de făcut". Este cuvântul unei persoane: agentul o adaugă doar când i s-a spus să predea PR-ul. Acea etichetă este opt-in-ul pentru totul după ea, și este lucrul care face un dezvoltator confortabil să lase un bot să împingă pe ramura lor.
Înainte de LGTM: o abilitate Claude Code transportă PR la gata
Abilitatea a început ca abilitatea babysit-pr în tstack
lui Theo Browne. Am păstrat observatorul și regulile sale de bază și am schimbat locul unde se oprește.
Un observator per cerere de extragere
pr-wait sondează o cerere de extragere și tipărește o linie per eveniment real: o verificare a eșuat, toate verificările s-au terminat, cineva a comentat sau a revizuit, main s-a mișcat sub fișierele pe care le atinge acest PR, ramura a rămas în urmă sau în conflict, PR-ul s-a fuzionat. În Claude Code rulează sub instrumentul Monitor, deci fiecare linie trezește agentul o dată. Un eveniment care nu necesită nicio acțiune termină rândul fără mesaj. „Tot aștept" nu este știre, și un agent care spune asta de cincizeci de ori îsi umple contextul propriu cu nimic.
Sortați sarcina CI roșie înainte de a atinge codul
Există patru tipuri de roșu, și doar unu este o reparație de cod:
- PR-ul l-a rupt. Reparați-o cu cea mai mică schimbare.
- Executorul a avut o eroare intermitentă. Re-executați sarcinile nereușite o dată. O a doua eșec pe aceeași revizuire nu este intermitentă.
- Main este roșu. Nu reparați main pe ramura de funcție a cuiva. Raportați-o și așteptați.
- O verificare de proces este roșie, de exemplu PR-ul nu leagă o problemă aprobată. Asta este un pas pentru o persoană.
Agenții lăsați singuri tratează toate patru ca pe prima, și PR-ul crește o soluție pentru o încercare care este ruptă pe main.
Dovediți o constatare de revizuire înainte de a o remedia
O constatare de revizuire pe care agentul o acceptă obține mai întâi o încercare eșuată, apoi reparația. O constatare pe care o respinge obține un motiv scris. Aceasta este aceeași regulă ca abilitatea noastră de revizuire dovedit, și este ceea ce oprește roboții de revizuire să dirijeze PR-ul în funcție de volumul constatărilor.
Păstrați PR de dimensiunea obiectivului său
Buclele de revizuire cresc un PR cu câte o reparație de aspect ieftin pe rând: o protecție pentru un caz extrem pe care nimeni nu îl atinge, o încercare pentru comportament care nu s-a schimbat, un shim de compatibilitate. Abilitatea remediază erorile reale în cazul intenționat și refuză restul în scris. Cele demne de remarcat devin probleme.
Gata este o listă de verificare
Fiecare sarcină de poartă CI verde pe head-ul curent, fiecare bot de revizuire finalizat pe acest head, nimic care așteptă pe un om, niciun fir nerezolvat, niciun conflict. Când asta se menține, agentul o raportează și se oprește din monitorizare.
După LGTM: un flux de lucru GitHub Actions rezolvă conflictele de fuzionare
Fluxul de lucru are două joburi.
Poarta decide ceea ce fiecare PR are nevoie
Poarta este ieftină: niciun agent, niciun checkout al codului PR. Se execută la fiecare push către main, la fiecare finalizare a CI, la fiecare etichetă și revizuire, și la fiecare 30 de minute, și o interogare GraphQL îi oferă fiecare PR LGTM deschis. Pentru fiecare unu, o funcție pură decide ce să facă. Adaugă RTM dacă este aprobat de cineva altcineva decât autorul, este verde și fără conflict. Nu face nimic dacă o revizuire se execută. Re-execută CI roșu o dată. Trimite un conflict, sau CI care este încă roșu după re-execuția sa, agentului de reparare.
Agentul de reparare fuzionează main
Agentul de reparare este un job de agent pentru un PR la un head. Fuzionează main în ramură fără să se angajeze, oferă agentului fișierele în conflict și jurnalele eșuate, și îl lasă să editeze doar fișierele în conflict și fișierele pe care le schimbă deja PR-ul. Apoi pune o întrebare.
Poate acest PR să aterizeze fără a schimba o linie pe care a scris-o autorul?
Dacă da, verdictul este MODERNIZE. Agentul rezolvă conflictul în jurul liniilor autorului, un validator verifică rezultatul, și fluxul de lucru împinge un commit de fuzionare normal. Dacă nu, deoarece main a șters funcția pe care o editează PR-ul sau codul propriu al PR-ului eșuează CI, verdictul este REWORK. Nimic nu este împins, LGTM se demontează, și autorul primește un comentariu cu cea mai mică rescriare. Dacă main deja face ceea ce face PR-ul, verdictul este CLOSE, și o persoană îl închide.
Validatorul păstrează fiecare linie pe care a scris-o autorul
Validatorul este ceea ce face regula să se menține. Respinge orice fuzionare care pierde o linie pe care a adăugat-o PR-ul, sau o linie pe care a adăugat-o main în fișierul în conflict. Respinge editările în afara fișierelor permise, markeri de conflict rămași, și schimbări ale fișierelor CI sau de securitate. Un agent care încearcă să „remedieze" codul autorului se termină cu o etichetă care cere un om, nu niciodată cu un push. Fluxul de lucru împinge fără forță, și doar dacă ramura nu s-a mișcat de când a început încercarea. O încercare per head și bază, două per head, trei comentarii per PR per zi.
Nu fuzionează niciodată
RTM, „gata de fuzionare", este declarația porții că un PR are tot ceea ce are nevoie: LGTM autorului, o aprobare de la cineva altcineva, CI verde și niciun conflict. O persoană face fuzionarea. Asta a ținut designul curat și a evitat argumentul cu privire la dacă un bot ar trebui să fuzioneze.
Ce se schimbă pentru autor, reviuzitor și pentru oricine fuzionează
Autorul spune gata o dată. Nu se întorc trei zile mai târziu pentru a fuziona main și a aștepța din nou CI, și un PR al unui agent nu se descompune deoarece sesiunea care l-a deschis s-a terminat.
Reviuzitorul deschide un PR care este verde și integrabil pe mainul de astăzi, deci aprobarea lor este ultimul pas și nu începutul unui alt tur.
Oricine fuzionează lucrează dintr-o singură listă. RTM rămâne o dată ce poarta o adaugă, și dacă main rupe PR-ul după asta, fluxul de lucru îl remediază și eticheta rămâne.
Și autorul păstrează controlul asupra codului lor. Cel mai rău lucru pe care un bot îl poate face unei ramuri este să adauge un commit de fuzionare pe care un validator l-a verificat linie cu linie.
De ce rezolvatorul nostru vechi de conflicte de fuzionare nu a mai rulat
Aveam un rezolvator de conflicte înainte de acesta. Un detector a găsit PR-uri în conflict și a comentat pe ele, și rezolvatorul a rulat când cineva a adăugat o etichetă cerând-o. În aceeași perioadă detectorul a rulat aproximativ 2.500 de ori. Rezolvatorul a rulat zero ori.
Nu cred că cineva a fost leneș. Un dezvoltator care consideră un PR finalizat nu se întorc la el pentru a apăsa un buton. Automatizarea care așteptă să i se ceară nu va fi cerută. De aceea acesta pornește de la LGTM, momentul în care autorul spune că a terminat, și face restul fără ei.
Ce nu merge încă?
Două lucruri, și aș prefera să le spun aici decât să le găsești tu.
Fluxul de lucru este în modul de probă
Poarta lui doar jurnalizează ceea ce ar face până când o variabilă depozit spune altceva. Înainte de asta, o revizuire care doar păstrează constatări pe care le poate dovedi cu o încercare eșuată a găsit unsprezece erori în ea. Câteva sunt demne de remarcat dacă îți construiești propria. Căutarea de etichete pe GitHub rămâne în urmă, deci un PR pe care îl returnează ar fi putut pierde eticheta acum câteva secunde, și decizia trebuie să verifice etichetele live. Un marker „acest head a avut deja re-execuția sa" scris înainte ca apelul de re-execuție să reușească permite unui apel API eșuat să folosească singura reîncercare a head-ului. Și o verificare „nu pierde nici o linie" care nu urmărește redenumirii vede fiecare linie a unui fișier redenumit ca pierdut.
Executoarele agentului au fost oprite
De la 19 octombrie, fiecare job vizând executoarele noastre de agent nu a reușit să obțină o mașină: 406 anulate, 24 încă în coadă când am verificat. Poarta rulează în altă parte și merge bine, dar fixerul are nevoie de un executor de agent, și una moartă arată exact ca o zi liniștită. Nimic nu a eșuat zgomotos. Joburile s-au pus în coadă și apoi au fost anulate. Dacă construiești asta, alertează pe execuțiile fixer-ului care stau în coadă.
Deci numerele de mai sus sunt imaginea de dinainte. Acum avem 27 de PR-uri LGTM deschise, 7 din ele cu CI roșu și niciuna cu RTM. Acestea sunt numerele pe care ar trebui să le schimbe, și voi raporta ce a făcut.
Cum se instalează skill-ul babysit-pr
github.com/LivinTribunal/babysit-pr-skill are:
SKILL.md, skill-ul, cu o scurtă secțiune „configurați o dată" pentru fluxurile dvs. CI, roboții de revizuire și verificările de proces.scripts/pr-wait, observatorul. Are nevoie de Python șighautentificat.docs/after-lgtm.md, designul fluxului de lucru după-LGTM: etichetele, poarta, fixerul, regula că nu schimbă niciodată liniile autorului, și cele unsprezece erori.
Fluxul de lucru este un design mai degrabă decât un fișier de copiat, deoarece al nostru rulează împotriva etichetelor, executor-elor și CI ale unei companii. Construiți-vă din doc, livrați-o în modul numai jurnal, citiți o zi din deciziile sale, apoi activați-o.
Se pereche cu modelul arhitectului , care decide cine scrie codul, și grain , care decide cum arată codul. babysit-pr este ceea ce se întâmplă după ce oricare din ei deschide cererea de extragere. Dacă ești să reglezi agentul însuși, testul CLAUDE.md A/B și limita de context care a redus utilizarea token-ului cu 17% acoperă instrucțiunile și costul.

