Not translated yet — page language: Russian

Ci Load Distribution 2026 07 31

Обновлено: 2026-08-02

CI: распределение нагрузки — где на самом деле уходит время (AD-1293)

Статус: research, только замеры и выводы. Ничего в конфигурации CI,
раннеров и машин этим документом не менялось.
Окно замера: 2026-07-30 02:17 UTC → 2026-07-31 02:17 UTC (24 часа).
Источник чисел: GitLab REST API проекта agadron/aero-forge (81171473),
эндпоинты /jobs, /pipelines, /runners, /pipeline_schedules,
/jobs/:id/trace; конфигурации раннеров прочитаны по ssh с nas и buildbox.
Выборка: 243 пайплайна, 1731 джоба.

0. Короткий ответ на постановку

Постановка звучала как «разгрузить единственный shell-раннер и равномернее
распределить нагрузку». Замеры этого не подтверждают.

Shell-раннер aero-forge-runner занят 202 минуты из 1440 — 14% суток.
Он не является узким местом. Раздача нагрузки по машинам уже сделана в AD-706:
build, test, build-images, ci-base и youtrack-* давно уезжают на
docker-раннеры, и половина из них — на buildbox.

Три вещи, которые действительно стоят времени:

  1. test — 638 из 961 раннер-минуты в сутки (66% всего CI) и 138 секунд
    из 231 секунды медианного develop-пайплайна. 12121 теста, pytest — 88%
    времени джобы. Всё остальное вместе меньше.
  2. Прод-машина несёт 629 мин/сут CI против 331 у простаивающего buildbox
    и почти вся эта нагрузка идёт не через shell-раннер, а через
    docker-раннер на той же машине. Конкуренция с продом реальна, но её
    источник не тот, который назван в постановке.
  3. Ядра переподписаны в 2–4 раза. pytest -n auto в docker-executor видит
    ядра хоста, а не долю раннера; при limit=4 на buildbox это 64 процесса
    на 16 ядер. Отсюда разброс времени test в 3.2 раза на одном и том же
    наборе тестов.

Если делать что-то одно — это не перенос джоб между машинами, а потолок
параллелизма у pytest. Если делать что-то второе — закрепить test за
buildbox, чтобы снять его с прод-машины.


1. Инвентаризация раннеров

Проектных раннеров у agadron/aero-forge три (групповых нет; общие
GitLab SaaS-раннеры доступны, но не используются — все джобы имеют теги).

id описание хост executor теги run_untagged limit
52629726 (без описания) nas shell aero-forge-runner нет 1
54345107 docker-build on tartarus (aero) nas docker docker-build да 2
54373997 buildbox (andrey-ms7e06, 16c/32G) buildbox docker docker-build нет 4

concurrent — 5 на nas (там же живут два раннера чужого проекта
build-version-counter: bvc-runner shell и docker-build (bvc)), 4 на buildbox.

Машины

nas (tartarus) buildbox (andrey-ms7e06) botter
ядер / RAM 12 / 31 ГБ 16 / 31 ГБ 4 / 7 ГБ
load average 14.40 / 11.39 / 11.19 3.48 / 12.62 / 11.92
диск свободно 284 ГБ из 457 806 ГБ из 931
что ещё крутится aero-web, aero-cad, cortex-mongo, registry, uptime-kuma, netdata, build-version-counter, весь Nextcloud AIO (14 контейнеров), Ollama, GPU только раннер MCP-стек

LA 14.4 при 12 ядрах на nas — машина перегружена до учёта CI.
Nextcloud AIO на прод-машине к CI отношения не имеет, но в конкуренции за
ядра участвует; при разговоре о «конкуренции CI с продом» это стоит держать
в голове.

Про постановку: утверждение «buildbox простаивает, неизвестно на какой
проект зарегистрирован» неверно. Он зарегистрирован на agadron/aero-forge
с 2026-07-16, активен, тег docker-build, и за сутки отработал 307 джоб.
На машине есть следы параллельной подготовки другим агентом (пользователи
cortex, runner, aagafonov) — не трогались.

