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.

majordomus recover

Uzavřete epizody, které nikdo neukončil, sloučte duplicitní záznamy a roztřiďte zatoulané soubory úložišť.

Uzavřete epizody, které nikdo neukončil, sloučte duplicitní záznamy a roztřiďte zatoulané soubory úložišť.

  • mění stav
  • systém

Opakovaná údržba, na rozdíl od migrate, což je jednorázový přesun z rozvržení před .ai. Každý subjekt je idempotentní a každý má --check, který nic nezapisuje. Nic se nemaže jen proto, že je to neznámé — kandidát, jehož důkazy nelze přečíst, se ohlásí, spočítá a nechá být.

Syntaxe

majordomus recover [status|episodes|records|orphans|all] [--check] [--older-than <duration>]

Životní cyklus

  1. Nastavit
  2. Začít
  3. Pracovat
  4. Ověřit
  5. Uzavřít
  6. Prozkoumat

Další příkazy v této fázi:init, update, migrate.

Čte

  • .ai/repo/policy.yaml
  • .ai/local/state/sessions-open/
  • .ai/local/state/ledger.jsonl
  • .ai/repo/sessions/
  • .ai/local/state/checkpoints/
  • .ai/local/state/handovers/

Zapisuje

  • .ai/repo/sessions/
  • .ai/local/state/sessions-open/
  • .ai/local/state/ledger.jsonl

Návratové kódy

Jen kódy, které tento příkaz může vrátit. Úplný kontrakt je na indexu příkazů.

  • 0 ok
  • 2 použití
  • 10 kontrakt nesplněn
  • 12 chybějící artefakt

Epizodu uzavírají důkazy, nebo nikdo

Poskytovatel, který je zabit, neposílá závěrečnou událost a epizoda, kterou otevřel, zůstane otevřená navždy. Obnova ji uzavře — ale jen když důkazy říkají, že její klient je pryč, a nikdy hádáním. Každý subjekt má --check, který nic nezapisuje, a měření, které rozhodlo o každém verdiktu, se vypíše dřív, než se s ním cokoli udělá.

Plán a měření za ním

jedna epizoda uvízlá a jedna živá
ano

Pro tento repozitář platí

# Installed, with two episodes open: one whose client is gone and one that is live.
#
# Both halves of the stranded episode's trail are aged, not only its open record. The last
# sign of life is the later of started_at and the newest ledger line the episode stamped, so
# an episode whose ledger is fresh is young however old its file claims to be — a fixture
# that moved one half would demonstrate the command passing for the wrong reason.
. "$FIXTURE_SETUP/installed.sh"
"$MJ" session start --provider-session gone-client >/dev/null
"$MJ" session start --provider-session this-client >/dev/null
_S=.ai/local/state
_dead="$(sed -n 's/^session_id: //p' "$_S/sessions-open/gone-client.yaml" | head -n 1)"
sed -i.bak 's/^started_at: .*/started_at: 2020-01-01T00:00:00Z/' "$_S/sessions-open/gone-client.yaml"
rm -f "$_S/sessions-open/gone-client.yaml.bak"
awk -v s="$_dead" '{ if (index($0, "\"session\":\"" s "\"") > 0) sub(/"ts":"[^"]*"/, "\"ts\":\"2020-01-01T00:00:00Z\""); print }' \
  "$_S/ledger.jsonl" > "$_S/ledger.mj-tmp" && mv "$_S/ledger.mj-tmp" "$_S/ledger.jsonl"

Spustit

$ majordomus recover episodes --check

Výstup obsahuje

  • naposledy viděno 2020-01-01T00:00:00Z
  • stranded:
  • živé: tento proces je uvnitř
  • check: 1 akce

ukončení 0

Poslední známka života každého kandidáta se vypíše, včetně těch, se kterými se nic nestane, takže chybný predikát je vidět ve výstupu, ne až v jeho důsledcích. Dry run nezapíše vůbec nic.

Uzavření té, jejíž klient zmizel

jedna epizoda uvízlá a jedna živá
ano

