fix(db-load-git,db-update): ловить тихие отказы платформы, как db-load-xml

Платформа рапортует об успехе (exit 0) и одновременно пишет в /Out-лог, что часть
метаданных отброшена. Детектор этого был только в db-load-xml, хотя db-load-git гоняет
тот же /LoadConfigFromFiles (и дописывает /UpdateDBCfg в тот же вызов), а db-update —
вторую половину той же цепочки. Оба лог печатали, но не разбирали.

Детектор извлечён в Find-SilentRejections / find_silent_rejections и внесён в реестр
семей check-inline-drift: инлайн-код гард сверять не умеет, а именно расхождение копий
и было бы главным риском такого дублирования.

Добавлен восьмой паттерн — «Для работы с конфигурацией необходима версия платформы не
меньше». Замерено при работе над issue #63: конфигурация с режимом совместимости выше
платформы грузится с кодом 0, db-update тоже отвечает 0, объекты в базу не попадают, а
отказ приходит только в рантайме. Строка обрезана до инвариантной части — конкретная
версия в сообщении меняется.

Текст предупреждения переписан. Убрана подсказка «pass -StrictLog to treat as error»:
ключ предназначен для регрессов (его передаёт verify-snapshots), а совет бессмысленный —
операция уже выполнена, и повторять её ради того же текста незачем. Формулировка больше
не утверждает «dropped properties/refs»: класс проблемы разный, а строки лога печатаются
следом и говорят за себя.

Две правки по дороге:

- `return ,$found` в паре с `@()` у вызывающего давал массив из одного пустого массива,
  то есть предупреждение «1 problem(s)» на чистом логе. Возврат без запятой-обёртки.
- py-порт писал предупреждение в stderr, PS1 — в stdout. В самом py-порте stderr занят
  исключительно фатальными «Error:» перед exit 1, так что не-фатальное предупреждение там
  было единственным исключением. Приведено к stdout — и к соглашению своего же файла, и к
  поведению PS1; verify-snapshots на падении читает `stderr || stdout`, поэтому диагностика
  не теряется.

