Files
llm/docs/1c-extension-layer-plan.md
T

299 lines
14 KiB
Markdown

# 1C Extension Layer Plan
Status: active work plan.
This plan defines how the 1C adapter and agent must handle extensions, full
1C paths, effective reads, provenance, and safe writes.
## Core Principles
The adapter has two responsibilities that must not be merged:
- return the effective picture that the 1C runtime and Configurator see after
applying active extensions;
- keep editor provenance so every change can be routed to the correct layer:
base configuration, a concrete extension, or a saved-state working copy.
Agent-facing APIs use 1C names and full paths. GUIDs, SQL table names, CAS
keys, and payload offsets are storage evidence, not the everyday language of
the agent.
## Addressing Model
The default address format is a full semantic 1C path:
```text
<ObjectKind>.<ObjectName>[.<Section>.<Member>...]
```
Examples:
```text
Справочник.Контрагенты
Справочник.Контрагенты.Наименование
Документ.РеализацияТоваровУслуг.Товары.Номенклатура
РегистрСведений.ЦеныНоменклатуры.Измерения.Номенклатура
РегистрСведений.ЦеныНоменклатуры.Ресурсы.Цена
Документ.РеализацияТоваровУслуг.Форма.ФормаДокумента.Товары
ОбщийМодуль.ИнтеграцияСCRM.ОтправитьКонтрагента
```
Short names are input conveniences only. Before analysis or writing, the agent
must normalize them to a single full path or return candidate paths when the
name is ambiguous.
There are three allowed address levels:
- `canonical_path`: full 1C path, safe for reads and write planning;
- `context_path`: shortened path valid only inside a known object, form, module,
tabular section, or routine;
- `local_name`: local BSL symbol or local form item name, never enough for a
cross-object write by itself.
The adapter must keep metadata path resolution separate from code symbol
resolution. In BSL, `Номенклатура.ЕдИзмерения.Код` may start from a variable,
form attribute, object attribute, tabular-section column, query field, or
procedure parameter. It must not be silently treated as
`Справочник.Номенклатура`.
## Layer Views
Every read API that can be affected by extensions should support these views:
- `base`: only the main configuration;
- `extension`: only one selected extension;
- `effective`: the runtime/configurator picture after applying active
extensions;
- `origin`: provenance of effective members and code fragments;
- `diff`: semantic differences between base and one or more extensions.
The effective view is the default for agent investigation. It is incomplete for
writing unless paired with origin and write-target evidence.
## Extension Provenance
For every metadata object, member, form, module, routine, command, and event
handler, responses should expose:
- `canonical_path`;
- `presentation` and synonym when known;
- `created_in`;
- `modified_by`;
- `effective_owner`;
- `active_extensions`;
- `extension_order`;
- `conflicts`;
- `storage_evidence` for debug/expert mode.
Extension changes must be classified semantically:
- object added by extension;
- base object adopted/extended by extension;
- attribute/tabular section/form/command/event added;
- property changed;
- module added;
- routine added;
- code inserted before;
- code inserted after;
- code replaced;
- code replaced with control.
For `replace_with_control`, the adapter must expose the controlled base
fragment and report whether it still matches the current base/effective source.
## Write Planning
Writes must start with a plan. The agent may read effective text, but must not
write effective text directly.
The write planner must answer:
- what full path or symbol is being changed;
- what layer owns the current effective element;
- which layer is the correct write target;
- whether the target is base saved state, extension saved state, generated
extension source, or read-only reference evidence;
- which operation is allowed: add, property change, insert before, insert after,
replace, replace with control, append routine, upsert routine, move form item;
- which guards are required: sha1, controlled fragment, expected old text,
syntax check, extension order, conflict scan;
- which follow-up reads and validation steps must be run.
The first production-safe write path remains extension-first:
```text
generate extension source
-> validate in 1C tooling
-> package extension
-> load into disposable base
-> run smoke tests
-> produce human approval diff
```
Direct active configuration writes remain forbidden.
## Agent Workflow
For concrete 1C tasks, the agent should follow this sequence:
1. Parse the user request and extract likely full paths, short names, and local
symbols.
2. Resolve all metadata paths through the adapter.
3. Read effective context for the selected objects.
4. Read origin/layer evidence before drawing conclusions about ownership.
5. For BSL expressions, resolve local symbols inside the concrete module,
routine, form, or query context.
6. If a change is needed, build a write plan before generating or applying a
patch.
7. Apply only through allowed saved-state, patch-workspace, or extension-source
routes.
8. Re-read effective and origin views.
9. Run semantic diff, BSL syntax checks, saved-state checks, and extension
conflict checks.
10. Report results to the user in full 1C paths, hiding storage ids unless the
user asks for expert evidence.
## Work Plan
1. Finalize the full-path contract in adapter docs and schemas.
2. Extend the resolver model to return `canonical_path`, `context_path`,
ambiguity candidates, and path-kind diagnostics.
3. Add a code symbol resolver that works inside a selected module/routine/form
context and distinguishes variables from metadata paths.
4. Extend object, form, and module reads with consistent origin fields.
5. Add an extension layer inventory that reports active extensions, order,
adopted base objects, added objects, and conflicts.
6. Add routine-level extension action evidence: before, after, replace, and
replace with control.
7. Add a read-only write planner that chooses base saved state, extension saved
state, or generated extension source without applying changes.
8. Wire the planner into `metadata.write` so writes without a resolved
full-path target and layer decision are rejected.
9. Add smoke tests for ambiguous short names, extension-added attributes,
extension-overridden routines, and replace-with-control drift.
10. Add eval cases so the agent learns to answer with full paths and to refuse
unsafe direct effective-text writes.
## First Implementation Slice
The first executable slice should be read-only:
- update `resolve_1c_fact.py` output to include canonical path metadata;
- add path ambiguity tests for object member paths;
- add origin fields to module/routine reads where extension overlays already
exist;
- document a proposed `metadata.write.plan` shape before implementing apply
behavior.
Current progress:
- `resolve_1c_fact.py` returns `canonical_path`, `path_kind`, and tabular
section `context_path` for verified object/member facts.
- `metadata.write.plan` validates full 1C paths and concrete saved-state/module
references without applying changes.
- `metadata.write.plan` infers form/module write intent from canonical path
sections such as `Форма.<FormName>` and `ОбщийМодуль.<Name>.<Routine>`.
- `metadata.write.plan` can call `metadata.definition.find` for compact
`origin_lookup` evidence.
- `metadata.write.plan` reports `ambiguous_origin_matches` when a full path
still resolves to multiple definitions, including same-layer ambiguity such
as object member versus form member.
- `metadata.write.plan` recommends `base_saved_state`, `extension_saved_state`,
`saved_state`, `blocked_unknown`, or `blocked_conflict` from origin evidence.
- `metadata.write.plan` normalizes `preferred_layer` and reports
`preferred_layer_conflict` when a requested base/extension target disagrees
with the origin-derived write recommendation.
- `metadata.write.plan` accepts `preferred_extension` and reports
`preferred_extension_conflict` when the requested extension name/GUID differs
from the resolved extension owner.
- `metadata.write.plan` validates module-code preconditions for
`replace_with_control`, `replace`, and `insert_before`/`insert_after` before
allowing even saved-state plans.
- `metadata.write.plan` normalizes Russian and English operation names into
stable `operation_class` values such as `insert_before`, `insert_after`,
`replace`, and `replace_with_control`.
- `metadata.write.plan` returns `route.apply_payload_hint` for concrete
saved-state module/form routes, so an agent can carry the validated guards
into `metadata.module.write_apply` or form write planning without inventing
field names.
- `metadata.write.plan` also carries selector fields inferred from
`canonical_path` into `route.apply_payload_hint`, including `kind`, `name`,
`form`, `element`, and `routine_name` when known.
- `metadata.write.plan` marks selector-only module/form hints as
`ready_for_apply_method=false` and returns `next_resolution` pointing to the
required saved-state target resolver before apply methods can be called.
- `metadata.write` blocks direct writes to effective `canonical_path` targets
without a concrete saved-state/module route.
- Blocked `metadata.write` responses now surface the plan's `apply_payload_hint`
and `next_resolution` for parsed form/module paths, keeping the next safe
resolver visible without allowing direct writes to the effective view.
- When a concrete saved-state form file or module stream is later provided with
that same full path, `metadata.write` merges missing selector fields from the
plan hint into the low-level apply payload, such as `form`, `element`, and
`routine_name`.
- Concrete references now keep their field identity in write planning and
hints: `module_ref`, `module_id`, `file_name`, and `form_guid` are not
collapsed into each other.
- Write planning rejects incompatible concrete references with
`concrete_reference_kind_mismatch`, so a form selector cannot be used as a
module route or the other way around.
- `resolve_1c_bsl_symbol.py` adds the first conservative code-symbol resolver:
full paths such as `Справочник.Номенклатура.Артикул` resolve as metadata,
context-proven object-module fields resolve as metadata members, but routine
parameters, local variables, and short object names stay BSL symbols until
proven otherwise.
- The live adapter now exposes the same conservative resolver as
`code.symbol.resolve`, backed by `modules.read`, `metadata.definition.find`,
and `metadata.object.attributes`.
- `check_1c_code_symbol_contract.py` verifies the public adapter method through
`call_method`, including that `canonical_path`, `context_path`, and
`safe_as_metadata_path` survive public-result sanitizing.
- `modules.read` now returns fallback public `origin` evidence from the storage
table for direct module references: applied configuration, saved state, or
unresolved CAS reference that requires owner resolution before write planning.
- `check_1c_module_origin_contract.py` verifies that public `modules.read`
and `code.read` responses keep this origin evidence visible without
`include_storage=true`.
- `code.search` items now preserve `origin` from `modules.search`, so the
agent can see provenance before selecting a `read_selector` for `code.read`.
- `metadata.write.plan` now accepts `target.origin`/`origin` from those prior
read/search results and converts it to `provided_origin_evidence`, preserving
layer recommendation while still requiring a concrete write route before
apply.
- `metadata.resolve_overrides` now exposes `extension_action` per routine link:
known evidence is normalized to `insert_before`, `insert_after`, `replace`,
or `replace_with_control`; unresolved extension routine actions are reported
as `unknown_extension_action` so the agent does not silently treat them as a
plain replace.
- `metadata.write.plan` now accepts that `extension_action` evidence directly:
known actions can infer the module operation when the user did not specify
one, unknown actions block planning, and explicit operation/action mismatches
are rejected before any saved-state apply route can run.
- Multi-item `extension_actions` from an override chain now block write
planning as `extension_action_ambiguous`; the agent must narrow to one
extension/module action before generating a patch.
- `metadata.resolve_overrides` now returns `write_plan_evidence`, a ready
`metadata.write.plan` fragment carrying the routine name, object selector
fields, `target.extension_action`, and `next_resolution.params` for
`metadata.saved_state.modules.search`; the follow-up uses a public object
`ref`/`kind`/`name` and semantic saved-state `layer`, while the search
resolves storage identities internally.
This reduces agent-side field translation while still requiring a concrete
saved-state module route.
- With `include_storage=true`, `metadata.saved_state.modules.search` returns
`streams[].write_plan_target`, a concrete module target with `module_ref`,
`file_name`, `stream_index`, and `expected_sha1` for the next
`metadata.write.plan` call.
- The OpenAPI contract now exposes the same write-plan response fields:
concrete reference identity, apply payload hints, next resolution, and
blocked high-level write responses.
- `metadata.write` now refuses to call low-level apply methods when the
corresponding read-only plan is blocked, for example
`replace_with_control` without a control fragment.
- Direct saved-state form/module apply methods now run the same
`metadata.write.plan` gate before SQL apply, so low-level callers cannot
bypass blocked guard checks.
- `metadata.write.plan` blocks `replace_with_control` as
`control_fragment_drift` when optional current-source evidence is supplied
and the controlled fragment no longer matches that source.