Pro tento repozitář platí

# Installed, with two episodes open: one whose client is gone and one that is live.
#
# Both halves of the stranded episode's trail are aged, not only its open record. The last
# sign of life is the later of started_at and the newest ledger line the episode stamped, so
# an episode whose ledger is fresh is young however old its file claims to be — a fixture
# that moved one half would demonstrate the command passing for the wrong reason.
. "$FIXTURE_SETUP/installed.sh"
"$MJ" session start --provider-session gone-client >/dev/null
"$MJ" session start --provider-session this-client >/dev/null
_S=.ai/local/state
_dead="$(sed -n 's/^session_id: //p' "$_S/sessions-open/gone-client.yaml" | head -n 1)"
sed -i.bak 's/^started_at: .*/started_at: 2020-01-01T00:00:00Z/' "$_S/sessions-open/gone-client.yaml"
rm -f "$_S/sessions-open/gone-client.yaml.bak"
awk -v s="$_dead" '{ if (index($0, "\"session\":\"" s "\"") > 0) sub(/"ts":"[^"]*"/, "\"ts\":\"2020-01-01T00:00:00Z\""); print }' \
  "$_S/ledger.jsonl" > "$_S/ledger.mj-tmp" && mv "$_S/ledger.mj-tmp" "$_S/ledger.jsonl"

Spustit

$ majordomus recover episodes

Výstup obsahuje

  • .ai/repo/sessions/
  • obnoveno: 1 akce

ukončení 0

Záznam nese to, co dokazují otevřený záznam a vlastní řádky ledgeru epizody. Jeho commits a changed_files jsou explicitní prázdný seznam a neuvádí žádný head: pracovní strom v době obnovy patří tomu, kdo právě pracuje, a otisknout ho na epizodu, která skončila před dny, by byl záznam vypadající přesně jako pravdivý.

Bez jakékoli degradace

jedna epizoda uvízlá a jedna živá
ne

Pro tento repozitář platí

# A repository with Majordomus installed and projections generated, and one commit of work.
"$MJ" init >/dev/null
"$MJ" update >/dev/null
mkdir -p lib docs
echo a > lib/a
echo d > docs/d
git add . && git commit -qm base

Spustit

$ majordomus recover

Výstup obsahuje

  • není co obnovovat

ukončení 0

Nepřítomnost je odpověď. Čisté úložiště skončí s 0 a řekne to, místo aby nemít co dělat bralo jako selhání.

Předmět, který tento příkaz nemá

jedna epizoda uvízlá a jedna živá
ne

Pro tento repozitář platí

# A repository with Majordomus installed and projections generated, and one commit of work.
"$MJ" init >/dev/null
"$MJ" update >/dev/null
mkdir -p lib docs
echo a > lib/a
echo d > docs/d
git add . && git commit -qm base

Spustit

$ majordomus recover everything

Výstup obsahuje

  • neznámý subjekt

ukončení 2

Chybně napsaný předmět je odmítnut, ne složen do výchozího. Příkaz obnovy, který by tiše udělal něco jiného, než bylo požádáno, je ten, který nesmí existovat.

Reference

Vrátit úložiště záznamů tohoto checkoutu do stavu, který popisuje kontrakt: zavřít epizody, které nikdo neukončil, sloučit duplicitní záznamy jedné epizody do jednoho a roztřídit zbloudilé soubory, které se v úložištích hromadí. Opakovaná, idempotentní údržba — na rozdíl od migrate, což je jednorázový přesun z rozvržení před .ai, který odmítne běžet dvakrát.

Subjekty: status (výchozí, pouze čtení), episodes, records, orphans, all.

Čte: .ai/local/state/sessions-open/, .ai/local/state/ledger.jsonl, úložiště uzavřených záznamů a úložiště checkpointů a předávek. Zapisuje: uzavřený záznam pro každou obnovenou epizodu pod .ai/repo/sessions/, sloučený záznam tam, kde existovaly duplicity, řádek knihy session.recovered pro každou akci a odstraňuje otevřené záznamy a zatoulané dočasné soubory, na kterých zasáhl.

