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.

Server checkoutu je jedním ze serverů repozitáře a jeho stav se poskytuje jako každá jiná skutečnost

Server checkoutu je jedním ze serverů repozitáře a jeho stav se poskytuje jako každá jiná skutečnost

majordomus://adr/adr-0035navrženo mcparchitekturakoordinace

odkazuje na

Nic. Tento objekt nedeklaruje žádný odkaz.

odkazuje na něj

35. Server checkoutu je jedním ze serverů repozitáře a jeho stav se obsluhuje jako každý jiný fakt

Kontext

ADR 0003 rozhodlo o jednom sdíleném serveru na repozitář: první majordomus mcp naváže loopbackové HTTP vedle své relace stdio, každý další se připojí a místem setkání je jeden lease soubor v lokální polovině checkoutu. Volba, kterou popisuje, obstála — lease každého tvaru se převezme, klient není nikdy odmítnut, vyměněný spustitelný soubor o lease přijde — a byla napsána dřív, než ADR 0021 dalo tomuto repozitáři propojené worktree jako běžný způsob práce na větvi.

Audit vstupu do repozitáře (docs/ENTRY_AUDIT.md, změřeno 2026-09-10) zjistil, o čem se obě rozhodnutí nikdy nesladila. Lease žije v kořeni checkoutu, kořen je nejbližší .ai/manifest.yaml, každý worktree jeden má a identita, kterou sonda porovnává, je digest tohoto kořene. „Jeden server na repozitář“ tedy byl jeden server na checkout: propojený worktree zvolil vlastní server na vlastním portu s vlastní nástěnkou peerů a žádné čtení žádného lease neříkalo, že dva takové servery patří k sobě. Relace v jednom worktree neviděla peery jiného, sekce peerů v context četla nástěnku primárního checkoutu z worktree hádáním cesty k primárnímu a scénář worktree z mandátu — stejný repozitář, odlišné worktree, peeři, kteří rozliší rozsahy — nebyl selhávající; byl nedosažitelný.

Tentýž audit našel lease čtený ručně na čtyřech místech: volba, read-only serving, snímek prostředí a dva shellové čtenáři (jq v lib/context.sh, sed v .just/serve.just), bez typu mezi nimi. To, co lease zaznamenává — pid, adresu, čas startu, executable — bylo na disku a na žádném povrchu; routa health počítala peery a o procesu neříkala nic; připravenost měla tři nesouvisející definice (existuje výstup adresáře; registr je neprázdný; TCP spojení uspělo); a žádná se neptala na jedinou otázku, kterou už třída zastaralého serveru stála den: je proces za touto adresou kód, který je na disku?

Rozhodnutí

Server obsluhuje checkout a každý checkout git repozitáře patří jednomu repozitáři. Volba se nemění: jedna lease na checkout, v lokální polovině checkoutu, jedno atomické vytvoření, každý zastaralý tvar převzat. Mění se to, že servery jednoho repozitáře lze nyní rozlišit od serverů dvou a vypsat z kteréhokoli z nich:

  • repository::git_identity se ptá gitu, kterému repozitáři checkout patří — adresář git, který sdílejí všechny pracovní stromy — a vytvoří z něj digest. Digest je jedna hodnota pro každý checkout repozitáře a nikdy cesta. Trasa indexu (/) ji vrací vedle vlastního repository_id checkoutu, s linked_worktree, aby čtenář kteréhokoli serveru věděl, jakého repozitáře je jedním z nich a zda je primární. Kde se gitu nelze zeptat, pole chybí; repozitář vrstvy nemusí být pod správou verzí a toto rozhodnutí u takového nic nemění.
  • Checkouty repozitáře se čtou z vlastního registru gitu (git worktree list, čtečka, kterou ADR 0021 už udržuje), nikdy ze souboru tohoto nástroje. Žádný registr serverů neexistuje: server se najde tam, kde je jeho checkout, přes lease, který tento checkout už má.

Lease je jeden typ, čtený jednou. lease::LeaseDocument je to, co server zapisuje a co každý čtenář parsuje; lease::LeaseFile::read je to jediné čtení a nikdy nezklame: chybějící, prázdný, poškozený a dokument jsou jeho čtyři odpovědi a co s každou udělat, je rozhodnutí čtenáře. Volba, serving, objevování služeb prostředí a stav serveru čtou všechny přes něj. Klíč, který čtenář nezná, se ignoruje, takže lease zapsaný novějším spustitelným souborem se stále čte; klíč, který starší lease nemá, dostane výchozí hodnotu. Dokument získává version, verzi spustitelného souboru, vedle identity spustitelného souboru, kterou už nesl; proces, který lease publikuje, si ponechává dokument, který zapsal (lease::held), aby mohl říct, co zapsal, aniž by četl zpět vlastní soubor.