Сколько джоб реально может идти параллельно

Шесть: 1 (shell) + 2 (nas-docker) + 4 (buildbox), с оговоркой, что
docker-build — общий тег для двух раннеров и GitLab раздаёт между ними
произвольно.

Узкое место — не количество слотов. За сутки медиана ожидания в очереди
у всех джоб, кроме ci-base-tag, ниже 3 секунд. Узкое место — длина
критического пути одной джобы (test) и последовательность стадий.


2. Профиль пайплайна

2.1. Куда уходят раннер-минуты (24ч)

джоба прогонов суммарно медиана p90 где идёт
test 245 638.3 мин 145.2с 246.8с docker (nas 124 / buildbox 112)
scan 105 138.3 мин 94.0с 137.0с shell
youtrack-sync 112 43.8 мин 49.8с 77.4с docker
build-images 106 33.7 мин 11.5с 16.6с docker
deploy 104 31.1 мин 17.4с 59.3с shell
build 243 30.8 мин 7.5с 9.7с docker
ci-base-tag 243 19.4 мин 4.8с 5.4с shell
youtrack-reconcile 112 11.9 мин 14.9с 15.7с docker
healthcheck 104 4.8 мин 3.5с 3.9с shell
deploy-mcp-stack 114 4.2 мин 37.5с shell (86 — кнопка)
i18n-translate 1 1.9 мин 111.3с shell
infra-prune 114 1.7 мин 24.6с shell (90 — кнопка)
deploy-infra 115 0.5 мин 3.7с shell (87 — кнопка)
apply-kuma-monitors 7 0.4 мин 9.1с shell
designer-kernel-tests 6 0.0 мин ни разу не выполнялась
ИТОГО 960.6 мин

Статусы за сутки: 1123 success, 271 manual, 185 canceled, 89 created,
34 skipped, 25 failed, 4 running.

Пайплайнов: 130 MR + 112 develop-push + 1 schedule.

2.2. Критический путь develop-деплоя

Трассировка типового полного пайплайна (2718223339), время от старта первой джобы:

  +0с ..   +5с  ci-base-tag      .pre           shell-nas
  +8с ..  +15с  build            build          nas-docker
 +18с .. +156с  test             test           nas-docker    ← критический путь
 +18с ..  +28с  build-images     build-images   nas-docker
 +33с .. +129с  scan             scan           shell-nas     ← спрятан за test
+161с .. +170с  deploy           deploy         shell-nas
+173с .. +176с  healthcheck      healthcheck    shell-nas     ← ПРОД УЖЕ ОБНОВЛЁН
+180с .. +231с  youtrack-sync    notify         nas-docker    ← +51с хвоста
+181с .. +197с  youtrack-reconcile notify       buildbox

Агрегат по 106 develop-пайплайнам: wall-clock медиана 231с, p90 351с.
Сумма длительностей джоб медианно 309с → параллелизм всего 1.34x.

По 130 MR-пайплайнам: медиана 161с, p90 272с. Здесь test — практически
весь пайплайн.

Что из этого следует.

  • test = 60% wall-clock develop. Всё остальное вместе — 40%.
  • scan (96с на shell-раннере) полностью спрятан за test — идёт с 33-й
    по 129-ю секунду, пока test идёт до 156-й. Перенос scan на другую машину
    не ускорит пайплайн ни на секунду. Это надо сказать прямо, потому что
    ровно этот перенос выглядит очевидным.
  • deploy занимает 9 секунд. Собственно раскатка прода — не проблема.
  • Хвост youtrack-sync — 51с после того, как прод уже обновлён и проверен
    healthcheck'ом. Это 22% wall-clock, потраченные на закрытие тикетов.
  • build (7.5с) стоит между ci-base-tag и test и стоит пайплайну ~10с
    накладных расходов планировщика на каждом прогоне.

2.3. Что съедает время внутри test

Разбор лога джобы 15636804059 (успешный прогон, 224с):

