Newer
Older
AI_Lab_SCRUME_Co / CHANGELOG.md

Изменения OM_Lab_Agent

История до 1.7.5 — в git log (сообщения коммитов вида v1.7.5: …). Здесь ведём план и состав следующего релиза.


1.7.7 — исправление чипа расхода

Статус: собрано 05.11.2026.

Дефект: чип ailab-limit в сборке 1.7.6 всегда показывал AI !, в desktop.log каждые 60 с [ailab-limit] fetch failed: ключ шлюза не найден в .env.

Причина: gw_usage.py искал ключ только как литерал sk-… в .env, а с 1.7.6 ключа в .env нет вообще — доступ выдаётся через key_cmd (gw-key.ps1, короткоживущий токен as-…).

Что изменено — только desktop-plugins/ailab-limit/gw_usage.py:

Что Как
key_cmds() читает key_cmd из config.yaml профилей, активный первым
token_from_cmd() запускает команду (CREATE_NO_WINDOW), берёт access_token из JSON; 12 с на попытку, не больше двух попыток в бюджете 20 с, по таймауту гасится всё дерево процессов (taskkill /T) — иначе shell.exec рвётся на своих 30 с
key_candidates() сначала sk-… из .env (совместимость со старыми установками), затем токен key_cmd; на 401/403 — следующий кандидат
JSON ответа добавлены total_spend, reset_at, source
mark() последний запуск пишется в %LOCALAPPDATA%\hermes\logs\ailab-limit-last.json — чтобы отличать «чип не запускался» от «данных нет»

Формат ответа для plugin.js не менялся — плагин не правился.

Проверено: прогон скрипта на живой установке и вызов из рендерера вернули одинаковый ответ — {"ok": true, "spend": 12.06, "budget": 100.0, "duration": "1d", "pct": 12.1, "alias": "testoff", "total_spend": 26.5, "reset_at": "2026-11-06T00:00:00+00:00", "source": "… из .env"}.

1.7.7, пересборка: окно приложения больше не теряется

Дефект, найденный на тестовом ноутбуке 05.11.2026: ночное обновление 1.7.6 → 1.7.7 прошло «успешно» (в update-check.log — обновление установлено), а папки App на диске не осталось: ярлык на рабочем столе есть, запускать нечего.

Причина: в app-setup.zip на сервере маркер app-version.txt был 1.7.6, а дистрибутив уже 1.7.7. Установщик распаковывал архив поверх рабочей папки, видел несовпадение версий и удалял App целиком — «окно не ставлю». Метка .ailab-install.json при этом уже была записана как 1.7.7, поэтому следующая ночная проверка считала машину актуальной и окно не возвращала.

Что изменено:

Файл Было Стало
setup.ps1, шаг 9/9 распаковка поверх App, при несовпадении версии Remove-Item $AppDir распаковка в App.new, сверка app-version.txt, подмена папки только при совпадении; при несовпадении рабочее окно остаётся нетронутым
setup.ps1, финал при отсутствии окна метка установки врала в .ailab-install.json добавляется app_missing: true
update-check.ps1 сравнивал только версии если нет App\Hermes.exe — ставит заново независимо от версии
build-app.ps1 архив окна мог остаться от прошлой версии при каждом выпуске архив пересобирается с app-version.txt = версии дистрибутива

Дополнительно (после жалобы «установлено 1.7.7, а в окне метка 1.7.6»): метка в композере вшивается в рендерер при сборке (vite.config.ts → __AILAB_BUILD__), поэтому правка одного app-version.txt внутри архива её не меняет. Окно пересобрано заново:

  • рендерер: AILAB_BUILD=1.7.7 AILAB_DISTRIBUTION=1 npm run build → метка 1.7.7 в dist/assets/main-C7bK8VL0.js, вхождений 1.7.6 в сборке нет;
  • приложение: npm run builder -- --dir -c.directories.output=<staging> в отдельный каталог (dist\release-app-177), живой Hermes владельца не тронут;
  • архив окна собран из staging через build-app.ps1 -App <staging> — 1216 записей, 179,29 МБ, md5 a63a46e8b20182ccf5d91a5a1e4fc94d, Hermes.exe 246 884 864 б;
  • исходник apps/desktop/assets/icon.ico был старым (101 488 б) и любая свежая сборка подставляла его вместо фирменного — заменён на om-lab.ico (35 450 б).

