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.

Integrace pull requestů

integrace pull requestů: každý otevřený pull request zařazený proti aktuálnímu masteru s jeho důkazy, čtrnáct dispozic, deterministické pořadí, jeden merge po druhém s přeplánováním po každém, obnova větve, práh úklidu, lease a auditní stopa (ADR 0101)

Vykresleno z docs/INTEGRATION.md — tentýž Markdown, který ukazuje GitHub.

Majordomus nesloučí seznam pull requestů. Integruje další prokazatelně bezpečnou změnu do aktuálního masteru, ověří, že přistála, zahodí, co předpokládal, a rozhodne znovu z toho, co je tam nyní. Rozhodnutí je zaznamenáno v ADR 0101, pravidlo je project.integration-follows-the-current-master a kód je crate::integration.

Model v platnosti

To je executor. Kdo přistává, kolik najednou a jak často, rozhoduje vlastník a rozhodnutí z 2026-10-16 je pravidlo project.the-cooperation-model-is-the-owners-word a ADR 0167. Pravidlo je jediný záznam rolí, rozsahu, který si každá nárokuje na meshi, a toho, co každá dělá, a tento dokument jej nekopíruje: web vykresluje pravidlo i rozhodnutí z těch souborů, takže se nemohou rozejít s tím, co se čte zde. Kdo kterou roli právě drží, kreslí obrazovka Mesh v UI (/ui/mesh) z živých nároků.

Rozhodnutí tu mění pracovní jednotku landeru, ne executoru. prs drain níže pořád bere jeden připravený pull request najednou a nikdy nepředává --admin; kombinovaný top je vlastní akt role landing, dávka, kterou ADR 0101 nechalo na člověku a kterou vlastník nyní zvolil. Vše ostatní, co tento dokument o rozhodnutí říká, platí i pro top: rozhoduje se proti aktuálnímu masteru a hlavám, které jmenuje, jeho důkazy se zaznamenávají a žádná kontrola se neobchází.

Pipeline

flowchart TD
  gh["forge (gh)"] --> obs["observation<br/>(recorded, with its moment)"]
  git["git merge-tree + check-attr"] --> rel["relation to master<br/>(cached by SHA pair)"]
  obs --> cls["classify: one assessment per pull request<br/>disposition, reasons, evidence, risk"]
  rel --> cls
  cls --> rank["rank: deterministic order,<br/>next merge, next refresh"]
  rank --> surfaces["CLI · HTTP · MCP · Cockpit<br/>(offline)"]
  rank --> drain["drain: lease, observe, decide,<br/>observe again, act, verify"]
  drain -->|every merge: plan void| gh

Příznak mergeable od forge se nikdy nečte. Tento repozitář řeší odvozené soubory ovladačem merge pro každý klon (merge=derived), který forge spustit neumí, takže forge označí téměř každý pull request za konfliktní. Vztah k masteru rozhoduje git: git merge-tree --write-tree s ovladači a git check-attr merge pro to, které cesty jsou odvozené, podle vlastního .gitattributes masteru.

Relace se rozhoduje přesně na headu, který forge ohlásil a který posouzení jmenuje jako vyhodnocený. Head, který se během obnovení posunul, v klonu není a jeho relace je unknown do dalšího obnovení. Nikdy se nerozhoduje podle toho, co drží právě stažený ref. Když git nemůže říct, které cesty jsou odvozené, protože git check-attr selhal, je relace také unknown, nikdy „nic není odvozené“. Relace se cachuje jen pod dvojicí úplných id commitů a unknown se nikdy necachuje.

Tam, kde by merge konfliktoval nebo změnil jen odvozený výstup, se ptá i git cherry. Když je každý commit, který hlava má a master nemá, na masteru už jako shodný patch, vztah je patch_ids_upstream: změna přistála, třeba cherry-pickem, a master šel dál. Částečná shoda ho nikdy nedá. Nedá ho ani hlava s vlastním merge commitem v tom rozsahu, protože rozřešení merge nemá patch k porovnání, ani čistý merge měnící autorské cesty: tam masteru něco chybí, co hlava nese, například přistálá změna, kterou master mezitím revertoval.

Hlava, která neobsahuje master, není vždy pozadu. Vztah je carries_master, když platí dvě věci: její merge do masteru je čistý a zapíše vlastní strom hlavy a každý commit, který master má a hlava nemá, je merge commit. Master pak nedrží nic, co hlava nemá. To je pull request postavený na hlavě jiného, jakmile ten druhý přistál (viz Vlak níže). V takovém merge se nesloučí žádná cesta, takže žádný driver žádnou nerozhoduje a merge ve forge zapíše stejný strom. Druhá polovina tam je proto, že odvozený výstup se skládá z historie stejně jako ze souborů: changelog vypisuje každý commit, který není merge, takže master, který přijal změnu a vrátil ji, má strom, jaký měl, a dva commity, které žádný changelog na hlavě nikdy nevypsal. Jedna změna v masteru, kterou hlava nikdy neviděla, ať psaná, nebo odvozená, nebo jeden vlastní commit masteru, který není merge, a hlava je behind.

Dispozice

Každý otevřený pull request má právě jednu. Rozhodují se v níže uvedeném pořadí, takže dřívější odpověď vítězí. ready se dosáhne až poté, co jsou všechny ostatní otázky zodpovězeny v jeho prospěch.

DispoziceDráhaKdyDalší
other_basedrženémíří na jinou větev než bázi a hlava žádného otevřeného pull requestu—
waiting_for_dependencyčekánavázáno na jiný otevřený pull request tohoto repozitáře, nebo deklaruje závislost na otevřeném (viz níže)nejdřív přistát tento
draftdrženékonceptoznačit jako připraveno
obsoletecleanupnese štítek, který ho označuje za zastaralý (rozhodnutí vlastníka D3; viz politika štítků níže); kontroluje se před štítky pozastavení, po draftzavře to člověk, nebo odstraní štítek
blockeddrženénese štítek, který jej drží (viz politika štítků níže)odstranit
unsafedrženéforge má na něm zapnuté auto-merge, takže by jej forge sloučil sámvyřaďte to z provozu: gh pr merge <n> --disable-auto
unknowndrženépull requesty, které ho zmiňují, se nečetly všechny (declarations_unread), takže některý z nich může deklarovat, že ho nahrazuje; nebo otevřený pull request, který říká, že ho nahrazuje, není mezi otevřenými pull requesty, které forge vypsal (seznam byl uříznut na limitu nebo byl otevřen mezi dvěma čteními)prs refresh
supersededcleanuppřistál oprávněný deklarovaný nástupce: git najde jeho head nebo jeho merge commit v masteru (viz značky nahrazení níže); superseded_by jej jmenujeprs cleanup --apply ho uzavírá
waiting_for_dependencyčekáautorizovaný deklarovaný nástupce je stále otevřenýpřistát nástupce; tento se pak uzavře, nikdy neslučuje
possibly_redundantcleanupdeklarovaný nástupce je slit, ale master neobsahuje ani jeho hlavní commit, ani jeho merge commitrozhodne člověk
unknowndrženédeklarovaný nástupce není otevřený a nešlo ho přečíst, nebo byl přečten bez toho, kde leží jeho head nebo kolik souborů měníprs refresh
redundantcleanupjeho head je předkem masteru, jeho sloučení nemění žádný soubor, nebo každý z jeho commitů je na masteru jako rovnocenný patchprs cleanup --apply ho uzavírá
possibly_redundantcleanupjeho merge mění jen odvozené artefaktyrozhodne člověk
unknowndrženéjeho head není stažen, git selhal, ochranu větve nelze přečíst nebo váže kontrolu na id aplikace, které není celé číslo, nebo běh kontroly kontextu vázaného na aplikaci nejmenuje žádnou aplikaciprs refresh
conflictingrepairsloučení má konflikt v ručně psané cestěřeší to autor
blockeddrženénastavení repozitáře nedovolují merge commit (viz metoda merge níže)povolit merge commity
waiting_for_reviewčekáchybí povinné review nebo byly vyžádány změny (viz níže)recenzent
needs_repairrepairpovinná kontrola na její hlavě selhala, nebo zaostává za masterem z forkuautor
needs_refreshčekámergne se čistě a žádný neobsahuje master ani jej neneseprs drain --refresh, nebo prs repair <n> --apply pro jeden
waiting_for_checksčekáobsahuje nebo nese master; povinná kontrola je na tomto headu nevyřízená nebo chybíwait
readypřipravenoobsahuje nebo nese master a každá povinná kontrola na tomto hlavním commitu prošlaprs drain

Požadovaná kontrola, která čeká, chybí, byla přeskočena nebo ji nelze přečíst, neprošla. Požadované kontroly se čtou z ochrany větve a rulesetů základu, každá s aplikací, která je k ní vázána, a nikdy se nevypisují zde. Zelená kontrola, která není požadovaná, nedokazuje nic.

Kontrola vázaná na aplikaci je jen check run té aplikace. Commit status téhož názvu to není a není jím ani check run téhož názvu jiné aplikace: nemůže kontrolu splnit, selhat ji ani ji držet čekající. Kontext, který dva zdroje váží ke dvěma aplikacím, se vyžaduje od obou. gh pr list neříká, která aplikace check run zapsala, takže když je kontext vázán, obnovení se forge zeptá, kdo každý zapsal: jedno čtení GraphQL (gh api graphql, dotaz, nikdy mutace) na každých 50 otevřených pull requestů a jedno další na každou stránku headu, který nese víc než 100 kontrol. Báze, která nic neváže, se na nic dalšího neptá. Čtení zapisovatele, které selže, shodí obnovení, stejně jako selhavší výpis.

