212 lines
9.4 KiB
Markdown
212 lines
9.4 KiB
Markdown
# 1C Agent Coding Contract
|
||
|
||
This contract is the default rule set for coding agents that work through the
|
||
1C adapter. The agent calls it only through the `onec_request` MCP tool; the
|
||
REST SQL adapter is MCP's private downstream transport.
|
||
|
||
## Default View
|
||
|
||
- Read current code and metadata from the working saved-state layer by default.
|
||
- For REST calls, use `state=working`.
|
||
- For MCP calls, use `source_state=working`.
|
||
- Treat saved-state objects as current programming state even when they are not
|
||
activated yet.
|
||
- Objects can exist only in saved-state and can later be activated or canceled.
|
||
Do not hide them from the agent view.
|
||
|
||
### Empty saved-state layer
|
||
|
||
An empty saved-state layer is normal before the first edit. In that case an
|
||
agent still uses only public selectors and reports the adapter result; it must
|
||
not obtain an active `ConfigCAS`/`Config` module reference and retry by hand.
|
||
|
||
Known adapter limitation (2026-08-02): for an extension-owned object module
|
||
with no prepared saved-state row, public `code.read` can return
|
||
`source_missing` even though the active module is proven to exist. Treat this
|
||
as an adapter defect, not as evidence that the 1C object or BSL is absent.
|
||
Use a developer-owned diagnostic check to investigate it; do not expose its
|
||
storage coordinates to a coding agent.
|
||
|
||
## Required adapter acceptance fixture
|
||
|
||
`upo_test` must contain one isolated extension-owned `Report` with a decoded
|
||
`object_module`, a unique BSL anchor, and no shared business role. This fixture
|
||
is created and maintained by a human in Configurator; the SQL-only adapter must
|
||
not fabricate it. It is the required target for the public acceptance sequence:
|
||
|
||
```text
|
||
code.read(ref, extension, module_ordinal=1)
|
||
→ code.write(old, new, apply_and_rollback)
|
||
→ code.search verifies new text
|
||
→ rollback and saved-state cleanup
|
||
```
|
||
|
||
The request must contain no `layer`, table, file name, module ref, payload hash,
|
||
or stream index. Until the fixture exists, unit tests prove routing only; they
|
||
do not prove a live extension Report write.
|
||
|
||
### Verified base-module smoke
|
||
|
||
On 2026-08-02 the public sequence was verified on `upo_test` against base
|
||
`Report.АвтоматическиеСкидки`, `module_ordinal=1`: a unique comment replacement
|
||
completed in about 25 seconds with `verified_and_rolled_back`. The adapter
|
||
auto-prepared `ConfigSave`, read back the write, rolled back the BSL change,
|
||
then removed the exact rows it had prepared. The public result contains the
|
||
opaque `prepare_receipt_id` and `prepare_cleanup`; the final saved-state status
|
||
was `empty`. This validates the base route only, not the extension Report route.
|
||
Live check on 2026-08-02 found 19 extensions but zero extension-owned Reports
|
||
in `upo_test`; therefore the required extension acceptance fixture is currently
|
||
missing and the extension write branch remains unaccepted.
|
||
|
||
Live check on 2026-08-13 found an extension BSL stream for
|
||
`Report.УОП_ИнвентаризационнаяОпись`, but its `role_status=unconfirmed`.
|
||
That is read-only evidence, not an acceptance fixture: do not write through an
|
||
ordinal, storage reference, or guessed Configurator role. A human must add or
|
||
identify one extension Report with a decoded `object_module` before the live
|
||
extension `apply_and_rollback` test can run.
|
||
|
||
## Compare Views
|
||
|
||
- Use `state=both` or `source_state=all` only when the task needs a comparison
|
||
with activated runtime state.
|
||
- Show the effective working text first.
|
||
- Mark comparison details explicitly:
|
||
- `saved_state`: saved and not activated;
|
||
- `active`: activated runtime state;
|
||
- `text_source`: which layer produced the returned text;
|
||
- `comparison.differs`: whether both layers exist and differ.
|
||
|
||
## Read Workflow
|
||
|
||
Use public names and selectors:
|
||
|
||
1. `extension.objects.find` with `state=working` to find extension objects.
|
||
2. `code.search` with `state=working` to find routines or fragments.
|
||
3. `code.read` with `state=working` to read the module or routine.
|
||
4. `code.read` with `state=both` only for an explicit saved-vs-active check.
|
||
|
||
For a report form, keep the descriptions separate:
|
||
|
||
1. `metadata.object.forms(ref=Report.<name>, source_state=working)` lists the
|
||
report's form references.
|
||
2. `metadata.object.form.details` with that same public report ref and the
|
||
returned form name reads the form description (attributes, parameters,
|
||
commands, items, and the form module).
|
||
3. `metadata.form.decode(view=structure)` is an optional compact static
|
||
projection. It must retain `unresolved` parent/child links where no SQL
|
||
codec has proved them.
|
||
|
||
A form command does not have its own module. Its handler is a named routine in
|
||
the form module only when the decoder returns an evidenced command link.
|
||
|
||
Use the `read_selector.selector_token` returned by discovery with the method
|
||
declared in that selector. Do not copy GUIDs, module refs, table names, or file
|
||
names into a follow-up request. A module ordinal, display name, or storage-derived role
|
||
is not a Configurator-tree path. If a result has `role_status=unconfirmed` or
|
||
`configurator_path_status=unconfirmed`, the agent must not name, write, or
|
||
infer its tree owner; report the missing decoder evidence instead.
|
||
|
||
When checking object commands, call `metadata.object.commands` with the same
|
||
public `ref`/`kind`+`name` and `extension` selector. The adapter resolves the
|
||
extension name and reads its active metadata itself. A prior `not_found` from a
|
||
route that did not carry the extension context is not evidence that the report
|
||
has no commands. Conversely, a BSL stream suffix alone is never evidence of a
|
||
command or of its module path.
|
||
|
||
Agents should ask for and report object names, routine names, and code text.
|
||
They should not ask users for SQL tables, storage file names, stream indexes, or
|
||
saved-state write flags during normal coding work.
|
||
|
||
## Write Workflow
|
||
|
||
All normal BSL writes go through `code.write`.
|
||
|
||
Supported public edit shapes:
|
||
|
||
- replace a whole module with `module_text`, `full_text`, or `code`;
|
||
- replace one procedure or function with `routine_name` and `routine_text`;
|
||
- replace one unique fragment with `old` and `new`; when `routine_name` is
|
||
supplied, the adapter scopes the replacement to that routine.
|
||
|
||
`code.write` saves into saved-state automatically. A coding agent should simply
|
||
say "save this code" and send the desired code text. It must not ask whether SQL
|
||
saved-state apply flags are allowed.
|
||
|
||
For extension object modules, preparation maps the active payload route to its
|
||
canonical saved-state filename internally. A public `code.write` therefore
|
||
continues with `extension`, `ref`, module role, and the proven replacement
|
||
only; it must never ask the caller to supply the canonical filename or stream.
|
||
|
||
Every successful `code.write` response must show:
|
||
|
||
- `write_mode.target=saved_state`;
|
||
- `write_mode.activation_state=not_activated`;
|
||
- `write_mode.production_apply=false`.
|
||
|
||
### Repository-controlled extension writes
|
||
|
||
For a repository-controlled extension, use the public sequence below and stop
|
||
when it asks for a human Configurator action:
|
||
|
||
```text
|
||
code.search(extension, ref, old fragment)
|
||
→ repository.lock.plan(extension, ref)
|
||
→ repository.lock.request
|
||
→ human captures the exact object in Configurator
|
||
→ repository.lock.confirm
|
||
→ code.write(extension, ref, module_ordinal, old, new, repository_lock)
|
||
→ code.search readback
|
||
```
|
||
|
||
The lock plan for `upo / фс_Отчеты1 /
|
||
Report.фс_ПродовольственнаяКорзина` resolves exactly one object:
|
||
`Отчет.фс_ПродовольственнаяКорзина`, in extension layer
|
||
`extension:8e02accd-8a34-11f1-8294-005056b0d483`. SQL cannot prove a native
|
||
Configurator capture; only a human confirmation can continue this route.
|
||
|
||
`metadata.write.preflight` currently plans canonical high-level
|
||
`metadata.write` targets and may return `needs_route` for this compatibility
|
||
`code.write` shape before saved-state preparation. This is not permission to
|
||
use its low-level payload hint. Use `code.write(mode=plan)` instead: a first
|
||
extension edit may return public `needs_prepare`, which means to confirm the
|
||
repository lock and reissue the same public request in an apply mode. Keep
|
||
using the public `code.write` route; report any different route failure to
|
||
adapter developers.
|
||
|
||
If it returns `extension_saved_state_prepare_protocol_unproven`, do not retry
|
||
or supply technical coordinates. The adapter has not yet proven the exact
|
||
saved-state preparation codec for this extension layout; report it for adapter
|
||
development. Do not infer that the extension was not saved in Configurator.
|
||
|
||
## Hidden Storage Details
|
||
|
||
The form module container marker `///----` is adapter-owned storage syntax.
|
||
Public `code.read` and `code.search` responses must not expose it as BSL.
|
||
Full-module writes must preserve the marker internally when the saved form
|
||
payload requires it.
|
||
|
||
Low-level methods such as `metadata.module.write_apply`, `metadata.write`, SQL
|
||
tables, stream refs, and saved-state apply flags are diagnostic tools. They are
|
||
not the default programming interface for agents.
|
||
|
||
## Agent Response Shape
|
||
|
||
When reporting a working saved-state result to a user, prefer concise wording:
|
||
|
||
```text
|
||
В working/save вижу формы:
|
||
t_Форма
|
||
tt_Форма3
|
||
ФормаЭлемента
|
||
|
||
Код читается из saved_state, еще не активирован.
|
||
```
|
||
|
||
If the user asks to compare active and saved state:
|
||
|
||
```text
|
||
Working/save: найдено, источник saved_state, не активировано.
|
||
Active: не найдено.
|
||
Эффективный код для программирования сейчас берется из saved_state.
|
||
```
|