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.

Životní cyklus relace patří epizodě, ne úloze

Životní cyklus relace patří epizodě, ne úloze

majordomus://adr/adr-0052navrženo relacecontinuitygovernancearchitektura

odkazuje na

odkazuje na něj

41. Životní cyklus relace patří epizodě, ne úloze

Kontext

Dne 2026-09-11 forenzní audit subsystému kontinuity zjistil, že tento repozitář od 2026-09-05 — šest dní — nezapsal žádný checkpoint ani předávku, zatímco doctor a watch celou dobu hlásily zdraví. Epizody se po celou dobu normálně otevíraly a zavíraly; session.started a session.closed dál přicházely do ledgeru. Zastavily se jen dva záznamy, z nichž budoucí worker skutečně pokračuje.

Příčinou je jeden řádek politiky vyjádřený v kódu třikrát. Úloha t-20260905034523-a9f1 byla 2026-09-05 označena outcome: handed_over a nikdy nebyla nahrazena. Od té chvíle:

  • lib/checkpoint.sh odmítal každý kontrolní bod, protože kontrolní bod byl definován jako poznámka o postupu uvnitř aktivní úlohy;
  • Kompaktní adaptér lib/capture.sh přeskočil odvozený checkpoint, protože se nejprve ptal, zda je úloha aktivní;
  • Koncový adaptér lib/capture.sh přeskočil odvozený záznam pokračování ze stejného důvodu.

Každé odmítnutí bylo správné vůči své vlastní smlouvě, zapsalo na stderr a vrátilo 0 — což provider hook musí. Žádné z nich nevytvořilo záznam, že k odmítnutí došlo, takže nic dál po proudu nevidělo, že zapisovatel přestal. Briefing mezitím dál rozlišoval nejnovější předávku na větvi a doslovně citoval její Next Action do každé nové epizody, se štítkem advanced, který říká, že zaznamenaný commit je předkem HEAD. advanced je pravdivé tvrzení o topologii a nic neříká o stáří. Šest dní pracovníkům říkal, aby pokračovali v práci, která byla šest dní hotová.

Tři oddělené vady sdílejí jeden předpoklad: že epizoda je něco, co se děje uvnitř úlohy. Není. Úloha je jednotka zamýšlené práce, kterou člověk otevírá a zavírá. Epizoda je hranice konverzace poskytovatele — začíná, když se klient připojí, a končí, když se odpojí, ať někdo deklaroval úlohu, nebo ne, a ať poslední úloha, kterou někdo deklaroval, skončila před týdnem. Učinit druhé závislým na prvním znamená, že běžný akt dokončení úlohy tiše vypne kontinuitu pro každou epizodu po ní a systém je o tom nejhlasitější přesně tehdy, když se nikdo nedívá.

Čtvrtá vada plyne ze stejného předpokladu z druhé strany. Protože zápisy vlastní shellový nástroj a typovaný čtecí model vlastní apps/majordomus-cli — continuity.rs tím začíná: „Čte se, nikdy se nezapisuje. Životní cyklus patří shellovému nástroji“ — neexistuje jediné místo, které by si toho mohlo všimnout. Čtečka věrně hlásila nejnovější záznam, který našla. Zapisovatel věrně odmítl nějaký zapsat. Nikdo z nich nemá pravdu; dohromady jsou systémem, který nepozná vlastní mlčení, protože invariant, který by to zachytil („události životního cyklu přicházejí, proto se musí posouvat odvozený stav“), zasahuje obě poloviny a nevlastní ho ani jedna.

Rozhodnutí

Životní cyklus epizody nezávisí na stavu úlohy. Checkpoint a předávka jsou artefakty epizody. Úloha je volitelná relace, kterou epizoda může nést a která obohacuje obsah těchto artefaktů. Výsledek úlohy může změnit, co záznam pokračování říká; nikdy nesmí rozhodnout, zda se zapíše. Každá ochrana tvaru outcome != active -> skip se z cesty životního cyklu odstraňuje.

Každá přijatá událost životního cyklu se zaznamená dříve, než poběží jakákoli ochrana. Každý adaptér poskytovatele připojí do ledgeru typovaný doklad jako svůj první čin — provider.session_start.received, provider.pre_compact.received, provider.session_end.received — a typovanou událost selhání, pokud následující práce nedoběhne. Hook může poskytovateli stále vrátit úspěch, protože blokování práce člověka je horší selhání; nesmí zanechat repozitář bez důkazu, že událost dorazila. Neblokuj poskytovatele a předstírej, že uspěl jsou různé pokyny a jen první je kontrakt.

Čerstvost je samostatná dimenze vedle divergence. exact | advanced | diverged | different_context je výrok o topologii gitu a zůstává beze změny. Vedle něj je fresh | aging | stale | unknown | invalid výrok o stáří, rozhodovaný proti prahům deklarovaným jednou v .ai/repo/policy.yaml pod session.freshness a čteným každou plochou. Záznam může být advanced a stale zároveň a právě tato kombinace způsobila tento výpadek.

Zastaralý záznam je historie, nikdy aktuální. Briefing smí ukázat zastaralý záznam pokračování — vědět, co dělal poslední worker, je užitečné —, ale je označen jako historický, uvádí se jeho stáří a důvod zastarání a jeho Next Action není citován jako to, co dělat nyní. Nekvalifikovaná instrukce, která byla před šesti dny správná, je horší než žádná, protože worker nepozná, že je špatná, dokud podle ní nejedná.