фаза время
подъём контейнера + git checkout 3.4с
lint незапиненных зависимостей + напоминание про changelog ~4с
JS-юнит-тесты (node tests/test_*.js, AD-624) ~11с
pytest (12121 passed, 6 skipped) 196.0с
scripts/coverage_ratchet.py 1.0с
выгрузка артефактов 6.0с

Вывод простой: test — это pytest, а pytest — это 12121 теста.
Никакой обвязки, которую имело бы смысл резать, внутри джобы нет.
Ускорять здесь можно только двумя способами — меньше тестов (AD-966 уже про
это) или лучше параллелизм (см. §4.1).


3. Где shell-executor вредит — и где нет

3.1. Занятость shell-раннера (24ч, limit=1)

джоба прогонов минут
scan 87 138.3
deploy 80 31.1
ci-base-tag 239 19.4
healthcheck 80 4.8
deploy-mcp-stack 8 4.2
i18n-translate 1 1.9
infra-prune 4 1.7
deploy-infra 8 0.5
apply-kuma-monitors 3 0.4
итого 510 202.2 мин = 14% суток

14% занятости — это не бутылочное горло. Но limit=1 означает, что даже
при низкой занятости конкуренция бывает: из 510 джоб 70 ждали дольше 10
секунд
, суммарно 65 минут очереди. Три худших случая — ci-base-tag с
ожиданием 237с, 214с и 200с. То есть .pre-джоба на 5 секунд, от которой
через needs зависит весь пайплайн, стояла в очереди четыре минуты за
единственным слотом, занятым scan.

3.2. Что обязано остаться на shell

  • deploy — доступ к docker-демону прода и /opt/cortex, resource_group: production.
  • healthcheck — проверяет реальный прод после раскатки.
  • deploy-infra, infra-prune, deploy-mcp-stack, apply-kuma-monitors
    инфра-операции на конкретных хостах (sudoers-wrapper для nginx, compose
    в /opt/infra, ssh на botter).

Суммарно это 42.7 мин/сут — 3% суток. Прод-специфичная часть shell-раннера
почти ничего не стоит.

3.3. Что уедет без разговоров

  • ci-base-tagsha256sum четырёх файлов. Прод-докер не нужен. Держать
    джобу, гейтящую весь пайплайн, на раннере с limit=1 — прямой вред,
    измеренный в 237 секундах худшего ожидания.
  • i18n-translate — ходит в Ollama по сети.

3.4. scan — отдельный случай

AD-706 закрыт (Done, Major) с формулировкой «перенести build-images + scan
на buildbox-раннер». Перенесён только build-images. В .gitlab-ci.yml у
scan стоит явный комментарий, что он остаётся на shell, потому что
«Trivy sibling-контейнеры маунтят host-пути».

Это 138 мин/сут — 68% всей нагрузки shell-раннера. Но, как показано в §2.2,
перенос не ускорит пайплайн: scan спрятан за test. Выигрыш от переноса —
освобождение единственного слота (то самое ожидание ci-base-tag) и снятие
нагрузки с прод-машины, а не wall-clock.

Отдельно стоит отметить расхождение: тикет закрыт целиком, а сделана половина.

3.5. Общее состояние между джобами

Заявленный в постановке риск «общее состояние shell-раннера — кеши, .venv,
мусор» на практике не подтвердился. Все джобы, где такое состояние
накапливалось бы (build, test, сборки образов), уже в docker-executor;
на shell остались короткие джобы без установки зависимостей. В логе
deploy-infra видно Reinitialized existing Git repository in /home/gitlab-runner/builds/... — переиспользуемый рабочий каталог есть,
но с git depth 20 и чекаутом в detached HEAD; следов протухания в выборке
не найдено.


4. Куда распределять

4.1. Сначала — потолок параллелизма (важнее любого переноса)

