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.

Kanonické vlastnictví a odvozování

kanonické vlastnictví: co smí být zapsáno dvakrát, co se musí odvozovat a které entity stále nemají vlastníka

Vykresleno z docs/DYNAMICITY.md — stejného Markdownu, který ukazuje GitHub.

Jak tento repozitář rozhoduje, kde fakt žije, co smí být zapsáno dvakrát a co se musí odvodit. Doprovodný soubor je HARDCODING_LEDGER.yaml, který zaznamenává každé místo, kde jsou níže uvedená pravidla právě porušena, s příkazem k reprodukci pro každé.

Tvrzení zde popisující chování, které ještě není implementováno, jsou formulována jako cíle.

Pravidlo

Jeden fakt má jednoho kanonického vlastníka. Každé další místo, kde se fakt objevuje, je z vlastníka odvozeno, nebo je kontrolou, že se oba shodují.

Selhání, kterému se tím předchází, není neuklizenost. Je to selhání, které nástroj existuje chytat: deklarované pravidlo, které nic nevynucuje, zdokumentovaný příkaz, který už neexistuje, počet, který byl kdysi pravdivý. Každá taková vada začíná jedním faktem zapsaným na dvou místech, z nichž se jedno změní.

Co se počítá jako napevno zapsané

Ne každá konstanta je vada a pročištění, které s nimi zachází stejně, vytváří nečitelnou nepřímost a skutečný drift přitom míjí.

Kontrakt zůstává doslovný. Jsou to rozhodnutí, ne zjistitelná fakta, a jejich sepsání je to, čím se stávají kontraktem:

DruhPříklad zde
Konstanty protokoluexit kódy v lib/common.sh
Verze schématversion: 1 v každém kanonickém souboru
Standardní názvy souborů.ai/repo/policy.yaml, CLAUDE.md
Výchozí hodnoty bootstrapunázev výchozího profilu
Rozhodnutí o podpořeoperační systémy v matici CI
Samotné schémashare/allow/*.txt, které definují povolené klíče
Redakční úsudeksloupce publika a účelu v docs/README.md

Zrcadlo je vada. Seznam je zrcadlem, když jeho obsah už zná něco jiného:

ZrcadloKde je pravda
obsah souborového systémuadresář
Příkazy CLIdispečerská tabulka
teststest/cases/ a metadata v každém případu
routesgenerované kolekce obsahu
doktrínysoubory pravidel pod .ai/repo/rules/
providersdeklarované projekce
tvrzenídocs/CLAIMS.yaml
počty čehokoli z výše uvedenéhoto, co se počítá

Rozlišující otázka není „mohlo by to být data?“, ale „ví už to něco jiného a budou se ty dvě rozcházet?“ Kurátorský seznam, jehož úplnost se vynucuje proti adresáři, který popisuje, není zrcadlo — docs/README.md je vzor: řádky jsou redakční a scripts/generate-site-data odmítne build, když se soubor v docs/ neobjeví v žádném řádku.

Kanonické vlastníky

EntitaKanonický vlastníkZjišťováníOdvozené povrchy
Politika.ai/repo/policy.yamlschéma v share/allow/policy.txtprojekce providerů
Profil.ai/repo/profiles/*.yamlglob adresářekontext, požadavky na dokončení, web
Doktrína.ai/repo/rules/ a vendorované balíčkyprůchod registremcheck, finish, doctor, watch, web
Validátormj_validate_* v lib/sken zdrojů, srovnaný s registremrozdělování doktrín
Tvrzenídocs/CLAIMS.yamlprůchod registremstránky záruk, docs/SITE_CLAIMS.md
Odpovědnostdocs/RESPONSIBILITIES.yamlprůchod registremweb, registr doktríny
Dokumentdocs/*.md + tabulky indexuglob adresáře, index vynucentrasy webu
Příkaz (nástroj shellu)share/commands.yamlověřeno proti dispatch tabulcedokumenty, stránky, ukázky, pokrytí, graf příkazů
Příkaz (spustitelný soubor)deklarace clap, apps/majordomus-cli/src/cli.rsprůchod stromem--help, docs/generated/cli.*, /docs/cli/**, graf příkazů
Pracovní postupjustfile a .just/*.justjust --dump --dump-format jsonsnapshot prostředí, banner, graf příkazů
Sémantika příkazů (efekt, interaktivita, požadavky, zdroje hodnot, aliasy kompatibility)command_graph/semantics.rs, vedle deklaraceúplnost vynucená proti stromu clap v obou směrechgraf a každá jeho projekce
Kde je příkaz vystavencommand_graph/policy.rsodvozeno z efektu a interaktivitymost workflow, doplňování, MCP, HTTP, Cockpit, reference
Typ událostishare/events.yamlprůchod registremvalidace knihy, history, docs/SCHEMAS.md
Projekce.ai/repo/policy.yaml projections[]policy walkupdate, doctor, watch
Poskytovatel kontextucíl: jedna tabulka v lib/context.shprůchod registremsestavení, zahazování podle rozpočtu, JSON
Generovaný artefaktgenerate::Target a Document, které každý cíl sestavujeplán generovánídocs/generated/**, share/allow/*.txt, bootstrapy poskytovatelů, site/data/registry/registry.json — a docs/generated/artifacts.{json,yaml,md}, generovaný index všech

Řádky označené target jsou entity, které dnes nemají vlastníka. Každá je řádkem v knize s důkazem, proč ho potřebuje.

Odvozování, ne duplikace

Odvozený povrch se regeneruje od svého vlastníka a nikdy není autoritou. Tři zde generované povrchy jsou instrukční soubory poskytovatelů (majordomus update), data a obsah webu (scripts/generate-site-data) a docs/SITE_CLAIMS.md. Každý je otiskován nebo porovnáván s čerstvým generováním, takže ruční úprava je hlášené selhání, ne tichá divergence.

Dvě vlastnosti, které musí mít každý generátor:

  • Transakční. Vykreslit do dočasného umístění, zvalidovat celý výsledek, pak nahradit. Generátor, který zkrátí svůj výstup a pak objeví chybu, zničil poslední dobrý stav. majordomus update to dělá; generátor webu vykresluje do dočasného adresáře a porovnává.
  • Úplná čerstvost. Kontrola, že generovaný artefakt je aktuální, musí iterovat to, co generátor vyprodukoval, ne seznam, který někdo napsal vedle. Zjištění generated-json-inventory v knize je tato vlastnost, která chybí.

Události

Trvalá změna stavu je událost. Kniha je jen k připisování a už je kanonickým záznamem; cíl je nad ní registrovaný slovník, ne druhý log.

share/events.yaml deklaruje každý název, který kniha přijímá, příkaz, který ho zapisuje, a klíče obsahu, které ten název vyžaduje. mj_ledger_append odmítne neregistrovaný název a takový, kterému chybí povinné pole; history --event odmítne filtrovat podle názvu, který není deklarován, místo aby odpověděl prázdným výsledkem, který by dal deklarovaný, ale chybějící název; history --validate hlásí uložený řádek, jehož název nezná žádný čtenář. Předtím překlep v názvu vytvořil trvalý záznam, který každý čtenář potichu ignoroval, a docs/SCHEMAS.md dokumentoval událost bootstrap, kterou nikdy nic nezapsalo.

Práci utvářela dvě omezení:

  • Stávající názvy se ponechávají. Přejmenování rozbije každou existující knihu, včetně té vlastní tohoto repozitáře, a čtenář, který tiše vynechá vše před přejmenováním, je horší než nekonzistentní název. Slovník je registrován tak, jak byl napsán.
  • Pořadí knihy je nosné. mj_record_rank používá pozici v knize k rozhodování shod rozlišení mezi záznamy vytvořenými ve stejné vteřině. Nic nesmí řádky přeuspořádat, přepsat ani rotovat, aniž by s tím počítalo.

Vykreslení je jediné místo, kde smí větev na událost stále existovat, protože to, jak se událost čte člověku, je prezentace, ne slovník. Existuje právě jedna taková větev, v lib/history.sh, a sesouhlasuje se s registrem místo odstranění: událost bez vykreslení i vykreslení události, která není deklarována, obojí selhává.

Jediná chybějící událost, kterou stále stojí za to přidat, je odmítnuté finish: přijaté dokončení se zaznamená a odmítnutí nezanechá stopu, takže úloha odmítnutá čtyřikrát vypadá přesně jako ta, která prošla napoprvé. test/cases/32_refusal_lifecycle.sh provede čtyři odmítnutí a nese tvrzení, které bude platit, až událost existuje.

Demonstrace jsou projekce, ne popisy

Stránka příkazu nese interaktivní demonstraci. Riziko v tom je zřejmé: stránka, která popisuje chování, se stává druhou implementací, a ta druhá není nikdy ta, která se dodává.

Takže ukázka se nepíše. test/fixtures/commands/<command>.json drží sadu scénářů — situaci, spuštěný příkaz, očekávaný návratový kód, řádky, které výstup musí obsahovat, a vysvětlení. test/cases/34_command_fixtures.sh provede každý z nich proti skutečné binárce v čerstvém repozitáři a generátor webu vloží tentýž soubor do stránky. To, co stránka ukazuje, je to, co test tvrdil.

Dva důsledky stojí za zmínku:

  • Ve fixture žije žádný shell. Příprava je skutečný skript pod test/fixtures/commands/setup/, složený načítáním (sourcing), který stránka zobrazuje doslova a případ jej načítá. Nic nespouští řetězec, který přišel z dat, což zachovává pravidlo proti eval a zároveň činí demonstraci poctivou.
  • Generátor odmítá, nedegraduje. Veřejný příkaz bez fixture, bez id demonstrace, bez behaviorálního případu nebo bez negativního případu zastaví sestavení. Neexistuje stav „testy brzy“ pro příkaz, o kterém projekt tvrdí, že ho podporuje.

Každé odmítnutí se vyvolá dřív, než se zapíše bajt výstupu. exit uvnitř skupiny { ... } | jq . > file zabije jen skupinu, zatímco přesměrování už cíl zkrátilo — odmítnutí zapsané tam proto hlásí špatný exit kód a nechá po sobě zničený soubor. Validace běží první; vysílající pipeline nemůže selhat na politice.

Stejné fixtures obsluhují druhý povrch. Stránka odpovědnosti ukazuje příkaz, který na ni působí, jak odmítá a přijímá, vykreslený z fixture toho příkazu — takže ukázka na /supervises/finish/ a ta na /commands/finish/ jsou tytéž scénáře, provedené týmž případem, a nemohou se rozcházet.

Uspořádání se vyplácí. Psaní fixtures našlo vadu, kterou nenašlo nic jiného: rev-parse HEAD v repozitáři bez commitů vypíše na stdout doslovný řetězec HEAD a potom selže, takže se k němu připojila záloha || printf 'NONE' a vzniklo pole identity s vloženým novým řádkem — trvale poškozený řádek v ledgeru jen pro připojování, pro každého, kdo spustil init a update před svým prvním commitem.

Pravidlo, které prochází ze stránky k věcem, na které odkazuje, najde jen odkazy, které jsou špatné. Nenajde odkazy, které chybí, protože chybějící odkaz je z této strany z principu neviditelný — na stránce není co kontrolovat.

Vada, která to učinila konkrétním: šest tvrzení v docs/CLAIMS.yaml deklarovalo responsibility: plan, stránka /supervises/plan/ neodkazovala na žádné z nich a každá kontrola se dívala ven ze stránky. Procházka ze strany tvrzení — každé tvrzení, které jmenuje odpovědnost, se musí objevit na stránce této odpovědnosti — to najde okamžitě.

Relace se tedy kontroluje v obou směrech, nebo se nekontroluje vůbec:

  • každé id, které stránka jmenuje, musí existovat, a
  • každý záznam, který stránku jmenuje, musí z ní být odkazován.

Druhá je ta, kterou nikdo nepíše, a je to ta, která vadu zachytí.

Dnes existují dvě taková pravidla, why a supervises, každé zná jedno spojení. To je snesitelné. Třetí je bod, v němž by se měl sám vztah stát daty — dvě kolekce, pole držící id a tvar trasy — a jedno pravidlo by je mělo procházet. Napsat třetí ručně psanou verzi by byla stejná chyba jako mapa, z níž vznikla vada této sekce.

Mutace musí dokázat, že mutovala

Test, který něco rozbije a pak hledá selhání, je jen tak dobrý jako to rozbití. sed mlčí, když jeho vzor nic nenajde: skončí s 0, aniž by cokoli změnil, a případ pak tvrdí, že no-op nevyvolal selhání, což platí triviálně. Případ zůstane zelený a nic nedokazuje, a to od okamžiku, kdy kód, který mutoval, změnil tvar.

Každá sonda proto nejdřív ověří, že se uplatnila, a teprve pak, co způsobila:

sed 's/<pattern>/<replacement>/' "$SRC" > "$PROBE"
grep -q '<the replacement>' "$PROBE" || { echo "    the probe did not take"; exit 1; }

Dvě zpřesnění, obě odnaučená v tomto repozitáři tvrdě:

  • Absence potřebuje obrácené tvrzení. sed '/x/d' nezanechá žádnou náhradu k nalezení, takže strážce ověřuje, že věc zmizela, ne že je tu něco nového.
  • Shodujte podle tvaru, ne podle obsahu. Sonda, která jmenuje dnešní seznam příkazů, přestane mutovat v den, kdy někdo příkaz přidá. To je táž vada jako validátor, který mlčky přestane běžet, a 35_future_command ji měl do hodiny po napsání — chytil ji jeho vlastní hlídač.

Mutace, která tiše přestane mutovat, a pravidlo, které se tiše přestane vynucovat, jsou táž chyba, a tento repozitář existuje právě kvůli té druhé.

Sebeřízení

Majordomus dohlíží na tento repozitář týmiž registry, které dodává. Neexistuje žádný inventář specifický pro sebe sama ani kódová cesta jen pro testy: doktríny, které tu běží, jsou pravidla pod .ai/repo/rules/ a zapojení, které doctor sjednocuje, je zapojení deklarované v .ai/repo/policy.yaml.

Vlastnost, kterou to má vytvářet, vyjádřená jako cíl: přidání příkazu, doktríny, providera, typu události, projekce nebo tvrzení vyžaduje definovat entitu, implementovat chování a přidat testy — a každý další povrch následuje, aniž by si správce musel pamatovat sekundární krok registrace. Kde to zatím neplatí, ledger to říká.

Jak přidat po jednom od každého

Záměrně krátké. Pokud seznam níže roste, architektura regresovala.

  • Doktrína — napište pravidlo pod .ai/repo/rules/ s jeho x-majordomus.validator a napište funkci mj_validate_<validator>, kterou jmenuje. doctor obě sesouhlasí a selže, pokud kterákoli chybí.
  • Tvrzení — přidejte položku do docs/CLAIMS.yaml a napište docs/claims/<id>.md. Generátor webu odmítne sestavovat bez detailní stránky a zaručené tvrzení bez cesty k testu je chyba.
  • Dokument — napište docs/<NAME>.md a přidejte jeho řádek do jedné ze dvou tabulek v docs/README.md. Trasa, stránka a položka indexu následují.
  • Profil — přidejte .ai/repo/profiles/<name>.yaml. Objevuje se podle glob vzoru a validuje ho doctor.
  • Příkaz — deklarujte jej tam, kde program, který jej implementuje, deklaruje své příkazy: větev clap a její příklad pro executable, položka v share/commands.yaml a větev dispatche pro shell nástroj, recept pro workflow. Anotujte jej v command_graph/semantics.rs jen tehdy, pokud není jen pro čtení a neinteraktivní. Následují most workflow, shell doplňování obou povrchů, strojové povrchy, které politika připouští, Cockpit a reference. docs/COMMANDS.md je celé.

Přidání typu události, poskytovatele nebo projekce zatím není takto krátké. To jsou zbývající řádky priority 1 a 2 ledgeru. Přidání příkazu takto krátké bylo, když graf příkazů nahradil seznamy pro každý povrch: viz docs/COMMANDS.md a pravidlo project.commands-are-projections.

Tvrzení, která tento dokument definuje

Každý odkazuje na vlastní stránku s implementací, testem a místy použití.

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