Běh kontroly vázaného kontextu, jehož aplikace nebyla přečtena, se nikdy nebere za běh vázané aplikace: kontrola je unknown (required_checks:unknown), nikdy ne prošla, a fronta říká, které pull requesty ji nesou. Stává se to, když se head pohnul mezi výpisem a čtením zapisovatelů, což příští refresh odstraní, a když sada kontrol nejmenuje žádnou aplikaci nebo head nese víc než 1000 kontrol, což neodstraní žádný refresh: člověk se musí podívat. Pozorování zaznamenané před čtením zapisovatelů je nemá, takže každá vázaná kontrola se čte unknown, dokud prs refresh.

Vazba pojmenovává aplikaci, nikoli workflow. Každý workflow repozitáře zapisuje jako tatáž aplikace (GitHub Actions je jedna aplikace), včetně workflow, který head pull requestu sám definuje nebo přepisuje: head, který mění .github/workflows/, rozhoduje o tom, co spustí jeho vlastní kontrola pojmenovaná ci. Vazba drží jinou aplikaci venku. Nedokazuje, který workflow běžel.

Kontroly, důvody a důkazy

Pořadí výše je seznam kontrol a každá kontrola se ptá bez ohledu na to, co odpoví ostatní:

KontrolaProjde, kdyžDůvody selhání
basemíří na základstacked_on:#N, nebo base_is:BRANCH
draftnení to konceptdraft
labelžádný štítek, který by ho držellabel:NAME, jeden na štítek
auto_mergeforge nemá nastavený auto-mergeauto_merge_armed
supersessionjeho křížové odkazy byly přečteny celé a žádný oprávněný nástupce není otevřený, přistál, nebyl sloučen jinde ani nepřečtendeclarations_unread, pak superseded_by:#N, successor_open:#N, successor_not_landed:#N, successor_unread:#N, jedno na nástupce
relation_to_masterjeho merge je čistý a něco měníhead_reachable_from_master, merge_changes_nothing, patch_ids_upstream, only_derived_artifacts_differ, relation_unknown:WHY, conflicts_on:COUNT
merge_methodrepozitář povoluje merge commitmerge_commit_not_allowed, nebo merge_settings_unread
dependencykaždá deklarovaná závislost přistáladepends_on:#N, jedna na každou otevřenou závislost
reviewpolitika review je na headu splněnareview:STATE, nebo review_policy_unread
no_failing_checkžádná požadovaná kontrola neselhalarequired_check_failed
freshnesshead obsahuje master, nebo jej nese: merge zapíše vlastní strom headu a chybí mu jen merge commitybehind_master:COMMITS, s fork_head pro fork
required_checkskaždá povinná kontrola prošlarequired_checks:STATE (pending, missing nebo unknown, když kontrola běhu kontextu vázaného na aplikaci žádnou aplikaci nejmenuje), no_required_checks, required_checks_unread

gates posouzení vypisuje každou kontrolu s tím, zda prošla. Jeho reasons drží důvody každé selhávající kontroly v tomto pořadí a první je rozhodující: dispozice je dispozicí první selhávající kontroly. Draft, který je také v konfliktu a selhává v kontrole, je draft s draft, conflicts_on:1 a required_check_failed. Kontrola, která selže jen proto, že selhala dřívější, například freshness při konfliktu mergi, nepřidává vlastní důvod. Připravený pull request má contains_master s required_checks_passed nebo required_checks_skipped. Důvody jsou typované (ReasonCode), ale na drátě jsou to tytéž řetězce jako dříve. Kód, který nese starší řádek stopy a tento seznam jej nejmenuje, se ponechá doslova.

Každý kus důkazu má kind, status, detail a source. Zdrojem je pozorování forge v daném okamžiku, nebo git na jmenovaném masteru a hlavě. Důkaz pro base a draft je tu vždy. Stejně tak required_checks, s jedním required_check na každý kontext, který základ vyžaduje, a review a relation_to_master. dependency se objeví pro každou deklarovanou závislost, label pro každý štítek, který ji drží, auto_merge kdykoli má forge nastavený auto-merge, repository_settings když nastavení nedovolují žádný merge commit, a supersession pro každého oprávněného deklarovaného nástupce (open, landed, not_landed nebo unread; landed je z gitu, na masteru a hlavě či merge commitu nástupce), pro každou deklaraci, kterou neučinil nikdo oprávněný (possible_supersession, jmenující, kdo ji učinil), a jednou, když se křížové odkazy pull requestu nečetly celé (references_truncated nebo references_unread). freshness je vyhrazený druh. evaluated_against jmenuje master, hlavu a okamžik pozorování; dvě rozhodnutí jsou stejná, když jsou stejné master a hlava.

Politika štítků

Štítky, které mají účinek, jsou jedna tabulka, LABEL_POLICY v src/integration/classify.rs. Každý štítek má účinek; platná politika tabulku kopíruje (policy.labels v prs status --json a integration.queue) a klasifikátor čte tu kopii. Žádný jiný seznam štítků neexistuje. Štítek se porovnává bez ohledu na velikost písmen.

PopisekÚčinek
do-not-mergepozastaveno
do not mergepozastaveno
blockedpozastaveno
holdpozastaveno
on-holdpozastaveno
wippozastaveno
manual-mergepozastaveno
obsoletezastaralé

hold činí pull request blocked, s label:NAME. obsolete jej činí obsolete, s label_obsolete:NAME v pravopisu forge (rozhodnutí vlastníka D3): značka osoby je jediný důkaz, který slovo dosáhne — stáří, sdílené cesty a podobný titulek nikdy — a nikdy se nezavírá automaticky. Pull request nesoucí obojí je obsolete, protože člověk na něj jedná tak či tak; draft, který ji nese, zůstává draft, protože se nejdřív ptá kontrola draftu. Neexistuje štítek, který by pull request vyřadil z obnovy executoru (rozhodnutí vlastníka D11).

Auto-merge a metoda merge

Pull request, na kterém má forge zbrojený auto-merge, je unsafe. Forge by jej sloučil sám, jakmile budou splněny jeho vlastní podmínky, mimo executor a proti jakémukoli masteru, který pak bude, a jeho obnova by forge jen předala head ke sloučení. Nic na něj nepůsobí, dokud jej člověk nezbrojí, a fronta vypisuje každý takový pull request v diagnostice.

Exekutor sloučí jen merge commitem, protože merge řeší driver odvozených souborů a squash nebo rebase by přehrál commity, které nikdy neviděl. Metoda merge (policy.merge_method) je merge, když nastavení repozitáře merge commit povolují (allow_merge_commit, čteno pomocí gh api repos/OWNER/NAME), jinak žádná. Při žádné je každý pull request, o němž nerozhodl už vztah k masteru, blocked s důkazy merge_commit_not_allowed a repository_settings a fronta říká proč. Když odpověď forge nenese žádné nastavení merge — token, který je číst nesmí, dostane repozitář bez nich, jako ten workflow Pages — nic není známo: politika říká merge_settings_unread, takový pull request je unknown s merge_settings_unread a fronta říká, že nastavení nešlo přečíst, nikdy že repozitář nepovoluje nic (I2966). Exekutor se nikdy nevrací ke squash ani rebase. Kontrola merge_method přichází po relation_to_master, protože zavření práce, která už je na masteru, nezávisí na nastavení merge: pull request redundant zůstává redundant, po svém vlastním důvodu vypíše merge_commit_not_allowed a prs cleanup --apply ho stále zavře. Stejně tak superseded.

Stavy revize

Nejdřív rozhodnutí revize forge a teprve potom požadavek ochrany větve:

Forge říkáOchrana vyžaduje reviewReviewDispozice, pokud nerozhodlo nic dřívějšího
CHANGES_REQUESTEDlibovolnýchanges_requestedwaiting_for_review
APPROVEDlibovolnýapprovedpokračuje ke kontrolám
REVIEW_REQUIREDlibovolnýpendingwaiting_for_review
nicanopendingwaiting_for_review
nicnenot_requiredpokračuje ke kontrolám
nicnepřečtenounknownunknown

REVIEW_REQUIRED je nevyřízeno i tehdy, když ochrana větve žádné review nevyžaduje. Ruleset nebo code owners mohou vyžadovat review, které ochrana nevyžaduje, a podle forge je review stále dlužné.

Značky závislostí

Pull request závisí na jiném, když řádek jeho těla otevírá jedna z těchto značek, v jakékoli velikosti písmen, následovaná jedním nebo více čísly:

  • Depends on #N
  • Stacked on #N
  • Requires #N
  • Land after #N

Před značkou smí stát jen odrážka (-, *, +, 1.), uvozovky (>) a zvýraznění (*, _), takže - **Depends on:** #7 deklaruje závislost. Další čísla následují s čárkami, and nebo &: Stacked on #644 and #645. Tatáž slova kdekoli jinde na řádku jsou próza: a regression introduced after #540 a thereafter #5 nedeklarují nic, ani holé After #N.

Závislost je splněna, jen když ten pull request byl sloučen. Refresh čte každou deklarovanou závislost, která není otevřená (gh pr view, s nástupci), aby fronta věděla, co se s ní stalo:

ZávislostPull requestDůvod
openwaiting_for_dependencydepends_on:#N
sloučenojím nedržený—
uzavřeno bez mergeblocked: jeho práce nikdy nepřistála, takže ji člověk znovu otevře nebo deklaraci odstranídependency_closed_unmerged:#N
není otevřený a forge to nedokázal říct — odmítnuto, nebo vůbec není pull requestunknown, nikdy nesplněnodependency_unread:#N
součást cyklu deklarovaných závislostí mezi otevřenými pull requestyblocked: žádný z nich nemůže přistát prvnídependency_cycle:#N, jeden na každého dalšího člena

Cyklus se uvádí dřív než cokoli jiného o závislostech, pak uzavřená, pak nepřečtená, pak otevřená. Git také implikuje závislosti: pull request, jehož pozorovaný head obsahuje pozorovaný head jiného, nese jeho commity, takže přistání jednoho přistane oba. Každá taková dvojice je závislost inferred s důkazem inferred — nikdy blokace, nikdy změna disposition nebo pořadí; pull request zadržuje jen deklarace. Refresh vypisuje nejvýše 500 otevřených pull requestů; forge s tolika to uvede v diagnostice fronty, protože závislost na pull requestu za nimi by se četla jako nepřečtená.

Značky nahrazení

Pull request je nahrazen jiným, když to deklaruje řádek těla, čtený stejným parserem ukotveným na řádek jako závislost:

  • Superseded by #N ve svém vlastním těle jmenuje N jako svého nástupce;
  • Supersedes #M v těle N jmenuje N jako nástupce M, z druhé strany.

Kdo smí deklarovat. Deklarace se počítá, jen když pull request, jehož tělo ji nese, je větví tohoto repozitáře, a ne forku, a forge jeho autora označuje jako OWNER, MEMBER nebo COLLABORATOR repozitáře. To platí v obou směrech a testuje se na autorovi těla, které mluví: Superseded by #N na autorovi nahrazeného pull requestu, Supersedes #M na autorovi nástupce. Jakákoli jiná asociace (CONTRIBUTOR, FIRST_TIME_CONTRIBUTOR, NONE), fork nebo asociace, která nebyla přečtena, není oprávněna. Pull request otevřený botem nese asociaci, kterou forge botovi přidělí, a ta je oprávněna, jen pokud je jednou z těch tří. Neoprávněná deklarace nemění žádnou dispozici: nedrží ani neuzavírá a hlásí se jako důkaz supersession se stavem possible_supersession, s uvedením, kdo ji deklaroval, jeho asociace, zda je větev z forku, a nápravy: vlastník, člen nebo spolupracovník řekne Supersedes #M v pull requestu tohoto repozitáře.

Deklarací je jen to, co uvádí autor těla. Značka na citovaném řádku (který začíná >), uvnitř ohraničeného bloku kódu (tři zpětné apostrofy nebo tři vlnovky) nebo uvnitř komentáře HTML jsou cizí slova, příklad nebo nápověda šablony a nic nedeklarují. Tělo vložené nebo předvyplněné ze zprávy commitu je stále jeho autora: co odešle pod svým jménem, to uvádí. Závislost si ponechává shovívavé čtení, citovaná či ne, protože může pull request jedině nechat čekat.

Dvě meze tohoto testu jsou známé a přijaté (ADR 0101 §6, rezidua). MEMBER je slovo forge pro kteréhokoli člena organizace, ať má k tomuto repozitáři jakýkoli přístup, a čte se v okamžiku pozorování: bývalý spolupracovník, který je stále členem, zde může upravit tělo svého starého pull requestu a nechat ho počítat. Osobní repozitář nemá členy. A otevřený pull request, u něhož příznak repozitáře, který deklarace čtou, nic neuvedl, se považuje za pull request z forku: nic nedeklaruje.

Kontrola supersession se klade před relation_to_master, protože pull request, jehož nástupce přistál, obvykle koliduje s tím, co nástupce přinesl, a je nahrazen, ne konfliktní. U oprávněné deklarace rozhoduje, co se s nástupcem stalo:

NástupceDispoziceDůvodDůkazyUzavřeno úklidem
je stále otevřenowaiting_for_dependencysuccessor_open:#Nopenne
landed: forge ho nazývá merged a master obsahuje jeho hlavu nebo jeho merge commitsuperseded, s superseded_by: Nsuperseded_by:#Nlanded („je mergnuto“)ano
přistálo uvnitř dávky: forge ho nazývá uzavřeným, jeho hlavní commit žije v tomto repozitáři a master tento commit obsahujesuperseded, s superseded_by: Nsuperseded_by:#Nlanded („je uzavřeno“)ano
byl zavřen bez merge a jeho hlava žije ve forku, ať hlava ukazuje kamkolijeho vlastního vztahu: držení se uvolnížádné z této kontrolynot_landedpouze pokud ho jeho vlastní vztah činí redundant
nemění žádný soubor, jak to hlásí forge, ať jeho hlava ukazuje kamkoliclosed: relace vlastní; merged: possibly_redundantžádné, nebo successor_not_landed:#Nnot_landedne
byl uzavřen bez sloučení a master neobsahuje ani jeho head, ani jeho merge commitjeho vlastního vztahu: držení se uvolnížádné z této kontrolynot_landedpouze pokud ho jeho vlastní vztah činí redundant
je sloučeno, ale master neobsahuje ani jeho head, ani jeho merge commit (sloučeno do jiné větve, nebo master tohoto klonu zaostává)possibly_redundantsuccessor_not_landed:#Nnot_landedne: rozhoduje člověk
není otevřen a nebylo možné jej přečístunknownsuccessor_unread:#Nunreadne
jakýkoli, když se křížové odkazy nahrazeného nečetly celéunknown, ať je známo cokoli jinéhodeclarations_unreadreferences_truncated nebo references_unreadne
jakýkoli, deklarovaný kýmkoli jiným nebo z forkubeze změny: vlastnížádnépossible_supersessionne

Přistání je fakt gitu. Head nástupce, nebo merge commit, který pro něj forge jmenuje, je předkem masteru; merged forge jen vyslovuje důkaz („je sloučen“ nebo „je uzavřen“). Takže nástupce sloučený squashem přistál svým merge commitem a ten, který byl uzavřen poté, co dávka přenesla jeho head do masteru, také přistál.

Faktu gitu se věří jen o hlavě, kterou nikdo nemohl přesunout, aby ho vyrobil (ADR 0101 §6, dodatek k D3; vlastník to může zvrátit). Nástupce, kterého forge nenazývá mergnutým, přistane jen tehdy, když jeho hlava žije v tomto repozitáři: autor forku může force-pushnout svou větev na libovolný starý commit masteru a zavřít pull request a ta hlava by pak byla předkem masteru bez jakékoli práce. Nástupce z jiného repozitáře zavřený bez mergnutí tedy nikdy nepřistane a uvolní hold, jako každý nástupce zavřený bez přistání. Ten, kterého forge nazývá mergnutým, přistane svou hlavou nebo svým merge commitem, fork či ne. Nástupce, o kterém forge říká, že nemění žádný soubor, nepřinesl nic a také nikdy nepřistane: je to stejný trik zahraný větví tohoto repozitáře resetovanou na master.

Částečné čtení křížových odkazů rozhoduje před čímkoli jiným. Pak z několika oprávněných nástupců rozhoduje ten, který přistál, pak ten, který je stále otevřený, pak ten, který byl mergnut jinde, pak ten, který nebyl přečten; ten, který byl uzavřen bez merge, nedrží nic a je jen důkazem. Když obě těla deklarují stejnou dvojici, je deklarací tělo nahrazeného, pokud smí jeho autor deklarovat, a jinak tělo nástupce. Na drátě zůstává dispozice jedním slovem a superseded_by (přítomné jen s superseded) je její nástupce.

Kde se čtou deklarace. Nástupce, který už není otevřený, není mezi otevřenými pull requesty, takže refresh se ptá forge, spolu s každým otevřeným pull requestem, na asociaci jeho autora a na pull requesty, které jej zmiňují: jeho křížové odkazy (jedno čtení GraphQL, gh api graphql, dotaz a nikdy mutace, na každých 50 otevřených pull requestů). Zmínka je deklarací, jen pokud tělo onoho pull requestu říká Supersedes a jmenuje jej; zmínka z jiného repozitáře je zahozena, protože #N tam není z tohoto repozitáře. Hledání v uzavřených pull requestech neexistuje. Každý nástupce nebo závislost, kterou jmenuje tělo otevřeného a která není otevřená, se čte pomocí gh pr view a každá taková hlava se stáhne, aby git mohl říct, zda přistála. Bez otevřeného pull requestu se na nic neptá.

Jedna stránka obsahuje sto křížových odkazů. Pull request s více se čte znovu samostatně, až do padesáti stránek, pěti tisíc odkazů. Za tím, nebo když forge hlásí, že další následují, a nejmenuje kurzor, je čtení zkráceno a pull request je zadržen: unknown, declarations_unread, důkazy references_truncated, nikdy nemergnut a nikdy neuzavřen, a diagnostika fronty ho jmenuje. Zadržení se týká jen toho pull requestu: zbytek fronty je rozhodnut a postupuje dál. Pull request, který forge z odpovědi vynechal, je zadržen stejně (references_unread) a další obnovení ho přečte znovu. Zkrácení nikdy zadržení neuvolní a nikdy neuzavře.

Držen svými zmínkami. Limit počítá každý křížový odkaz a zmínka od úkolu nebo z jiného repozitáře se zahodí až poté, co byla proložena stránkami. Takže kdokoli, kdo umí napsat owner/repo#N více než pět tisíc krát, kdekoli, drží #N: každé obnovení přečte padesát stránek a shledá ho useknutým a žádný příkaz ho neuvolní. Toto je známý zbytek (ADR 0101 §6, R2): blokuje jeden pull request a nikdy žádný nezavře a rozhoduje o něm člověk. Neexistuje žádná značka uvolnění.

