97. Razítko plánu nese pečeť své události
Kontext
Stav úkolu se odvozuje z jeho záznamu: started_at, verified_at, completed_at a jeho položek důkazů. Přechod — plan::transition za schopností plan.transition (MCP majordomus_plan_transition, POST /api/v1/plan/transition) a mj_plan_transition za majordomus plan start|verify|done — je střeženou hranicí a po zapsání razítka připojí plan_start, plan_verify nebo plan_done do ledgeru.
Dne 2026-09-15 bylo změřeno, že hranice je nepovinná. ve fixture byly completed_at, started_at, verified_at a jedna položka důkazů ručně připojeny do YAML úkolu a commitnuty. majordomus plan show odvodil DONE, majordomus plan validate vypsal 0 failure(s) a skončil s 0 a ledger neobsahoval žádnou událost plan_*. Žádná kontrola neporovnávala razítka s událostmi. Zvlášť done neměl v žádném z enginů předpoklad na stav, takže úkol READY šlo dokončit, aniž by byl kdy zahájen, a shellový engine zapsal completed_at na úkol CANCELLED.
Samozřejmá kontrola — každé razítko má svou událost v knize — se nedá rozhodnout tam, kde na ní záleží. .ai/local/state/ledger.jsonl je v gitignore a patří jednomu checkoutu: klon, jiný worktree i každá úloha CI začínají bez ní. Vlastní plán repozitáře obsahuje 142 razítek a kniha primárního checkoutu 57 událostí plan_*, protože přechody běžely v mnoha worktree. Kontrola proti knize by byla v CI neznámá a lokálně nepravdivá.
Rozhodnutí
Přechod zapíše pečeť vedle každého razítka, ve stejném zápisu, a plán odmítne razítko bez ní. Pečeť je
sha256:<hex of "majordomus.plan-event/v1\n<event>\n<issue>\n<stamp>\n">
v started_event, verified_event nebo completed_event. Je to sledovaná polovina události: název události, úkol a okamžik, což je přesně to, co řádek ledgeru zaznamenává navíc oproti obálce checkoutu, v němž byl zapsán. Pravda je stále jedna — přechod — a dva záznamy o tom, co udělal, jeden lokální a úplný, druhý sledovaný a minimální, zapsané stejným voláním.
Obě odvození (lib/project.awk, plan.rs) berou razítko jako fakt, jen když jeho pečeť sedí. Nedokázané razítko nehýbe žádným stavem a je selháním FAIL stamp_without_event, které jmenuje úkol, razítko a událost. plan validate na ně končí s 10; scripts/ci/core-check spouští plan validate v každém plánu CI, takže kontrola se rozhoduje ze samotného stromu a nikdy není neznámá. Shellový motor hashuje každé razítko plánu jedním procesem sha256sum/shasum, takže kontrola stojí jeden fork na načtení, ne jeden na razítko.
done nyní vyžaduje ACTIVE nebo VERIFY v obou enginech, po kontrole závislostí a před kontrolou důkazů.
Razítka, která předcházejí pečetím, jsou pojmenována, ne zvýhodněna datem. unsealed_stamps v každém záznamu úkolu uvádí svá vlastní jako <field> <stamp> — v záznamu, protože index project.yaml neobjevuje a oba motory musí číst týž seznam. Položka omlouvá přesně tuto hodnotu a jen tehdy, když je starší než SEALED_FROM (2026-10-01T00:00:00Z, konstanta v obou motorech). Razítko zapsané v tomto okamžiku nebo po něm potřebuje svou pečeť, ať seznam říká cokoli, takže seznam se může zkracovat a nelze jím omlouvat novou práci.
Zamítnuté alternativy
- Porovnat s ledgerem. V CI neznámé a špatně v každém checkoutu, který neprovedl každý přechod. Zamítnuto měřením, výše.
- Sledovat ledger, nebo log plánovacích událostí vedle záznamů. Druhá sledovaná historie týchž událostí, s konflikty při merge u každého paralelního přechodu a novým zapisovatelem, který je třeba držet v synchronizaci. Pečeť žije v záznamu, který přechod už přepisuje.
- Vyjmout každé razítko starší než datum. Zpětně datované razítko by prošlo. Pojmenovaný seznam to uzavírá: zpětně datované razítko by muselo být ve stejném diffu přidáno i do seznamu, do kterého pravidlo přidávat zakazuje.
- Delegovat přechod v shellu na schopnost v Rustu v této změně. Schopnost řeší úkoly přes index, který vyčísluje jen sledované soubory, stojí asi dvě sekundy za volání a každé odmítnutí hlásí jako exit 10; devět behaviorálních případů pohání přechod v shellu nad nesledovanými fixture a tvrdí exity 12 a 15. To je samostatná změna. Dokud nepřistane, oba enginy nesou stejné ochrany a zapisují stejné bajty, což drží
test/cases/133_plan_transition.sha582_the_done_guard_holds_in_both_engines.sh.
Důsledky
- Ručně napsané razítko je vidět: selže
plan validatejménem a na žádném povrchu neukazuje žádný pokrok. - Pečeť je digest veřejných hodnot, ne podpis. Zfalšovat ji je možné a je to nyní záměrný čin, jehož výstupem je řádek diffu, který nezapsal žádný přechod; znemožnit to by vyžadovalo klíč, který repozitář nemá.
- Záznamy důkazů jsou stále volný text připojovaný
plan evidence; padělaný záznam důkazu může splnit guarddone. Zpečetění důkazů je další řez téhož zákona. - Větev, která označí úkol starším executable po
SEALED_FROM, neprojde validací, dokud se úkol znovu nepřesune aktuálním.