Uzavřeno. Při opakovaném měření proti
masterv6042f4286(v0.5.0) byl počet 112, ne 109: nález byl živý a rostl spolu s balíčkem pravidel. Nyní je 1 a ten patří vlastnímu repozitáři, který pravidla přijímá. Oddíl 8 zaznamenává, co bylo rozhodnuto, jaký mechanismus ve skutečnosti byl — oddíl 3 ho pojmenovává chybně a ten rozdíl je důležitý — a jak měření zopakovat.docs/ADOPTION.mduž neslibuje nulu; uvádí, co hlásí první běh.
Majordomus se zevnitř vlastního checkoutu čte jako zdravý a zvenčí jako rozbitý. Tento dokument zaznamenává měření, protože ten rozdíl je 109 selhání a nic v repozitáři to neříkalo.
Vše níže bylo ověřeno proti publikovanému release v0.3.1 a stromu v c2629a26 instalací nástroje tak, jak ho instaluje cizí člověk: curl | sh z publikovaného webu do jednorázového HOME, poté čerstvý repozitář git init. Zjištěno bylo dvakrát, dvěma relacemi pracujícími nezávisle během několika minut, a obě rozklady se přesně shodují. Nic zde nenavrhuje změnu; čtení je rozhodnutí a oddíl 6 říká, co je třeba rozhodnout, místo aby to rozhodl.
0. Proti čemu se měřilo
Forenzní dokument, který nelze znovu spustit, se rozpadne na pouhé tvrzení, proto jsou podmínky zafixovány, nikoli popsány:
| verze nástroje | v0.3.1, publikovaný release |
| jak byl nainstalován | curl -fsSL .../install.sh | sh do zahazovaného HOME, z veřejného webu — ne z lokálního buildu, ne z tohoto checkoutu |
| testovaný repozitář | čerstvé git init s jedním prázdným commitem a ničím dalším |
| repozitář, kterého se zjištění týká | tento, na c2629a26 |
| pravidla, která balíček dodává | 50, všechny pod .ai/repo/rules/vendor/majordomus/ |
| pravidla, která produkují zjištění | 41 |
Pozdější běh, který se od tohoto liší, je buď drift, nebo oprava, a čísla výše jsou to, co je rozliší.
1. Smlouva, kterou to vyvrací
docs/ADOPTION.md první běh nejen navrhuje. Předepisuje čtyři příkazy a pak stanoví výsledek. V době tohoto zjištění zněl:
Přidejte dva řádky hooku, které
initvypsal. Spusťtedoctorznovu; měl by hlásit nula selhání.
To je slib s číslem v sobě, což ho činí testovatelným. Už to neříká: věta byla odstraněna ve prospěch změřeného popisu druhého běhu, což je druhá polovina sekce 8.
2. Co se skutečně děje
Zdokumentovaná cesta, dodržená do písmene a bez čehokoli dalšího, co by se s repozitářem udělalo:
curl -fsSL https://majordomus.dev/install.sh | sh
cd <fresh repository>
majordomus init
majordomus update
# the two hook lines init prints, pasted into .git/hooks/
majordomus doctor
doctor hlásí 109 selhání a končí s 10. Dvě kontroly zapojení se přepnou na OK, takže hooky jsou skutečně splněny; těch 109 je to, co zbývá poté, co byly provedeny instrukce samotného dokumentu.
| počet | selhání |
|---|---|
| 68 | jmenuje tvrzení <id>, které není v docs/CLAIMS.yaml |
| 39 | test test/cases/NN_*.sh neexistuje |
| 1 | test/run.sh neglobuje test/cases/; nový případ by se nespustil |
| 1 | žádné .github/workflows/validate.yml; nic nespouští testy doktrín při integraci |
Před vložením hooků je počet 111: stejných 109 plus dva řádky hooků, které dokument říká přidat. 109 je číslo, které uvidí člověk, který čte náš dokument o adopci a dělá, co říká.
3. Proč je každé z nich pro adoptujícího neopravitelné
Každé ze 109 jmenuje něco, co existuje jen v tomto repozitáři: náš registr tvrzení, naše testovací případy, náš testovací runner, náš CI workflow. Adoptující repozitář žádné z nich nemá a mít nemá.
108 z nich jsou cesty k důkazům: dokument nebo testovací soubor, který pravidlo cituje jako vlastní důkaz. 109. je jiný druh věci a oddíl 5 ho bere zvlášť, takže „shnilá cesta k důkazu“ popisuje 108 z těchto nálezů, ne všechny.
Reference pocházejí z balíku pravidel, který nástroj instaluje. Například ai-layout-integrity.v1.md, tak jak ho init zapíše do cizího repozitáře:
x-majordomus:
claims: [init-refuses, ai-layer-manifest, local-state-ignored, legacy-migration, tool-location-independent]
tests: [test/cases/01_init.sh]
Ta dvě pole popisují, jak my ověřujeme vlastní pravidlo. Validátor je kontroluje v jakémkoli repozitáři, ve kterém běží, takže mimo domov se každé z nich rozřeší na nic.
Jde o celou baseline, ne o hlučný kout. Těch 109 pochází ze 41 odlišných doktrín — ai-layout-integrity 6, projection-integrity 5, pak state-consistency, rule-package-integrity, doctrine-wiring-integrity a context-integrity po 4 a dlouhý ocas — z 50 pravidel, která balík dodává. V čerstvém repozitáři .ai/repo/rules/project/ drží jen své README.md, takže se neúčastní žádné projektové pravidlo a nic není zaměněno. Nález je přesně ten, že dodávaný balík nemůže sám sobě vyhovět nikde jinde než doma.
4. Proč si toho nikdo nevšiml
Každá relace, která kdy spustila doctor, ji spustila uvnitř tohoto checkoutu, kde existují test/cases/ a docs/CLAIMS.yaml a každý odkaz se vyřeší. Nástroj o problému nemlčí; jen mu nikdy nikdo nepoložil otázku zvenčí.
Stejný tvar vyrobil defekt release nalezený téže noci: push provedený výchozím tokenem nespustí žádný workflow, takže release mohl být publikován a web by přesto pro jeho metadata vracel 404. Obě jsou kontroly, které projdou v jediném prostředí, na které se díváme, a selžou v tom jediném, ve kterém je uživatel. To je jedno poučení, ne dvě.
5. Ten, který se mýlí dvakrát
Tři ze čtyř kategorií jsou shnilé cesty důkazů — dokument nebo test, který tu existuje a tam ne. Čtvrtá není:
FAIL doctrine ci — no .github/workflows/validate.yml; nothing runs the doctrine tests on integration
To tvrdí, že adoptující repozitář musí nést vlastní soubor workflow Majordoma. Oprava problému s cestou důkazů by to umlčela, ale stále by šlo o pravidlo o CI dodavatele vynucované proti repozitáři spotřebitele, což je samostatná vada na stejném řádku. Mělo by se rozhodnout zvlášť, ne smést pod stůl.
6. Co je třeba rozhodnout
Čtení, k němuž obě relace došly nezávisle, vyjádřené tak, aby je šlo přijmout nebo odmítnout, ne předpokládat:
U převzatého pravidla jsou
x-majordomus.testsax-majordomus.claimsdůkazy dodavatele pro jeho vlastní pravidlo, nikoli povinnost repozitáře, který je přijímá. Měly by se ověřovat v domovském repozitáři balíčku, kde se cesty rozlišují, a jinde přeskakovat.
Upozornění, které k tomu patří. „Přeskoč, když se cesta nerozliší“ je o řádek vedle kontroly, která nemůže selhat. Implementováno líně, přeskakuje důkazy všude, včetně zde, a balíček pak může vyslat pravidla, jejichž testy a tvrzení shnily, aniž to cokoli řeklo. U adoptujícího se obě implementace chovají stejně a v diffu vypadají stejně. Odlišuje je test v tomto repozitáři, který dokazuje, že důkazy se tu stále kontrolují. Bez toho testu není oprava k nerozeznání od vady, kterou nahrazuje.
Zde nerozhodnuto: zda má vendorovaný balíček ta pole vůbec nést, nebo je nést pod názvem, který říká, čí jsou to důkazy; zda má být pravidlo CI v sekci 5 odstraněno, zúženo na vendora, nebo přeformulováno jako něco, co adoptující může splnit; a zda se mají dvě zjištění hooků číst jako čekající místo selhání, což je otázka formulace bez designového obsahu, která by neměla jet s větším rozhodnutím.
7. Reprodukce
T=$(mktemp -d); export HOME="$T"
curl -fsSL https://majordomus.dev/install.sh | sh
mkdir "$T/r" && cd "$T/r" && git init -q . && git commit -q --allow-empty -m init
"$T/.local/bin/majordomus" init
"$T/.local/bin/majordomus" update
printf '#!/bin/sh\n%s doctor || exit $?\n' "$T/.local/bin/majordomus" > .git/hooks/pre-commit
printf '#!/bin/sh\n%s finish --check || exit $?\n' "$T/.local/bin/majordomus" > .git/hooks/pre-push
chmod +x .git/hooks/pre-commit .git/hooks/pre-push
"$T/.local/bin/majordomus" doctor; echo "exit $?" # 109 failures, exit 10
rm -rf "$T"
Dvě upozornění pro každého, kdo to znovu spouští. export HOME="$T" potřebuje instalátor a cestou rozbije shim správce verzí — asdf-spravovaný python3 přestane být nalezen a doctor pak ohlásí všech 41 schémat jako neparsovatelná, což je chyba harnessu, ne nástroje. A MAJORDOMUS_SHARE zděděná z checkoutu Majordomus nasměruje nainstalovaný nástroj na share/ toho checkoutu; nováček takovou proměnnou nemá, proto spouštějte každý příkaz pod env -u MAJORDOMUS_SHARE.
8. Rozřešení
Znovu změřeno na master v 6042f4286 (v0.5.0), doslovným následováním ADOPTION.md v jednorázovém repozitáři git init s README, jedním zdrojovým souborem a jedním commitem:
| selhání | ukončení | z toho vlastních v repozitáři | |
|---|---|---|---|
| před | 112 | 10 | 1 |
| po | 1 | 10 | 1 |
| po, a jeden nález opraven | 0 | 0 | — |
Třetí řádek je podstatou: nula byla vždy dosažitelná a 111 nálezů stálo mezi adoptujícím a ní. Oprava přeživšího zabrala jednu větu v README.md repozitáře.
Těch 112 se rozkládá tak, jak popisuje sekce 2, v prvních dvou řádcích o jedno větší, protože balíček nyní dodává více pravidel: 69 tvrzení, 40 testovacích cest, runner, CI workflow a jeden nález bootstrap, který skutečně patří adoptujícímu — README.md repozitáře nejmenuje AGENTS.md, který právě zapsal update. Ten přežívá záměrně: je pravdivý, patří adoptujícímu a jeden řádek ho uzavře.
Mechanismus, opraveno
Oddíl 3 říká, že se pole „kontrolují v jakémkoli repozitáři, ve kterém běží“. To se neděje a ten rozdíl je celá oprava. mj_validate_doctrine_wiring je rozřeší proti MJ_HOME — distribuci nástroje — nikdy proti MJ_ROOT. lib/common.sh o těch dvou kořenech výslovně mluví a vždy mluvil.
Pokus, který to rozhodne: spusťte bin/majordomus doctor z checkoutu Majordomu proti témuž cizímu repozitáři, bez jakékoli další změny. 110 se změní na 3. Zjištění nikdy nepopisovala adoptující repozitář; popisovala jakýkoli strom, z něhož byl nástroj spuštěn, a scripts/release-package záměrně dodává bin/ lib/ libexec/ share/ LICENSE a razítko RELEASE.json — žádné test/, žádné docs/CLAIMS.yaml, žádné .github/. Důkazy jsou tedy nečitelné v každé nainstalované kopii z principu a adoptující repozitář byl jen místem, kde se výsledný šum náhodou četl.
Proto by „nechte kontrolu řešit proti repozitáři“ nespravilo nic a proto byl počet stejný, ať repozitář adoptujícího obsahoval cokoli.
Co bylo rozhodnuto
Čtení v sekci 6 je přijato se zostřeným diskriminátorem. tests a claims vendorovaného pravidla jsou důkazy dodavatele a ověřují se tam, kde je zdroj dodavatele, ale nástroj to rozhoduje z razítka RELEASE.json, které zapisuje release-package a bez kterého release-verify archiv odmítne — nikdy podle toho, zda soubory s důkazy náhodou jsou přítomny.
To je přesně ta opatrnost, kterou zvedá oddíl 6. „Přeskočit, když se cesta nerozřeší“ je stejný diff a kontrola, která nikde nemůže selhat, včetně zde, a balíček by pak mohl dodat zetlelé důkazy, aniž by to cokoli říkalo. test/cases/97_vendor_evidence.sh je to, co obě rozlišuje: tvrdí, že nerazítkovaný strom stále čte důkazy a stále selže na chybějící cestě k testu, že razítkovaný ne a že právě razítkování téhož stromu to přepne.
Zjištění o CI v sekci 5 se řeší stejným pravidlem, ne zvlášť: je to workflow dodavatele, ověřené ve zdrojích dodavatele a nikoho jiného se na ně neptáme.
Přeskočení se oznamuje, není tiché — INFO doctrine vendor evidence, jmenující release — protože čtenář ho musí umět rozeznat od důkazu, který byl zkontrolován a prošel. Následuje precedens již v doctor: INFO command coverage — this installation carries no test suite to measure.
majordomus doctrine status nesl stejnou vadu o příkaz dál, počítal tytéž nečitelné soubory testů a končil exitem 10 v každém adoptujícím repozitáři. Opraveno je stejně a hlásí not readable here místo zavádějící nuly.
Stále otevřené a záměrně zde nedořešené. Dvě otázky formulace, na žádné z nich slib nezávisí:
- zda by balíček měl nést tato pole pod názvem, který říká, čí jsou to důkazy — přejmenování s migrací, ne vada;
- zda by výrok
doctrine-wiring-integrity.v1měl říkat, kde se ověřuje každá klauzule. Zní „…je dokázáno testem, který CI spouští“, což platí o sadě pravidel vendora a nyní se to kontroluje ve zdroji vendora. Úprava přehašuje pravidlo vshare/standard/majordomus/manifest.yamla znovu vendoruje kopii pod.ai/repo/rules/vendor/, což je víc změn, než kolik vyjasnění stojí, dokud chování i oba dokumenty už říkají totéž jasně.
Dvě zjištění hooků, o nichž se zmiňuje sekce 6, už nevznikají: čtyři zdokumentované příkazy nechávají hooky zapojené a obě kontroly zelené.