# MCP:RSV Server — Релиз 7.3.0

## Содержание

- [Установка плагина](#установка-плагина)
  - [Плагин ставится на новые версии 1C:EDT](#плагин-ставится-на-новые-версии-1cedt)
- [Лицензия и доступность](#лицензия-и-доступность)
  - [Резервный канал проверки лицензии для сетей с ограничениями](#резервный-канал-проверки-лицензии-для-сетей-с-ограничениями)
  - [Работа без связи с сервером лицензирования](#работа-без-связи-с-сервером-лицензирования)
  - [Окончание срока лицензии](#окончание-срока-лицензии)
  - [Инструмента нет в вашем профиле — об этом сказано там, где агент читает](#инструмента-нет-в-вашем-профиле--об-этом-сказано-там-где-агент-читает)
- [Обновление информационной базы](#обновление-информационной-базы)
  - [Состояние базы больше не слетает в «неизвестно» после обновления](#состояние-базы-больше-не-слетает-в-неизвестно-после-обновления)
  - [Отказ загрузки называет виновника и ошибки в нём](#отказ-загрузки-называет-виновника-и-ошибки-в-нём)
  - [Свежее расширение в безопасном режиме](#свежее-расширение-в-безопасном-режиме)
  - [Длительность обновления в отчёте](#длительность-обновления-в-отчёте)
- [Версия плагина и обновление](#версия-плагина-и-обновление)
  - [После обновления видно, какая версия действительно работает](#после-обновления-видно-какая-версия-действительно-работает)
- [Выгрузка конфигураций и расширений в файл](#выгрузка-конфигураций-и-расширений-в-файл)
  - [Неполный файл расширения больше не выдаётся за готовый](#неполный-файл-расширения-больше-не-выдаётся-за-готовый)
  - [Откуда собирать файл — теперь можно указать явно](#откуда-собирать-файл--теперь-можно-указать-явно)
  - [Обрыв выгрузки называет объекты-подозреваемые](#обрыв-выгрузки-называет-объекты-подозреваемые)
- [Правка метаданных и форм](#правка-метаданных-и-форм)
  - [Тип параметра заимствованной команды: расширение принимается базой](#тип-параметра-заимствованной-команды-расширение-принимается-базой)
  - [Право роли расширения на объект основной конфигурации](#право-роли-расширения-на-объект-основной-конфигурации)
  - [Неуспешная операция больше не оставляет следов в форме](#неуспешная-операция-больше-не-оставляет-следов-в-форме)
  - [Регистрация обработчика события: или привязка и процедура, или ничего](#регистрация-обработчика-события-или-привязка-и-процедура-или-ничего)
  - [Пакет операций: видно, что применилось, а что нет](#пакет-операций-видно-что-применилось-а-что-нет)
  - [Проверка кода видит вызов метода, который в чужом модуле недоступен](#проверка-кода-видит-вызов-метода-который-в-чужом-модуле-недоступен)
  - [Вложенные подсистемы: проект собирается и загружается в базу](#вложенные-подсистемы-проект-собирается-и-загружается-в-базу)
  - [Удаление подсистемы не оставляет следов на диске](#удаление-подсистемы-не-оставляет-следов-на-диске)
  - [Поле на форме без данных больше не выдаётся за размещённое](#поле-на-форме-без-данных-больше-не-выдаётся-за-размещённое)
  - [Удаление реквизита и табличной части убирает их из динамических списков форм](#удаление-реквизита-и-табличной-части-убирает-их-из-динамических-списков-форм)
  - [Смена запроса набора данных приводит состав полей к новому запросу](#смена-запроса-набора-данных-приводит-состав-полей-к-новому-запросу)
  - [Справка объекта: текст не рвётся, а оформление доходит до окна справки](#справка-объекта-текст-не-рвётся-а-оформление-доходит-до-окна-справки)
  - [Подпись реквизита ставится тем словом, которым её просят](#подпись-реквизита-ставится-тем-словом-которым-её-просят)
  - [Быстрое исправление обещается только там, где оно есть](#быстрое-исправление-обещается-только-там-где-оно-есть)
  - [Отказ правки метаданных отвечает по-русски](#отказ-правки-метаданных-отвечает-по-русски)
  - [Опечатка в имени объекта — сразу предложено верное имя](#опечатка-в-имени-объекта--сразу-предложено-верное-имя)
  - [«Объект уже существует» показывает, что это за объект](#объект-уже-существует-показывает-что-это-за-объект)
  - [Удаление объекта из расширения: сказано, что именно мешает](#удаление-объекта-из-расширения-сказано-что-именно-мешает)
  - [Создание расширения: где имя расширения, а где базовая конфигурация](#создание-расширения-где-имя-расширения-а-где-базовая-конфигурация)
  - [Заимствование объекта не требует лишнего параметра](#заимствование-объекта-не-требует-лишнего-параметра)
- [Расширения в информационной базе](#расширения-в-информационной-базе)
  - [Операции с расширениями не оставляют за собой процессов конфигуратора](#операции-с-расширениями-не-оставляют-за-собой-процессов-конфигуратора)
  - [База с пользователями: понятная причина вместо таймаута и способ задать логин](#база-с-пользователями-понятная-причина-вместо-таймаута-и-способ-задать-логин)
  - [Неподходящий логин базы: отказ вместо ожидания, и в проекте ничего не остаётся](#неподходящий-логин-базы-отказ-вместо-ожидания-и-в-проекте-ничего-не-остаётся)
  - [Привязка большой базы отвечает честно](#привязка-большой-базы-отвечает-честно)
  - [Видно, не осталось ли за операцией процессов конфигуратора](#видно-не-осталось-ли-за-операцией-процессов-конфигуратора)
  - [Служебные утилиты берутся под версию работающего сервера](#служебные-утилиты-берутся-под-версию-работающего-сервера)
- [Чтение форм](#чтение-форм)
  - [«Мёртвые обработчики» больше не приписываются рабочим процедурам](#мёртвые-обработчики-больше-не-приписываются-рабочим-процедурам)
  - [Поиск элемента на большой форме находит то, что на ней есть](#поиск-элемента-на-большой-форме-находит-то-что-на-ней-есть)
  - [Командная панель показывает то, что увидит пользователь](#командная-панель-показывает-то-что-увидит-пользователь)
  - [Знакомство с несуществующим объектом — отказ, а не успех](#знакомство-с-несуществующим-объектом--отказ-а-не-успех)
- [Несколько окон 1С:EDT](#несколько-окон-1сedt)
  - [Вызов сам попадает в то окно, где открыт нужный объект](#вызов-сам-попадает-в-то-окно-где-открыт-нужный-объект)
  - [Окно, которое не смогло открыть рабочую область, больше не путает адресацию](#окно-которое-не-смогло-открыть-рабочую-область-больше-не-путает-адресацию)
  - [Перечень проектов объясняет, чего в нём нет](#перечень-проектов-объясняет-чего-в-нём-нет)
  - [Список информационных баз — страницами и с поиском](#список-информационных-баз--страницами-и-с-поиском)
  - [Перечень точек останова: отбор по проекту и честный пустой ответ](#перечень-точек-останова-отбор-по-проекту-и-честный-пустой-ответ)
- [Снимки проекта](#снимки-проекта)
  - [Свой снимок находится среди служебных](#свой-снимок-находится-среди-служебных)
  - [Сравнение без параметров больше не выглядит повтором обычного состояния](#сравнение-без-параметров-больше-не-выглядит-повтором-обычного-состояния)
  - [Новый файл в сравнении показывает своё содержимое](#новый-файл-в-сравнении-показывает-своё-содержимое)
  - [Счётчик неотправленных снимков подписан ветвью](#счётчик-неотправленных-снимков-подписан-ветвью)
  - [Запись о восстановлении называет, что именно вернулось](#запись-о-восстановлении-называет-что-именно-вернулось)
  - [Пустая область восстановления больше не означает «весь проект»](#пустая-область-восстановления-больше-не-означает-весь-проект)
- [Файлы проекта на диске](#файлы-проекта-на-диске)
  - [Переводы строк — как настроено у проекта, во всех файлах](#переводы-строк--как-настроено-у-проекта-во-всех-файлах)
- [Запись кода в модули](#запись-кода-в-модули)
  - [Заглушка обработчика кладётся в область модуля](#заглушка-обработчика-кладётся-в-область-модуля)
  - [Удаление метода больше не портит модуль](#удаление-метода-больше-не-портит-модуль)
  - [Пакет методов: признак создания работает, а список методов в отказе не врёт](#пакет-методов-признак-создания-работает-а-список-методов-в-отказе-не-врёт)
  - [Поиск по коду наконец слушается указания объекта и вида модуля](#поиск-по-коду-наконец-слушается-указания-объекта-и-вида-модуля)
- [Юнит-тесты (YAxUnit)](#юнит-тесты-yaxunit)
  - [Повторный вызов за результатом больше не начинает прогон сначала](#повторный-вызов-за-результатом-больше-не-начинает-прогон-сначала)
  - [Готовый отчёт отдаётся, а не отбрасывается как устаревший](#готовый-отчёт-отдаётся-а-не-отбрасывается-как-устаревший)
  - [Прогон, который не начался, больше не висит «выполняется» без конца](#прогон-который-не-начался-больше-не-висит-выполняется-без-конца)
- [Сценарное тестирование (Vanessa)](#сценарное-тестирование-vanessa)
  - [Прогон сценария больше не трогает базу без спроса](#прогон-сценария-больше-не-трогает-базу-без-спроса)
  - [Правка сценария даёт свежий результат, а не вчерашний отчёт](#правка-сценария-даёт-свежий-результат-а-не-вчерашний-отчёт)
  - [Отбор по тегам действительно отбирает](#отбор-по-тегам-действительно-отбирает)
  - [Ожидание прогона укладывается в один вызов](#ожидание-прогона-укладывается-в-один-вызов)
  - [Несколько снимков в одном сценарии видно до прогона](#несколько-снимков-в-одном-сценарии-видно-до-прогона)
  - [Подсказка про вход клиента тестирования не сбивает с толку](#подсказка-про-вход-клиента-тестирования-не-сбивает-с-толку)

## Установка плагина

### Плагин ставится на новые версии 1C:EDT

При установке на свежую версию среды установщик отказывался её завершить и
сообщал, что не может найти один из необходимых элементов. Поставить плагин на
такую версию было нельзя — то есть проблема возникала ровно в тот день, когда
разработчик переходил на свежую версию 1C:EDT.

Исправлено: установка больше не зависит от того, какие версии входящих в состав
1C:EDT компонентов использует конкретная версия среды. Плагин ставится на новые
версии 1C:EDT так же, как на прежние, — отдельный дистрибутив под каждую версию
среды не нужен. Поддержка ранее выпущенных версий сохранена в полном объёме,
обращение к встроенной справке платформы (`get_platform_docs`) работает на всех
поддерживаемых версиях без изменений.

## Лицензия и доступность

### Резервный канал проверки лицензии для сетей с ограничениями

У части пользователей плагин не запускался и сообщал, что серверы лицензирования
недоступны: активация не проходила, а в уже работающей среде инструменты
переставали открываться. Причина была не в лицензии — она была действующей, — а в
сети: корпоративные политики и ограничения провайдера не выпускали запросы к
серверам проверки лицензии. Обойти это можно было только через VPN или через
администратора сети, что для рабочего места разработчика решение так себе.

Исправлено: у проверки лицензии появился резервный канал. Если основной адрес
проверки не отвечает, плагин автоматически повторяет запрос через запасной — и
активация, выдача пробного периода и регулярная проверка лицензии проходят как
обычно, без VPN и без настройки на стороне пользователя. Порядок обращения не
изменился: сначала всегда используется основной канал, запасной включается только
после его отказа, поэтому у тех, у кого всё и так работало, ничего не поменяется.

### Работа без связи с сервером лицензирования

Плагин рассчитан на то, что при недоступности сервера лицензирования он
продолжает работать ещё 30 дней с момента последней успешной проверки — чтобы
обрыв связи, командировка или временные ограничения в сети не останавливали
работу. На деле этот период не наступал: стоило серверу стать недоступным, и
плагин отказывался запускаться с сообщением о недоступности серверов, даже если
последняя успешная проверка была совсем недавно.

Исправлено: оговорённый тридцатидневный срок автономной работы работает так, как
заявлен. Пока связи нет, плагин запускается и работает до конца этого срока, а
после первой же успешной проверки срок отсчитывается заново. Условия остались
прежними: сам по себе срок не продлевается, автономная работа возможна только на
том компьютере, где лицензия активирована, а по его истечении плагин снова
попросит связь с сервером. Тем, кто из-за этого сидит без плагина прямо сейчас,
достаточно установить обновление — выходить для восстановления работы в сеть не
требуется.

### Окончание срока лицензии

Плагин перестаёт работать по окончании срока действия лицензии — в том числе
когда связи с сервером лицензирования нет, и в том числе в уже открытой среде:
раньше окончание срока замечалось только при следующем запуске, поэтому среда,
открытая накануне, продолжала работать. Последний день срока рабочий: если
лицензия действует по сегодняшнее число, сегодня всё работает как обычно, а
прекращается со следующего дня. Остановка аккуратная: начатая операция
доигрывает и возвращает результат, новые запросы уже не принимаются — работа
прерывается предсказуемо и без последствий для проекта. Сообщение об окончании
срока называет причину и дату, по которую лицензия действовала, вместо
технического кода ошибки, — чтобы сразу было понятно, что нужно продление, а не
наладка сети или обращение в поддержку. Продление подхватывается обычным
способом: введите новый код активации на странице настроек MCP:RSV Server; если
лицензия продлена, а среда открыта, плагин узнает об этом сам при очередном
обращении к серверу лицензирования.

### Инструмента нет в вашем профиле — об этом сказано там, где агент читает

Профиль скрывает инструменты, которые в него не входят. При этом описания
остальных инструментов продолжали ссылаться на скрытый: «правку метаданных делает
такой-то инструмент». Агент читал такую ссылку как факт, искал инструмент,
не находил и пробовал вызвать его снова и снова — на профиле «Разработчик» это
превращалось в глухой круг, из которого пользователю приходилось выводить агента
руками.

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

## Обновление информационной базы

### Состояние базы больше не слетает в «неизвестно» после обновления

На клиент-серверных базах обновление проходило, изменения в базу попадали — а
состояние базы после него становилось «неизвестно», и связь синхронизации у
проекта конфигурации оказывалась потерянной. Среда продолжала показывать, что
базу нужно обновить, повторные обновления ничего не меняли, а разбор состояния
советовал «выполните обычное обновление» — то есть отправлял по кругу. Выйти из
этого можно было только перезапуском среды.

Исправлено: обновление больше не разрывает связь синхронизации, которая была
установлена до вызова, — закрывается только та, которую открыло само обновление.
После загрузки состояние базы читается как «база актуальна», связь у всех
участников остаётся живой, и среда не просит обновить уже обновлённую базу. Если
связь всё же оказалась потерянной (например, её оборвало что-то извне), плагин
восстанавливает её сам сразу после успешной загрузки и пересчитывает состояние —
данные базы при этом не меняются. Мягкий ремонт (`reconnectStale`) теперь тоже
видит этот случай: раньше он отвечал «переподключать нечего» именно тогда, когда
связь и была потеряна. Заодно ушла лишняя работа: повторный вызов на уже
обновлённой базе отвечает «загружать нечего» за мгновение, а не запускает
загрузку заново. Разбор состояния больше не противоречит сам себе — участник не
может оказаться одновременно «актуален» и «требует обновления».

### Отказ загрузки называет виновника и ошибки в нём

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

Исправлено: отказ теперь начинается с того, что действительно помогает —
пересборки проекта-виновника, она занимает секунды. В этом случае загрузку чаще
всего срывает устаревший кеш сборки, а не метаданные. Рядом в ответе появились
ошибки самого виновника: сколько их и первые из списка — платформа не загружает в
базу то, что среда считает ошибочным, и разбор логично начинать отсюда. Сборка в
файл осталась в подсказке, но последним шагом и с оговоркой, что успешная сборка
виновника не оправдывает.

### Свежее расширение в безопасном режиме

Когда расширение попадает в базу впервые, платформа сама включает ему «Безопасный
режим» и «Защиту от опасных действий». В этом режиме перехваты расширения молча не
исполняются: доработка не работает, ошибок нет, а автотесты в таком расширении
показывают зелёный результат при неработающей доработке.

Исправлено: обновление базы сообщает об этом сразу и даёт готовую команду с
подставленным именем расширения, а не шаблон, в который имя надо вписывать самому.
Отметка приходит и тогда, когда обновление завершилось с ошибкой: расширение к
этому моменту уже опубликовано, и знать про режим нужно независимо от итога
загрузки. В тексте прямо сказано, что галочки поставила платформа, а не вы.

### Длительность обновления в отчёте

Длительность в отчёте об обновлении считалась до момента, когда за результатом
обратились, а не до конца самой операции. Из-за этого тяжёлое обновление, за
результатом которого возвращались позже, показывало в отчёте часы вместо
фактических минут. Теперь в отчёт попадает длительность самой операции. Заодно
устранён связанный случай: результат давно завершившегося обновления мог
достаться более позднему вызову как его собственный — вызов при этом базу не
обновлял, но отвечал чужим итогом.

## Версия плагина и обновление

### После обновления видно, какая версия действительно работает

Инструмент `show_edt_version` возвращает не только номер версии, но и отметку времени сборки
(`serverBuild`) — по ней видно, что вызовы обслуживает именно та версия, которую вы поставили.
Раньше номер мог принадлежать версии, установленной рядом, а не работающей: человек ставил
обновление, видел новый номер и не понимал, почему исправления не действуют.

Если новая версия уже установлена, а работает ещё прежняя, плагин теперь говорит об этом прямо
— в ответе появляются `staleBuild` и пояснение, что изменения вступят в силу после перезапуска
1C:EDT. При работе с несколькими 1C:EDT одновременно порт, на который настроен ИИ-клиент, больше
не может занять устаревший экземпляр плагина.

## Выгрузка конфигураций и расширений в файл

### Неполный файл расширения больше не выдаётся за готовый

Файл расширения — это поставка: его отдают заказчику, и он должен содержать всё,
что вы сделали. Случалось, что при сборке файла из проекта платформа принимала не
всё содержимое расширения, а инструмент об этом молчал: в ответе стоял успех, путь
и размер файла. Обнаруживалось это уже у заказчика — по тому, что часть доработки
у него не работает.

Исправлено: содержимое расширения проверяется при сборке, и если платформа приняла
не всё, инструмент говорит об этом прямо — в ответе появляется раздел
предупреждений с текстом претензий платформы. Файл по-прежнему собирается (иногда
он именно такой и нужен), но теперь видно, что перед передачей заказчику его надо
проверить. Отдельно разобран самый частый случай — расширение, которое дорабатывает
объекты и формы основной конфигурации: для такой сборки нужное окружение
подготавливается автоматически, и то, что раньше платформа отвергала, доезжает до
файла. У расширений, которые состоят только из собственных объектов, сборка идёт
как прежде и с прежней скоростью.

### Откуда собирать файл — теперь можно указать явно

У выгрузки конфигурации и расширения появился параметр «откуда собирать»: из
привязанной информационной базы или из проекта. Из базы — быстро и ровно то, что в
ней лежит: удобно, когда база уже содержит нужную версию доработки. Из проекта —
когда файл должен соответствовать именно проекту. Не указали — источник, как и
раньше, выбирается сам: из базы, если она совпадает с проектом, иначе из проекта.
Заданный источник при этом не подменяется другим: если собрать запрошенным путём не
получилось, придёт понятная ошибка с причиной и подсказкой, а не файл, собранный
как-то иначе, — так вы всегда знаете, что именно у вас в руках.

### Обрыв выгрузки называет объекты-подозреваемые

Выгрузка большого проекта иногда обрывалась сообщением среды разработки о
незаполненных данных, но без имени объекта, из-за которого всё встало. Проверка
проекта такие поломки не показывает вовсе, и искать виновника было нечем — вручную
перебирали отчёты и формы.

Исправлено: в отказе теперь перечислены объекты, которые до выгрузки не доехали, —
виновник среди них, и круг поиска сужается с целого проекта до нескольких имён.

## Правка метаданных и форм

### Тип параметра заимствованной команды: расширение принимается базой

Типовой приём при доработке расширением — вывести общую команду типовой
конфигурации на форме своего документа: команду заимствуют в расширение и
добавляют свой документ к типу её параметра, не трогая базовый состав. Ответ на
такую правку приходил успешным, проверка проекта была чистой, а платформа затем
отвергала расширение при обновлении информационной базы — «значение
контролируемого свойства „Тип параметра команды“ не совпадает со значением в
расширяемой конфигурации». Дефект всплывал на самом дорогом шаге, и по нему легко
было заключить, что платформа такую доработку не поддерживает, хотя вручную в
среде разработки она делается и работает.

Исправлено: тип параметра заимствованной команды записывается так же, как это
делает сама среда разработки, и база принимает расширение. Перечислять базовые
типы не нужно — расширение только дополняет состав; попытка заменить состав,
потеряв типы основной конфигурации, отклоняется до записи и объясняет, как
добавить тип. В ответе видно, что получилось: фактический состав параметра
целиком и отдельно то, что добавило расширение. Чтение объекта тоже показывает
фактический состав, а не одну добавленную строку, — теперь тип параметра команды
приходит сразу, без дополнительных параметров запроса.

### Право роли расширения на объект основной конфигурации

Роль расширения работает только с объектами, которые есть в самом расширении, —
собственными и заимствованными. Попытка выдать право на объект основной
конфигурации отвечала «объект-цель не найден»: похоже на опечатку в имени, и
настоящая причина оставалась неизвестной.

Исправлено: отказ называет проект, в котором объект лежит, объясняет правило и
даёт готовый вызов заимствования — после него право выдаётся тем же вызовом, что
и раньше. Так же теперь отвечают операции ограничения доступа к данным.

### Неуспешная операция больше не оставляет следов в форме

Если правка формы не удавалась на середине — например, при добавлении таблицы
динамического списка не удавалось разобрать путь к колонке, — приходил отказ, но
заготовка таблицы в форме уже оставалась. Отказ приходил и при запросе
предварительного просмотра, где по смыслу измениться не должно ничего. Заметить это
было почти невозможно: ответ говорил об ошибке, и следующая попытка добавляла в
форму ещё одну заготовку. У одного из пользователей так накопилось четыре
незавершённых таблицы, а в форме появились элементы с одинаковыми именами — такую
форму платформа уже не принимает, и разбираться приходилось вручную.

Исправлено: операция либо выполняется целиком, либо не выполняется вовсе. Ответ об
ошибке теперь означает, что в проекте ничего не изменилось: убирать за неудавшимся
вызовом нечего, а повторить его после устранения причины безопасно — лишние
элементы и дубли не появятся. В таком ответе это сказано прямо, отдельным
пояснением. Единственное исключение — установка нескольких свойств одним вызовом:
там непринятое свойство по-прежнему не отменяет уже принятые, и ответ перечисляет,
что именно применилось.

### Регистрация обработчика события: или привязка и процедура, или ничего

Если файл модуля формы оказывался недоступен для записи (только чтение из системы
контроля версий, блокировка файла, права на каталог), регистрация обработчика
события отвечала «выполнено», хотя процедура в модуль не попадала: в форме
оставалась привязка события на несуществующую процедуру, и в работающей программе
это событие падало с сообщением «процедура не определена».

Исправлено: недоступный для записи модуль — это честный отказ с указанием причины,
и привязка события в форме при этом не сохраняется. Либо и привязка, и процедура,
либо ничего.

### Пакет операций: видно, что применилось, а что нет

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

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

### Проверка кода видит вызов метода, который в чужом модуле недоступен

Вызов метода другого общего модуля, объявленного без `Экспорт`, гарантированно
падает при выполнении с сообщением «Метод объекта не обнаружен». При этом проверка
ошибок (`get_validation_errors`) с обычными настройками про такой вызов молчала,
код-ревью не упоминал его вовсе, а ответ записи кода сообщал «код корректен». То же
самое с опечаткой в имени метода: обращение к методу, которого в модуле нет.
Проблема доживала до работающей базы и обнаруживалась уже прогоном, когда связь с
исходной правкой была потеряна — у одного из пользователей так вышел релиз, в котором
главный инструмент падал на каждом вызове больше недели.

Исправлено: оба случая теперь приходят ошибкой сразу — и в проверке ошибок, и в
код-ревью, и в ответе записи кода, то есть до загрузки в базу. В тексте замечания
названы модуль, метод и строка его объявления, а также сказано, что именно произойдёт
при выполнении и что с этим делать — добавить `Экспорт` или вызвать другой метод.
Обращение к методу изнутри его собственного модуля, к экспортному методу, к
переменной или параметру, названному как общий модуль, замечанием не считается:
проверка сообщает только о том, в чём уверена.

### Вложенные подсистемы: проект собирается и загружается в базу

Дочерняя подсистема, созданная или перенесённая инструментом, при выгрузке проекта
в файлы конфигурации попадала не в каталог своего раздела, а в общий корень
каталога подсистем. Проверить это было нечем: выгрузка сообщала об успехе, число
файлов сходилось, XML был корректным, проверка ошибок молчала, а состав объектов
показывал верное дерево. Проект отказывался собираться только на загрузке файлов
в информационную базу — сообщением «Файл объекта не существует», причём уже после
того, как база заблокирована и сеансы пользователей погашены. При переносе целого
поддерева выгрузка вместо этого обрывалась. Именованные группы панели навигации
внутри раздела делаются именно дочерними подсистемами, поэтому обойти это было
нечем: обычный приём оформления интерфейса приводил к неразвёртываемому проекту, и
узнавал об этом разработчик в самый неудобный момент.

Исправлено: дочерние подсистемы любой глубины выгружаются в каталоги своих
разделов, файл поставки собирается, загрузка в базу проходит. Это относится и к
созданию новой дочерней подсистемы, и к переносу существующей — как внутрь другого
раздела, так и обратно на верхний уровень.

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

### Удаление подсистемы не оставляет следов на диске

Удаление подсистемы убирало её из состава конфигурации, но её файл оставался в
проекте. Не замечал этого никто: проверка ошибок чиста, выгрузка файл игнорирует,
каталог объектов подсистему не показывает — увидеть остаток можно было только по
снимку хранилища исходников, а при переоткрытии проекта удалённая подсистема могла
вернуться: обновление информационной базы такой остаток не замечает, поэтому
обнаруживался он позже и в неожиданном месте.

Исправлено: вместе с подсистемой уходит и её файл — и когда удаляется одна дочерняя
подсистема, и когда удаляется раздел вместе со всем поддеревом. То же касается
переноса: после него в прежнем каталоге ничего не остаётся.

### Поле на форме без данных больше не выдаётся за размещённое

Поле, добавленное на форму без указания пути к данным, создавалось как пустая
оболочка: ответ был успешным, элемент в структуре формы виден, а в 1С:Предприятии
его нет — и проверка проекта об этом молчит. Разработчик узнавал о пропаже уже на
работающей форме.

Исправлено: если путь к данным не указан, поле связывается по имени реквизита —
сначала ищется реквизит формы, затем реквизит или табличная часть объекта. Если
связать не с чем, операция отклоняется и перечисляет реквизиты формы, подсказывая,
чем поле завести; на форме после отказа ничего не остаётся. Заодно ответ перестал
называть созданием то, что созданием не было: если поле с таким путём к данным на
форме уже есть, оно переносится в указанное место и перечисляется отдельно —
вместе со своим прежним именем, которым его и надо адресовать дальше.

### Удаление реквизита и табличной части убирает их из динамических списков форм

Удалённый реквизит (или табличная часть) оставался в описании динамического списка
на форме списка: ссылка на несуществующие данные, о которой проверка проекта не
сообщает ничем. Обнаруживалось это только тем, что форма списка не открывалась у
пользователя, а найти причину можно было единственным способом — поиском по
исходникам проекта руками.

Исправлено: описания удаляемого реквизита и вложенные наборы удаляемой табличной
части вычищаются из всех форм объекта, и ответ прямо перечисляет, что именно было
убрано — с указанием формы и списка. Текст произвольного запроса списка операция
удаления не переписывает (это работа разработчика), но если удаляемое имя ещё
встречается в запросе, ответ отдельно предупреждает об этом и называет операцию,
которой запрос правится.

### Смена запроса набора данных приводит состав полей к новому запросу

Замена текста запроса у набора данных схемы компоновки оставляла в наборе поля,
которых в новом запросе больше нет, — хотя справка обещала обратное. Поле-сирота
проверкой не ловится, а компоновка отчёта в 1С:Предприятии на нём падает.

Исправлено: состав полей приводится к новому запросу, а удалённые поля
перечисляются в ответе. Поля, оставшиеся в запросе, сохраняют свои роли и
заголовки. Прежнее поведение по-прежнему доступно — параметром «сохранить поля».
Заодно смена запроса динамического списка на форме сверяет с новым текстом и
описания параметров запроса: те, что остались не у дел, называются в ответе (сами
описания не трогаются — их мог настроить разработчик, а вот забытый параметр
переживает снос доработки вместе со своим типом).

### Справка объекта: текст не рвётся, а оформление доходит до окна справки

Справку объекта удобно писать в Markdown, а документы в репозитории принято
верстать по 80–100 символов в строке. Такой текст справка портила: каждый перенос
строки в исходнике становился жёстким переносом на экране, поэтому абзац рвался
не по ширине окна, а по местам, где его свернул редактор; продолжение пункта
списка со следующей строки вылетало из пункта отдельным абзацем; а выделение,
разорванное переносом, так и оставалось звёздочками на виду у пользователя.
Лечилось это только переписыванием всей справки в одну длинную строку на абзац.

Исправлено: одиночный перенос строки внутри абзаца — это пробел, как в обычном
Markdown, и текст переносится по ширине окна справки; продолжение пункта списка
принадлежит пункту; выделение и код собираются, даже если перенос прошёл по
их середине. Жёсткий перенос там, где он нужен, задаётся двумя пробелами в конце
строки или обратной косой чертой.

Отдельно исправлено оформление. Параметр оформления записывался в страницу, ответ
сообщал об успехе, чтение страницы подтверждало, что правила на месте, — а окно
справки 1С:Предприятия их не применяло: оно понимает только оформление, записанное
прямо в теге. Разработчик видел мелкий шрифт и не мог понять, почему «крупнее» не
сработало; уходило это на два-три круга «поправил — посмотрел». Теперь правила
раскладываются по тегам самой страницы при записи, и заказанный крупный шрифт
виден в окне справки; правило для страницы целиком достаточно написать один раз —
его наследует весь текст. В ответе появилось число оформленных тегов: по нему
сразу видно, что оформление действительно дойдёт до пользователя, а не просто
записалось в файл. Правило, которое разложить нельзя (сложный селектор), больше
не обещается молча — оно названо в ответе.

### Подпись реквизита ставится тем словом, которым её просят

«Подпись» — то, что видит пользователь, — у объекта метаданных и его реквизитов
называется синонимом, а у элемента формы то же самое зовётся заголовком. Агент,
который только что ставил заголовок элементу формы, тем же словом просил подпись
у реквизита и получал отказ-тупик: свойство не применено, а подсказка предлагала
совсем другое свойство. Поставить подпись становилось нечем, хотя способ есть.

Исправлено: просьба задать подпись, заголовок или представление объекту
метаданных выполняется — значение применяется к синониму, и ответ прямо говорит,
что подпись объекта метаданных называется синонимом. Заголовок элемента формы
работает как прежде, ничего не подменяется.

### Быстрое исправление обещается только там, где оно есть

Замечание проверки могло прийти с признаком «есть быстрое исправление», а попытка
его применить заканчивалась ошибкой без объяснения. Причина в том, что признак
относился к самой проверке — «у таких замечаний исправления бывают», — а для
конкретного замечания среда не предлагала ни одного применимого варианта.

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

### Отказ правки метаданных отвечает по-русски

Часть отказов операций правки приходила английской строкой посреди русского
ответа. Агент читал такую строку как чужой системный сбой, переставал доверять
остальному ответу и начинал перебирать варианты вслепую.

Исправлено: тексты отказов правки метаданных, форм, схем компоновки, ролей,
команд и заимствования — на русском и платформенными словами. Отказ называет,
что именно не найдено или не задано и что делать дальше.

### Опечатка в имени объекта — сразу предложено верное имя

Ошибка в одну букву давала сухое «объект не найден», и агент шёл смотреть
каталог объектов отдельным вызовом.

Исправлено: отказ операций правки предлагает близкие имена того же вида
объектов, а если имя написано верно, но указан не тот вид, — прямо называет
объект нужного вида. Похожих имён в проекте нет — отказ так и говорит и ничего
не выдумывает.

### «Объект уже существует» показывает, что это за объект

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

Исправлено: в отказе приходит краткий состав существующего объекта — сколько
у него реквизитов, табличных частей, форм, команд и как они называются. Сразу
видно, продолжать работу с ним или брать другое имя.

### Удаление объекта из расширения: сказано, что именно мешает

Объект расширения, на тип которого ссылаются элементы этого же расширения,
удалить нельзя — иначе платформа отвергнет расширение целиком. Отказ перечислял
ссылки и предлагал три операции на выбор, а был ли внутри самого объекта ещё
какой-то мусор, приходилось выяснять отдельным вызовом.

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

### Создание расширения: где имя расширения, а где базовая конфигурация

При создании нового проекта расширения агент называл свою конфигурацию не тем
параметром и получал отказ «укажите базовую конфигурацию» — как будто сказанное
им не услышали.

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

### Заимствование объекта не требует лишнего параметра

В рабочей области с двумя и более конфигурациями заимствование объекта
в расширение отказывало с просьбой указать базовую конфигурацию, хотя она
у расширения одна и известна.

Исправлено: базовая конфигурация берётся у самого проекта расширения. Если её
всё же нет, отказ перечисляет конфигурации рабочей области на выбор.

## Расширения в информационной базе

### Операции с расширениями не оставляют за собой процессов конфигуратора

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

### База с пользователями: понятная причина вместо таймаута и способ задать логин

Если в информационной базе заведены пользователи, конфигуратору нужен логин.
Раньше без него операция просто ждала и заканчивалась сообщением «инструмент не
уложился в лимит», а запущенный конфигуратор оставался жить. Теперь ответ
называет причину словами платформы («Пользователь ИБ не идентифицирован»),
предлагает готовое решение и не оставляет за собой процессов.

Логин базы задаётся один раз при её привязке к проекту — `manage_infobase`
`operation=associate` с параметрами `user` и `password`; дальше обновление базы,
установка и удаление расширений идут под этим пользователем. Пустой `user`
снимает логин. Базы без пользователей работают как раньше — ничего указывать не
нужно.

Заодно в разборе состояния базы (`sync_database` с `diagnoseUpdateState`) появился
раздел со служебными процессами конфигуратора: какие живы, с какой базой работают
и когда последний раз что-то делали. Процесс, который давно ничего не пишет, —
первый подозреваемый, если база «занята» без видимой причины.

### Неподходящий логин базы: отказ вместо ожидания, и в проекте ничего не остаётся

Если логин базы неполный или неверный, среда разработки спрашивает доступ окном и
ждёт человека. Пока никто не ответит, обращения к базе не двигаются, а вызов
заканчивается сообщением о нехватке времени. Хуже другое: привязка с таким логином
оставалась в проекте, и окно всплывало снова каждые несколько секунд — оно мешало
работать со всей средой и не давало даже отвязать эту базу.

Теперь привязка с логином, который база не принимает, **не создаётся**. Ответ
называет причину словами платформы, говорит, что делать, и предупреждает про окно —
в том числе про то, что окно может оказаться не на переднем плане и со стороны
выглядеть как молчаливое зависание. Всё, что успела создать неудачная попытка,
снимается: и привязка, и регистрация базы в списке, и записанный логин. Если база
доступна и логин подходит — всё как раньше, никаких новых отказов не появляется.

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

### Привязка большой базы отвечает честно

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

### Видно, не осталось ли за операцией процессов конфигуратора

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

### Служебные утилиты берутся под версию работающего сервера

На машине с несколькими установленными версиями платформы служебные утилиты
администрирования кластера брались из самой новой установки. Если сервер 1С
работает под другой версией, утилита с ним не разговаривает — серверные прогоны
тестов и завершение сеансов перед обновлением базы не работали вообще. Теперь
версия берётся у работающего сервера, а в журнале операции видно, какая выбрана
и совпадает ли она с кластером.

## Чтение форм

### «Мёртвые обработчики» больше не приписываются рабочим процедурам

Снимок структуры формы мог одновременно перечислить процедуру как привязанную к
событию и объявить её мёртвой — с подсказкой «привяжи событие», выполнение которой
сломало бы рабочую форму. Попадали под это события формы объекта — «перед записью»,
«после записи», «при чтении на сервере» и родственные: они хранятся в форме иначе,
чем события вроде «при открытии», и проверка их просто не видела. У формы с пятью
такими обработчиками все пять объявлялись неработающими, и настоящая находка —
привязка к процедуре, которой в модуле нет, — терялась среди ложных.

Исправлено: привязки читаются целиком, и штатно заведённый обработчик мёртвым не
называется; процедура, названная в ответе привязанной, в список мёртвых не попадает
ни при каких условиях. Настоящие неиспользуемые процедуры по-прежнему находятся.
Заодно привязки к отсутствующим процедурам вынесены в отдельный список: это про
сломанную форму, а не про лишний код, и теряться среди прочего такая находка не
должна.

### Поиск элемента на большой форме находит то, что на ней есть

Точечный поиск элемента по имени или подписи на крупной форме мог честно ответить
«найдено: 0», хотя элемент с таким именем на форме был: обход формы обрывался по
внутреннему ограничению, и до нужного узла дело не доходило. Признака обрыва в
ответе не было — выглядело это как достоверное «такого элемента нет».

Исправлено: точечный поиск идёт по всей форме независимо от её размера. Объём
ответа определяют совпадения, а не размер формы; если под условие подошло слишком
много узлов, приходит первая порция и общее число совпадений.

### Командная панель показывает то, что увидит пользователь

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

Исправлено: у панели видно её фактическое автозаполнение, а состав кнопок —
эффективный. Автозаполнение снято — стандартных команд в панели нет, и рядом
сказано, сколько их скрыто и чем вернуть.

### Знакомство с несуществующим объектом — отказ, а не успех

Запрос контекста по объекту, которого в проекте нет (опечатка в имени, объект из
другого проекта), возвращал успешный ответ с пояснением внутри. Тот, кто читает
только признак успеха, шёл дальше с пустым контекстом.

Исправлено: такой вызов — отказ с объяснением, похожими именами и подсказкой, где
смотреть состав проекта.

## Несколько окон 1С:EDT

### Вызов сам попадает в то окно, где открыт нужный объект

Когда на машине открыто несколько окон 1С:EDT с разными рабочими областями,
агент раньше упирался в тупик: он называл объект, а вызов уходил в то окно,
к которому подключён, и получал «объект не найден» — при том что объект был
открыт в соседнем окне. Приходилось выяснять, в каком именно проекте он живёт,
и повторять вызов с именем проекта.

Теперь вызов с именем объекта попадает туда, где объект открыт, — имя проекта
называть не нужно. В ответе видно, в какой рабочей области он выполнен, поэтому
агент не гадает, откуда пришли данные. Если объект с таким именем открыт сразу
в нескольких окнах, вызов не выполняется вовсе: приходит перечень копий с их
рабочими областями, чтобы выбрать нужную осознанно, а не наугад.

### Окно, которое не смогло открыть рабочую область, больше не путает адресацию

Если запустить второе окно 1С:EDT на рабочей области, которая уже открыта
в другом окне, среда показывает «не удалось заблокировать рабочую область»
и ждёт человека. Такое окно ничего не открыло, но плагин в нём всё равно
поднимался и отвечал списком проектов соседа. Дальше страдали все остальные
окна: один и тот же проект выглядел открытым дважды, и вызовы по имени проекта
переставали выполняться — «открыт сразу в нескольких EDT».

Теперь плагин в таком окне не поднимается и в перечень запущенных сред не
попадает, а причина написана в журнале среды: какая рабочая область, каким
окном уже открыта. Работа остальных окон не нарушается.

### Перечень проектов объясняет, чего в нём нет

Перечень проектов рабочей области по умолчанию показывает только проекты 1С,
а в статистике при этом стоит общее число проектов. Разница между «всего»
и «показано» ничем не объяснялась: агент видел, что часть проектов куда-то
делась, и делал второй вызов, чтобы понять, какие именно.

Теперь пропущенные проекты названы поимённо и с причиной. Отдельно называются
ЗАКРЫТЫЕ проекты: пока проект закрыт, среда не сообщает его вид, поэтому среди
них может оказаться и конфигурация, и расширение — раньше такой проект исчезал
из ответа бесследно.

Заодно у проектов внешних обработок и отчётов соседних окон теперь виден состав:
такой проект — только контейнер, и работают не с его именем, а с полными именами
объектов внутри. В каждой записи сказано, из какого проекта и какого окна она.

### Список информационных баз — страницами и с поиском

Список информационных баз, зарегистрированных в 1С:EDT, приходил одним куском:
на рабочей машине это сотня записей со строками соединения чужих баз — около
двадцати килобайт в одном ответе, из которых нужна одна строка.

Теперь список отдаётся страницами и умеет искать: по части имени записи, по
каталогу файловой базы или по имени базы в кластере. В ответе сказано, сколько
записей подошло, сколько показано и есть ли ещё — просить следующую страницу
можно осознанно.

### Перечень точек останова: отбор по проекту и честный пустой ответ

Точки останова живут во всей рабочей области, а перечень отдавал их все сразу
и без возможности сузить до нужного проекта. Хуже того, пустой перечень читался
как «точек останова нет вообще», хотя они могли стоять в соседнем окне 1С:EDT.

Теперь есть отбор по проекту, видно распределение точек по проектам, а пустой
ответ честно говорит, что на машине открыты и другие окна среды и точки могут
быть в них.

## Снимки проекта

### Свой снимок находится среди служебных

В истории снимков вперемешку лежат человеческие записи и служебные — автоснимки
перед опасными операциями и отметки восстановления. На реальной истории нужный
снимок приходилось искать глазами среди двух десятков записей.

Теперь история умеет отбор: только человеческие снимки, только служебные — или
по части сообщения. Отбор просматривает историю целиком, а не первый экран,
поэтому «не нашлось» означает «нет вовсе»; в ответе видно, сколько записей
подошло и сколько просмотрено.

### Сравнение без параметров больше не выглядит повтором обычного состояния

Сравнение снимков, вызванное без параметров, давало ровно тот же состав
изменённых файлов, что и обычное состояние проекта. Со стороны это выглядело
дублированием двух операций, и было непонятно, зачем нужна вторая.

Теперь такой ответ прямо говорит, что это то же самое, и называет, с чего
начинается собственная польза сравнения: подробности по одному файлу и сравнение
снимка со снимком.

### Новый файл в сравнении показывает своё содержимое

У файла, которого в снимке ещё не было, сравнение показывало только число строк
и перечень методов — чтобы увидеть, что в нём написано, нужен был отдельный вызов.
Теперь содержимое нового файла приходит прямо в сравнении; очень длинный файл
обрезается с честной пометкой и подсказкой, чем дочитать.

### Счётчик неотправленных снимков подписан ветвью

Состояние проекта показывало, сколько снимков не отправлено на сервер, но не
говорило, к какой ветви это относится. В проекте с несколькими ветвями число
читалось как «во всём проекте», хотя относится только к текущей ветви.

Теперь рядом со счётчиками названа ветвь и её ветвь на сервере, а подсказка
про отправку тоже называет ветвь по имени.

### Запись о восстановлении называет, что именно вернулось

После восстановления отдельных файлов в истории оставалась запись
«восстановление к снимку такому-то». Позже она читалась как возврат всего
проекта к тому снимку, хотя вернулись, например, два файла.

Теперь в записи названа область: весь проект или конкретные пути. История
перестала обещать больше, чем произошло.

### Пустая область восстановления больше не означает «весь проект»

Восстановление возвращает проект целиком, если область не задана. Но пустое
значение области — это не то же самое, что «не задавал»: так выглядит ошибка
в вызове, а цена ошибки здесь — возврат всего проекта вместо двух файлов.

Теперь пустая область отклоняется: приходит отказ с объяснением, файлы не
тронуты, а вернуть проект целиком можно только вызовом, где области нет вовсе.
Клиентов, которые устроены так, что всегда присылают все параметры и пустое
значение у них означает «не передавал», это не касается — для них поведение
прежнее.

## Файлы проекта на диске

### Переводы строк — как настроено у проекта, во всех файлах

Файлы метаданных плагин отдаёт писать самой среде, и они получались в том стиле
переводов строк, который настроен у проекта. Всё остальное, что плагин кладёт на
диск сам, — модули, заглушки обработчиков, справка объекта, текстовые и HTML-макеты,
модули команд — шло мимо этой настройки: где в стиле Unix, где в стиле операционной
системы, а страница справки умудрялась совмещать оба стиля в одном файле. В проекте
получалась каша: система контроля версий показывала изменённым весь файл вместо
правленых строк, ревью превращалось в просмотр сотен «изменившихся» строк, а слияние
веток конфликтовало там, где никто ничего не менял. Хуже всего вело себя дописывание
заглушки в существующий модуль: добавление восьми строк отмечало изменившимися все
тридцать две строки файла.

Исправлено: разделитель строк берётся из настройки проекта — той же, по которой
работает сама среда, — и применяется на всех путях записи. Настроен стиль Windows —
новый модуль пишется в стиле Windows; настроен Unix — в Unix; настройки нет — берётся
значение, которое подставит среда для этого проекта. Существующий файл при правке
сохраняет свои переводы строк: правка одной строки остаётся правкой одной строки,
даже если стиль файла отличается от настройки проекта. Файлы, где стили уже
перемешаны, не переписываются целиком под видом мелкой правки — иначе одно обновление
плагина дало бы «изменённым» весь проект. В ответе записи кода теперь видно, какими
переводами строк записан файл и откуда этот стиль взят — из настройки проекта или
из самого файла.

## Запись кода в модули

### Заглушка обработчика кладётся в область модуля

Заглушка процедуры-обработчика дописывалась в самый конец файла — после последней
области модуля. Среда помечала каждую такую процедуру замечанием «метод необходимо
разместить в одной из верхнеуровневых областей», и разработчик получал зелёный
ответ вместе с новым замечанием, которое потом разгребал руками. Заодно запись
заглушки перебивала переводы строк во всём модуле, и правка на четыре строки
выглядела в системе контроля версий как изменение всего файла.

Исправлено: заглушка кладётся в свою область — события формы, события элементов
шапки, события элементов таблицы, обработчики команд; нужной области нет — она
заводится на своём месте по стандартному порядку областей модуля формы. В ответе
сказано, в какую область легла процедура. Переводы строк модуля сохраняются как
были, в правку попадают только добавленные строки. Модуль, в котором областей нет
вовсе, не перекраивается — заглушка дописывается в конец, как и раньше.

### Удаление метода больше не портит модуль

Метод удаляют, передавая в запись пустое содержимое, — так снимают код фичи, от которой
отказались. При этом директива компиляции (`&НаСервере`, `&НаКлиенте`, `&После(...)`) и
комментарий-описание удалённого метода оставались в модуле. Остаток прилипал к следующей
процедуре и молча менял её контекст исполнения: платформа отказывалась инициализировать
модуль формы, и карточка объекта не открывалась вообще — с сообщением, что процедура не
определена. Ответ инструмента при этом был успешным, встроенная проверка кода замечаний не
давала, и дефект доезжал до информационной базы: расширение публиковалось «зелёным», а форма
у пользователя не открывалась. Снос шести методов оставлял в модуле шесть таких остатков.

Исправлено: удаление метода убирает его целиком — вместе с директивами компиляции и
описанием над объявлением, не оставляя лишнего пустого разделителя на месте метода. В ответе
перечислено, что именно убрано (имя метода, сколько строк, какие директивы, сколько строк
описания), а в предварительном просмотре видно уходящий блок и место склейки. Если обращения
к удалённому методу остались в этом же модуле, ответ называет их номерами строк и
предупреждает, что на таком вызове платформа сообщит о неопределённой процедуре. Удалить
несколько методов можно одним вызовом — пакетом, в котором допустимо смешивать удаление,
замену и добавление методов. Попытка удалить метод, которого в модуле нет, отклоняется с
объяснением, а не выполняется вслепую.

### Пакет методов: признак создания работает, а список методов в отказе не врёт

При записи нескольких методов одним вызовом признак «создать метод, если его нет» читался
только у вызова целиком. Указанный внутри отдельного метода пакета, он принимался без единого
слова и не действовал: пакет отказывал с сообщением, что метод не найден, — а признак,
который должен был это предотвратить, был передан. Кроме того, список методов модуля в тексте
такого отказа собирался с учётом ещё не записанных изменений и содержал методы, которых на
диске нет. Рядом было сказано «ничего не записано», и агент искал несуществующее расхождение.

Исправлено: признак «создать, если нет» действует и внутри отдельного метода пакета, перебивая
для него общее значение вызова — «два метода поправить, третий дописать» делается одним
вызовом с точной настройкой. Список методов в отказе описывает состав модуля на диске и прямо
об этом говорит. Неизвестный ключ внутри метода пакета (например, опечатка в названии
признака) теперь отклоняется до записи с перечнем допустимых — молча проигнорирован он больше
быть не может.

### Поиск по коду наконец слушается указания объекта и вида модуля

Поиск текста по коду принимал имя объекта и вид модуля, но не применял их: искал по всему
проекту и отдавал совпадения из посторонних модулей. Со стороны это выглядело как объектный
поиск — по описанию параметра он таким и обещан, — поэтому найденное в чужом модуле
принималось за найденное в указанном. На типовой конфигурации один такой вызов
просматривал несколько тысяч файлов и занимал полминуты.

Исправлено: указание объекта и вида модуля действительно сужает область. Имя объекта без
вида модуля ищет по всем его файлам, включая формы и команды; вместе с видом модуля — ровно
в этом модуле; один вид модуля без объекта — во всех модулях этого вида. Поиск по общему
модулю теперь идёт сканом одного файла и отвечает мгновенно. Если такого объекта или такого
его модуля в области нет, инструмент честно отказывает и подсказывает, что проверить, — а не
показывает результаты всего проекта под видом объектных. Область, по которой шёл поиск,
теперь видна прямо в ответе. Вызовы без этих параметров работают в точности как раньше.

## Юнит-тесты (YAxUnit)

### Повторный вызов за результатом больше не начинает прогон сначала

Прогон, не уложившийся в одно ожидание, добирается повторным вызовом. Если в этом вызове
стоял принудительный перезапуск, каждый повтор запускал 1С заново и стирал уже готовый
отчёт — а подсказка звала повторить «с теми же параметрами», то есть снова с
перезапуском. Получался круг, из которого результата не было вовсе: на наборе из
трёхсот тестов это по девять минут за круг.

Исправлено: пока прогон с этими параметрами идёт, принудительный перезапуск пропускается
и в ответе так и написано — почему и что делать. Подсказки теперь прямо говорят повторить
вызов БЕЗ перезапуска. А когда перезапуск действительно нужен, отчёт прошлого прогона
сохраняется и его путь приходит в ответе: даже во время нового прогона прежний результат
остаётся под рукой.

### Готовый отчёт отдаётся, а не отбрасывается как устаревший

Отчёт переиспользуется, пока тестовые модули не менялись, и это определялось по времени
файлов. Но прогон и обновление базы сами переписывают выгрузку расширения — теми же
самыми строками, только время файла становится новее отчёта. Готовый результат объявлялся
устаревшим, и вместо него шёл новый прогон; при выключенном обновлении базы вместо отчёта
приходил отказ «база не синхронизирована», хотя результат лежал на диске.

Исправлено: правку теста теперь видно по содержимому модулей, а не по времени файлов.
Перезапись тем же текстом отчёт не обесценивает, настоящая правка — как и раньше —
запускает свежий прогон. Отказ по несинхронной базе больше не молчит о готовом отчёте:
в ответе есть его путь и время.

### Прогон, который не начался, больше не висит «выполняется» без конца

Если клиент 1С так и не поднялся, запуск оставался в среде «незавершённым» навсегда.
Каждый следующий вызов уходил его ждать и возвращал одно и то же, а принудительный
перезапуск в этом состоянии не срабатывал — выйти было нечем, кроме перезапуска среды.
Вдобавок за клиента прогона засчитывался любой процесс платформы, появившийся на машине
позже: на компьютере с несколькими открытыми средами разработки инструмент сообщал
«клиент прогона жив», когда никакого прогона не было.

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

## Сценарное тестирование (Vanessa)

### Прогон сценария больше не трогает базу без спроса

Прогон сценария и снимок формы поднимают настоящую 1С, и перед стартом инструмент приводил
информационную базу в соответствие с проектом. Делал он это молча и всегда: клиент просил
один сценарий только на чтение, а в базу уезжали основная конфигурация и посторонние
расширения соседних проектов рабочей области — включая те, которых в базе вообще не было, они
там просто появлялись. Отказаться было нечем, и состав загрузки заранее нигде не показывался;
на контуре, где конфигурация на замке и выкладка идёт только файлом, это цена, за которую
сценарные прогоны через плагин просто перестают использовать.

Исправлено: появился параметр `updateInfobase`. По умолчанию (`auto`) база по-прежнему
приводится в соответствие — без этого 1С показывает окно «Обновить и запустить?» и прогон
виснет, — но теперь состав загрузки приходит в ответе отдельным блоком: кто именно грузится и
что с ним делается. Посторонние расширения, которых в базе ещё нет, `auto` туда больше не
публикует: прогон останавливается и называет их поимённо, предлагая либо разрешить публикацию
явно (`full`), либо сделать её отдельным осознанным действием, либо закрыть эти проекты в
рабочей области. Свой проект и его конфигурация-владелец публикуются как обычно. Значение
`skip` запрещает трогать базу вовсе: если проект и база разошлись, прогон честно откажется и
покажет, что именно разошлось, вместо того чтобы менять базу. Отказ обновления теперь тоже
несёт этот состав — раньше ответ говорил «не удалось обновить», а часть изменений уже была в
базе.

### Правка сценария даёт свежий результат, а не вчерашний отчёт

Если поправить `.feature`-файл и запустить прогон снова по тому же пути, в ответ мог прийти
отчёт предыдущей редакции — тот же самый, слово в слово. Особенно надёжно это повторялось,
когда прошлый прогон запускался с оставленными открытыми окнами 1С. Агент видел зелёный
результат у заведомо красного сценария (или наоборот) и делал выводы по несуществующему
прогону; обходились переименованием файла.

Исправлено: результат прогона привязан к содержимому сценариев, а не только к их пути. Любая
правка файла — это новый прогон с чистого листа, даже если путь и имя не менялись. Готовый
отчёт отдаётся один раз: повторный вызов после того, как отчёт уже получен, запускает прогон
заново, а не показывает старый. Оставленные открытыми окна 1С прошлого прогона больше не
мешают следующему запуститься.

### Отбор по тегам действительно отбирает

Указание тега не давало ничего: прогонялись все сценарии подряд, включая те, что откатывали
состояние, которое проверял отобранный сценарий.

Исправлено: отбор выполняется до запуска 1С — непрошедшие сценарии не выполняются вовсе.
В ответе видно, сколько сценариев отобрано из скольких и какие пропущены. Тег пишется строкой
`@имя` перед сценарием (тег перед «Функционал» действует на все его сценарии), в параметре
знак `@` не нужен и регистр не важен. Если под указанный тег не подошёл ни один сценарий,
прогон не запускается и говорит об этом прямо, а не поднимает 1С впустую.

### Ожидание прогона укладывается в один вызов

Долгий прогон должен возвращать «ещё выполняется» и продолжаться в фоне, но на подготовке
(приведение базы в соответствие) и на самом ожидании отсчитывались два независимых срока.
В сумме один вызов мог занять вдвое больше допустимого, и вместо честного «ещё выполняется»
агент получал обрыв связи, после которого непонятно, идёт прогон или нет.

Исправлено: у вызова один общий срок, который делят между собой подготовка и ожидание, и он
заведомо короче того, что выдерживают клиенты. Больше указанного потолка запросить нельзя —
значение приводится к нему, и это написано в описании параметра.

### Несколько снимков в одном сценарии видно до прогона

Второй и третий шаги сохранения снимка в одном и том же сценарии проходили зелёными, а файлов
не создавали: средство съёмки пишет один кадр на сценарий. Прогон выглядел успешным, снимков
не было.

Исправлено: проверка сценария без прогона находит такие места, называет файл, сценарий и
строку и даёт рецепт — разнести шаги по отдельным сценариям. Если файлы всё-таки не создались,
та же причина названа и в ответе прогона.

### Подсказка про вход клиента тестирования не сбивает с толку

Когда второе окно 1С не поднималось, ответ всегда советовал вписать логин в шаг подключения —
даже если логин там уже был вписан. Совет невыполним, а настоящая причина (разовый не-старт
окна, лечится повтором) оставалась ненайденной.

Исправлено: подсказка теперь зависит от сценария. Логина в шаге подключения нет — совет
прежний, вписать его. Логин есть — ответ так и говорит: дело не в нём, сначала просто повтори
прогон, а если повторяется — проверь свободные слоты лицензии 1С и правильность самого логина.