1.7.6 — план (не выпущено)

Статус: состав накапливается. Сборка не запускается — Олег добавляет нововведения, релиз собирается после закрытия состава.

Тема: правило периметра данных доводится до работающего механизма, а не остаётся декларацией в промпте.

Основание — аудит профиля ai-si 05.11.2026. Проверенное состояние:

Что Факт
skills/productivity/docx/references/anonymization.md процедура полная: тело, таблицы, все headerN/footerN.xml, docProps/core.xml, app.xml, картинки; замена подчёркиваниями; верификация из 3 шагов. Лежит только в профиле ai-si — в сборке файла нет
skills/productivity/docx/scripts/scan_open_pii.py работает (--summary, --header, --json, --fail-on-open). Лежит только в профиле ai-si — в сборке файла нет
skills/ailab/anonymization-check лежит в сборке, в профиль не ставится — категории ailab в установленном профиле нет
skills/engineering/ai-data-perimeter есть только в профиле ai-si, в сборке отсутствует → получателям не приедет
profiles/<p>/hooks/ пусто — принуждения нет
SOUL.md сборки про обезличивание, периметр и заказчика — ни слова

Отсюда формулировка «у нас обезличивание до отправки в модель» сегодня не подтверждается: правило записано в скилле, но срабатывает по триггеру и зависит от того, вспомнит ли модель его применить.

1. Один канон процедуры + скилл в сборку и в профиль

Проблема: одна и та же процедура описана в трёх местах — docx/references/anonymization.md, ailab/anonymization-check, engineering/ai-data-perimeter. Три редакции разъедутся.

Иерархия, которую фиксируем:

Место Роль
engineering/ai-data-perimeter канон: правила периметра, проверка «соблюдается ли», порядок работы с документом заказчика, чек-лист и нормы (references/perimeter-rules.md)
docx/references/anonymization.md техника правки DOCX-пакета + scripts/scan_open_pii.py — исполнение под каноном
ailab/anonymization-check свести к тонкой ссылке на канон либо убрать; сейчас это третья редакция того же правила
  • Что: положить engineering/ai-data-perimeter в сборку (dist/vasily/skills/engineering/) — в сборке этой категории нет вообще, поэтому переносится каталог целиком, вместе с references/perimeter-rules.md и templates/soul-perimeter-block.md.
  • Что, дополнительно (иначе канон ссылается на отсутствующий файл): перенести в сборку исполнение — skills/productivity/docx/references/anonymization.md и skills/productivity/docx/scripts/scan_open_pii.py. Оба сейчас есть только в профиле ai-si; в dist/vasily/skills/productivity/docx/ их нет. Копировать без __pycache__.
  • Сделано 05.11.2026 — файлы в сборке: skills/engineering/ai-data-perimeter/ (SKILL.md, references/perimeter-rules.md, references/hermes-intercept.md, templates/soul-perimeter-block.md), skills/productivity/docx/references/anonymization.md, skills/productivity/docx/scripts/scan_open_pii.py. md5 совпадают с профилем ai-si, __pycache__ не попал, синтаксис скрипта проверен.
  • Проверить, что категории engineering и ailab доезжают до установленного профиля при установке и обновлении (ailab сейчас не доезжает — см. таблицу выше).
  • Критерий приёмки: после чистой установки в профиле есть skills/engineering/ai-data-perimeter/SKILL.md + references/perimeter-rules.md; третьей редакции правила в профиле нет.
  • Причина: скилл, лежащий только в профиле разработчика или только в сборке, в работе не участвует. Правило в SOUL.md на него ссылается — битая ссылка хуже отсутствия ссылки.

2. Правило порядка в SOUL.md — сведено с ai-data-perimeter

