Zdůvodnění
Pracovníci v tomto repozitáři nejsou lidé a příkazy, po kterých sahají, byly většinou psány pro lidi. git log se sám napojí do pageru, který čeká na q. git rebase -i otevře editor. Správce balíčků se ptá, zda pokračovat. Každé z toho je malá zdvořilost vůči lidskému operátorovi a deadlock pro všechno ostatní, protože program není rozbitý ani pomalý — čeká, správně, na vstup, který nikdy nepřijde.
Toto selhání je horší než pád specifickým způsobem: spotřebuje celý rozpočet čekání a nic nehlásí. Příkaz, který skončí nenulově, řekne, co se stalo, za sekundu. Příkaz zablokovaný na pageru nevydá žádný výstup, žádný návratový kód a žádnou diagnózu; zvenčí je k nerozeznání od pomalé práce, což je nejednoznačnost, kterou má řešit project.every-wait-is-bounded a kterou má toto pravidlo předem nevytvářet.
Oprava není vychytralá a nemusí být. Téměř každý takový program má zdokumentovanou neinteraktivní formu — proměnnou prostředí, --yes, --no-pager, --batch, argument místo výzvy. Její volba nestojí nic a odstraní celou třídu zamrznutí.
Požadované chování
Neinteraktivní podoba je výchozí volba. Pagery jsou vypnuté (PAGER=cat, GIT_PAGER=cat, --no-pager). Potvrzení se zadávají explicitními příznaky, ne odpovědí na výzvu. Kde příkaz čte stdin, stdin se poskytne nebo záměrně zavře, místo aby zůstal připojen k terminálu, který může a nemusí existovat. Kde program respektuje CI, TERM=dumb nebo ekvivalent, nastaví se.
Příkaz, který může blokovat čekáním na vstup, se nespouští. Interaktivní pagery a prohlížeče, editory, celoobrazovkové monitory a REPL nejsou součástí automatického běhu. Stejně tak žádný příkaz, jehož zdokumentované chování zahrnuje čekání na stisk klávesy. Kde je takový příkaz jediný způsob, jak něco udělat, je to nález, ne krok.
Interaktivní relace je výslovná žádost. Operátor o ni může požádat a pak se toto pravidlo na to, oč požádal, nevztahuje. Nic jiného ho neruší — zejména ne „asi to bude v pořádku, protože výstup je krátký“, protože zda se pager zapne, závisí na terminálu, ne na výstupu.
Potvrzení a interakce nejsou totéž. Toto pravidlo vyžaduje, aby se potvrzení předalo jako argument, ne aby se přeskočilo. Destruktivní akce stále potřebuje oprávnění, které pro ni repozitář vyžaduje; mění se jen to, že oprávnění přichází jako předem rozhodnutý příznak, a ne jako výzva zodpovězená tím, kdo se náhodou dívá.
Chování při selhání
test/cases/08_no_forbidden_constructs.sh selže, když cokoli, co běží bez dozoru — scripts/, lib/, sada, bin/ a definice CI — spustí na pozici příkazu některou z výše jmenovaných konstrukcí: pager na konci roury, editor, celoobrazovkový monitor, prompt read -p, interaktivní režim gitu, npx bez --yes, interaktivní přihlášení, sudo, které se může zeptat (sudo hostovaného runneru nemůže, takže workflow jsou z tohoto výjimkou), nebo kontejner s přiděleným terminálem. Nález jmenuje konstrukci, soubor a řádek. Skenování se nejprve testuje proti sobě: každá konstrukce je zasazena do fixture a musí být nalezena, zatímco próza a neinteraktivní formy vedle ní nesmějí.
scripts/liveness-check rozhoduje druhou polovinu nad každým sledovaným shellovým souborem: git log, diff, show nebo blame, jehož výstup není zachycen, poslán rourou, přesměrován ani --no-pager, stránkuje do terminálu a zastaví se na stisk klávesy, který žádný agent neposílá, a hlásí se jako nález pager-blocks. Je zařazena jako kontrola always: true v úloze structure a její dluh se ratchetuje v .ai/repo/liveness-baseline.txt.
Co žádné skenování nevidí, zůstává přezkumu: program, jehož zdokumentované chování je čekat na stisk klávesy, ale jehož jméno není na seznamu, a příkaz, který člověk spouští ručně.
Ověření
test/cases/08_no_forbidden_constructs.sh, mechanická polovina, kterou tam umístilo ADR 0039, a tvar pager-blocks z scripts/liveness-check, testovaný mutacemi v test/cases/122_liveness_gate.sh. test/cases/121_liveness_doctrine.sh drží třídu tohoto pravidla a blok vynucování.