Stav serveru je schopnost. server.status — GET /api/v1/server, nástroj majordomus_server, zdroj majordomus://server — odpovídá, kde server tohoto checkoutu stojí, změřeno proti tomu, co by obsluhoval tento spustitelný soubor: absent (žádný lease), starting (lease stále platí), ready (odpovídá pro tento checkout, ze souboru na disku, v této verzi), outdated (odpovídá, ale z jiné verze nebo ze souboru, který byl od startu nahrazen) nebo stale (neodpovídá, nebo to není lease), s důvodem; lease, který tento proces drží, když je serverem; a každý checkout repozitáře, primární první, každý s leasem, stavem a počtem peerů, které jeho server drží. Rozhodnutí je čistá funkce souboru leasu, jeho stáří, jedné sondy a verze tohoto spustitelného souboru, testovaná větev po větvi; schopnost čte soubory a servery při každém volání a nic necachuje, protože leasy zapisují jiné procesy.

Jak široká je odpověď, rozhoduje volající. Výpis každého checkoutu stojí čtení lease a sondu na každý a stroj se stovkou registrovaných worktrees platí obojí stokrát — což by volající, který chce vědět jen o checkoutu, ve kterém je, platit neměl. Vstup nese jedno pole, checkouts: repository, každý checkout, který git registruje, a this, pouze tento. this je levné z konstrukce, ne z filtrování — git se nikdy nedotazuje na registr work trees, takže se nevyčísluje žádný jiný checkout, nečte se žádný jiný lease a nesonduje žádný jiný server — a nespouští ani žádný vlastní proces: zda je checkout primární, plyne ze stat, který git identita už udělala, a jeho větev se čte z jeho vlastního HEAD. Výchozí je repository, protože to je odpověď, kterou schopnost dávala před existencí pole, a je to kompatibilitní povrch; čtenáři, kteří vždy chtěli jen tento checkout, si o něj říkají jménem.

Vstup konverguje a server, který nevlastní žádný klient, má omezenou životnost. serve ensure přečte lease a otestuje server, který jmenuje, jako to dělá volba, a když žádný neodpovídá, spustí jeden jako samostatný proces — serve --fallback --idle, jeho log vedle lease — a pak čeká, až je připraven; serve stop ukončí ten, který lease jmenuje, pokud odpovídá za tento checkout; serve status je projekce server.status v příkazové řádce. Startovní událost poskytovatele volá ensure (session.ensure_server_on_start, ve výchozím stavu zapnuto) a briefing uvádí, kde server stojí, takže agent má server před prvním připojením; launcher MCP vždy konvergoval stejně přes volbu; shell vstupující do repozitáře je informován, ale není obsloužen, protože vstupní hook nesmí nic spouštět (project.envrc-is-an-adapter) a shell není klient. Server spuštěný ensure skončí, když po --idle sekund nebyl připojen žádný peer, což udržuje větu ADR 0003 — žádný proces bez klienta — pravdivou v čase, nikoli v každém okamžiku.

Oznámení přežije server, kterému bylo učiněno. Most uchovává argumenty posledního přijatého oznámení svého klienta a říká je znovu po opětovném připojení nebo je po převzetí přenese na vlastní nástěnku; jediné místo, které vidí oznámení i opětovné připojení, je to, které je opakuje, a žádný worker nemusí nic pamatovat.

Volba držitele dodrží své sliby i při pomalém startu. Držitel udržuje svůj lease čerstvý, dokud se vrstva načítá, takže studený start pomalejší než bind grace se nikdy nepovažuje za opuštěný; převzetí odstraní jen soubor, který posoudilo; držitel, jehož lease byl při bindování převzat, odmítne publikovat a degraduje; server, jehož lease je převzat později, ho přestane nárokovat a skončí se svými peery; a vlastní čtečka serveru zapomene relace, které přestaly pingovat, na každé cestě.

Zamítnuté alternativy

  • Přesun lease do primárního checkoutu, jeden server na git repozitář. Odpovídá doslovně slovům mandátu a obsluhuje špatný strom: server obsluhuje vrstvu checkoutu, ve kterém byl spuštěn, a relace na feature branchi připojená k serveru primárního by četla pravidla, rozhodnutí a plán trunku. Jeden proces indexující každý worktree by byl poctivou podobou tohoto rozhodnutí; je to větší změna než tento slice a toto rozhodnutí ji nevylučuje — server obsluhující několik checkoutů by zde byl stále uveden, jednou za checkout.
  • Registr serverů 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 stejnými způsoby selhání a novým vlastním zastaralým stavem. Git už checkouty registruje; lease, který každý má, stačí.
  • Porovnávání verzí ve volbě. Lease jmenující server jiné verze se přebírá na fix/stale-runtime-is-loud, což je vlastní větev tohoto rozhodnutí; stav hlásí nesoulad jako outdated a chování volby je třeba měnit v této větvi.
  • Server spuštěný při cd. Žádá o to mandát, který to podnítil; vstupní hook nesmí nic spouštět, ADR 0003 odmítá proces bez klienta a shell není klient. Vstup agentem konverguje; vstup shellem hlásí.
  • Démon se supervizorem. Zamítnuto ADR 0003 a zbytečné: ensure je idempotentní a bezpečné vůči souběhu díky volbě a server, který končí při nečinnosti, nepotřebuje, aby ho někdo hlídal.
  • Zabíjení zastaralého serveru z ensure. Server, který odpovídá, je něčí; stav ho jmenuje outdated s nápravou, stop ho ukončí, když je požádán jménem, a nahrazený spustitelný soubor ztratí svůj lease volbou jako dřív.