.python-test гоняет pytest -n auto. В docker-executor без cpu-лимита
auto определяет число воркеров по ядрам хоста, а не по доле раннера.
Ни у nas-docker, ни у buildbox в [runners.docker] не заданы ни cpus,
ни memory — проверено чтением /etc/gitlab-runner/config.toml на обеих
машинах.

раннер ядер limit воркеров при полной загрузке
buildbox 16 4 4 × 16 = 64 процесса на 16 ядер
nas-docker 12 2 2 × 12 = 24 процесса на 12 ядер + весь прод

Измеренное следствие — разброс времени test на неизменном наборе тестов:

раннер n min медиана p90 max
buildbox 93 90.6с 134.5с 215.2с 289.4с
nas-docker 114 132.2с 152.1с 273.1с 317.5с

От 90.6с до 317.5с — 3.5x на одних и тех же 12121 тестах. Это не тесты,
это конкуренция за ядра.

AD-1294: заменить -n auto на явный бюджет, согласованный с limit.
Правка в несколько строк, ничего не переносится, эффект — на самой дорогой
джобе CI.

4.2. Предлагаемая раскладка по тегам

тег раннеры джобы обоснование
aero-forge-runner (shell, nas, limit 1) 52629726 deploy, healthcheck, deploy-infra, deploy-mcp-stack, infra-prune, apply-kuma-monitors доступ к проду обязателен; 43 мин/сут
heavy-test (новый, buildbox) 54373997 test, designer-kernel-tests снять 638 мин/сут с прод-машины; на buildbox быстрее на 18с медианы
docker-build (nas-docker + buildbox) 54345107, 54373997 ci-base, ci-base-tag, build, build-images, youtrack-sync, youtrack-reconcile, i18n-translate лёгкие, резервируются двумя машинами
docker-build — кандидат scan если Trivy получится увести с host-путей (§3.4)

4.3. Ограничение (а): агенты основателя на buildbox

Забирать все 16 ядер нельзя. Сегодня потолка нет вообще: limit=4,
concurrent=4, без cpus/memory — CI способен занять машину целиком.

Предложение — бюджет вместо «кто успел»:
* задать cpus в [runners.docker] раннера buildbox (потолок CI);
* согласовать с ним -n у pytest;
* остаток явно закрепить за агентами и записать в docs/dev/.

Порядок величин: за сутки buildbox отработал 331 минуту = 23% времени одного
слота. Даже после переезда всего test (638 мин) суммарно выходит ~970
мин/сут на 4 слота — примерно 17% ёмкости. Запас под агентов есть, но его
надо зафиксировать конфигурацией, а не надеждой.

AD-1304.

4.4. Ограничение (б): деплой остаётся у прода

Соблюдено: deploy/healthcheck/инфра-джобы в раскладке не двигаются.

4.5. Совместимость с переходом develop на resource_group

Решение (в работе у другого агента) — пайплайны на develop перестают отменять
друг друга и идут последовательно. Что это меняет для чисел выше:

  • Пропускная способность develop становится равна 1 / wall-clock. Сегодня
    wall-clock = 231с медиана → потолок ~15 пайплайнов в час. За измеренные сутки
    было 112 develop-пайплайнов, ночью — плотнее; запас есть, но не кратный.
  • Хвост youtrack-sync в 51с бьёт напрямую: это 22% времени
    последовательного окна, потраченные после того, как прод уже обновлён.
    При 112 пайплайнах — около 1.6 часа последовательного окна за сутки (AD-1301).
  • Отмены перестанут освобождать слоты. За сутки 185 джоб отменены,
    на них сожжено 17.4 раннер-минуты — сама по себе величина малая, но
    shell-раннер с limit=1 будет занят чаще, а значит ожидание
    ci-base-tag (сегодня до 237с) станет типичным, а не редким (AD-1295).

Ни одно предложение этого документа переходу не противоречит; два из них
(AD-1295, AD-1301) становятся после перехода заметно ценнее.


5. Что можно просто не делать

Отдельный раздел, как и просили. Здесь честно: большого выигрыша по времени
тут нет
, вопреки ожиданию. Path-based gating (AD-707) и build-once/deploy-many
(AD-526) уже сняли самое очевидное.

