Initial project import
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
# Common form modules
|
||||
|
||||
## Proven form facts
|
||||
|
||||
The `test2` common forms `t_Форма` and `tt_Форма3` are distinct objects with
|
||||
distinct GUIDs and descriptors. A label must be decoded from the descriptor;
|
||||
do not shorten or normalize it by guesswork (`tt_Форма3` is not `t_Форма3`).
|
||||
|
||||
A form `.0` payload can contain more than a simple standalone BSL string. The
|
||||
adapter must use the proven container extractor and preserve all non-BSL
|
||||
segments, including form settings and command metadata.
|
||||
|
||||
## Module patch rules
|
||||
|
||||
- Obtain the BSL region from the decoded container, not from a global text
|
||||
search over compressed bytes.
|
||||
- Count the requested anchor in the relevant BSL region.
|
||||
- Replace a unique exact fragment once; report ambiguity otherwise.
|
||||
- Re-encode using the source payload’s detected codec and line-ending style.
|
||||
- Read back, re-extract BSL, and verify the target occurrence count.
|
||||
|
||||
## Pending-state resolution
|
||||
|
||||
When `ConfigCASSave` contains a `__configinfo` map, that map is authoritative
|
||||
for the pending overlay even if the corresponding module row is absent. The
|
||||
active `ConfigCAS` source must be selected through the saved map before a new
|
||||
delta row is created. Reading only active content can incorrectly conclude
|
||||
that a pending comment is absent and cause a duplicate insertion.
|
||||
@@ -0,0 +1,55 @@
|
||||
# Граф составляющих объекта конфигурации
|
||||
|
||||
Объект конфигурации — это корень, а не минимальная единица работы. Его
|
||||
составляющие: модуль объекта, формы и их модули, макеты, схема компоновки
|
||||
данных (СКД), а после декодирования СКД — наборы данных, запросы, поля,
|
||||
ресурсы и варианты. Для записи нужен адрес именно составляющей и доказанный
|
||||
физический носитель этой составляющей.
|
||||
|
||||
## Публичная инвентаризация
|
||||
|
||||
`metadata.object.components` — read-only фасад над уже доказанными SQL
|
||||
декодерами. Он принимает обычный селектор владельца (`ref` либо `kind` и
|
||||
`name`, при необходимости `extension`) и возвращает граф:
|
||||
|
||||
- корень `metadata_object`;
|
||||
- только реально найденные `module`, `form`, `template` и `scd`;
|
||||
- публичные `path` и `read_selector` каждого потомка;
|
||||
- `unresolved` для областей, которые не были подтверждены.
|
||||
|
||||
Метод не создаёт потомок потому, что он обычно есть у такого типа объекта.
|
||||
Например, пустой ответ `metadata.object.modules` у общей формы означает
|
||||
«модуль этим маршрутом не найден», а не повод назвать форму модулем.
|
||||
|
||||
Пример запроса:
|
||||
|
||||
```json
|
||||
{
|
||||
"method": "metadata.object.components",
|
||||
"payload": {
|
||||
"base_id": "upo_test",
|
||||
"extension": "test2",
|
||||
"ref": "Report.tt_Отчет",
|
||||
"include_storage": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`read_selector` можно передать следующему read-only методу. Это не является
|
||||
разрешением на запись: запись выбирает компонент по его `path`, повторно
|
||||
подтверждает конкретный carrier/stream и разрешается только для семейства
|
||||
контейнеров с доказанным byte-preserving кодеком.
|
||||
|
||||
## Иерархия и кодеки
|
||||
|
||||
Логический BSL один и тот же независимо от владельца, но его физический
|
||||
носитель может различаться. Поэтому не нужны отдельные эвристики «для формы»
|
||||
и «для отчёта»: нужен реестр семейств carrier-кодеков. Один кодек применяется
|
||||
к нескольким типам объектов лишь после доказательства одинаковых границ,
|
||||
непрозрачных атомов и round-trip проверки.
|
||||
|
||||
Текущий пример: модуль общего формы в `upo_test/test2` имеет доказанный
|
||||
write-кодек saved-state; обнаруженный поток модуля отчёта — только
|
||||
read-only structural codec. Второй компонент может быть найден и прочитан,
|
||||
но не получит разрешение на SQL-запись, пока его служебный хвост не будет
|
||||
декодирован.
|
||||
@@ -0,0 +1,115 @@
|
||||
# Модуль объекта отчёта в расширении
|
||||
|
||||
Статус: чтение, точное разрешение владельца и контролируемая запись короткого
|
||||
фрагмента поддержаны для доказанного hash-keyed saved-state маршрута.
|
||||
|
||||
Наблюдение в `upo_test`, расширение `test2`, отчёт `tt_Отчет`: сохранённый файл
|
||||
`<extension-guid>__<report-guid>.0` является `raw_deflate` контейнером из пяти
|
||||
потоков. BSL-модуль расположен в потоке `4`.
|
||||
|
||||
Поток начинается читаемым UTF-8-комментарием, но последующий текст содержит
|
||||
нулевые байты и смешанное представление символов. Общий потоковый декодер
|
||||
позволяет найти комментарий, однако его обратное кодирование меняет байты
|
||||
неизменённого хвоста BSL. Экспериментальная запись показала это в Конфигураторе
|
||||
и была немедленно восстановлена из парной резервной копии.
|
||||
|
||||
Правило: наличие читаемого BSL-фрагмента не доказывает возможность записи.
|
||||
Для потока с `NUL` адаптер возвращает
|
||||
`mixed_encoding_module_stream_unsupported` и не создаёт SQL-изменений.
|
||||
Это не означает, что для каждого отчёта нужен свой кодер: один доказанный
|
||||
кодек может обслуживать все модули с одинаковым физическим носителем.
|
||||
|
||||
Два ручных образца определили безопасную границу записи: редактируется только
|
||||
объявленный UTF-8-префикс, а непрозрачный хвост и остальные потоки сохраняются
|
||||
побайтно. Для hash-keyed overlay рабочий слой создаётся доказанным копированием
|
||||
подтверждённых ключей `ConfigCAS → ConfigCASSave`; `__configinfo` для него не
|
||||
создаётся и не предполагается.
|
||||
|
||||
Текущая реализация `parser.cas_payload.stream_blocks_with_data` ищет похожие
|
||||
заголовки регулярным выражением по всему распакованному буферу. В потоке
|
||||
отчёта такие последовательности встречаются и внутри данных, поэтому это
|
||||
эвристика для чтения, а не структурный декодер. Нельзя использовать её индекс
|
||||
потока как основание для обратной записи.
|
||||
|
||||
Структурный read-only декодер `decode_declared_utf8_bsl_prefix` подтверждён на
|
||||
этом образце: пять последовательных блоков; пятый имеет `declared_1 = 68` и
|
||||
`declared_2 = 512`. Первые 68 байт — UTF-8 BOM и точный BSL-текст, оставшиеся
|
||||
444 байта — непрозрачный служебный хвост. Декодер вернул только:
|
||||
`// protocol-report-baseline-1` и `// protocol-report-manual-change-4`.
|
||||
|
||||
## Пара ручных образцов `2 → 3`
|
||||
|
||||
Образцы `samples/manual-change-2.json` и `samples/manual-change-3.json`
|
||||
содержат raw-deflate байты, сохранённые человеком в Конфигураторе. В
|
||||
распакованном контейнере длиной 1283 байта замена цифры `2` на `3` изменила
|
||||
BSL ровно в смещении `838` (`0x32 → 0x33`). Одновременно платформа изменила
|
||||
шесть служебных диапазонов: `110..113`, `230..252`, `437..464`, `590..593`,
|
||||
`598..601`, `716..719`. Трёхбайтовое значение повторяется в нескольких
|
||||
местах, а два диапазона содержат связанные Base64-представления.
|
||||
|
||||
Это доказывает, что нельзя перепаковывать поток общим writer'ом. Отдельный
|
||||
fixed-width кодек меняет только первые `declared_1` байт: короткий текст
|
||||
дополняется пробелами внутри этого поля, хвост и размер члена не меняются.
|
||||
Рост префикса или структурная правка процедуры явно отклоняются.
|
||||
|
||||
## Полный объявленный поток: переменная длина
|
||||
|
||||
Нельзя переносить ограничение fixed-width с описанного выше носителя на все
|
||||
объектные BSL-модули. На рабочем маршруте `upo / фс_Отчеты /
|
||||
Report.УОП_ПечатьЦенниковАссортимента / .2 / stream:4` подтверждён другой
|
||||
контейнер: у выбранного BSL-потока `declared_1 == declared_2 == 36101` и
|
||||
`opaque_tail_bytes == 0`. Это полный UTF-8 поток, а не префикс перед
|
||||
непрозрачными данными.
|
||||
|
||||
Для такого носителя адаптер использует обычный структурный stream writer:
|
||||
он меняет текст, пересобирает оба объявленных размера в заголовке и сдвигает
|
||||
только последующие байты контейнера. Локальная обратная проверка целевой
|
||||
замены `НоваяСтрока.Выбран = Истина;` на более длинный фрагмент дала размер
|
||||
потока `36101 → 36198`, новый заголовок `36198/36198`, одно новое вхождение и
|
||||
нулевое старое. Все байты до заголовка выбранного потока сохранились.
|
||||
|
||||
Правило выбора кодека: fixed-width применяется **только** если доказан
|
||||
ненулевой непрозрачный хвост; если `declared_1 == declared_2` и хвоста нет,
|
||||
безопасна контролируемая замена переменной длины через структурный writer.
|
||||
Неизвестный или частично декодированный контейнер остаётся заблокированным,
|
||||
а не переводится в переменную длину по предположению.
|
||||
|
||||
## Правило публичного маршрута
|
||||
|
||||
Если объектный модуль состоит только из комментариев, это всё равно BSL-модуль:
|
||||
у него нет маркеров `Процедура`/`Функция`, но его наличие подтверждает
|
||||
структурный UTF-8-префикс в потоке. Адаптер обязан вернуть владельца и точный
|
||||
селектор чтения, не заставляя клиента искать поток. При записи он обязан
|
||||
использовать только fixed-width кодек, а не общий stream writer, который
|
||||
перезаписывает непрозрачный хвост. Парное обновление `__configinfo` допустимо
|
||||
только в отдельно подтверждённом каноническом layout.
|
||||
|
||||
## Повтор `code.write` после успешной записи
|
||||
|
||||
Повтор одного и того же публичного `code.write` не является новой операцией.
|
||||
До автоматической подготовки `ConfigCASSave` адаптер читает указанную
|
||||
процедуру в `effective_working`. Если старого фрагмента уже нет, а точный
|
||||
новый фрагмент присутствует ровно один раз в этой же процедуре, результат —
|
||||
`status: already_applied`, `applied: false`. В этом случае запрещены и
|
||||
подготовка saved-state, и новая SQL-запись.
|
||||
|
||||
Это правило предотвращает опасный путь: повторный запрос нельзя начинать с
|
||||
активного `ConfigCAS`, потому что его копирование способно заново построить
|
||||
рабочую копию из доизменённого источника и скрыть факт уже выполненной
|
||||
операции. Если оба фрагмента отсутствуют, новый фрагмент встречается
|
||||
несколько раз либо процедура не подтверждена, идемпотентность не
|
||||
предполагается: применяется обычная безопасная ошибка `not_found`/
|
||||
`ambiguous` или диагностика маршрута.
|
||||
|
||||
## Цепочка версий `2 → 3 → 4`
|
||||
|
||||
Третий live-SQL образец подтвердил повторяемую часть протокола. 20-байтовое
|
||||
Base64-поле в каждой новой версии равно SHA-1 сырого файла предыдущей версии:
|
||||
запись `3` хранит SHA-1 записи `2`, а запись `4` — SHA-1 записи `3`. Это
|
||||
доказанная ссылка версии, а не случайный текст. Его контрольный SHA-1:
|
||||
`fc84f0a9ef17034f8d82f44c5f9b07064864b524`.
|
||||
|
||||
Рядом расположен 16-байтовый токен, который меняется при каждом сохранении и
|
||||
дублируется фрагментами в трёх служебных местах. Алгоритм его создания не
|
||||
декодирован: адаптер его не генерирует и не изменяет. Его нельзя считать
|
||||
основанием для создания или изменения `__configinfo` в hash-keyed overlay.
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"schema": "onec_report_module_stream_sample.v1",
|
||||
"origin": "Configurator manual save in upo_test/test2/tt_Отчет; no adapter write",
|
||||
"logical_change": "// protocol-report-manual-change-2",
|
||||
"physical_file_name": "<extension-guid>__<report-guid>.0",
|
||||
"compression": "raw_deflate",
|
||||
"raw_sha1": "89827a3c7fa07ae50a268d20a7cee34195d1d7a7",
|
||||
"raw_bytes": 618,
|
||||
"inflated_sha1": "6385a80972841eb8a97df43596ed15dd16966495",
|
||||
"inflated_bytes": 1283,
|
||||
"raw_base64": "7VLJbhNBEG2iPlnyBXHgBKMRByDTcc/S0zNCBtnEie2MvI2XwQJFPat3J/ZkV4TCgV/gCge+ggMfwE9w4MaBTzDtbLIFQYgzT+rq6q5+9apVNZvNXoMVAG6BCyQT+ByyIVw7NLyAkExs8idv+Zpx2kdO+7Zy4V/RFCxcOws0of/q4cvcCnj/+OzRfJ+jC0YgBOMlVRwKl+wl+o9Pn09USZawJIoSPrUyL5qqOQ39SafeLxxF5YlbpLvtDc9JJhMZfdUYD+L8gdHqWa2CWqNuX8aHekQ766GjlUqpIKodbzQcJ5M+lZKJE1MSZeK6MnMZ0onMkKYGKnJVipFHNdPHpoI9F4tSs1jp9OS6TTZ9u0GmTlVtDtrtmm9YuTTPYRjEoExHGtVVpOnYQKYcYkRNrCvU1TSdeaJU2S8PGo2jdaVXtVvTeF1TUsNi02rtVKp/mWONV7JVydojpRo6qtVNPW8acbe+29JLBWNvnoXyqjXKufwj/Dcm0RHzVA/JpumFLlYJ8xVROp760f6w5tml4n6l1GnQYSNbdFyl0MN/yHHd56vxUJbG46q/i31+AGwQgwkIAANDflrst2bc2G9dkgMiK4y5SP6H6Yq53iG3S2raTWqplLAzGcdjbzxAk2BnPImRy6bBoDsK5uq/CQ/ZaI8NkNdhoyhACtY9X2WUiFLZjywrzvhReJDP94ZRJqjn28pqPlcz0qdwjZcUg21wD2ZgGj6FCrcYlqHA/SfQgoIgfN2y30l3efzZ5R09f4dhlvuLvC1ILnkGvMNtGd7mUQJz8P4vTMLPBJrwe/YNl/jwxT4TBPAf5/gJ"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"schema": "onec_report_module_stream_sample.v1",
|
||||
"origin": "Configurator manual save in upo_test/test2/tt_Отчет; no adapter write",
|
||||
"logical_change": "// protocol-report-manual-change-3",
|
||||
"physical_file_name": "<extension-guid>__<report-guid>.0",
|
||||
"compression": "raw_deflate",
|
||||
"raw_sha1": "357c39a55e8f66c3efd8f7aac968a4db5d5eb5fb",
|
||||
"raw_bytes": 620,
|
||||
"inflated_sha1": "eb72cadfe12f68969cd278901a6f83e627ee1a53",
|
||||
"inflated_bytes": 1283,
|
||||
"raw_base64": "7VLLbhMxFDWVV5GyQSxYwWjEApRxa8+MxzOqAkrV0HQ6ah6TVyMQ8jyTNMmkybSlVBWCBb8AWxZ8BQs+gBV/wIIdCz4huE8lgiLEmiP5+trX555r3TubzV6CJQBugHNkM/gMxJSuHBadQ8pmNsSTN2LNBO2DoH1bOvcvaSqWrpw5mrT79P6T4hKofHn34HQ/RQ+MQASSBVUcSRfsBfqPj5+ONYUoWJFlBZ84hZ2mZk2jYNKt724exeWJZ7O9zmO/nc1mCkbOTAZp6dBs9Z3WplZj3i6h+lGQs8l2vZ0YNNnTUr5hr0/zJ0o2c2wpMqGeR7jHkUEJR7oWasjTGEY+060AWyr2PSwrTbvS7ZO6SzcCt0Gn7arWHHQ6tcB0inmRwzSpybiBdGZoSDewiSwSYcQsbKjM03WD+7JSOSgPGo2jdbVfdVvTdF1XV4Z202mNK9W/zLEsKunt2EallIvD/caWneB4bLJ+tdOuEcMXWZioWmeCKz4ifmNRA3Ff8xGxLD/ysEZ5oMrKi2kQHwxrvrttH1S2uw02bKzZbU/d7OM/5Ljq8+V4qAvjcdnf+T7fAy5IwQSEgIOhOM33Wzev7behkJASlXMPkX+YrlToPRd2QU2/Tm1lRRpPkjTxkwGahONkkiKPT8NBbxSeqv8mPOSjfT5AfpeP4hBp2PADjTMqK+Ugdpy0EMTRYanUH8aFsF7qqLlSsWbmT+CyKCkFz8AdWIB5+BCqwmJYhpLwV6EDJUn6uuW+VW6L+KOLO3b2DsM14c/ztiC94JnwlrBleFNEKSzCu78wqThTaMHva6+FxPvP7itJAv9xhp8="
|
||||
}
|
||||
Reference in New Issue
Block a user