18 KiB
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
- Select an object by a public 1C name.
- Confirm there are no unrelated pending Designer changes.
- Capture the target from live SQL, including active and saved-state origin.
- In Designer change exactly one property and save it without applying the configuration when saved-state evidence is sufficient.
- Capture
ConfigSaveorConfigCASSaveagain and compute the structural and byte-level diff. - Repeat with a second value; one pair is only a hypothesis.
- Promote a decoder only after the name, type, path, and ownership are stable.
- 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
- Resolve the object through
data.schemausing its public name. - Capture
data.countand a narrowly filtereddata.list. - Create or edit one test record through 1C Enterprise, never through SQL.
- Capture the same logical filter after the 1C transaction commits.
- Correlate logical values with SQL columns, including composite branches.
- 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 marker1, root length10, metadata block marker21;ChartOfCalculationTypes: brace root marker1, root length8, metadata block marker35;- 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.