5.1. Что уже не делается (и работает)

  • AD-707: из 106 develop-пайплайнов 26 (25%) пропустили
    build-images/scan/deploy/healthcheck как docs-only. Механизм живой и
    экономит примерно четверть тяжёлых прогонов.
  • AD-599: ci-base за сутки не пересобиралась ни разу (нет прогонов в
    выборке) — хэш-тег работает, пересборка образа без изменений не происходит.
  • AD-526: build-images медиана 11.5с — образы тянутся по tree-hash,
    а не собираются заново.

5.2. Артефакты, которые никто не читает

Единственная явно лишняя работа, которую удалось измерить.

артефакт test размер потребитель
artifacts.zip (report.html + coverage_html/) 6.3 МБ не найден
job.log 3.76 МБ человек, изредка
junit.xml.gz 0.22 МБ MR-виджет GitLab
cobertura-coverage.xml.gz 0.08 МБ бейдж покрытия (AD-967)

10.37 МБ × 245 прогонов = 2.54 ГБ/сут. job_artifacts_size проекта —
7.06 ГБ из 7.14 ГБ всего storage. Выгрузка стоит 6с в каждой джобе.

--cov-report=json трогать нельзя — его читает scripts/coverage_ratchet.py
(AD-968). Речь только про self-contained HTML и coverage_html/. → AD-1302.

5.3. Джоба build

7.5с полезной работы (compileall) ценой полного цикла планировщика, git
checkout и подъёма контейнера — ~10с накладных на каждом из 243 пайплайнов.
Сливается в test первой секцией. → AD-1303.

5.4. Джобы, которые всегда allow_failure и потому бессмысленны

Искалось отдельно. Найдено следующее.

designer-kernel-tests — механизм есть, но покрасить ничего не может.
Джоба заведена AD-1274 по итогам AD-1273 («179 node-тестов ядра v2 не гоняются
нигде»). Её правила:

  • на MR и develop — when: manual + allow_failure: true.
    За сутки 6 экземпляров, статус manual, длительность 0 — ни разу не нажата;
  • единственный автоматический путь — $CI_PIPELINE_SOURCE == "schedule".
    В проекте ровно одно расписаниеi18n, cron 19 2 * * * Asia/Yerevan;
  • allow_failure: true стоит и на уровне джобы, и в каждом rules-ветвлении —
    то есть даже отработав по расписанию и упав, она оставит пайплайн зелёным.

Проверено по последнему schedule-пайплайну (2720217201, 2026-07-30 23:07 UTC):
там семь джоб — ci-base-tag, build, test, build-images, scan, infra-prune, i18n-translate. designer-kernel-tests отсутствует (вмержена позже).
На момент замера джоба не выполнялась ни разу.

Оговорка честности ради: allow_failure у ручной джобы поставлен осознанно
по AD-1276 (ручная джоба без него блокирует пайплайн), и это верно. Дефект —
в комбинации: единственный авто-путь раз в сутки + флаг, гасящий результат
и на этом пути тоже. → AD-1300.

deploy-infra — уже известно, дополнено замером. За сутки создавалась 115
раз: 87 остались кнопкой, 20 отменены, 8 стартовали — 7 упали, 1 прошла.
Все падения — docker compose up -d в /opt/infra, конфликт container_name
(registry уже занят контейнером вне compose-проекта). nginx-часть при этом
проходила успешно, что дополнительно маскировало проблему.
Уже покрыто AD-1251 (миграция контейнеров выполнена 2026-07-31); замер
добавлен туда комментарием. Дубль не заводился.

Ручные инфра-джобы. infra-prune (90 из 114 — кнопка), deploy-mcp-stack
(86 из 114), apply-kuma-monitors — висят кнопкой в каждом develop-пайплайне.
Это осознанное решение канона (.claude/rules/cicd.md), не дефект; но стоит
знать, что 271 из 1731 джобы за сутки (16%) — это ненажатые кнопки.