Сверено с каноном. SOUL не переписывает светофор и контуры (они в references/perimeter-rules.md), а закрывает то, что действует до первого чтения файла, и не противоречит трём правилам скилла: аудит вместо согласия (Правило 0), декларация ≠ контроль (Правило 1), агент сам канал (Правило 2).

Расхождения первой редакции, исправленные при сверке:

Было в первой редакции Что говорит скилл Исправлено
не покрывала запрос «подтверди, что соблюдается» Правило 0: это аудит по двум слоям, а не согласие добавлены оба слоя и запрет ответа по одному
«не открывается, пока не решено» — без статуса данных документ до классификации считается красным добавлен статус «считается красным»
правило жило само по себе процедура — в скилле, SOUL задаёт только порядок добавлена ссылка на канон, дублирование убрано
не было стоп-сигнала «маркеров нет» = скорее всего оригинал; ноль находок ≠ чисто добавлено
не сказано, кто обезличивает обезличивание — работа человека, спорное агент не решает добавлено

Формулировка для вставки в SOUL.md (в сборку и в рабочий профиль):

## Периметр данных

Правила, светофор и процедура — скилл `ai-data-perimeter`. Здесь — то, что
действует до первого чтения файла.

- Документ заказчика (ТЗ, договор, переписка, форма, ИД) до классификации считается
  красным. Инструментами чтения он не открывается, пока не решено, откуда берётся
  обезличенная копия: её даёт владелец или агент делает копию и читает только её.
- Оригинал не открывать «чтобы посмотреть объект». Таблица соответствия токенов и
  реальных значений не читается никогда — она и есть закрываемые данные.
- Обезличивание — работа человека по его таблице соответствий. Агент делает копию по
  технике `docx/anonymization.md`, только если об этом попросили, и не решает за
  человека, что закрывать в спорных случаях.
- Проверка полноты: `python scripts/scan_open_pii.py "<файл>" --summary`. Агент читает
  счётчики; полный отчёт со значениями — человеку, потому что находки и есть
  закрываемые данные.
- «Маркеров нет» — единственный стоп-сигнал: скорее всего, это оригинал. Ноль находок
  ≠ «документ чист». Формулировка: «шаблоны нашли N, открыто: …».
- «Документ обезличен» и «у нас это соблюдается» без проверки файлов — запрещены.
  На просьбу подтвердить меру проверяются два слоя: организационный (приказ,
  регламент, журнал) и технический (SOUL, установленные скиллы, hooks). Ответ по
  одному слою — ошибка в обе стороны.
- Если механизма принуждения нет — говорить это прямо: правило в промпте срабатывает
  по триггеру, а не по факту.
  • Где: SOUL.md в сборке (приезжает всем получателям) + profiles/<p>/SOUL.md в рабочем профиле (иначе правило не действует у того, кто уже установлен).
  • Критерий приёмки: правило есть в обоих файлах; на контрольной задаче («прочитай ТЗ и найди требования») агент сначала спрашивает про обезличенную копию, а не открывает оригинал.
  • Оговорка для релиз-ноутов, честно: это по-прежнему правило в промпте. Принуждение — только hook/шлюз (п. 4).

3. Журнал применения ИИ — с записями, а не пустая форма

  • Что: форма журнала + процедура, при которой запись появляется по факту задачи, а не заполняется задним числом «для проверки».
  • Минимальный состав записи: дата · задача · сервис · контур · категория данных (🟢/🟡/🔴) · обезличивание выполнено (да/нет, чем подтверждено) · результат перепроверен человеком · кто.
  • Куда писать: файл журнала в рабочей папке проекта (CSV/MD), запись — по факту задачи; при инциденте — отдельной строкой в журнал инцидентов.
  • Критерий приёмки: после пилота на одной команде в журнале есть не менее 5 реальных записей, каждая с категорией данных и отметкой обезличивания; повторяющаяся операция закрывается одной строкой, без ручного заполнения таблицы каждый раз.
  • Причина: в папке «AI безопасность» журнал присутствует только как пустая форма Регламента. Пустая форма — не контроль.

4. Перехват на исходящем запросе: маска + журнал, роли по типам документов

