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
+340 -32
View File
@@ -2,22 +2,18 @@
## Configuration repository control
The current adapter release is SQL-only. It does not start Designer, call a
Windows runner, or inspect repository internals. External 1C execution is a
future-version capability and is disabled by default with
`ONEC_ADAPTER_ENABLE_EXTERNAL_1C=false`.
The adapter is SQL-only. It does not start, automate, emulate, or require
Designer/Configurator. Configurator actions are performed by a human and are
outside the adapter's execution boundary.
Repository operations are available through `repository.status`,
`repository.lock.plan`, `repository.lock`, `repository.lock.confirm`, `repository.lock.verify`,
`repository.unlock`, `repository.commit.plan`, and `repository.commit`.
Configuration is selected only by `payload.base_id`: the base runtime profile
declares `repository.backend=direct|karman_bridge`, the Designer executable,
infobase selector, endpoint, optional extension, users, and environment-variable
names containing transient passwords. No repository, bridge, or endpoint name is
hard-coded or inferred from naming conventions.
Configuration is selected only by `payload.base_id`. No Designer executable,
Configurator endpoint, bridge, or external 1C runner is used by this adapter.
`repository.lock_mode=automatic|manual` is also selected per base. Automatic
mode uses the configured runner. Manual mode requires no Designer or runner:
`repository.lock_mode=manual` is selected per base. Manual mode requires no
Designer integration:
`repository.lock.plan` returns the exact public development-object names to
lock in Configurator, and `repository.lock.confirm` records the user's explicit
confirmation for only that object set. Such a session is marked
@@ -43,13 +39,11 @@ further SQL writes through that session.
The adapter keeps a bounded audit trail of request creation, confirmation,
cancellation, and closure and exposes it to the administrative requests view.
Both backends invoke standard Designer repository commands. A Karman/Filebox
backend is an opaque native TCP transport and does not own credentials, object
locks, or repository transactions. For configured bases, saved-state apply is
blocked until the caller supplies an active adapter-owned `lock_session_id`.
Commit additionally requires `allow_repository_commit=true` and a non-empty
version comment. Unlock and commit operate only on the object set recorded for
that adapter session.
Repository coordination records only the human-confirmed scope. It does not
invoke Designer repository commands and does not prove a native lock. For
configured bases, saved-state apply is blocked until the caller supplies an
active adapter-owned `lock_session_id`; that session is coordination evidence,
not a native repository transaction.
Status: draft, read-only first.
@@ -64,6 +58,30 @@ Related work plan: `docs/1c-extension-layer-plan.md`.
- When XML-derived rules are promoted into the adapter, the runtime write path
must still resolve to concrete SQL storage targets such as `ConfigSave` or
`ConfigCASSave`, with explicit gates and readback verification.
- SQL readback is not proof that Configurator accepts, displays, saves, or
activates a change. Only a human may provide that confirmation.
- The adapter must reject, rather than fabricate, a `ConfigSave`/
`ConfigCASSave` container or signature whose SQL protocol is not proven.
## Data Composition Schema Query Writes
`scd.patch` changes only one proven direct XML scalar: a dataset `query`, a
calculated-field `expression`, or a resource `expression`. It resolves the
report and SCD by public 1C names, preserves the surrounding SQL payload bytes
and compression envelope, and never accepts a storage key from a caller.
For `execution_mode=apply`, `apply_and_verify`, or `apply_and_rollback`, a
missing saved SCD payload is prepared internally through the established
saved-state copy codec when `allow_sql_saved_state_prepare=true` is supplied.
The caller still explicitly authorizes the eventual edit with
`allow_saved_state_write=true` and `allow_sql_saved_state_apply=true`.
`apply_and_rollback` additionally requires
`allow_sql_saved_state_rollback=true`. It restores the exact apply backup, not
a newly encoded copy of the old query. If this request created the saved-state
overlay, it then removes only receipt-recorded rows after hash precondition
checks. A successful result proves SQL readback and cleanup only; it does not
prove Configurator visibility, acceptance, or activation.
## User Identity And Access Terminology
@@ -123,8 +141,8 @@ Password mutation is available only for the platform `infobase_user` layer:
`allow_administrator_password_change=true`;
- normally both mutations are blocked when `ONEC_ADAPTER_SERVICE_TOKEN` is
empty. A disposable isolated test stand may explicitly set
`ONEC_INFOBASE_USER_ADMIN_ALLOW_UNAUTHENTICATED=true`; this also permits an
unprotected runtime bridge endpoint and must never be enabled in production.
`ONEC_INFOBASE_USER_ADMIN_ALLOW_UNAUTHENTICATED=true`; it affects only this
isolated SQL operation and must never be enabled in production.
Both operations select the exact user through `infobase.user.get` and update
only `dbo.v8users.Data`. The clear-text password for `set` exists only in memory
@@ -411,6 +429,64 @@ Purpose:
Normal coding agents should write BSL through `code.write`, not through SQL,
storage rows, payload paths, or `metadata.module.write_apply`.
### Working-state and saved-state ownership rule
An agent works only with the effective working configuration. It reads the
saved development version when one exists and otherwise reads active code; it
does not determine whether `ConfigSave` or `ConfigCASSave` exists, and it must
not call a separate saved-state preparation operation as part of a normal code
change.
The adapter owns that transition. A `concrete_reference` returned by
`code.search` or `code.read` is an opaque proof of the exact active module
stream, extension, and layer—not permission to write active storage. After
preflight has resolved that reference, a normal apply must do the following
inside the adapter:
`code.write` accepts the same reference either directly or inside
`write_selector.target`. It verifies the supplied public `ref`, extension,
layer, canonical path, and routine against that exact stream, then routes it
to the saved copy without repeating `metadata.object.modules` discovery.
For one apply request the adapter authorizes the public extension scope once
before preparation. Its internal prepare and writer stages reuse that
process-bound authorization; they must not repeat broad support/owner scans
against `ConfigCASSave`. If authorization is absent, the request returns a
bounded `blocked` result before any support scan or saved-state mutation.
For a client transport deadline shorter than the adapter write budget, call
`adapter.job.start` with `method="code.write"` and the same public payload,
then poll `adapter.job.get`. This preserves the final structured write result;
the caller must not retry the SQL write while the job is running.
1. verify the exact extension/layer and active source stream;
2. create a missing saved-state copy through the proven
`Config`/`ConfigCAS` to `ConfigSave`/`ConfigCASSave` copy path;
3. apply the guarded edit only to saved state;
4. make a backup, validate BSL and the old-text/SHA preconditions, and reread
the written result; and
5. support the requested rollback, including removal or restoration of any
adapter-created saved-state copy.
`metadata.write.preflight` reports such a first write as `status=ready` with
`route.preparation.status=adapter_managed`,
`route.preparation.caller_action_required=false`, and
`saved_state.status=will_prepare`. `needs_prepare` is reserved for a route
whose copy protocol is not sufficiently proven for the adapter to execute.
The adapter must never write the active `Config` or `ConfigCAS` layer.
For a hash-keyed extension overlay, this internal copy includes the live
extension root manifest (`root_cas_key`) and the confirmed object parts. An
exact BSL stream reference remains the write target, but must not reduce the
saved-state preparation to that leaf stream alone.
The caller never invokes or waits for this preparation as a separate workflow:
`code.write` performs the bounded copy, write, verification, and readback as
one adapter operation. Its preparation gate is restricted to the confirmed
extension layer and public object; it does not perform a whole-extension
support scan before copying proven source parts.
`code.write` accepts 1C names and code text:
```json
@@ -428,11 +504,21 @@ storage rows, payload paths, or `metadata.module.write_apply`.
Contract:
- default `mode` is `apply`, and apply means save to the working
`ConfigSave`/`ConfigCASSave` layer, not production apply;
- default `mode` is `plan` and does not write SQL. `apply`,
`apply_and_verify`, and `apply_and_rollback` must be requested explicitly;
they save only to the working `ConfigSave`/`ConfigCASSave` layer, not to
production;
- every `code.write` response includes `write_mode.target=saved_state`,
`write_mode.activation_state=not_activated`, and
`write_mode.production_apply=false`;
- the normal agent view is the effective working configuration: a matching
`ConfigSave`/`ConfigCASSave` overlay is read ahead of active code. Agents
do not inspect, create, or select saved-state rows. For a first extension
write, the adapter takes the exact active module handle returned by
`code.search`/`code.read`, creates the proven `ConfigCASSave` copy inside
its guarded apply workflow, and then edits that copy. Preflight reports this
as `route.preparation.status=adapter_managed`; no separate prepare call is
required from the agent.
- saved-state `code.read` and `code.search` responses include
`current_state.source=saved_state` and
`current_state.activation_state=not_activated`;
@@ -455,7 +541,9 @@ Contract:
For embedded form modules the adapter writes only the scalar module token in
the saved form payload with `path_preserve_format`. Whole-form payload
canonicalization is forbidden because Designer may reject the form even if the
payload decoder can parse it.
payload decoder can parse it. A write plan for such a container returns a ready
`code.write` apply hint rather than asking the caller to invent a
`#stream:<index>`.
## Resolve Object
@@ -601,6 +689,22 @@ Important methods:
Constants are exposed as a typed `value`; enumeration rows include their
public value `name`, `synonym`, and `value_ref`. Business-process storage is
resolved through the platform `_BPr<N>` route internally.
- `additional_attributes.find` is the read-only entry point for additional
requisites. It reads a public `ChartOfCharacteristicTypes` selector (by
default `ДополнительныеРеквизитыИСведения`) and accepts `query` for a
description search. Its `empty_source` result is deliberately distinct from
`not_found`: it means that the resolved chart route has no records in the
selected infobase, so no property reference or value type can be claimed.
`additional_attributes.storage.resolve` requires a confirmed 32-hex
`property_ref` plus `owner_ref`. It searches candidate information registers
and returns a storage join only after live metadata proves dimensions
`Объект` and `Свойство`, a `Значение` resource, and that `Свойство` is a
reference to the selected PВХ. Otherwise it returns `unresolved` and never
guesses physical `_Fld...` columns.
For `ChartOfCharacteristicTypes`, `data.schema` and the find result also
expose chart-level `allowed_value_types` with its live Config evidence path.
This is explicitly not represented as the type of an individual property
record until that record's `ТипЗначения` route is decoded.
- `data.present` returns a compact presentation for one `record_ref`, and
`data.movements` reads register rows for a `recorder_ref`.
- BSP access-key methods use the same object/record separation without
@@ -728,6 +832,10 @@ Important methods:
`Модуль сервиса интеграции`. Handler names decoded by
`metadata.object.properties` can therefore be followed directly into their
live SQL module routines.
- Exact extension objects are resolved by the same public `kind` + `name` or
`ref` selectors as base objects. `metadata.object.modules` also returns form
modules owned by the selected object, with qualified 1C names and without
exposing CAS keys unless `include_storage=true`.
- The same module APIs expose the four configuration-level modules through the
public `Configuration.<Name>` selector: ordinary application, external
connection, managed application, and session. Runtime discovery reads the
@@ -859,6 +967,15 @@ Important methods:
`module_ref` values remain valid for narrow follow-up cleanup. The method
changes only adapter-local SQLite state, never the 1C SQL database; use
`dry_run=true` to inspect the matching count without deleting cache rows.
- `metadata.module_owner_cache.backfill` incrementally builds the reverse
`module_ref -> 1C object` map from current metadata. One call processes a
bounded object page and returns `next_cursor` (`kind_index`, `kind`,
`offset`) until `complete=true`. The discovered public owner is propagated
to existing lexical/vector code-index rows, including the matching
active/saved-state table pair. By default objects without code-index rows
are skipped so the operation remains fast; `deep=true` explicitly enables
their slower metadata-module decoding. This changes adapter-local SQLite
only.
- For backward compatibility, a legacy bare `guid` without an owner selector
may still identify a form. `object_guid` never gets that legacy treatment.
- Logical schema results are cached briefly. `refresh_cache=true` forces a live
@@ -905,7 +1022,11 @@ Important methods:
code fragment. `state` is passed through to `modules.search`; the MCP
`source_state=working` policy maps to this `state=working` mode.
- `code.read`: wraps module/routine reads for agent-facing code analysis. It
may set `source.kind=code_read`, but it must preserve the module `origin`
accepts either `routine_name` or the inclusive `line_start`/`line_end` range.
A focused request may use a previously decoded local code-index snapshot
(`source.kind=code_index_cache`, `freshness.verified_against_sql=false`) to
avoid decoding a large container again; pass `prefer_code_index=false` for
the normal live SQL decode path. It must preserve the module `origin`
evidence from `modules.read` so write planning can still distinguish base,
saved state, extension, or unresolved CAS references.
- `metadata.adapter.audit`: reports recognized metadata kinds, public kind
@@ -1000,6 +1121,9 @@ Working source state:
`comparison.both_present` plus `comparison.differs`. When `include_text=true`,
top-level `text` is the effective programming text: saved-state text if it
exists, otherwise active text. `text_source` names the layer used.
For extension form modules, the saved counterpart is matched by extension,
logical form owner, and form GUID rather than by assuming identical active
and saved CAS file names.
- `code.search state=both` also returns a mixed view for saved CommonForm code:
saved-state matches are listed first, active matches are fetched with an
independent `state=active` pass, and `counts.saved_matches` /
@@ -2103,6 +2227,15 @@ Selector rules:
row details. `include_storage=true` retains the low-level diagnostic response.
`plan` remains the default and performs no write; `apply` and
`apply_and_verify` still require `allow_sql_saved_state_prepare=true`.
- `metadata.saved_state.ensure` is the preferred idempotent public facade for
that operation. It resolves `ConfigSave` or `ConfigCASSave` from the public
object/extension selector, copies only missing active parts, and never asks a
user to create a missing save layer in Configurator. It remains a plan by
default; its apply modes use the same explicit SQL gate.
- `metadata.saved_state.ensure.rollback` removes only rows inserted by the
opaque receipt returned from an ensure apply. It SHA-checks every row first,
requires `allow_sql_saved_state_rollback=true`, and never touches active
`Config` or `ConfigCAS`.
- Every public RPC `next_resolution`/`next_call` entry uses `{method, params}`.
`payload` is reserved for the outer RPC request envelope and internal
apply-hint bodies; it must not be used as the arguments field of a public
@@ -2134,6 +2267,74 @@ Selector rules:
accepts the backward-compatible `table=ConfigSave|ConfigCASSave`, compares
saved rows with their active source by file part, size, and SHA1, and returns
per-file `changed`, `unchanged`, or `saved_only` statuses.
- `configuration.activation.status` is the read-only activation boundary for
`saved_state -> active`. It checks both layers by default, or accepts
`layer=base_saved_state|extension_saved_state`, and delegates to the live SQL
saved-state comparison above. It never uses the code cache or vector index as
authority. `activation_required=true` means at least one `changed` or
`saved_only` object exists. If the configured scan limit is reached without a
detected difference, the result is `inconclusive` rather than a false
`up_to_date`.
- `configuration.activation.plan` uses that live status to build a read-only
handoff. When changes exist, it returns a `{method, params}` review call, a
manual Designer action (`Обновить конфигурацию базы данных`, F7), and a live
verification call whose expected status is `up_to_date`. The current adapter
does not start Designer or mutate the active configuration, even when
`ONEC_ADAPTER_ENABLE_EXTERNAL_1C` is enabled. A future execution method must
use a dedicated Designer bridge and separate explicit confirmation.
- `configuration.activation.request` creates an expiring adapter-local request
only when the live status is `activation_required`. The request fingerprint
includes the exact pending storage files and their saved/active SHA1 values;
storage coordinates and hashes are not returned as the public activation
status. Requests and lifecycle events are stored outside the infobase in the
local SQLite database selected by `ONEC_ADAPTER_STATE_DB`, in
`configuration_activation_requests` and
`configuration_activation_events`. The legacy JSON path selected by
`ONEC_CONFIGURATION_ACTIVATION_STATE_FILE` is imported once and then remains
read-only.
- `configuration.activation.execute` currently accepts only `mode=debug` and
requires `confirm_activation=true` plus the exact request id. It repeats the
live SQL read and rejects the request if it expired, the base differs, the
pending state disappeared, or any fingerprinted file changed. A successful
result is `debug_accepted`; Designer is not started and the active
configuration is not changed. Use
`configuration.activation.request.status` to inspect the adapter-local
request state.
- `configuration.activation.request.cancel` requires `confirm_cancel=true` and
records a lifecycle event for the exact request. Cancellation is idempotent
and has no 1C side effect. `configuration.activation.audit` returns a bounded
base-scoped list of request states and events without exposing the internal
per-file fingerprint evidence.
- `configuration.activation.capabilities` reports only boolean/configuration
readiness: runner kind, presence of a Designer path and infobase selector,
external-1C enable flag, and supported workflow gates. It never returns the
executable path, runner URL, infobase selector, users, passwords, or tokens.
The base layer reports documented `/UpdateDBCfg` as `debug_only`; extension
activation reports `manual_only` until a verified platform command is
implemented.
- `configuration.activation.bridge.probe` performs an explicit debug-only
readiness call. For a local runner it checks that the configured Designer
executable exists and exactly one infobase selector is present. For an HTTP
runner it calls `/configuration/activation/debug` using the existing runner
token configuration. Both paths return only booleans and runner kind:
Designer is not started, credential values are not read by the local probe,
and paths, URLs, selectors, users, and secret names are not returned.
- `configuration.activation.execute` accepts optional `bridge_debug=true`.
After all request, expiry, confirmation, live-SQL, and fingerprint checks
pass, the adapter sends only `base_id`, semantic layer, request id, and the
64-hex fingerprint to the debug runner. The runner must return a matching
request/fingerprint plus a 64-hex receipt. A missing, mismatched, or
not-ready receipt blocks acceptance. A valid receipt records the
`bridge_debug_accepted` lifecycle event; it still does not start Designer or
change the active configuration.
- `configuration.activation.verify` closes the manual activation loop for an
exact request. It repeats the live SQL comparison with no cache. The result
is `not_activated` when the original fingerprint is still pending,
`changed_since_request` when pending files differ from the confirmed
fingerprint, and `verified_up_to_date` only when saved and active layers
align. SQL alignment does not prove that Designer performed activation—it
can also result from discarding or replacing saved changes—so the response
reports `activation_proven=false`.
- `metadata.saved_state.changes.list` is the read-only pending-change overview
across the base and extension saved-state layers. Use the semantic
`layer=base_saved_state|extension_saved_state` filter when only one layer is
@@ -2178,7 +2379,11 @@ Freshness statuses:
- `cache_hit_verified`: cache candidate was rechecked against current SQL
`payload_sha1` and `text_sha1`;
- `cache_hit_stale`: cache candidate exists, but current SQL no longer matches;
- `cache_refreshed_from_sql`: a stale cache row was rebuilt from current SQL
and will be reranked before it can be returned;
- `vector_candidate_unverified`: vector result is only a retrieval candidate.
- `dirty_with_live_fallback`: local coverage is incomplete, so the response
includes a direct live-SQL search for newly added code.
RPC methods:
@@ -2195,24 +2400,91 @@ RPC methods:
}
```
- `metadata.code_index.status`: reports cache/module/vector chunk counts;
- `metadata.code_index.search`: fast lexical search over cached BSL, verifying
candidates by default;
- `metadata.code_index.status`: reports cache/module/vector chunk counts,
pending outbox events, overlay tombstones, and the local snapshot token;
- `metadata.code_index.search`: strict lexical search over cached BSL. Strict
mode is the default: it overfetches, verifies against live SQL, refreshes and
discards stale rows, and switches to live SQL while the index is dirty;
- `metadata.code_index.verify`: verifies one `module_ref` against live SQL;
- `metadata.code_index.refresh_changed`: verifies search candidates and refreshes
stale modules from SQL;
- `metadata.code_vector.search`: searches cached module/routine chunks with
local hashing embeddings or supplied `query_embedding`, then revalidates by
default.
- `metadata.code_index.sync_pending`: processes exact dirty/outbox targets after
saved-state writes;
- `metadata.code_index.poll_changes`: detects Configurator/external changes.
Saved tables are checked by default; use `include_active=true` for a less
frequent active-configuration scan;
- `metadata.code_vector.pending`: returns current BSL chunks that still need an
embedding for a requested model, with `chunk_id` and `text_sha1`
preconditions. Optional `chunk_kinds=["routine"]` and `max_text_chars`
support fast incremental passes without falsely marking skipped long chunks
as embedded;
- `metadata.code_vector.embedding.upsert`: stores an external embedding only
while those preconditions still match. Changed or removed chunks return
`conflict`;
- `metadata.code_vector.search`: hybrid lexical/vector search over cached
module/routine chunks. It overfetches, verifies live SQL, reranks after stale
refreshes, suppresses active rows shadowed by saved state, and returns
name-first `object_ref`/`object_selector` fields.
If older global index rows have empty owners, run
`metadata.module_owner_cache.backfill` page by page. Search also performs a
cheap local owner lookup for top candidates. For base `Config`/`ConfigSave`
modules whose part name starts with a GUID, the adapter resolves that GUID
against current metadata, requires an exact identity match, and persists the
verified public owner. It never launches a configuration-wide owner scan on
the hot search path.
For active extension `ConfigCAS` modules, the adapter follows the current
extension manifest from the exact CAS content hash to the owning descriptor,
decodes its public kind/name, and returns the extension name/GUID in both
`owner.extension` and `object_selector`. The manifest relation and descriptor
are cached locally only after this current-SQL resolution. Hashes are never
presented as object names.
`strict=true` and `verify=true` are the safe defaults. `strict=false` is a
diagnostic/candidate mode and must not drive programming changes.
The adapter keeps revision, dirty/outbox, tombstone, and vector data in the
local adapter SQLite database. It does not add project tables or settings to
the 1C SQL database.
External embeddings are optional. The worker supports deterministic local
hashing for tests and any OpenAI-compatible embedding endpoint:
```powershell
python scripts\embed_1c_code_vectors.py `
--base-id upo_test `
--embedding-provider openai-compatible `
--embedding-model <code-embedding-model> `
--embedding-base-url http://<embedding-host>:<port> `
--json
python scripts\search_1c_code_vectors.py "где рассчитывается налог" `
--base-id upo_test `
--embedding-provider openai-compatible `
--embedding-model <code-embedding-model> `
--embedding-base-url http://<embedding-host>:<port> `
--embed-pending `
--json
```
API keys are read only from the configured environment variable and are not
written to SQLite, responses, or project files. The embedding model label and
vector dimensions are stored so vectors from different models cannot be mixed.
For Matryoshka-capable OpenAI-compatible models the code worker includes the
requested dimension in the cache label (for example `@d384`), slices a longer
response deterministically, and normalizes the stored vector again.
Operational modes:
- `fast`: cache plus SQL hash verification;
- `fast`: strict cache search plus SQL hash verification;
- `live`: direct SQL search/read, slower but authoritative;
- `background_refresh`: intended for long cache warming jobs.
Never apply code changes from cache or vector output alone. Use the returned
`read_selector` after freshness is `cache_hit_verified` or read live SQL again.
`read_selector` after freshness is `cache_hit_verified`, then run the normal
live write preflight. A non-null snapshot token identifies a clean local index;
it is not a native 1C repository lock.
## Saved-State Form Search And Write Target Resolve
@@ -2353,12 +2625,23 @@ Purpose:
- build a routine chain for a concrete object and method name across base and
extension modules;
- include modules of forms owned by the selected object, including extension
objects resolved from a public `ref`/`kind`/`name` without requiring an
extension GUID or CAS key;
- apply the same source policy as code reads: `state=working` prefers the saved
form-module counterpart with active fallback, `state=save` is saved-only,
`state=active` is active-only, and `state=both` can report both versions;
- mark every chain link with `activation_state=active|saved_state`, so a saved
routine is never mistaken for already applied runtime code;
- return public read selectors for every found routine without exposing storage
ids by default;
- expose `chain[].extension_action` for each routine link. For base
configuration links this is `operation_class=base_definition`;
- for extension links, normalize known action evidence into
`insert_before`, `insert_after`, `replace`, or `replace_with_control`;
- classify an unannotated routine of an object defined by the extension itself
as `extension_definition`; it is not an unresolved interception of a base
routine and therefore does not trigger the unknown-action write guard;
- when a routine is found in an extension but the action metadata is not yet
resolved, return `extension_action.status=unknown` and
`operation_class=unknown_extension_action`. The agent must not treat this as
@@ -2967,6 +3250,31 @@ Purpose:
- return backup ids, source metadata, sha1 and byte counts without returning
rollback payload hex.
## Saved-State Backup Retention
RPC method:
```json
{
"method": "storage.saved_state.backups.prune",
"payload": {
"base_id": "<base-id>",
"table": "ConfigCASSave",
"older_than_days": 30,
"keep_latest": 20,
"limit": 500,
"dry_run": true
}
}
```
The method only inspects adapter-local backup JSON files. It is base-scoped,
defaults to `dry_run=true`, preserves `keep_latest` matching backups, and never
writes the 1C database. Actual deletion additionally requires
`dry_run=false` and `confirm_delete=true`. Backups referenced by
`metadata.write.history` are never selected for deletion. If history lookup is
unavailable for a base, its matching backup files remain protected.
## Kind Smoke
Command: