Files
llm/docs/runbooks/1c-designer-sql-decoding.md
T

317 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Controlled Designer-to-SQL Decoding
Use the disposable `upo_test` base to learn SQL encodings that cannot be
established from static samples. The mutation is performed by 1C Designer or a
1C Enterprise client. The adapter remains a read-only SQL observer. The active
rule is `plugins/1c/connector/policies/designer-sql-decoding-policy.yaml`.
## Credential rule
Keep the 1C user password outside the repository. Supply it for one process
through an environment variable or an operating-system credential store. Do
not add it to `.env`, YAML, JSON, test fixtures, reports, or command examples.
## Metadata experiment
1. Select an object by a public 1C name.
2. Confirm there are no unrelated pending Designer changes.
3. Capture the target from live SQL, including active and saved-state origin.
4. In Designer change exactly one property and save it without applying the
configuration when saved-state evidence is sufficient.
5. Capture `ConfigSave` or `ConfigCASSave` again and compute the structural and
byte-level diff.
6. Repeat with a second value; one pair is only a hypothesis.
7. Promote a decoder only after the name, type, path, and ownership are stable.
8. Revert through Designer and verify rollback in SQL.
Applying the configuration is a separate explicit phase because it can change
`Config`, `ConfigCAS`, and the physical application-data schema.
## Application-data experiment
1. Resolve the object through `data.schema` using its public name.
2. Capture `data.count` and a narrowly filtered `data.list`.
3. Create or edit one test record through 1C Enterprise, never through SQL.
4. Capture the same logical filter after the 1C transaction commits.
5. Correlate logical values with SQL columns, including composite branches.
6. Revert or delete through 1C Enterprise and verify rollback read-only.
## Noise controls
- Record configuration-check errors that existed before the experiment.
- Do not run two experiments against the same object concurrently.
- Separate base configuration and extension ownership.
- Treat timestamps, version bytes, caches, and background service data as
volatile unless explicitly targeted.
- Discard a run when more than one semantic property changed.
Each accepted experiment produces a manifest with the public selector,
intended change, before/after SQL hashes, changed paths or columns, semantic
rule, second verification case, rollback evidence, and regression tests. XML
may be attached as offline naming evidence but is not read by the adapter.
## Confirmed baseline
The first live `upo_test` CAS comparison is recorded in
`reports/1c-sql/upo_test/designer-sql-baseline-20260714.json`. It proves a BSL
module-text change at tree path `$.2`. The accompanying `pos` and `end` changes
are stream-directory offsets recalculated from the text length; they are not
independent metadata properties and must be filtered as derived evidence.
## Saved extension metadata descriptors
The `test2` experiment on 2026-07-15 added a minimal calculation register and
its required chart of calculation types through Designer, then saved the
extension without applying it. The objects remain intentionally `saved_only`
for adapter regression checks.
Observed read-only SQL signatures in `ConfigCASSave`:
- `CalculationRegister`: brace root marker `1`, root length `10`, metadata
block marker `21`;
- `ChartOfCalculationTypes`: brace root marker `1`, root length `8`, metadata
block marker `35`;
- saved extension descriptor names use
`<extension-guid>__<object-guid>`; child/module parts add a numeric suffix.
The runtime adapter derives these signatures only from SQL payloads. The XML
export is offline evidence used to confirm the public object kind, name, GUID,
and the register-to-chart relationship; it is not a runtime data source.
When `state=working`, `extension.objects.find` must overlay these descriptors
from `ConfigCASSave` and report `saved_only` or `saved_override`. With
`state=active`, the same unapplied objects must not be returned. Route-cache
rebuilds must reclassify active descriptors so an earlier guessed kind cannot
survive as a false match.
Public saved-state card selectors expose `extension_guid`, object `guid`, and
`table=ConfigCASSave`; they do not expose the physical descriptor name. The
adapter reconstructs `<extension-guid>__<object-guid>` internally before the
read-only SQL lookup.
For `ChartOfCalculationTypes`, the verified kind-specific map currently covers
17 properties: the five scalar code/name settings at paths `1.24``1.30`, six
default/auxiliary form references, five localized presentations, and
`ActionPeriodUse` at `1.57`. The paths were cross-checked on the live
`Начисления` and `Удержания` descriptors against their offline XML exports.
For the saved-only `CalculationRegister`, the verified header map covers 13
properties: periodicity, action/base-period flags, list-form references, chart
reference, standard-command/help flags, lock and full-text modes, and three
localized list presentations. `metadata.object.properties` accepts the public
`extension_guid` + object `guid` selector and reconstructs the `ConfigCASSave`
descriptor name internally. Runtime property responses remain SQL-only.
The saved register descriptor also confirms all seven variable child-part
collections: `Attribute` at root path `3`, `Recalculation` at `4`, `Template`
at `5`, `Resource` at `6`, `Form` at `7`, `Command` at `8`, and `Dimension` at
`9`. The three field roles were distinguished by a controlled Designer sample
containing one `Реквизит1`, `Ресурс1`, and `Измерение1`. Designer saved the
extension without applying it; the adapter identified the records read-only
from the resulting live `ConfigCASSave` payload.
Saved-only register fields are available through `metadata.object.attributes`
with `table=ConfigCASSave`, `extension_guid`, and the public object `guid`.
The response returns names and decoded types while reconstructing the physical
saved descriptor key internally. `metadata.object.related` accepts the same
selector for recalculations, templates, forms, and commands; saved child keys
are also prefixed internally and remain hidden unless storage diagnostics are
explicitly requested.
A second controlled Designer sample added one item to every related collection:
`Перерасчет1`, `Макет`, `ФормаСписка`, and `Команда1`. The root descriptor then
reported a declared count of one at paths `4`, `5`, `7`, and `8`. Recalculation,
template, and form descriptors use the internal
`<extension-guid>__<child-guid>` key. A saved command exposes its BSL payload as
`<extension-guid>__<command-guid>.2`; the additional command-class GUID inside
the owner record is type evidence, not a second related command. Public related
results therefore keep only the record identity GUID and probe the `.2` module
route internally when the direct saved command descriptor is absent.
The specialized `metadata.object.forms`, `metadata.object.form.details`,
`metadata.object.commands`, and `metadata.object.modules` methods accept the
same saved-state selector. Form enumeration and detail decoding use the
internally reconstructed `<extension-guid>__<form-guid>.0` payload. Object
commands are returned from the owner descriptor and their saved `.2` payload
is verified without exposing the physical key in normal responses. Each saved
object command also returns a ready public `modules.read` selector, so callers
select the command by name and never need to calculate its GUID or SQL route.
The `.2` payload is a raw-deflate multi-stream container; `modules.read`
automatically selects its single BSL-marked stream when whole-payload text
decoding is not applicable.
Object-scoped `modules.search` and its `code.search` wrapper include these
saved command modules alongside the owner's regular modules. A caller can
therefore search by the public register selector plus BSL text and receive a
ready `modules.read`/`code.read` selector for the matching command module.
`metadata.definition.find` with `areas=["modules"]` follows the same saved
selector, enumerates command-module routines, and returns the exact procedure
or function definition with a routine-scoped read selector.
`metadata.object.parts` and `metadata.object.decode` also reconstruct the
saved descriptor prefix before reading. The former enumerates the root and
suffix payloads under `<extension-guid>__<object-guid>`; the latter decodes the
root descriptor from that key while keeping physical storage coordinates
hidden by default.
The combined `metadata.object.full` profile promotes saved object-command
selectors into its `modules` collection as `command_module` handles. This
keeps the profile lightweight (no BSL text is loaded there) while ensuring the
reported module count includes code carriers owned by commands.
Targeted `metadata.code_index.build` runs on saved command `.2` containers now
retain only streams that are positively identified as BSL. Command owner
metadata cached from `metadata.object.commands` is inherited by the concrete
`#stream:N` index row, and obsolete non-BSL rows plus their vector chunks are
pruned when the source file is rebuilt. The extension GUID is recovered from
the saved module route and retained in the indexed owner metadata.
For saved extensions, `metadata.object.get` resolves an object name through
the saved extension manifest/state route before reading its descriptor.
The public `/rpc` dispatcher preserves this name selector when
`extension_guid` and `table=ConfigCASSave` are supplied; callers may use the
object name directly and do not have to resolve its GUID first. An explicit
`guid` still takes precedence when both selectors are present.
`metadata.code_index.build` can therefore be scoped by `kind` plus `name` and
`extension_guid`; it discovers owner and command module files internally and
does not require callers to pass a physical prefix or command GUID.
The same object-scoped build enumerates saved forms, decodes their embedded
modules separately from container streams, and indexes a form only when a
valid non-empty BSL module is present. Empty generated forms are not emitted
as code carriers. Build counts distinguish `forms_scanned`,
`form_modules_discovered`, `empty_form_modules`, and `form_module_errors`, so
coverage and decoding failures are observable separately.
`CalculationRegister` is included in the public register code-carrier matrix.
Its record-set/register/command module handles use the same name-first SQL-only
read and saved-state write contract as the other register kinds.
Offline `Form.xml` analysis uses the same public vocabulary as the SQL form
decoder for form commands, events, attributes and value-table columns, check
box fields, and search/view-status/search-control additions. The XML profile
also exposes semantic properties of the root `Form` node, including command
bar location and visibility. XML remains comparison evidence only and is never
consulted by runtime adapter calls.
The SQL/XML comparison report records property-route evidence as
`XML kind/property -> SQL marker/parameter/source`. Across the 11 controlled
test-extension forms, 764 elements and 3,361 properties compare without
mismatches or XML-only properties; 23 routes have at least two matching
examples and a single SQL route. `UsualGroup.Visible` remains intentionally
variant-aware because marker `22` uses parameter `26` or `28` in two observed
structures. A controlled Designer probe on
`t_FORM_ContainerTableBehaviorVariants` changed only
`ГруппаФорма.Visible=false -> true`: parameter `26` changed `0 -> 1`, while
parameter `10` and nested `Группа1` remained unchanged. In the nested shape,
parameter `26` is a GUID and parameter `28` is the boolean visibility slot.
Saved-state writes therefore select parameter `26` only when it is boolean;
otherwise they select boolean parameter `28`. The extension was restored with
`/RollbackCfg -Extension test`, and its `ConfigCASSave` prefix was verified
empty after the probe.
Root form properties are compared separately from element properties. A
controlled `ShowCommandBar=false -> true` Designer probe changed exactly two
form atoms: parameter `17` from `0` to `2` and parameter `56` from `0` to `1`.
The SQL profile exposes this as `ОтображатьКоманднуюПанель` with
`write_shape=paired_scalar`; it is readable but must not be routed through a
single-scalar writer. `АвтоКоманднаяПанель` is resolved from the decoded form
item with `id=-1`. Before the next controlled probe, 33 root properties
matched and 44 remained.
A controlled `WindowOpeningMode=DontBlock -> LockOwner` Designer probe changed
exactly form parameter `2` from `0` to `1` and companion parameter `54` from
`0` to `1`. The SQL profile exposes the confirmed values as
`РежимОткрытияОкна=DontBlock|LockOwner` with `write_shape=paired_scalar`.
Other platform enum values remain undecoded until separately observed. The
probe was loaded only into the saved extension configuration, then rolled back;
the `test` extension prefix in `ConfigCASSave` was verified empty afterwards.
Across the 11 fixtures, 44 root properties now match; the remaining 33 are
three scalar properties repeated on each form: `AutoSaveDataInSettings`, root
`Group`, and `CommandBarLocation`.
A controlled `AutoSaveDataInSettings=Use -> DontUse` Designer probe changed
only form parameter `7` from `1` to `0`. The SQL profile exposes this as
`АвтоСохранениеДанныхВНастройках=Use|DontUse` with
`write_shape=scalar_enum`. The extension was rolled back and the `test`
prefix in `ConfigCASSave` was verified empty. Across the 11 fixtures, 55 root
properties now match; the remaining 22 are root `Group` and
`CommandBarLocation`, each repeated on all forms.
A controlled root `Group=Vertical -> Horizontal` Designer probe changed four
form parameters together: `11`, `40`, `47`, and `57`, all from `0` to `1`.
The SQL profile exposes `Группировка=Vertical|Horizontal` with
`write_shape=composite_scalar`; partial single-atom writes are not safe. The
extension was rolled back and the `test` prefix was verified empty. Across the
11 fixtures, 66 root properties now match; only `CommandBarLocation` remains.
`CommandBarLocation` shares the same parameter pair as `ShowCommandBar`. With
the panel enabled, `Top` produced `[17,56]=[2,1]` and `Bottom` produced
`[3,1]`; the hidden state is `[0,0]` and is exposed as `None`. XML `None` with
`ShowCommandBar=true` normalizes to the same SQL state as `Top`, so SQL exposes
the effective position. The profile returns
`ПоложениеКоманднойПанели=None|Top|Bottom` with
`write_shape=paired_scalar_shared`; both properties must be encoded together.
After each probe the extension was rolled back and its saved prefix was empty.
All 77 root properties across the 11 controlled forms now match SQL to XML.
The platform's third window-opening mode was verified separately because it is
not present in the UPO XML inventory. The accepted XML literal is
`LockWholeInterface`; a controlled Designer probe changed form parameters
`[2,54]` from `[0,0]` to `[2,2]`. `РежимОткрытияОкна` now decodes the complete
confirmed enum: `DontBlock=[0,0]`, `LockOwner=[1,1]`, and
`LockWholeInterface=[2,2]`. The failed tentative `LockUI` literal was rejected
by XDTO before any SQL saved state was created. The successful probe was rolled
back and the extension saved prefix was verified empty.
The complete root `Group` enum observed in UPO was verified with two additional
Designer probes. `AlwaysHorizontal` maps to
`[11,40,47,57]=[1,1,3,3]`, while `HorizontalIfPossible` maps to
`[1,2,2,2]`. Together with `Vertical=[0,0,0,0]` and
`Horizontal=[1,1,1,1]`, the decoder now covers every root form grouping value
present in the XML inventory. Each probe was rolled back and the saved prefix
was verified empty.
Active base-configuration forms also use compact root layouts. Across multiple
SQL-only samples, form payload versions 49 and 50 store
`WindowOpeningMode` directly in parameter `2`; values `0` and `1` were
confirmed by `DontBlock` list forms and `LockOwner` item forms. In these
layouts, parameter `11=0` consistently identifies root `Group=Vertical` even
when the newer companion positions are absent. The decoder applies these
fallbacks only to versions 49/50 and observed values; runtime remains SQL-only.
The active base catalog form `ЗадачиАссистентаУправления.ФормаСписка`
confirmed the compact marker-55 dynamic-list layout. Parameter `54` is the
property-bag entry count; its typed key/value pairs decode keys `5`, `6`, `8`,
`9`, `11`, `12`, `14`, and `16` as `AutoRefresh`, `AutoRefreshPeriod`,
`ChoiceFoldersAndItems`, `RestoreCurrentRow`, `ShowRoot`, `AllowRootChoice`,
`UpdateOnDataChange`, and `AllowGettingCurrentRowURL`. The following tail
records contain the user-settings-group item id, `InitialTreeView`, and the
standard `DefaultPicture` field reference. The same live payload confirms
`CommandBarLocation=None` at parameter `6` and `DefaultItem=true` at parameter
`16`. Compact marker-22 command bars expose `Autofill` at parameter `28`.
Marker-35 label fields with nested subtype marker `11` store
`AutoMaxWidth/MaxWidth` in nested positions `15/16` of parameter `39`.
The SQL/XML comparison normalizes these public XML names to the decoder's
Russian semantic vocabulary and treats marker-55 `Динамический список` as the
SQL implementation of XML `Table`. XML is used only to validate the learned
routes; runtime decoding reads the SQL payload alone.
The base item form of the same catalog confirmed more compact-layout routes.
Root parameter `20` is a typed enum with type GUID
`59ef2b80-c86b-11d5-a3c1-0050bae0a776`; value `0` decodes
`UseForFoldersAndItems=Items`. Root event bindings may reside in a direct form
block such as `1.23`; they are discovered by the GUID/handler pair shape rather
than a fixed position. GUID `bf0ac0e1-bcbb-4dfe-8fc4-0b1923b461a6` identifies
`BeforeWriteAtServer`. Compact pages options `{3,1,...}` decode
`PagesRepresentation=TabsOnTop`.
Object-backed data paths resolve public standard fields `-2/-3/-4/-5` as
`Code/Description/Parent/Ref`; custom object and tabular-section fields are
resolved from the element name and owning table. XML `AdditionalColumns`
definitions are correlated with the physical SQL form element by their full
data path. Across both active forms of
`Catalog.ЗадачиАссистентаУправления`, the comparison now covers 144 XML
elements, including the logical additional column, with no missing elements,
property mismatches, or XML-only properties.