feat(support-edit): навык переключения состояния поддержки + ссылка из диагностики гарда

Замыкает петлю issue #23: после отказа support-guard модель может
легитимно включить редактирование. support-edit правит правила поддержки
в Ext/ParentConfigurations.bin выгрузки (только XML; в ИБ — полной загрузкой):
  -Path <путь> -Set editable|off-support|locked   (пообъектно или корень)
  -Path <путь> -Capability on|off                  (возможность изменения)
Path-based, симметрично гарду — модель берёт путь прямо из отказа.

Реализация: regex-замена in-place по разобранному формату bin (round-trip
байт-в-байт; парсер подтверждён consumed=100% на корпусе acc/erp/K=7).
При выключенной возможности (G=1) пообъектный -Set отказывает с подсказкой
«сначала -Capability on» (явные шаги). Включение возможности ставит всё на
замок (вендорские флаги «не редактировать» в выгрузке недоступны — массовой
разблокировки нет; non-goal). Оба порта дают байт-в-байт идентичный bin.

Диагностика support-guard (32 файла, 16 мутаторов × 2 порта) теперь печатает
готовую команду support-edit под конкретный отказ.

Тесты: фикстуры g0/g1 + кейсы set-editable/off-support/предусловие/capability
со снапшотами bin; зелёные на PowerShell и Python. Все 16 мутаторов +
support-edit зелёные на обоих рантаймах.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-06-20 16:45:43 +03:00
co-authored by Claude Opus 4.8
parent acbd6be46c
commit de04a8dc7a
65 changed files with 654 additions and 32 deletions
@@ -0,0 +1,15 @@
{
"script": "support-edit/scripts/support-edit",
"setup": "none",
"args": [
{
"flag": "-Path",
"from": "workPath",
"field": "path"
}
],
"snapshot": {
"root": "workDir",
"normalizeUuids": true
}
}
@@ -0,0 +1,14 @@
{
"name": "Capability off: вся конфа read-only",
"setup": "fixture:g0",
"params": {
"path": "Configuration.xml"
},
"args_extra": [
"-Capability",
"off"
],
"expect": {
"stdoutContains": "ВЫКЛЮЧЕНА"
}
}
@@ -0,0 +1,14 @@
{
"name": "Capability on: возможность включена",
"setup": "fixture:g1",
"params": {
"path": "Configuration.xml"
},
"args_extra": [
"-Capability",
"on"
],
"expect": {
"stdoutContains": "ВКЛЮЧЕНА"
}
}
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" version="2.17">
<Catalog uuid="22222222-2222-2222-2222-222222222222">
<Properties>
<Name>Locked</Name>
<Synonym/>
<CodeLength>9</CodeLength>
<DescriptionLength>25</DescriptionLength>
</Properties>
<ChildObjects/>
</Catalog>
</MetaDataObject>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" version="2.17">
<Catalog uuid="33333333-3333-3333-3333-333333333333">
<Properties>
<Name>Removed</Name>
<Synonym/>
<CodeLength>9</CodeLength>
<DescriptionLength>25</DescriptionLength>
</Properties>
<ChildObjects/>
</Catalog>
</MetaDataObject>
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" version="2.17">
<Configuration uuid="11111111-1111-1111-1111-111111111111">
<Properties>
<Name>ТестКонфиг</Name>
<Vendor>ТестВендор</Vendor>
<Version>1.0</Version>
</Properties>
<ChildObjects>
<Catalog>Locked</Catalog>
<Catalog>Removed</Catalog>
</ChildObjects>
</Configuration>
</MetaDataObject>
@@ -0,0 +1 @@
{6,0,1,aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa,0,bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb,"1.0","ТестВендор","ТестКонфиг",3,0,0,11111111-1111-1111-1111-111111111111,0,0,22222222-2222-2222-2222-222222222222,22222222-2222-2222-2222-222222222222,2,0,33333333-3333-3333-3333-333333333333,33333333-3333-3333-3333-333333333333}
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" version="2.17">
<Catalog uuid="22222222-2222-2222-2222-222222222222">
<Properties>
<Name>Locked</Name>
<Synonym/>
<CodeLength>9</CodeLength>
<DescriptionLength>25</DescriptionLength>
</Properties>
<ChildObjects/>
</Catalog>
</MetaDataObject>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" version="2.17">
<Catalog uuid="33333333-3333-3333-3333-333333333333">
<Properties>
<Name>Removed</Name>
<Synonym/>
<CodeLength>9</CodeLength>
<DescriptionLength>25</DescriptionLength>
</Properties>
<ChildObjects/>
</Catalog>
</MetaDataObject>
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" version="2.17">
<Configuration uuid="11111111-1111-1111-1111-111111111111">
<Properties>
<Name>ТестКонфиг</Name>
<Vendor>ТестВендор</Vendor>
<Version>1.0</Version>
</Properties>
<ChildObjects>
<Catalog>Locked</Catalog>
<Catalog>Removed</Catalog>
</ChildObjects>
</Configuration>
</MetaDataObject>
@@ -0,0 +1 @@
{6,1,1,aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa,1,bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb,"1.0","ТестВендор","ТестКонфиг",3,1,0,11111111-1111-1111-1111-111111111111,1,0,22222222-2222-2222-2222-222222222222,22222222-2222-2222-2222-222222222222,1,0,33333333-3333-3333-3333-333333333333,33333333-3333-3333-3333-333333333333}
@@ -0,0 +1,14 @@
{
"name": "Set editable: объект на замке → редактируется",
"setup": "fixture:g0",
"params": {
"path": "Catalogs/Locked.xml"
},
"args_extra": [
"-Set",
"editable"
],
"expect": {
"stdoutContains": "редактируется с сохранением поддержки"
}
}
@@ -0,0 +1,14 @@
{
"name": "Set off-support: объект снят с поддержки",
"setup": "fixture:g0",
"params": {
"path": "Catalogs/Locked.xml"
},
"args_extra": [
"-Set",
"off-support"
],
"expect": {
"stdoutContains": "снят с поддержки"
}
}
@@ -0,0 +1,12 @@
{
"name": "Set при выключенной возможности → отказ-предусловие",
"setup": "fixture:g1",
"params": {
"path": "Catalogs/Locked.xml"
},
"args_extra": [
"-Set",
"editable"
],
"expectError": "Capability on"
}
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" version="2.17">
<Catalog uuid="UUID-001">
<Properties>
<Name>Locked</Name>
<Synonym/>
<CodeLength>9</CodeLength>
<DescriptionLength>25</DescriptionLength>
</Properties>
<ChildObjects/>
</Catalog>
</MetaDataObject>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" version="2.17">
<Catalog uuid="UUID-001">
<Properties>
<Name>Removed</Name>
<Synonym/>
<CodeLength>9</CodeLength>
<DescriptionLength>25</DescriptionLength>
</Properties>
<ChildObjects/>
</Catalog>
</MetaDataObject>
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" version="2.17">
<Configuration uuid="UUID-001">
<Properties>
<Name>ТестКонфиг</Name>
<Vendor>ТестВендор</Vendor>
<Version>1.0</Version>
</Properties>
<ChildObjects>
<Catalog>Locked</Catalog>
<Catalog>Removed</Catalog>
</ChildObjects>
</Configuration>
</MetaDataObject>
@@ -0,0 +1 @@
{6,1,1,UUID-001,1,UUID-002,"1.0","ТестВендор","ТестКонфиг",3,1,0,UUID-003,1,0,UUID-004,UUID-004,1,0,UUID-005,UUID-005}
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" version="2.17">
<Catalog uuid="UUID-001">
<Properties>
<Name>Locked</Name>
<Synonym/>
<CodeLength>9</CodeLength>
<DescriptionLength>25</DescriptionLength>
</Properties>
<ChildObjects/>
</Catalog>
</MetaDataObject>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" version="2.17">
<Catalog uuid="UUID-001">
<Properties>
<Name>Removed</Name>
<Synonym/>
<CodeLength>9</CodeLength>
<DescriptionLength>25</DescriptionLength>
</Properties>
<ChildObjects/>
</Catalog>
</MetaDataObject>
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" version="2.17">
<Configuration uuid="UUID-001">
<Properties>
<Name>ТестКонфиг</Name>
<Vendor>ТестВендор</Vendor>
<Version>1.0</Version>
</Properties>
<ChildObjects>
<Catalog>Locked</Catalog>
<Catalog>Removed</Catalog>
</ChildObjects>
</Configuration>
</MetaDataObject>
@@ -0,0 +1 @@
{6,0,1,UUID-001,0,UUID-002,"1.0","ТестВендор","ТестКонфиг",3,0,0,UUID-003,0,0,UUID-004,UUID-004,0,0,UUID-005,UUID-005}
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" version="2.17">
<Catalog uuid="UUID-001">
<Properties>
<Name>Locked</Name>
<Synonym/>
<CodeLength>9</CodeLength>
<DescriptionLength>25</DescriptionLength>
</Properties>
<ChildObjects/>
</Catalog>
</MetaDataObject>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" version="2.17">
<Catalog uuid="UUID-001">
<Properties>
<Name>Removed</Name>
<Synonym/>
<CodeLength>9</CodeLength>
<DescriptionLength>25</DescriptionLength>
</Properties>
<ChildObjects/>
</Catalog>
</MetaDataObject>
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" version="2.17">
<Configuration uuid="UUID-001">
<Properties>
<Name>ТестКонфиг</Name>
<Vendor>ТестВендор</Vendor>
<Version>1.0</Version>
</Properties>
<ChildObjects>
<Catalog>Locked</Catalog>
<Catalog>Removed</Catalog>
</ChildObjects>
</Configuration>
</MetaDataObject>
@@ -0,0 +1 @@
{6,0,1,UUID-001,0,UUID-002,"1.0","ТестВендор","ТестКонфиг",3,0,0,UUID-003,1,0,UUID-004,UUID-004,2,0,UUID-005,UUID-005}
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" version="2.17">
<Catalog uuid="UUID-001">
<Properties>
<Name>Locked</Name>
<Synonym/>
<CodeLength>9</CodeLength>
<DescriptionLength>25</DescriptionLength>
</Properties>
<ChildObjects/>
</Catalog>
</MetaDataObject>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" version="2.17">
<Catalog uuid="UUID-001">
<Properties>
<Name>Removed</Name>
<Synonym/>
<CodeLength>9</CodeLength>
<DescriptionLength>25</DescriptionLength>
</Properties>
<ChildObjects/>
</Catalog>
</MetaDataObject>
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" version="2.17">
<Configuration uuid="UUID-001">
<Properties>
<Name>ТестКонфиг</Name>
<Vendor>ТестВендор</Vendor>
<Version>1.0</Version>
</Properties>
<ChildObjects>
<Catalog>Locked</Catalog>
<Catalog>Removed</Catalog>
</ChildObjects>
</Configuration>
</MetaDataObject>
@@ -0,0 +1 @@
{6,0,1,UUID-001,0,UUID-002,"1.0","ТестВендор","ТестКонфиг",3,0,0,UUID-003,2,0,UUID-004,UUID-004,2,0,UUID-005,UUID-005}