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:
| checkout | port | git_repository_id | repository_id | peers |
|---|---|---|---|---|
prismatic-majordomus (primární) | 8741 | 4ca83e49… | b8293f11… | 4 |
…-wt/feature/surfaces-compose-alike | 8801 | 4ca83e49… | 7aa97991… | 0 |
…-wt/feature/swagger-offline | 60204 | (starší spustitelný soubor) | 31d111bc… | 0 |
…-wt/feature/the-cockpit-shows-the-board | 62403 | 4ca83e49… | 284b86b7… | 0 |
…-wt/fix/cockpit-answers-quickly | 8791 | 4ca83e49… | 8f8685e5… | 0 |
…-wt/fix/stale-runtime-is-loud | 8799 | (starší spustitelný soubor) | 8c355cc1… | 0 |
…-wt/fix/worktrees-page-is-fast | 8792 | (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.listje ve výchozím stavu celorepozitářové. Vyčísluje checkouty, které git registruje, a čte lease každého — přesserver::checkouts_ofaserver::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 propeers.list, a peeři se vrátí sloučení.- Shromáždění je z konstrukce hluboké jeden skok. Sourozenec se ptá pomocí
checkouts=thisa 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 (Emptyzakazuje 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:p1je první relace každé nástěnky, takže sloučený výpis bez toho by obsahoval několik peerů zvanýchp1a 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_amongje nyní jedním algoritmem pro stranu výpisu —PeerBoard::overlapsje 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 podlePeerId, z důvodu výše. - Odpověď říká, jak velkou část repozitáře pokrývá.
boardsobsahuje 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;completejefalse, 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: thiskvů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ý.