Přeskočit na obsah

Tato stránka byla automaticky přeložena z angličtiny, jediného jazyka, ve kterém se tento web píše. Číst originál.

Vše, co se hromadí, se měří, omezuje a uklízí commitnutým příkazem

Vše, co se hromadí, se měří, omezuje a uklízí commitnutým příkazem

majordomus://rule/project.accumulation-is-measured@2aktivní operacegitworktreebezpečnostagentikoordinacecidisk

Co se změnilo ve verzi 2 a proč

Verze 1 pojmenovala čtyři veličiny: otevřené pull requesty, připojené worktree, lokální branche a běžící servery. Dne 2026-09-12 pátá veličina ukončila najednou všechny relace na tomto stroji. Svazek dosáhl nuly volných bajtů a první, co selhalo, nebyl build, ale harness zapisující vlastní soubory úloh — takže každá relace četla svůj konec jako rozbité nástroje, ne jako plný disk, a jediný příkaz, který by řekl něco jiného (df), také nešel spustit. Přibližně 145 GB z toho tvořilo apps/majordomus-cli/target ve worktree, jejichž branche už byly sloučeny do origin/master, jeden z nich celé hodiny.

Verze 2 proto přidává disk a přidává polovinu, kterou žádná veličina dříve neměla: mez na straně poptávky. Ostatní čtyři se redukují zpětně a to jim stačí, protože nahromaděné pull requesty snižují propustnost, ale neukončí stroj. Disk takový není: ve chvíli, kdy je měřitelný jako problém, už neběží nic, co by jej mohlo změřit. ADR 0055 nese úvahu a měření.

Zdůvodnění

V tomto repozitáři roste pět věcí, aniž by o tom kdokoli rozhodl: otevřené pull requesty, připojené worktree, lokální branche, běžící servery a výstupy buildů, které ty worktree drží. Žádná z nich se sama nezmenšuje a žádná není vidět z místa, kam se člověk dívá. Výsledkem není pomalý úpadek — je to útes. Toto repozitář ho zasáhlo dvakrát: šestnáct otevřených pull requestů, z nichž patnáct se čistě sloučilo na stroji kteréhokoli vývojáře; šedesát čtyři linked worktree; sto jedenáct lokálních branchí; čtrnáct opuštěných serverů, jeden starší než den, které dohromady držely třináct portů a ~150 MB. A pak 180 GB adresářů buildů na svazku o 926 GiB, z toho 145 GB patřilo práci, která už přistála. Zvenčí byl první příznak jediná věta — nic se nenasazuje — a druhým bylo, že všichni agenti na stroji zemřeli ve stejné minutě. Každá jednotlivá část systému fungovala přesně tak, jak byla navržena.

Příčina je u všech pěti společná a nejde o lenost. Každá z nich je veličina, kterou vidí jen příkaz. git worktree list nespouští to, co vytváří worktrees; gh pr list nespouští to, co otevírá pull requesty; rodič serveru zemře, aniž by to komukoli řekl; a nic na dokončení práce neodstraní build adresář, který vytvořila. Každá tak narůstá pod prahem pozornosti, dokud nepřekročí práh následků, a první hlášení pochází od člověka, pozdě.

Případ pull requestu má druhou příčinu, kterou stojí za to jmenovat zvlášť, protože vypadá jako nedbalost a není. Tento repozitář rozřešuje své odvozené artefakty vlastním merge driverem gitu (merge=derived v .gitattributes, scripts/merge-derived). Vlastní driver je spustitelný soubor konfigurovaný na klon; GitHub jej spustit neumí. GitHub tedy provede obyčejný třícestný merge nad soubory, které každá větev regeneruje, najde konflikty ve všech a pull request označí CONFLICTING. Tlačítko merge tu není pomalé ani nespolehlivé; je strukturálně nedostupné a nikdy dostupné nebude. Přispěvatel, který na ně čeká, čeká věčně, a fronta, která se za tímto čekáním tvoří, je ta výše.

Případ disku má i druhou příčinu a je to důvod, proč to týden relací nikdo neopravil: žádný worker nesměl. project.reclaim-only-what-you-own workerovi zakazuje odstraňovat výstup buildu jiného worktree — právem, poté co relace dvakrát za den způsobila, že spustitelný soubor kolegy zmizel za běhu — a končí slovy „tlak na disk se hlásí, neřeší se odebráním cizích nástrojů“. Každá relace na stroji toho rána se tím řídila a místo toho oznámila měření. Pravidlo bylo správné a mezera skutečná: stranou, která ji smí vyřešit, je commitnutý příkaz, který klasifikuje každého kandidáta dřív, než jedná, a do verze 2 takový příkaz neexistoval.

