# 1C Adapter API Contract ## Configuration repository control The current adapter release is SQL-only. It does not start Designer, call a Windows runner, or inspect repository internals. External 1C execution is a future-version capability and is disabled by default with `ONEC_ADAPTER_ENABLE_EXTERNAL_1C=false`. Repository operations are available through `repository.status`, `repository.lock.plan`, `repository.lock`, `repository.lock.confirm`, `repository.lock.verify`, `repository.unlock`, `repository.commit.plan`, and `repository.commit`. Configuration is selected only by `payload.base_id`: the base runtime profile declares `repository.backend=direct|karman_bridge`, the Designer executable, infobase selector, endpoint, optional extension, users, and environment-variable names containing transient passwords. No repository, bridge, or endpoint name is hard-coded or inferred from naming conventions. `repository.lock_mode=automatic|manual` is also selected per base. Automatic mode uses the configured runner. Manual mode requires no Designer or runner: `repository.lock.plan` returns the exact public development-object names to lock in Configurator, and `repository.lock.confirm` records the user's explicit confirmation for only that object set. Such a session is marked `user_confirmation_only`; `repository.lock.verify` returns `manual_confirmation_unverified` and never represents it as an automatic repository check. In the SQL-only release, `repository.lock.request` persists an adapter-side coordination request with status `pending_user_lock` and the resolved public object scope. It deliberately does not write a marker into the 1C infobase SQL database: such a marker would not create a native repository lock. `repository.lock.request.status` exposes the request state, and `repository.lock.confirm` can consume its `request_id`; confirmation always uses the immutable object set stored in the request. Manual requests expire after `ONEC_REPOSITORY_REQUEST_TTL_SECONDS` (24 hours by default) and may be explicitly cancelled with `repository.lock.request.cancel`. Manual confirmations expire after `ONEC_REPOSITORY_CONFIRMATION_TTL_SECONDS` (2 hours by default). After the user releases the objects in Configurator, `repository.lock.close` closes the confirmation, marks its originating request as `closed`, and immediately blocks further SQL writes through that session. The adapter keeps a bounded audit trail of request creation, confirmation, cancellation, and closure and exposes it to the administrative requests view. Both backends invoke standard Designer repository commands. A Karman/Filebox backend is an opaque native TCP transport and does not own credentials, object locks, or repository transactions. For configured bases, saved-state apply is blocked until the caller supplies an active adapter-owned `lock_session_id`. Commit additionally requires `allow_repository_commit=true` and a non-empty version comment. Unlock and commit operate only on the object set recorded for that adapter session. Status: draft, read-only first. Related work plan: `docs/1c-extension-layer-plan.md`. ## Source Boundaries - The live adapter works with 1C through SQL storage only. - XML exports and Form.xml files may be used by this project for analysis, fixtures, learning, diffing, and rule discovery, but they are not a live 1C write transport for the adapter. - When XML-derived rules are promoted into the adapter, the runtime write path must still resolve to concrete SQL storage targets such as `ConfigSave` or `ConfigCASSave`, with explicit gates and readback verification. ## User Identity And Access Terminology An unqualified user request means an **infobase user**: the platform identity visible in Configurator under administration of infobase users. It does not mean the BSP `Catalog.Пользователи` record. The two layers are intentionally separate: | Layer | Canonical term | Source | Authoritative for | |---|---|---|---| | Platform | `infobase_user` / Configurator user | `dbo.v8users` and the 1C `ПользователиИнформационнойБазы` runtime API | login identity, authentication flags, platform administrator flag, assigned platform role set and exact platform roles | | Application | `bsp_catalog_user` / BSP user | BSP catalogs, access groups, profiles and access registers | BSP membership, profiles, access groups, RLS/access-key chains and application access diagnostics | Routing rules: - ordinary "users", "user roles", "login", "password", and "Configurator users" start with `infobase.users.search` or `infobase.user.get`; - explicit BSP/group/profile/RLS questions use `access.users.search` and `access.user.explain`; - a name match between the layers is correlation only and never proves that the records are identical; - BSP groups/profiles must never be reported as the exact role assignment of a Configurator user; - SQL `RolesID` proves the assigned platform role-set identity, but exact role names require the supported 1C runtime `ПользователиИнформационнойБазы` API. `infobase.users.search` and `infobase.user.get` expose only safe `v8users` fields: platform id, name/full name, change time, login-list visibility, authentication-presence flags, administrator flag, `RolesID`, and protected payload size. They never expose `Data`, password hashes, password-policy blobs, material keys, or raw `users.usr` content. Until a runtime connector is added, responses set `role_assignment.exact_role_names_status=runtime_required`. ### Configurator User Password Operations Password mutation is available only for the platform `infobase_user` layer: - `infobase.user.password.capabilities` reports whether the protected path is ready for a concrete `base_id`; - `infobase.user.password.status` reports `empty`, `set`, or `standard_authentication_disabled` for one exact platform user. It never returns password hashes or `Data`; - `infobase.user.password.set` changes the password and requires `user`, the exact 32-hex `confirm_user_id`, `new_password`, and `allow_password_change=true`. It uses the same guarded SQL transaction as `clear`, storing the Base64-encoded SHA-1 pairs for the UTF-8 password and its Unicode uppercase form; - `infobase.user.password.clear` removes the password and requires `user`, the exact 32-hex `confirm_user_id`, and `allow_password_clear=true`; it rejects a `new_password` field. This operation uses SQL only: it locks the exact `dbo.v8users` row, decodes that row's XOR-protected `Data` container, replaces only the first adjacent current SHA-1/Base64 password pair with the empty password pair, writes with an old-`Data` concurrency predicate, and verifies readback before commit; - a platform administrator additionally requires `allow_administrator_password_change=true`; - normally both mutations are blocked when `ONEC_ADAPTER_SERVICE_TOKEN` is empty. A disposable isolated test stand may explicitly set `ONEC_INFOBASE_USER_ADMIN_ALLOW_UNAUTHENTICATED=true`; this also permits an unprotected runtime bridge endpoint and must never be enabled in production. Both operations select the exact user through `infobase.user.get` and update only `dbo.v8users.Data`. The clear-text password for `set` exists only in memory and is not included in responses or write-history payloads. Neither operation updates `Params/users.usr`, `EAuth`, roles, administrator flags, names, or BSP records. Both are rejected when `EAuth=0`, because changing stored hashes does not enable standard authentication. The SQL path decodes the row-specific XOR key, patches the first adjacent current-hash pair in the authentication section, reuses the original key and byte layout, and verifies that no other parsed scalar changed. A compare-old `Data` predicate prevents overwriting a concurrent user edit. Successful `set` and `clear` results are recorded in `metadata.write.history` with method, operation, target platform id/name, transport, status, and verification result. Request payloads are never written to that history, so `new_password` is not persisted. The SQL layout with 43 root fields was live-verified on `upo` during an administrator password clear. ## Undecoded Evidence Public decode/read methods should not drop useful payload evidence when a decoder is incomplete or when only part of the object is understood. Methods that expose decoded object, part, form, or template payloads accept: ```json { "evidence_mode": "none | summary | full | raw" } ``` Contract: - `none`: omit `undecoded_evidence`; - `summary`: return compact role, markers, root signature, string samples, payload size/hash metadata, and safe stream/base64 samples; - `full`: return broader samples and longer text excerpts for agent-side analysis; - `raw`: return the broadest evidence. Low-level storage offsets, block hashes, and physical coordinates are exposed only together with `include_storage=true`. `evidence_mode` is intentionally separate from object `view` (`effective/base/extension`): `view` selects the metadata layer, while `evidence_mode` selects diagnostic detail. Current methods using this contract include `metadata.object.decode`, `metadata.object.parts`, `metadata.object.templates`, `metadata.object.template.details`, `metadata.form.decode`, and `metadata.object.full` through its `parts_summary` section. ## Template Content Export `templates.read` can return the actual current SQL-stored template content in read-only mode. Content is opt-in and bounded: ```json { "base_id": "upo_test", "kind": "Document", "name": "АктВыполненныхРабот", "template": "ПФ_MXL_УдалитьАкт", "view": "full", "include_content": true, "max_content_bytes": 262144 } ``` Each part then contains `content_export.container`: media type, decoded byte size, returned byte size, SHA1, truncation flag, and base64 data. Embedded decodable stream/base64 blocks are also returned in `extracted_text`, including HTML as text. `max_content_bytes` is limited to 1 MiB per returned item. The operation never writes to 1C SQL tables; it only reads the configured database and does not perform platform rendering to pixels or PDF. ## Managed Form Element Types SQL form profiles distinguish every element type observed in the reference UPO `Form.xml` export. This includes containers, pages, command bars, tables and their search additions, input/label fields, checkbox fields, picture fields, radio-button fields, spreadsheet-document fields, label/picture decorations, context menus, and extended tooltips. XML is used only to confirm decoding rules; live `metadata.form.decode` and `metadata.object.form.details` responses are produced from SQL payloads. Dynamic table profiles also expose confirmed read-only/skip-on-input and row-set-change flags, height in table rows, footer, row-selection mode, horizontal/vertical line flags, alternating-row color, automatic row insertion, and drag-start/drag flags. The dynamic-table SQL positions for `ChangeRowSet`, `HeightInTableRows`, and `Footer` were confirmed against four distinct tables in the reference UPO form. Rare layout and behavior properties remain best-effort until their SQL positions are confirmed by multiple samples. The complete offline UPO inventory covers 6,748 `Form.xml` files, all parsed successfully, with 821,077 named elements, 41 element kinds, and 253 direct property tags. Runtime still does not read XML. SQL section records additionally decode `CurrentRowUse` and `ModifiesSavedData` for commands and `MainAttribute` and `SavedData` for attributes. The confirmed payload positions are 9/10 for command current-row/saved-data behavior and 10/11 for attribute main/saved-data flags. Table search, view-status, and search-control additions expose a structured `AdditionSource` derived from their decoded parent-table hierarchy. Its public value contains `owner_element` and `representation`; it deliberately does not use the reserved `table` key, which denotes physical SQL storage in adapter diagnostics. Command-bar buttons also decode `ButtonImportance`, `GroupHorizontalAlign`, and `GroupVerticalAlign`; label/picture decorations decode both group-alignment properties. Input, label, picture, checkbox, radio-button, and chart fields use positions 53/54. Marker-22 containers (ordinary/column groups, command bars, and pages) use the last three and last two entries of their variable-length node (`-3/-2`). The other confirmed SQL positions are 11/41/42 for command-bar buttons and 32/33 for decorations. The vertical enum is normalized as `Top`, `Center`, `Bottom`, or `Auto`. These positions were cross-checked against contrasting XML declarations and the matching live SQL payloads; XML remains an offline analysis source only. Marker-35/37 fields also expose `AutoEditMode=true` when position 26 is `EnterOnInput`. In the reference document-form inventory, all 11,817 explicit `AutoEditMode` declarations are paired with `EditMode=EnterOnInput`; the live SQL payload stores that pair as the single enum code `2` at position 26. The adapter therefore returns `AutoEditMode` as a confirmed derived property and does not invent a separate storage position. Table additions have two confirmed live SQL layouts: marker-5 records embedded directly in the variable tail of a dynamic list/table, and the same records embedded in its auto command bar. Both are normalized to public marker-6 addition items. Validation against 12 UPO forms decoded 39/39 XML-declared search-string, view-status, and search-control additions with a resolved owner and representation. The variable-length dynamic-table tail is decoded relative to the end of the element after validating the four table-addition records. It exposes `SearchStringLocation`, `ViewStatusLocation`, `SearchControlLocation`, and `FileDragMode`. The location enum maps were confirmed against eleven live SQL tables covering `Default`, `None`, `CommandBar`, `Top`, `FormCaption`, and `PullFromTop` values present in the reference XML export. Related-form discovery follows the object descriptor layout for reports (`Form` section 5), data processors (section 6), exchange plans (section 6), selection criteria (section 3), and settings storages (section 4). Report and data-processor template sections are kept separate from forms. Live descriptor routes are also confirmed for enum forms (section 3), information-register forms (section 5), accumulation-register forms (section 8), business-process and task forms (section 4), chart-of-characteristic-types and chart-of-calculation-types forms (section 7), chart-of-accounts forms (section 6), and document-journal forms (section 6). Form list and full SQL payload decoding were verified by public object/form names for every listed kind. Template sections for exchange plans and charts of characteristic types remain distinct at section 4. Template discovery additionally covers enum templates (section 4), information-register templates (section 6), and document-journal templates (section 3). Catalog templates use section 3; section 4 is the catalog command section. Safe bounded `templates.read include_content=true` export was verified for the newly routed kinds, including MOXCEL content. Object-command discovery is confirmed for catalogs (section 4), documents (section 6), data processors and document journals (section 5), accumulation registers (section 4), information registers and tasks (section 8), and exchange plans and reports (section 7). When a separate command descriptor is absent, the public command identity falls back to the identity embedded in the owner descriptor. Results are deduplicated by command GUID/name. ## Payload Diff `payload.diff` is a diagnostic method for comparing two payload snapshots. It accepts `before` and `after` sources as either live storage pointers (`base_id`, `table`, `file_name`) or inline payloads (`payload_base64`, `payload_hex`, or `text`). It requires `diagnostic=true`. The response includes: - byte sizes and SHA1 hashes; - decoded envelope metadata; - unified text diff; - scalar brace-tree changes with paths such as `$.1.3.2`; - changed string sequence entries; - compact `undecoded_evidence` for both sides when `include_evidence=true`. Use it after manual Designer/configurator edits to identify which raw payload nodes changed before promoting a rule into a higher-level decoder or writer. ## Agent-Facing Addressing Agent-facing selectors and answers should prefer full semantic 1C paths over GUIDs, SQL names, CAS keys, or bare local names. Default path shape: ```text .[.
....] ``` Examples: ```text Справочник.Контрагенты Справочник.Контрагенты.Наименование Документ.РеализацияТоваровУслуг.Товары.Номенклатура РегистрСведений.ЦеныНоменклатуры.Ресурсы.Цена Документ.РеализацияТоваровУслуг.Форма.ФормаДокумента.Товары ОбщийМодуль.ИнтеграцияСCRM.ОтправитьКонтрагента ``` Short names are allowed as input conveniences, but adapter methods must either normalize them to one `canonical_path` or return ambiguity candidates. Bare member names such as `Наименование` are not safe write targets without object, form, module, or routine context. Metadata path resolution and BSL symbol resolution are separate operations. A code expression such as `Номенклатура.ЕдИзмерения.Код` starts from a local symbol until the adapter proves that the symbol maps to a metadata path or typed value. Resolved agent-facing objects should include, where known: - `canonical_path`; - `context_path` when a short path was resolved inside a known context; - `path_kind`, for example `metadata_object`, `metadata_member`, `form_element`, `module`, `routine`, or `code_symbol`; - `presentation` and synonym; - `ref` and GUID/storage evidence for internal follow-up calls. ## BSL Symbol Resolution Command: ```text python scripts/resolve_1c_bsl_symbol.py --metadata --modules --expression --module-id [--object-kind ] [--object-name ] [--routine-name ] ``` Safe Unicode command shape: ```text python scripts/resolve_1c_bsl_symbol.py --metadata --modules --expression-b64 ``` Output schema: ```text onec_bsl_symbol_resolution.v1 ``` Live adapter RPC: ```json { "method": "code.symbol.resolve", "payload": { "base_id": "", "expression": "Номенклатура.ЕдИзмерение.Код", "module_ref": "", "routine_name": "" } } ``` Purpose: - resolve BSL expressions inside a concrete module/routine/form context before treating them as metadata paths; - return `metadata_path` only for full semantic paths such as `Справочник.Номенклатура.Артикул` or for members proven by context, for example a current object-module standard attribute; - in live adapter mode, read the module through `modules.read`, use `metadata.definition.find` for full metadata paths, and use `metadata.object.attributes` for context-proven owner members; - return `parameter` or `local_variable` when the first expression segment is declared in the current routine/module, with `safe_as_metadata_path=false`; - return unresolved candidates for short object names such as `Номенклатура.ЕдИзмерение.Код` instead of silently converting them to `Справочник.Номенклатура...`. ## Agent-Facing Code Writes Normal coding agents should write BSL through `code.write`, not through SQL, storage rows, payload paths, or `metadata.module.write_apply`. `code.write` accepts 1C names and code text: ```json { "method": "code.write", "payload": { "base_id": "upo_test", "object_type": "CommonForm", "object_name": "t_Форма", "routine_name": "ЗаменаДомена", "routine_text": "Процедура ЗаменаДомена(Команда)\n\t// code\nКонецПроцедуры\n" } } ``` Contract: - default `mode` is `apply`, and apply means save to the working `ConfigSave`/`ConfigCASSave` layer, not production apply; - every `code.write` response includes `write_mode.target=saved_state`, `write_mode.activation_state=not_activated`, and `write_mode.production_apply=false`; - saved-state `code.read` and `code.search` responses include `current_state.source=saved_state` and `current_state.activation_state=not_activated`; - `code.read state=working` is save-first with active fallback, `state=save` reads only the saved layer, and `state=active` skips saved-state lookup. `state=both` returns side-by-side layers and comparison metadata; - SQL/storage gates are set by the adapter for this facade; - public responses hide physical storage details unless `include_storage=true`; - full module replacement uses `module_text`, `full_text`, or `code`; - routine replacement uses `routine_name` plus `routine_text`; - fragment replacement uses `old` plus `new`. With `routine_name` or a routine-level `canonical_path`, `old` must occur exactly once inside that procedure/function; without routine scope, it must occur exactly once in the current saved module text; - if the fragment is missing or repeated, the adapter returns `fragment_not_found` or `ambiguous_fragment` and does not write; - low-level storage methods remain diagnostic and implementation details. For embedded form modules the adapter writes only the scalar module token in the saved form payload with `path_preserve_format`. Whole-form payload canonicalization is forbidden because Designer may reject the form even if the payload decoder can parse it. ## Resolve Object Command: ```text python scripts/resolve_1c_object.py --kind --name --index ``` Output schema: ```text onec_object_resolution.v1 ``` Purpose: - resolve objects by configurator-visible names, synonyms, qualified names, and generated type names such as `DocumentRef.ПриходнаяНакладная`; - return the canonical base object plus extension overlays; - keep storage details under `storage`, so agent-facing code can continue to operate with 1C metadata names. ## Object Brief Context Command: ```text python scripts/get_1c_object_brief_context.py --index --kind --name --view effective|base|extension --extension --max-attributes --max-modules --max-forms --output ``` Output schema: ```text onec_object_brief_context.v1 ``` Purpose: - provide the default starting context for an agent after a user names a 1C object; - keep the response compact: object identity, active extension names, attribute summary, tabular section names, form list, module list, overlay counts, and suggested follow-up tools; - use `view=effective` by default so the agent sees the same working object picture as the user sees in Configurator; - avoid loading large BSL modules or full form XML; use the dedicated module and form APIs for detail reads. ## Fact Resolution Command: ```text python scripts/resolve_1c_fact.py --index --path --view effective|base|extension [--extension ] ``` Safe Unicode command shape for agents and PowerShell callers: ```text python scripts/resolve_1c_fact.py --index --path-b64 ``` Output schema: ```text onec_fact_resolution.v1 ``` Purpose: - verify concrete facts about the current configuration before code generation, for example `Справочник.Номенклатура.Цвет` or `Документ.ПриходнаяНакладная.ДатаСоздания`; - return `exists`, `confidence`, `area`, object identity, matched member, and source provenance; - support object, attribute, tabular section, form, module, and snapshot-backed checks through the same agent-facing shape; - keep examples and old snapshots out of the current-configuration path unless the caller explicitly passes `--snapshot`. - normalize positive results to a full `canonical_path` and return ambiguity candidates when a short path is not unique. Policy: - RAG may explain platform behavior, patterns, and documentation. - `resolve_1c_fact.py` or a richer adapter method must confirm concrete object, attribute, form, command, module, and data facts for the selected base. - A negative result means the fact is not confirmed in the provided source; the agent should not silently replace it with a fact from examples or generic documentation. ## Live Adapter Navigation The REST adapter exposes metadata and BSL navigation through public selectors. Agents should prefer these selectors over diagnostic storage fields. Object selectors: - Object-scoped methods accept the same public selector shapes: `ref`, `kind` + `name`, `guid`, or MCP-friendly aliases `object_type`, `object_name`, and `object_guid`. - `ref` can be a public qualified object reference such as `Обработка.` or `Document.`; the adapter normalizes Russian and English metadata kind names to the canonical internal kind. - Public selectors returned by the adapter keep backward-compatible `kind`/`name`/`guid` fields and, when `kind` + `name` are known, also include compact `ref=.`. - Do not branch on concrete object names in client or MCP code. Normalize the selector once and pass the resulting public selector through adapter methods. - If a result contains `read_selector.method`, call that method with the selector payload as-is. Do not reconstruct the selector from display text or storage diagnostics. - `help.methods` exposes `selector_capabilities` for object-scoped methods. Agents should use these flags instead of inferring selector behavior only from natural-language descriptions. Important methods: - `data.schema`, `data.list`, `data.get`, `data.count`, and `data.query` expose logical 1C data names while reading physical SQL tables. The object is selected by public `ref` (for example `Catalog.`) or by `kind` + `name`; a row is selected separately with `record_ref`. SQL table names and `_Fld...` columns are internal routes, not caller-facing selectors. Constants are exposed as a typed `value`; enumeration rows include their public value `name`, `synonym`, and `value_ref`. Business-process storage is resolved through the platform `_BPr` route internally. - `data.present` returns a compact presentation for one `record_ref`, and `data.movements` reads register rows for a `recorder_ref`. - `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 compact preview and never limits handler resolution. - The same form details expose command `CurrentRowUse`/`ModifiesSavedData`, attribute `MainAttribute`/`SavedData`, and structured table-addition `AdditionSource` properties directly from the live SQL payload. Command-bar buttons additionally expose `ButtonImportance`, `GroupHorizontalAlign`, and `GroupVerticalAlign`; decorations expose their horizontal and vertical group alignment. - `metadata.object.special.details` for `ScheduledJob` returns the complete decoded SQL schedule: date/time windows, completion interval, intraday repeat and pause, weekdays, day/month restrictions, months, and week/day repeat periods, together with use/predefined and restart settings. It also resolves the handler's common module and returns `handler.read_selector`; pass that selector unchanged to `modules.read` to read the exact procedure. A non-predefined disabled job may legitimately return `schedule.status=not_configured` when its separate `.0` schedule payload is absent. - `metadata.object.properties` has kind-specific live SQL decoders for `EventSubscription`, `WebService`, and `HTTPService`. Event subscriptions expose their source objects, event and handler. The handler contains a `read_selector` that can be passed unchanged to `modules.read` to obtain the exact common-module procedure from the working SQL state. Web services expose namespace, XDTO packages, descriptor/session settings, operations and parameters; HTTP services expose root URL/session settings, URL templates, HTTP methods and handlers. XML exports are used only to establish and test the Config layout, never as a runtime data source. - The same property API has SQL decoders for `CommonAttribute`, `SessionParameter`, `FunctionalOption`, and `FunctionalOptionsParameter`. Common attributes expose their value type, content objects, indexing, full-text/history flags, and data-separation settings and references. Session parameters preserve composite types, including unions of several reference or platform types. Functional options expose their storage location, privileged-get flag, and every affected top-level or nested metadata object; functional-option parameters expose every `Use` target. XML exports are used only to learn field layout and verify names—the runtime values and references always come from the selected SQL base. - `CommonCommand`, `SettingsStorage`, and `Subsystem` also have dedicated SQL-only property decoders. Common commands expose their public command group (including standard platform groups), parameter type, and a ready command-module read selector. Settings storages expose all four default and auxiliary save/load form roles plus every owned form; every physical module stream is classified as a manager module. Subsystems expose use/help/command interface flags, picture, content, child subsystems, and references decoded from the separate command-interface SQL part. - A normal `metadata.objects.list` request validates a kind-specific cache hit against the current configuration-root object count. If a root-discovered kind is only partially represented in the local metadata cache, the adapter ignores that cache hit and returns the authoritative live SQL list. This prevents a partial `DBNames` cache from hiding root-only objects such as settings storages. The check and fallback are read-only for the 1C database. - `Language`, `CommonPicture`, `Style`, and `StyleItem` are decoded from live SQL as first-class metadata. Languages expose their language code. Common pictures expose choice/appearance flags and a bounded binary summary from their `.0` part (format, byte count, and hash) without returning unbounded binary data. Recognized formats include PNG, JPEG, GIF, BMP, ICO, SVG, and zipped 1C picture packages. Styles expose every value from the separate style table; style items decode absolute/web/standard colors, font attributes, and borders. Unknown platform codes remain explicit with `status=unknown_code`. - `XDTOPackage` reads its live `.0` XML payload and returns namespace/form settings, imports, object/value types, nested anonymous type definitions, properties, constraints, and enumeration values. `WSReference` reads the location and generated manager identifiers from its main payload, then decodes the `.0` stream container into WSDL and XSD. The public result links messages, port-type operations, SOAP actions, bindings, services, ports, addresses, schemas, types, elements, restrictions, and enumerations. XML files exported by Configurator are not used at runtime. - `ExternalDataSource` is decoded from the live SQL `Config` hierarchy. The source returns its tables, cubes, and functions; each table has a public name-based ref, its `NameInDataSource`, key fields, and the complete field collection with SQL name, 1C value type, `ReadOnly`, and `AllowNull`. Primitive number, string, date, boolean, and binary (`R`) patterns are decoded without consulting the Configurator export. Child payloads are read in one batch. The adapter only describes connection metadata and never opens or changes the external system itself. Live `upo_test` validation decoded 30 tables, 733/733 typed fields, and 53 key-field links; this base contains no cubes or functions. - A top-level `CommonTemplate.` is a direct template selector for `metadata.object.template.details`, `templates.read`, `templates.analyze`, and `templates.map`. It is resolved internally to the Config GUID and its payload parts, while the public response preserves the `CommonTemplate` name and ref. This is distinct from a template nested under another metadata object and no longer returns an empty template collection. - `DefinedType.` is decoded completely from its live SQL `Config` payload. `metadata.object.special.details` returns the identity, comment, union value type, and every constituent type. Generated platform types are resolved internally to their owning metadata object, including business process object/ref/selection/list/route-point variants and constant value managers. A full `upo_test` audit read all 612 payloads and resolved all 1,943 unique type GUIDs across 6,241 type references; no unresolved type remained. - `SelectionCriterion.` returns its value type, standard-command flag, default forms, list presentation, and complete metadata content collection. Content GUIDs are translated to public name-based refs. Live validation decoded all 11 criteria and resolved 862/862 content references. - `Enum.` returns its identity, comment, standard-command and quick-choice settings, choice mode, and ordered values with public refs. Multilingual and empty-synonym identities are supported. Live validation decoded 1,226 enums and 9,380/9,380 values. - `metadata.object.modules`, `modules.read`, and `code.read` support `WebService`, `HTTPService`, and `IntegrationService`. Service Config parts can contain both the complete BSL module and a short repeated fragment; the adapter selects the largest canonical BSL stream and exposes one public module as `Модуль Web-сервиса`, `Модуль HTTP-сервиса`, or `Модуль сервиса интеграции`. Handler names decoded by `metadata.object.properties` can therefore be followed directly into their live SQL module routines. - The same module APIs expose the four configuration-level modules through the public `Configuration.` selector: ordinary application, external connection, managed application, and session. Runtime discovery reads the embedded Configuration identity GUID from the current SQL root descriptor and maps its `.0`, `.5`, `.6`, and `.7` parts internally. An intentionally empty external-connection module is returned as an empty module instead of being treated as missing. XML is not consulted at runtime. - `CommonModule.` 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. - For `Role`, `metadata.object.properties` reads the separate SQL part `.0` and returns `set_for_new_objects`, `set_for_attributes_by_default`, `independent_rights_of_child_objects`, object and child-object rights, per-right RLS conditions, and full restriction templates. Standard right GUIDs are translated to public 1C names; unrecognized platform GUIDs remain visible with `status=unknown_right_guid` instead of being silently discarded. Permission targets are resolved to public names even when the target is nested and has no standalone `Config` file: `_Fld`/`_VT` routes are joined through the read-only SQL schema to their parent object, object commands are found in the parent's SQL `Config` payload, and integration channels are matched to the decoded `IntegrationService` channel list. The resulting refs use public paths such as `Catalog..Attribute.`, `DataProcessor..Command.`, and `IntegrationService..Channel.`. These decoded identities may be cached only in the adapter's local save index; the live 1C SQL database is never modified. - For `DocumentJournal`, pass `include_column_types=true` to resolve every public column type through the referenced document attributes. This is a supported deep read, not an undecoded property; prefer `adapter.job.start` because large journals may require a long metadata scan. - `data.virtual` supports `СрезПоследних`/`СрезПервых` for periodic information registers and `Остатки`/`Обороты`/`ОстаткиИОбороты` for accumulation registers. Exact dimension values are passed in `filters`. At least one dimension filter is required by default; an intentional broad query must set `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. - 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 not be used with `extension`; extension-scoped queries such as `test2` must use `extension.objects.find` or `metadata.definition.find` with `extension`. - `extension.objects.find`: lists extension objects from the current working programming view by default. `state=working` overlays saved rows from `ConfigCASSave` over applied extension rows; saved-only objects are returned too. Results carry `activation_state`: `active`, `saved_override`, or `saved_only`. - `metadata.definition.find`: resolves public names and references such as `Обработка.` or `Document.`. When exactly one metadata object is found, it is promoted to top-level `object`; `related_selectors` lists the next safe calls allowed by the object's capabilities, including card/full reads and scoped `code.search`/`modules.search` selectors for module-capable objects. These related selectors include `ref` when the object kind and name are known. - `modules.search`: searches decoded BSL and returns matches with `read_selector.method="modules.read"`. The selector may contain an opaque `module_ref`; pass it through unchanged. When the owner is resolved, the same selector also includes the public owner fields such as `kind`, `name`, `guid`, and `ref`. For extension programming, `state=working` is the default and searches `ConfigCASSave` first, including saved-only form/module payloads that are not applied yet. Use `state=active` only when intentionally checking the applied extension; use `full_scan=true` only for broad active `ConfigCAS` fallback scans. - `modules.read`: reads a module by public object selector or opaque `module_ref`. Public responses include `origin` layer evidence even when the owner object is not fully recovered: `Config` means applied configuration, `ConfigSave` means base saved state, `ConfigCASSave` means saved state that still needs owner/layer evidence for base-vs-extension choice, and unresolved `ConfigCAS` means `cas_reference` with `write_surface=requires_owner_resolution`. - `code.search`: agent-facing search wrapper. Items contain `read_selector.method="code.read"` and can be read directly by `code.read`. If `modules.search` resolved the owner, `code.search` preserves the owner selector fields while changing the read method to `code.read`. Scoped calls may pass `module_ordinal` together with `ref`/`kind`/`name`/`guid`; the response must stay a public `onec_code_search.v1` object. Items also carry public `origin` evidence from `modules.search`, so the agent can see base, saved-state, extension, or unresolved CAS provenance before reading the full code fragment. `state` is passed through to `modules.search`; the MCP `source_state=working` policy maps to this `state=working` mode. - `code.read`: wraps module/routine reads for agent-facing code analysis. It may set `source.kind=code_read`, but it must preserve the module `origin` 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. - 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 rather than inferred from collection position alone. Generate a reproducible live coverage matrix without putting adapter or SQL credentials in a file: ```text python scripts/audit_1c_adapter_coverage.py --base-id upo_test --output reports/1c-adapter-coverage.json ``` The script reads the adapter bearer token from `ONEC_ADAPTER_TOKEN` and never reads or prints the SQL password. For a resumable read-only application-data audit, run the full public chain for one object of every data-bearing metadata kind: ```text python scripts/audit_1c_adapter_coverage.py --base-id upo_test --sample-data-reads --workers 2 --timeout 90 --checkpoint reports/1c-adapter-data-checkpoint.json --output reports/1c-adapter-coverage-live.json ``` The checkpoint is replaced atomically after every completed operation and kind. Resume an interrupted run with `--resume`; add `--retry-degraded` to rerun only timed-out or failed kinds while retaining successful evidence. Each data check records durations and statuses for `data.schema`, `data.list`, `data.count`, and `data.get` when the sampled row has a public reference key. Register rows with no reference key report `data.get=not_applicable` rather than a false failure. An XML export can be used as an independent property-schema reference. The analyzer keeps the base configuration and each extension as separate layers: ```text python scripts/analyze_1c_xml_metadata.py --include-artifacts --output reports/1c-xml-metadata-analysis.json ``` Owner resolution: - Search results distinguish module readability from owner resolution. A module can be readable through `read_selector` even when `owner.status=unresolved`. - Use `counts.owner_resolved`, `counts.owner_unresolved`, `counts.owner_scan_limit_hit`, and `diagnostics.owner_resolution` to decide whether to narrow the selector or increase `owner_scan_limit`. - Do not request `include_storage=true` only to read a found module; use the public `read_selector` first. Working source state: - For programming/designer analysis, agents must query the latest saved working state first. In MCP calls this is `source_state=working`; the MCP bridge maps it to REST `state=working` for `extension.objects.find`, `modules.search`, `code.search`, and `metadata.resolve_overrides`. - `source_state=applied` maps to REST `state=active` and intentionally ignores saved rows. Use it only when checking what is already applied. - `source_state=all` maps to REST `state=both` for side-by-side inspection. The response keeps `activation_state` markers such as `saved_only`, `saved_override`, and `active`, so agents can tell which findings are not applied yet. - `code.read state=both` reads the saved layer and the active layer as two independent views. The response sets `current_state.source=both`, returns ordered `layers` entries for `saved_state` and `active`, and includes `comparison.both_present` plus `comparison.differs`. When `include_text=true`, top-level `text` is the effective programming text: saved-state text if it exists, otherwise active text. `text_source` names the layer used. - `code.search state=both` also returns a mixed view for saved CommonForm code: saved-state matches are listed first, active matches are fetched with an independent `state=active` pass, and `counts.saved_matches` / `counts.active_matches` show layer coverage. - If an extension object exists only in `ConfigCASSave`, it is still part of the working programming surface. Analysis and write planning must not discard it just because activation has not happened yet. Smoke check: ```text python scripts/smoke_1c_mcp_selector_chain.py --json ``` This offline smoke validates generic MCP selector chains such as `metadata.definition.find -> related_selectors.code_search -> code.search -> item.read_selector -> code.read`. Examples use placeholders only and must not contain concrete configuration object names. Optional live smoke: ```text python scripts/smoke_1c_mcp_selector_chain.py --live --transport rest --adapter-url <1c-rest-adapter-url> --base-id --json ``` To run the same live chain through the MCP proxy instead of direct REST `/rpc`, use: ```text python scripts/smoke_1c_mcp_selector_chain.py --live --transport mcp --mcp-url <1c-mcp-proxy-url> --base-id --json ``` The live mode discovers a module-capable metadata object through `metadata.objects.list`, verifies `metadata.definition.find` related selectors, reads the first module through `modules.read` using the returned selector, then derives a search token from module text or routine metadata and verifies `code.search -> item.read_selector -> code.read`. It does not hard-code object names or BSL fragments, and it passes object selectors through instead of reconstructing them from display text. MCP transport performs the same calls through `initialize`, `Mcp-Session-Id`, and `tools/call` + `onec_request`. ## Question Routing Command: ```text python scripts/route_1c_question.py --text --index --view effective|base ``` Safe Unicode command shape: ```text python scripts/route_1c_question.py --text-b64 --index ``` Output schema: ```text onec_question_route.v1 ``` Purpose: - classify a user question before tools are selected; - route documentation questions to official-docs RAG; - route concrete configuration facts to the fact resolver; - detect source-risk phrases such as "in the RAG example" and require current configuration confirmation before code generation; - extract explicit facts such as `Справочник.Номенклатура.Артикул` and phrased facts such as "реквизит Артикул у справочника Номенклатура". Routes: - `docs_rag`: only official documentation context is needed. - `current_config_fact`: current configuration facts are needed before answer or code. - `mixed_docs_and_current_config`: use official docs for platform behavior, but confirm object/member facts through the adapter first. - `needs_clarification`: neither docs nor current-config target was clear. Contract check: ```text python scripts/check_1c_question_router.py --index --output reports/1c-question-router.json ``` ## Agent Intake Command: ```text python scripts/build_1c_agent_intake.py --text --index --view effective|base ``` Output schema: ```text onec_agent_intake.v1 ``` Purpose: - create the first packet an agent should inspect before answering or writing code; - include the question route, source policy, confirmed/unresolved current-base facts, answer/code policy, and next tool commands; - make the "example is not current fact" rule machine-readable through `source_policy.examples_are_current_facts=false`; - set `answer_policy.code_generation_allowed=false` when required current facts are missing or not checked. HTTP console API: ```text POST /api/1c/intake { "question": "...", "source_path": "reports/1c-sql/upo/unified-object-route-index.json", "view": "effective" } ``` ## Saved State Object Compare Command: ```text powershell -NoProfile -ExecutionPolicy Bypass -File scripts/compare_1c_saved_state_objects.ps1 -Server -Database -User -Password -Output ``` Normal agent command: ```text powershell -NoProfile -ExecutionPolicy Bypass -File scripts/build_1c_saved_state_object_report.ps1 -Server -Database -User -Password -OutputDir [-SkipMarkdown] ``` Repeated observation command: ```text powershell -NoProfile -ExecutionPolicy Bypass -File scripts/watch_1c_saved_state_once.ps1 -Server -Database -User -Password -OutputRoot python scripts/list_1c_saved_state_watch_runs.py --root [--limit ] [--only-with-delta] [--only-changed] --output [--skip-markdown] [--skip-check] python scripts/check_1c_saved_state_watch_run_list.py --list --output python scripts/get_1c_saved_state_latest_watch_run.py --root [--require-delta] [--require-changed] --output [--skip-markdown] [--skip-check] python scripts/check_1c_saved_state_latest_watch_run.py --latest --output python scripts/render_1c_saved_state_latest_watch_run_markdown.py --latest --output python scripts/render_1c_saved_state_watch_run_list_markdown.py --list --output ``` Markdown rendering: ```text python scripts/render_1c_saved_state_object_report_markdown.py --report --output ``` Contract check: ```text python scripts/check_1c_saved_state_object_report.py --report --output python scripts/check_1c_saved_state_watch_once.py --manifest --output python scripts/render_1c_saved_state_watch_once_markdown.py --manifest --output ``` Report-to-report delta: ```text python scripts/compare_1c_saved_state_object_reports.py --before --after --output [--skip-markdown] [--skip-check] ``` ```text python scripts/check_1c_saved_state_object_report_delta.py --delta --output python scripts/render_1c_saved_state_object_report_delta_markdown.py --delta --output ``` Object change lookup: ```text python scripts/list_1c_saved_state_object_changes.py --report [--layer base|extension] [--kind ] [--payload-role ] [--active-missing true|false] [--text-diff true|false] --output ``` ```text python scripts/get_1c_saved_state_object_change.py --report --name --output ``` Output schema: ```text onec_saved_state_object_comparison.v1 onec_saved_state_object_detail.v1 onec_saved_state_object_report.v1 onec_saved_state_object_report_check.v1 onec_saved_state_watch_once.v1 onec_saved_state_watch_once_check.v1 onec_saved_state_watch_run_list.v1 onec_saved_state_watch_run_list_check.v1 onec_saved_state_latest_watch_run.v1 onec_saved_state_latest_watch_run_check.v1 onec_saved_state_object_report_delta.v1 onec_saved_state_object_report_delta_check.v1 onec_saved_state_object_change_list.v1 onec_saved_state_object_change.v1 ``` Purpose: - compare saved-but-not-applied SQL state with active state in 1C object terms; - provide a single read-only report command that runs comparison, exports the required payload evidence, performs object detail analysis, and writes a Markdown summary by default; - provide a one-shot watch command that stores timestamped observations and compares the new observation with the previous one when available; it writes a Markdown watch summary by default unless `-SkipMarkdown` is used; - list timestamped watch observations without reading SQL, including latest run, linked artifacts, check statuses, and delta counts; write Markdown next to the run-list JSON by default and run a contract check when `--output` is used; - return the latest matching watch observation directly, with optional requirements for a delta or actual delta changes; run a contract check by default and write Markdown when `--output` is used; - include `agent_summary` in `onec_saved_state_object_report.v1` so agents can see changed 1C object names, changed payload parts, active-missing part counts, payload roles, and short semantic term hints without parsing Markdown or full detail payloads; - compare `ConfigSave` with `Config` and `ConfigCASSave` with `ConfigCAS`; - return `object_changes` as configurator objects such as `ОбщийМодуль.HttpBridgeКлиент` or extension forms; - keep `FileName`, byte sizes, and hashes under storage evidence; - keep `root`, `versions`, and extension `configinfo` under `system_changes`. - optionally analyze changed object payloads for text deltas, added/removed words, and saved form/module string samples. - when extension manifest summary and active `ConfigCAS` export are provided, detail analysis resolves extension saved parts to active CAS keys before comparing payloads. - render the JSON report as compact Markdown for human review while keeping 1C configurator names first and SQL storage names as evidence. - classify changed payload parts with roles such as `bsl_module_text`, `form_descriptor`, `form_body`, `primary_payload`, or `metadata_payload`; - keep raw word diffs in detail evidence, but expose filtered `semantic_hints.added_terms` and `semantic_hints.removed_terms` for agent triage. - validate each generated report with a final read-only contract check before treating it as reliable agent input. - compare two saved-state report observations by 1C object name and stable payload-part fingerprints when the user continues editing between checks; write Markdown and a contract-check JSON next to the delta JSON by default when `--output` is used. - support object-level lookup from a saved-state report by full name, short configurator name, synonym, suffix, or contains match; ambiguous matches must return candidates rather than selecting one silently. - support compact changed-object listing and filtering by layer, kind, extension, payload role, text diff presence, and missing active counterpart. ## Object Context Search Command: ```text python scripts/search_1c_object_context.py --index --kind --name --text --view effective|base|extension --extension --search-code --max-form-items --limit --output ``` Output schema: ```text onec_object_context_search.v1 ``` Purpose: - search one resolved object by human/configurator terms; - search metadata attributes, tabular section names, forms, form items, form attributes, form commands, form events, module names, and optionally BSL code lines; - keep origin/effective action evidence so matches from extensions are not confused with base configuration matches; - return file paths and line snippets for code hits, allowing the agent to follow up with `get_1c_module.py --routine` or module snippet reads. ## Task Context Plan Command: ```text python scripts/plan_1c_task_context.py --index --text --view effective --max-objects --max-terms --max-matches --output ``` Output schema: ```text onec_task_context_plan.v1 ``` Purpose: - turn a user task into a read-only investigation plan; - find likely metadata object candidates by configurator-visible object names and synonyms, using kind hints such as "document" or "catalog"; - for each candidate, gather brief context and search the object for task terms across metadata, forms, commands, events, modules, and BSL code; - produce recommended follow-up reads such as object metadata, form context, and exact module reads; - keep write support explicitly blocked by `docs/1c-write-path-safety.md`. ## Task Evidence Bundle Command: ```text python scripts/build_1c_task_evidence.py --index --text --view effective --max-objects --max-module-chars --code-snippet-radius --max-code-snippets --output ``` Output schema: ```text onec_task_evidence_bundle.v1 ``` Purpose: - materialize the read-only task plan into a compact evidence bundle for code generation or human review; - include full effective metadata summaries, selected form contexts, selected module snippets, and targeted code snippets around search hit lines; - preserve base/extension origin, file paths, form XML paths, module paths, and line numbers; - keep large files bounded by explicit limits while retaining focused evidence for relevant code found deep inside large modules. ## Task Change Proposal Command: ```text python scripts/propose_1c_task_changes.py --evidence --output ``` Output schema: ```text onec_task_change_proposal.v1 ``` Purpose: - turn a read-only evidence bundle into a structured implementation proposal; - infer broad task intents such as form command, attribute, lifecycle, or inspection; - separate extension-first write candidates from base/read-only reference files; - identify existing form commands/items, metadata attributes, and related code hits before any patch is generated; - use full 1C paths as change targets, and keep local names only when they are bound to a concrete object, form, module, routine, or symbol context; - keep the proposal under the write safety contract: no SQL/Config writes and no automatic production update/apply. Markdown rendering: ```text python scripts/render_1c_task_proposal_markdown.py --proposal --output ``` The Markdown report is for human review and should mirror the JSON proposal, not replace it as machine-readable evidence. Safety check: ```text python scripts/check_1c_change_proposal_safety.py --proposal --output ``` Output schema: ```text onec_change_proposal_safety_check.v1 ``` Purpose: - gate future patch generation on machine-checkable safety rules; - require write candidates to live in the preferred extension origin and path; - verify candidate/reference paths exist; - reject direct SQL/Config/ConfigSave/ConfigCAS write targets; - preserve the required gates that still block real write/apply operations. ## Patch Workspace Command: ```text python scripts/create_1c_patch_workspace.py --proposal --output-root --slug --output ``` Output schemas: ```text onec_patch_workspace_creation.v1 onec_patch_workspace_manifest.v1 ``` Purpose: - create a safe local workspace for future generated edits; - run the proposal safety check before copying anything; - copy only extension write candidates into `original/` and `working/`; - keep `proposal.json`, `safety.json`, `manifest.json`, and `README.md` beside the copies; - require edits to happen only under `working/`. Diff command: ```text python scripts/check_1c_patch_workspace_integrity.py --workspace --output python scripts/check_1c_patch_source_freshness.py --workspace --output python scripts/validate_1c_patch_workspace_semantics.py --workspace --output python scripts/edit_1c_bsl_routine.py --workspace --relative-path --operation append|replace|upsert --routine-text-b64 [--keep-on-failure] --output python scripts/edit_1c_form_command.py --workspace --relative-path --operation append|replace|upsert --name --title --action [--tooltip ] [--id ] [--keep-on-failure] --output python scripts/edit_1c_form_button.py --workspace --relative-path --operation append|replace|upsert --parent-name --name --title --command-name [--id ] [--keep-on-failure] --output python scripts/add_1c_form_button_workflow.py --workspace --form-relative-path --bsl-relative-path --operation append|replace|upsert --routine-text-b64 --command-name --command-title --command-action --button-parent-name --button-name --button-title [--keep-on-failure] --output python scripts/diff_1c_patch_workspace.py --workspace --output python scripts/create_1c_patch_bundle.py --workspace --output-root --slug --output python scripts/check_1c_patch_bundle.py --bundle-dir [--zip ] --output python scripts/create_1c_extension_staging_from_bundle.py --bundle-dir --output-root --slug --output python scripts/check_1c_extension_staging.py --staging-dir --output python scripts/check_1c_extension_runner_config.py --config --output python scripts/create_1c_extension_validation_plan.py --staging-dir [--runner-config ] --output --markdown-output python scripts/create_1c_extension_validation_evidence.py --plan [--output-root ] --output python scripts/check_1c_extension_validation_evidence.py --plan [--evidence-root ] --output python scripts/check_1c_extension_validation_release.py --plan [--evidence-root ] --output python scripts/render_1c_extension_validation_release_markdown.py --release-check --output python scripts/check_1c_patch_preflight.py --workspace --output python scripts/render_1c_patch_preflight_markdown.py --preflight --output ``` Output schema: ```text onec_patch_workspace_integrity.v1 onec_patch_source_freshness.v1 onec_patch_workspace_semantic_validation.v1 onec_bsl_routine_edit.v1 onec_form_command_edit.v1 onec_form_button_edit.v1 onec_form_button_workflow.v1 onec_patch_workspace_diff.v1 onec_patch_bundle.v1 onec_patch_bundle_creation.v1 onec_patch_bundle_check.v1 onec_extension_staging.v1 onec_extension_staging_creation.v1 onec_extension_staging_check.v1 onec_extension_runner_config_check.v1 onec_extension_validation_plan.v1 onec_extension_validation_evidence_manifest.v1 onec_extension_validation_evidence_check.v1 onec_extension_validation_release_check.v1 onec_patch_preflight.v1 ``` Purpose: - verify `original/` hashes still match the manifest before any diff/package step; - verify source extension files still match the hashes recorded when the patch workspace was created, so stale patches cannot overwrite newer source files; - verify every manifest file exists under both `original/` and `working/`; - flag unexpected files under `original/` as errors and unexpected files under `working/` as warnings; - validate edited workspace semantics before review: parse `Form.xml`, parse BSL routines, reject duplicate routines/commands, check basic BSL block balance, and verify form command actions have matching form-module routines when both files are in the workspace; - edit one BSL procedure/function under `working/` through a manifest-bound operation: append a new routine, replace an existing routine, or upsert one routine; the command validates the full workspace semantics after writing and rolls the file back by default when validation fails; - edit one form command under `working/` through a manifest-bound operation: append a new ``, replace an existing command, or upsert one command; the command chooses a safe numeric id when omitted, validates the full workspace semantics after writing, and rolls the file back by default when validation fails; - edit one visible form button under `working/` through a manifest-bound operation: append/replace/upsert one `