Selhání čtení deklarací je jiný výsledek. Když forge neodpoví na stránku nebo na odkazy jednoho pull requestu (odmítnutí, nebo výpadek přesahující opakování), selže celé obnovení s exit 12, stejně jako selhaný výpis, a nezaznamená žádné pozorování: to zaznamenané dříve zůstane bajt po bajtu tím, čím bylo, a nic se nerozhoduje z části odpovědi.

Pull request, který míří na jinou větev, je naskládán na otevřený pull request, jehož head je tato větev. Počítají se jen větve tohoto repozitáře. Větev forku o větvi zde nic neříká, ať se jmenuje jakkoli, takže fork, jehož větev se jmenuje master, nenaskládá nic.

Úkol a milník

Každé posouzení jmenuje úkol, který jmenuje jeho hlavní větev, pokud nějaký jmenuje, a milník tohoto úkolu: issue a milestone, jinak chybí. Větev je spojení, ve tvaru, jaký jí dává majordomus worktree create --issue <id> (feature/<id>-<slug>): součást cesty rovná id úkolu z .ai/repo/project/issues/, nebo id následované -, a nic jiného se nepočítá — větev feature/I10030 nejmenuje I1003. Milník je ten, který deklaruje záznam úkolu. Obojí se odvozuje při každém čtení fronty ze zaznamenaného pozorování a projektového modelu tohoto checkoutu a nikdy neukládá vedle nich; ani jedno nerozhoduje o dispozici nebo pořadí. prs explain je vypisuje (issue: I0810 · milestone M003), Cockpit je ukazuje vedle názvu a prs status --format json, HTTP API a MCP je nesou u každého posouzení.

Čeho se změna dotýká

Vedle vztahu každé hlavy, ze stejné dvojice commitů a uložené v cache pod stejným klíčem v relations.json, fronta čte, co její sloučení mění podle druhu (change_shape v posouzení): její ručně psané cesty, její odvozené cesty a version_bump, verzi, kterou deklaruje v apps/majordomus-cli/Cargo.toml, pokud to není ta, kterou deklaruje její merge base. Ručně psané cesty jsou celou změnou, včetně hlavy s konfliktem, a rozhodují:

Co sdílejí dva otevřené pull requestyoverlaps[].kindRizikový faktor
obě zvyšují verzi crateversion_bumpoverlapping_version_bump:#N
oba mění záznam pod .ai/repo/releases/releaseoverlapping_release:#N
autorská cestaauthoredžádné

Riziko je nízké, střední nebo vysoké podle dotčených cest. Head, který zvyšuje verzi (version_bump:V), sdílené zvýšení verze či release a vztah, o kterém git nedokázal rozhodnout (paths_unknown), jsou vysoké: ať se z dvou zvýšení verze přistane druhé, musí se znovu odvodit nad prvním a změna, kterou nikdo nedokázal přečíst, není nikdy „jen dokumentace“.

Pořadí

Fronta je řazena podle lane, dispozice, rizika (nízké, střední, vysoké, jak je uvedeno výše), počtu jiných připravených nebo obnovitelných pull requestů, se kterými se překrývá (méně je dřív, protože jeho landing zneplatní méně), počtu otevřených pull requestů, které deklarují, že na něj čekají a ještě nejsou splněné (víc je dřív, protože jeho landing je odblokuje), počtu autorských cest, které mění (méně je dřív: menší změnu je levnější přistát i vrátit), stáří (starší dřív, aby nová snadná práce nemohla vyhladovět starou) a čísla. Každý klíč je hodnota posouzení nebo fronty kolem něj, takže pořadí je úplné a nezávisí na pořadí, v jakém je forge vypsal; src/integration/tests.rs to dokazuje jako vlastnost. Každé posouzení nese faktory, podle kterých bylo řazeno (rank_factors), a prs explain je vypisuje, takže pořadí není nikdy číslo bez důvodů.

Čekání a hladovění

Každý pull request ready nebo needs_refresh nese, jak dlouho je na executoru, aby s ním jednal, a jak často executor zvolil místo něj jiný (wait u posouzení). Obojí se skládá z auditní stopy (crate::integration::wait) a z ničeho jiného:

  • každý krok executoru zaznamenává přechody od posledního slova stopy, jako became_actionable a left_actionable (s dispozicí, kterou má nyní, nebo že už není otevřený);
  • každý výběr zaznamenává ostatní akceschopné pull requesty, které passed_over.

Pull request, který byl při svém současném čekání třikrát přeskočen, se vypisuje jako starving. To se ukazuje na prs status, prs explain, v Cockpitu a v briefingu a nikdy to nemění pořadí. Rozhodnutí podle stáří už upřednostňuje starší ze dvou jinak shodných kandidátů a dlouhé čekání není nikdy důvod mergnout něco méně bezpečného dříve. Běh nasucho nezaznamenává ani přechody, ani výběr, takže běh nasucho stále nezanechává stopu. Čekání začíná, když executor poprvé vidí pull request jako akceschopný, ne když byl forge poprvé pozorován.

Jedno sloučení v jednom okamžiku

prs drain smyčkuje jeden krok a mezi kroky nic nedrží:

  1. pozorovat forge, stáhnout každou otevřenou hlavu a sestavit frontu;
  2. vzít první pull request ready;
  3. pozorovat znovu a přestavět frontu;
  4. jednat jen tehdy, když druhé rozhodnutí jmenuje stejný master a head a stále říká ready, jinak zaznamenat stale_decision a začít znovu;
  5. merge s merge commitem (--merge) a --match-head-commit <head>, nikdy --admin, squash nebo rebase;
  6. ověřit, že forge ukazuje merged a že stažený master obsahuje jeho hlavu;
  7. zaznamenejte merge s masterem před a po.

Merge posune každý jiný pull request za master, takže další krok vždy začíná novým pozorováním.

Merge, který mění promítaný záznam plánu, nechá GitHub pozadu přesně o tuto změnu. Záznamy jsou soubory pod .ai/repo/project/issues/ a .ai/repo/project/milestones/ a každý záznam, jehož odvozený stav se s některým z nich pohne. scripts/github-sync --apply promítá master a nic jiného a prs drain je nikdy nespouští. Přistání ano: každý push do masteru spustí .github/workflows/github.yml, které se ptá, co GitHub ještě neukazuje (scripts/github-sync --check), aplikuje to a výsledek dokáže pomocí scripts/ci/github-check. Workflow drží issues: write a nic širšího, běží po jednom, nikdy se neruší a odmítne aplikovat bez spustitelného souboru v Rustu. Jeho model je .ai/repo/ci/github.yaml a pravidlo je project.the-projection-is-applied-at-landing. Ten, kdo executor provozuje, tu nemá žádný krok k zapamatování.

scripts/ci/github-check dává aplikaci deklarované okno, apply.window ve stejném souboru. Na vlastním headu pull requestu se záznamy, které změnil, hlásí jako PENDING a neodmítají se. Na masteru zůstávají PENDING, dokud je přistání mladší než okno. Po jeho uplynutí kontrola master odmítne a pojmenuje příkaz. To je záloha pro běh, který selhal: člověk spustí scripts/github-sync --apply z čistého hrotu masteru, s MAJORDOMUS_BIN pojmenovávajícím spustitelný soubor. Do 2026-10-12 byla tímto mechanismem ruční aplikace a master zčervenal v den, kdy byl executor zaneprázdněn déle než okno.

Když není nic připraveno, prs drain --refresh přivede master do prvního pull requestu needs_refresh. Použije odkládací worktree pod společným adresářem gitu, spustí git merge --no-commit s odvozeným driverem (rerere vypnuto, aby žádné zapamatované řešení nerozhodovalo cestu, na kterou se nikdo nepodíval), spustí scripts/derive, commitne s běžícími hooky a pushne fast-forward na větev pull requestu prostým pushem, nikdy vynuceným. Nejdřív zkontroluje, že to, co pushuje, sestupuje z headu, který pozoroval, a že origin ten head stále servíruje (git ls-remote): větev, kterou autor od té doby posunul, dopředu, do strany či zpět, je odmítnuta a nic se nepushne. Mezi touto kontrolou a pushem git sám odmítne větev posunutou dopředu či do strany, protože push pak není fast-forward. Převinutí zpět v tom okně, kdy autor force-pushne větev zpět na předka pozorovaného headu, je jediný krok, který proklouzne: push je pak fast-forward, který obnoví commity, jež autor odstranil. Toto okno je přijato; žádná historie se nikdy nepřepíše. Je to merge commit a nikdy přepis, jak předepisuje project.land-and-publish. Pipeline je jednu úroveň hluboká: dokud obnovený pull request čeká na své kontroly, žádný další se neobnovuje, protože sloučení prvního by druhý znovu zařadilo pozadu. Propustnost je tedy jeden pull request na běh požadované kontroly, což je skutečná cena mechaniky tohoto repozitáře.

Pipeline drží jen běh, který executor spustil: požadovaná kontrola headu, který událost refreshed zaznamenala jako pushnutý (head_after), dokud je pending nebo missing. Počítají se obě, protože forge nevytvoří běh kontroly pro agregační úlohu, jako je ci tohoto repozitáře, dokud nedoběhne každá úloha, kterou potřebuje, takže vlastní head executoru se většinu jeho běhu čte jako missing. Kontrola missing drží pipeline jen po REFRESHED_HEAD_REPORTS_WITHIN (čtyři hodiny) po té události. Poté se bere, že kontrola nikdy nezahlásí, a další pull request se obnoví, takže jedna mlčící kontrola nemůže zastavit každý refresh. Kontrola běžící na headu, který pushnul autor, nedrží nic. Událost refreshed zaznamenaná před existencí head_after nepojmenovává žádný head, takže pull request obnovený starším executorem pipeline nedrží.

