Zdůvodnění
Dne 2026-10-09 CI dvakrát odmítlo release 0.19.0, pokaždé kvůli něčemu, co lokální běh najde za pár sekund. Prvním byla strukturní kontrola, economics-claims, za 6 s a always: true. Druhým případ sady, 08, za 1 s. Ani jedno před pushem neběželo. Pre-push hook spustil finish --check, který hlásí požadované kontroly jako nikdy nenahlášené a žádnou z nich nespouští, a případy se vybíraly odhadem. Každé odmítnutí stálo okruh přes CI delší než hodinu, pak další derive za zámkem stroje, a to u jediné změny, na kterou vlastník čekal.
Celá úloha structure odpovědí není. Trvá asi 20 minut, sahá na API GitHubu a z jednoho stroje pushuje devět relací. Co push dluží, je ta část CI, která je levná, lokální a jistě selže stejným způsobem, vybraná podle toho, co CI měřilo.
Požadované chování
.githooks/pre-pushvoláscripts/ci/run-plan --before-pushpofinish --check. Politika to deklaruje (enforcement: structure-gates-on-push, zapojeno přesgit-hook:pre-push), takžedoctora skrze něj hook pre-commit odmítne klon, jehož hook je přestane volat.- Krok spočítá plán tohoto stromu, jako to dělá CI, a push odmítne (exit 12), když se plán spočítat nedá.
scripts/ci-planodmítne base nebo head, který nejmenuje žádný commit. Dřív pipoval selhávajícígit diffdosort, jehož stav selhání skryl, a vracel tak plán spočítaný z ničeho s kódem 0. - Kontroly. Spouští vybrané strukturní kontroly plánu, které nejsou v
network: trueoznačeny.ai/repo/ci/gates.yamla jejichž zaznamenané sekundy nejsou víc nežMJ_PUSH_GATE_SECONDS(výchozí 15). Sekundy pocházejí z.ai/repo/ci/structure-durations.tsv, kteréscripts/ci-baseline --structure-durationszapisuje z artefaktůci-metrics-structure, jež CI nahrává. Bere je od nejlevnější, dokud jejich součet zůstává vMJ_PUSH_GATE_BUDGET(výchozí 120). - Přeskočené kontroly. Každá vynechaná kontrola vypíše jeden řádek, který ji jmenuje a říká proč: sahá na síť, nemá zaznamenanou dobu trvání, je nad limitem na kontrolu, nebo je za rozpočtem. Chybějící soubor dob trvání push odmítne.
- Případy. Spouští případy, které
.ai/repo/ci/suite-durations.tsvzaznamenal nejvýšeMJ_PUSH_CASE_SECONDS(výchozí 5), po čtyřech zároveň. Jmenovitě vynechává případ, který deklarujemajordomus-exclusivenebo spouští server (serve_up,mcp_shared,serve ensure|start, launcher MCP). Rychlé je to, co zaznamenalo CI. Případ se serverem měří časování a porty a na stroji, který sdílí devět relací, selže kvůli zátěži, ne kvůli změně: pět jich tak selhalo při prvním běhu. - Mez a verdikt. Hlásí svůj naměřený čas proti
MJ_PUSH_BOUND(výchozí 180). Překročení pojmenuje nejpomalejší kroky a push nikdy neodmítne: vytížený stroj jej nesmí shodit, jinak lidé krok obcházejí. Neprošlá kontrola nebo případ push odmítne, pojmenuje je a vypíše konec svého výstupu. - Stdin. Každá kontrola a každý případ běží se zavřeným stdin. Stdin hooku je seznam refů.
test/run.shdal každému případu stdin runneru, protože úloha na pozadí pod řízením úloh si jej ponechává, takže případ, který četl stdin, čekal věčně na otevřené rouře: případ 54, 39 minut, téhož dne.
Chování při selhání
Push je odmítnut se jmény toho, co selhalo, a větou „CI would refuse this push for the same reason“. Neexistuje žádný příznak, který krok přeskočí, stejně jako neexistuje --no-verify.
Ověření
test/cases/1021_a_push_runs_what_ci_would_find_first.sh řídí krok nad plánem a trváními, které zapisuje. Dokazuje:
- spustí se levná kontrola a levná selhávající kontrola odmítne push s jejím výstupem;
- každý druh vynechané kontroly je jmenován s důvodem: síť, žádné zaznamenané trvání, přes limit na kontrolu a za rozpočtem;
- chybějící soubor s dobami trvání nebo plán, který nelze spočítat (neznámý základ), push odmítne;
- hook volá krok, politika deklaruje vynucování a plán nese síťový příznak modelu;
- případ, který čte stdin v rouře, jež se nikdy nezavře, už runner nezablokuje.
První běh kroku na vlastní branchi tu branch odmítl kvůli nepřipnutému sort (order-check), dřív než ji viděla jakákoli CI.