Проверено 05.11.2026 по установленной сборке: точка перехвата в Hermes существует и врезана в путь запроса.

  • Плагин регистрирует middleware: ctx.register_middleware("llm_request", fn) — hermes_cli/plugins.py:939.
  • Применяется перед вызовом провайдера: agent/turn_api_request.py:156 → apply_llm_request_middleware(...), и api_kwargs заменяются тем, что вернул плагин (hermes_cli/middleware.py:88).
  • Middleware видит полный request, включая messages/input, и может переписать их или прервать вызов исключением.
  • Парные точки: tool_request (аргументы инструмента до выполнения) и llm_execution (обёртка самого вызова провайдера).

Решение Олега 05.11.2026: режим — маскировать и логировать. Блокировка — только там, где маскирование бессмысленно. Причина: шаблоны ПДн дают ложные срабатывания на техническом тексте (номера СП и ГОСТ, ИНН поставщика в спецификации, кадастровые в выписке), а жёсткая блокировка валит нормальную работу и толкает её на личный телефон.

Категория — не по шаблону, а по типу документа и роли. Классификатор угадывает и ошибается; поэтому тип документа определяется до чтения, а подтверждает человек одним вопросом, и ответ живёт в метке сессии.

Три точки в одном плагине:

Точка Что делает
tool_request (read_file, DOCX/PDF-парсер, OCR) определяет тип документа по имени файла, титулу и штампу; сверяет с ролью пользователя; ставит метку категории в сессии; при запрете — отказ до чтения файла, содержимое в модель не попадает
llm_request маскирует по правилам категории из метки; пишет строку в журнал
llm_execution возвращает реальные значения в ответе (демаскировка)

Плагин работает только с содержимым запроса к модели. Ключи доступа, учётные данные и личные файлы он не читает и не меняет — это отдельный контур, к политике доступа к документам отношения не имеет.

Политика — файл в профиле (policy.yaml), правится без пересборки:

Категория Кому Что входит Режим
🟢 зелёный всем открытые нормативы, методики, обезличенные тексты без маски
🟡 жёлтый всем ТЗ, реестры замечаний, переписка, локальные сметы, ВОР маска + журнал
🔴 красный только роль «договорной пул» (несколько человек) договоры, сводные сметы, акты, ИД, кадры, финансы остальным — отказ с подсказкой, к кому идти

Маскировать красное и отправлять нельзя: у договора маска убивает предмет — стороны, суммы, особые условия. Поэтому для красного единственный корректный ответ — не пускать.

Два ограничения по доступу — согласованы с Олегом 05.11.2026:

  1. Роль не даёт права отправить красное в облако. По светофору красное не уходит наружу никому: договорной пул получает право открыть документ агенту (снять структуру, собрать обезличенную выписку), но отправка самого договора в облачную модель блокируется и им тоже. Пока локального контура нет, по договорам агент у договорного пула почти не работает — это цена честной схемы, а не недоделка.
  2. Роль вешается на учётку, а не на флаг в профиле. Переключатель в том же профиле сотрудник поставит себе сам, и контроль фиктивный. Красный уровень — отдельный профиль или отдельная учётка у нескольких человек договорного пула.

Источник ролей — Единый докер USER.xlsx (лист USERS, колонка «роль», добавлена 05.11.2026), 11 учёток:

Роль (как записана) Кто Категории Отправка в облако
инженер ОВиК, ТЗ, ТУ, СТУ, проекты — 7 Гришкевич, Воробей, Фролагина, Воронцов, Анушов, Кашина, Нечаев 🟢🟡, ТЗ — всем да, с маской
гл. бухгалтер (договоры, контракты, сметы, тендеры) — 1 Хундадзе 🟢🟡 + открытие красного нет
совладелец директор (договоры, контракты, сметы, тендеры) — 2 Швецов, Дуда 🟢🟡 + открытие красного нет