Vlak

Jeden pull request na běh požadované kontroly je cena obnovení každého headu jen na master. Vlak ji platí jednou za několik (ADR 0129). Jeho články jsou pull requesty se skládanými heady: druhý se aktualizuje na obnoveném headu prvního, ne na masteru, třetí na headu druhého, a každý to říká řádkem Stacked on #N ve svém těle. Požadované kontroly každého článku běží současně, každá na headu, který drží vše pod ním.

OdkazJe
nejnižší, s prošlými kontrolamiready, contains_master
nad otevřeným linkemwaiting_for_dependency, depends_on:#N, ať její kontroly říkají cokoli
nad článkem, který přistál, s prošlými kontrolamiready, carries_master: žádný refresh a žádný druhý běh kontrol
nad linkem, který přistál poté, co se jeho head pohnulneeds_refresh: master drží to, co tato hlava nikdy neviděla
nad odkazem, který byl uzavřen bez mergeblocked, dependency_closed_unmerged:#N: rozhoduje člověk

Pořadí je pořadím kontroly závislostí, nikoli zvyk: článek se sloučí až po tom, který jmenuje. Druhý merge činí bezpečným vztah, o kterém rozhoduje git a který se nikdy nepředpokládá ze skládání: merge článku do masteru, který nyní drží první, musí zapsat vlastní strom článku a merge commit prvního musí být vším, co článku chybí. Pak je verdikt, který jeho head už má, verdiktem přesně o tom, čím se master stane. Článek, který zčervená, stojí články nad ním po opravě a přistání jedno běžné obnovení, což stojí každý z nich i bez trainu, a nikdy merge stromu, který nikdo neposoudil.

Vlak připravuje ten, kdo uvádí hlavy do aktuálního stavu; vykonavatel rozhoduje o každém článku podle toho, co o něm říká git, a zatím žádný nesestavuje sám.

Pull request se záznamem, který znovu otevírá

Release navrhuje svůj záznam jako release/record-<tag>, otevřený vlastním tokenem workflow, a forge nespustí žádný workflow z události, kterou tento token způsobil. Takový pull request nemá vlastní kontrolu a nikdy mít nebude: čte se waiting_for_checks s required_checks:missing, dokud ho nikdo nezavře a znovu neotevře, a dokud záznam není na masteru, kontrola releasu selhává na každém jiném otevřeném headu.

Proto když není nic připraveno a před jakýmkoli refreshem, prs drain hledá pull request z větve release/record- v tomto stavu a ptá se forge na to, co fronta nenese: kdo jej otevřel, kdy a zda má jedinou vlastní kontrolu. Pokud je otevřený na rozhodnuté hlavě, otevřel jej app/github-actions, je starší než dvě minuty (RECORD_REOPEN_GRACE) a jeho rollup je prázdný, exekutor jej zavře s komentářem, proč, a ihned znovu otevře, což je událost, která spustí jeho běh. Úkon se provede jednou na hlavu: hlava, kterou stopa jmenuje v reopen_attempted nebo reopened, se nikdy nezkouší znovu, protože znovuotevřený pull request se čte také jako missing, dokud neexistuje poslední job jeho běhu. Nic nepushuje, takže nepotřebuje --refresh, a --dry-run jej jen jmenuje.

Záznam, který otevřel člověk, takový, který má jakoukoli vlastní kontrolu, takový, který je stále v ochranné lhůtě, takový, který forge nedokáže ukázat, a každá větev, která není záznamem, se nechají být. Pokud forge odmítne znovuotevření po uzavření, pull request zůstane uzavřen: odčerpávání to řekne, pojmenuje gh pr reopen <n>, zaznamená reopen_failed a skončí s 10.

Urychlené přistání

Vše výše je executor a executor nikdy neprojde --admin. Jedna věc je mimo něj: vlastník ochrany větve se může rozhodnout ji utratit. Pravidlo project.an-expedited-landing-is-the-owners-word a ADR 0155 říkají, kdy smí jmenovaný lander mergnout mimo požadovanou kontrolu a čeho se to nikdy nedotkne. Od 2026-10-16 je landerem role landing seat z Platný model a to, co přistává, může být složený top místo jednoho pull requestu: v jednu chvíli jedna role a přistání může nést celý top.

Požadovaná kontrola trvá asi hodinu a pool posuzuje vždy jeden pull request. Dne 2026-10-12 záznam o release, který změnil jeden soubor, čekal dvě a půl hodiny za běhy, které nikdo neměl v úmyslu číst, zatímco web jmenoval release o dvě verze starší. Následný příkaz vlastníka je citován v ADR. Co činí přistání pod ním bezpečným, bylo měřeno během následujícího dne:

landerprotože
drží výhradní nárok na přistání na meshi, sámmerge mezi kontrolami jiného landeru a jeho mergem činí z těchto kontrol verdikt o stromu, který už neexistuje
sloučí master do větve, commitne merge, pak odvodíhlava posuzovaná samostatně není strom, který přistane, a derive pořízený na nepotvrzeném merge je zastaralý
spustí celou úlohu struktury, testy knihovny a případy, kterých se změna dotýká, na tomto sloučeném stromu a jmenuje commit, na kterém každá běželakontrola, kterou nikdo nespustil, se čte jako kontrola, která prošla; přistání s nedokončenou úlohou structure dalo masteru dvě červené
před posouzením prohledá testy, co změnu čte: identifikátor sourozence napříč apps/majordomus-cli/tests a test/cases, když změna přidává pojmenovaný záznam (dovednost, obrazovku, pravidlo, schopnost), jméno skriptu, když mění, jak skript volá nástroj; a spustí každý nalezený testtest, který vyjmenovává záznamy podle jména nebo nahrazuje nástroj zástupnou verzí a čte, o co byl požádán, žije v rustových lane a shardech sady, které úloha structure nespouští; dvě přistání z 2026-10-13 tuto úlohu prošla a nechala trunk červený, 95 minut a po dobu dalšího běhu
po nalezení červené hledá stejný tvar, než pushne opravuprvní oprava z 2026-10-13 jmenovala dovednost v testu crate; případ, který klade stejný požadavek, by byl příští červenou o jeden běh později
merge s gh pr merge --admin --merge --match-head-commit <head>hlava, která se po posouzení posunula, se odmítne
po sloučení zruší běh vlastní větveběh, který nikdo nepřečte, stále drží runner a běh trunku čeká za ním
ověří commit, který servíruje produkce, pomocí scripts/pages verifykaždé přistání je nasazení a merge, který rozbil publikaci, nic neřekne

Běh je zastaralý a ruší se, když je jeho pull request mergnut či zavřen, když jeho hlava už není hlavou jeho větve, nebo když jiný běh téhož workflow už posuzuje týž commit. Jediný běh commitu na trunku, nasazení v běhu, release běh a běh jiné relace na aktuální hlavě se nikdy neruší. Přistání na trunku samo nic neruší: validační běhy trunku jsou každý svou skupinou souběžnosti a fronta publikací nikdy neruší nasazení v běhu.

Běh, který už nemůže skončit zeleně, se také zruší: jakmile jedna úloha běhu větve selhala, úlohy, které ještě běží, o tom headu nerozhodují a drží runnery, na které čeká běh trunku. Lander čte selhanou úlohu jako první, přes jobs API, které odpovídá, i když běh ještě probíhá. Vlastní běh trunku se nechá doběhnout: jeho ostatní úlohy jsou jediným čtením ostatních drah trunku. Dokud běh trunku čeká ve frontě, je běh větve na headu, který trunk obsahuje, tímto čtením, dráhu po dráze, a čte se před zrušením. U pull requestu to workflow dělá samo: poslední krok každé kontrolní úlohy, na failure() samotné události pull_request, zruší běh podle jeho vlastního id (.github/workflows/validate.yml, případ 3019). Push do master, plán a dispatch se tak nikdy neruší.

Co sloučený strom dluží, se řídí tím, čeho se změna dotýká, a klauzule 4 pravidla to vypisuje: záznam, který čte test crate (dovednost, pravidlo, tvrzení, základní linie kvality, záznam plánu), dluží testy crate, které otevírají samotný tento repozitář (tests/skills.rs, tests/quality.rs a jejich sourozenci) a kontrolu intent-check, i když se žádný Rust nepohnul. Aktivní dovednost chybějící v záhlaví tests/skills.rs nebo v případu 391 je odmítnuta v jobu structure kontrolou skill-naming a případ, který jmenuje záznam releasu, aniž by ho spouštěla kontrola release-record-cases, kontrolou release-record-listing. Změna, která přidává nebo rozšiřuje exportovanou položku Rustu, dluží scripts/rust-check --quality před pushem: report kontroly rust-quality na stroji autora s nálezem, který by vypsal job structure; dvě implementace z 2026-10-14 tuto kontrolu potkaly až v jobu structure.

Červená na trunku má jednoho nositele, jmenovaného integrátorem. Druhá relace, která buildí tutéž opravu, stojí disk a nepřistane nic dřív.