Behaviour:

  • --check vypíše plán a důkazy za ním a nic nezapíše. Totéž měření řídí skutečný běh, takže plán je akce.
  • Zbloudilý soubor se posuzuje podle stáří dřív než podle obsahu: dočasný soubor publikace starý vteřiny patří session close, které právě běží, a .mj-stage.XXXXXX staré minuty scripts/derive, které právě běží. Obojí se hlásí jako live a ani jedno se nedotkne; soubor, jehož stáří nelze přečíst, se přeskočí a započítá.
  • Zastaralý staging adresář se hlásí a nikdy neodstraňuje. Tento příkaz nemaže žádný strom adresářů — SECURITY.md uvádí „žádné rekurzivní mazání“ — takže .mj-stage.XXXXXX za prahem se jmenuje, počítá se jako přeskočený a nechá se člověku k odstranění.
  • Epizoda je uvízlá, když je její poslední známka života — pozdější z jejího vlastního started_at a nejnovějšího řádku knihy, který označila — starší než session.stranded_after. --older-than <duration> pro jeden běh přepíše politiku.
  • Mezi živou epizodou a úklidem stojí dvě pojistky a ani jedna není zálohou té druhé. Epizoda, na kterou se tento proces překládá, je vyloučena dříve, než se spustí jakýkoli predikát; a kandidát, jehož důkaz nelze přečíst jako časové razítko, se přeskočí a započítá, nikdy se nepovažuje za nejstarší v množině (project.destructive-sweeps-fail-closed). Epizoda patřící jinému worktree se ohlásí a tady se nikdy nezavře.
  • Obnovený záznam nese to, co dokazují otevřený záznam a vlastní řádky knihy epizody. commits a changed_files jsou explicitní prázdný seznam a head a working_tree chybí: popisují uzavření, které se nikdy nestalo, a pracovní strom v okamžiku obnovy patří tomu, kdo právě pracuje. outcome je interrupted, čím také bylo.
  • Duplicitní záznamy se sloučí do nejstaršího podle created_at s sjednocením seznamů, které ostatní dokládají, a názvy nahrazených souborů se zapíší do těla přeživšího. Záznamy, které se neshodují v identitě nebo časech epizody, se ohlásí a nic se neslučuje.
  • Nic se nemaže jen proto, že to nebylo rozpoznáno. Dočasný soubor publikace po prahu, který drží jedinou kopii záznamu, se publikuje; ten, jehož epizoda je už publikována, nebo prázdný, se odstraní; ten, který drží obsah, jejž tato verze neumí klasifikovat, zůstane přesně tam, kde je, a započítá se. Adresář, který někdo vložil do úložiště kontrolních bodů, se pojmenuje, změří a ponechá.
  • Idempotentní. Dvojí spuštění nad jedním předmětem provede jeho akce jednou a spuštění po pádu uprostřed běhu provede ty, které se nestaly: záznam se zapíše dřív, než se odstraní otevřený soubor, takže přerušení mezi nimi nic nestojí.
$ majordomus recover episodes --check
episodes — open episodes in .ai/local/state/sessions-open
  s-20260910194205-72ea  key=187c9e1e-…  last seen 2026-09-10T19:42:05Z (ledger, 13h ago)
    stranded: 13h ago, over the 12h threshold; close with outcome interrupted
  s-20260911063532-b41b  key=c93d195f-…  last seen 2026-09-11T08:31:02Z (ledger, 0m ago)
    live: this process is inside it; never a candidate

check: 1 action(s) would be taken and nothing was written (run: majordomus recover all)

Důkazy

Každý případ níže běží v CI na Linuxu i macOS. Web se odmítne sestavit, pokud veřejný příkaz nemá behaviorální případ, negativní případ nebo ukázku.

Způsoby selhání

Ukázka

Testuje test/cases/34_command_fixtures.sh, který přehraje fixture a porovná ji s tím, co příkaz vypíše.

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