29. Changelog je projekce toho, co repozitář už zaznamenává, a verze má jednoho zapisovatele, ne jeden zdroj
Změněno ADR 0051 (navrženo), 2026-09-12. Čtvrté rozhodnutí níže — že
release bumpve výchozím nastavení bere zvýšení, které implikují conventional commits — již neplatí. Minimální verze se měří z veřejného povrchu schopností proti poslednímu release a conventional commits jsou důkazem vedle tohoto verdiktu, ne autoritou pro něj. Sekce důsledků tohoto záznamu jmenuje toto odvození jako známý náklad („breaking change commitnutá jakofeatvyvolá minor zvýšení“); ADR 0051 je to, co jej odstranilo. Vše ostatní platí: changelog je skládán, okno je jeden interval řečený dvakrát, parser je totální a verze drží dvě tvrzení a jednoho zapisovatele.
Doplněno ADR 0085 (navrženo), 2026-09-24. Verze už nedrží dvě tvrzení. Píše se jednou, v manifestu crate, a shellový nástroj čte
share/version.txt, generovanou projekci dodávanou v každém archivu. Alternativa zamítnutá níže jako Sbalení verze do jediného zdroje zamítla výstup buildu a závislost za běhu; ADR 0085 odpovídá na každý ze čtyř jejích důvodů projekcí arelease bumpnyní zapisuje řádek manifestu a záznam o něm v zámku, nebin/majordomus. Rozhodnutí o changelogu platí. Stav tohoto záznamu se nemění: jeproposeda závěrečná poznámka ADR 0051, že „zůstáváaccepted“, je přepsání, které se opravuje tím, že se to zde říká, nikdy zápisemaccepted.
Kontext
ADR 0002 udělal z registru schopností jedinou deklaraci za každým rozhraním, ADR 0027 totéž pro příkazy a project.interfaces-are-projections to vyžaduje obecně. Když oba dorazily, byl release posledním veřejným faktem tohoto repozitáře bez kanonické deklarace — a chyběla mu ve dvou různých ohledech.
Žádný changelog neexistoval. Ne zastaralý: žádný. To, co se ve verzi změnilo, žilo v release notes GitHubu, psaných tím, kdo release vydal, uložených mimo repozitář, který je vytvořil, a nikdy už nepřečtených ničím tady. Člověk, který se ptal „co se změnilo v 0.3.1?“, musel opustit strom, aby to zjistil, a žádná kontrola nemohla poznat, kdy je odpověď špatná, protože nic v repozitáři netvrdilo, že ji drží.
Vše, co by takový dokument říkal, už bylo ve stromu a už bylo kanonické pro to, co uváděl:
.ai/repo/releases/*.yaml what shipped, when, from which commit (kind release-record)
.ai/repo/adrs/*.md the decisions, dated (kind adr)
git log <commit>..<commit> everything that has no object of its own
Tři zdroje, tři slovníky, žádný join. Záznam zná svůj commit a artefakty a nic o důvodu; ADR zná rozhodnutí a datum a nic o tom, který release ho nesl; git zná každou změnu a nic o tom, k čemu která byla.
Verzi nezvýšilo nic. Je uvedena v apps/majordomus-cli/Cargo.toml a v bin/majordomus (MJ_VERSION) a scripts/release-version --check skončí s kódem 10, když se obě liší. Duplicita není vada a skript říká proč: nainstalovaný strom nemá Cargo.toml a crate se kompiluje dřív, než shellový nástroj existuje, takže žádný z programů nemůže za běhu číst kopii druhého. Vada byla na druhé straně. Kontrola bez zapisovatele ověřuje paměť člověka — může promluvit teprve poté, co někdo upravil jeden soubor a zapomněl na druhý, a prvním krokem postupu vydání v docs/DISTRIBUTION.md byl doslova editor otevřený na obou.
Rozhodnutí
Připojit to, co je již deklarováno, a přidat jednoho zapisovatele.
- Changelog se skládá, nikdy nepíše ručně. Jedna sekce na každý záznam release, nejnovější první, s nevydanou prací na začátku. Jeho rozhodnutími jsou ADR datovaná uvnitř okna daného release, jeho změnami konvenční commity v jeho rozsahu, jeho artefakty vlastní důkazy záznamu. V tomto repozitáři není žádné
CHANGELOG.mda jeho přidání by byla chyba, ne oprava. - Okno je jeden interval vyslovený dvakrát. Rozhodnutí spadají do
(previous release's date, this release's date], commity doprevious..this— protože ADR nese datum a žádný commit a commit nenese žádné datum, které by vrstva indexovala. Oba zdroje píší ISO-8601, takže porovnání je lexikografické nad dnem, který mají společný. - Parser commitů je totální. Předmět, který není konvenční, se stane druhem
Othera stále se objeví, s předmětem zachovaným celým. Changelog, který zahazuje, co neumí klasifikovat, lže vynecháním. - Verze si ponechává dva výroky a získává jednoho zapisovatele.
majordomus release bumpzapisuje oba řádky — a jen ty dva — a ve výchozím stavu bere zvýšení, které konvenční commity implikují: breaking je major, funkce je minor, cokoli jiného je patch, žádné commity vůbec je none.--levela--exactjej přepisují pro to, co commity neříkají.scripts/release-version --checkje beze změny a nyní dokazuje práci jednoho zapisovatele místo paměti jednoho člověka. - Každý povrch je odvozen. Dvě čtecí poloviny jsou schopnosti —
release.changelogarelease.version— takže příkazová řádka,GET /api/v1/changelog,GET /api/v1/release/version, nástroj a zdroj MCP i Cockpit vykreslují jednu hodnotu. Vygenerovaný dokumentdocs/generated/changelog.{json,yaml,md}je cílemmajordomus generate, takže stávajícígenerate --checkje to, co si všimne, že changelog přestal popisovat strom. - Zvýšení verze je skryto před každým strojovým povrchem, aniž to někdo nařídil. Je anotováno
RepositoryMutationvedle příkazové řádky a zbytek obstará politika vystavení z ADR 0027. Žádná schopnost ho nedeklaruje a nebyla napsána žádná výjimka.
Zamítnuté alternativy
Ručně psaný CHANGELOG.md. Konvenční odpověď, která tu selhává ze stejného důvodu jako každá ručně udržovaná projekce v tomto repozitáři: v den napsání je správná a poté tiše degraduje, aniž by kontrola uměla rozlišit záměrné vynechání od zapomenutého. Byl by to také jediný veřejný dokument ve stromu, který opakuje fakta, jež už drží tři kanonické zdroje, přesně to, co derived-once a interfaces-are-projections existují, aby odmítly. Poctivá podoba této alternativy zní „udržovat ručně čtvrtou kopii historie vydání“ a takto vyslovená se tím rozhoduje.
Odvozovat changelog jen z konvenčních commitů. To dělá každý hotový generátor, nepotřebuje páteř ADR a bylo by to o třetinu kódu méně. Odpovídá to však na špatnou otázku. Předmět commitu říká, co se udělalo; neříká, co se rozhodlo, a v tomto repozitáři je rozhodnutí trvalým artefaktem — ADR čte o měsíce později někdo, kdo posuzuje, zda omezení stále platí, a changelog, který neumí říct, který release nesl adr-0027, k tomu použít nelze. Rozhodnutí jsou již datované objekty vrstvy; vynechat je by znamenalo, že nejvíce posuzované záznamy repozitáře se v žádné historii releasů neobjeví.
Sbalení verze do jediného zdroje. Lákavé a nemožné bez vzdání se něčeho. Shellový nástroj musí uvést svou verzi v nainstalovaném stromu, který nemá Cargo.toml; build skript zapisující MJ_VERSION do bin/majordomus by udělal ze sledovaného souboru výstup sestavení a crate se sestavuje dřív, než shellový nástroj vůbec existuje. Generovat jedno z druhého za běhu vyměňuje kontrolu, která stojí milisekundy, za runtime závislost mezi dvěma programy, které se dodávají zvlášť. Duplikace je skutečné omezení dodávání dvou programů z jednoho stromu, takže správný cíl nikdy nebyl jeden zdroj — byl jeden zapisovatel plus kontrola, která už existovala.
Parsování release notes z GitHubu zpět do repozitáře. Poznámky jsou místem, kde historie dnes žije, takže jejich import vypadá jako její záchrana. Udělalo by to z externí, měnitelné, po síti dosažitelné služby autoritu pro fakt repozitáře: poznámky může po publikaci upravit kdokoli s právem zápisu, nejsou dostupné buildu bez sítě a fork ani zrcadlo je nemá. Obrátilo by to také směr, který už funguje — release pipeline zapisuje .ai/repo/releases/*.yaml z toho, co skutečně publikovala, takže repozitář je upstream poznámek a čtení zpět by nechalo projekci krmit vlastní zdroj.
Důsledky
Každý povrch, který uvádí, co bylo dodáno, nyní vykresluje jednu hodnotu a záznam release, který přistane ve stromu, dostane svou sekci do příkazové řádky, API, MCP resource, Cockpitu i generovaného dokumentu bez druhé registrace. docs/RELEASE.md je architektonický dokument; docs/DISTRIBUTION.md uchovává postup release a je nyní jediným místem, které stále popisuje ruční zvýšení verze — jeho první krok by se měl stát majordomus release bump.
Tři náklady jsou skutečné. Obsah changelogu závisí na historii gitu, kterou klon nese, takže mělký checkout vytvoří sekce bez změn; to se hlásí v diagnostics a vykresluje pod „Co nešlo přečíst“, místo aby se mlčky vynechalo, což je správné chování, ale znamená, že generovaný dokument je reprodukovatelný jen z plného klonu. Generovaný changelog se připojuje k množině, kterou generate --check hlídá, takže každý commit, který mění historii, nyní mění sledovaný soubor — stejná cena merge, jakou už nese každý další generovaný dokument v tomto repozitáři. A výchozí hodnota zvýšení verze je odhad z předmětů commitů, takže zásadní změna commitnutá jako feat vyvolá minor zvýšení; přepsání pro to existuje, zpráva vypisuje commity, které přečetla, jako své důkazy, a project.conventional-commits bylo v době tohoto rozhodnutí spíše doporučující než blokující, takže odhad bude občas třeba přepsat. Od verze 2 tohoto pravidla je blokující: hook commit-msg odmítne zprávu, kterou politika nepřijímá, a 54 commitů této historie, které jí předcházejí, je zaznamenáno, ne přepsáno. Odhad nad commity vytvořenými od té doby je tedy nad konvenčními předměty; přepsání, které tento odstavec předvídal, zůstává dostupné a zůstává věcí autora release, protože předpona feat: je důkazem pro zvýšení, nikdy rozhodnutím (viz COMMIT.md).
Co to drží: jednotkové testy crate nad aritmetikou oken, parserem, funkcí bump a úzkostí zápisu; test/cases/103_release_projection.sh nad celým povrchem proti skutečnému executable v repozitáři vytvořeném pro tento účel, protože každá otázka, kterou případ klade, je otázka o historii; scripts/ci/release-check nad tím, co generate --check nevidí, tedy driftem mezi dvěma deklaracemi, kde je verze uvedena, a objevením se ručně vedeného changelogu; a scripts/release-version --check, beze změny.