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.

Spolupráce je celorepozitářová, protože se nástěnka sbírá, ne proto, že se server sdílí

Spolupráce je celorepozitářová, protože se nástěnka sbírá, ne proto, že se server sdílí

majordomus://adr/adr-0044přijato mcparchitekturakoordinaceworktrees

odkazuje na

  • put_in_force apps/majordomus-cli/src/capability/builtin/peers.rs (soubor)
  • put_in_force apps/majordomus-cli/src/peers.rs (soubor)
  • put_in_force mcp-peers
  • put_in_force mcp-shared-server
  • put_in_force test/cases/250_the_board_is_repository_wide.sh (test)

odkazuje na něj

44. Spolupráce je v celém repozitáři, protože nástěnka se sbírá, ne protože se sdílí server

Kontext

Každý worker tohoto repozitáře je zaváděn jednou větou o spolupráci, v CLAUDE.md i v AGENTS.md stejně:

Tento repozitář obsluhuje jeden sdílený server a každý k němu připojený worker je viditelný pro každého dalšího přes majordomus_peers.

První polovina té věty je nepravdivá a je od doby, kdy ADR 0021 učinilo z linked worktrees běžný způsob práce na větvi. Druhá polovina tedy byla nepravdivá také, a to v jediné situaci, kdy na ní záleželo.

Změřeno 2026-09-11 na stroji, na kterém se tento repozitář vyvíjí. Čtení lease každého checkoutu (.ai/local/state/mcp/server.json) a dotaz každé adresy, kterou jmenuje, na její identitu a nástěnku:

checkoutportgit_repository_idrepository_idpeers
prismatic-majordomus (primární)87414ca83e49…b8293f11…4
…-wt/feature/surfaces-compose-alike88014ca83e49…7aa97991…0
…-wt/feature/swagger-offline60204(starší spustitelný soubor)31d111bc…0
…-wt/feature/the-cockpit-shows-the-board624034ca83e49…284b86b7…0
…-wt/fix/cockpit-answers-quickly87914ca83e49…8f8685e5…0
…-wt/fix/stale-runtime-is-loud8799(starší spustitelný soubor)8c355cc1…0
…-wt/fix/worktrees-page-is-fast8792(starší spustitelný soubor)84c4e090…0

Sedm živých serverů. Jeden git repozitář. Sedm nástěnek. majordomus serve status hlásil 118 registrovaných checkoutů za 3,0 s. Worker v jednom z těch worktrees volající majordomus_peers dostal odpověď z paměti vlastního serveru, viděl toho, kdo sdílel jeho checkout, a o ostatních šesti se nedozvěděl vůbec nic — zatímco bootstrap, který právě četl, mu říkal, že viděl všechny.

To není přehmat v dokumentaci. Je to selhání, kterému má věta zabránit, běžící bez dozoru: paměť tohoto repozitáře už zaznamenává „two workers built the same subsystem in one afternoon because neither looked first“ a dne 2026-09-09 nesouvisející relace zaznamenala „the peer board is per-checkout and collision-check only sees pushed refs“ jako samostatnou třídu vad. V den, kdy to bylo napsáno, v tomto repozitáři pracovalo devět agentů, napříč šedesáti worktrees, každý čtoucí nástěnku, která držela jen sebe.

ADR 0035 vidělo polovinu toho. Dalo každému serveru git_repository_id, naučilo server.status vyčíslovat checkouty, které git registruje, a hlásit zámek, postavení a počet peerů každého, a skončilo řádkem, z něhož toto rozhodnutí vychází: „Peer stále nenese na nástěnce vlastní worktree; to je věc dalšího rozhodnutí.“ Počet není nástěnka. Vědět, že server jiného worktree drží tři peery, říká workerovi, že není sám, a nic o tom, čeho se ti tři dotýkají, což je jediné, co worker potřeboval vědět.

Rozhodnutí

Jeden server na checkout, s nástěnkou shromážděnou napříč repozitářem. Ne jeden server na repozitář.

