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, jehož zámek byl převzat, to říká na koncovém bodu, který sondují všichni čtenáři, odmítá přijmout nového klienta a hlásí, že to, co popisuje jeho health, je jiný proces; relace, které už měl, pokračují a skončí s nimi

Lease přejde na jiného, zatímco proces, který ho držel, stále běží a je zdravý. Obvyklou příčinou je rebuild: volba čte zaznamenaný spustitelný soubor lease, vidí, že soubor, který pojmenovává, byl nahrazen, a server běžící s kódem, který už na disku není, považuje za zastaralý. Nahrazený proces se nezabíjí — klient uprostřed odpovědi by neměl přijít o server jen proto, že někdo spustil cargo build — takže si ponechává svůj socket, nástěnku peerů, historii provádění i generaci vrstvy, kterou načetl před hodinami.

deklarovaný stavdeklarovaný stav: zaručeno Deklarováno jako deterministické a blokující, implementováno a s uvedeným behaviorálním testem, který to má dokázat. Zda to zaznamenaný běh podporuje, říká verdikt důkazů zobrazený vedle.

zaznamenané důkazyzaznamenané důkazy: nespuštěno Deklarováno jako zaručené, ale nepodložené zaznamenaným během: test je pojmenován, ale žádný úspěšný běh nad současnými vstupy zaznamenán není. jak se zaznamenávají důkazy

Samotné převzetí je správné, hlídač zastaralého spustitelného souboru udělal svou práci; bez vlastníka zůstaly jeho důsledky. Vystřídaný proces si ponechal svůj socket, svou nástěnku peerů i svou generaci vrstvy a na GET / odpovídal stejným name a repository_id jako držitel leasu, takže na něm prošel každý test živosti v systému. Změřeno 2026-09-10 - dva servery jednoho checkoutu, jeden lease a relace, jejíž prostředí nesla starší adresu a četla nástěnku s jedním peerem, zatímco sdílená nástěnka měla dva. GET / nyní nese leaseholder (lease::LEASEHOLDER_KEY, čte ho lease::probe, takže zapisovatel a čtenář se nemohou rozejít), nový initialize je odmítnut s 409 lease_lost a jménem launcheru a kontrola serveru v health.report varuje, že tento proces není serverem, který popisuje. Server příliš starý na to, aby na otázku odpověděl, probe záměrně přijme - jeho odmítnutí by převzalo živý server, a tak se stane, že jeden checkout má servery dva. Doktrína je project.shared-server-resilience.

Co to znamená

Lease přechází na jiného, zatímco proces, který jej držel, stále běží a je zdravý. Obvyklou příčinou je přestavba: volba přečte zaznamenaný spustitelný soubor leasu, zjistí, že soubor, který jmenuje, byl nahrazen, a server běžící s kódem, který už není na disku, považuje za zastaralý. Nahrazený proces se nezabíjí — klient uprostřed odpovědi by neměl přijít o server, protože někdo spustil cargo build — takže si ponechává svůj socket, nástěnku peerů, historii provádění a generaci vrstvy, kterou načetl před hodinami.

Přestává být tím serverem. Jeho index odpovídá leaseholder: false; lease::probe, kterým prochází každý čtenář zapamatované adresy, ji odmítá; nový initialize je odmítnut s 409 lease_lost jmenujícím launcher jako cestu k aktuálnímu serveru; a jeho vlastní health.report varuje, že server, který popisuje, je jiný proces. Relace, které už měl, zůstávají jeho vlastní a proces končí spolu s nimi.

Princip

src/lease.rs zaznamená ztrátu jednou v lost(): příznak platný pro celý proces, který se nikdy neruší, publikovaný dokument leasu je vyčištěn a obsluha signálu dostane pokyn přestat odpojovat soubor, který je nyní někoho jiného. was_lost() je jediná otázka, kterou klade zbytek programu, a záměrně to není held().is_none() — proces, který lease nikdy nezískal (test, přemostěný klient, jednorázový příkaz), musí dál obsluhovat toho, kdo se zeptal. src/shared.rs je to, co si toho všimne: vlastní čtečka serveru porovná token souboru s vlastním každých REAP_INTERVAL a při prvním rozdílu zavolá lost().