Требования к колонке, без которых policy.yaml не собрать:

  1. Роль — машинный код (engineer / contracts / admin), а не перечисление задач: «инженер ОВиК, ТЗ, ТУ, СТУ, проекты» не парсится и меняется от задачи к задаче. Описание оставить отдельной колонкой для человека.
  2. policy.yaml генерируется из этой таблицы скриптом, а не правится руками: два источника правды разъедутся на первой же кадровой замене.
  3. Учётки со статусом root (TESTOFF) политику не обходят — иначе одна учётка отменяет контроль. Для них отдельная запись в журнале с пометкой admin.
  4. Колонка «роль» приведена к кодам 05.11.2026: столбец G — код (engineer — 7, contracts — 3, admin — 1), столбец H «роль — что делает» — исходное описание задач для человека. Дуда В. заведён (ключ выдан сотруднику, хэш в таблицу не сохранялся) — прежний пункт снят.
  5. Единый докер USER.xlsx — личная таблица Олега (OneDrive). Источник ролей, но не рабочий файл сборки: агент её читает, не изменяет и не переписывает. policy.yaml генерируется из копии, снятой на момент подготовки релиза, — чтобы правка личной таблицы не ломала политику, а политика не правила личную таблицу.

  6. Критерий приёмки:

    1. Сотрудник без роли просит проверить договор → отказ до чтения, файл не открывается.
    2. ТЗ у любого сотрудника → уходит маской, в журнале строка, ответ приходит с реальными значениями.
    3. 20 запросов без ПДн → ни одной маски и ни одной блокировки.
    4. В журнале: пользователь, тип документа, категория, сколько замен, модель, время.
    5. Сотрудник с ролью договорного пула просит отправить договор в облачную модель → отказ: роль открывает документ агенту, но не отправку в облако.
  7. Остаточные риски, фиксируем честно: картинки и вложения не маскируются; PDF-сканы без текстового слоя требуют OCR до маски; путь «человек скопировал в браузер мимо агента» закрывается только шлюзом или DLP на периметре.

Порядок работ: сначала tool_request + политика + журнал в режиме «только запись» (ничего не маскируем, смотрим поток), затем включаем маску на жёлтом, и только после настройки правил — демаскировку ответа.

5. Состав из «OM_Lab — требования к следующей сборке»

Единый источник UI- и функциональных требований — C:\Users\Admin\OneDrive\Документы\OM LAB\OM_Lab — требования к следующей сборке.md (§0 — сводка, §1–§4 — тексты). Здесь только состав и статусы; требования не дублируются, при расхождении верен документ.