Požadované chování

  1. Každá kumulující se veličina má jeden měřicí příkaz. Worktrees a větve: majordomus worktree (majordomus_worktrees). Opuštěné servery a výstup sestavení přistálých worktrees: scripts/reap-orphans. Přistatelné pull requesty: scripts/ci/backlog-check. Veličina bez příkazu není spravována; přidat ji bez jejího příkazu je závada, kterou toto pravidlo jmenuje.
  2. Přistání je lokální a na forge se nikdy nečeká. Pull request se sloučí na stroji, který má nakonfigurovaný ovladač derived (just derive-merge-driver), na integrační větvi, s odvozenými artefakty regenerovanými po sloučení a před pushem. CONFLICTING/DIRTY na GitHubu není falešně pozitivní — konflikt je skutečný pro každý klon bez ovladače a GitHub je vždy takový. Odpověď, která rozhoduje, zda práce může přistát, je ta z klonu, který ovladač má, převzatá z návratového kódu merge-tree a nikdy z grepu jeho výstupu. Žádný dokument, workflow ani instrukce nesmí přispěvateli říkat, aby použil tlačítko merge.
  3. Proces se ukončuje podle predikátu, nikdy podle jména. Relace zde jsou navzájem svými nástroji. Server se ukončí, jen když je jeho rodičem init, má nula navázaných spojení a je starší než minimální hranice — každé znovu ověřeno bezprostředně před signálem. pkill -f majordomus je zakázáno úplně: zabíjí servery, ke kterým jsou připojeni živí peeři.
  4. Nic nepublikovaného se nemaže. Worktree nebo branch se odstraní, až když je jeho práce pushnutá. Nula unikátních commitů není důkaz: sloučený branch může držet necommitnutou a nesledovanou autorskou práci a většina zdejších worktrees je špinavá. Klasifikujte pracovní strom, nejen historii.
  5. Výstup sestavení se uvolňuje podle predikátu a jen výstup sestavení. Reaper odstraňuje apps/majordomus-cli/target a nikdy worktree, takže falešně pozitivní nález stojí přestavbu a nikdy ani bajt zdrojů. Adresář sestavení se uvolní, jen když je špička jeho worktree sloučena do origin/master nebo obsažena ve sledovaném vzdáleném refu, nikdo v tom worktree nepracuje, git status je prázdný a adresář je prokazatelně vlastní adresář cargo uvnitř tohoto worktree. Pro tento účel se pushnuté počítá jako přistálé: 2026-10-10 mohla forma jen pro sloučené uvolnit 3 z 31 adresářů sestavení, zatímco 270 GB leželo ve větvích, které byly pushnuté a ve frontě, nebo v odpojených offload stromech, a svazek dosáhl 99 % na dvou strojích zároveň. Živost se čte ze stroje — ps a pracovní adresář každého procesu — a nikdy z nástěnky peerů: oznámení patří spojení a pracovník, který se znovu připojí, si ponechá práci, ale ztratí místo na nástěnce, což je přesně okno, ve kterém reaper běží. Samotná sloučenost by uvolnila worktree každé relace, která ještě nic necommitovala. Primární checkout je vyloučen jménem, ne predikátem, protože každý jiný checkout si půjčuje jeho spustitelný soubor.
  6. Úklid, který neumí změřit živost, nezíská zpět nic. U každého kandidáta vstup, který nešlo přečíst, tohoto kandidáta vyloučí a započítá se do zprávy (project.destructive-sweeps-fail-closed). Pro živost je odmítnutí úplné: čistič, který nerozezná živé od mrtvého, nezíská zpět nic, místo aby získal všechno. Predikátem není nikdy mtime — právě u něj se chybějící vstup mění v extrémní hodnotu, find -newermt na macOS nic nenajde a status sweep, který obnoví index, předstírá živost každého stromu, kterého se dotkne.
  7. Build je omezen dříve, než začne, a uvolní místo dříve, než je odmítnut. Každá cesta, která spouští build jménem pracovníka, se jedné sdílené kontroly ptá, zda je místo. Pod horní hladinou (MAJORDOMUS_RECLAIM_BELOW_MB, výchozí 50GiB) tato kontrola nejprve spustí klasifikované uvolnění reaperu, nejvýše jednou za deset minut na stroj, takže úklid proběhne proto, že se builduje, a ne proto, že si na něj někdo vzpomněl; teprve pak odmítne pod spodní mezí. Reaper, který chybí nebo odmítne, build nikdy neshodí: rozhoduje spodní mez. Testovací runner nastavuje hladinu na nulu, protože případ nesmí jednat na stroji, který měří. Spodní mez je odvozena z měření toho, kolik spotřebuje jeden build tohoto crate, a měření je zapsáno vedle čísla. Mez, jejíž vlastní vstup nelze změřit, to řekne a nechá build běžet — opak mazacího predikátu, a záměrně: odmítat každý build na stroji, jehož df je nečitelný, zastaví veškerou práci kvůli hypotéze.
  8. Co adresář buildu nahromadí, se uklízí před každým buildem a nikdy za jeho běhu. Výstup buildu uvnitř worktree vrací reaper (5); co se hromadí mimo jakýkoli worktree, ne, a 2026-10-16 a 2026-10-17 to byla právě ta věc, která zaplnila svazek: nečinné inkrementální relace (79 GB), zastaralé generace tohoto cratu v deps sdíleného adresáře (204 GB) a soukromé adresáře buildu, na které buildy přešly a nechaly je (178 GiB ve 35). Proto každý build nejdřív spustí mj_rust_prune_build_dir a kontrola limitu disku spouští také mj_rust_reclaim_private (lib/rust_bin.sh), každé s deklarovaným stářím (MAJORDOMUS_INCREMENTAL_IDLE_MIN 30, MAJORDOMUS_DEPS_IDLE_MIN 120, MAJORDOMUS_PRIVATE_BUILD_IDLE_MIN 120 minut). Profil se uklízí jen tehdy, drží-li úklid vlastní zámek cargo na něm (<profile>/.cargo-build-lock, braný bez čekání) a žádný proces jej nejmenuje: cargo test uvolní zámek dříve, než se spustí binárky a doctesty, které sestavil, a úklid posuzovaný jen podle stáří odstranil rlib, který běžící build četl. Generace se posuzuje celá a zůstává, dokud je kterýkoli její soubor čerstvý nebo otevřený; soukromý adresář zůstává, dokud je v něm cokoli čerstvé, drží se jakýkoli jeho zámek nebo jej jmenuje proces. Bez flock(1) nebo lsof se neodstraní nic. Testovací runner vypíná všechny tři.
  9. Růst je hlasitý, než se stane srázem. scripts/ci/backlog-check hlásí přistatelný backlog a selže, když překročí svůj práh, takže „nic se nenasazuje“ je nález kontroly, ne člověka.

