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.

Commit

commit jako hodnota: jediná gramatika, kterou sdílejí changelog a soudce, politika deklarovaná jako data s šířkou předmětu změřenou z této historie, slovník scope naučený z logu, ne vedený v tabulce, plán opatřený otiskem repozitáře, worktree, HEAD a množiny změn, a kde ji vynucuje každý ze tří okamžiků

Vykresleno z docs/COMMIT.md — stejný Markdown, který ukazuje GitHub.

Zpráva commitu je v tomto repozitáři hodnota s gramatikou, politikou a verdiktem, ne konvence, o které se lidem připomíná. Tato stránka říká, co to znamená, co to stojí a kde žije každá polovina.

Problém, pro který byl napsán

Dvě poloviny tohoto předmětu existovaly a nevěděly o sobě.

Repozitář mohl commit přečíst: release::commits od existence changelogu parsuje konvenční subjekty z logu, aby changelog sestavil, řeší I1305 a M000 proti tomu, co vrstva drží, a vypouští id, které se nevyřeší na nic.

Repozitář žádný nedokázal posoudit. project.conventional-commits uvedlo konvenci a jeho chování při selhání četlo „Žádný příkaz o tomto pravidle nerozhoduje; rozhoduje reviewer.“ Měření z doby psaní: z 1161 commitů bez merge přesahuje 48 předmětů šířku, kterou tento projekt deklaruje pro řádek čehokoli, a 38 nese typové slovo, které neobsahuje žádný slovník. Nikdo si nevšiml, protože nikdo nehledal.

Třetí polovina byla úplně mimo repozitář. Postup psaní commitu — odvodit scope z cesty, propojit práci, nevymýšlet číslo úkolu, oprava potřebuje test — žil v próze, kterou klient AI četl a prováděl ručně, jeden soubor na klienta, s tabulkou cesta-scope udržovanou člověkem. Workflow, jehož sémantika žije v promptu, je nezverzované, nevynutitelné, netestovatelné a pravdivé pro právě jeden nástroj.

Co existuje nyní

flowchart TD
    policy["<b>.ai/repo/policy.yaml</b><br/><code>commit:</code><br/>the width, three levels"]
    log["<b>git log</b><br/>at most 1500 commits"]
    status["<b>git status</b><br/>this working tree"]

    subgraph domain["apps/majordomus-cli/src/commit/"]
        direction TB
        header["<b>header</b> · the one grammar<br/><b>message</b> · header, body, trailers"]
        pol["<b>policy</b> · what a commit is held to"]
        scopes["<b>scopes</b> · the vocabulary, learned"]
        plan["<b>plan</b> · the tree, grouped, fingerprinted"]
        verdict["<b>verdict</b> · the judge"]
    end

    policy --> pol
    log --> scopes
    status --> plan
    header --> verdict
    pol --> verdict
    scopes --> verdict
    plan --> verdict

    hook["<b>commit-msg hook</b><br/>one message, with its paths"]
    gate["<b>scripts/ci/commit-policy</b><br/>the history, ratcheted"]
    cli["<b>majordomus commit</b><br/>a person"]
    mcp["<b>MCP tools + resources</b><br/>an agent"]
    api["<b>GET /api/v1/commit/…</b><br/>a program"]

    verdict --> hook
    verdict --> gate
    domain --> cli
    domain --> mcp
    domain --> api

    classDef source fill:#eef2ff,stroke:#4f46e5,color:#1e1b4b
    classDef surface fill:#ecfdf5,stroke:#059669,color:#064e3b
    class policy,log,status source
    class hook,gate,cli,mcp,api surface

Čtyři schopnosti, deklarované jednou v apps/majordomus-cli/src/capability/builtin/commit.rs, každá promítnutá na každý povrch, který politika expozice připouští:

schopnostna co odpovídáCLIMCPHTTP
commit.scopeskteré rozsahy tato historie používá, jak často, o kterých adresáříchmajordomus commit scopesmajordomus_commit_scopes, majordomus://commit/scopesGET /api/v1/commit/scopes
commit.planco by pracovní strom commitnul, rozdělené, s otiskemmajordomus commit planmajordomus_commit_plan, majordomus://commit/planGET /api/v1/commit/plan
commit.validateverdikt k jedné zprávěmajordomus commit validatemajordomus_commit_validateGET /api/v1/commit/validate
commit.historykaždý commit v rozsahu, v jednom průchodumajordomus commit historymajordomus_commit_historyGET /api/v1/commit/history

Nic v té tabulce se neregistruje nikde dvakrát. Název nástroje MCP, trasa a příkazová řádka jsou pole deklarace schopnosti; operace OpenAPI, payload Cockpitu, shellové doplňování a docs/generated/capabilities.md se z ní odvozují a majordomus capabilities projections --unmet shodí build, když deklarace tvrdí příkazovou řádku, kterou spustitelný soubor nemá.

Samotné provedení commitu tu záměrně není. git commit je mutace repozitáře a politika expozice (command_graph::policy) zastavuje každý strojový povrch u lokální mutace. Agent se smí ptát, čím by commit byl a zda zpráva projde; commituje člověk. Podsystém je tak tvarován: plánovač i soudce jsou čisté funkce stromu a zprávy.

Gramatika

Jeden parser, commit::CommitHeader::parse, totální a nikdy neselhávající:

  feat(commit)!: the header is parsed once
  ^^^^ ^^^^^^ ^  ^^^^^^^^^^^^^^^^^^^^^^^^
  word scope  breaking            subject

Changelog a soudce čtou stejný parse a liší se jen v tom, co dělat s hlavičkou, která není konvenční. Pro changelog to není selhání — commit, který nikdo nenapsal konvenčně, se přesto stal, a changelog, který by jej vynechal, by lhal o tom, co release obsahuje. Pro soudce je to jeden nález, commit.not_conventional, a jeho důsledky se záměrně nehlásí jako samostatné nálezy: ten, kdo opravuje update stuff, nepotřebuje navíc slyšet, že jeho rozsah není znám.

Slova typů jsou slova ChangeKind, z nichž už changelog vykresluje nadpisy. V politice není klíč types:, protože druhá kopie těch slov je přesně duplikace, kterou tento subsystém odstraňuje. merge je mezi nimi: tento repozitář píše merge: bring origin/master into feature/x ručně pro integrace, takže tyto předměty se drží stejné šířky a stejných odkazů jako všechny ostatní, místo aby byly vyňaty z kontroly úplně.

Politika

commit: v .ai/repo/policy.yaml, jehož tvar vlastní schéma majordomus.policy/v1 a z něhož se generuje share/allow/policy.txt:

commit:
  subject_max_chars: 100
  scope_unknown: warning
  fix_requires_test: warning
  reference_unresolved: error
  breaking_unexplained: error

subject_max_chars je změřeno, ne zvoleno. Konvence gitu je 72; přes 1161 ne-merge commitů tohoto repozitáře je medián předmětu 73 znaků a 95. percentil 98. 100 je to, co tento projekt deklaruje pro řádek čehokoli, a šířka, kterou tato historie splní. Mez, kterou porušuje polovina historie, není mez — je to šum, který lidi učí kontrolu ignorovat.

Tři úrovně jsou soudy, o nichž se repozitáře mohou rozumně lišit. off je hodnota, ne absence: repozitář, který rozhodl, že se na něj kontrola nevztahuje, učinil rozhodnutí a rozhodnutí stojí za to přečíst zpět.

Nálezy

kódzávažnostco to znamená
commit.not_conventionalchybahlavička není type(scope): subject
commit.subject_emptychybanic za dvojtečkou
commit.subject_too_longchybaširší než subject_max_chars, měřeno celé
commit.subject_trailing_periodchybasubjekt je titulek, ne věta
commit.unknown_scopepolicyrozsah, který historie nepoužila
commit.breaking_unexplainedpolicy! bez těla a bez BREAKING CHANGE:
commit.unresolved_referencepolicyid záznamu, které vrstva nedrží
commit.fix_without_testpolicyfix bez testu mezi svými soubory