№ в документе Пункт Раздел Статус на 05.11.2026
1 Только разрешённые модели, персональный ключ, бренд агрегатора скрыт §1 готово к реализации
2 Один провайдер (шлюз), прямой polza.ai удалён, discover_models выключен + миграция для установленных §3a готово к реализации
3 Прогресс-бар лимита — по ключу в рублях, через шлюз §1a блокер: нужен /v1/wallet на шлюзе
4 Vision через шлюз тем же ключом §1b готово к реализации
5 Резерв proxyapi.ru, только автопереключение, пользователю не виден §2 в объёме 1.7.6, делается при сборке (работа шлюза, не клиента): ключ есть (797 моделей), группы и fallbacks заведены, но LiteLLM отклоняет переход по правам ключа → переделать на второй деплоймент в группе + cooldown_time: 300
6 Настройки: пять вкладок, «О программе» скрыть §3 готово к реализации
6a Вкладка «Боты» скрыта, Bot Mode остаётся в коде §3b решено 04.11.2026: только вкладка
6b Первое открытие после установки — тёмная тема §3c записано 04.11.2026
7 Бот на звонок в Телемост §4 блокер: отдельная учётка Яндекс
8 Ключ привязан к машине: зачисление + key_cmd, статического ключа в .env нет §1c сделано 05.11.2026 (см. ниже)
  • Пункт 8 (привязка доступа к машине) — сделано 05.11.2026. Шлюз: gw-issuer v2 — /enrol (обмен старого sk-… на зачисление), /app-key (сессия as-… на 300 с по X-Install-Token), /resolve (подмена сессии на ключ человека для nginx), /revoke, /list. nginx на gw.ailabscrume.ru получил auth_request: в LiteLLM уходит тот же ключ, что и раньше, поэтому лимиты и учёт не меняются (короткие ключи через /key/generate отвергнуты — каждый ключ это отдельная строка расхода и прогресс-бар §1a показывал бы ноль). Клиент: gw-key.ps1 (DPAPI-конверты, коды 0/1/2/3/4, кэш при недоступном хабе), установщик зачисляет машину по почте и коду, пишет key_cmd вместо key_env, чистит .env, файл зачисления кладёт в %LOCALAPPDATA%\AILabSCRUME (вне дома агента). Проверено живьём: агент на временном профиле ответил моделью через key_cmd при пустом .env; отзыв зачисления → helper выходит с кодом 3. ISSUER_STRICT=0 — статические ключи пока проходят насквозь; включать 1 после обновления всех машин.

  • Брендинг 1.7.6 (решение Олега 05.11.2026). Название агента — OM_Lab_Agent (видимые строки: установщик, ярлык, описание задачи Планировщика, README/INSTALL/CHANGELOG, проверка самоназвания $NamePat). Лого на пустом чате — assets/scrum-engineering.svg заменён на логотип OM Lab (прозрачный PNG, обрезка по содержимому + поля 2 %, 640 px внутри SVG, alt OM_Lab_Agent, ширина 280 px, height:auto, objectFit:contain); под логотипом подпись «Приятной работы, с уважением, команда OM_LAB_Co». Иконка — assets/om-lab.ico = image-cutout.ico (256×256, прозрачная) в resources/icon.ico и в ярлыке; иконка самого Hermes.exe не менялась (нужен rcedit, Олег отложил). Номер сборки — метка BuildVersionLabel в chat/composer/controls.tsx: версия дистрибутива вписывается в рендерер при сборке (AILAB_BUILD → __AILAB_BUILD__), appVersion (версия ядра, 0.22.7) не показывается. Рендерер окна лежит в ДВУХ местах — app.asar и app.asar.unpacked\dist; обновлять оба, иначе интерфейс остаётся старым при живой иконке. Сборка окна для получателей идёт через staging-копию (build17.ps1), чтобы не подменять рабочий Hermes владельца. Display-имя Electron НЕ меняем (product-identity.cjs: display: 'Hermes'): оно задаёт %APPDATA%\Hermes, где лежат список чатов и настройки окна — переименование «потеряло» бы их у всех. Триггер автообновления не трогаем (остаётся Daily 03:00 + 0…44 мин с -StartWhenAvailable); поведение при выключенном ПК: обновление выполняется при первом включении/входе, но если в этот момент открыто окно Hermes.exe → «отложено» до следующего окна.

  • Что реально войдёт в 1.7.6: пункты без внешних блокеров — 1, 2, 4, 6, 6a, 6b, 8 (плюс безопасность п.1–3 выше) и пункт 5 (резерв, работа шлюза — по решению Олега 05.11.2026 переделка делается при сборке 1.7.6, а не сейчас).

  • Пункт 5 (резерв) — не клиентская работа, но входит в 1.7.6 и делается при сборке (решение Олега 05.11.2026). Проверено 05.11.2026 на шлюзе: ключ proxyapi.ru живой, GET /v1/models → 200, 797 моделей, ограничений на ключе нет (подтверждено Олегом). Группы proxy/<vendor>/<model> и router_settings.fallbacks для всех алиасов уже заведены, но переход не выполняется: в логе gw-llm — Fallback to proxy/google/gemini-4-argon was skipped because the caller is not authorized to call it. Причина: у ключа сотрудника в models только его 9 моделей, proxy/* в них нет. Отсюда решение: не отдельная группа, а второй деплоймент внутри той же группы <alias>/<vendor>/<model> (список моделей у ключа не меняется — резерв остаётся невидимым), плюс явный cooldown_time: 300 (сейчас «5 минут» держатся на дефолте роутера, в router_settings его нет).
  • Маппинг моделей — решено Олегом 05.11.2026. 7 из 9 моделей совпадают с proxyapi по имени один в один. Решения по двум:
    • anthropic/claude-sonnet-5.5 → резерв anthropic/claude-sonnet-5-5 (у proxyapi дефис вместо точки);
    • openai/gpt-6.1-sol-pro → на proxyapi отсутствует, резерв = деградация на openai/gpt-6.1-sol (подтверждено Олегом). Технически это второй деплоймент в той же группе: model_name = <alias>/<vendor>/<model> (то, что видит ключ), litellm_params.model = фактическая модель proxyapi, api_base = https://api.proxyapi.ru/v1. Группа и список моделей у ключа не меняются.
  • Переносятся 3, 7 — собираются, когда закроются блокеры; тогда же поднимается номер (1.7.7 или следующий по порядку).
  • Не путать: «п.4» здесь — vision, а «§4» документа — бот на звонок; сквозная нумерация в документе своя.
  • Перед сборкой закрыть открытые вопросы §5 документа: префиксы testoff/… в названиях моделей, точный перечень вкладок настроек, маппинг моделей proxy.

Что НЕ входит в 1.7.6

  • Локальная модель / RAG (Ollama + Open WebUI): решения нет, железа нет. Ценность такого контура — только на красной категории, и он снимает риск утечки ценой качества на русском техническом тексте.
  • Заполнение Регламента и приказа ООО «СКРАМ ИНЖИНИРИНГ» — организационный слой, отдельная работа вне сборки.

Подготовка релиза 1.7.6 (prepare release)

Мероприятия по этапам. Галочка ставится по факту проверки, а не по факту «сделали».

Этап 1. Закрыть состав

  • Олег закрывает список нововведений; всё, что «ещё думаю», уезжает в 1.7.7, а не висит в 1.7.6.
  • У каждого пункта есть критерий приёмки — у пп. 1–4 есть.
  • По п.4 зафиксировано, где живёт policy.yaml: общий файл на диске (план) или политика на шлюзе; шлюз остаётся вторым рубежом для тех, кто ходит мимо агента.
  • Роли сняты из личной таблицы Олега на момент подготовки; таблица не изменяется.

Этап 2. Реализовать и проверить

  • Скилл engineering/ai-data-perimeter в сборке и в установленном профиле (п.1). В сборке лежит с 05.11.2026; осталась проверка установленного профиля после чистой установки.
  • Раздел «Периметр данных» в SOUL.md сборки и профиля (п.2).
  • Журнал применения: форма + запись по факту задачи (п.3).
  • Плагин, шаг 1: tool_request + policy.yaml + журнал в режиме «только запись», без маски (п.4).
  • Плагин, шаг 2: маска на жёлтом.
  • Плагин, шаг 3: демаскировка ответа в llm_execution.
  • Прогнать 5 критериев приёмки п.4 на живых документах: ТЗ, реестр замечаний, договор.
  • Проверить на чистой установке, а не только в рабочем профиле: иначе скилл и политика не доедут — на этом уже спотыкались.

Этап 3. Документы к релизу

  • CHANGELOG.md: перенести 1.7.6 из «план» в «выпущено», поставить дату и номер сборки.
  • Release notes для получателей: что вошло, что не вошло, честная оговорка про остаточные риски — картинки и вложения не маскируются, сканы без текстового слоя требуют OCR до маски, браузер мимо агента закрывается только шлюзом.
  • Инструкция сотруднику: что такое категория документа, почему спросят один раз, что делать при отказе по договору.
  • Инструкция договорному пулу: почему роль не даёт отправку в облако и что делать вместо этого.
  • README.md: раздел безопасности — новые правила и роли.

Этап 4. Сборка

  • Состав закрыт; пункты 1–3 (безопасность) проверены на чистой установке, а не только в рабочем профиле, и пункты 1, 2, 4, 6, 6a, 6b из п.5 (UI) проверены там же.
  • distribution.yaml → version: 1.7.6; README.md → «Текущая версия: 1.7.6».
  • Коммит с сообщением v1.7.6: <главное изменение> + тег.
  • Сборка bundle, проверка по разделу «Проверка перед передачей» в README.
  • Прогон на чистой машине: установка → скилл виден → правило в SOUL → журнал пишется → маска срабатывает.

Этап 5. Откат и первые две недели

  • Предыдущий bundle (1.7.5) сохранён как точка отката.
  • Записано, как выключается плагин без пересборки (флаг в config.yaml) — маска не должна требовать релиза, чтобы её отключить при массовых ложных срабатываниях.
  • Назначен ответственный за журнал инцидентов на первые две недели после выдачи.
  • Через две недели — разбор: сколько записей в журнале, сколько отказов по красному, сколько ложных масок.

1.7.8 — план (под вопросом)

Статус: под вопросом. Собирать только после явного «да» Олега при сборке.

Тема: один ключ сотрудника (sk-…) открывает модели и MCP ГОСТ-ассистента; прямой api.gostassistent.com из клиента убирается.

Основание: ТЗ §7 («MCP гостассиента https://gw.ailabscrume.ru/mcp тем же ключом») не доехало в 1.7.6/1.7.7 — клиент ходит напрямую с отдельным upstream-ключом 64 символа. Проверено живьём 06.11.2026: ключ сотрудника sk-… (25 симв.) на шлюзе gw.ailabscrume.ru/mcp → initialize/tools/list/tools/call = 200, 4 инструмента, реальная карточка ГОСТ; тот же ключ на api.gostassistent.com/api/mcp → 401.

Что меняется

№ Что Где
0 Разделение сборок флагом AILAB_DISTRIBUTION. Скрытие служебных вкладок (биллинг, «О программе», экспорт/импорт/сброс, секции chat/workspace/safety/browser) выполняется только при AILAB_DISTRIBUTION=1. Чистый Hermes владельца собирается без флага и показывает всё. Реализовано: src/lib/build-flags.ts, vite.config.ts, settings/constants.ts, settings/index.tsx сборка
1 mcp_servers.gostassistent.url → https://gw.ailabscrume.ru/mcp, авторизация тем же ключом, что модели (через key_cmd), без отдельной переменной config.yaml
2 MCP_GOSTASSISTENT_API_KEY убрать из env_requires (сейчас required: false, но само наличие переменной создаёт путаницу) distribution.yaml
3 Имена инструментов станут gostassistent_<alias>-document_* (в агенте mcp__gostassistent_<alias>__*). Скиллы на старые имена не зашиты — проверено сборка
4 Ключ без object_permission.mcp_servers → 403 с понятным текстом, а не молчание шлюз/клиент
5 Тексты: INSTALL.md (сейчас «включается своим ключом в .env»), README.md стр. 97, CHANGELOG документы

Вопросы, которые задать Олегу при сборке

  1. Главный: переводим MCP на шлюз или оставляем прямой путь? Переезд означает один общий upstream-ключ ГОСТ на всех — персонального стопа на уровне базы не остаётся, ограничение только на ключе шлюза (и это ограничение неденежное — LiteLLM MCP-вызовы не тарифицирует, max_budget на них не действует).
  2. Права: у duda.v и anushov.k сейчас 0 MCP-серверов (проверено /key/list?return_full_object=true, 06.11.2026). После переезда они получат 403. Выдать право или зафиксировать, что инструменты им не положены?
  3. Мерж конфига: установщик копирует config.yaml целиком с -Force, без .bak и без мержа (проверено setup.ps1, строки 565–571). Правка url доедет до всех ночным автообновлением — но у тех, кто уже что-то настроил локально, настройки исчезнут. Делаем config.local.yaml + бэкап в этом релизе или отдельно?

Критерий приёмки

  • На чистой установке в .env одна переменная ключа; grep api.gostassistent.com по профилю → 0 совпадений.
  • initialize / tools/list / tools/call ключом сотрудника → 200.
  • Ключ без права MCP → 403 с текстом, а не молчание.
  • Модели продолжают работать тем же ключом.

Блокеры и риски

  • Установщик перезаписывает config.yaml и skills/ без бэкапа и мержа — правка в config.yaml без этого механизма бессмысленна для тех, кто уже настроил локальные дополнения.
  • duda.v, anushov.k — без права MCP.
  • Общий upstream-ключ ГОСТ: нет персонального стопа, нет денежного учёта MCP-вызовов.