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
+130
View File
@@ -0,0 +1,130 @@
# Adapter Observer
`adapter-observer` is an independent, read-only web service for adapter telemetry.
It must never connect to 1C SQL, call write methods, modify `/data`, or be a
runtime dependency of `adapter-1c-rest` or `adapter-1c-mcp`.
## Inputs and guarantees
- It mounts REST and MCP Docker volumes at `/audit:ro` and `/mcp-audit:ro` and
reads only rotated `adapter-audit.jsonl*` / `mcp-audit.jsonl*` files.
- The source events contain public selector summaries, status/error, request
correlation id, timings, and safe result summaries. They intentionally omit
BSL text, raw SQL payloads, storage keys, and credentials.
- A missing or malformed log is an Observer condition, never an adapter error.
- The UI distinguishes `exception` from expected safe outcomes such as
`blocked`, `unsupported`, and `invalid_argument`.
## Tabs
- **Журнал запросов**: filterable individual REST events and their safe details.
- **Аналитика**: p50/p95, slow method ranking, grouped non-OK fingerprints and
evidence-based next actions.
- **Покрытие**: contract for adding a future `metadata.adapter.audit` snapshot.
## Retry boundary
Audit JSONL deliberately has no complete request payload. Do not reconstruct
or guess it from selector summaries. A future replay button may repeat only a
request captured by Observer itself with an explicit read-only allowlist. It
must never replay a write request from logs.
## Deployment
On `docker.cin.su`, inspect the existing REST container and volume first:
```text
docker inspect adapter-1c-rest
docker volume ls
```
Deploy only the Observer stack from `core/deploy/docker/adapter-observer`.
It uses external volume `adapter-1c_adapter-1c-data` read-only and port 8031
by default. Do not run `down` against the adapter compose project.
```text
docker compose --env-file .env -f compose.yaml up -d --build
curl http://localhost:8031/health
```
## Development contract
When adapter telemetry changes, preserve backwards parsing: unknown fields are
shown in event details; known metrics remain optional. Before adding a special
visualization, record its input schema and add fixture JSONL tests. The general
journal must continue working for unknown adapter methods.
## Key decisions for future agents
1. Keep Observer a separate Compose project, port, image and failure domain.
Never add it as a dependency to REST/MCP and never restart those containers
while deploying it.
2. The volumes are externally named `adapter-1c_adapter-1c-data` and
`adapter-1c-mcp_adapter-1c-mcp-data` on `docker.cin.su`; Observer mounts
them only as `/audit:ro` and `/mcp-audit:ro`.
3. Audit events are evidence, not replay payloads. The historical journal can
link to an object by a public selector but cannot reconstruct omitted fields.
4. Treat job lifecycle statuses `accepted`, `running`, `done` and `cancelled`
as operational state, not failures. Expected rejections are shown separately
from adapter exceptions.
5. Retain both `duration_ms` (Observer-facing REST wall time) and optional
result timings. Do not manufacture nested timings if the adapter did not
return them; the first precise per-span waterfall requires an Observer-owned
read-only proxy/session trace.
## Delivery plan
### Delivered MVP
- Rotated REST JSONL reader, safe event details and filters.
- p50/p95/max latency by method, error fingerprint grouping and guidance.
- Read-only Docker deployment and health endpoint.
- MCP-to-REST request correlation by `request_id`; absent REST pair is shown as
a transport boundary, not a decoder failure.
- A bounded read-only coverage refresh (`help.methods` and
`metadata.adapter.audit`) stored in Observer's own state volume, with the
latest 50 snapshots per base and a schema/method/count delta.
- A best-effort background coverage snapshot every 900 seconds for `upo_test`.
It has a 300-second minimum interval and must never affect UI availability.
### Next safe increments
1. Add an Observer-owned, read-only allowlist proxy. It can save complete
*sanitized* read request payloads for user-initiated replay and form a true
parent/child waterfall; no historical write replay.
2. Periodically invoke `metadata.adapter.audit` through that proxy and persist
versioned coverage snapshots in an Observer-owned SQLite database.
3. Add regression screens: compare coverage/schema/method catalog before and
after an adapter release, with an explicit `not comparable` state.
4. Add retention, export and role controls before exposing the journal outside
the internal network.
### Explicit non-goals until separately approved
- No replay of historical write, activation, repository or password operations.
- No raw request/response capture solely to make replay convenient.
- No automatic remediation, SQL optimization, Configurator launch or mutation.
- No claim that a slow request is an adapter defect without repeated evidence.
### Items commonly forgotten in observability work
- **Clock semantics:** preserve source UTC timestamp and Observer receive time;
never compare durations across hosts as if clocks were synchronized.
- **Asynchrony:** display job poll calls separately from end-to-end job time;
polling volume must not dominate failure charts.
- **Cardinality:** bound selector/error fingerprints so arbitrary object names
cannot create an unbounded metrics index.
- **Release correlation:** record Observer version and adapter health/method
catalog snapshot beside each periodic coverage run.
- **Availability:** health, disk/read errors and log rotation failures of
Observer must appear in its own diagnostics, not as adapter failures.
- **Retention and access:** define data lifetime, exported fields and viewer
permissions before making port 8031 internet-facing or adding Caddy routes.
## Review checklist
- Does a proposed feature work with omitted payload fields rather than guessing?
- Does it classify expected rejection separately from exception/transport loss?
- Does it preserve `request_id` and public selector provenance?
- Is every newly persisted field redacted and bounded by retention?
- Can the Observer be stopped without affecting adapter requests?