Mezi tagem a jeho záznamem nepřistane nic jiného. Pull request záznamu, který workflow release otevře, je záznam a soubory z něj odvozené, generované proti master dané minuty; přistání v tom okně tyto soubory pod ním pohne a web dál jmenuje předchozí release, dokud se záznam nesloučí s master a znovu neodvodí. Záznam se sloučí první, pinnutý, jakmile se přečtou jeho vlastní kontroly.

Release se nikdy neurychluje. Tag se pushuje jen na commit, jehož kontrola ci skončila úspěchem; scripts/ci/release-verdict odmítne cokoli jiného, release workflow se na to ptá před buildem a žádná kontrola se kvůli tomu nevypíná, nepřeskakuje ani neupravuje. Merge se opraví dalším merge. Tag publikuje spustitelné soubory, které lidé instalují.

Oprava

Dráha repair patří člověku. Většina pull requestů tu přejde na forge do CONFLICTING během minut po každém mergi do master, a téměř vždy kvůli merge=derived souborům, které forge nedokáže rozřešit, protože odvozený ovladač je konfigurací jednotlivého klonu. prs repair <n> (nebo název head větve) přenese master do jednoho pojmenovaného pull requestu, ať v jaké dráze čeká, tímtéž krokem jako prs drain --refresh. Nahrazuje scripts/unblock, které to dělalo mimo integrátor, bez leasu a bez stopy.

Sám nic nerozhoduje. Čte posouzení pojmenovaného pull requestu a jedná jen tehdy, když klasifikace říká, že hlavě chybí master a merge gitu s odvozeným atributem nekonfliktuje na žádné autorské cestě, vztah behind. Každý konflikt, který forge hlásí, je pak na cestě merge=derived, kterou vyřeší regenerace.

Posouzení říkáprs repair
vztah behindzpůsobilé: master je slit, odvozen, commitnut a pushnut
vztah conflictingodmítnuto s exit 10, jmenuje každý autorský soubor v konfliktu: jejich vyřešení náleží vlastníkovi
vztah up_to_datenení co opravovat: hlava už obsahuje master
vztah carries_masternení co opravovat: sloučení zapíše vlastní strom a jeho kontroly posoudily právě ten strom
redundant, superseded, relace contained, superseded, patch_ids_upstream nebo derived_onlynení co opravovat: je to dráha cleanupu, nebo člověka
vztah unknown, head forku, zapnutý auto-merge, jiná základna, neotevřenýodmítnuto s exit 10

Bez --apply, což je výchozí a píše se také --dry-run, jde o čtení. Rozhoduje podle fronty posledního zaznamenaného pozorování, tak jako prs status a prs explain. Nesahá na síť, nebere lease, nic nezapisuje do stopy a končí s exit 10, když nebylo nikdy nic pozorováno. prs refresh pozoruje znovu. S --apply se řídí pravidly vyprazdňování:

  1. převezme integrační lease základní větve a drží jej, dokud akt neskončí, takže jej drain nemůže předběhnout a druhý executor mezitím spuštěný je odmítnut (exit 12);
  2. znovu pozoruje forge, přesně jako krok drainu, a znovu na tom základě rozhoduje;
  3. zaznamená repair_selected a pak repair_attempted, než cokoli dorazí na remote, a nedělá nic, když nelze zapsat kterýkoli z řádků;
  4. v scratch worktree pod společným adresářem gitu, nikdy ve vlastním worktree větve, sloučí master, o kterém rozhodl, spustí scripts/derive a commitne se spuštěnými hooky;
  5. pushne fast-forward headu, který pozoroval, prostým pushem a jen dokud origin ten head servíruje, poté zaznamená repaired s headem, který pushnul, nebo repair_refused s třídou selhání.

Merge, derive, commit nebo push, které selže, nenechá na větvi nic a je repair_refused. Větev, která se pohnula, je klasifikována stale. Nikdy se nemerguje do masteru, nikdy nežádá forge o merge a nikdy se nedotkne checkoutu člověka. Odmítnutí rozhodnuté z klasifikace se zaznamená také, když byl zadán --apply, takže stopa říká, proč se požadovaná oprava nestala.

Úklid