youtrack-sync срабатывает реже, чем кажется. Создана 112 раз, реально
выполнена 47: 41 осталась в статусе created, 19 отменены, 5 skipped.
То есть штатный механизм закрытия тикетов отрабатывает менее чем в половине
develop-пайплайнов. Под эту дыру заведена youtrack-reconcile (AD-810) —
у неё ровно та же картина (47 из 112). Покрывает ли она пропуски полностью,
из этих чисел не видно; отмечено в AD-1301.


6. Риски второго раннера

Тег docker-build носят два раннера, и GitLab раздаёт джобы между ними
произвольно. Одна и та же джоба может быть зелёной на одном и красной на
другом, и механизма, который бы это заметил, нет.

Что дрейф уже закрывает: общий образ $CI_BASE_IMAGE_HASH (AD-599) —
версии Python и зависимостей приезжают из registry по хэш-тегу, разъехаться
не могут. Это главный источник, и он закрыт.

Что остаётся открытым:

  • число ядер — 12 против 16, а pytest -n auto от него зависит напрямую
    (§4.1). Тест, чувствительный к параллелизму или таймингу, будет флапать
    «через раз» и выглядеть случайным;
  • локальный кэш образовpull_policy = ["if-not-present"] на обоих;
    на buildbox уже 8 тегов ci-base и десятки cortex-aero-web:tree-*;
  • /cache-том — свой на каждой машине, содержимое не сверяется;
  • docker-сокет — на nas в контейнер джобы прокинут прод-демон
    (/var/run/docker.sock, там же aero-web, cortex-mongo, Nextcloud);
    на buildbox — отдельный. Джоба, собирающая образ, работает в разном окружении;
  • ретенция — на nas есть infra-prune, на buildbox нет ничего.

Сигнал, который уже виден в числах

Падения test за сутки распределены неравномерно:

раннер success failed доля падений
nas-docker 114 5 4.2%
buildbox 93 12 11.4%

Разница в 2.7 раза. Это наблюдение, а не вывод: раннеры выбираются не
случайно относительно веток (какой свободен, тот и берёт), и ночью на buildbox
могли попасть более «сырые» MR. Но проверить стоит — если перекос подтвердится,
это не тесты, а машина.

Чем лечится и чего стоит

Два взаимоисключающих пути:

  1. Держать паритет двух машин — постоянные накладные расходы навсегда:
    сверка ядер, кешей, ретенции, штамп окружения в логе.
  2. Прибить каждую джобу к одному раннеру (heavy-test → только buildbox) —
    разовая правка тегов, класс «у меня зелёно, у него красно» исчезает целиком.
    Цена: теряется резервирование, падение buildbox блокирует все MR,
    потому что test — гейт мержа.

Выбор за основателем. Замеры говорят в пользу второго (выигрыш от закрепления
измерим, выигрыш от резервирования — нет), но это решение про риск, а не
про производительность. → AD-1305.


7. Что проверить не удалось

