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.

Předávka putuje mezi stroji jako podepsaný záznam ve vlastním refu a navazuje se jen podle plánu

Předávka putuje mezi stroji jako podepsaný záznam ve vlastním refu a navazuje se jen podle plánu

majordomus://adr/adr-0105navrženo architekturacontinuityhandoverzařízeníbezpečnost

odkazuje na

  • put_in_force apps/majordomus-cli/src/continuity/lineage.rs (soubor)
  • put_in_force apps/majordomus-cli/src/continuity/mod.rs (soubor)
  • put_in_force apps/majordomus-cli/src/continuity/record.rs (soubor)
  • put_in_force apps/majordomus-cli/src/continuity/store.rs (soubor)
  • put_in_force adr-0014
  • put_in_force adr-0067
  • put_in_force docs/CONTINUITY.md (dokument)
  • put_in_force project.session-continuity-is-portable@1
  • put_in_force test/cases/821_a_session_moves_between_machines.sh (test)

odkazuje na něj

Nic ve vrstvě to nejmenuje. Zpětné odkazy se odvozují, takže prázdný seznam je odpověď, ne opomenutí.

Kontext

Člověk přeruší práci na jednom stroji a pokračuje na jiném — notebook večer, desktop ráno. Všechno, co by druhému stroji umožnilo pokračovat, aniž by člověk rekonstruoval práci z paměti, už existuje, na prvním stroji: předávka (# Objective, # Current State, # Next Action), úloha a její rozsah, rozhodnutí, která úloha zaznamenala. To vše je pod .ai/local/state/, které se nikdy necommituje, a vše pojmenovává ten stroj — absolutní cestu worktree, id repozitáře, které je cestou, pořadí v ledgeru.

Dva stávající mechanismy přesouvají jeho části a ani jeden případ nepokrývá:

  • Git přenáší zdroj a od ADR 0014 i obálku uzavřené relace. Nepřenáší předávku a odkazy obálky ukazují na lokální soubory, které druhý stroj nemá.
  • Mesh (ADR 0067) replikuje publikovanou předávku mezi runtimes — ale jen během živého synchronizačního kola mezi dvěma běžícími servery. Notebook, který spí, když se probudí stolní počítač, se s ním nikdy nepotká, ledaže jej přenese třetí, vždy zapnutý runtime; a předávka převzatá z mesh se zapíše jako working_tree: clean, ať byla jakákoli, bez úlohy, rozhodnutí a jakéhokoli původu.

A audit našel mezery, které zdědí jakýkoli transport: ze čtyř způsobů, jak kódová základna říká „který repozitář“, je jen ten z mesh — digest kořenových commitů — na dvou strojích stejný; nic nemaže ani neodmítá tajemství v předávce; nic nezaznamenává, na kterou předávku navazuje pozdější, takže dva stroje pokračující ve stejné práci nešlo rozeznat od dvou strojů dělajících různou práci.

Rozhodnutí

Přenosnou jednotkou je předávka, ne nový objekt. Publikovaná předávka (continuity::record::Record) je tělo předávky přesně tak, jak ho mesh nese (HandoverBody), vedle toho, co jiný stroj potřebuje, aby z ní mohl pokračovat: identita repozitáře (digest root-commitu meshe), zařízení (id a štítek klíče uzlu meshe), epizoda, zdrojový stav (větev, commit, čistý nebo špinavý, změněné cesty a otisk necommitnuté změny — nikdy ne její obsah), úloha (titul, rozsah, profil), rozhodnutí, která úloha zaznamenala, a záznam, v němž pokračuje. Neexistuje pole pro cestu na disku autora, proces, port ani socket. Slovník nezískává žádné podstatné jméno: je to předávka, publikovaná.

Identifikuje se obsahem a podepisuje ho zařízení. Id je digest kanonického JSON záznamu; podpis je klíč Ed25519 mesh zařízení nad vlastní doménou. Tentýž klíč je identita zařízení; důvěryhodný seznam mesh (.ai/repo/mesh/majordomus.yaml, trust.allow) je seznam zařízení tohoto repozitáře.

Odmítne se, neredaguje, když nese to, co nesmí cestovat. Před podpisem se zkontroluje každý řetězec: přihlašovací údaj známého tvaru (redaction.rs), hodnota jakékoli tajné proměnné prostředí publikujícího procesu, cesta domovského adresáře a — v polích, která drží cesty repozitáře — cokoli, co není relativní a uvnitř repozitáře. Odmítnutí jmenuje pole a nikdy neopakuje hodnotu. Odmítnutí místo redakce zachovává záznam takový, jaký napsal autor; co říká, rozhoduje autor.

Putuje v refs/majordomus/continuity, zapsané plumbingem. Jeden commit, jehož stromem je records/<id>.json. Vlastní ref místo souborů na větvi, z důvodů, které tento repozitář už zaplatil:

  • záznam se zapisuje pomocí hash-object/mktree/commit-tree/update-ref, takže se nepohne žádná větev, index ani pracovní strom, a špinavý strom se předá bez commitu k práci;
  • nenese jej žádný pull request, nevznikají na něm žádné konflikty merge a nezneplatňuje jej žádná odvozená projekce sledovaného stromu (sledovaný záznam by znovu zastaral data webu);
  • vidí ho každý worktree klonu, protože refy žijí ve společném adresáři;
  • kontrakt pre-push (finish --check) se ptá, zda smí být práce úlohy publikována; push, který přesouvá jen refs/majordomus/*, nenese žádnou práci, takže ho hook připustí, místo aby odmítl předávku právě pro úlohu, kterou předává.

Sloučení dvou úložišť je sjednocení jejich souborů: záznamy jsou neměnné a adresované obsahem, takže stejný název jsou stejné bajty, a název nesoucí jiné bajty se ohlásí a lokální kopie se ponechá. Obyčejné git push nebo pull ref nechá být; continuity sync ho posune, explicitně, přes běžný git remote. publish se nikdy nedotkne sítě, takže publikace offline uspěje a zůstane čekající, dokud sync nedosáhne vzdáleného repozitáře.

Pořadí je rodokmen, nikdy hodiny. Záznam jmenuje svého rodiče — záznam, který tento checkout naposledy publikoval nebo obnovil na téže branchi — a svou linii (id prvního záznamu). Dva záznamy jsou equal, newer, older, diverged (stejná linie, ani jeden nepochází z druhého: tatáž práce pokračovala dvakrát) nebo independent (různé linie: samostatná práce). published_at se zobrazuje a používá pro stáří; nerozhoduje o ničem. Samostatné linie na dvou strojích jsou běžné a jako takové se hlásí; rozešlá linie je konflikt, který člověk řeší jmenováním záznamu.

Každý záznam je přijat dříve, než ho cokoli přečte — při každém čtení, z obou úložišť: meze, schéma (pozdější verze je too_new, ponechána v úložišti a hlášena jako upgrade), id proti obsahu a názvu souboru, podpis proti klíči zařízení, identita repozitáře (fork sdílí jméno, ale ne kořenovou historii a je odmítnut), přenositelnost. Co přijetí odmítne z důvodu, který žádný pozdější spustitelný soubor neotočí — podvrh, cizí, úniky — zůstane mimo strom, který synchronizace slučuje.

Obnovení jedná jen podle plánu. continuity plan nic nezapisuje a rozhoduje: je podepisující důvěryhodný (nedůvěryhodný je odmítnut; bez deklarovaného seznamu důvěry je to varování), liší se záznam od toho, na kterém tento checkout stojí, drží lokální zdroj svůj commit a větev (head_missing, local_behind, branch_differs vyžadují aktualizaci zdroje; zdroj diverged je konflikt; nic zde nespouští git), byl zapsán v nečistém stromu (source_incomplete: kontext je obnoven a o zdroji se říká, že ne), může druhé zařízení ještě pracovat (doporučení: nic nezamyká). continuity resume pokračuje jen při ready nebo ready_with_warnings: zapíše předávku do předávek tohoto checkoutu přes zapisovač, který používá mesh — kde ji najdou handover --resolve a briefing relace —, připojí rozhodnutí úlohy do protokolu rozhodnutí jednou každé a stojí na záznamu. Příkazy, které plán uvádí, jsou doporučení; nic, co záznam říká, se nespouští.

Vstupní banner čte cache. sync, publish a resume nechávají obnovitelné předávky v .ai/local/state/continuity.json; kontrola session.continuity preflightu čte tento soubor a nic jiného, takže vstup do adresáře nestojí žádné volání gitu ani sítě.

Zamítnuté alternativy

Samotný git — předávka jako sledovaný soubor na větvi. Uprostřed úlohy pre-push kontrakt push odmítne; špinavý strom potřebuje commit záznamu, že práce není připravena; každý záznam se objeví v pull requestu a znovu zastarává odvozená data webu. Sledovaná obálka z ADR 0014 zůstává; zaznamenává epizodu, nikoli pokračování.

Samotný mesh. Vyžaduje, aby oba stroje, nebo stále zapnutý relay, byly online současně, a nenese žádnou linii, žádný stav zdroje ani žádnou úlohu. Mesh zůstává živým transportem mezi běžícími servery; tento ref je asynchronní. Oba nesou stejné HandoverBody a přijatou předávku zapisují stejným zapisovačem.

Sdílená databáze nebo hostovaná služba stavu. Server, který by se musel provozovat pro každý repozitář, a druhý záznam stavu, který git už drží.

CRDT nebo konsenzus. Záznamy jsou neměnné, takže množina pouze s růstem je na úrovni úložiště už bez konfliktů; jediný konflikt, na kterém záleží — táž práce pokračovaná dvakrát — je sémantický, řeší jej člověk a žádná funkce merge jej za něj vyřešit nemůže.

Volit nejnovější záznam podle časového razítka. Dvoje hodiny na dvou strojích; a „nejnovější“ by tiše zahodilo pokračování druhého stroje.

Redaktovat tajemství místo odmítnutí. Redaktovaná předávka je jiná předávka než ta, kterou napsal její autor, a redakce je pro osobu, která ji obnovuje, neviditelná.

Důsledky

  • Člověk spouští majordomus handover, majordomus-cli continuity publish a continuity sync na jednom stroji a continuity sync, plan a resume na druhém. Koncový hook poskytovatele už předávku zapisuje; její automatická publikace je ponechána pozdějšímu rozhodnutí, místo aby se přidávala ke konci každé relace.
  • Klíč každého zařízení musí být na seznamu důvěry repozitáře, aby jeho handovery mohly být obnoveny tam, kde je seznam deklarován — na stejném seznamu, který používá mesh. continuity device --label jmenuje zařízení; klíč, a tedy identita, se nikdy nemění.
  • Ref kontinuity se pushuje na jakýkoli synchronizovaný remote. Ve veřejném repozitáři jsou jeho záznamy veřejné, stejně jako sledované obálky relací: těla předávek jsou próza o práci a odmítnou se, pokud nesou tajemství nebo cestu stroje. Kde to nelze přijmout, synchronizujte se soukromým remotem (--remote).
  • Retence je věcí gitu: záznamy jsou malé a neměnné a nic je nepročišťuje. Politika pročišťování, pokud by byla kdy potřeba, musí zachovat každý záznam, od kterého řádek stále pochází.
  • Necommitnutý zdroj nikdy necestuje. Předávka ze špinavého stromu říká, které cesty a kolik; přenos samotné práce je úkol gitu a plán to říká.

Ověření

test/cases/821_a_session_moves_between_machines.sh je běh dvou strojů od začátku do konce; 822 (špinavý strom a kompatibilita zdrojů), 823 (divergence), 824 (nezávislé relace), 825 (offline), 826 (tajemství a cesty strojů), 827 (manipulace, schéma, fork, nedůvěryhodný podepisovatel). Moduly záznamu, původu, úložiště a lokální nesou unit testy každé kontroly.

Dodatek, 2026-10-15: smlouva pre-push posuzuje větve, které se pushují (I1990)

Hook už čte refy, které git předává na standardním vstupu, ale jen proto, aby pustil push, který nehýbe ničím kromě refs/majordomus/*. Jakýkoli jiný push se ptal finish --check na vlastní úlohu checkoutu, takže push větve X z checkoutu, jehož úloha je na větvi Y, selhal s different_context. OSCILLA kvůli tomu pushovala feature větve z hlavního checkoutu.

Každý pushnutý refs/heads/<b> se posuzuje podle úlohy checkoutu, který má <b> checkoutnutý, což je jeho kanonický worktree; úloha aktuálního checkoutu se ptá jen na jeho vlastní větev. Pushnutá větev, kterou nedrží žádný checkout nebo jejíž checkout nemá aktivní úlohu, se posuzuje jako push bez úlohy dnes: připuštěna, s jedním řádkem, který ji jmenuje. refs/majordomus/* zůstává osvobozen a smazaná ref (lokální sha samé nuly) se přeskočí. Vazba úlohy na její větev zůstává jako dřív; rozhoduje se zde jen o tom, které refy hook zkoumá.

Zamítnuto: posuzovat úlohu vlastního checkoutu při každém pushi (nutí to pushovat z nesprávného checkoutu) a neposuzovat nic při pushi jiných větví (zahazuje to kontrakt rozsahu větve, jejíž vlastní worktree má úlohu).

Práce jsou dva kusy, každý jeden pull request:

  1. finish --check bere refy. lib/finish.sh přijímá pushnuté refy, vyřeší worktree držící každou větev (git worktree list --porcelain) a ptá se úlohy onoho worktree; .githooks/pre-push předává refy, které přečetl. Případ prepush_refs_case: z checkoutu Y (úloha na Y) pushněte větev X, jejíž úloha ve worktree je mimo rozsah, a push je odmítnut s jménem X; s X v rozsahu je přijat; úloha Y se neptá.
  2. Adoptéři dostanou stejný hook. Hook nainstalovaný initem v share/skeleton a řádky hooku v docs/CLI.md nesou totéž chování a případ běží proti nainstalovanému hooku.

Odkud to pochází

kanonický soubor
.ai/repo/adrs/0105-a-handover-moves-between-machines-as-a-signed-record-in-a-ref-of-its-own.md
identity
adr-0105
dostupné také jako
Zdroj MCP majordomus://adr/adr-0105 · majordomus entity show adr/adr-0105 · GET /api/v1/entity?uri=majordomus://adr/adr-0105
v Cockpitu
/cockpit/objects/adr/adr-0105

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.