Zavření pull requestu vyžaduje víc důkazů než jeho mergnutí. prs cleanup vypisuje ty redundant a superseded a zavírá je jen s --apply (--dry-run uvádí výchozí hodnotu), s komentářem, který jmenuje důvod, jenž rozhodl, bázi a master a head, které to dokázaly. Komentář má dvě podoby. U redundantního říká, že jeho práce je již na bázi. U nahrazeného začíná jeho nástupcem (Superseded by #N, which landed.), říká, že #N byl prohlášen za jeho náhradu někým, komu to tento repozitář dovoluje, a že báze jej obsahuje, a netvrdí, že zavřená práce je na masteru. Zavření se provádí jako merge: forge se nejprve znovu pozoruje a pull request se zavře, jen když druhé rozhodnutí stále říká totéž proti témuž masteru a headu, jinak trail zaznamená stale_decision a nic se nezavře. Forge se těsně předtím zeptá na stav a head pull requestu a head, který se posunul, se nikdy nezavře. possibly_redundant se vypíše a ponechá člověku, ať je jeho důkazem odvozený výstup, nebo nástupce mergnutý někam, co master neobsahuje. Stáří, sdílené cesty a podobné názvy nejsou důkazem ničeho.

Před 0.13 (rozhodnutí vlastníka D2) slovo superseded znamenalo to, co nyní znamená redundant, a jeho uzavření se zaznamenávalo jako closed_superseded. Silný případ je nyní redundant, uzavřený jako closed_redundant; superseded a closed_superseded znamenají jen autorizovaného deklarovaného nástupce, který přistál. Starší řádky stopy se stále čtou: řádek closed_superseded zapsaný dříve nese head_reachable_from_master nebo merge_changes_nothing, nikdy superseded_by:#N.

Větve, které po sloučených pull requestech zůstaly

Větve se tu nikdy nemažou: rozhoduje o tom delete_branch_on_merge forge (rozhodnutí vlastníka D4), takže exekutor nedrží žádný zápis, který větev odstraňuje. Co forge zanechal, se hlásí místo toho, samotným prs cleanup: čte větve originu (git ls-remote --heads) a na požádání nejnovějších 1000 sloučených pull requestů a uchovává každou větev tohoto repozitáře, kterou origin stále poskytuje na přesné hlavě, jež byla sloučena. prs refresh se nikdy neptá — exekutor ho spouští před každým rozhodnutím a fakt jen pro report, který žádný merge nerozhoduje, zůstává mimo tuto cestu; čte jen nastavení z nastavení repozitáře, na které se už ptá. Větev, jejíž špička se po merge posunula, nese novější práci a nikdy se nevypíše; stejně tak větev forku, ať se jmenuje jakkoli, nebo báze. Cleanup vypíše seznam po pull requestech a zaznamená ho jako left-branches.json vedle pozorování, s časem, kdy byl přečten, takže povrchy, které nikdy nesáhnou na síť, vykreslí poslední report s jeho stářím:

merged branches left on origin (2); the forge decides deletion, so none is deleted here:
  fix/left                                         #1     3f2a9c1d0b7e  left_for_a_person
  fix/here                                         #3     9c0d4e5f6a7b  kept: checked out at /…/here-wt
  next: the forge keeps merged branches: enable delete_branch_on_merge, and delete this one with git push origin --delete fix/left

Větev vyčtená v worktree tohoto repozitáře se uvádí jako kept s cestou: někdo na ní může stále stát. Čtení, které selže, ponechá seznam nepřečtený (merged branches: unread), zaznamenaný jako nepřečtený a nikdy jako prázdný. prs cleanup --format json zůstává seznamem pull requestů k zavření.

Bezpečnost

  • Jeden vykonavatel na základní větev: drain, cleanup --apply a repair --apply drží exkluzivní lease na <git-common-dir>/majordomus/locks/integration-<base>.lock, se zaznamenaným držitelem. Držet ho znamená držet exkluzivní flock na tomto souboru po dobu života vykonavatele, takže o držiteli rozhoduje kernel: z vykonavatelů spuštěných ve stejném okamžiku, v jednom checkoutu nebo v několika worktree repozitáře, ho drží právě jeden a žádný pull request není sloučen dvakrát. Jednotkové testy integrace závodí osm vykonavatelů za kolo a případy 855 a 856 závodí samostatné procesy přes příkazovou řádku. Držitel, který skončí, i pádem, lease okamžitě uvolní; živý držitel není nikdy převzat. Záznam nedotčený 30 minut je pozorovatelům hlášen jako zastaralý (prs brief, prs status), kteří lease nikdy nepřebírají. Vykonavatel obnovuje svůj záznam před každým pozorováním a refresh ho udržuje čerstvý, zatímco běží derive větve. Když cesta už nepojmenovává soubor, který vykonavatel zamkl, nebo záznam pojmenovává jiného držitele, lease je ztracen: odčerpávání se zastaví jako při každém systémovém selhání (prs drain skončí s 12) a nic neprovede. Lease se bere pro základ, o kterém bylo naposledy pozorováno, že ho forge pojmenovává, a pozoruje se jako první, když se tento checkout nikdy neptal, nikdy ne pro uhodnuté master.

  • Jeden executor na repozitář, napříč stroji: lease hlídá jeden klon, protože každý worktree sdílí svůj společný adresář gitu a jiný klon má svůj vlastní. Když sdílený server tohoto checkoutu provozuje mesh repozitáře (ADR 0067), executor nejprve vezme exkluzivní nárok na meshi na integration/<repository>/<base> jako relace svého checkoutu a každý propojený runtime proti němu rozhoduje: prs drain druhého stroje skončí kódem 12, jmenuje držící relaci a to, k čemu řekla, že slouží, dřív, než vezme své vlastní lease. Klíč nároku je v záznamu lease; uvolňuje se po lease. Tam, kde žádný mesh neběží, hlídá jen lease a prs brief a Cockpit říkají „per-clone guard only“. Executor úplně zabitý zanechá nárok držený — jeho relace patří jeho checkoutu, kterému mesh nikdy neodmítne sám sebe — a další executor toho checkoutu zbytek uvolní, takže pád stojí ostatní stroje čekání, nikdy nárok, který nikdo nemůže vrátit (integration::exclusive, tests/integration_across_machines.rs, případ 924).

  • Každý akt se připojí do auditní stopy dřív, než se stane. Stopa je jeden soubor na repozitář, <git-common-dir>/majordomus/integration/events.jsonl, vedle lease, takže každý worktree zapisuje tutéž stopu a prs events, prs brief, prs status, schopnosti integration.* a Cockpit ji čtou z kteréhokoli z nich. Shrnutí poslední fronty (summary.json) leží vedle ní. Pozorování a cache vztahů zůstávají v checkoutu, pod .ai/local/state/integration/. Zaznamenané pozorování je schéma 4: nese asociaci každého autora a zda byly křížové odkazy každého pull requestu přečteny celé. Záznam jiného schématu, staršího či novějšího, se odmítne se jmény obou schémat a majordomus prs refresh, který zaznamená takový, jaký tento executable čte; nikdy se nečte jako prázdný ani jako aktuální. Executable 0.14.0 odmítne záznam schématu 4 stejně, podle jeho čísla.

  • Čtení nic nezapisuje. prs status, plan, explain, schopnosti integration.* a Cockpit staví frontu ze zaznamenaného pozorování a nechávají checkout tak, jak ho našly; jen prs refresh a executor, které právě pozorovaly forge, ponechají relace, o nichž rozhodly, a shrnutí, které čte briefing. To, o čem čtení rozhodlo, se přesto uchová v procesu, který četl: dlouho běžící server si pamatuje každou relaci a tvar podle dvojice master..head a to, zda jedna zrcadlená hlava obsahuje jinou, podle dvojice commitů, takže jeho příští čtení téhož checkoutu se git znovu ptá jen na hlavu nebo master, které se pohnuly. Čtení jednoho checkoutu se střídají, takže souběžní čtenáři rozhodnou každou dvojici jednou. MAJORDOMUS_INTEGRATION_MEMO=off čte bez této paměti; odpověď je stejná (integration::memo). Pozorování starší než hodina se uvádí v diagnostice fronty a každé čtení fronty s diagnostikou — status, plan i explain — končí s kódem 10.

  • Stopa se píše první. Merge se od forge žádá až poté, co je merge_attempted na stopě, refresh se pushuje až po refresh_attempted, oprava až po repair_attempted, pull request se uzavírá až po close_attempted a záznamový pull request se uzavírá a znovu otevírá až po reopen_attempted. Když nelze ten řádek zapsat, akce se neprovede: krok hlásí trail_unwritable, vyprazdňování se zastaví a prs drain skončí s 12 (prs repair --apply také s 12). Lease, který stopa nedokáže zaznamenat, se vrátí a odmítne. Jakýkoli jiný zápis, který stopa odmítne, ukončí běh chybou, místo aby pokračoval bez záznamu.

  • Události, každá jako typovaný action na jednom řádku JSON:

    UdálostKdy
    lease_acquired, lease_releasedexecutor bere a vrací lease základní větve
    continuous_started, continuous_stoppedzačne souvislé vyprazdňování a skončí s uvedením důvodu
    observedprs refresh nebo krok executoru pozoroval forge
    became_actionable, left_actionabledva přechody, z nichž se čekání skládá
    selectedvybrán je první připravený pull request, s těmi, které byly přeskočeny
    refresh_selectedvybere se první obnovitelný, s jeho důkazy
    stale_decisionmaster nebo head se mezi rozhodnutím a činem pohnul
    merge_attemptedpřed sloučením, s jeho důkazy
    merge_succeeded, merge_failed, verification_failedpo něm
    failure_acknowledgedčlověk se podíval na merge, který nešlo ověřit (prs drain --resume-after-failure)
    refresh_attempteddříve než se master zmerguje do větve a pushne
    refreshed (s hlavou, kterou pushnul), refresh_failedpo něm
    repair_selected, repair_attemptedprs repair --apply vybral pojmenovaný pull request a chystá se do něj sloučit master a pushnout
    repaired (s hlavou, kterou pushnul), repair_refused (s jeho třídou)po něm, nebo když jej klasifikace odmítla
    close_attemptednež je zavřen nadbytečný nebo nahrazený pull request
    closed_redundant, closed_superseded (s jeho důkazy), close_failedpo něm
    reopen_attempteddříve, než je pull request záznamu, který otevřel token workflow, zavřen a znovu otevřen
    reopened, reopen_failed (s jeho třídou, která říká, zda byl ponechán uzavřený)po něm
    idlenic nebylo připraveno
    observe_failedcyklus průběžného vyprazdňování narazil na výpadek dost krátký na to, aby se přečkal

    Událost může nést také evidence (posouzení, u úkonů výše uvedených jako nesoucích je), class (proč selhala, po klasifikaci) a merge_commit. Každé se při prázdnosti vynechá a řádek zapsaný před jejich vznikem se čte s prázdnými.

  • Checkout, který si držel vlastní stopu pod .ai/local/state/integration/events.jsonl, ji má připojenou ke stopě repozitáře při prvním čtení stopy, dokud repozitář žádnou nemá. Značka events.moved-from vedle stopy zabraňuje tomu, aby se to stalo dvakrát. Staré stopy jiných worktrees zůstávají na místě, protože jejich postupné připojování by jejich řádky poskládalo mimo pořadí.

  • Zkušební běh pozoruje a rozhoduje a nic nemění. Zaznamená jen to, co pozoroval (observed).

  • Odmítnutý merge a zastaralé rozhodnutí jsou specifické pro kandidáta: další krok plánuje znovu. Selhání ověření zastaví vyprazdňování.

  • Každý selhaný úkon ve stopě nese své class: stale, conflict, new_failing_check, review_revoked, transient nebo policy_violation patří jednomu kandidátovi a drain pokračuje dalším; verification_failed a unreadable jej zastaví. Pull request, který forge odmítl mergovat nebo jehož refresh selhal, se zobrazuje jako needs_repair s executor_merge_refused:<head> nebo executor_refresh_failed:<master> tak dlouho, dokud jeho hlava a master jsou ty, které byly odmítnuty, takže se místo opakování téhož odmítnutí vmerguje další připravená změna. Push do větve nebo nový master to smaže; přechodné selhání nikdy změnu nezadrží.

  • Signál zastaví jednorázový drain tak, jako zastaví souvislý: rozpracovaný krok skončí a žádný další nezačne. Souvislý drain přečká krátký výpadek forge (observe_failed, nejvýše tři po sobě jdoucí cykly), než skončí.

  • Merge se ověřuje tam, kde přistál, ne tam, kde říká forge. Base se stáhne a commit hned po masteru rozhodnutí na prvorodičovské linii masteru musí být tento merge: jeho první rodič master, proti kterému se rozhodovalo, a u merge commitu jeho druhý rodič head, o kterém se rozhodlo. Merge, který přistál na jiný merge, na master, který s ním nikdo netestoval, selže jako unexpected_master, i když jej forge nazývá zmergovaným. Commit se zaznamená jako merge_commit na merge_succeeded. To je polovina guardu na straně executora; polovinou na straně forge je „require branches to be up to date“ ochrany (required_status_checks.strict). Politika fronty říká, zda to base vyžaduje (up_to_date_required), a ukazují to prs status a Cockpit; nerozhoduje žádnou dispozici a zapnout to je úkon vlastníka (rozhodnutí D8).

  • Merge, jehož odpověď se ztratila (timeout, přerušené spojení), se nedotazuje na opakování merge, ale na to, zda přistál: přistál a je prokázán, je merge_succeeded; nepřistál, merge_failed.

  • Executor, který se zastavil mezi vyžádáním merge a jeho ověřením, zanechá merge_attempted bez konce. Další drain nejprve ověří tento merge a zaznamená, jak skončil, a teprve pak o čemkoli rozhodne.

  • Selhání ověření drží každý pozdější drain (rozhodnutí vlastníka D7). Dokud se člověk nepodíval a nespustil prs drain --resume-after-failure, což zaznamená failure_acknowledged, drain nic nesloučí, řekne proč a skončí s exit 10; --continuous se zastaví. Dry run stále plánuje.

  • Přechodná selhání forge se ptají znovu (crate::integration::retry): timeout, 5xx, rate limit nebo ztracené spojení, nejvýš čtyři pokusy s čekáním 2, 4 a 8 sekund. Cokoli jiného, například odmítnutí, 401, 404 nebo posunutá hlava, je odpověď a vrací se hned. Observace, fetch a ověření po merge se opakují. Samotný merge se nikdy neopakuje: merge, který vypršel, mohl přistát, a zjistí to ověření. Drain, který po odmítnutém merge rozhodne znovu, činí nové rozhodnutí z nové observace, v mezích svého počtu kroků, a neopakuje.

Příkazy

PříkazSíťCo
majordomus prs / prs statusneseřazená fronta; exit 10, když je pozorování zastaralé nebo chybí
majordomus prs plannepříští merge, příští refresh a ostatní dráhy
majordomus prs explain <n>nekontroly, důvody, důkazy a pořadí jednoho pull requestu
majordomus prs eventsneauditní stopa repozitáře, ze všech worktree stejná
majordomus prs trainsnetrainy naskládaných pull requestů v pořadí přistání: dispozice každého článku, vztah k masteru, připravená hlava pod refs/prep/<n> (pushnutá nebo čekající) a řada; exit 10, je-li observace zastaralá nebo chybí
majordomus prs briefnejeden řádek pro briefing: poslední fronta sestavená v repozitáři, lease a jak daleko sahá, poslední merge, poslední obnovení, selhání nebo zastaralé rozhodnutí; nic v checkoutu, který forge nikdy nepozoroval
majordomus prs refreshanopozorovat forge a stáhnout každý otevřený hlavní commit
majordomus prs drain [--max N] [--dry-run] [--refresh]anointegrovat, jedno sloučení po druhém
majordomus prs drain --resume-after-failureanozaznamenat, že se člověk podíval na neověřený merge, pak vyprázdnit
majordomus prs drain --continuous [--interval S] [--max N] [--refresh]anovyprázdnit, počkat, znovu vyprázdnit až do zastavení
majordomus prs cleanup [--apply]anouzavře to, co je prokazatelně na masteru nebo nahrazeno oprávněným nástupcem, který přistál; vypíše to, co patří osobě (možná redundantní, zastaralé), a větve, které sloučené pull requesty nechaly na origin
majordomus prs repair <n|branch>nezda lze master přivést do tohoto pull requestu, podle posledního pozorování (nanečisto)
majordomus prs repair <n|branch> --applyanopřivést do něj master, pod lease, jak to dělá drain --refresh

Tatáž fronta je GET /api/v1/pull-requests (MCP majordomus_pull_requests), s lease a posledním merge vedle ní. Jeden pull request je GET /api/v1/pull-requests/explain?number= (majordomus_pull_request_explain) a stopa je GET /api/v1/pull-requests/events (majordomus_integration_events). Co by udělal cleanup, je GET /api/v1/pull-requests/cleanup (majordomus_pull_requests_cleanup): plán rozhodnutý offline z posledního zaznamenaného pozorování — would_close nebo left_for_a_person pro každý pull request, tatáž tabulka, podle které jedná prs cleanup — vedle reportu větví, který prs cleanup zaznamenal naposledy, s jeho stářím. Nic nezavírá, nemaže a na forge se na nic neptá. Všechny čtyři jsou deklarovány jednou v capability/builtin/integration.rs.

Cockpit tyto dvě odpovědi vykresluje na /cockpit/integration. Ukazuje počty podle lane, propustnost executoru za posledních sedm dní (merge, merge za den, medián čekání od akceschopnosti po merge, kola CI na merge, medián cyklu, zastaralá rozhodnutí, selhané a neověřené merge — medián, který nic neměřilo, se říká, nezobrazuje jako nula), master, proti kterému bylo učiněno každé rozhodnutí, další merge, kdo drží lease a jak daleko sahá, poslední merge, tabulku na lane s důvody, další akcí a čekáním každého pull requestu a nedávné akce executoru. Když nic není pozorováno, řekne to a jmenuje prs refresh. majordomus context nese prs brief pod INTEGRATION a předávka odvozená s majordomus handover --derive nese stejný řádek pod # Current State, takže relace, která pokračuje v práci drain, začíná s vědomím, co bylo mergnuto, co zbývá, jak dopadl poslední krok a zda executor běží.

Vlaky

Train je skupina otevřených pull requestů naskládaných na sebe: každý článek stojí na tom pod ním a train přistává odspodu nahoru. Hrany jsou potvrzené závislosti, které klasifikátor už čte (Dependency markers): základní větev, která je head jiného otevřeného pull requestu, nebo řádek Stacked on #N, je hrana STACKED_ON; Depends on, Requires a Land after jsou hrany DEPENDS_ON. Odvozená závislost (head, který jiný jen obsahuje) nespojuje nic. Pull request, který deklaruje závislost na tom, který už není otevřený, je stále svým vlastním trainem, s tímto pull requestem pod sebou — přistálým, zavřeným bez merge nebo nepřečteným. Rozhodnutí je ADR 0138; kód je crate::integration::train.

Každý článek nese, co o něm fronta rozhodla — disposition, lane, důvody, další akci, požadované kontroly a každou kontrolu na jeho head, vztah k masteru včetně toho, jak daleko je pozadu a zda master nese (ADR 0129) — a to, co dokáže říct jen train:

PoleCo
positionjeho pořadí, počítáno od 1: topologické řazení, nižší články první, shody rozhodnuté pořadím ve frontě
depthčlánků pod ním na jeho nejdelší cestě k masteru; kořen je 0
at_turnkaždá závislost, kterou deklaruje, přistála, takže pořadí ho povoluje jako další
on, carriesna čem stojí a odkazy na něm naskládané
prephead, který pro něj executor připravil pod refs/prep/<n>, pushed, když je tento commit headem, který forge servíruje, a pending, když čeká, až na něj přijde řada
in_cycleuvězněno v cyklu potvrzených závislostí: žádný jeho článek nemůže přistát první

Na každý train: roots (pod nimi žádný otevřený článek), tops (nic na nich nenaskládáno), next (první článek na řadě), edges (splněno, když pull request pod ním přistál) a pull requesty beneath ho. Vedle trainů unattached_prep vypisuje připravené hlavy, jejichž pull request není článkem — otevřený a na ničem nenaskládaný, nebo vůbec ne otevřený.

Vše se čte: fronta ze zaznamenaného pozorování, těla a kontroly ze stejného pozorování a lokální refy refs/prep/ s git for-each-ref. Nic se nestahuje, nepushuje ani nepřesouvá; pushnutí připravené hlavy v jejím pořadí zůstává aktem executoru.

$ majordomus prs trains
2 train(s), 5 link(s) of o/r observed at 2026-10-11T04:56:48Z; master at 1393d9ef2a; 1 prepared head(s) pending

train-884  roots #884  tops #898  next #884
   1. > #884   needs_refresh          behind 37        prep 9658f78da5 pending on master     fix(http): ...
   2.   #898   waiting_for_dependency behind 37        no prep              on #884       fix(http): ...

Táž odpověď je GET /api/v1/pull-requests/trains (MCP majordomus_pull_request_trains), deklarovaná jednou jako integration.trains. Cockpit ji kreslí na /cockpit/trains po způsobu Neo4j Browseru: master jako kotevní uzel, každý článek jako kruh s číslem a titulkem uvnitř, obarvený podle své dispozice z designových tokenů (přistálé pull requesty pod trainem vlastní barvou, čárkovaně), šipky popsané STACKED_ON / DEPENDS_ON a šipka TARGETS od každého kořene k masteru; silové nebo vrstvené rozvržení, přetahování, zoom a posun, zvýrazněné sousedy uzlu pod ukazatelem a panel vlastností se všemi poli vybraného článku a odkazy na pull request, jeho kontroly a prs explain. Filtruje podle trainu a dispozice (legenda je filtr), hledá podle čísla, titulku nebo větve a ovládá se klávesnicí (šipky přecházejí z článku na článek, Enter otevře pull request, +/- zoom, 0 přizpůsobí, Escape zruší výběr); pohyb se řídí prefers-reduced-motion. Route se znovu ptá jednou za minutu, dokud je záložka viditelná, a ukazuje, kdy se naposledy ptala. Bez JavaScriptu je stránka jedna tabulka na train se stejnými fakty.

Kontinuální režim

prs drain --continuous vyprázdní frontu, čeká --interval sekund (výchozích 300, 30 až 900) a vyprázdní ji znovu. Po celý běh drží lease základní větve, takže druhý executor je odmítnut, zatímco pozorovatelé ne. Strop drží čekání hluboko pod 30 minutami, po kterých se lease nazývá zastaralý. Každý cyklus je běžné omezené vyprázdnění: --max merge, každý z čerstvého pozorování, a mezi cykly se nic nepřenáší. Ctrl-C nebo SIGTERM nechá dokončit probíhající krok, pak se vyprazdňování zastaví a lease se uvolní. Druhý signál jej ukončí okamžitě. Selhání ověření jej zastaví pro člověka a stejně tak forge nebo git, které nelze po opakováních přečíst. Nikdy neběží s --dry-run a nezačne dřív, než to dovolí záznam o rolloutu (viz níže).

Rollout

  1. Nanečisto. prs refresh && prs status && prs drain --dry-run proti skutečnému repozitáři. Klasifikace byla ověřena 2026-09-30 proti 70 otevřeným pull requestům a fáze 1 byla provedena s vydanou verzí 0.14.0 dne 2026-10-06 proti 16, aniž by se cokoli přesunulo (INTEGRATION_ROLLOUT.md).
  2. Jeden merge. prs drain --max 1, jakmile je pull request ready.
  3. Omezené. prs drain --refresh --max 3.
  4. Kontinuální. prs drain --continuous je zamítnuto s exit kódem 10, dřív než se dotkne lease, báze nebo forge, dokud auditní stopa neobsahuje pět ověřených merge (ROLLOUT_MERGES_BEFORE_CONTINUOUS) od posledního merge, který ověřit nešlo. Merge, který ověřit nešlo, počítání začíná znovu, i po --resume-after-failure, protože záznam, který ukončuje, byl důkazem. Kontrola čte stopu a nic jiného: stupně 2 a 3 ji plní (ADR 0101 §13).

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