161. Uzel mesh sleduje publikovaný release, přes jeden instalátor, jen vpřed
Kontext
Neexistuje žádná samoaktualizace. Pro upgrade člověk na každém stroji znovu spustí install.sh s --version (docs/DISTRIBUTION.md, „Self-update“). Milník safe-self-update nechal ústřední otázku záměrně otevřenou: „Zda je kontrola aktualizací na pozadí žádoucí, je rozhodnutí vlastníka zaznamenané jako ADR před jakýmkoli kódem; tento milník ji nepředpokládá.“
Vlastník rozhodl 2026-10-14. Slova, jak byla napsána relacím:
- „do vseho se pust max efektivne a deploy asap, bump version, tak abychom to zacali automaticky vsichni v majordomus mesh pouzivat, critical“ (pusť se do všeho co nejefektivněji a nasaď co nejdřív, zvedni verzi, ať to všichni v majordomus meshi začneme automaticky používat; kritické).
- "safe-self-update rozhodni co je treba, zapis, popis, adr, docs, gh pages, deploy, start using asap, critical as well" (rozhodnout, co safe-self-update potřebuje, zapsat to, popsat: ADR, dokumentace, GitHub Pages, nasazení, začít to používat co nejdřív; také kriticky).
Co ukázal tentýž den:
| co se stalo 2026-10-14 | kolik to stálo |
|---|---|
| v0.25.0 dorazilo na pět uzlů mesh až poté, co jedna relace ručně upgradovala každý uzel a poslala archiv pro jetson přes LAN, protože jetson nemá cestu na github.com | asi hodina jedné relace plus uzel, který tiše zůstane pozadu, kdykoli to nikdo nezopakuje |
| sdílený server primárního checkoutu byl debug sestavení 0.21.0, zatímco nainstalované CLI bylo 0.25.0 | majordomus mesh status z CLI 0.25.0 odpovědělo „žádný běžící server pro tento checkout“, ačkoli ho nějaký server obsluhoval |
v0.26.0 byla publikována v 18:58Z a v 19:19Z ji releases/latest.json jmenoval | každý uzel stále běžel na 0.25.0, protože ukazatel nečte nic kromě člověka |
Co už existuje a je typované: cesta důvěry od share/distribution.yaml k releases/latest.json, instalátor, který před rozbalením ověří digest a velikost a launcher vymění atomickým přejmenováním, jeden verzovaný strom na každý release pod ~/.local/share/majordomus/versions/<version>/, Releases::latest_stable() a kontrola leasu, že server, jehož vlastní spustitelný soubor byl nahrazen, obsluhuje kód, který už neexistuje (lease::serving_replaced_code). Chybí čtečka ukazatele, uspořádané předání mezi servery různých verzí (I2163, které závisí na I2127) a původ nad rámec kontrolního součtu (I2165).
Rozhodnutí
Uzel meshe sleduje publikovaný stabilní release sám. Každý stroj, který deklarace meshe zapisuje, včetně hubů, drží svůj nainstalovaný Majordomus na verzi, kterou jmenuje releases/latest.json, bez člověka na tom stroji. Sledování se deklaruje na uzel v deklaraci meshe (follow: stable, follow: pinned <version> nebo follow: off). Zapsaný uzel meshe vlastníka má výchozí hodnotu stable. Repozitáře, který Majordomus přijme bez zapsání strojů do tohoto meshe, se to netýká: při vstupu do repozitáře nic nic nestahuje.
Rozhodnutí se čte z důvěryhodné cesty, nikdy od peera. Uzel se povýší jen na verzi, kterou pojmenovává releases/latest.json, a jen na archiv, jehož digest a velikost odpovídají releases/<tag>.json. Událost meshe, která ohlašuje release, znamená jen „zkontroluj teď“. Nikdy nenese binárku ani digest, kterým by uzel důvěřoval. Uzel bez cesty k webu, například jetson, může archiv převzít od peera. Kopie od peera se přesto ověřuje proti metadatům, která si uzel přečetl sám, nebo proti metadatům předaným přes autentizovaný mesh link a podepsaným publikujícím uzlem, jakmile bude I2165 přistáno.
Riskantní část má jednu implementaci. majordomus self update znovu spustí publikovaný instalátor s --version <tag> a vlastním prefixem uzlu. Stažení, ověření ani výměnu v Rustu znovu neimplementuje. To odpovídá na otázku, kterou docs/DISTRIBUTION.md nechal otevřenou: jeden instalátor, testovaný případem 85, a příkaz je typovaná schopnost kolem něj (--check hlásí, --apply instaluje).
Jen dopředu, jen stabilní. Uzel se nikdy nepřesune na verzi nižší, než na jaké běží, nikdy na pre-release a nikdy na verzi, kterou metadata neuvádějí. Připnutý uzel zůstává připnutý. Návrat je akt operátora přes install.sh --version, nikdy automatický, s jedinou výjimkou: rollback po selhané aktivaci, níže.
Nainstalovat vedle, aktivovat v pořadí, ponechat předchozí verzi. Nový release se nainstaluje do vlastního verzovaného stromu, zatímco starý server dál obsluhuje. Aktivace následuje předání, které milník vyžaduje:
- Hub běží pod svým správcem služeb (uživatelská jednotka systemd, agent launchd) a je restartován na nový launcher, když není připojena žádná relace, nebo po omezené době odkladu.
- Sdílený server checkoutu, který vidí novější nainstalovaný spustitelný soubor, předá své relace dál a skončí (I2127, I2163). Dokud ty nepřistanou, nahradí se při dalším nečinném konci nebo restartu a
serve statusjmenuje verzi, o kterou je pozadu.
Předchozí verzovaný strom se drží, dokud nová verze neprojde kontrolou zdraví.
Neúspěšná aktivace se sama vrátí a řekne to. Kontrolou stavu je to, že server odpoví na svou trasu readiness a mesh verify projde živým kolem. Pokud selže v rámci lhůty, launcher se přejmenuje zpět na předchozí verzi, uzel dál servíruje předchozí verzi a nástěnka nese položku rollout failed jmenující verzi, uzel a kontrolu, která selhala. Verze, která selhala na jednom uzlu, se na tom uzlu nezkouší znovu, dokud není publikována novější.
Mesh ukazuje nasazení. Každý runtime hlásí svou verzi v tom, co publikuje do meshe. majordomus mesh peers ji vypíše a mesh doctor pojmenuje uzel, který je o více než jeden release za stabilním ukazatelem. Release je nasazen, když ho hlásí každý zapsaný, sledující uzel.
Kdy kontroluje. Při startu serveru, každých 15 minut s jitterem a když mesh oznámí release. Kontrola je jeden požadavek HTTPS na releases/latest.json. Nikdy neblokuje požadavek, na který server odpovídá.
Zamítnuté alternativy
Znovu implementovat stažení, ověření a výměnu v Rustu. Pak nejrizikovější kód produktu existuje dvakrát a pouze jedna kopie je testována případem instalátoru. Instalátor už dělá všechny tři. Příkaz ho obaluje.
Nechat peera pushnout binárku nebo digest do meshe. Pak jeden kompromitovaný nebo zmatený uzel může nainstalovat kód na každý další. Mesh říká jen „zkontroluj“. To, co uzel instaluje, určují metadata, která umí ověřit.
Upgrade při vstupu do repozitáře, nebo při dalším příkazu, který člověk spustí. Milník vylučuje stahování ze sítě při vstupu do repozitáře. Příkaz člověka by neměl čekat na stahování a stroj bez člověka, například hub, by se nikdy neaktualizoval.
Dál upgradovat ručně, rychleji. 2026-10-14 je důkaz proti tomu: mesh je přesně tak aktuální jako poslední relace, která si vzpomněla to udělat.
Sledovat každý release, včetně pre-release. Uzel meshe vlastníka je infrastruktura, na které závisejí další relace. Pre-release vyzkouší člověk, který si ho zvolil, pomocí --version.
Důsledky
- Milník
safe-self-updatepřestává být podmíněný: jeho požadovaný stav nyní zahrnuje uzel, který sleduje release, a je povýšen na p0. Jeho nové úkoly jsou I2720 (self updateobaluje instalátor), I2721 (uzel sleduje stabilní ukazatel), I2722 (hub aktivuje novou verzi pod svým správcem služeb, s kontrolou zdraví a rollbackem), I2723 (mesh ukazuje verzi každého uzlu a rollout) a I2724 (archiv předaný peerem pro uzel bez cesty k webu). I2163 a I2127 zůstávají p1 a jsou nyní na kritické cestě pro servery checkoutů. I2165 je povýšeno z p3 na p1, protože automatické sledování zvyšuje cenu špatného archivu. - Dokud nepřistanou I2721 a I2722, platí praxe, kterou nařídil vlastník: relace, která drží roli release, upgraduje každý zapsaný uzel, jakmile
releases/latest.jsonjmenuje novou verzi, ověří hlášenou verzi každého uzlu a řekne to na nástěnce. docs/DISTRIBUTION.md(„Self-update“) adocs/MESH.md(„The hubs as services“) uvádějí toto rozhodnutí. Web je nese jako projekci těchto dokumentů.- Změna schématu drátu, leasu nebo žurnálu nyní dosáhne každého uzlu do jednoho intervalu kontroly po release. To dělá z milníkového „změna schématu drátu, leasu nebo žurnálu bez zvýšení verze selže ve version-surface“ předpoklad, ne vymoženost.
- Toto rozhodnutí je
proposed. Vlastník je nařídil slovy citovanými výše a přijetí textu je aktem vlastníka. Pokud je vlastník zamítne, uzly se vrátí k ručnímu povyšování a úkoly výše se s ním zruší.