# Ускорение сборки и поставки Monitor / ASR / LinTO

Результат на 27 октября 2026: изменения опубликованы в `main` трёх проектов. Выполнены полная регрессия механизма отбора, адресная сборка Front и bridge, три повторные кодовые сборки worker/LinTO и проверки существующего runtime. Новые application images в этих замерах не публиковались. Подготовка и выпуск уже работающего ASR digest прошли без pull, прогрева, update и закрытия admission.

Основная исходная потеря времени была в подготовке/поставке: build LinTO 24095 занял 389,321 с, а deployment 24099 отменили через 2617,397 с. Два незавершённых ASR pull и этот deploy суммарно заняли 6239,423 с runner — около 104 минут. Конкретный зависший Docker-вызов в старом логе не установлен. Быстрые ASR-тесты сохранены: 149 тестов занимают около 5,75 с.

## Поставленные исходники

| Проект | Исходный SHA | Итоговый SHA | Строки + / − | Файлы |
|---|---|---|---:|---:|
| Front / Monitor | `553bc572` | [b40e84d7](<https://git.giscloud.ru/voice-chat/webrtc-komaroff/-/commit/b40e84d7b4d09c2eacb149eb0971d5fd77414c48>) | +706 / −111 | 29 |
| ASR / LinTO | `b4570f47` | [05a393a2](<https://git.giscloud.ru/voice-chat/py_faster_whisper/-/commit/05a393a2d725f996e45e0c4b0002f057d671b67e>) | +549 / −67 | 17 |
| rag-stack: ASR release | `9ca0c303` | [88cc3ea7](<https://git.giscloud.ru/ai-assistant/deployments/rag-stack/-/commit/88cc3ea750def075965008fa4af1c967aea46b07>) | +298 / −28 | 9 |

Итого **+1553 / −206 строк**, включая проверки и документацию, 55 файлов. Новых сервисов, таблиц, runtime-хранилищ и соединений — **0**. Добавлены локальные механизмы выбора работ, ограниченного выполнения Docker CLI и их тесты. Полные diff находятся в `evidence/changes-*.patch`, SHA и статистика — в `source-state.json`.

Работа выполнена одним writer в изолированных checkout. Пользовательские изменения основной копии сохранены. `Dockerfile.build`, корпоративные версии build-labels/dry-stack, DRS и known_hosts не изменены. Runner, registry, daemon, DNS, SSH, сети, GPU, тома, PostgreSQL и NATS не перенастраивались.

## Что изменилось

1. **Отбор по входам.** Статическая матрица учитывает общий код, Docker COPY, push/MR/явную базу, удаление и переименование файлов. Неизвестная база или путь включает полный соответствующий набор. `CI_FULL_CHECKS=1` включает все checks. Пропуск выводится как `skipped`, до установки зависимостей и запуска suite. Общие streaming/Vitest suites сохранены целиком.
2. **Сборки.** Совместимый worker/LinTO автоматически использует закреплённый code-only runtime. Изменение зависимостей, моделей или рецепта базы переключает на полную сборку. Повторные LinTO releases принимают совместимые собственные overlays; одноразовый переход с vendor image остаётся отдельным случаем. Bridge копирует только используемый код, поэтому изменение worker не пересобирает bridge.
3. **Front.** Production bundle собирается один раз в Docker. CI выполняет TypeScript, Vitest и runtime-settings; nginx проверяется в образе. Убрана обязательная сборка приложения в том же pipeline перед refresh. Проверки release-helper выполняются один раз в check job на основе фактически упакованного deployment image.
4. **Повторное использование.** Release SHA и source SHA образа разделены. Можно передать проверенный digest; активация проверяет его наличие и SHA без повторного pull/разрешения `latest`. Здоровый текущий digest возвращает `already_current`.
5. **Поставка.** Docker reads ограничены 90 с, code-image pull — 300 с, full GPU pull — 1800 с. Сохранены пределы прогрева/rollout, вложенные команды используют остаток бюджета. Длительные операции показывают этап, время и прогресс; буферы ограничены. После timeout проверяется фактическое состояние, автоматического повторного deploy нет. Конфигурация соседа и независимый restart его task проверяются раздельно.
6. **Обычный release.** Front preflight больше не запрашивает погоду, stats и RootFS всех сервисов. Проверяются необходимые зависимости. Добавлены операции по компонентам; исторические migration/repair/retirement доступны через `CI_MAINTENANCE=1`.
7. **Кэш и contexts.** npm/pip/tokenizer используют проектные пути GitLab cache с ключами зависимостей/среды/архитектуры. Хеши tokenizer проверяются при каждом использовании. Результаты тестов не кэшируются. Docker contexts исключают локальные зависимости, build outputs, временные файлы и `.repowise`, сохраняя необходимые Git-метаданные.

## Приёмка

| Критерий | Результат и доказательство |
|---|---|
| Front-only / worker-only / docs-only / helper-only | PASS: обе матрицы и Git rename fixture; реальный docs-only build [24518](<https://git.giscloud.ru/voice-chat/webrtc-komaroff/-/jobs/24518>) вывел `services: {}`. Application builds — 0. Helper-only выбирает только соответствующие release checks, приложение не собирается. |
| Shared contract, неизвестный путь/база, полный ручной режим | PASS: matrix checks в [24387](<https://git.giscloud.ru/voice-chat/webrtc-komaroff/-/jobs/24387>) и [24437](<https://git.giscloud.ru/voice-chat/py_faster_whisper/-/jobs/24437>). |
| Два последовательных кодовых выпуска LinTO | PASS в release-contract tests для HTTP и WebSocket: 13 тестов / 37 assertions, [24439](<https://git.giscloud.ru/voice-chat/py_faster_whisper/-/jobs/24439>). Два настоящих обновления модели ради теста не выполнялись. |
| Изменение зависимостей запрещает code-only | PASS: настоящие Git fixtures с изменёнными requirements worker/LinTO; `evidence/base-compatibility.log`. Полный GPU image ради этого условия не собирался. |
| Один production bundle Front | PASS: [24405](<https://git.giscloud.ru/voice-chat/webrtc-komaroff/-/jobs/24405>), один `RUN npm run build`; в frontend checks Vite build отсутствует. nginx layer успешно переиспользован из кэша. |
| Реальная сборка bridge | PASS: [24475](<https://git.giscloud.ru/voice-chat/py_faster_whisper/-/jobs/24475>), `pip check`, импорт StreamingBridge и вычисление локального VAD окна. |
| Подготовленный / уже работающий digest | PASS: [24489](<https://git.giscloud.ru/ai-assistant/deployments/rag-stack/-/jobs/24489>) подготовил существующий digest без pull; [24490](<https://git.giscloud.ru/ai-assistant/deployments/rag-stack/-/jobs/24490>) вернул `already_current`, без pull/candidate/update. |
| Timeout, потеря подготовленного образа, mutable tag, restart соседа | PASS: bounded-process tests, Front release tests, LinTO tests и 22 ASR release tests / 68 assertions. Проверены остановка клиента, ограничение вывода, отказ до изменения target и отсутствие повторного update. |
| Полная Front регрессия | PASS: все пять checks [pipeline 5437](<https://git.giscloud.ru/voice-chat/webrtc-komaroff/-/pipelines/5437>). Python: 248 passed, 13 subtests, **103 skipped**; они не выдаются за выполненные. Отдельно реально выполнены 84 integration tests с PostgreSQL/NATS и 4 browser/NATS tests; Vitest — 444 теста. |
| ASR и release checks | PASS: streaming — 149 тестов; bridge/status — 7/6; LinTO — 13. После исправления COPY выполнена только выбранная streaming-группа в [5440](<https://git.giscloud.ru/voice-chat/py_faster_whisper/-/pipelines/5440>), release suites явно пропущены. rag-stack checks и реальный already_current — [5441](<https://git.giscloud.ru/ai-assistant/deployments/rag-stack/-/pipelines/5441>). |

Итоговый Front commit содержит только результаты замеров поверх проверенного кода `ed1553be`. Его [pipeline 5442](<https://git.giscloud.ru/voice-chat/webrtc-komaroff/-/pipelines/5442>) проверил docs-only: все пять application suites **пропущены**, выполнена проверка исходников/документации. Статус pipeline `manual` означает оставшиеся ручные jobs; это не утверждение, что каждый deployment job выполнен.

## Измерения «было → стало»

Время ниже — длительность jobs без очереди. Это отдельные наблюдения на существующем runner, не нормативы и не контролируемое сравнение одинакового состояния кэша.

| Работа | Было, с | Стало, с | Разница, с | Разница, % |
|---|---:|---:|---:|---:|
| Все пять Front checks | 380,182 | 315,774 | −64,408 | −16,94% |
| Python checks | 109,385 | 95,957 | −13,428 | −12,28% |
| Browser NATS checks | 20,273 | 20,563 | +0,290 | +1,43% |
| Frontend checks | 46,140 | 51,777 | +5,637 | +12,22% |
| Ruby checks | 12,199 | 15,241 | +3,042 | +24,94% |
| Integration checks | 192,185 | 132,236 | −59,949 | −31,19% |
| Front preflight | 90,245 | 19,026 | −71,219 | −78,92% |
| ASR prepare: ранее с pull → существующий digest | 14,917 | 10,470 | −4,447 | −29,81% |

Первая строка сопоставляет jobs 24120–24124 и 24384–24388. Preflight — 24147 → 24409. Более быстрые общие результаты не означают, что ускорился каждый suite: таблица показывает и выросшие времена.

Docs-only больше не исполняет application suites. Пять коротких guard jobs суммарно заняли **57,231 с**: по сравнению с прежними пятью полными checks 380,182 с это −322,951 с (−84,95%). Это намеренное сокращение выполняемой работы, а не ускорение тех же тестов. Сохранились затраты на запуск jobs, checkout, cache lookup и старт integration services. Сам build-wrapper в docs-only job занял 12,417 с целиком; образ приложения не собирался.

### Три повторные кодовые сборки

Режим: одинаковый source `7f68a453`, `CI_FORCE_BUILD=1`, `CI_SKIP_PUSH=1`, прогретые слои. Сборка запускалась корпоративным build-labels → Bake. В каждом логе подтверждён автоматический code-only выбор.

| Компонент | Job / выполнение / очередь, с | Медиана job, с | Медиана участка Buildx, с |
|---|---|---:|---:|
| Worker | 24442: 12,762 / 47,995; 24465: 11,279 / 1,318; 24467: 9,633 / 1,517 | **11,279** | 0,422 |
| LinTO | 24444: 13,089 / 59,686; 24466: 9,554 / 43,291; 24468: 9,727 / 1,683 | **9,727** | 0,500 |

Ранее опубликованные code-only jobs: worker 24200 — 17,322 с, LinTO 24291 — 14,666 с. Численная разница с нынешними медианами составляет −6,043 с (−34,89%) и −4,939 с (−33,68%), **но её нельзя целиком приписывать оптимизации: старые jobs включали push, новые — нет; состояния кэша различаются**. Полные worker 519,535 с и LinTO 389,321 с относятся к ещё более ранним сборкам. Сам code-only подход уже существовал до этой задачи; здесь он стал автоматическим и пригодным для последовательных выпусков.

### Разделение этапов

| Этап | Наблюдение |
|---|---|
| Очередь | Записана отдельно для каждого job в `jobs.csv`. У первого Front check: 2104,301 → 5,836 с. Это состояние очереди; эффектом кода не считается. Очереди нескольких jobs перекрываются и не суммируются. |
| Подготовка зависимостей | В текущем полном прогоне pip Python — 66,648 с, pip integration — 56,553 с, npm ci — 7,386 с; интервалы до следующей команды из timestamped trace. Старый integration pip был около 45 с: улучшения на этом этапе не показано. |
| Tokenizer | Integration step — 1,540 с против прежних примерно 91 с; разница около −89,460 с / −98,31%. При этом cache restore сообщил miss, поэтому результат не является доказательством действия GitLab cache. Проверка SHA-256 сохранена. |
| Только тесты | ASR 149 — 5,750 с; Vitest 444 — 21,030 с; browser/NATS 4 — 9,507 с; integration 84 — суммарно 37,848 с внутри test runners. |
| Build | Front job 40,764 с, из них `npm run build` в Docker — 16,0 с; bridge job 31,140 с, импорт/VAD — 3,8 с. Повторные worker/LinTO показаны выше. |
| Push | В новых измерениях отключён. Текущая пропускная способность registry не измерялась. |
| Pull | В реальных prepare 24489 и activation 24490 — **0 вызовов / 0 с**. В прежнем prepare 24215 — 5,318 с; прежняя activation 24216 повторяла pull ещё на 1,737 с. Отсутствие pull также проверено на ветке активации нового подготовленного образа в контрактных тестах. |
| Прогрев | В текущем `already_current` — **0 запусков / 0 с**. Исторический candidate 24216 — 16,299 с. Новый cold/warm GPU rollout не измерялся перезапуском неизменённого приложения. |
| Rollout | В текущем `already_current` — **0 update / 0 с**. Job с проверкой текущего состояния целиком — 10,324 с. Исторический настоящий deploy 24216 — 56,309 с; это другой объём работы. |
| Закрытый admission | В этой поставке CI/helper — **0 с**: запрос drain не выполнялся. Время остановки при следующем настоящем изменении модели должно измеряться отдельно; исторический интервал по имеющимся логам надёжно не восстановлен. |

## Ограничения и найденные ошибки

- **GitLab package cache:** конфигурация сохранения/восстановления добавлена, записи cache создаются, но последующие jobs на текущем runner снова сообщают `Cache file does not exist`. Поэтому ускорение за счёт этого кэша не подтверждено. Инфраструктурная причина не исправлялась; Docker layer cache в повторных сборках действительно работает.
- **Artifacts:** первый ASR preflight 24457 успешно подготовил digest, затем упал при загрузке dotenv: `lookup gitlab ... server misbehaving`. Итоговая схема не зависит от загрузки artifacts: точные SHA/digest передаются существующими переменными job/pipeline и проверяются до активации. Исправленная подготовка 24489 и activation 24490 прошли. DNS не менялся.
- Исправлены выявленные регрессии: старый тест требовал обязательный app build перед refresh; runtime-settings тест ожидал production `dist`; bridge COPY ошибочно обращался к каталогу `diarization`, хотя это `diarization.py`. Полные логи неуспехов сохранены, итоговые проверки перечислены выше.
- Тайм-аутные сценарии и два последовательных LinTO update проверены контрактными тестами. Принудительные сбои живого Docker daemon и два ненужных перезапуска модели не выполнялись.

## Фактический runtime и использование

В [24459](<https://git.giscloud.ru/ai-assistant/deployments/rag-stack/-/jobs/24459>) и [24490](<https://git.giscloud.ru/ai-assistant/deployments/rag-stack/-/jobs/24490>) подтверждены ASR source **`3f00eeaa1bb1fe86092919d53ab8883bd23e24f5`**, готовность трёх моделей и digest:

```text
builder-registry.builder.giscloud.ru/gis/webrtc-komaroff/voice-chat/webrtc_streaming_asr/main@sha256:85f73b8793889dc45e894e517918e6670c03a6e596f619fc312c767c82a7ffe5
```

Это source приложения; release-helper использует новый rag-stack SHA `88cc3ea7`. HTTP LinTO preflight [24447](<https://git.giscloud.ru/voice-chat/py_faster_whisper/-/jobs/24447>) подтвердил Python 3.12.15, CTranslate2 4.8.2 и faster-whisper 1.2.1+linto. Новые Front/bridge/worker/LinTO application versions этим изменением не разворачивались. Runtime-версии остальных сервисов не переаттестовывались.

Обычный поток работы:

1. Выбрать компонент и достоверную Git-базу. Для web/API — `CI_SCOPE_BASE_SHA`; при повторном использовании образа — его `CI_REUSE_IMAGE_SOURCE_SHA`.
2. Проверить selected/skipped в логах. Собирать только изменённые входы; `CI_FORCE_BUILD=1` оставлен для явного benchmark/recovery.
3. Передать проверенный digest: Front — `CI_APPLICATION_IMAGES`; ASR — `CI_WEBRTC_ASR_SOURCE_SHA` и `CI_WEBRTC_ASR_IMAGE_DIGEST`; LinTO/bridge — соответствующая переменная digest из документации проекта.
4. Подготовить и проверить образ до drain. При смене ASR использовать существующие отдельные Front drain/resume; новых межпроектных доступов и оркестратора нет.
5. Активировать подготовленный digest, проверить target, открыть admission. При timeout сначала сверить фактическое состояние; автоматического повторного deploy нет.

В каталоге отчёта: `measurements.json` — расчёты, `jobs.csv` — jobs/queue/SHA, `measure.py` — воспроизводимый расчёт, `source-state.json` — объём изменений, `evidence/` — редактированные от credentials полные логи и diff.
