56. Každý objekt vrstvy má odvozenou adresu, oba směry každé relace a deklarované místo publikace
Rozšiřuje ADR 4 a ADR 13.
Kontext
ADR 2 učinilo z každého rozhraní programu projekci jednoho registru schopností a ADR 4 učinilo z jedné kanonické deklarace jediné místo, kde je schopnost zapsána. Deklarativní polovina repozitáře — každý soubor pod .ai/, indexovaný jako typovaný objekt s druhem, identitou a URI majordomus:// — se už takto četla: jedna tabulka relací řeší každou referenci, kterou objekt deklaruje, graph.compose ji kreslí a každý objekt je zdrojem MCP.
Chyběly tři věci a každá byla druhem mezery, která vypadá jako vylepšení, dokud na ni čtenář nenarazí.
Identita není adresa. Objekt bylo možné číst v Cockpitu na /cockpit/object?uri=majordomus%3A%2F%2Frule%2Fproject.x%401 — parametr dotazu nesoucí URI zakódované procentově. Nic na něj neodkazovalo, nic nešlo uložit do záložek, neexistoval index druhu a uzly složeného grafu mířily na tuto adresu, takže jediné místo, kde se relace kreslily, posílalo každé kliknutí do řetězce dotazu.
Tabulka vztahů se četla jen dopředu. Pravidlo deklarovalo, na čem závisí; nic neodpovídalo co závisí na tomto, ačkoli hrana, která odpovídá, už v grafu byla, jen opačným směrem. Totéž platilo pro rozhodnutí a to, co uvedlo v platnost, pro tvrzení a jeho implementaci, pro aplikaci a případy užití, které jí slouží.
Nic neříkalo, kde je druh publikován. Veřejný web měl redakční sekce pro dovednosti, příkazy, případy užití, funkce, tvrzení, relace, profily a katalog Why — a žádnou stránku pro rozhodnutí ani pro 78 vlastních pravidel tohoto repozitáře. Které druhy se na web dostanou, bylo implicitní ve dvaceti řádcích shellového generátoru, takže druh mohl být přidán do vrstvy a nedostat se na žádnou veřejnou stránku, aniž by to kdekoli bylo řečeno. To je tiché selhání objevování, které tento repozitář už dvakrát potkal, v globu, který neodpovídal žádnému ADR, a v site-check s prázdnou množinou subjektů.
Rozhodnutí
Adresa se odvozuje, nikdy nepřiděluje. entity::slug zredukuje identitu na jeden segment cesty — malá písmena, každý souvislý úsek čehokoli jiného se změní na jediné -, okraje se oříznou — a adresa je druh a tento segment. Neexistuje tabulka mapující objekty na trasy, protože tabulka může být neúplná a funkce nemůže. Funkce však může zobrazit dvě identity jednoho druhu na jeden segment; to je kolize, entity::collisions najde každou z nich a scripts/ci/entity-check odmítne strom, dokud nějaká existuje. Trasa, která odpovídá jedním ze dvou objektů, je horší než žádná trasa, protože čtenář nepozná, který z nich dostal.
Jedna schopnost odpovídá za entitu, na každém povrchu. entity.show vrací identitu, adresu, původ, front matter, obsah, odchozí hrany, příchozí hrany, povrchy, které za objekt odpovídají, a co lze říct o spustitelných artefaktech, které jmenuje. Projektuje se do MCP jako majordomus_entity, do HTTP jako GET /api/v1/entity, do příkazové řádky jako majordomus entity show a je to to, co rozvrhuje stránka entity v Cockpitu. entity.kinds je totéž pro katalog druhů.
Zpětné odkazy se odvozují z dopředné deklarace. entity::edges čte graph::RELATIONS — jedinou tabulku, kterou skládaný graf a kontrola visících odkazů už sdílejí — přes každý objekt a ponechává hrany, jejichž kterýkoli konec je subjekt. Vztah přidaný do té tabulky se stane dopřednou hranou na jedné stránce a zpětným odkazem na druhé, bez čehokoli deklarovaného dvakrát. Nic ve vrstvě nedeklaruje zpětný odkaz a nic nesmí: půl vztahu je způsob selhání, který toto vylučuje.
Každý druh deklaruje, kde je publikován. site/data/publication.toml nese jeden záznam na druh indexu: publikován jako stránky entit na trase, už publikován redakční sekcí, nebo nepublikován s napsaným důvodem. scripts/ci/entity-check čte ten soubor a majordomus entity kinds odmítá obojí směr — druh, který index drží a deklarace ho nezmiňuje, a druh, který deklarace jmenuje a index ho nedrží.
Veřejné stránky entit jsou jedna projekce, ne jedna na druh. Dvě šablony — entity.html a entities-section.html — obsluhují každý druh, který publikuje stránky entit, a žádná nejmenuje druh. Kontrola odmítne jméno druhu v kterékoli z nich, protože šablona, která by nějaký jmenovala, by z přidání druhu udělala úpravu konzumenta.
Hub dokumentace čte tytéž dvě deklarace a index je indexem buildu. Přidáno 2026-09-24. Horní část /docs/ uvádí každý druh s jeho počtem a kde je publikován, nebo důvod, proč není. Tyto řádky jsou catalogue z entities.json: deklarace publikace spojená s indexem. Vedle jsou počty rozhraní (schopnosti, operace příkazové řádky, trasy HTTP, nástroje a zdroje MCP, moduly), což jsou vlastní summary registru. /docs/index.json zapisuje scripts/lib/docs-index.mjs po buildu: prochází stránky, které Zola vyrobila, ne seznam. Drží tedy každou stránku, kterou může návštěvník otevřít, spojuje každou stránku entity s jejím objektem, nese identitu /build.json buildu, který ji zapsal, a odmítne build (exit 10), když trasa, kterou katalog publikuje, nebyla sestavena. Vyhledávání hubu čte tento soubor, takže výsledek vyhledávání může být jen stránka, která existuje. scripts/pages verify-docs žádá veřejný web o týž soubor, ověřuje, že jmenuje nasazený commit, a sonduje každou trasu, kterou publikuje. Běží jako krok workflow Pages poté, co web obsluhuje commit. Případ 500 drží všechny čtyři.
Zamítnuté alternativy
Tabulka rout v Cockpitu. Nejnasnadě ležící tvar, který mandát vedoucí k této práci výslovně zakázal: je to inventář, tiše zastarává a přidání pravidla z něj dělá úpravu routeru.
Publikovat každý druh. 1309 objektů ve 29 druzích. Většina už má redakční stránku — úkol na /plan/, tvrzení na /guarantees/, relace na /sessions/ — a druhá adresa téhož objektu je duplicita, kterou celý subsystém odstraňuje. Některé jsou fakta o checkoutu, ne o produktu: identita mesh, deklarace rozsahu, prompt. Rozhodnutí tedy není „publikovat vše“, ale „rozhodnout o všem, písemně, tam, kde to může číst kontrola“.
Deklarace publikace v share/kinds.yaml. Tento soubor patří distribuci nástroje, sdílí ho každý dozorovaný repozitář; to, kde tento web publikuje daný druh, není všude vlastností toho druhu. Patří webu a sídlí vedle další deklarace webu, nav.toml.
Druhá datová sada pro web. docs/generated/graph.json už nese každý uzel a každou hranu, generuje ji spustitelný soubor a kontroluje se její drift. entities.json webu je její projekcí, ne druhým čtením vrstvy.
Vyhledávací služba nebo vestavěný vyhledávací index Zoly. Vzdálená služba je závislost, kterou statický web nepotřebuje. Index Zoly pokrývá každé slovo každé stránky, přidává runtime knihovnu a byl by druhým výpisem stránek vedle toho, který toto sestavení už zapisuje. Filtr nad tituly a popisy /docs/index.json odpovídá na otázku „kde to je“, k čemuž slouží index dokumentace.
ExDoc. Mise, která o hub žádala, ho jmenovala. Majordomus nemá žádný kód v Elixiru, takže spuštění ExDoc by znamenalo spustit toolchain, aby napodobil svůj vlastní výstup. Vlastnosti, které činí ExDoc užitečným, jsou index podle druhu, stabilní stránka na entitu, odkazy na zdroj, křížové odkazy, vyhledávání a deterministický výstup a každá z nich je projekce, kterou tento repozitář už měl nebo zde má. Referenční API samotného cratu je cargo doc, což publikuje jiná změna.
Důsledky
- Soubor přidaný pod
.ai/dostane řádek indexu, adresu, stránku, své místo ve zpětných odkazech každé další stránky, zdroj MCP, odpověď HTTP a odpověď příkazové řádky, bez úpravy kteréhokoli spotřebitele. Přejímací test napíše jedno pravidlo a ověří přesně toto. - Druh přidaný do vrstvy selže na
entity-check, dokud někdo písemně nerozhodne, zda jej web publikuje. To je záměrné tření na jediném místě, kde mlčení bylo drahé. graph::RELATIONSzačíná být nosné pro stránku určenou uživatelům, nikoli jen pro kresbu a kontrolu. Relace v něm deklarovaná je nyní okamžitě viditelná v obou směrech, což je smyslem, a relace v něm vynechaná je neviditelná v obou.- Publikovaný web získá jednu stránku pro každé rozhodnutí a každé pravidlo. Generují se z vlastních souborů objektů, takže próza má jeden domov a stránky se od ní nemohou rozejít.
- Stránka entity smí říct, co objekt jmenuje jako své spustitelné artefakty a zda je strom drží. Nesmí říct, že je objekt vynucován:
resolvedje výrok o cestách a zda některá z nich kdy běžela, je otázka prorules.show, na kterou stránka odkazuje, místo aby na ni odpovídala. /docs/nepočítá nic vlastního a/docs/index.jsonnic vlastního nevypisuje. Druh, stránka nebo rozhraní přidané do repozitáře se objeví v obou, protože bylo přidáno. Deklarovaná trasa, která se nesestaví, shodí build, a nasazený commit, jehož dokumentace neodpovídá, shodí běh Pages.