Vynucování

  • scripts/ci/backlog-check — kontrola: reaper a integrátor existují a jsou spustitelné, reaper vybírá procesy predikátem a maže jen adresáře sestavení, stále drží všechny tři podmínky pro jeho uvolnění (přistálo nebo pushnuto, není živý, čistý) a stále odmítá, když nelze změřit živost, každá cesta, která spouští sestavení, se ptá sdílené kontroly prostoru, ta uvolňuje pod svou značkou dřív než pod podlahou a spouštěč testů to vypíná, každé sestavení uklízí své adresáře sestavení pod zámkem cargo a spouštěč testů tyto úklidy vypíná, doktrína pojmenovává omezení forge, žádný dokument nepropaguje tlačítko merge a (s tokenem) landable backlog je v rámci prahu.
  • test/cases/131_backlog_hygiene.sh — behaviorální případ pro servery a kontrolu.
  • test/cases/3080_idle_incremental_sessions_are_pruned.sh, test/cases/3196_stale_crate_artifacts_are_pruned_under_cargos_lock.sh a test/cases/3197_idle_private_build_dirs_are_reclaimed.sh — úklidy z položky 9 proti adresářům buildu fixtures: co zmizí, co zůstane a že se nic neodstraňuje pod zámkem cargo ani dokud nějaký proces jmenuje profil.
  • test/cases/276_disk_is_bounded.sh — behaviorální případ pro výstup buildu a mez: co reaper odmítne, že pushnutý čistý bezobslužný worktree se uvolní a nepushnutý se ponechá, že build pod značkou uvolňuje nejdřív a jednou za interval a že build pod hranicí nezačne.
  • scripts/reap-orphans — reaper, ve výchozím stavu dry-run, s --kill a --reclaim jako dvěma samostatnými souhlasy.

Odkud to pochází

kanonický soubor
.ai/repo/rules/project/accumulation-is-measured.v2.md
identity
project.accumulation-is-measured@2
dostupné také jako
Zdroj MCP majordomus://rule/project.accumulation-is-measured@2 · majordomus entity show rule/project-accumulation-is-measured-2 · GET /api/v1/entity?uri=majordomus://rule/project.accumulation-is-measured@2
v Cockpitu
/cockpit/objects/rule/project-accumulation-is-measured-2

Tato stránka je generována z výše uvedeného souboru pomocí scripts/generate-site-data; úprava stránky nic nemění, úprava souboru změní všechna rozhraní. Výše uvedené vztahy jsou hrany docs/generated/graph.json, které spustitelný program zapisuje ze stejného indexu.

Prohledává názvy a popisy všech stránek, které tento web publikuje.