Health měří zapsanost, ne jen dosažitelnost. doctor a watch získávají invarianty tvaru pokud přicházejí události životního cyklu, odvozený stav, který vytvářejí, musí postoupit: checkpoint nebo předávka starší než politika, zatímco se dál otevírají epizody, je zjištění, počet session.started převyšující session.closed o víc než skutečně otevřené epizody je zjištění a příjemka bez výsledné události je zjištění. „Úložiště je dosažitelné“ není tvrzení, že se do něj cokoli zapisuje.

Kanonický směr je jedna doménová služba ve spustitelném souboru Rust. Dvojí autorita popsaná výše — shell vlastní zápisy a životní cyklus, Rust vlastní typovaný čtecí model, server, API, MCP a Cockpit — je strukturální důvod, proč tato třída vad existuje, a je tím, co se má odstranit. Cílem je jediná kanonická doménová služba relace/kontinuity v apps/majordomus-cli, která vlastní typovaný stavový automat životního cyklu, identitu, události, aktuálnost, persistenci, obnovu a projekci; .envrc, shimy hooků providerů, CLI, MCP, HTTP a Cockpit se všechny stanou adaptéry a projekcemi nad ní a shell nedrží žádný doménový stavový automat, parser schémat, resolver kontinuity, engine aktuálnosti ani engine obnovy. Tím se nahrazuje kontrakt continuity.rs jen pro čtení. Nezavádí druhé úložiště: append-only kniha a stávající adresáře záznamů zůstávají podkladem a jejich cesta zápisu se přesouvá pod službu, místo aby se duplikovala vedle ní.

Tato migrace je rozdělena do fází, protože shellová cesta má čtyři tisíce řádků a jiní workeři ji aktivně mění. Toto rozhodnutí opravuje třídu výpadku na místě a určuje směr; přechod je vlastní prací a .ai/local/ zůstává po celou dobu lokální a gitignorovaný, přičemž .ai/repo/sessions/ zůstává jediným sledovaným nositelem trvalé kontinuity.

Důsledky

Kontrolní bod zapsaný mimo úlohu zaznamenává task: none a je normálním záznamem, ne odmítnutím. majordomus checkpoint už neselhává, když není otevřena žádná úloha, což mění návratový kód příkazu, který některé skripty mohou volat; odmítnutí, které nahrazuje, bylo samo vadou. Předávky zapsané mimo úlohu byly s --no-task možné už dříve a adaptér konce nyní jde touto cestou místo toho, aby nezapsal nic.

Kniha získává události potvrzení, a proto roste rychleji. ledger.retention_max_lines ji už ohraničuje.

Prahy session.freshness jsou politika, takže jejich změna je rozhodnutí repozitáře s jedním místem, kde se dělá, a žádný povrch nesmí nést druhou kopii čísel.

Briefing se při zastaralém záznamu prodlouží nejvýše o dva řádky a zkrátí se o délku Next Action, který už necituje — což je smysl.

Dodatek, 2026-09-20: potvrzení uvádí událost poskytovatele v poli, ne ve svém id

Rozhodnutí výše jmenuje tři události potvrzení — provider.session_start.received, provider.pre_compact.received, provider.session_end.received. Slovník nese místo toho jednu dvojici, provider.event.received a provider.event.failed, z nichž každá vyžaduje provider a provider_event. To je lepší tvar a tento záznam přespecifikoval.

SessionStart, SessionEnd a PreCompact jsou názvy událostí jednoho providera. Jsou deklarovány jako data, v share/providers.yaml pod claude-code.lifecycle, právě aby je nic v nástroji nevyjmenovávalo; project.providers-are-data z toho dělá blokující pravidlo. Tři id z nich postavená by zkompilovala slovník jednoho providera do ledgeru, do kterého píše každý provider, a další adaptér — Codex, Gemini, worker bez vlastní konvence — by měl buď potvrzení, jehož id jmenuje událost, kterou nemá, nebo čtvrté id, které nikdo neodvodí. Id říká, co se stalo tomuto repozitáři: dorazila událost životního cyklu providera. Která událost a od koho, jsou data, která nese řádek.

Důsledky, které z účtenek rozhodnutí vyvodilo, se nezměnily a platí dnes. Párování je to, co čte health: lib/doctor.sh počítá provider.event.received proti provider.event.failed a hlásí účtenku bez výsledného záznamu. Trojí rozlišení je k dispozici tam, kde ho čtenář potřebuje, a je ověřováno oběma směry — test/cases/130_lifecycle_survives_a_stale_task.sh vyžaduje účtenku nesoucí provider_event z start, compact a end postupně a test/cases/282_the_ledger_envelope_is_reserved.sh vyžaduje, aby dvojice deklarovala requires: [provider, provider_event]. Samotný název provider_event je druhá oprava: pole se do 2026-09-12 jmenovalo event, což kolidovalo s vlastním klíčem obálky záznamu, a mj_ledger_append nyní takovou kolizi odmítá rovnou.

Chyběla kontrola, která drží slovník nezávislý na poskytovateli, protože tvar, který tento dodatek stanoví, byl konvencí, již žádná kontrola nedržela. test/cases/408_a_receipt_is_provider_neutral.sh odmítne id události v share/events.yaml sestavené z jakékoli deklarované lifecycle události poskytovatele a vyžaduje, aby dvojice potvrzení dál nesla poskytovatele a jeho událost jako pole.

Odkud to pochází

kanonický soubor
.ai/repo/adrs/0052-the-session-lifecycle-is-the-episodes-not-the-tasks.md
identity
adr-0052
dostupné také jako
Zdroj MCP majordomus://adr/adr-0052 · majordomus entity show adr/adr-0052 · GET /api/v1/entity?uri=majordomus://adr/adr-0052
v Cockpitu
/cockpit/objects/adr/adr-0052

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.