Complete name-first 1C adapter saved-state support
This commit is contained in:
+301
-23
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user