720 lines
36 KiB
Markdown
720 lines
36 KiB
Markdown
# 1C Connector
|
|
|
|
Standalone-ready service for safe interaction with live 1C databases.
|
|
|
|
The connector is read-first and optimized for an operational coding loop where full XML export and EDT sync are too slow for every task.
|
|
|
|
Preferred live architecture:
|
|
|
|
- SQL-only connector for diagnostics, metadata decoding, and controlled
|
|
saved-state work in an explicitly authorised test base;
|
|
- a human-operated Configurator for viewing and applying pending changes;
|
|
- cached metadata/module snapshots with freshness checks;
|
|
- change proposals as reviewable artifacts, not direct production writes.
|
|
|
|
The connector is responsible for:
|
|
|
|
- metadata reads;
|
|
- BSL module search/read;
|
|
- read-only query validation and execution;
|
|
- metadata/module snapshots;
|
|
- change proposals and, only where a reverse codec is activation-proven,
|
|
controlled `ConfigSave`/`ConfigCASSave` writes with rollback evidence.
|
|
|
|
The adapter never writes `Config`, `ConfigCAS`, or application data directly.
|
|
It does not automate Configurator and must not invent unknown 1C structures.
|
|
The protocol evidence base is [docs/1c-sql-protocol](../../../docs/1c-sql-protocol/README.md).
|
|
|
|
Contracts:
|
|
|
|
- `contracts/openapi.yaml`
|
|
- `policies/read-only-query.yaml`
|
|
- `policies/change-workflow.yaml`
|
|
- `policies/config-layer-write-policy.yaml`
|
|
- `policies/sql-base-access-policy.yaml`
|
|
- `policies/xml-decoding-reference-policy.yaml`
|
|
|
|
The model must use this connector instead of inventing metadata or directly changing a live database.
|
|
|
|
XML exports are development-time evidence only. They may be analyzed by
|
|
repository scripts to infer and test generic SQL payload decoders, but the
|
|
running connector is configured only with a SQL entry for `base_id`. It does
|
|
not mount or read XML and rejects XML path arguments in runtime requests.
|
|
|
|
## Standalone boundary
|
|
|
|
This directory is the service boundary for the adapter. It is still developed
|
|
inside the current monorepo, but it should be kept movable as an independent
|
|
project.
|
|
|
|
Service-owned files:
|
|
|
|
- `adapter_1c_server.py`
|
|
- `contracts/openapi.yaml`
|
|
- `policies/*.yaml`
|
|
- `Dockerfile`
|
|
- `docker-compose.yml`
|
|
- `.env.example`
|
|
- `pyproject.toml`
|
|
- `service.yaml`
|
|
- sibling package `../parser`
|
|
|
|
Repository-owned integration files:
|
|
|
|
- `plugins/1c/mcp/adapter_1c_mcp.py`
|
|
- `plugins/1c/agent/`
|
|
- `plugins/1c/rag/`
|
|
- `plugins/1c/training/`
|
|
- top-level health and contract scripts under `scripts/`
|
|
|
|
The connector must not depend on RAG, training, or agent code. MCP and agent
|
|
code may depend on the connector contract.
|
|
|
|
## Local Run
|
|
|
|
From `plugins/1c`:
|
|
|
|
```powershell
|
|
python connector/adapter_1c_server.py
|
|
```
|
|
|
|
From `plugins/1c/connector` after installing package dependencies:
|
|
|
|
```powershell
|
|
python adapter_1c_server.py
|
|
```
|
|
|
|
Health without a concrete base:
|
|
|
|
```powershell
|
|
Invoke-RestMethod http://localhost:8011/health
|
|
```
|
|
|
|
Live database calls require `base_id` and SQL connection configuration.
|
|
|
|
## Configuration repository operations
|
|
|
|
Repository access is configured per `base_id`, preferably as a `repository`
|
|
object inside the same JSON entry used by `ONEC_SQL_BASES_JSON_FILE`. The
|
|
repository backend is never inferred from a bridge name or endpoint. Set
|
|
`backend` explicitly to `direct` or `karman_bridge`; both backends execute the
|
|
standard 1C Designer repository commands, while a Karman/Filebox bridge only
|
|
relays the native opaque TCP stream.
|
|
|
|
See `config/1c_repository_bases.example.json` for a secret-free example.
|
|
Passwords are resolved only from the configured environment-variable names.
|
|
The adapter does not return them or store them in lock-session state.
|
|
|
|
When the adapter runs in a Linux container and Designer is installed on the
|
|
Windows Docker host, use `runner.kind=http`. Run
|
|
`scripts/run_1c_repository_runner.py` on Windows with its own external base
|
|
configuration (example: `config/1c_repository_runner_bases.example.json`). The
|
|
container sends only `base_id`, action, public object names, and commit comment;
|
|
infobase/repository credentials remain on the Windows runner. Protect the
|
|
runner with `ONEC_REPOSITORY_RUNNER_TOKEN` and a host firewall rule limited to
|
|
the Docker host/container network.
|
|
|
|
The guarded workflow is:
|
|
|
|
1. `repository.status` (optionally `probe=true`);
|
|
2. `repository.lock.plan` with public 1C object names;
|
|
3. `repository.lock` with `allow_repository_lock=true`;
|
|
4. pass the returned `lock_session_id` to write preflight/apply;
|
|
5. `repository.commit.plan` and explicit `repository.commit`, or
|
|
`repository.unlock` for only that adapter-owned session.
|
|
|
|
Apply operations are blocked for a repository-configured base unless an active
|
|
adapter-owned lock session is supplied. Structural add/delete/rename plans are
|
|
kept blocked for confirmation because parent and reference objects can also be
|
|
required.
|
|
|
|
## Configuration activation debug workflow
|
|
|
|
Activation is a separate boundary from saved-state writes and repository
|
|
coordination. The current workflow is intentionally debug-only:
|
|
|
|
1. `configuration.activation.status`;
|
|
2. `configuration.activation.plan`;
|
|
3. `configuration.activation.request`;
|
|
4. forward the returned request id to `configuration.activation.execute` with
|
|
`mode=debug` and `confirm_activation=true`;
|
|
5. inspect or cancel the request through
|
|
`configuration.activation.request.status`,
|
|
`configuration.activation.request.cancel`, and
|
|
`configuration.activation.audit`.
|
|
|
|
The request is bound to a live-SQL fingerprint and is rejected when pending
|
|
files change or the request expires. Requests and events are stored in the
|
|
adapter-local SQLite selected by `ONEC_ADAPTER_STATE_DB`; they contain no
|
|
payload bytes or credentials. `ONEC_CONFIGURATION_ACTIVATION_STATE_FILE` is a
|
|
one-time legacy JSON import source only. `configuration.activation.capabilities`
|
|
reports runner readiness without returning paths, URLs, selectors, users,
|
|
passwords, or tokens.
|
|
`configuration.activation.bridge.probe` can then check the local runner or the
|
|
authenticated HTTP runner endpoint `/configuration/activation/debug`. The
|
|
probe verifies only Designer-file availability and infobase-selector presence;
|
|
it never starts a process.
|
|
Pass `bridge_debug=true` to `configuration.activation.execute` when the runner
|
|
must also acknowledge the exact request id and live-SQL fingerprint. The runner
|
|
returns an opaque SHA-256 debug receipt; mismatched or missing receipts block
|
|
the request, while a valid receipt adds a `bridge_debug_accepted` audit event.
|
|
After a manual F7, call `configuration.activation.verify` with the same request
|
|
id. It reports `not_activated`, `changed_since_request`, or
|
|
`verified_up_to_date` from a fresh SQL comparison. The last status proves
|
|
saved/active alignment, not the historical fact that Designer performed the
|
|
activation.
|
|
|
|
Real Designer execution remains disabled. `/UpdateDBCfg` is recorded only as
|
|
the documented future base-configuration operation. Extension activation stays
|
|
manual until a separately verified platform command and post-activation check
|
|
are implemented.
|
|
|
|
Activation request mutations use SQLite `BEGIN IMMEDIATE` transactions, so
|
|
concurrent adapter processes cannot overwrite each other's request/event
|
|
updates. Saved-state backup retention is explicit:
|
|
`storage.saved_state.backups.prune` defaults to a dry run, is scoped by
|
|
`base_id`, preserves the newest requested count, and requires
|
|
`confirm_delete=true` before deleting adapter-local backup files. Backups
|
|
referenced by `metadata.write.history` are always protected; when write-history
|
|
availability cannot be verified, affected backup files are protected
|
|
fail-closed.
|
|
|
|
## Docker Run
|
|
|
|
Create a local `.env` from `.env.example`, keep real passwords outside git, and
|
|
run:
|
|
|
|
```powershell
|
|
docker compose -f plugins/1c/connector/docker-compose.yml --env-file plugins/1c/connector/.env up -d --build
|
|
```
|
|
|
|
The compose build context is `plugins/1c` because the adapter imports the
|
|
sibling `parser` package. If this service is moved to a separate repository,
|
|
copy `plugins/1c/parser` into that repository or publish it as a package.
|
|
|
|
## Standalone Extraction Checklist
|
|
|
|
When the adapter is eventually moved out of this monorepo:
|
|
|
|
1. Copy `connector/` and `parser/`.
|
|
2. Keep `contracts/openapi.yaml` versioned with releases.
|
|
3. Keep policies with the service.
|
|
4. Keep `service.yaml`, `pyproject.toml`, `Dockerfile`, `docker-compose.yml`,
|
|
and `.env.example`.
|
|
5. Move or duplicate contract checks that assert public behavior:
|
|
`check_1c_write_plan_contract.py`,
|
|
`check_1c_extension_action_contract.py`,
|
|
`check_1c_module_origin_contract.py`, and
|
|
`check_1c_code_symbol_contract.py`.
|
|
6. Do not move RAG datasets, training configs, or agent prompts into the
|
|
adapter service unless they become runtime dependencies.
|
|
|
|
## Live database access
|
|
|
|
### Web management
|
|
|
|
The runtime SQL connection list can be viewed and edited at
|
|
`http://<adapter-host>:8011/admin/`. The screen supports adding, editing, and
|
|
deleting entries and writes them atomically to `ONEC_SQL_BASES_JSON_FILE`
|
|
(normally `/data/onec-sql-bases.json`). Production-style deployments should set
|
|
`ONEC_ADAPTER_SERVICE_TOKEN`; the browser keeps it only in session storage. For
|
|
the isolated test profile, `ONEC_ADAPTER_ALLOW_UNAUTHENTICATED_ADMIN=true`
|
|
explicitly permits access without a token. Stored SQL passwords are never
|
|
returned by the API in either profile.
|
|
|
|
When `ONEC_SQL_BASES_JSON` is set directly, web editing is disabled because the
|
|
environment value would override the file. Move the connection map to the
|
|
configured JSON file before using the screen.
|
|
|
|
The adapter is not tied to one 1C database. Requests that read database-specific
|
|
sources must pass `base_id`; otherwise the adapter returns `base_id_required`.
|
|
|
|
### Mandatory SQL base access rule
|
|
|
|
`base_id` is the required settings key. Its entry contains the SQL server IP or
|
|
host, SQL database name, login, and password (preferably through
|
|
`password_env`). The adapter uses only that entry's existing credentials. It
|
|
must never create or change SQL logins, database users, roles, or permissions.
|
|
|
|
Application data and the metadata structure are read-only. The only SQL write
|
|
exception is a reviewed metadata saved-state change:
|
|
|
|
- base configuration metadata → `ConfigSave`;
|
|
- extension metadata → `ConfigCASSave`.
|
|
|
|
The exception does not permit writes to application-data tables, `Config`, or
|
|
`ConfigCAS`, and does not activate the saved configuration. Saved-state writes
|
|
remain gated by explicit opt-in, SHA-1 precondition, backup, transaction, and
|
|
readback verification. The binding policy is
|
|
`policies/sql-base-access-policy.yaml`.
|
|
|
|
Configure every base explicitly. Prefer `password_env` so secrets stay outside
|
|
repository files:
|
|
|
|
```json
|
|
{
|
|
"upo_test": {
|
|
"server": "sql-host.example.local",
|
|
"database": "upo_test",
|
|
"user": "configured_login",
|
|
"password_env": "ONEC_SQL_PASSWORD_UPO_TEST"
|
|
}
|
|
}
|
|
```
|
|
|
|
Set it as `ONEC_SQL_BASES_JSON` and pass the password separately as
|
|
`ONEC_SQL_PASSWORD_UPO_TEST`, or mount the same JSON outside the repository and
|
|
set `ONEC_SQL_BASES_JSON_FILE` to its container path. There is no implicit or
|
|
default database connection.
|
|
|
|
Current live methods:
|
|
|
|
- `query.validate`
|
|
- `query.run`
|
|
- `extensions.list`
|
|
- `schema.tables.list`
|
|
- `storage.files.list`
|
|
- `storage.file.get`
|
|
- `metadata.dbnames.summary`
|
|
- `metadata.kinds`
|
|
- `metadata.objects.list`
|
|
- `metadata.object.get`
|
|
- `metadata.object.properties`
|
|
- `metadata.object.property.write`
|
|
- `metadata.object.decode`
|
|
- `metadata.object.parts`
|
|
- `metadata.object.modules`
|
|
- `metadata.object.related`
|
|
- `metadata.object.forms`
|
|
- `metadata.object.templates`
|
|
- `metadata.object.template.details`
|
|
- `templates.read`
|
|
- `templates.analyze`
|
|
- `templates.map`
|
|
- `metadata.route.resolve`
|
|
- `metadata.form.decode`
|
|
- `metadata.object.attributes`
|
|
- `metadata.relationship.verify`
|
|
- `metadata.relationship.find`
|
|
- `metadata.object.full`
|
|
- `metadata.snapshot`
|
|
- `codec.decode`
|
|
- `codec.encode`
|
|
- `extension.objects.find`
|
|
- `modules.search`
|
|
- `modules.read`
|
|
|
|
Metadata methods require `base_id` and read live `Params`, `Config`, and
|
|
`ConfigCAS` storage through SQL. They do not use filesystem route indexes as a
|
|
source of truth. High-level metadata methods return 1C-facing data by default:
|
|
object identity, synonyms, decoded semantic sections, forms, modules, and
|
|
counts. Physical SQL table names, `_Fld...` columns, DBNames indexes, and
|
|
storage routes are internal diagnostics and are exposed only by low-level
|
|
methods (`storage.*`, `schema.*`, `query.*`, `metadata.dbnames.*`) or by
|
|
passing `include_storage=true`.
|
|
|
|
Object-scoped adapter methods accept the same public selector shapes:
|
|
`ref`, `kind` + `name`, `guid`, or MCP-friendly
|
|
`object_type`/`object_name`/`object_guid`. `ref` may use Russian or English
|
|
qualified metadata names such as `Обработка.<Name>` or `Document.<Name>`.
|
|
Client, MCP, and agent code must not add conditions for concrete object names;
|
|
the adapter owns generic selector normalization.
|
|
|
|
Saved-state client calls use the same name-first selectors together with
|
|
`layer=base_saved_state|extension_saved_state`. Public module search results
|
|
include a name-first `write_plan_target` (`ref`, form/module names, and a
|
|
1-based stream ordinal); `metadata.write.plan` resolves its physical handle
|
|
internally. SQL tables, file names, GUID owners, module handles, and payload
|
|
hashes remain diagnostic continuations exposed only with
|
|
`include_storage=true`. Every public RPC follow-up is shaped as
|
|
`{"method": "...", "params": {...}}`; `payload` is not the arguments field of
|
|
`next_call` or `next_resolution`.
|
|
|
|
Layer write policy:
|
|
|
|
- `Config` and `ConfigCAS` are **active-applied** and must be treated as read-only in adapter workflows.
|
|
- `ConfigSave` and `ConfigCASSave` are **saved, not yet applied** layers and are the only writable targets for connector staging changes.
|
|
- Base vs extension mapping:
|
|
- base config → `ConfigSave`
|
|
- extension config → `ConfigCASSave`
|
|
- Production apply to active layers is out of scope for this connector and requires a separate human-controlled deployment path.
|
|
|
|
Agent-facing code write rule:
|
|
|
|
- BSL edits must use `code.write`, not low-level SQL/write helpers.
|
|
- The agent passes 1C names (`object_type`/`object_name`/`routine_name`) or a
|
|
public path such as `<extension>.<form>.<routine>` plus full code text.
|
|
- `code.write` automatically targets the saved-state layer and reports
|
|
`write_mode.target=saved_state` with `activation_state=not_activated`.
|
|
- Write plans for embedded form-container modules return a ready
|
|
`code.write` hint; they do not incorrectly request a nonexistent
|
|
`#stream:<index>`.
|
|
- Use `code.read`/`code.search` with the default working state for current
|
|
programming-time code; use `state=both` only when an explicit saved vs active
|
|
comparison is needed.
|
|
|
|
`metadata.object.get` returns a live object card and decoded semantic sections
|
|
without physical SQL/storage traces by default. `metadata.object.decode` also
|
|
returns a 1C-facing decoded object profile by default; pass
|
|
`include_storage=true` only when adapter diagnostics need the underlying decoded
|
|
payload metadata, record containers, or DBNames/storage routes.
|
|
Exact extension objects use the same public `kind` + `name`/`ref` selectors as
|
|
base objects. `metadata.object.modules` includes owned form modules and returns
|
|
qualified names such as
|
|
`test2.Форма.t_Форма.Модуль формы`; extension GUIDs and CAS keys remain internal.
|
|
|
|
`metadata.object.properties` is the unified property endpoint for every 1C
|
|
metadata kind. It selects a kind-specific SQL decoder for `Configuration`,
|
|
`Constant`, `DocumentNumerator`, `IntegrationService`, `CommandGroup`,
|
|
`ScheduledJob`, and `DocumentJournal`, and otherwise returns the generic live
|
|
semantic profile. XML exports are analysis evidence only and are never a
|
|
runtime source for this method or any other adapter method.
|
|
|
|
`metadata.object.property.write` is the name-first saved-state writer for the
|
|
standard identity properties `synonym` and `comment`. Pass a public object
|
|
`ref` or `kind` + `name`. For an existing attribute, tabular section,
|
|
dimension, or resource, also pass `member_ref` or `member_kind` +
|
|
`member_name`; the adapter resolves the exact parent/member GUIDs and
|
|
serialized tree path internally. The method supports `plan`, `apply`,
|
|
`apply_and_verify`, and `apply_and_rollback`, requires explicit saved-state
|
|
gates, and never writes active `Config`/`ConfigCAS`. Renaming an object or
|
|
member, removing collection items, and adding a new synonym locale remain
|
|
intentionally disabled.
|
|
|
|
`metadata.object.member.add` adds one new object requisite or tabular-section
|
|
column (`Attribute`) by cloning an existing attribute in the same collection.
|
|
The caller passes only
|
|
`template_member_ref`, `new_member_name`, and optionally synonym/comment; the
|
|
adapter generates the GUID, preserves the template's type/settings, appends to
|
|
the exact declared collection, and verifies the new identity, empty/default
|
|
comment, container, and preserved non-identity settings after apply. A template
|
|
is blocked when its GUID or name is referenced outside its declared identity
|
|
fields. Arbitrary type construction and deletion are not supported by this
|
|
first structural route.
|
|
|
|
Managed form bodies in base `Config` are resolved from the public form GUID to
|
|
the sibling `<guid>.0` SQL payload. Command-bar buttons expose public command
|
|
names when their SQL binding points to a common command or a recognized
|
|
platform standard command; standard reference field `-5` is exposed as a
|
|
public `...Ref` data path. Callers never need the internal GUIDs or field codes.
|
|
Element event GUIDs are converted to platform event names (for example
|
|
`OnChange`, `ChoiceProcessing`, `AutoComplete`, `Selection`, and table row
|
|
events) and linked to their BSL handlers when the routine is present.
|
|
|
|
`metadata.object.attributes` is the preferred method for "show object
|
|
attributes/requisites" questions. It returns 1C metadata attribute names and
|
|
tabular section names from the live Config payload. For tabular sections, it
|
|
also returns decoded column names when nested column records are present.
|
|
Attributes and columns include decoded type evidence (`date`, `boolean`,
|
|
`string`, `number`, `reference`) and visible type parameters such as string
|
|
length, number precision/scale, or reference type GUID. Reference type GUIDs are
|
|
resolved back to live metadata object names and synonyms when the referenced
|
|
type exists in the base metadata. It must be preferred over SQL table/column
|
|
inspection for user-facing answers. The object can be selected by `guid`, by
|
|
`kind` + `name`, or by 1-based `ordinal` within `metadata.objects.list` for that
|
|
kind.
|
|
|
|
For a safe answer to "are these objects linked?", do not infer a link from a
|
|
similar field name, BSL mention, or a runtime value. Use
|
|
`metadata.relationship.verify` with an exact source `member` and optional
|
|
`target_ref`. It returns `confirmed` only when that member's declared 1C type
|
|
explicitly names the target object; otherwise it returns `not_confirmed` or an
|
|
explicitly ambiguous result. To discover a direct typed field without knowing
|
|
its name, call `metadata.relationship.find` with public refs only:
|
|
|
|
```json
|
|
{
|
|
"method": "metadata.relationship.find",
|
|
"payload": {
|
|
"base_id": "upo_test",
|
|
"ref": "Document.СписаниеЗапасов",
|
|
"target_ref": "Document.РасходнаяНакладная",
|
|
"direction": "either",
|
|
"execution_mode": "job"
|
|
}
|
|
}
|
|
```
|
|
|
|
`direction=either` checks both objects for explicitly declared references and
|
|
returns the direction of every confirmed edge. A `not_found` result means that
|
|
no direct declared metadata reference was found; it does not prove that an
|
|
indirect BSL, query, form, or business-process relationship is absent.
|
|
|
|
`metadata.object.full` is the preferred high-level method for agent answers like
|
|
"show everything about this document". It combines the live object card,
|
|
semantic sections, decoded forms, BSL module profiles, and counts in one
|
|
1C-facing response. Module profiles include routine lists and lightweight BSL
|
|
structural validation. Streams with BSL markers that are not complete modules
|
|
are kept, but marked as `completeness: fragment_or_invalid`. Full module text is
|
|
returned only with `include_module_text=true`. The method hides SQL/storage
|
|
traces by default; pass `include_storage=true` only for adapter diagnostics.
|
|
|
|
`metadata.object.parts` returns object part roles by evidence: metadata
|
|
payloads, form payloads, BSL stream containers, templates, and help/html
|
|
payloads. Physical Config part keys and numeric suffixes are hidden by default
|
|
and returned only with `include_storage=true`.
|
|
|
|
`metadata.object.modules` lists BSL stream modules discovered in those live
|
|
parts. Public responses use 1C-facing names such as `Модуль объекта`; physical
|
|
`module_id` values are returned only with `include_storage=true`.
|
|
|
|
`metadata.object.related` reads live related `Config` records referenced by
|
|
known object-kind sections, such as document forms and templates. Missing
|
|
references are returned explicitly with `source_missing`. Physical section paths
|
|
and Config file names are hidden unless `include_storage=true`.
|
|
|
|
`metadata.object.forms` resolves object forms through `metadata.object.related`
|
|
and then reads each form's live parts, including root `4` form payloads. Public
|
|
responses show form names and part roles; physical payload keys are hidden unless
|
|
`include_storage=true`.
|
|
|
|
`extension.objects.find` is the preferred first step for extension-specific
|
|
tasks. It searches live extension metadata by `extension`, `query`, `kind`, or
|
|
`guid`, returns object/template routes, and provides safe `read_selector`
|
|
payloads for follow-up calls. It can recover extension manifest routes even
|
|
when DBNames-Ext is incomplete; owner mismatches are returned as diagnostics
|
|
instead of silently hiding the object.
|
|
|
|
`metadata.route.resolve` resolves ConfigCAS/DBNames routes for extension
|
|
objects and child objects. Use it when a previous search returned a route
|
|
handle or when the caller has a CAS file name but needs the live object route.
|
|
|
|
`templates.read` and `templates.analyze` read MXL/MOXCEL templates by owner
|
|
selector, template selector, or direct ConfigCAS route. They return decoded
|
|
template structure: dimensions, named areas with row/column ranges, text and
|
|
parameter cells, column widths, cell text identifiers, cell parameters,
|
|
area-to-cell coverage, area intersections, shape variants, and explicit
|
|
capability flags. `merged_ranges` are reserved for authoritative merged-cell
|
|
records; until the MOXCEL merge record is decoded, possible merges are exposed
|
|
as `merged_range_candidates` with `confidence: low`.
|
|
|
|
Use `view=summary|structure|full`, `sections`, and `max_*` limits to keep
|
|
responses small for agents. `templates.map` is the compact agent-facing wrapper
|
|
over `templates.analyze`; it defaults to `view=summary` and is preferred when an
|
|
agent needs a quick layout map instead of all decoded lists.
|
|
|
|
1C templates are not only tabular MXL/MOXCEL documents. The 1C template
|
|
constructor offers these template types:
|
|
|
|
- `Табличный документ` - tabular document, MXL/MOXCEL. This is the current deep
|
|
decoder focus.
|
|
- `Текстовый документ` - plain or structured text payload.
|
|
- `Двоичные данные` - arbitrary binary payload.
|
|
- `Active document` - Active document payload.
|
|
- `HTML документ` - HTML payload.
|
|
- `Географическая схема` - geographic schema.
|
|
- `Графическая схема` - graphical schema.
|
|
- `Схема компоновки данных` - data composition schema.
|
|
- `Макет оформления компоновки данных` - data composition appearance template.
|
|
- `Внешняя компонента` - external component payload.
|
|
|
|
Always identify the template type before applying a decoder. Current
|
|
`templates.*` decoding is evidence-first for tabular documents; non-tabular
|
|
templates should be surfaced with type, raw route, payload markers, preview, and
|
|
explicit capability gaps until dedicated decoders are implemented.
|
|
|
|
For MOXCEL reverse engineering, request `sections=moxel_records,diagnostics`
|
|
and optionally `max_moxel_records`. The response includes parser-level record
|
|
head counts, grouped head samples with `tree_position`, and coordinate-like
|
|
samples. Use `top_level_records` with a larger `max_moxel_records` to inspect
|
|
ordered MOXCEL sections around a specific tree position. These diagnostics are
|
|
not authoritative merged-cell records. For a narrow ordered window, pass
|
|
`moxel_record_start` and `moxel_record_end`, for example `431..460`.
|
|
Use `moxel_record_heads` to keep only selected top-level record head codes,
|
|
for example `1049761,1413047`. Add `moxel_record_context` to include neighbor
|
|
records around matched top-level records; context records are marked with
|
|
`match: false`. `top_level_record_summary` summarizes the returned record
|
|
window with position range, head counts, match count, and compact numeric-field
|
|
variation by head. Its `field_hints` are low-confidence labels such as
|
|
`flag_like`, `small_enum_like`, or `coordinate_or_offset_like`; use them as
|
|
navigation hints, not as authoritative MOXCEL decoding. `numeric_field_matrix`
|
|
then shows those hinted/varying field values per `tree_position` without
|
|
returning every numeric item again, and `field_runs` compresses adjacent equal
|
|
values in that matrix. `field_transitions` lists the switch points between
|
|
those runs. `cell_style_candidates` exposes inline MOXCEL text cells with
|
|
nearby scalar style evidence and following metadata nodes; treat it as a
|
|
controlled-diff aid until border/font/alignment semantics are decoded.
|
|
`top_level_shapes`
|
|
groups top-level records by structural shape
|
|
(`head`, list length, numeric/string counts) and includes sample positions.
|
|
`top_level_shape_candidates` ranks rare/long/numeric-heavy shapes as
|
|
low-confidence hints for manual layout/merge investigation. Each candidate can
|
|
include `rank` and `suggested_windows` with a ready `request_hint` for the next
|
|
focused `templates.map` call. Pass `moxel_candidate_rank` to focus
|
|
`top_level_records` on that 1-based candidate rank without copying the request
|
|
hint manually. Use `moxel_candidate_window_index` to select a later suggested
|
|
window from the same candidate when the structural shape appears more than
|
|
once. Use `moxel_candidate_reasons`, for example
|
|
`coordinate_like_prefix,long_record`, to return only candidates containing all
|
|
requested reason codes. Use `moxel_candidate_min_score` to keep only candidates
|
|
above a heuristic score threshold. `top_level_candidate_summary` reports score
|
|
and reason distributions plus the count returned after filters. Use
|
|
`moxel_candidate_heads` to filter the candidate list by head code; use
|
|
`moxel_record_heads` when filtering actual top-level records in a focused
|
|
window. Use `moxel_candidate_start`/`moxel_candidate_end` to filter candidates
|
|
by their top-level positions; use `moxel_record_start`/`moxel_record_end` when
|
|
filtering returned records.
|
|
|
|
`metadata.form.decode` decodes one form payload into an evidence-first profile:
|
|
event handlers, form items, attributes, commands, auxiliary table/command-bar
|
|
records, and the embedded form module summary. Form records include stable
|
|
paths back into the decoded tree for names, ids, localized titles, handler
|
|
names, and known platform event ids. Counts include both returned and total
|
|
record numbers so truncated responses are explicit. The profile also links form
|
|
events and form commands to module routines, links command buttons to commands
|
|
by GUID evidence, and marks handlers as `resolved` or `missing`.
|
|
|
|
`modules.search` searches live BSL text and returns snippets by default.
|
|
Physical module ids and payload coordinates are hidden unless
|
|
`include_storage=true`. Every public match includes a `read_selector` with
|
|
`method: "modules.read"` and either an object selector or an opaque
|
|
`module_ref`; agents should pass that selector to the next read call instead of
|
|
requesting storage details. When `resolve_owners=true`, results also include
|
|
`counts.owner_resolved`, `counts.owner_unresolved`, and
|
|
`diagnostics.owner_resolution` so incomplete owner recovery is explicit.
|
|
`modules.read` reads by object selector (`ref`, `guid`, `kind` + `name`,
|
|
`object_type`/`object_name`/`object_guid`, or `kind` + 1-based object
|
|
`ordinal`) and optional 1-based `module_ordinal`; it also accepts `module_ref`
|
|
from a prior search result. The response hides source and payload metadata
|
|
unless `include_storage=true`.
|
|
|
|
`code.search` is the agent-facing wrapper over module search. Its items include
|
|
`read_selector.method: "code.read"` and preserve `module_ref` when that is the
|
|
best available safe handle. `code.read` can consume that selector directly;
|
|
the selector pins the configuration view that produced the hit. A storage
|
|
stream whose Configurator-tree role is not independently decoded is returned
|
|
as `bsl_module` with `role_status=unconfirmed` and must not be treated as a
|
|
command, manager, or a tree path.
|
|
|
|
`metadata.object.commands` resolves an `extension` name to the active
|
|
extension internally before it reads the selected object. A caller provides
|
|
only the public object and extension selectors; it must not replace them with
|
|
a base-configuration route or infer a command from a BSL stream suffix. A
|
|
successful empty command list is the only evidence currently returned for “no
|
|
decoded commands”; an unresolved object route is reported separately.
|
|
For object-owned extension forms, `modules.search` and `code.search` resolve
|
|
the form module from the public owner reference. In the default
|
|
`state=working` view they inspect the saved counterpart first and fall back to
|
|
the active module only when needed; `state=active` never returns saved-only
|
|
text. Saved matches carry `activation_state=saved_state` and
|
|
`current_state.activation_state=not_activated`.
|
|
For an active extension form selector, `code.read state=both` resolves the
|
|
saved form by logical owner/form identity, even when active and saved CAS file
|
|
names differ, and reports live text SHA1 comparison evidence.
|
|
|
|
`metadata.resolve_overrides` uses the same name-first form ownership and
|
|
saved-first working-state rules. A public selector such as `Catalog.test2`
|
|
therefore resolves routines located in forms owned by that extension object;
|
|
the returned chain identifies the form and activation state without exposing
|
|
the object's physical SQL route.
|
|
|
|
`metadata.definition.find` accepts public object references such as
|
|
`Обработка.<Name>` or `Document.<Name>` in `query` and the common object
|
|
selector aliases for scoped lookup. A single metadata object match is promoted
|
|
to the top-level `object` field and the response includes `related_selectors`
|
|
for the next public calls (`metadata.object.get`,
|
|
`metadata.object.full`, `metadata.object.modules`, `metadata.object.form.details`,
|
|
`code.search`, `modules.search`, and similar selectors allowed by the object's
|
|
capabilities).
|
|
|
|
`metadata.adapter.audit` reports recognized metadata kinds, public kind counts,
|
|
missing supported kinds when `include_missing=true`, and unmapped DBNames roles
|
|
when `include_unmapped=true`. Missing entries are marked
|
|
`presence_status=supported_absent_in_selected_base`; this is a statement about
|
|
the selected infobase, not a claim that the adapter lacks that kind.
|
|
|
|
Use `python scripts/check_1c_metadata_kind_fixtures.py --live` from the
|
|
repository root to check the reproducible rare-kind fixtures. The checker does
|
|
not write SQL or create metadata. The fixture manifest pins the exact Designer
|
|
version and external reference commit. The companion
|
|
`scripts/export_1c_extension_sources.ps1` performs a read-only `test2` source
|
|
export with operating-system integrated authentication and exposes no
|
|
infobase-user or credential arguments.
|
|
|
|
`codec.decode` and `codec.encode` are low-level lossless helpers. A no-op encode
|
|
from a live source keeps the original bytes exactly; modified text/tree payloads
|
|
are encoded back using the original compression and text encoding envelope.
|
|
|
|
`changes.propose` reads one live storage payload, checks an optional
|
|
`expected_sha1`, applies `edits` to decoded brace-tree paths in memory, and
|
|
returns the re-encoded payload metadata for review. It never writes to SQL.
|
|
Each edit has `path`, `value`, optional `node_type` (`auto`, `atom`, `string`),
|
|
and optional `expected_old`. For stream payloads, an edit can use
|
|
`stream_index` with either full `text` replacement or `replace: {old, new}`,
|
|
plus optional `expected_contains`; stream headers are rebuilt with updated
|
|
byte lengths before the payload is encoded back. Diagnostic `source.module_id`
|
|
values returned by `metadata.object.modules` with `include_storage=true` or
|
|
accepted by `modules.read` can be used directly; when the module id includes
|
|
`#stream:<index>`, stream edits inherit that index unless an edit specifies its
|
|
own `stream_index`. The response
|
|
includes `validation`, produced by re-decoding the encoded proposal in memory.
|
|
For BSL stream edits, validation also runs lightweight structural checks for
|
|
routine, region, and preprocessor-block balance. Stream edits can also target
|
|
a whole BSL routine with `routine: {operation, name, text}` where operation is
|
|
`replace`, `append`, or `upsert`. Routine edits accept
|
|
`expected_old_contains` and `expected_old_sha1` as live preconditions against
|
|
the current routine text; failed preconditions reject the proposal before any
|
|
encoded review artifact is returned.
|
|
|
|
`storage.*` methods read 1C storage rows directly from SQL tables
|
|
`Params`, `Config`, `ConfigSave`, `ConfigCAS`, and `ConfigCASSave`. They are
|
|
diagnostic building blocks for the live metadata decoder; they do not create or
|
|
read filesystem indexes.
|
|
|
|
## Cache policy
|
|
|
|
The source of truth is the live database. A filesystem cache may be added only
|
|
as a derived acceleration layer for expensive decoded metadata/module payloads,
|
|
not for current table data. Cache entries must carry `base_id`, source
|
|
fingerprint, generation time, TTL, and `fresh/stale` status. If freshness cannot
|
|
be proven, the adapter must re-read live SQL or return an explicit stale-cache
|
|
error.
|
|
|
|
Operational runbook: `docs/runbooks/1c-operational-coding.md`.
|
|
|
|
## Development audit telemetry
|
|
|
|
Every REST `/rpc` call produces a privacy-safe JSONL event in
|
|
`/data/adapter-audit.jsonl`. It contains the UTC time, correlation id, public
|
|
method and selector summary, result status/error, duration, public route and
|
|
resolver timings/counts (when a write route is involved), and exception type
|
|
when the request itself fails. A `public_write_route_unresolved` event retains
|
|
the safe resolver status/error/candidate count so it can be diagnosed without
|
|
asking a caller for a module handle. It deliberately excludes BSL text, SQL
|
|
payloads, physical file names, stream indexes, credentials, and SQL connection
|
|
details. The MCP proxy forwards its generated
|
|
request id in `X-Request-ID`, so an agent response can be correlated with the
|
|
REST record. The log is shared by all configured
|
|
`base_id` values so cross-base failures and slow calls can be compared.
|
|
|
|
For development, the default retention is deliberately generous: 50 MiB per
|
|
file and ten retained files. Configure `ONEC_ADAPTER_AUDIT_MAX_BYTES` and
|
|
`ONEC_ADAPTER_AUDIT_KEEP_FILES` to change it. Rotation is best-effort and can
|
|
never fail an adapter request. A caller may supply an `X-Request-ID` header to
|
|
correlate a client event with the REST record.
|
|
|
|
The `adapter-1c-audit` Compose service writes an aggregate report every 15
|
|
minutes to `/data/adapter-audit-reports/latest.json`; set
|
|
`ONEC_ADAPTER_AUDIT_INTERVAL_SECONDS` to alter the interval. It reports base
|
|
distribution, failures, slow operations, malformed rows, and recent failures.
|
|
For an immediate manual report, run `python scripts/analyze_1c_adapter_audit.py`
|
|
against a copied log or `python /app/analyze_audit.py` inside the REST image.
|
|
The MCP proxy has its own persistent `/data/mcp-audit.jsonl` and periodic
|
|
summary: it records failures that happen before a request reaches REST.
|
|
|
|
For an extension-wide `code.search` without a concrete object selector,
|
|
`timeout_seconds` is a total search budget. If owner-route discovery consumes
|
|
that budget, the adapter returns `status=partial` with
|
|
`diagnostics.code=time_budget_exhausted`; it does not continue serial owner
|
|
probes in the background. Narrow routine work with `ref` or `kind`/`name`.
|
|
|
|
REST deployments use a five-minute Docker stop grace period. On `SIGTERM` the
|
|
adapter stops accepting new work and waits for already-running request threads,
|
|
including verified saved-state writes, to complete. Do not deploy the REST
|
|
service while an operator is intentionally running a production-base write;
|
|
the deployment prevents a half-response, but the client should still retry only
|
|
after it receives a structured result.
|
|
The deployment script also waits for `health.runtime.active_rpc_count=0` before
|
|
recreating REST. `-SkipDrainCheck` is an emergency-only override and must not
|
|
be used while a write is in progress.
|