Initial project import

This commit is contained in:
2026-08-14 09:40:51 +03:00
parent 00040e5ce4
commit d7099bf80d
146 changed files with 30509 additions and 1055 deletions
+168 -4
View File
@@ -6,8 +6,9 @@ The connector is read-first and optimized for an operational coding loop where f
Preferred live architecture:
- read-only SQL connector for fast diagnostics and data samples;
- lightweight 1C agent for metadata, forms, commands, and BSL modules;
- SQL-only connector for diagnostics, metadata decoding, and controlled
saved-state work in an explicitly authorised test base;
- a human-operated Configurator for viewing and applying pending changes;
- cached metadata/module snapshots with freshness checks;
- change proposals as reviewable artifacts, not direct production writes.
@@ -17,7 +18,12 @@ The connector is responsible for:
- BSL module search/read;
- read-only query validation and execution;
- metadata/module snapshots;
- change proposals without direct apply.
- change proposals and, only where a reverse codec is activation-proven,
controlled `ConfigSave`/`ConfigCASSave` writes with rollback evidence.
The adapter never writes `Config`, `ConfigCAS`, or application data directly.
It does not automate Configurator and must not invent unknown 1C structures.
The protocol evidence base is [docs/1c-sql-protocol](../../../docs/1c-sql-protocol/README.md).
Contracts:
@@ -122,6 +128,57 @@ adapter-owned lock session is supplied. Structural add/delete/rename plans are
kept blocked for confirmation because parent and reference objects can also be
required.
## Configuration activation debug workflow
Activation is a separate boundary from saved-state writes and repository
coordination. The current workflow is intentionally debug-only:
1. `configuration.activation.status`;
2. `configuration.activation.plan`;
3. `configuration.activation.request`;
4. forward the returned request id to `configuration.activation.execute` with
`mode=debug` and `confirm_activation=true`;
5. inspect or cancel the request through
`configuration.activation.request.status`,
`configuration.activation.request.cancel`, and
`configuration.activation.audit`.
The request is bound to a live-SQL fingerprint and is rejected when pending
files change or the request expires. Requests and events are stored in the
adapter-local SQLite selected by `ONEC_ADAPTER_STATE_DB`; they contain no
payload bytes or credentials. `ONEC_CONFIGURATION_ACTIVATION_STATE_FILE` is a
one-time legacy JSON import source only. `configuration.activation.capabilities`
reports runner readiness without returning paths, URLs, selectors, users,
passwords, or tokens.
`configuration.activation.bridge.probe` can then check the local runner or the
authenticated HTTP runner endpoint `/configuration/activation/debug`. The
probe verifies only Designer-file availability and infobase-selector presence;
it never starts a process.
Pass `bridge_debug=true` to `configuration.activation.execute` when the runner
must also acknowledge the exact request id and live-SQL fingerprint. The runner
returns an opaque SHA-256 debug receipt; mismatched or missing receipts block
the request, while a valid receipt adds a `bridge_debug_accepted` audit event.
After a manual F7, call `configuration.activation.verify` with the same request
id. It reports `not_activated`, `changed_since_request`, or
`verified_up_to_date` from a fresh SQL comparison. The last status proves
saved/active alignment, not the historical fact that Designer performed the
activation.
Real Designer execution remains disabled. `/UpdateDBCfg` is recorded only as
the documented future base-configuration operation. Extension activation stays
manual until a separately verified platform command and post-activation check
are implemented.
Activation request mutations use SQLite `BEGIN IMMEDIATE` transactions, so
concurrent adapter processes cannot overwrite each other's request/event
updates. Saved-state backup retention is explicit:
`storage.saved_state.backups.prune` defaults to a dry run, is scoped by
`base_id`, preserves the newest requested count, and requires
`confirm_delete=true` before deleting adapter-local backup files. Backups
referenced by `metadata.write.history` are always protected; when write-history
availability cannot be verified, affected backup files are protected
fail-closed.
## Docker Run
Create a local `.env` from `.env.example`, keep real passwords outside git, and
@@ -237,6 +294,8 @@ Current live methods:
- `metadata.route.resolve`
- `metadata.form.decode`
- `metadata.object.attributes`
- `metadata.relationship.verify`
- `metadata.relationship.find`
- `metadata.object.full`
- `metadata.snapshot`
- `codec.decode`
@@ -287,6 +346,9 @@ Agent-facing code write rule:
public path such as `<extension>.<form>.<routine>` plus full code text.
- `code.write` automatically targets the saved-state layer and reports
`write_mode.target=saved_state` with `activation_state=not_activated`.
- Write plans for embedded form-container modules return a ready
`code.write` hint; they do not incorrectly request a nonexistent
`#stream:<index>`.
- Use `code.read`/`code.search` with the default working state for current
programming-time code; use `state=both` only when an explicit saved vs active
comparison is needed.
@@ -296,6 +358,10 @@ without physical SQL/storage traces by default. `metadata.object.decode` also
returns a 1C-facing decoded object profile by default; pass
`include_storage=true` only when adapter diagnostics need the underlying decoded
payload metadata, record containers, or DBNames/storage routes.
Exact extension objects use the same public `kind` + `name`/`ref` selectors as
base objects. `metadata.object.modules` includes owned form modules and returns
qualified names such as
`test2.Форма.t_Форма.Модуль формы`; extension GUIDs and CAS keys remain internal.
`metadata.object.properties` is the unified property endpoint for every 1C
metadata kind. It selects a kind-specific SQL decoder for `Configuration`,
@@ -348,6 +414,32 @@ inspection for user-facing answers. The object can be selected by `guid`, by
`kind` + `name`, or by 1-based `ordinal` within `metadata.objects.list` for that
kind.
For a safe answer to "are these objects linked?", do not infer a link from a
similar field name, BSL mention, or a runtime value. Use
`metadata.relationship.verify` with an exact source `member` and optional
`target_ref`. It returns `confirmed` only when that member's declared 1C type
explicitly names the target object; otherwise it returns `not_confirmed` or an
explicitly ambiguous result. To discover a direct typed field without knowing
its name, call `metadata.relationship.find` with public refs only:
```json
{
"method": "metadata.relationship.find",
"payload": {
"base_id": "upo_test",
"ref": "Document.СписаниеЗапасов",
"target_ref": "Document.РасходнаяНакладная",
"direction": "either",
"execution_mode": "job"
}
}
```
`direction=either` checks both objects for explicitly declared references and
returns the direction of every confirmed edge. A `not_found` result means that
no direct declared metadata reference was found; it does not prove that an
indirect BSL, query, form, or business-process relationship is absent.
`metadata.object.full` is the preferred high-level method for agent answers like
"show everything about this document". It combines the live object card,
semantic sections, decoded forms, BSL module profiles, and counts in one
@@ -488,7 +580,33 @@ unless `include_storage=true`.
`code.search` is the agent-facing wrapper over module search. Its items include
`read_selector.method: "code.read"` and preserve `module_ref` when that is the
best available safe handle. `code.read` can consume that selector directly.
best available safe handle. `code.read` can consume that selector directly;
the selector pins the configuration view that produced the hit. A storage
stream whose Configurator-tree role is not independently decoded is returned
as `bsl_module` with `role_status=unconfirmed` and must not be treated as a
command, manager, or a tree path.
`metadata.object.commands` resolves an `extension` name to the active
extension internally before it reads the selected object. A caller provides
only the public object and extension selectors; it must not replace them with
a base-configuration route or infer a command from a BSL stream suffix. A
successful empty command list is the only evidence currently returned for “no
decoded commands”; an unresolved object route is reported separately.
For object-owned extension forms, `modules.search` and `code.search` resolve
the form module from the public owner reference. In the default
`state=working` view they inspect the saved counterpart first and fall back to
the active module only when needed; `state=active` never returns saved-only
text. Saved matches carry `activation_state=saved_state` and
`current_state.activation_state=not_activated`.
For an active extension form selector, `code.read state=both` resolves the
saved form by logical owner/form identity, even when active and saved CAS file
names differ, and reports live text SHA1 comparison evidence.
`metadata.resolve_overrides` uses the same name-first form ownership and
saved-first working-state rules. A public selector such as `Catalog.test2`
therefore resolves routines located in forms owned by that extension object;
the returned chain identifies the form and activation state without exposing
the object's physical SQL route.
`metadata.definition.find` accepts public object references such as
`Обработка.<Name>` or `Document.<Name>` in `query` and the common object
@@ -553,3 +671,49 @@ be proven, the adapter must re-read live SQL or return an explicit stale-cache
error.
Operational runbook: `docs/runbooks/1c-operational-coding.md`.
## Development audit telemetry
Every REST `/rpc` call produces a privacy-safe JSONL event in
`/data/adapter-audit.jsonl`. It contains the UTC time, correlation id, public
method and selector summary, result status/error, duration, public route and
resolver timings/counts (when a write route is involved), and exception type
when the request itself fails. A `public_write_route_unresolved` event retains
the safe resolver status/error/candidate count so it can be diagnosed without
asking a caller for a module handle. It deliberately excludes BSL text, SQL
payloads, physical file names, stream indexes, credentials, and SQL connection
details. The MCP proxy forwards its generated
request id in `X-Request-ID`, so an agent response can be correlated with the
REST record. The log is shared by all configured
`base_id` values so cross-base failures and slow calls can be compared.
For development, the default retention is deliberately generous: 50 MiB per
file and ten retained files. Configure `ONEC_ADAPTER_AUDIT_MAX_BYTES` and
`ONEC_ADAPTER_AUDIT_KEEP_FILES` to change it. Rotation is best-effort and can
never fail an adapter request. A caller may supply an `X-Request-ID` header to
correlate a client event with the REST record.
The `adapter-1c-audit` Compose service writes an aggregate report every 15
minutes to `/data/adapter-audit-reports/latest.json`; set
`ONEC_ADAPTER_AUDIT_INTERVAL_SECONDS` to alter the interval. It reports base
distribution, failures, slow operations, malformed rows, and recent failures.
For an immediate manual report, run `python scripts/analyze_1c_adapter_audit.py`
against a copied log or `python /app/analyze_audit.py` inside the REST image.
The MCP proxy has its own persistent `/data/mcp-audit.jsonl` and periodic
summary: it records failures that happen before a request reaches REST.
For an extension-wide `code.search` without a concrete object selector,
`timeout_seconds` is a total search budget. If owner-route discovery consumes
that budget, the adapter returns `status=partial` with
`diagnostics.code=time_budget_exhausted`; it does not continue serial owner
probes in the background. Narrow routine work with `ref` or `kind`/`name`.
REST deployments use a five-minute Docker stop grace period. On `SIGTERM` the
adapter stops accepting new work and waits for already-running request threads,
including verified saved-state writes, to complete. Do not deploy the REST
service while an operator is intentionally running a production-base write;
the deployment prevents a half-response, but the client should still retry only
after it receives a structured result.
The deployment script also waits for `health.runtime.active_rpc_count=0` before
recreating REST. `-SkipDrainCheck` is an emergency-only override and must not
be used while a write is in progress.