Тесты: фейковая платформа .cmd, которая вычитывает путь из /Out и кладёт туда готовый лог,
— по четыре кейса на db-load-xml и db-update (отбраковка, она же под -StrictLog, новый
паттерн, чистый лог без предупреждения). Раньше детектор не был покрыт вообще.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-08-13 15:14:36 +03:00
co-authored by Claude Opus 5
parent 06f21ab3d1
commit a024b7da9c
15 changed files with 627 additions and 52 deletions
@@ -0,0 +1,42 @@
{
"name": "Чистый лог: предупреждения нет (иначе паттерн, ловящий всё подряд, прошёл бы остальные кейсы)",
"osOnly": "win32",
"preRun": [
{
"writeFile": {
"path": "fake.cmd",
"content": "@echo off\r\nrem SELF запоминаем ДО цикла: shift сдвигает и %0, после него %~dp0 указывает не на скрипт\r\nset SELF=%~dp0\r\n:loop\r\nif \"%~1\"==\"\" goto done\r\nif /i \"%~1\"==\"/Out\" set OUT=%~2\r\nshift\r\ngoto loop\r\n:done\r\ncopy /y \"%SELF%log.txt\" \"%OUT%\" >nul\r\nexit /b 0\r\n"
}
},
{
"writeFile": {
"path": "log.txt",
"content": "Загрузка конфигурации из файлов.\r\nЗагрузка завершена. Суммарное время выполнения операции: 780 миллисекунд.\r\n"
}
},
{
"writeFile": {
"path": "ib/1Cv8.1CD",
"content": "stub"
}
},
{
"writeFile": {
"path": "src/Configuration.xml",
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject/>"
}
}
],
"args_extra": [
"-V8Path",
"{workDir}\\fake.cmd",
"-InfoBasePath",
"{workDir}\\ib",
"-ConfigDir",
"{workDir}\\src"
],
"expect": {
"stdoutNotContains": "[warning] platform reported success, but the log contains"
},
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы"
}
@@ -0,0 +1,45 @@
{
"name": "Режим совместимости выше платформы: сообщение классифицируется как отказ (issue #63)",
"osOnly": "win32",
"preRun": [
{
"writeFile": {
"path": "fake.cmd",
"content": "@echo off\r\nrem SELF запоминаем ДО цикла: shift сдвигает и %0, после него %~dp0 указывает не на скрипт\r\nset SELF=%~dp0\r\n:loop\r\nif \"%~1\"==\"\" goto done\r\nif /i \"%~1\"==\"/Out\" set OUT=%~2\r\nshift\r\ngoto loop\r\n:done\r\ncopy /y \"%SELF%log.txt\" \"%OUT%\" >nul\r\nexit /b 0\r\n"
}
},
{
"writeFile": {
"path": "log.txt",
"content": "Для работы с конфигурацией необходима версия платформы не меньше, чем 8.3.27.\r\nТекущая версия 8.3.24.1691.\r\n"
}
},
{
"writeFile": {
"path": "ib/1Cv8.1CD",
"content": "stub"
}
},
{
"writeFile": {
"path": "src/Configuration.xml",
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject/>"
}
}
],
"args_extra": [
"-V8Path",
"{workDir}\\fake.cmd",
"-InfoBasePath",
"{workDir}\\ib",
"-ConfigDir",
"{workDir}\\src"
],
"expect": {
"stdoutContains": [
"[warning] platform reported success, but the log contains 1 problem(s):",
"необходима версия платформы не меньше"
]
},
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы"
}
@@ -0,0 +1,46 @@
{
"name": "Тихий отказ в логе: платформа вернула 0, навык предупреждает (fake platform)",
"osOnly": "win32",
"preRun": [
{
"writeFile": {
"path": "fake.cmd",
"content": "@echo off\r\nrem SELF запоминаем ДО цикла: shift сдвигает и %0, после него %~dp0 указывает не на скрипт\r\nset SELF=%~dp0\r\n:loop\r\nif \"%~1\"==\"\" goto done\r\nif /i \"%~1\"==\"/Out\" set OUT=%~2\r\nshift\r\ngoto loop\r\n:done\r\ncopy /y \"%SELF%log.txt\" \"%OUT%\" >nul\r\nexit /b 0\r\n"
}
},
{
"writeFile": {
"path": "log.txt",
"content": "Загрузка конфигурации из файлов.\r\nНеверное свойство объекта метаданных. Свойство LineNumberLength не входит в состав объекта метаданных TabularSection. - LineNumberLength\r\nЗагрузка завершена.\r\n"
}
},
{
"writeFile": {
"path": "ib/1Cv8.1CD",
"content": "stub"
}
},
{
"writeFile": {
"path": "src/Configuration.xml",
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject/>"
}
}
],
"args_extra": [
"-V8Path",
"{workDir}\\fake.cmd",
"-InfoBasePath",
"{workDir}\\ib",
"-ConfigDir",
"{workDir}\\src"
],
"expect": {
"stdoutContains": [
"[warning] platform reported success, but the log contains 1 problem(s):",
"Свойство LineNumberLength не входит в состав объекта метаданных"
],
"stdoutNotContains": "-StrictLog"
},
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы"
}
@@ -0,0 +1,44 @@
{
"name": "Тот же лог под -StrictLog: код возврата поднимается до 1 (fake platform)",
"osOnly": "win32",
"preRun": [
{
"writeFile": {
"path": "fake.cmd",
"content": "@echo off\r\nrem SELF запоминаем ДО цикла: shift сдвигает и %0, после него %~dp0 указывает не на скрипт\r\nset SELF=%~dp0\r\n:loop\r\nif \"%~1\"==\"\" goto done\r\nif /i \"%~1\"==\"/Out\" set OUT=%~2\r\nshift\r\ngoto loop\r\n:done\r\ncopy /y \"%SELF%log.txt\" \"%OUT%\" >nul\r\nexit /b 0\r\n"
}
},
{
"writeFile": {
"path": "log.txt",
"content": "Загрузка конфигурации из файлов.\r\nНеверное свойство объекта метаданных. Свойство LineNumberLength не входит в состав объекта метаданных TabularSection. - LineNumberLength\r\nЗагрузка завершена.\r\n"
}
},
{
"writeFile": {
"path": "ib/1Cv8.1CD",
"content": "stub"
}
},
{
"writeFile": {
"path": "src/Configuration.xml",
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaDataObject/>"
}
}
],
"args_extra": [
"-V8Path",
"{workDir}\\fake.cmd",
"-InfoBasePath",
"{workDir}\\ib",
"-ConfigDir",
"{workDir}\\src",
"-StrictLog"
],
"expect": {
"stdoutContains": "[warning] platform reported success, but the log contains 1 problem(s):"
},
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы",
"expectError": true
}
@@ -0,0 +1,34 @@
{
"name": "Чистый лог: предупреждения нет (иначе паттерн, ловящий всё подряд, прошёл бы остальные кейсы)",
"osOnly": "win32",
"preRun": [
{
"writeFile": {
"path": "fake.cmd",
"content": "@echo off\r\nrem SELF запоминаем ДО цикла: shift сдвигает и %0, после него %~dp0 указывает не на скрипт\r\nset SELF=%~dp0\r\n:loop\r\nif \"%~1\"==\"\" goto done\r\nif /i \"%~1\"==\"/Out\" set OUT=%~2\r\nshift\r\ngoto loop\r\n:done\r\ncopy /y \"%SELF%log.txt\" \"%OUT%\" >nul\r\nexit /b 0\r\n"
}
},
{
"writeFile": {
"path": "log.txt",
"content": "Загрузка конфигурации из файлов.\r\nЗагрузка завершена. Суммарное время выполнения операции: 780 миллисекунд.\r\n"
}
},
{
"writeFile": {
"path": "ib/1Cv8.1CD",
"content": "stub"
}
}
],
"args_extra": [
"-V8Path",
"{workDir}\\fake.cmd",
"-InfoBasePath",
"{workDir}\\ib"
],
"expect": {
"stdoutNotContains": "[warning] platform reported success, but the log contains"
},
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы"
}
@@ -0,0 +1,37 @@
{
"name": "Режим совместимости выше платформы: сообщение классифицируется как отказ (issue #63)",
"osOnly": "win32",
"preRun": [
{
"writeFile": {
"path": "fake.cmd",
"content": "@echo off\r\nrem SELF запоминаем ДО цикла: shift сдвигает и %0, после него %~dp0 указывает не на скрипт\r\nset SELF=%~dp0\r\n:loop\r\nif \"%~1\"==\"\" goto done\r\nif /i \"%~1\"==\"/Out\" set OUT=%~2\r\nshift\r\ngoto loop\r\n:done\r\ncopy /y \"%SELF%log.txt\" \"%OUT%\" >nul\r\nexit /b 0\r\n"
}
},
{
"writeFile": {
"path": "log.txt",
"content": "Для работы с конфигурацией необходима версия платформы не меньше, чем 8.3.27.\r\nТекущая версия 8.3.24.1691.\r\n"
}
},
{
"writeFile": {
"path": "ib/1Cv8.1CD",
"content": "stub"
}
}
],
"args_extra": [
"-V8Path",
"{workDir}\\fake.cmd",
"-InfoBasePath",
"{workDir}\\ib"
],
"expect": {
"stdoutContains": [
"[warning] platform reported success, but the log contains 1 problem(s):",
"необходима версия платформы не меньше"
]
},
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы"
}
@@ -0,0 +1,38 @@
{
"name": "Тихий отказ в логе: платформа вернула 0, навык предупреждает (fake platform)",
"osOnly": "win32",
"preRun": [
{
"writeFile": {
"path": "fake.cmd",
"content": "@echo off\r\nrem SELF запоминаем ДО цикла: shift сдвигает и %0, после него %~dp0 указывает не на скрипт\r\nset SELF=%~dp0\r\n:loop\r\nif \"%~1\"==\"\" goto done\r\nif /i \"%~1\"==\"/Out\" set OUT=%~2\r\nshift\r\ngoto loop\r\n:done\r\ncopy /y \"%SELF%log.txt\" \"%OUT%\" >nul\r\nexit /b 0\r\n"
}
},
{
"writeFile": {
"path": "log.txt",
"content": "Загрузка конфигурации из файлов.\r\nНеверное свойство объекта метаданных. Свойство LineNumberLength не входит в состав объекта метаданных TabularSection. - LineNumberLength\r\nЗагрузка завершена.\r\n"
}
},
{
"writeFile": {
"path": "ib/1Cv8.1CD",
"content": "stub"
}
}
],
"args_extra": [
"-V8Path",
"{workDir}\\fake.cmd",
"-InfoBasePath",
"{workDir}\\ib"
],
"expect": {
"stdoutContains": [
"[warning] platform reported success, but the log contains 1 problem(s):",
"Свойство LineNumberLength не входит в состав объекта метаданных"
],
"stdoutNotContains": "-StrictLog"
},
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы"
}
@@ -0,0 +1,36 @@
{
"name": "Тот же лог под -StrictLog: код возврата поднимается до 1 (fake platform)",
"osOnly": "win32",
"preRun": [
{
"writeFile": {
"path": "fake.cmd",
"content": "@echo off\r\nrem SELF запоминаем ДО цикла: shift сдвигает и %0, после него %~dp0 указывает не на скрипт\r\nset SELF=%~dp0\r\n:loop\r\nif \"%~1\"==\"\" goto done\r\nif /i \"%~1\"==\"/Out\" set OUT=%~2\r\nshift\r\ngoto loop\r\n:done\r\ncopy /y \"%SELF%log.txt\" \"%OUT%\" >nul\r\nexit /b 0\r\n"
}
},
{
"writeFile": {
"path": "log.txt",
"content": "Загрузка конфигурации из файлов.\r\nНеверное свойство объекта метаданных. Свойство LineNumberLength не входит в состав объекта метаданных TabularSection. - LineNumberLength\r\nЗагрузка завершена.\r\n"
}
},
{
"writeFile": {
"path": "ib/1Cv8.1CD",
"content": "stub"
}
}
],
"args_extra": [
"-V8Path",
"{workDir}\\fake.cmd",
"-InfoBasePath",
"{workDir}\\ib",
"-StrictLog"
],
"expect": {
"stdoutContains": "[warning] platform reported success, but the log contains 1 problem(s):"
},
"noSnapshot": "навык ничего не пишет в рабочий каталог — проверяется разбор лога платформы",
"expectError": true
}
+9
View File
@@ -214,6 +214,15 @@ const FAMILIES = [
},
// ─── Обвязка вызова платформы 1С (db-* и потребители) ────────────────────
// Детектор строк, о которых платформа сообщает, НЕ поднимая код возврата. Живёт во всех
// навыках, читающих /Out-лог загрузки: разъехавшийся список паттернов означал бы, что один
// навык ловит тихий отказ, а соседний по той же операции — нет.
{
name: 'platform: silent_rejections', py: 'find_silent_rejections', ps1: 'Find-SilentRejections',
variants: [
{ id: 'base', authority: 'db-load-xml', consumers: ['db-load-git', 'db-update'] },
],
},
{
name: 'platform: resolve_extra_args', py: 'resolve_extra_args', ps1: 'Resolve-ExtraArgs',
variants: [