Initial project import

This commit is contained in:
2026-08-14 09:40:51 +03:00
parent 00040e5ce4
commit d7099bf80d
146 changed files with 30509 additions and 1055 deletions
+46
View File
@@ -0,0 +1,46 @@
# SQL protocol knowledge base for 1C configuration storage
This directory is the durable, evidence-first record for the 1C SQL adapter.
It complements [the general format specification](../1c-sql-format-spec.md).
Do not put all observations into one chronological note: add a fact to the
document for its layer, object type, codec, operation, or experiment.
## Non-negotiable runtime rule
The adapter works **only through SQL**. It may decode and encode only what was
observed in the target database and proven by round-trip checks. It must never
invent a metadata object, physical path, BSL fragment, form element, join,
codec, or cryptographic value. Unknown or ambiguous work returns an explicit
unsupported/protocol-incomplete result.
The Configurator remains a human-operated consumer of the saved-state overlay.
The adapter does not start it, automate it, or claim to change its in-memory
state.
## Map
- [Rules and evidence discipline](rules/evidence-and-safety.md)
- [Agent contract: do not invent](rules/agent-contract.md)
- [Configuration SQL layers](layers/configuration-storage.md)
- [Extension saved-state overlay](extensions/saved-state-overlay.md)
- [Common form and BSL module handling](objects/common-form-module.md)
- [Object component graph and child selectors](objects/component-graph.md)
- [Report object-module carrier](objects/report-object-module.md)
- [Payload envelope codec](codecs/payload-envelope.md)
- [`__configinfo` map and service atom](codecs/configinfo.md)
- [Configurator refresh behaviour](operations/configurator-cache.md)
- [Reproducible `upo_test/test2` experiment](experiments/upo-test-test2.md)
- [Known dead ends and prohibited shortcuts](research/known-dead-ends.md)
- [Template for the next experiment](templates/experiment-record.md)
- [Current adapter component map](implementation/adapter-components.md)
## Maintenance rule
After every material protocol investigation, record all three outcomes:
1. proven direction and the exact evidence;
2. failed direction and why it failed;
3. remaining unknowns and the next safe experiment.
Keep raw payloads and credentials out of git. Reference private learning
artifacts by opaque ID or SHA-1 only.
+35
View File
@@ -0,0 +1,35 @@
# `__configinfo`: file map and service atom
## Proven map
The decoded `E__configinfo` text contains logical file-name pairs:
```text
"<object-guid>.0",<base64 of 20-byte SHA-1>
```
The Base64 value is the SHA-1 of the complete raw `BinaryData` stream for that
logical file. Updating a module without replacing this map value produces the
Configurator error “Ошибка хеш-версии файла конфигурации”.
The map rewrite is deterministic and losslessly round-trip proven for the
studied extension form module.
## Service atom: current status
The root block also contains three observed binary atoms: two 48-byte values
and a 32-byte value. The 32-byte value changed across manual saves, including
when the module bytes returned exactly to a previous SHA-1. A random mutation
of its variable part triggered a platform licensing/crypto error.
Therefore:
- preserve all service atoms byte-for-byte during the proven incremental
protocol;
- do not synthesise, randomise, zero, or “recalculate” them;
- do not claim their reverse codec is known;
- record new observations in an experiment file before changing this rule.
The `test2` map-update experiment activated successfully while preserving the
existing service atom. This is activation evidence for preservation, not for
generation.
@@ -0,0 +1,27 @@
# Payload envelope codec
## Observed codec pipeline
For the studied configuration payloads:
```text
SQL BinaryData
→ raw-deflate (or detected alternative envelope)
→ UTF-8 text, sometimes BOM
→ brace-based 1C serialized value tree / container text
```
The decoder must retain envelope type, original encoding, BOM, line endings,
and all unmodified text. An encoder is valid only if an unchanged
decode→encode cycle returns byte-identical payload bytes.
## Lossless transform discipline
1. Decode source bytes.
2. Identify the exact BSL or value-tree slice with a proven extractor.
3. Replace only that slice.
4. Encode with the original codec metadata.
5. Calculate SHA-1 from the final raw stored bytes, never from decoded text.
Do not canonicalize braces, whitespace, strings, BOM, compression level, or
base64 blocks without an independently proven canonical writer.
@@ -0,0 +1,72 @@
# `upo_test` / `test2` saved-state experiment
## Scope
- Test base: `upo_test`
- Extension: `test2`
- Extension GUID: `fb26cf42-7609-11f1-828f-005056b0d483`
- Common form: `t_Форма`
- Form GUID: `77494708-43ea-4956-ac3c-199cfb035ad2`
- Independently manually edited form: `tt_Форма3`
- Form GUID: `99590008-addf-49fa-9ada-24962756d0cf`
These are experiment identifiers, not a universal hardcoded route.
## Follow-up cross-extension confirmation (2026-08-13)
The same logical-file protocol was exercised on a different extension and
object class:
- Extension: `фс_Отчеты`
- Extension GUID: `9b11f844-3d08-11f1-8287-005056b0d483`
- Object: `Report._ПоступлениеТовара`
- Object GUID: `c428f629-785a-4141-b038-f2192bb4580d`
- Guarded change: `//Пример - 3``//Тест - 3`
The active root was a hash-keyed `ConfigCAS` record, but decoding it exposed
the logical `O` / `O.0` map and the SHA-1 of each active payload. The adapter
created exactly `E__configinfo`, `E__O`, `E__O.0`, executed a public
`code.write` replacement and reread it. A controlled `apply_and_rollback`
passed before `apply_and_verify`. A human then confirmed `//Тест - 3` in the
Configurator extension editor.
This proves the canonical object-module overlay route for this observed
extension-root family. The implementation must retain the suffix of the exact
resolved BSL stream: a separately diagnosed production route for
`Report.УОП_ПечатьЦенниковАссортимента` resolves its manager module as `.2`,
not `.0`. This does not authorize a guessed suffix: the selected `O.S` entry
and its SHA-1 must be present in the decoded root map. Forms or an unknown
root that cannot be decoded into that exact logical map remain unproven.
## Outcomes
1. Writing a `.0` module alone made a comment visible after a reload but
failed activation with a hash-version error.
2. Pairing the module write with the matching `__configinfo` map update made
the comment activate into `ConfigCAS`; Configurator cleared
`ConfigCASSave` after successful application.
3. Building a complete three-file initial overlay while Configurator was
closed, then opening and applying it, succeeded for `change-10`.
4. A manual save in `tt_Форма3` produced a three-row pending overlay for that
form plus `__configinfo`. Incrementally adding `t_Форма` descriptor/module
while preserving the existing rows and map entries kept both edits.
5. A pending `__configinfo` map can point at a newer active module than an
earlier inspection of `ConfigCAS`; selecting the source through the pending
map avoids duplicate BSL comments.
## Failed paths retained as evidence
- Raw module-only write: invalid collection hash.
- Random service-atom bytes: licensing/crypto error.
- Treating the active module as authoritative while a pending map exists:
duplicate comment insertion.
- Assuming UI text means SQL save: the editor buffer can differ from
`ConfigCASSave`; verify SQL immediately after saving.
## Verification after every apply
1. `ConfigCASSave` for the extension becomes empty.
2. Extension root key in `_ExtensionsInfo`/`ConfigCAS` changes to the new
`__configinfo` SHA-1.
3. Active `ConfigCAS` contains the requested BSL text.
4. The active map points to the SHA-1 of the active module bytes.
@@ -0,0 +1,128 @@
# Extension saved-state overlay (`ConfigCASSave`)
> **Deployment and integration-test target:** `adapter-1c-mcp` runs on
> `docker.cin.su`. Use that host for deployment and live adapter checks;
> `test-docker` is staging only and requires an explicit request.
## Canonical object-module overlay: activation evidence
For extension GUID `E` and object GUID `O`, the overlay uses:
```text
E__configinfo
E__O
E__O.S
```
This route is now human-confirmed in two independently selected extension
object-module cases on `upo_test`:
| Extension | Object | Public test | Human confirmation |
|---|---|---|---|
| `test2` | Common form/module fixture | prior `change-10` experiment | Configurator applied overlay into `ConfigCAS` |
| `фс_Отчеты` | `Report._ПоступлениеТовара` object module | `//Пример - 3``//Тест - 3` | Configurator displayed `//Тест - 3` in the extension editor |
The descriptor and module are separate objects. A pending extension may contain
only rows changed manually by the user; the root `__configinfo` map can still
refer to unchanged active parts. An adapter must preserve those rows and all
their map entries.
For the separately observed hash-keyed overlay, the equivalent boundary is the
live extension `root_cas_key`: an automatic first-write copy must include that
root manifest together with the selected object parts. A leaf module key alone
is not a complete working-copy selection boundary.
## Hash-keyed first-write status
In `upo_test` / `фс_Отчеты`, copying the complete evidenced hash-key group
from `ConfigCAS` to `ConfigCASSave` under unchanged hash names produced a
byte-for-byte SQL readback, but Configurator continued to read the active
`ConfigCAS` module. Therefore a same-name hash copy is **not** a working-copy
protocol.
The active extension root has since been decoded as the equivalent logical
file map: it contains `"<object-guid>[.suffix]",Base64(SHA-1(payload))`
pairs, including the target descriptor and the selected BSL module. For the evidenced
object-module family the initial overlay maps exactly three active files to:
```text
root manifest -> E__configinfo
object descriptor -> E__O
object `.S` module -> E__O.S, where `.S` is the suffix of the exact resolved
BSL stream (for example `.0` or `.2`)
```
The adapter must reject any incomplete route and must never fall back to
unchanged hash names. The map and all service atoms are copied verbatim on the
first overlay; subsequent writes update only the proven file-SHA reference.
### Exact prepare/write algorithm
1. Resolve the extension, public object `O`, active descriptor and active `.S`
BSL stream from the extension manifest.
2. Decode the selected active root. Require exactly one map entry for `O` and
exactly one for the selected `O.S`; require their SHA-1 values to equal the selected
active descriptor/module payloads.
3. If the overlay is absent, atomically copy only those three sources as
`E__configinfo`, `E__O`, and `E__O.S`. Do not copy the whole extension.
4. If it exists, preserve pending rows and maps; never overwrite another
change. Prepare may add only missing object parts.
5. Replace BSL only after the exact old fragment, source SHA-1, extension,
public object and module stream agree. For an object module, update the one
`O.S` SHA-1 value in `E__configinfo` in the same transaction and preserve
service atoms byte-for-byte.
6. Re-read the BSL and both changed rows. `apply_and_rollback` must restore
the module and remove adapter-created first-overlay rows.
`code.write` callers provide only public selectors and the replacement. The
adapter owns storage mapping, preparation, paired update and rollback.
## Rejected approaches (retain as regression hazards)
- Copying `ConfigCAS` hash rows to `ConfigCASSave` under the same names. It
produced correct SQL readback but Configurator ignored it for `фс_Отчеты`.
- Writing only the BSL module payload. The map continues to point to the old
SHA-1 and Configurator reports a collection/hash-version error.
- Generating `__configinfo`, its service atoms, or logical file mappings from
names alone. The adapter must first decode the actual selected root map.
- Replacing the entire compressed module container. Only the declared BSL
prefix codec is allowed; opaque stream tail bytes must remain unchanged.
- Resolving an already selected object-module path through generic metadata
path traversal. Its module suffix is a BSL container, so this can fail before the
saved-state writer sees the exact module route.
## Proven incremental write protocol
For a form module change:
1. Read the current `E__configinfo` from `ConfigCASSave` if it exists;
otherwise derive a complete initial overlay from active `ConfigCAS`.
2. Resolve the form descriptor and module hashes from that map.
3. Patch the module with a unique BSL anchor and lossless payload codec.
4. Replace exactly the Base64(SHA-1(raw module bytes)) value paired with
logical name `O.0` in `E__configinfo`.
5. Preserve every unrelated map entry and service atom byte-for-byte.
6. In one transaction insert missing `E__O`/`E__O.0` rows and update
`E__configinfo`, with compare-and-set SHA-1 preconditions.
The adapter core exposes a pure `build_extension_saved_state_pair_plan` helper
for steps 35. It refuses a plan when the ConfigInfo map does not reference the
current saved stream, so a later transaction cannot silently overwrite a
divergent human overlay.
For an already existing single-part pending stream, the paired writer locks the
module and `__configinfo`, verifies both preconditions, writes both payloads
and their `DataSize` values in one transaction, keeps independent rollback
evidence, and verifies both rows afterwards. `__configinfo` itself is never a
primary editable stream. Missing overlay rows still use the separate prepare
route before this writer may update them.
This protocol was activation-proven in the `test2` experiment. It is not yet
a universal proof for every 1C platform version or every extension object
class; new classes require their own evidence record.
## Important overlay behaviour
An external SQL overlay write does not set the Configurators in-memory dirty
flag. Its visibility therefore depends on the current session. See
[Configurator refresh behaviour](../operations/configurator-cache.md).
@@ -0,0 +1,24 @@
# Current adapter component map
This map says where to extend the project without losing protocol boundaries.
It is not a substitute for reading the linked source before editing it.
| Component | Location | Responsibility | Evidence boundary |
|---|---|---|---|
| RPC/service orchestration | `plugins/1c/connector/adapter_1c_server.py` | Base resolution, live SQL calls, saved-state plans/apply, verification, backups | Must keep active layers read-only |
| Payload codec | `plugins/1c/parser/payload.py` | Envelope detection, decompression, lossless encode metadata | Require byte-identical unchanged round trip |
| Brace parser | `plugins/1c/parser/*` | Decode 1C serialized brace/value trees | A parse tree is not semantic proof by itself |
| Extension routes | `plugins/1c/parser/extensions.py` and adapter extension resolvers | `_ExtensionsInfo` and `ConfigCAS` manifest routes | Never infer part role from suffix alone |
| DBNames mapping | `plugins/1c/parser/dbnames.py` | Metadata-to-physical SQL role evidence | Names/roles must come from live DBNames evidence |
| Storage access | adapter storage helpers | Single/multi-part row reads, hashes, paired extension map updates, compare-and-set and backups | Writes only to allowed saved-state tables |
| Policy | `plugins/1c/connector/policies/` | Runtime boundary and base-access rules | Policy must match tested capability, not aspiration |
| Regression tests | `tests/1c/` and `scripts/smoke_1c_*` | Preserve routes and observed protocol rules | Add fixture/test before promoting a decoder rule |
## Required update order for a new object type
1. Add an experiment record with before/after SQL evidence.
2. Add/extend a decoder fixture and test.
3. Add the narrow codec or route resolver.
4. Add a writer only after lossless round-trip, paired-index handling, rollback,
and human activation verification.
5. Update the relevant topic document and this map if ownership changed.
@@ -0,0 +1,39 @@
# Configuration storage layers
The following SQL tables have the same observed storage-row shape:
`FileName`, `Creation`, `Modified`, `Attributes`, `DataSize`, `BinaryData`,
`PartNo`.
| Layer | Role | Direct adapter writes |
|---|---|---|
| `Config` | Active base configuration | Forbidden |
| `ConfigSave` | Pending base configuration changes | Controlled `upo_test` only |
| `ConfigCAS` | Active extension content-addressed store | Forbidden |
| `ConfigCASSave` | Pending extension configuration overlay | Controlled `upo_test` only |
`PartNo` must be read and preserved. The currently proven writer handles a
single-part stream only; a multi-part stream is unsupported until a
table-aware round-trip codec exists.
## Addressing rules
Base `Config` objects are commonly addressed by metadata GUID. Extension active
objects are reached through `_ExtensionsInfo` → extension root in `ConfigCAS`
→ root manifest → object part SHA-1 key. Do not infer a semantic role from a
suffix such as `.0`; inspect the payload and route evidence.
For normal content-addressed rows, `ConfigCAS.FileName` was observed to equal
SHA-1 of the stored bytes. Always compute and compare the hash rather than
trusting the name: an activation experiment left a legacy alias whose name was
an old key while its bytes had the new SHA-1.
## Write sequence
1. Resolve public object/form/module against live SQL.
2. Read active bytes and any existing saved-state rows.
3. Prepare only missing saved rows; never overwrite a users existing rows.
4. Encode the changed stream losslessly.
5. Update every proved companion index in the same SQL transaction.
6. Read back and validate hashes and semantic exact-match count.
7. Tell the human which Configurator scope to reload.
@@ -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 payloads 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="
}
@@ -0,0 +1,35 @@
# Configurator refresh behaviour
## Observed session model
`ConfigCASSave` is an SQL overlay, but writing it outside Configurator does not
set Configurators in-memory changed/dirty state.
Observed consequences:
| State before adapter write | Minimal human action after write |
|---|---|
| Object already existed in saved-state | Close and reopen that object |
| Adapter created the first pending object for an extension | Close and reopen the extension |
| Adapter created the first pending object for base configuration | Close and reopen the configuration |
If the user manually edits and saves any object in an extension, Configurator
marks the extension changed; reopening another object can then load its
`ConfigCASSave` overlay.
## Required adapter response
Write results should return machine-readable guidance:
```json
{
"configurator_refresh": {
"required": true,
"scope": "object|extension|configuration",
"action": "close_reopen_object|close_reopen_extension|close_reopen_configuration"
}
}
```
This guidance does not claim that the adapter controls Configurator; it merely
reports the minimum observed reload boundary.
@@ -0,0 +1,27 @@
# Known dead ends and prohibited shortcuts
## Do not repeat
- Do not write only a module `.0` row: `__configinfo` then references stale
bytes and activation fails.
- Do not use random, zeroed, copied-from-unrelated, or guessed HashVersion
service atoms. A controlled random test produced a licensing/crypto error.
- Do not write `Config` or `ConfigCAS` directly, even in tests.
- Do not use a suffix such as `.0` as proof of “object module”.
- Do not infer an object name from a GUI tree label, table suffix, or an
approximate Russian name.
- Do not overwrite all saved-state rows when adding a delta: preserve user
work in other objects and every map entry.
- Do not treat an open Configurator screen as SQL evidence.
## Open questions
- The generation algorithm and ownership of the 32-byte `__configinfo`
service atom are unknown. Preservation is proven for the studied flow;
generation is not.
- Multi-part storage streams need a dedicated row-layout codec.
- The extension protocol must be reproduced on another object class and a
second platform build before being declared generally supported.
- Configurators in-memory dirty-state implementation is inferred from
behaviour, not decoded from platform source. Only the reload guidance is
operationally relied upon.
@@ -0,0 +1,51 @@
# Contract for an agent using the 1C SQL adapter
The agent is a consumer of evidence returned by the adapter. It must never
turn a plausible interpretation into a fact.
## Fundamental adapter rule
The adapter is a **SQL codec**, not an expert system for 1C. It reads and
writes only according to the versioned configuration-storage specification
that has been decoded from live SQL and recorded in this knowledge base.
It may expose a semantic name only when that mapping is proven by the decoder.
For an unknown carrier, field, child object, byte range, checksum, or service
atom, the only valid result is `unsupported`, `partial`, or `ambiguous` with
the observed evidence. It must not synthesize a structure, BSL, or value to
make an operation appear complete.
## Required behaviour
- Start from a public 1C name/ref supplied by the user.
- Ask the adapter to resolve the live route; internal GUIDs, SQL numbers and
file names remain adapter implementation details.
- Use public `code.read`, `code.search`, and `code.write` for normal BSL work.
Never pass or request `ConfigCAS`, `ConfigCASSave`, a payload hash, a
canonical saved filename, or a stream index. Those are diagnostic evidence,
not an agent-facing selector contract.
- Read the target bytes before proposing any edit.
- Quote the exact proven fragment, its count, and the selected layer.
- For a write, require a plan/preflight and retain the returned rollback and
refresh guidance.
- State `unknown`, `ambiguous`, or `protocol_incomplete` when evidence is
absent. Ask for a larger fragment or a human Configurator action instead of
guessing.
## Forbidden behaviour
- Invent BSL procedures, form controls, field paths, joins, storage tables,
module streams, extension ownership, or `__configinfo` atoms.
- Claim that a SQL saved-state edit is active before active-layer verification.
- Claim a repository lock merely because an adapter request was recorded.
- Tell the user that the Configurator UI has refreshed unless the required
close/reopen boundary was completed by the human.
- Write directly to active configuration or application tables.
- Work around a public-route failure by retrying against an internal module
reference. Report the public `not_found`, `ambiguous`, `unsupported`, or
`protocol_incomplete` result so the adapter can be corrected.
## Write-result language
Use the adapters `configurator_refresh` object verbatim in human-facing
instructions. Do not collapse `object`, `extension`, and `configuration` into
the same generic “restart” advice.
@@ -0,0 +1,55 @@
# Evidence and safety rules
## Evidence levels
| Level | Meaning | Permitted use |
|---|---|---|
| Observed | Read from live SQL once | Diagnosis only |
| Reproduced | Seen in independent before/after saves | Decoder rule candidate |
| Round-trip proven | Decode → unchanged encode returns identical bytes | Safe read/transform component |
| Activation proven | A human Configurator applied it and active SQL verified it | Controlled `upo_test` writer component |
No rule may be promoted because a name, suffix, or payload shape “looks right”.
## Codec boundary
The configuration-storage specification is the adapter's sole authority for
decoding and encoding. A writer is enabled only when the relevant version of
that specification defines every changed byte and every dependent integrity
atom, and round-trip evidence proves the encoder. Any remaining opaque atom is
preserved byte-for-byte; if a requested edit requires changing it, the write is
unsupported until the specification is extended by a controlled experiment.
## Allowed mutation boundary
- The adapter runtime uses SQL only.
- `upo_test` may receive controlled writes to `ConfigSave` and
`ConfigCASSave` only.
- `Config`, `ConfigCAS`, and application data are never direct write targets.
- A write must have a live target resolution, optimistic SHA-1 precondition,
reversible evidence, atomic transaction, and readback verification.
- Repository coordination is a separate policy; an adapter marker is not a
native repository lock.
## Exact edits
For BSL fragment replacement, provide one of:
- an old fragment occurring exactly once;
- a larger unique surrounding fragment;
- a proven structural container path/offset plus original SHA-1.
If a fragment occurs zero or more than once, do not choose arbitrarily. Return
the count and candidate contexts. Deletion follows the same rule.
## What an agent must report
Every proposal and applied result must state:
- active and saved layers used;
- public target and SQL evidence retained internally;
- original and new SHA-1 values;
- paired files changed;
- exact-match count;
- rollback reference;
- Configurator refresh guidance.
@@ -0,0 +1,41 @@
# Protocol experiment record template
Create one file per material experiment under `experiments/`.
```markdown
# <date> — <short target and action>
## Scope
- Base and classification:
- Extension/object public names:
- Runtime/platform build:
- Authority for mutation:
## Before
- Active source table/key/SHA-1:
- Saved-state files and SHA-1:
- Relevant descriptor/map entries:
## Exact action
- Public target resolution evidence:
- Old fragment / structural selector and occurrence count:
- Payload codec and round-trip result:
- Paired files written in one transaction:
## After SQL evidence
- Readback SHA-1 values:
- Map/reference validation:
- Unrelated pending files preserved:
## Human Configurator verification
- Reload action:
- Visible result:
- Apply result:
- Active/saved postcondition:
## Outcome
- Proven fact:
- Failed hypothesis:
- Remaining unknown:
- Follow-up regression fixture/test:
```