Důsledky

server.status, pole git_repository_id a linked_worktree trasy index, LeaseDocument a jeho pole version se stávají kompatibilními plochami. Každý worktree nese svůj vlastní server jako dříve; nové je, že každý z nich umí pojmenovat ostatní.

context je první čtenář, který chce úzkou otázku: ptá se na checkout, v němž běží, a na nic jiného, a platit za každý checkout repozitáře bylo to, co učinilo dotaz na server dražším než nedotazovat se.

Sekce peerů v context a recepty .just/serve.just stále čtou lease samy; jsou to čtenáři, které dodatek ADR 0003 ponechal v shellu, a přesunou se na odpověď spustitelného souboru s příštím slicem (docs/ENTRY_AUDIT.md, fáze 09). Tento slice přistál téhož dne; viz dodatek níže.

Scénář worktree z mandátu je nyní dosažitelný: dva worktree jednoho repozitáře hlásí stejné git.id, odlišná checkout_id a servery a počty peerů toho druhého. Peer stále nenese na nástěnce vlastní worktree; to je věc dalšího rozhodnutí, nad žurnálem nástěnky, který přináší ADR 0034.

tests/server_status.rs drží případ dvou worktree a případ zastaralého leasu; tests/shared_units.rs a tests/mcp_shared.rs drží volbu jako dřív, přes totéž typované čtení.

Dodatek, 2026-09-18: dva shellové čtecí skripty se přesunuly a kontrola drží jejich počet na jedné

Odstavec výše odložil poslední dva shellové čtenáře lease na fázi 09. Přesunuli se v den, kdy byl tento záznam napsán, v 534e8fb7bc — feat(mcp): the shared server's lease has one reader, and a gate that keeps it — takže odložení nebylo nikdy dosaženo a tento záznam od té doby popisuje strom, který už neexistuje.

Co ten řez udělal a co jej drží dnes:

  • lib/context.sh se ptá serve status --repo <root> --format json a čte lease.url odpovědi; recept open v .just/serve.just se ptá téže schopnosti na adresu serveru tohoto checkoutu. Ani jeden soubor neotevírá; scripts/cockpit-probe, třetí čtenář, který odstavec nejmenoval, se přesunul s nimi.
  • Pravidlem je project.the-lease-is-read-once, kontrolou scripts/ci/lease-reader-check a dluh, který ratchet drží, je .ai/repo/lease-reader-baseline.txt — prázdný, takže počet je jeden čtenář, ne jeden čtenář plus zaznamenané výjimky.
  • test/cases/110_lease_reader.sh spouští kontrolu nad fixtures, vloží čtenáře do každého jazyka, v němž ho lze napsat, a vyžaduje, aby ho odmítnutí pojmenovalo.

Změřeno 2026-09-18 na master 751eb3a581: kontrola hlásí 0 known reader(s) kromě apps/majordomus-cli/src/lease.rs a končí kódem 0; zasazení ručního parsování jq do lib/context.sh způsobí, že končí kódem 10, jmenuje soubor, shodná jména a opravu; odstranění sondy obnoví kód 0. Nezávisle na kontrole jsou jedinými sledovanými soubory, které jmenují název souboru leasu mimo čtečku, testy a dokumentaci, .envrc, který žádá direnv, aby ho sledoval, a nikdy ho neotevře, a sama kontrola.

Na rozhodnutí se nic nemění. Tento dodatek existuje proto, aby záznam přestal odporovat stromu, o kterém rozhodl.

Odkud to pochází

kanonický soubor
.ai/repo/adrs/0035-a-checkout-s-server-is-one-of-the-repository-s-and-its-state.md
identity
adr-0035
dostupné také jako
Zdroj MCP majordomus://adr/adr-0035 · majordomus entity show adr/adr-0035 · GET /api/v1/entity?uri=majordomus://adr/adr-0035
v Cockpitu
/cockpit/objects/adr/adr-0035

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.