Tři odpovědi plynou z toho jednoho faktu. src/http/router.rs zapisuje leaseholder do indexu pod lease::LEASEHOLDER_KEY a lease::probe ho čte pod toutéž konstantou, takže zapisovač a čtenář se nemohou rozejít. src/http/mcp.rs odmítne initialize, který nenese id relace, když lease zmizel. src/capability/builtin/health.rs přidá nález ke kontrole server a varuje, protože stav, který hlásí, je přesný o procesu, který není tento.

Server příliš starý na to, aby na otázku vůbec odpověděl, sonda přijme. Na tomto endpointu jej nelze odlišit od aktuálního a odmítnout jej by bylo horší selhání: živý server považovaný za mrtvý se převezme, a tak jeden checkout přijde ke dvěma.

Jak to vidět

just build
# start a server and note its address
apps/majordomus-cli/target/debug/majordomus mcp < /dev/null &
url="$(sed -n 's/.*listening on \(http:\/\/127\.0\.0\.1:[0-9]*\).*/\1/p' <<<"$(jobs)" )"
curl -s "$url/" | jq .leaseholder          # true
# take the lease away, as a rebuild's election would
rm .ai/local/state/mcp/server.json
sleep 1
curl -s "$url/" | jq .leaseholder          # false
curl -s -o /dev/null -w '%{http_code}\n' -X POST "$url/mcp" \
  -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"late","version":"0"}}}'
# 409
curl -s "$url/api/v1/health" | jq '.checks[] | select(.id=="server") | .findings'

Co nepokrývá

Klientovi, který už drží zastaralou adresu, se řekne, že tam žádný server není; není přesměrován na ten, který tam je. Nalezení aktuálního serveru je volba launcheru, kam tato znalost patří. Server starší než toto pole sonda přijme, z důvodu výše, takže záruka platí od této verze dále, ne pro každý proces na stroji. A nic zde neprodlužuje ani nezkracuje život nahrazeného serveru: skončí, když skončí jeho poslední relace, což u nečinného klienta je časový limit nečinnosti relace.

Proč existuje

Změřeno v tomto repozitáři 2026-09-10. Za jeden checkout odpovídaly dva servery: držitel lease a ten, jehož spustitelný soubor byl o hodinu dříve nahrazen. Oba hlásily stejné jméno, stejné repository_id, stejné počty objektů a schopností — a různé otisky registru. Relace, jejíž prostředí neslo starší adresu, četla nástěnku peerů s jedním peerem, zatímco nástěnka, kterou sdílely všechny ostatní relace, měla dva, a žádná odpověď neříkala, kterou nástěnku čte. Převzetí fungovalo přesně podle návrhu; nikdo nevlastnil jeho následky. Doktrína je project.shared-server-resilience a apps/majordomus-cli/tests/lease_lost.rs dokazuje stav před i po v jednom procesu, protože lease, který byl převzat, se nevrací.

Detail vykreslený z docs/claims/mcp-lease-lost.md.

Od tvrzení k důkazu

  1. 1 · veřejné tvrzení

    Server, jehož zámek byl převzat, to říká na koncovém bodu, který sondují všichni čtenáři, odmítá přijmout nového klienta a hlásí, že to, co popisuje jeho health, je jiný proces; relace, které už měl, pokračují a skončí s nimi

    Žádná funkce ani odpovědnost v README ji nepojmenovává; tato stránka je místo, kde je uvedena.

  2. 2 · kanonické tvrzení

    mcp-lease-lostdeklarovaný stav: zaručeno v docs/CLAIMS.yaml

    Definováno v přečtěte si to na tomto webu · docs/MCP.md

  3. 3 · implementace

    apps/majordomus-cli/src/lease.rs

  4. 4 · test a scénáře

    Test: apps/majordomus-cli/tests/lease_lost.rs

  5. 5 · zaznamenané běhy

    zaznamenané důkazy: nespuštěno jak se zaznamenávají důkazy

Ověřte si to sami

Test běží v jednorázovém dočasném repozitáři a ověřuje chování, ne řetězec ve zdrojovém kódu.

z klonu repozitáře
bash test/run.sh apps/majordomus-cli/tests/lease_lost.rs

Související tvrzení stejná implementace

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