Initial project import
This commit is contained in:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user