Files
llm/plugins/1c/connector
2026-08-14 13:02:01 +03:00
..
2026-08-14 09:40:51 +03:00
2026-08-14 09:40:51 +03:00
2026-08-14 09:40:51 +03:00
2026-08-14 09:40:51 +03:00
2026-08-14 09:40:51 +03:00
2026-08-14 13:02:01 +03:00
2026-08-14 09:40:51 +03:00
2026-08-14 09:40:51 +03:00
2026-08-14 09:40:51 +03:00
2026-08-14 09:40:51 +03:00

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.

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:

python connector/adapter_1c_server.py

From plugins/1c/connector after installing package dependencies:

python adapter_1c_server.py

Health without a concrete base:

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:

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:

{
  "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:

{
  "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.