Раздел обязательный, здесь без сглаживания.

  1. MCP-сервер ci не работает — отвечает Invalid request parameters на
    любой вызов. Обошли прямым GitLab REST API с токеном из .mcp.secrets.json.
    Отсутствие ответа MCP за отсутствие проблемы не принималось.
  2. MCP-сервер youtrack не работает — та же ошибка на всех действиях,
    включая youtrack_projects. Дополнительно: YOUTRACK_TOKEN в
    .mcp.secrets.json протух
    — YouTrack REST отвечает Invalid token.
    Рабочий токен взят из окружения MCP-стека на botter. Это отдельная
    проблема, тикет по ней не заводился (вне рамок исследования), но
    зафиксировать стоит.
  3. Эффект предложений не измерен — по условию задачи ничего не менялось.
    Все цифры выигрыша (−18с медианы test на buildbox, −10с на слиянии
    build, −6с на артефактах) получены сравнением наблюдений, а не A/B.
    Нужен повторный замер после каждой правки.
  4. Не проверено, что именно требует host-путей у Trivy — вывод про scan
    опирается на комментарий в .gitlab-ci.yml, не на попытку запуска в
    docker-executor (это была бы правка CI).
  5. designer-kernel-tests не наблюдалась в работе ни разу — вывод о том,
    что она стартует по расписанию, сделан из чтения rules, а не из факта.
    Первый настоящий прогон — в ближайший nightly; результат надо посмотреть.
  6. Влияние Nextcloud AIO на LA nas не разделено — 14 контейнеров на
    прод-машине участвуют в конкуренции за ядра, но их вклад отдельно от CI
    и от aero-web не замерялся.
  7. Перекос падений test по раннерам (4.2% vs 11.4%) не объяснён
    выборка не контролировалась по веткам. См. §6.
  8. Расписание i18n показывает last_pipeline: null через API, хотя
    schedule-пайплайны исправно создаются каждый день в 23:07 UTC. Похоже на
    особенность API, но исключить проблему с привязкой расписания нельзя.
  9. concurrent = 5 на nas при сумме limit = 5 (1 shell + 2 aero-docker +
    1 bvc-shell + 2 bvc-docker = 6) — потолок ниже суммы лимитов, то есть
    раннеры чужого проекта build-version-counter конкурируют за те же слоты.
    Влияние на очередь aero-forge не измерялось.

8. План (заведённые тикеты)

Порядок — по отношению выигрыша к риску.

# тикет что выигрыш риск
1 AD-1294 убрать pytest -n auto, задать явный бюджет воркеров самая дорогая джоба CI, p90 вдвое хуже медианы правка конфигурации, ничего не переносится
2 AD-1295 ci-base-tag → тег docker-build убирает худшее наблюдавшееся ожидание (237с) у джобы, гейтящей весь пайплайн минимальный
3 AD-1296 test → отдельный тег на buildbox −638 раннер-минут/сут с прод-машины, −18с медианы buildbox становится единственным носителем гейта мержа
4 AD-1300 designer-kernel-tests не может ничего покрасить тесты ядра v2 снова окажутся невыполняемыми (AD-1273 повторно) нет
5 AD-1301 хвост youtrack-sync — 22% wall-clock develop важно к переходу на resource_group трогает закрытие тикетов — делать аккуратно
6 AD-1304 бюджет ядер buildbox между CI и агентами предотвращает конфликт с AD-1291 до его возникновения подбирать замером
7 AD-1297 scan остался на shell вопреки закрытому AD-706 освобождает 68% нагрузки shell-раннера; wall-clock не меняет неизвестно, снимается ли зависимость Trivy от host-путей
8 AD-1302 выбросить нечитаемые HTML-артефакты −2.5 ГБ/сут, −6с на прогон проверить бейджи AD-967
9 AD-1303 слить build в test −10с на пайплайн, −1 слот проверить AD-452 (пустой develop-пайплайн)
10 AD-1305 паритет двух раннеров либо закрепление джоб убирает класс «у меня зелёно, у него красно» решение про риск, а не про скорость

Смежное, дубль не заводился: AD-1251 (deploy-infra, дополнен замером),
AD-966 (аудит 12121 теста — единственный реальный путь сократить test
кардинально), AD-1291 (агенты на buildbox), AD-1273 (тесты ядра v2).


9. Как воспроизвести замеры

# токен — из .mcp.secrets.json (GITLAB_TOKEN)
for p in $(seq 1 30); do
  curl -sS -H "PRIVATE-TOKEN: $GT" \
    "https://gitlab.com/api/v4/projects/81171473/jobs?per_page=100&page=$p" \
    -o jobs_$p.json &
done; wait

Дальше — агрегация по name / runner.id / duration / queued_duration
с окном 24 часа по created_at. Критический путь строится по started_at
и finished_at джоб одного pipeline.id. Конфигурации раннеров:
sudo cat /etc/gitlab-runner/config.toml на nas и buildbox.