Každé je Diagnostic — stejná závažnost, kód a zpráva, kterými hlásí zbytek tohoto spustitelného souboru, takže zjištění dorazí do terminálu, ke konzumentovi JSON i ke klientovi MCP stejně.

Slovník rozsahů, naučený, ne deklarovaný

Obvyklý způsob, jak odpovědět na „do jakého rozsahu tato změna patří?“, je tabulka vzorů cest. V den napsání je správná; pak se přidá nebo přejmenuje adresář, nebo se rozdělí podsystém, a tabulka jmenuje rozsah, který historie přestala používat před měsíci, a nic si toho nevšimne — tabulka nemá jak se mýlit.

commit.scopes místo toho čte odpověď z historie. Každý commit je vzorový příklad toho, do jakého rozsahu patří množina cest, rozhodnutý tím, kdo změnu provedl, a udržený tím, kdo ji zrevidoval. Čte se nejvýše 1500 commitů; rozsahy se počítají a spolu s nimi i asociace každého rozsahu s předponami adresářů hlubokými čtyři segmenty.

$ majordomus commit scopes
learned from 1161 commit(s), at most 1500
  derive                211  site, site/data, site/data/registry
  site                  134  site, site/data, scripts
  ci                     60  docs, scripts, site
  plan                   44  site, site/data, site/data/generated
  …

Rozsah mimo slovník je varování, nikdy zamítnutí: inference nesmí zamítnout první commit subsystému, který nikdy neviděla. Slovník nepotřebuje údržbu — subsystém commitnutý dnes je v něm dnes a ten, kterého se rok nikdo nedotkl, klesne sám.

Změřeny jsou i čtyři segmenty. Zdroj tohoto repozitáře žije na apps/majordomus-cli/src/<subsystem>/; tři segmenty končí o úroveň nad podsystémem, kde má commity tucet rozsahů a žádnou cestu nelze od jiné odlišit.

Plán

$ majordomus commit plan
branch       feature/the-commit-is-an-intent · no upstream
tree         16 staged, 0 unstaged, 0 untracked
fingerprint  11a032984c6f @ 8998e11fd

commit 1    <type>(release): <subject>
  why        4 file(s) under apps/majordomus-cli/src/release, which 8 prior commit(s) scoped `release`
  …

O tom výstupu stojí za to říct tři věci.

Předmět je záměrně prázdný. Co změna udělala, je jediná věc, kterou žádný důkaz ve stromu nedokáže vyslovit, a plánovač, který by o tom napsal sebejistou větu, by do historie psal fikci. Rozsah a druh jsou odvozeny tam, kde je důkazy rozhodují; věta je vaše.

Seskupení je doporučení s připojeným zdůvodněním, nikdy automatické rozdělení. Cesty, které historie označuje stejným rozsahem, jsou jeden commit a zdůvodnění říká, kolik dřívějších commitů to říká. Cesty v adresářích, na které má právo více rozsahů stejně, jsou jedna skupina a zdůvodnění to říká, což je jiná situace než adresář, který historie nikdy nezařadila, a vede k jinému dalšímu kroku. Při nízké jistotě se nic nedělí.

Otisk je část pro více agentů. Plán se odvozuje ze stromu v daném okamžiku. V repozitáři, na kterém pracuje jeden člověk, je to detail; v tomto, kde několik workerů sdílí checkout a další sdílejí repozitář, plán spočítaný při jednom HEAD a provedený při jiném commituje soubory, které někdo jiný stageoval, pod zprávou o práci, která už není tím, co se změnilo. Otisk tvoří repozitář (společný adresář gitu), worktree (cesta tohoto checkoutu), HEAD a hash přes každou změnu s jejím stagem a stavem. Cokoli jedná podle plánu, jej nejprve porovná se stromem před sebou, a co ohlásí, je věta:

HEAD moved from a1b2c3d4e to e4f5a6b70 since the plan was made
the plan is of another worktree (/repo-wt/feature/x rather than /repo)

Není to zámek a nezabrání to závodu. Odmítá být tím, kdo v něm potichu prohraje.

Kde se vynucuje

