Zdůvodnění
Osm relací pracovalo na tomto repozitáři jedno odpoledne a téměř nic se nedostalo na veřejnost. Web servíroval verzi 0.3.1 bez changelogu, zatímco master nesl změny za tři releasy, sedm pull requestů zůstávalo otevřených a integrační větev vytvořená v 17:52 byla v 18:00 už zastaralá. Nic z toho nebyl spor o samotnou práci. Každá část byla mechanickým selháním, které nikdo neviděl zevnitř vlastní větve, a každou jsme změřili, místo abychom o ní diskutovali:
- Konflikty nebyly konflikty. Dva pull requesty byly označeny
CONFLICTINGna týchž deseti souborech a deset z deseti bylomerge=derived. Ani jeden nebyl zdrojový soubor. Tento repozitář máscripts/merge-deriveda ty je řeší; GitHub nemůže spustit vlastní merge driver, takže server hlásí konflikty, které neexistují na ničím stroji. Lokální merge masteru dostal jeden z těchto pull requestů na nulu konfliktů, aniž by se cokoli řešilo ručně. Předchozí integrace zde přešla od třiceti tří konfliktů k nule stejným způsobem. - Ovladač je pro každý klon. Worktree, který nikdy nespustil
just derive-merge-driver, bojuje s týmiž soubory i lokálně, a proto se zdálo, že bojují s každým. - Toolchain je na každém stroji zvlášť. Derive sestavuje spustitelný soubor, takže klon bez připnutého toolchainu Rustu po mergi odmítne každý
prs repair --applya jmenujecargoa nic jiného.majordomus doctorto kontroluje (derive-toolchain); před opravou nebo derivací tam ho nainstalujte přes rustup. - Dávka stojí víc než její konflikty. Každý konfliktní merge potřebuje plné
just derive, než jej pre-commit hook přijme, a každá oprava zdroje po tomto derive jej zneplatní. Jedna relace spustila tři derive pro jeden merge. - Veřejný web se rozešel s repozitářem. V 17:46 UTC poskytoval commit z nesloučené větve — výsledek
site-deploy --any-ref, který se sám popisuje jako náhled, namířeného na produkci dvěma různými relacemi, včetně této. - Merge rozbil publikaci a nic to neřeklo. Změna tvaru dokumentu, která se nikdy nevykreslila lokálně, dodala stránku, kterou generátor webu nedokázal sestavit; běh stránek selhal a veřejný web tiše zůstal na předchozím commitu.
- Zelená a dosud nenahlášená vypadaly stejně. Žádný validační běh na masteru nedoběhl přes čtyři hodiny, zatímco master nesl dvě závady, které rozbily každou branch, jež ho mergovala.
Požadované chování
- Přistávejte často a po malém. Větev se mergne do masteru, jakmile je zelená, jedna po druhé. Integrační větev, která dávkuje mnoho, je poslední možnost pro nevyřízené věci, které už existují, je tak deklarována a poté není vzorem.
- Sloučte master lokálně, pak pushněte, než požádáte o review. Spusťte
just derive-merge-driverjednou na worktree. Vyřešte konflikty ve zdrojích, opravte build, pak jednou derivujte, pak commitněte — derive před poslední opravou zdroje je derive udělaný dvakrát. Odvozený soubor se nikdy neřeší ručně: přegeneruje se, protože ručně vyřešený odvozený soubor projde merge a selžederive-checko jeden commit později. Pohled serveru se nezmění, dokud není lokální merge pushnut.majordomus prs repair <n>(bere i název větve) je celé toto gesto jako jeden příkaz integrátoru, ve scratch worktree, které se nikdy nedotkne vlastního worktree větve. Je způsobilý, jen když klasifikace integrátoru říká, že pull requestu chybí master a jeho merge nekonfliktuje na žádné cestě mimo množinumerge=derived; odmítne a jmenuje každý autorský konflikt, místo aby o něm rozhodoval. Bez--applyjen říká, co by udělal. S ním drží integrační lease, nejdřív zapíše akt do stopy, sloučí trunk tam, kde existuje driver, derivuje, commitne a pushne větev s leasem na head, který pozoroval, takže větev, do které mezitím někdo pushnul, se odmítne. Existuje, protože desetiminutové ruční gesto prováděné několikrát denně je to, které se pod tlakem přeskakuje, a větev, do které nikdo master nepřinese, je větev, kterou někdo sloučí bez čtení. - Mechanické sjednocení je napříč generacemi špatně. Vzít obě strany je správně pro seznam, který získal položky, a špatně, když jedna strana je starší generace téhož kódu: sloučení jedné větve tímto způsobem znovu zavedlo druhé rameno matche postavené proti předchozímu tvaru, a s ním sedm chyb překladu.
- Publikujte master a jen master.
scripts/site-deploy --any-refje lokální náhled. Commit, který gh-pages jmenuje, je vždy předkem masteru. - Ten, kdo merguje, kontroluje, co se veřejnosti servíruje. Rovnost není test — merge dopadající během okna nasazení nechá publikovaný commit jako předka místo headu, aniž by bylo něco špatně. Ten, kdo merguje, v omezené době ověří, že web servíruje head, který sloučil, pomocí
scripts/pages verify --url … --commit "$(git rev-parse …)", a ne druhého ručně psaného porovnání, a nikdy ne zkráceným SHA: porovnání je shoda řetězců proti čtyřiceti znakům, takže krátký SHA spálí celý timeout a pak ohlásí neshodu, která žádnou neodpovídá. Selhání jmenuje očekávaný i servírovaný commit. - Nasazení patří k merge. Jeden vlastník na merge, aby dvě relace nepublikovaly jedna přes druhou.
- Změna tvaru se vykreslí před mergem.
scripts/site-build && scripts/site-checkna hlavě, před mergem, kdykoli změna sahá na tvar dokumentu nebo na šablony, které jej vykreslují. Workflow pro pages tyto kontroly znovu nespouští, takže nic mezi mergem a veřejností to nezachytí. - Merge, který mění veřejný kontrakt, nese svou verzi. Přistání bez navýšení je důvod, proč publikovaný web jmenoval verzi o tři release pozadu za kódem.
Chování při selhání
scripts/ci/pages-check, registrovaná jako kontrola pages-live, rozhoduje o publikované polovině. Čtyři věci, protože publikace tu selhala čtyřmi způsoby: commit, který gh-pages jmenuje, musí být předkem masteru; master od něj nesmí odskočit po cestě, která může změnit web, na déle než okno deploye; commit, který živé stránky jmenují, musí být ten, který gh-pages publikoval — selhání, které způsobí push autorizovaný tokenem, kdy nezačne žádný workflow a všechny kontroly stromu zůstanou zelené; a vlastní build gh-pages na straně GitHubu nesmí skončit chybou, což je polovina publikování, kterou tento repozitář nevlastní a kvůli které se žádný náš workflow nezčervená.
Druhá z nich je bod 5 učiněný mechanickým a je to ta, která chyběla. Samotný původ byl jednosměrná kontrola: publikace, která je na masteru, na něm je, ať je jakkoli stará, takže 2026-09-10 kontrola celé odpoledne říkala ok, zatímco web zaostával o hodiny. Okno odděluje nasazení v běhu, které bod 5 omlouvá, od nasazení, které nepřijde; je to třicet minut, dimenzováno podle pětadvacetiminutové fronty Actions pozorované onoho dne, a commit, který nemůže změnit web, nedluží žádnou publikaci — cesty, které mohou, jsou scripts/pages paths, což je také vlastní spouštěč publikačního workflow.
Běží v plném plánu vedle installer-live, nikdy v plánu spouštěném cestou: kontrola s živou sítí při každém pushi kolektivně selže, když je některý origin pomalý, a kontrola, která křičí vlk, se obchází.
Zbytek rozhoduje review a záznam na nástěnce sdíleného serveru. Kontrola nemůže poznat, že větev čekala na dávku, a vymýšlet takovou by bylo horší lék než nemoc.
Ověření
test/cases/104_published_site.sh drží scripts/ci/pages-check u toho, co tvrdí, proti fixture repozitářům, ne proti síti: publikace z trunku se přijme, publikace z větve, která v něm není, se odmítne s pojmenovanou příčinou a nápravou, trunk, který publikaci předběhl, se přijme, dokud je deploy mladý, a odmítne, jakmile je starší než okno — obojí nad jedním fixture, takže posuzovaným je stáří, ne strom — deploy commit, který neříká, odkud pochází, se odmítne jako neauditovatelný místo hádání, měření, které kontrola nemohla provést, se hlásí jako poznámka a nikdy jako ok a kontrola nenese ani vlastní URL, ani cestu identity — obojí se čte z deklarací, které je už drží. Případ byl prokázán jako nevakuózní tím, že se z kontroly odebralo odmítnutí a sledovalo se, jak selže.
Živá polovina není simulovaná: případ, který by postavil HTTP server, by testoval vlastní fixture, a případ, který by sáhl na skutečný web, by selhal vždy, když selže síť. --offline je ten šev a případ ověřuje, že se šev ohlásí sám, místo aby se potichu přeskočil.
test/cases/97_pages_fast_path.sh drží samotnou publikační cestu včetně její souběžnosti: skupina pages- serializuje běhy a nic neruší probíhající deploy (cancel-in-progress: false; jeho zrušení 2026-09-12 publikaci vyhladovělo) a běh uvádí, zda pushnul gh-pages, než skončil, protože zrušený běh není selhání a čtrnáct ze sedmnácti zrušených běhů z 2026-09-09/10 už publikovalo. Chování derived-merge-driveru je test/cases/57_derived_merge_driver.sh a test/cases/911_repair_decides_and_moves_nothing.sh a test/cases/912_repair_acts_under_the_lease_and_the_trail.sh drží majordomus prs repair u klauzule 2, proti skriptovanému forge a lokálnímu holému originu. Pull request v konfliktu jen na odvozených souborech je způsobilý a ten v konfliktu na psaném souboru je odmítnut se jmény souborů; výchozí dry run nesáhne na žádný forge, nezapíše žádnou stopu a nepohne žádným refem; aplikovaná oprava zaznamená pokus před pushem, drží lease po dobu práce, pushne merge trunku s lease na pozorovaný head a nikdy se nedotkne masteru; a větev, která se mezitím pohnula, je odmítnuta a ponechána tak, jak ji autor pushnul. Rustové testy integration::repair drží stejná rozhodnutí a pořadí stopy bez repozitáře.