Cestou k temné továrně: tempo určuje agent

3. díl z 5 v sérii „Towards the Dark Factory“ (Cestou k temné továrně)
Druhý díl popsal zeď. Tenhle díl je o tom, co vám zeď, která drží, přinese: agentům se dá věřit, že sami rozhodnou, co dělat dál a kdy. Žebřík Saumyi Tyagiho měří autonomii podle toho, kdo schvaluje merge; my jsme našli druhou osu, na které v malém týmu záleží stejně, kdo určuje tempo. Na úrovni 2 rozhoduje člověk, na čem bude agent pracovat dál. V bodě, kam jsme se se Sestavou dostali, rozhoduje agent, na nástěnce, kterou spravuje člověk, v mezích, které nás naučil stroj.
Tři věty od vlastníka
Pravidlo, které proměnilo frontu úkolů v proces s vlastním tempem, zaznělo třikrát, pokaždé kratší.
- září, třetí den: „když nemáš co dělat, vezmi další logický úkol, mysli na vytížení CPU.“ 27. září: „jakmile je volný slot, další úkol vybíráš ty.“ A večer 29. září, když šel vlastník spát: „až budeš hotový s prací a bude volný slot, vyber si na noc vhodný bug.“
Zapsané jako trvalé pravidlo to zní: když řídicí agent odevzdá práci, uzavři jeho běh (review, brány, worktree), pak vyber nejdříve datovanou otevřenou položku pro launch na roadmapové nástěnce, jejíž soubory se nekříží s běhy, které ještě jedou, a pošli ji. Položky, které potřebují vlastníka (rozhodnutí, přihlášení, kontrolu na zařízení), se žádají v hlášení a nikdy se na ně nečeká. Výběr oznam.
Všechno ostatní v tomhle dílu je o slovech „slot“ a „kříží“.
Stroj a jeho sloty
Všechno běží na jednom Macu, deset jader, přes den i s vlastníkovou vlastní prací. Limity nikdo nenavrhl; každý se našel tím, že se porušil.
Nejvýš dva swiftové běhy, a jeden, když běží mutační brána. Šestý den sdílely stroj tři swiftové běhy, zatímco jeden pouštěl mutační bránu. Mutanti nechávali testovací sadu viset až do timeoutu (zhruba 400 sekund dvakrát, 630 sekund dvakrát); jedna brána zvládla 32 ze 490 mutantů za 21 minut a prostředí odřízlo agenta, který na ni čekal. Tytéž brány bez souběhu neměly timeout žádný. Souběžné swiftové běhy navíc buildí s --jobs 2, takže brána nikdy nezabere celý stroj.
Jeden nabootovaný simulátor. Tentýž den nabootovaly tři běhy tři simulátory. Zhruba 170 systémových procesů simulátoru bylo připravených k běhu, load average přesáhl 400 a aplikace při startu zamrzla v synchronních voláních notifikací, řeči a zvuku. Dva agenti ztratili každý hodinu. Teď běh své zařízení vypne, když jeho testy skončí, a čeká, dokud je nabootované jiné.
Jeden simulátor na běh, pojmenovaný po worktree běhu. Před tím pravidlem testovaly dva aplikační běhy na jediném simulátoru, který vybírá pomocný skript. Oba instalují stejné bundle id, takže testy každého běhu spouštěly build toho druhého; aplikace při startu padala na chybějícím symbolu, macOS ukazoval vlastníkovi na obrazovce dialogy „Sestava cannot be opened“ a každý výsledek testu z toho překryvu neznamenal nic. Každý běh si teď vytvoří vlastní zařízení přes xcrun simctl create a skript, který worktree ukončuje, smaže každé zařízení toho jména.
Disk. Mutační brána skončila předčasně na 357 z 516 mutantů, když volné místo kleslo na 600 MB, a vedle ní selhal build reviewera. Simulátor každého běhu naroste na 3 až 4 GB, jakmile se aplikace nainstaluje a otestuje; každý worktree drží zhruba gigabajt výstupu buildu; npm cache jednou dosáhla 16 GB. Před každým odesláním úkolu se teď kontroluje volný disk a pod 8 GB koordinátor nejdřív ukončí worktree, než spustí další běh. Výstup buildu zůstává uvnitř worktree běhu, takže jeho ukončení ho uklidí.
Práce v Node (testy webového editoru, smoke sada webu) se s tím vším může překrývat, s jednou výjimkou naučenou 30. září: 322 specifikací Playwrightu vedle mutační brány a UI sady vyhnalo load average na 580 a jeden test startu trval 491 sekund místo 34. Všechno prošlo. Prohlížečová sada se pro limit slotů zatím počítá jako swiftový běh; pravidlem se stane, pokud to vydrží.
Koordinátor sleduje deníky
Koordinátor je session, která drží nástěnku a sloty. Nečte přepisy řídicích agentů; čte jejich deníky. mise run status pustí skript nad progress.md každého worktree, spočítá úkoly plánu a ty hotové, přečte časová razítka odeslání a odhadne dokončení z mediánu doby úkolu, označené jako extrapolace. Co nedokáže přečíst, hlásí jako problém; nikdy nehádá, že je běh hotový. Tiskne i volný disk.
Řádky deníku jsou psaný formát s testy nad fixturami, což zní jako přehnané pro textový soubor, dokud nevidíte proč. Skript se nejdřív zkontroloval od oka na dvou denících psaných jedním řídicím agentem. Do hodiny napsal třetí řídicí agent dispatch místo dispatched a psal k řádkům čas i se sekundami: dva ze tří živých běhů ukazovaly 0/9 a jeden řádek by shodil hlášení pro všechny běhy. Adversariální review toho pull requestu to našlo před mergem a fixtury od té doby drží.
Ze stejného týdne přišla dvě pravidla o úsudku koordinátora. Posuzuj běh podle deníku, ne podle přepisu: řídicí agent, jehož deník říká „čekám na agenta“, čeká, nezasekl se; koordinátor jednou nahlásil zdravý běh jako zaseknutý ze zastaralého konce přepisu. A šťouchni do řídicího agenta, jehož deník je 30 minut tichý, protože jeden řídicí agent se zastavil, zatímco jeho pracovník běžel, a už se neprobudil; jeden pull request stál devět hodin na jednom úkolu.
Deníky, které přežijí pád
Důvod, proč je jednotkou pravdy deník a ne konverzace, je ten, že konverzace končí. Řídicí agenty prostředí odřízne po zhruba 120 až 150 voláních nástrojů. Týdenní limit využití ukončí každého běžícího agenta najednou, potichu, uprostřed kroku; stalo se to 26. září a znovu 30. září v 08:50 UTC, jednou s neuloženými úpravami v pracovním worktree. 29. září začal den restartem vlastníkovy session. 30. září ve 12:27 UTC se uživatelská session rozpadla (id bez uživatelského jména, I/O chyba z getconf, žádný GitHub, žádná služba simulátoru) a session Claude Code spadla, aniž by se Mac restartoval.
Každý z těch případů se obnovil stejně. Řídicí agent píše řádek RESUME POINT před každým čekáním: který úkol, který commit, které zadání, na co čeká. Nástupce si deník přečte a pokračuje od toho řádku, nikdy znovu neposílá úkol, o kterém deník říká, že je hotový. Po pádu ve 12:27 byli tři řídicí agenti přerušeni uprostřed kroku a obnoveni 25 minut po restartu. Plány delší než zhruba devět úkolů se dělí, aby běh skončil před limitem, ne na něm.
Stejně se zachází s dlouhými bránami. Plná mutační brána trvá na zatíženém Macu hodiny (zhruba tři pro 1 730 mutantů balíčku jádra, zhruba dvě pro 1 622 balíčku aplikační logiky) a řídicí agent, který na jednu dvě hodiny čekal dotazováním, stál 20 volání nástrojů a nedodal nic, než byl odříznut. Dlouhé brány proto běží odpojeně a po skončení zapíší do souboru řádek s návratovým kódem; řídicí agent nikdy nečeká na bránu déle než deset minut; koordinátor sleduje soubor a odešle další krok, když se řádek objeví. Odpojená brána, která běžela ve 12:27, pád přežila a jela dál.
Jedna noc, hodinu po hodině
Takhle vypadá tempo, když není vzhůru nikdo, kdo by ho určoval. Časy jsou v UTC, z deníků 29. a 30. září.
- 21:15 Vlastníkova noční instrukce. Fronta: oprava, která přesune kontroly generovaného plánu mimo jazykový model, mrtvé tlačítko Start po souhrnu, aplikace blokující při startu hlavní vlákno a oprava webu odblokovaná mergem blogu.
- 22:00 Kontrola Search Console pro vlastníka, jen pro čtení, se promění ve dvě issues o přesměrováních webu a chybějících nadpisech. Oprava haptiky dokončí implementaci a jde do review.
- 00:40 Opravy webu jsou draft pull request, CI zelené i na Linuxu; jeho review vyžaduje změny (skryté odkazy pořád braly fokus z klávesnice; nový test stránek by shodil první článek na blogu) a začíná kolo oprav. Review haptiky vyžaduje změny ve třech bodech; i tam začíná kolo oprav. Autor plánu je odříznut uprostřed přehrávání; koordinátor jeho plán commitne a odešle opětovné review.
- 02:35 Disk klesne na 600 MB volného místa a předčasně ukončí mutační bránu. Uvolní se devět gigabajtů (tři nečinné simulátory, dvě složky derived data, osiřelé dočasné soubory). Oprava startu je odeslána, jakmile load average klesne na 15.
- 04:20 Najde se příčina nočních pádů aplikace při startu: audio démon Macu je zaseknutý a jakýkoli start audio enginu po zhruba devíti sekundách spadne na kterémkoli vlákně, i při zátěži 2. Každý test hostovaný v aplikaci se pozastaví a ranní seznam pro vlastníka dostane první řádek.
- 04:42 Vlastník, vzhůru brzy, merguje pull request webu.
- 04:45 Démon se sám vzpamatuje, jakmile je stroj nečinný. Aplikační brány obou oprav běží v jednom agentovi, jeden simulátor po druhém.
- 05:40 Oprava startu je pull request se všemi branami zelenými, se starým chováním nejdřív ručně obnoveným, aby nový test ukázal červenou na pěti tvrzeních, a se studeným zahřátím změřeným na 0,074 sekundy.
Nic z té noci nezamergoval agent. Dva bugy prošly z fronty dvěma koly review každý, jeden až do pull requestu a druhý k zeleným branám, kde čeká, až přijde na řadu; jednu opravu webu zamergoval vlastník před šestou, jedna porucha prostředí byla diagnostikována a jeden incident s diskem vyřešen a vlastníkův ranní seznam měl šest položek.
Co tempo stojí
Poctivý deník má sekci úzkých hrdel a tři položky se v ní opakují.
Sériový řetězec implementátor, reviewer, oprava a opětovné review na každý úkol je mechanismus kvality a zároveň to, co určuje celkovou dobu. Zrevidovaný úkol byl po prvních dvou dnech odhadnut na 25 až 60 minut, swiftové úkoly na pomalém konci kvůli mutační bráně. Řetězec držíme pro kód jádra a aplikace; pro dokumentaci a web stačí jedno review na konci.
Mutační brána dominuje každému swiftovému úkolu. Odpověď zatím je běh nad změněnými soubory na úkol a jeden plný běh na vlnu, což je také důvod, proč projekt dodává jeden pull request na vlnu: mutační brána v CI je ten drahý job a lokální merge worktree s jediným pushem ji drží na jednom běhu.
A vlastníkova rozhodnutí přicházejí v dávkách. Tři pull requesty jednou čekaly na 19 rozhodnutí. Koordinátor teď u technických otázek zaznamená prozatímní rozhodnutí podle svého doporučení, dost malé na to, aby šlo vrátit; nedělá to u toho, jak aplikace působí v ruce. Což je pátý díl (30. října).
Předtím čtvrtý díl (23. října): odkud přišla pravidla z tohohle dílu a jak agenti píší backlog, který pak zpracovávají.
Toto je 3. díl série Towards the Dark Factory. 1. díl: Z úrovně 2 na úroveň 3 za týden. 2. díl: Zeď. 4. díl: Agent plní backlog (vyjde 23. října). 5. díl: Kde ještě zůstává člověk (vyjde 30. října).
Související: 140 pull requestů za týden · Jak používáme Claude Code Skills
Titulní foto: Hyundai Motor Group na Unsplash.