okamžikco běžínaměřeno
commit-msg.githooks/commit-msg → commit.validate s připravenými cestami806 ms
kontrolascripts/ci/commit-policy → commit.history, dvakrát: větev a historie1720 ms
CIkontrola commit-policy v jobu structurejako výše

Jsou to čísla z debug sestavení na vytíženém stroji, což je nejhorší případ, s jakým se člověk setká. Tři příkazy čtoucí historii stojí asi sekundu každý — commit scopes 957 ms, commit plan 926 ms, commit history 992 ms nad 1788 commity — a nic na horké cestě z toho neplatí nic: env enter má 38 ms proti rozpočtu 750 ms, completion query 11 ms, --help 10 ms, a žádný se logu nedotýká. Historie se čte jen tam, kde už člověk čeká na git.

Hook běží v jediném okamžiku, kdy existují zpráva i soubory, proto se tam lze zeptat fix_requires_test a nikde jinde: oprava bez testu mezi soubory stojí za povšimnutí, dokud je přidání jednoho levné. Kontrola čtoucí historii žádné cesty nezná, a proto tento nález nečiní — soud, jehož důkaz chybí, se neprovede, místo aby se hádal.

Hook je registrován pod enforcement: v .ai/repo/policy.yaml jako commit-policy-on-message, což způsobí, že jej majordomus doctor sesouhlasí: cesta se musí vyřešit, být spustitelná a být volána .githooks/commit-msg, aniž by byl její exit kód spolknut.

Baseline

54 commitů této historie nesplňuje politiku. Každý je publikován, takže jejich přepsání nepřichází v úvahu. Počet žije v .ai/repo/commit-policy-baseline.txt; kontrola selže, když vzroste, a ohlásí, když klesne. Commity, které větev přidá, podléhají politice bez výhrad a bez baseline, protože hook tyto zprávy odmítl už při psaní — selhání tam znamená, že hook byl obejit nebo se politika posunula.

$ scripts/ci/commit-policy
commit-policy: branch 8998e11fd..HEAD, 0 failing
commit-policy: history 54 failing, baseline 54

Checkout bez trunku, se kterým by se porovnával, ohlásí, že nic neměřil, místo aby hlásil úspěch.

Použití

$ majordomus commit plan                          # what this tree would commit, and why
$ majordomus commit scopes                        # the vocabulary, and what it was learned from
$ majordomus commit validate <<'EOF'              # one message, before writing it
feat(commit): a subject
EOF
$ majordomus commit validate --rev HEAD           # the message of a commit already made
$ majordomus commit history origin/master..HEAD   # this branch's commits
$ majordomus commit plan --format json            # the same answer, for a program

Vše výše funguje offline. Nic v tomto subsystému nesahá do sítě a nic, co se týká vstupu do repozitáře, doplňování slova nebo odpovědi na --help, nečte historii — slovník se učí ve chvíli, kdy se commit plánuje nebo posuzuje, což je chvíle, která už čekání na git zahrnuje.

Důkaz

cokde
pravidlo.ai/repo/rules/project/conventional-commits.v2.md (blokující)
jednotkaapps/majordomus-cli/src/commit/ — 46 testů vedle kódu, který posuzují
behaviorálnítest/cases/274_commit_policy.sh — skutečné repozitáře, skutečné worktree, skutečný hook
kontrolascripts/ci/commit-policy, deklarováno v .ai/repo/ci/gates.yaml
deklaraceapps/majordomus-cli/src/capability/builtin/commit.rs
bash test/run.sh 274_commit_policy
scripts/ci/commit-policy
cargo test --manifest-path apps/majordomus-cli/Cargo.toml --lib commit::

Co záměrně nedělá

Neposuzuje, zda je předmět dobrá věta, zda je změna atomická ani zda stála práce za udělání. To rozhoduje recenzent a validátor, který by předstíral opak, je validátor, kterému nikdo nevěří.

Nevytváří úkoly, nepushuje ani neotevírá pull requesty. To jsou vzdálené mutace s vlastními způsoby selhání a celá hodnota tohoto podsystému je v tom, že je čistou funkcí stromu a zprávy: funguje offline, nemůže uspět napůl a každou jeho odpověď lze přepočítat a ověřit.

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.