Complete name-first 1C adapter saved-state support

This commit is contained in:
2026-07-26 16:39:53 +03:00
parent b8c62fa8fa
commit aed134d817
44 changed files with 15436 additions and 697 deletions
+301 -23
View File
@@ -603,6 +603,22 @@ Important methods:
resolved through the platform `_BPr<N>` route internally.
- `data.present` returns a compact presentation for one `record_ref`, and
`data.movements` reads register rows for a `recorder_ref`.
- BSP access-key methods use the same object/record separation without
overloading their query-area selector. For `access.keys.query`,
`kind=object` selects the access-key area; it is not a metadata kind. Pass
`object_ref=Справочники.Номенклатура` to select the metadata object and
`record_ref=<32-hex-ref>` to select one application-data record.
`access.object_keys.resolve` and `access.object.explain` accept the same
pair. The adapter resolves `object_sql_number` and `object_id` internally.
Raw `object`, `object_id`, and `object_sql_number` remain compatibility
filters only and should not be generated by new MCP clients.
- `metadata.adapter.audit include_unmapped=true` distinguishes configuration
metadata from platform storage. Live `upo_test` DBNames verification showed
the former candidate roles `Acoustic`, `Bots`, `Ecs`, `LangModel`,
`MobileClientDataExchange`, `STT*`, `URLExternalData`, and
`WebSocketClients` as singleton platform-system tables, normally carrying
the zero GUID. `ExtDataSrcPrms` is auxiliary external-data-source storage.
None of these roles is exposed as an invented public metadata kind.
- `metadata.object.form.details` decodes form commands with their explicit
`Action` value from the SQL form payload. `command_links` resolve that action
against the complete form-module routine index; `routines_sample` is only a
@@ -722,8 +738,12 @@ Important methods:
- `CommonModule.<Name>` is a complete public SQL route: root discovery resolves
the object by its 1C name, and module APIs read its canonical `.0` Config
stream. Live `upo_test` discovery contains 3,400 common modules; sampled
modules decoded as BSL with public routine indexes. Common-module writes, when
explicitly enabled, remain limited to the saved-state layer.
modules decoded as BSL with public routine indexes. In public
`metadata.object.modules`, `modules.read`, and code-search responses, the
module `name`, `qualified_name`, and `display_name` are the 1C common-module
name; Config GUID/stream coordinates are exposed only with
`include_storage=true`. Common-module writes, when explicitly enabled, remain
limited to the saved-state layer.
- For `Role`, `metadata.object.properties` reads the separate SQL part
`<role-guid>.0` and returns `set_for_new_objects`,
`set_for_attributes_by_default`, `independent_rights_of_child_objects`,
@@ -752,6 +772,95 @@ Important methods:
`allow_full_scan=true`. Accounting-register totals are reported as
`unsupported_register` until account and subconto semantics are resolved for
the selected register; raw movements remain readable.
- All `data.*` methods publish the same name-first object selector contract in
`help.methods`: callers may pass `object_ref`, `ref`, `kind/name/guid`, or
MCP aliases `object_type/object_name/object_guid`. Prefer `object_ref` with a
1C code-style name such as `Справочники.Номенклатура` when a method also
needs `record_ref` or `recorder_ref`; a record reference is never treated as
the metadata object name.
- `metadata.support.decode` accepts the same optional public object selectors.
When `ref` or `kind/name` is supplied, the adapter resolves the metadata GUID
internally and returns the effective supplier-support rule for that named
object; callers do not need to discover or pass storage identifiers.
- `metadata.code_index.build` accepts an optional public object selector for a
targeted local-cache refresh. A named base object is resolved through
`Config`, while an extension object with `extension_guid` uses
`ConfigCASSave`; omitting the selector keeps the bounded global `ConfigCAS`
scan. The index remains a local derivative cache and never writes to the 1C
database.
- `metadata.form.owner_index.build` keeps the owner selector and form selector
separate. Use `ref`/`kind/name` for the owning 1C object and `form` or
`form_name` for the nested form. For example,
`ref=Обработки.ОбменДанными, form_name=ФормаОбмена` searches the owner by
`ОбменДанными` and indexes only the named form; the two names are not
substituted for one another.
- `metadata.form.command_button.verify` uses the same owner/form separation and
publishes `command_name`, `button_name`, and `handler_name` as distinct child
selectors. Saved forms with the same name are matched against owner evidence
before verification, so a form belonging to another object is not selected
merely because its form name matches.
- `metadata.form.command_button.write` uses the same disambiguation before it
creates any proposal. `object_guid` identifies the owner and `form_guid`
identifies the nested form; they are never substituted for one another.
Name-first selection does not weaken the write workflow:
`allow_saved_state_write`, repository apply checks,
`allow_sql_saved_state_apply`, verification, and rollback guards remain
mandatory in their existing execution modes.
- `metadata.form.write_target.resolve` and
`metadata.form.write_target.verify` use the same public hierarchy:
`ref`/`kind`/`name` select the form owner, `form_name`/`form_guid` select the
nested form, and `element`/`command`/`attribute` select the child target.
`object_guid` is never treated as a nested `form_guid`.
- `metadata.form.element.write` and `metadata.form.element.write_apply` pass
that hierarchy through unchanged when resolving the concrete saved-state
file. An owner `object_guid` therefore cannot bypass name-first form
resolution. Planning remains opt-in and SQL apply still requires the
existing explicit apply and repository gates.
- `metadata.form.target.move` resolves the owner and nested form before it
resolves `from_element` and `to_element`; structural moves cannot select a
same-named form owned by another object. Its write/apply/rollback gates are
unchanged.
- `metadata.form.write_matrix.build` and `.smoke` use the same owner/form
hierarchy while resolving the saved-state file. The build operation is
read-only; smoke remains restricted to explicit apply-and-rollback.
- `metadata.write_learning.capture_before` and `.capture_after` also accept
the public owner `ref` plus a separate form selector. They write only local
learning artifacts; the selected 1C saved-state file is read, not modified.
- `metadata.saved_state.forms.search` accepts the same owner scope and filters
decoded saved forms by owner evidence before returning them. Its default
response contains the public owner ref, form name, qualified name, and
name-based selectors for matched elements, commands, and attributes.
SQL files, GUID identities, internal brace paths/markers, and low-level
writable-property coordinates are returned only with
`include_storage=true`. `form_guid` remains a separate exact diagnostic
selector. The method is read-only.
- `metadata.saved_state.modules.search` accepts a public module-owner `ref` or
`kind/name/guid`, resolves the internal saved-state prefix itself, and keeps
`file_name`/`stream_index` as opt-in diagnostic selectors. By default its
rows contain only the 1C owner, nested form, module role, qualified name,
source preview, and a semantic selector. SQL tables/files, GUID identities,
hashes, `module_ref`, and low-level write targets are returned only with
`include_storage=true`. Callers do not need to know an owner GUID for
name-first saved-code search.
- `code.write` is the public name-first write facade. It accepts the module
owner through `ref` or `kind/name/guid`, with `routine_name` as a separate
child selector, then resolves the concrete saved-state module internally.
`metadata.module.write_apply` remains the guarded low-level apply operation
for an already resolved `module_ref`.
- `templates.areas.find` accepts a public template ref such as
`Макеты.ПечатнаяФорма`. The template selector, named-area selector
(`area_name`/`area_query`), and low-level direct route are separate MCP
fields; normal callers do not need a storage route.
- `metadata.cache.lookup` accepts a public object `ref` in addition to
`kind/name/guid`. Its result is only a local identity-cache hint; operations
that require current evidence still verify against live SQL.
- `metadata.module_owner_cache.prune` accepts the cached module owner through
a public `ref` or `kind/name` and resolves `owner_guid` internally. Generated
`module_ref` values remain valid for narrow follow-up cleanup. The method
changes only adapter-local SQLite state, never the 1C SQL database; use
`dry_run=true` to inspect the matching count without deleting cache rows.
- For backward compatibility, a legacy bare `guid` without an owner selector
may still identify a form. `object_guid` never gets that legacy treatment.
- Logical schema results are cached briefly. `refresh_cache=true` forces a live
metadata decode after a configuration change.
- `metadata.objects.list`: lists base/effective metadata objects only. It must
@@ -800,7 +909,10 @@ Important methods:
evidence from `modules.read` so write planning can still distinguish base,
saved state, extension, or unresolved CAS references.
- `metadata.adapter.audit`: reports recognized metadata kinds, public kind
counts, missing supported kinds, and unmapped DBNames roles.
counts, missing supported kinds, and unmapped DBNames roles. Every
`missing_supported_kinds` item has
`presence_status=supported_absent_in_selected_base`: absence in one
infobase is not reported as absence of adapter implementation.
- Base root discovery includes the configuration object itself, command groups,
document numerators, external data sources, and integration services. The
root collection UUID map is verified against object UUIDs from the XML export
@@ -816,6 +928,22 @@ python scripts/audit_1c_adapter_coverage.py --base-id upo_test --output reports/
The script reads the adapter bearer token from `ONEC_ADAPTER_TOKEN` and never
reads or prints the SQL password.
Rare-kind regression fixtures for `CalculationRegister`, `Sequence`, and the
legacy `Interface` are checked separately:
```text
python scripts/check_1c_metadata_kind_fixtures.py --live
```
The fixture checker is read-only. It reuses one extension saved-state query for
all fixtures on the same layer and does not force the slower active
`ConfigCAS` full scan. It requires an explicit dedicated-base mapping for
`Interface`.
The manifest pins the required Designer version and an external structural
reference. Use `scripts/export_1c_extension_sources.ps1` to export `test2`
through operating-system integrated authentication; the helper accepts no
infobase user or credential parameters and never writes platform SQL.
For a resumable read-only application-data audit, run the full public chain for
one object of every data-bearing metadata kind:
@@ -1967,28 +2095,63 @@ Selector rules:
`write-rollback-safety-mcp-smoke.json` for MCP. These reports must show the
method in `help.methods`, readable write history, and blocked rollback when
`allow_sql_saved_state_rollback` is absent.
- `metadata.saved_state.prepare` prepares an object's saved-state working copy.
Prefer a public selector (`ref` or `kind/name`) together with
`layer=base_saved_state|extension_saved_state`. Its default response reports
the selected 1C object, active/saved semantic layers, record counts, and
readiness without exposing database/table names, storage files, hashes, or
row details. `include_storage=true` retains the low-level diagnostic response.
`plan` remains the default and performs no write; `apply` and
`apply_and_verify` still require `allow_sql_saved_state_prepare=true`.
- Every public RPC `next_resolution`/`next_call` entry uses `{method, params}`.
`payload` is reserved for the outer RPC request envelope and internal
apply-hint bodies; it must not be used as the arguments field of a public
follow-up. Saved-state follow-ups use the semantic contract: `layer` plus a
public object `ref` or `kind/name`. Internal `target_table`, `source_table`,
`file_name`, `file_names`, `module_ref`, object GUIDs, and
`include_storage` are not copied into public follow-up payloads. If only an
opaque storage target is known, the follow-up reports `selector_required`
instead of exposing that target.
- `metadata.saved_state.diff` is the agent-facing read-only comparison between
a saved-state payload and its active SQL source. It accepts `table` +
`file_name` or `module_ref`, maps `ConfigSave -> Config` and
`ConfigCASSave -> ConfigCAS`, reads both payloads from live SQL, and returns
`changed`/`unchanged`, `needs_prepare`, current hashes, compact text/tree
diff, and `freshness.status=live_sql_verified`.
a saved-state module and its active source. Prefer a public 1C selector such
as `ref=Справочник.Номенклатура` or `kind/name` plus `module_ordinal`;
the adapter resolves the saved-state table and physical file internally.
Generated `module_ref` or `table` + `file_name` remain accepted for chained
tooling. Name-first responses hide storage coordinates unless
`include_storage=true`, and a missing save layer returns a name-first
`metadata.saved_state.prepare` payload. The method maps
`ConfigSave -> Config` and `ConfigCASSave -> ConfigCAS`, reads both payloads
from live SQL, and returns `changed`/`unchanged`, `needs_prepare`, current
hashes, compact text/tree diff, and
`freshness.status=live_sql_verified`.
Deployment verification persists REST/MCP smoke reports as
`saved-state-diff-smoke.json` and `saved-state-diff-mcp-smoke.json`.
- `metadata.saved_state.status` is the read-only overview for a whole save
layer. It accepts `table=ConfigSave|ConfigCASSave`, compares saved rows with
`Config`/`ConfigCAS` by `FileName`, `PartNo`, size, and SHA1, and reports
counts plus per-file statuses: `changed`, `unchanged`, or `saved_only`.
- `metadata.saved_state.status` is the read-only name-first overview for a whole
save layer. Prefer `layer=base_saved_state|extension_saved_state`; the default
response reports semantic aggregate state and object/record counts without
exposing SQL tables, database names, files, hashes, or internal diff
selectors. `include_storage=true` enables the diagnostic storage view, which
accepts the backward-compatible `table=ConfigSave|ConfigCASSave`, compares
saved rows with their active source by file part, size, and SHA1, and returns
per-file `changed`, `unchanged`, or `saved_only` statuses.
- `metadata.saved_state.changes.list` is the read-only pending-change overview
across `ConfigSave` and `ConfigCASSave` by default. It returns changed and
saved-only files with `diff_selector` links, or includes unchanged files when
`include_unchanged=true`. Pass `include_context=true` for best-effort
form/module context by file; the freshness of the pending-change list remains
live SQL verified, while context is explanatory metadata. Pass
across the base and extension saved-state layers. Use the semantic
`layer=base_saved_state|extension_saved_state` filter when only one layer is
needed; the low-level `table` filter is retained for compatibility. Its
default response is name-first: object/form/module context is resolved
automatically, layer names are semantic, and SQL tables/files, GUIDs, hashes, module refs, concrete diff
selectors, low-level actions, and SQL-specific freshness vocabulary are
hidden. Unresolved changes remain in the
counts and are marked `context_unresolved`. Use `include_storage=true` for
the previous per-file diagnostic view with concrete `diff_selector` links.
`include_unchanged=true` also includes unchanged entries. The freshness of
the pending-change list remains live SQL verified, while context is
explanatory metadata. Pass
`group_by_context=true` to also return compact `groups` keyed by resolved
form/module/object context; grouping uses the same best-effort context
enrichment and falls back to per-file groups when context cannot be resolved.
Each group includes compact `selectors`: per-file `diff` selectors, plus
In diagnostic storage mode each group includes compact `selectors`: per-file
`diff` selectors, plus
`module_refs` and `write_plan_targets` when the resolved module context
exposes them. Groups also include `next_actions`, derived from those
selectors, for safe follow-up calls such as inspecting a diff, reading a
@@ -2209,9 +2372,12 @@ Purpose:
- include `write_plan_evidence.next_resolution.method` and
`write_plan_evidence.next_resolution.params` for
`metadata.saved_state.modules.search`, so the agent has the next safe lookup
for `module_ref`. The saved-state module search accepts
`object_type`/`object_name`/`object_guid` as public selectors and resolves
names to `owner_guid` when possible. Its matching streams return
for the module. The follow-up uses `ref` or `kind/name` and the semantic
`layer=base_saved_state|extension_saved_state`; it does not expose
`owner_guid` or SQL table names. The saved-state module search also accepts
the object selector aliases and resolves names to storage identities
internally. With the explicit diagnostic
`include_storage=true` option, its matching streams return
`write_plan_target` with `module_ref`, `file_name`, `stream_index`, and
`expected_sha1` for the concrete `metadata.write.plan` target. This override
evidence itself is not a concrete saved-state write route.
@@ -2253,6 +2419,111 @@ Output schema:
onec_metadata_write.v1
```
Standard object identity properties use the same high-level method and public
1C selector:
```json
{
"method": "metadata.write",
"payload": {
"base_id": "<base-id>",
"target": {
"area": "object",
"kind": "Catalog",
"name": "Номенклатура",
"property": "synonym"
},
"value": "Номенклатура товаров",
"expected_old": "Товары",
"mode": "plan"
}
}
```
This route delegates to `metadata.object.property.write`. It resolves the
object GUID and exact saved-state tree path internally, supports only existing
`synonym` locales and scalar `comment`, and preserves the original payload
format. Apply modes retain SHA1/semantic preconditions, backup, readback
verification, and rollback. Object rename and structural collection edits are
not part of this route.
An existing child metadata identity uses the same method:
```json
{
"method": "metadata.object.property.write",
"payload": {
"base_id": "<base-id>",
"member_ref": "Catalog.Номенклатура.Attribute.Артикул",
"property": "comment",
"value": "Код товара поставщика",
"allow_saved_state_write": true,
"execution_mode": "plan"
}
}
```
`member_kind` + `member_name` is also accepted. If the same child name occurs
in several collections, callers must provide the full `member_ref`; the
adapter returns `ambiguous` instead of choosing a GUID. Supported existing
member categories are `Attribute`, `TabularSection`, `Dimension`, and
`Resource`, including Russian aliases.
Adding one requisite uses a separate clone-based method:
```json
{
"method": "metadata.object.member.add",
"payload": {
"base_id": "<base-id>",
"template_member_ref": "Catalog.Номенклатура.Attribute.Артикул",
"new_member_name": "КодПоставщика",
"new_member_synonym": "Код поставщика",
"allow_saved_state_write": true,
"execution_mode": "plan"
}
}
```
The adapter requires an existing `Attribute` template from the same collection,
generates a deterministic GUID internally, rejects duplicate names, clones the
template type/settings, and appends the cloned record to the same declared
collection. The proposal verifies both the appended node and updated declared
count. Apply/verify/rollback use the normal saved-state gates and backup.
For a tabular-section column, use the complete nested template path:
```text
Document.АвансовыйОтчет.TabularSection.Запасы.Attribute.Номенклатура
```
Name uniqueness and the deterministic GUID seed are scoped to that tabular
section, so identical column names in other table parts do not conflict.
Scheduled-job schedule planning uses the same method and a public 1C reference:
```json
{
"method": "metadata.write",
"payload": {
"base_id": "<base-id>",
"target": {
"kind": "schedule",
"ref": "РегламентныеЗадания.ОбменДанными"
},
"schedule": {
"begin_time": "09:00:00",
"week_days": [1, 2, 3, 4, 5]
},
"allow_saved_state_write": true,
"mode": "plan"
}
}
```
This route returns `onec_scheduled_job_schedule_write.v1`, resolves the object
name to its GUID internally, and targets only `<guid>.0` in `ConfigSave`.
Purpose:
- provide one agent-facing write entry point;
@@ -2285,6 +2556,13 @@ Purpose:
`metadata.write`;
- v1 routes `target.kind=form` to
`metadata.form.element.write_apply`;
- v1 routes `target.area=object` to
`metadata.object.property.write` for `synonym` and `comment`;
- v1 routes `target.area=object` with `operation=add_attribute` to
`metadata.object.member.add`;
- v1 routes `target.kind=schedule` to the named scheduled-job schedule writer;
scalar schedule fields and structural `week_days`/`months` resize are
supported through a verified full schedule-tree replacement;
- v1 routes saved-state form payload container module refs without `#stream`
to the embedded form payload writer when `routine_name` and `routine_text`
identify a single routine edit; this path preserves existing leading BSL
@@ -2297,8 +2575,8 @@ Purpose:
- preserve the same gates as the lower-level form runner:
`plan`, `apply`, `apply_and_rollback`, explicit SQL apply/rollback flags,
sha1 preconditions, backup, and semantic verification;
- keep future non-form writers behind explicit target routing instead of
ad-hoc direct SQL methods.
- keep remaining writers behind explicit target routing instead of ad-hoc
direct SQL methods.
## Metadata Write Preflight
+4 -3
View File
@@ -275,11 +275,12 @@ Current progress:
- `metadata.resolve_overrides` now returns `write_plan_evidence`, a ready
`metadata.write.plan` fragment carrying the routine name, object selector
fields, `target.extension_action`, and `next_resolution.params` for
`metadata.saved_state.modules.search`; saved-state module search now resolves
public `object_type`/`object_name` selectors to owner GUIDs when possible.
`metadata.saved_state.modules.search`; the follow-up uses a public object
`ref`/`kind`/`name` and semantic saved-state `layer`, while the search
resolves storage identities internally.
This reduces agent-side field translation while still requiring a concrete
saved-state module route.
- `metadata.saved_state.modules.search` now returns
- With `include_storage=true`, `metadata.saved_state.modules.search` returns
`streams[].write_plan_target`, a concrete module target with `module_ref`,
`file_name`, `stream_index`, and `expected_sha1` for the next
`metadata.write.plan` call.
+60 -2
View File
@@ -62,8 +62,66 @@ independent metadata properties and must be filtered as derived evidence.
The `test2` experiment on 2026-07-15 added a minimal calculation register and
its required chart of calculation types through Designer, then saved the
extension without applying it. The objects remain intentionally `saved_only`
for adapter regression checks.
extension without applying it. That historical fixture was later removed from
the live saved state. The observations below remain decoder evidence, but they
must not be interpreted as proof that the current `upo_test` still contains the
object.
The reproducible fixture requirements are declared in
`config/1c_metadata_kind_fixtures.json`. Validate the declaration offline:
```powershell
python scripts/check_1c_metadata_kind_fixtures.py
```
Probe the current adapter and test base:
```powershell
python scripts/check_1c_metadata_kind_fixtures.py --live
```
Use `--require-ready` only as a strict regression gate after the fixtures have
been loaded with 1C Designer. The checker never creates metadata and never
writes platform SQL. `CalculationRegister` and `Sequence` belong in the saved
`test2` extension. Legacy `Interface` requires a dedicated compatible test
base, supplied explicitly as
`--target-base interface_legacy_base=<base_id>`; it must not be simulated in a
modern configuration by editing `Config`, `ConfigCAS`, or `DBNames`.
At the 2026-07-26 verification point, the `upo_test` server required platform
`8.5.1.1236`. The exact Designer build is now installed at
`C:\Program Files\1cv8\8.5.1.1236\bin\1cv8.exe`; the previous client-version
blocker is closed.
Export the current saved `test2` sources through operating-system integrated
authentication only:
```powershell
.\scripts\export_1c_extension_sources.ps1 `
-OutputDirectory C:\Temp\upo-test-test2-source
```
The export helper verifies the exact executable version, refuses a non-empty
output directory, always passes `/WA+`, and has no user or credential
parameters. It only reads and exports the extension; it does not load, save, or
apply a configuration.
The current workstation account is not mapped to an infobase user on
`wsr\upo_test`, so the server export stops with
`Пользователь ИБ не идентифицирован`. A disposable local file infobase needs a
client license and stops with `Не найдена лицензия`. Therefore provisioning is
still blocked by execution environment, not by adapter code or platform
version. Continue on a licensed workstation under an already authorized
operating-system identity; do not add a user name or password to scripts,
manifests, or reports, and do not bypass the block with direct SQL.
An external structural reference is pinned to
`asosnoviy/go1cover@c7e3ea3d90396d341cb98285c29973bcc0a82eca`,
path `testresourse/cf/designer/src`. It contains examples of
`CalculationRegister`, `Sequence`, and legacy `Interface`. The upstream
repository is GPL-3.0; its files are reference input only and are not vendored
into this project. The pinned source and per-kind paths are declared in the
fixture manifest.
Observed read-only SQL signatures in `ConfigCASSave`:
+179
View File
@@ -0,0 +1,179 @@
# Политика хранилища по слоям конфигурации 1С
Каждая конфигурация имеет собственную политику: основная конфигурация — слой
`base`, каждое расширение — слой `extension:<GUID>`. Подключение основной
конфигурации к хранилищу не означает подключения расширения и наоборот.
Адаптер работает с метаданными 1С только через SQL. Он не считает SQL-таблицы
доказательством нативного захвата объекта в хранилище.
Заявки на захват и явные ручные подтверждения — это служебные данные адаптера,
а не данные 1С. Они хранятся в `/data/onec-repository-locks.json` в named
volume Docker `adapter-1c-data` и переживают пересоздание контейнера. Это
хранилище не используется для вывода о нативном захвате и не требует записи в
какую-либо базу 1С.
## Настройка
В `development_layers` для каждого фактически используемого слоя задаётся
`repository.connection_state`:
```json
{
"base": {
"repository": {"mode": "manual", "connection_state": "configured"},
"support": {"mode": "unknown"}
},
"extension:86d12be8-086c-11f0-925c-0050568c1b38": {
"repository": {"mode": "none", "connection_state": "not_configured"},
"support": {"mode": "unknown"}
}
}
```
Допустимые состояния:
| Состояние | Политика записи |
| --- | --- |
| `not_configured` | Слой не подключён к хранилищу; захват не требуется. Ограничения поддержки сохраняются. |
| `configured` | Подключение известно. В SQL-only режиме нужен запрос и явное подтверждение захвата. |
| `unavailable` | Подключение предполагается, но проверить его нельзя; нужен запрос и явное подтверждение захвата. |
| `unknown` | Не делать предположений: запись в слой блокируется до настройки. |
Для ручного подтверждения всегда передаётся точный объект и явный флаг
`user_confirmed_locked`. Имя пользователя хранилища берётся из
`repository_user` настройки данного слоя. Поэтому при заполненной настройке
его не нужно повторять в каждой заявке или подтверждении. Если клиент всё же
передаёт `confirmed_repository_user`, оно должно совпадать с настроенным
именем. Если имя не настроено, подтверждение попросит его явно.
## Сохранение факта подключения агентом
Агент может сохранить подтверждённый факт в служебной конфигурации адаптера
через `repository.layer.connection.set`. Метод не меняет SQL-базу 1С и требует
явного флага подтверждения.
Основная конфигурация подключена к хранилищу:
```json
{
"method": "repository.layer.connection.set",
"payload": {
"base_id": "neft",
"layer_id": "base",
"connection_state": "configured",
"repository_user": "ivanov",
"confirm_repository_connection_change": true
}
}
```
Расширение точно не подключено:
```json
{
"method": "repository.layer.connection.set",
"payload": {
"base_id": "neft",
"extension_guid": "86d12be8-086c-11f0-925c-0050568c1b38",
"connection_state": "not_configured",
"confirm_repository_connection_change": true
}
}
```
При `not_configured` адаптер устанавливает режим слоя `none`. При
`configured` или `unavailable` новый слой по умолчанию получает ручную
политику захвата. Рекомендуется сразу передать постоянный
`repository_user`: он сохраняется только в конфигурации адаптера для этого
слоя и используется во всех последующих ручных подтверждениях.
## Ручное подтверждение захвата
После `repository.lock.request` клиент должен использовать возвращённый
`next_call` без самостоятельного подбора имён полей. Поля из
`next_call.params` передаются как RPC `payload`; его эквивалент:
```json
{
"method": "repository.lock.confirm",
"payload": {
"base_id": "neft",
"request_id": "rreq-…",
"user_confirmed_locked": true
}
}
```
`objects`, `operation` и `layer_id` не передаются повторно: подтверждение
берёт их из неизменяемой сохранённой заявки. Если имя пользователя сохранено
для слоя, оно тоже не передаётся. Успешный ответ содержит `lock_session_id`;
его необходимо передать в preflight и операцию записи.
Ответ `repository.lock.confirm` содержит готовый `write_context`. Его можно
передать целиком либо верхнеуровневым полем `write_context`, либо алиасом
`repository_lock`; адаптер нормализует поля до проверки захвата:
```json
{
"base_id": "neft",
"target": {"module_id": "Config:<form-guid>.0"},
"repository_lock": {"lock_session_id": "rlock-…", "repository_object": "Document.Имя.Form.ИмяФормы", "layer_id": "base"}
}
```
Если одновременно переданы вложенное и верхнеуровневое значение, они должны
совпадать; иначе возвращается `repository_lock_context_conflict`.
## Проверка
`repository.layers.audit` обнаруживает основную конфигурацию и расширения из
live SQL и выдаёт для каждого слоя состояние хранилища, общий режим поддержки
и безопасное следующее действие:
```json
{
"method": "repository.layers.audit",
"payload": {"base_id": "neft"}
}
```
Ключевые действия в ответе:
- `repository_lock_not_required` — слой явно не подключён к хранилищу;
- `request_and_confirm_repository_capture` — перед записью требуется
подтверждение захвата;
- `configure_repository_connection_state` — слой нельзя менять, пока не
установлен один из статусов подключения.
Проверка поддержки выполняется отдельно от хранилища. Для конкретного объекта
используйте `metadata.write.preflight`: разрешение объекта определяет его
`origin`, и адаптер применяет политику найденного слоя, а не клиентский выбор
слоя.
## Захват формы владельца
Для формы документа, справочника, обработки или отчёта область захвата задаётся
точно, без сворачивания к владельцу:
```json
{
"method": "repository.lock.request",
"payload": {
"base_id": "neft",
"objects": ["Document.тл_Планировщик.Form.ФормаДокументаНовая"],
"operation": "modify"
}
}
```
До создания заявки `repository.lock.plan` и сама заявка разрешают форму через
live SQL, получают GUID формы и сохраняют точную каноническую область. После
ручного подтверждения эта сессия не даёт права на соседние формы или модуль
владельца.
Также принимается `Form.<GUID>`. Для него адаптер проверяет связь формы с
владельцем по live SQL; при отсутствии готовой производной записи владельца
выполняется ограниченный SQL-скан форм поддерживаемых типов владельцев. Если
владелец не найден, планирование и заявка завершаются `not_found`, а не
возвращают ложный `ready`.
+41 -1
View File
@@ -126,7 +126,10 @@ REST and MCP selector-chain smoke tests. The selector-chain smoke also checks,
when a routine name is available from module metadata, that
`metadata.resolve_overrides` returns `write_plan_evidence.next_resolution` for
`metadata.saved_state.modules.search` with the same `base_id` and routine query,
then follows that resolver. If a saved-state stream exposes `write_plan_target`,
plus a public object `ref`/`kind`/`name` and semantic
`layer=base_saved_state|extension_saved_state`; public follow-ups never require
`ConfigSave`, `ConfigCASSave`, or `owner_guid`. The smoke then follows that
resolver. If a saved-state stream exposes `write_plan_target`,
the smoke composes it with `write_plan_evidence.target` and checks the resulting
read-only `metadata.write.plan`; when the test base has no saved-state stream,
that last composition step records `skipped_no_saved_state_target`.
@@ -506,6 +509,23 @@ roles/users can read or write this metadata object". Do not depend on
`metadata.objects.list kind=Role`: some live bases do not expose roles as regular
metadata objects through that route.
For BSP data-access keys, keep the metadata object and concrete data record
separate:
```json
{
"base_id": "upo_test",
"kind": "object",
"object_ref": "Справочники.Номенклатура",
"record_ref": "00112233445566778899AABBCCDDEEFF"
}
```
Here `kind=object` is the `access_keys_query` area, not the metadata kind.
`object_ref` is resolved to the internal BSP SQL number and `record_ref` to the
record id. The same public pair works with `access_object_keys_resolve` and
`access_object_explain`; do not invent `object_sql_number` in MCP code.
For BSP role-right checks, `action=write` means add or modify rights. Read-only
roles must not be returned for `write`; query `action=read` separately when you
need visibility roles. Returned permissions keep `source_fields` from
@@ -634,6 +654,26 @@ Agent rules:
`metadata.form.command_button.write` for the complete form command + visible
button + handler workflow. `code.write` remains a compatibility shortcut for
simple module edits.
- For a metadata object's standard `synonym` or `comment`, call generic
`onec_request` with `method=metadata.object.property.write`, a public
`ref`/`kind` + `name`, and `allow_saved_state_write=true`. Prefer
`execution_mode=plan` first. The adapter resolves GUIDs and serialized paths;
MCP callers must not pass SQL tables or file names. Object rename and adding
a new synonym locale are intentionally unsupported.
- For an existing requisite, tabular section, dimension, or resource, add a
public `member_ref` such as
`Catalog.Номенклатура.Attribute.Артикул`. When only
`member_kind` + `member_name` is used and several identities match, preserve
the adapter's `ambiguous` result and retry with the full member path.
- To add a requisite, call `metadata.object.member.add` through `onec_request`
with a full `template_member_ref` from the same object and the new public
name/synonym. Never invent a GUID, Config table, collection path, or type
descriptor in MCP code; the new requisite inherits type/settings from the
named template.
- The same method adds a tabular-section column when
`template_member_ref` contains the full
`...TabularSection.<name>.Attribute.<column>` path. Keep the complete path so
duplicate checks and generated identity remain scoped to that table part.
- For unresolved module owners, inspect `diagnostics.owner_resolution` and
`counts.owner_scan_limit_hit`; narrow by `kind`/`name`/`guid` or increase
`owner_scan_limit` before falling back to broader searches.