Topologie se nemění a žádná nová se nevymýšlí. Neexistuje druhá autorita, registr serverů, démon, nový port, nový lease ani nový soubor: volba z ADR 0003 a jeden lease na checkout z ADR 0035 platí přesně tak, jak jsou. Mění se jediné čtení.

  • peers.list je ve výchozím stavu celorepozitářové. Vyčísluje checkouty, které git registruje, a čte lease každého — přes server::checkouts_of a server::standing_at, čtečky, které už používá server.status, takže obě schopnosti se nemohou rozejít v tom, které checkouty existují nebo kde jejich servery stojí. Vlastní nástěnku čte z paměti tohoto procesu. Každý další checkout, jehož server odpoví, je dotázán na vlastní nástěnku přes routu, kterou registr deklaruje pro peers.list, a peeři se vrátí sloučení.
  • Shromáždění je z konstrukce hluboké jeden skok. Sourozenec se ptá pomocí checkouts=this a server, který na tuto otázku odpovídá, nevyjmenovává žádný checkout, nečte žádný jiný lease a nesonduje žádný jiný server. Záměrně neexistuje opakování bez parametru: server starší verze jej odmítne (Empty zakazuje neznámá pole) a odpovědět celou jeho nástěnkou by byl cyklus. Nástěnka, kterou nelze číst úzce, se hlásí jako nepřečtená, s důvodem.
  • Každý peer nese checkout, na kterém je. Peer::checkout — digest identity checkoutu, cesta jeho worktree, jeho větev a zda je to tento. To není dekorace: p1 je první relace každé nástěnky, takže sloučený výpis bez toho by obsahoval několik peerů zvaných p1 a nebyl by způsob, jak je rozlišit. Čtenář, který peera shromáždil, jej označí, včetně vlastní nástěnky, protože nástěnka neví, čí nástěnkou je.
  • Překryvy se počítají napříč sjednocením. peers::overlaps_among je nyní jedním algoritmem pro stranu výpisu — PeerBoard::overlaps je ta funkce nad vlastními peery — takže kolizi mezi dvěma worktrees najde přesně ten kód, který již našel kolizi mezi dvěma relacemi jednoho checkoutu. Peeři se párují podle pozice a nikdy podle PeerId, z důvodu výše.
  • Odpověď říká, jak velkou část repozitáře pokrývá. boards obsahuje jeden záznam pro každý pokrytý checkout, ať byl dosažen, či ne, spolu s jeho stavem a důvodem, proč nebyl přečten; complete je false, pokud byl některý vynechán. Výpis, který mlčky vynechá checkouty, jež nedokázal zastihnout, má stejný tvar jako opravovaná vada — pracovník vidí krátkou nástěnku a usuzuje, že tu nikdo další není.

A tvrzení je zúženo tam, kde bylo prostě nesprávné. Rozšíření implementace činí pravdivou druhou polovinu věty bootstrapu; nemůže učinit pravdivou první polovinu a nic by nemělo. CLAUDE.md, AGENTS.md (přes .ai/repo/policy.yaml, který generuje obojí) a docs/CLAIMS.yaml nyní říkají, co platí: server obsluhuje checkout, v němž byl spuštěn, váš worktree má svůj vlastní a nástěnka, kterou čtete, je nástěnkou repozitáře, protože je sbírána ze všech.

Zamítnuté alternativy

  • Jeden server na repozitář, obsluhující každý worktree. To je čtení, ke kterému věta bootstrapu vybízí, a ADR 0035 jej už správně zamítlo: server obsluhuje vrstvu .ai/ checkoutu, v němž byl spuštěn, takže relace na feature větvi připojená k serveru primárního checkoutu by četla pravidla, rozhodnutí a plán trunku. Aby to bylo správně, musel by jeden proces indexovat každý worktree — mnohem větší změna, než jakou tvrzení potřebuje, a taková, která dává kontext každého pracovníka za živost jednoho procesu. Dnes změřeno, musel by obsluhovat 118 checkoutů. Nejmenší změna, která tvrzení učiní pravdivým, je sbírat nástěnku, ne centralizovat server.
  • Sdílený soubor nástěnky pod lokální polovinou primárního checkoutu. Soubor, do kterého každý server zapisuje a ze kterého se sám odstraňuje, je druhý lease se všemi stejnými způsoby selhání a novým vlastním zastaralým stavem — přesně ta alternativa, kterou ADR 0035 zamítlo pro registr serverů, a nástěnka se k tomu hodí hůř: nástěnka je o teď a soubor přežije proces, jehož paměť popisoval.
  • Posílání oznámení mezi servery. Replikace potřebuje doručování, opakování a smiřování a každý server by měl názor na peery, se kterými nikdy nemluvil. Sběr je pull, v okamžiku dotazu, z procesů, které jsou o sobě autoritativní.
  • Ponechat peers.list úzké a přidat druhou, širokou schopnost. Dvě schopnosti odpovídající na „kdo další tu pracuje“ jsou opakovaná sémantická definice, kterou ADR 0004 nazývá vadou návrhu, a ta špatná by byla výchozí — což je přesně opravovaný stav, protože každý worker, který čte bootstrap, volá majordomus_peers.
  • Učinit výchozí checkouts: this kvůli ceně. Cena je skutečná (viz níže) a je menší než cena workera, který věří, že je sám. Úzká odpověď zůstává dostupná jménem.

Důsledky

