Initial SQL-only 1C adapter baseline
This commit is contained in:
@@ -0,0 +1,297 @@
|
||||
# 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`; saved-state module search now resolves
|
||||
public `object_type`/`object_name` selectors to owner GUIDs when possible.
|
||||
This reduces agent-side field translation while still requiring a concrete
|
||||
saved-state module route.
|
||||
- `metadata.saved_state.modules.search` now 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.
|
||||
Reference in New Issue
Block a user