PeerList získává boards a complete; Peer a Overlap získávají volitelné checkout; peers.list získává volitelný vstup checkouts přijímající totéž slovo, se stejnou výchozí hodnotou, jako server.status. Vše je aditivní: čtenář starého tvaru čte dál. peers.announce zůstává nedotčeno — odpovídá o oznamující relaci na nástěnce tohoto serveru a ta odpověď nikdy nebyla nejednoznačná.

Náklady. Jedno čtení lease na registrovaný checkout, jedna sonda na checkout, jehož lease uvádí adresu, jedna další obousměrná výměna na každý server, který odpoví. V tomto repozitáři dne 2026-09-11 — 118 registrovaných checkoutů, 7 živých serverů — výčet a sondování, které server.status už provádí, trvalo 3,0 s skutečného času a nástěnky jsou jen hrstka loopbackových výměn navíc. checkouts: this nic nevyčísluje, nic nesonduje a čte jednu nástěnku z paměti; měřicí případ ji používá, protože měření nesmí záviset na tom, kolik worktrees má stroj, na kterém běží.

Během nasazování je každý běžící server checkout, který nelze číst, a odpověď to říká. Server spuštěný před touto změnou odmítá checkouts=this — jeho peers.list nepřijímal vstup a zamítal neznámá pole — takže sběr proti sedmi serverům živým 2026-09-11 se vrátil jako complete: false se sedmi důvody jmenujícími adresu a 400. To je návrh v praxi: ohlásil, že se nemohl zeptat, místo aby ohlásil prázdný repozitář, což je chování, které má celé rozhodnutí vytvářet. Náprava je tady běžná pro změnu spustitelného souboru — server checkoutu se restartuje (serve stop, pak volba dalšího klienta, nebo serve ensure) — a tyto servery už server.status z téhož důvodu hlásí jako outdated.

Id peera stále není trvalá identita pracovníka a toto rozhodnutí z něj trvalou identitu nedělá. p1, p2, p3 jsou pozice na jedné nástěnce v pořadí připojení, přidělované znovu při restartu serveru a přeřazované, když se pracovník znovu připojí — relace, která byla ráno p3, je po opětovném připojení svého mostu p1. Nic nesmí korelovat pracovníka napříč opětovným připojením podle jeho pozice na nástěnce. Toto rozhodnutí přidává trvalou polovinu: Peer::checkout jmenuje worktree, který přežije každé k němu navázané spojení, a v topologii tohoto repozitáře je worktree branch a branch je kus práce. Čtenář, který potřebuje říct „toto je stejný pracovník jako předtím“, použije checkout a to, co peer oznámil, nikoli id.

Oznámení stále zaniká se svým spojením a je to přijato. ADR 0035 už zařídilo, že most zopakuje poslední oznámení svého klienta po opětovném připojení nebo převzetí, takže běžné znovupřipojení je pokryto; worker, jehož proces mostu skončí a je nahrazen, oznamuje znovu, jak obě bootstrapové instrukce říkají. Aby oznámení přežilo svůj proces, bylo by nutné ho persistovat, a nástěnka je záměrně paměť: záznam o tom, co relace říkala, že dělá, poté, co relace zanikla, je zastaralý claim, který odrazuje workery od půdy, na které nikdo nestojí. Odešlý peer je na své nástěnce už zachován s attached: false po celou dobu života serveru, což je správné množství paměti — je to fakt o procesu a s procesem končí.

Co stále není vidět. Checkout bez běžícího serveru nepřispívá ničím, a právem: nikdo tam není připojen. Větev pushnutá před začátkem relace nenese žádné ohlášení a není o nic menším nárokem — čtenářem pro to je scripts/collision-check a project.work-is-claimed-before-it-is-built už vyžaduje obojí. A Overlap pojmenovává dřívějšího peera páru, ale ne pozdějšího; pole peers nese obě strany s jejich checkouty, takže dvojici lze obnovit, ale samotný záznam je jednostranný. To už existovalo a nechává se být, aby se nerozšířilo do tohoto diffu.

test/cases/250_the_board_is_repository_wide.sh je důkaz nad skutečnými procesy: dva worktree jednoho repozitáře, v každém připojený skutečný klient MCP přes bin/majordomus-mcp, každý vidí pracovníka toho druhého a překryv mezi jejich nároky; souběžný vstup z obou worktree najednou zanechá jeden lease a jeden server na checkout; a checkout se zastaveným serverem je hlášen jako pokrytý a prázdný, ne vynechaný.

Odkud to pochází

kanonický soubor
.ai/repo/adrs/0044-cooperation-is-repository-wide-the-board-is-gathered-not-shared.md
identity
adr-0044
dostupné také jako
Zdroj MCP majordomus://adr/adr-0044 · majordomus entity show adr/adr-0044 · GET /api/v1/entity?uri=majordomus://adr/adr-0044
v Cockpitu
/cockpit/objects/adr/adr-0044

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.