Files
han-app/modules/module-09-observability.md
T

31 KiB
Raw Blame History

module-09. Наблюдаемость production-like контура

Статус: целевая спецификация наблюдаемости MVP на одной VM.
Источники: README.md, arch-00-glossary.md, arch-01-system-architecture.md, arch-02-api-contracts.md, arch-03-docker-compose-blueprint.md, arch-04-settings-and-content.md, arch-05-agent-development-process.md, module-01-api-backend.mdmodule-08-keycloak.md.

1. Цели и границы

Наблюдаемость должна позволять:

  • найти пользовательский запрос по request_id, trace_id или ux_session_id;
  • восстановить путь «frontend → nginx → API → Safety → S3/Open Lines»;
  • измерять доступность, задержку, ошибки и насыщение каждого сервиса;
  • обнаруживать backlog, DLQ, circuit open, потерю telemetry и истечение TLS;
  • расследовать security/audit события без записи PII и секретов;
  • проверять SLO по данным, независимым от бизнес-логов.

Telemetry не является источником бизнес-истины и не влияет на auth, safety verdict или доставку сообщений. Недоступность Collector не должна блокировать запросы. Audit в han_app — отдельный durable контур.

2. Production-like решение MVP

2.1. Обязательный минимум в основном Compose

Архитектура явно требует только otel-collector. Поэтому основной production-like Compose обязан содержать Collector, но не обязан размещать Prometheus/Grafana/Loki/Tempo на той же VM.

Предпочтительный operable-вариант после выбора backend:

  1. приложения экспортируют OTLP gRPC в otel-collector:4317;
  2. Collector отправляет telemetry в выбранный удалённый управляемый OTLP backend провайдера;
  3. JSON stdout остаётся аварийным локальным журналом Docker с rotation;
  4. пока удалённый backend не выбран, допустим архитектурный минимум из arch-03: bounded JSON stdout/platform logs и Collector debug exporter с sampling в acceptance; такой режим не считается полноценным production-хранением и не закрывает alerting/SLO.

Требуемые возможности удалённого backend: OTLP ingest, поиск traces, PromQL-совместимые или эквивалентные metrics, поиск структурированных logs, alerting, RBAC, retention и TLS.

2.2. Самостоятельно размещаемая опция

Опциональный Compose profile observability-local может включать:

  • Prometheus — scrape метрик Collector/Redis/Keycloak/nginx exporters;
  • Grafana — dashboards и alerts;
  • Loki — логи;
  • Tempo — traces.

Он не включается по умолчанию на малой VM: стек требует дополнительной RAM/диска и сам становится объектом backup/monitoring. Для operable local-варианта нужны отдельный volume каждому backend, retention limits, compaction, auth через ops/VPN и отсутствие host ports. Grafana доступна только через отдельный защищённый ops route/VPN, не через публичный /.

Рекомендуемый минимум VM при local profile: дополнительно 4 vCPU, 8 ГБ RAM и 100+ ГБ SSD сверх приложения; точный размер — после измерения ingest.

3. Архитектура Collector

3.1. Компоненты

backend services ─OTLP gRPC/HTTP─┐
nginx/Redis/Keycloak exporters ──┼─> otel-collector
Docker JSON stdout ─filelog───────┘      ├─ OTLP/TLS remote backend
                                        ├─ Prometheus endpoint (optional)
                                        └─ debug exporter (acceptance only)

Collector запускается одним сервисом MVP. При росте разделяется на agent/gateway: локальный agent принимает и буферизует, remote gateway выполняет policy/export.

3.2. Receivers

  • otlp gRPC 0.0.0.0:4317 — основной internal receiver;
  • otlp HTTP 0.0.0.0:4318 — совместимость SDK;
  • prometheus — scrape самого Collector, Keycloak metrics, Redis exporter, nginx exporter и сервисных /metrics, если они не идут OTLP;
  • filelog — только если Docker logging driver предоставляет read-only каталог/volume; парсит JSON stdout без чтения secret-файлов;
  • hostmetrics — CPU, memory, filesystem, network VM/container host, если Collector получает только необходимые read-only mounts.

Порты 4317, 4318, 8888, 8889 используют expose, не ports. Receiver доступен только в сети observability.

3.3. Processors и порядок

Во всех pipelines первым стоит защита памяти, последним — batch:

  1. memory_limiter: check interval 1s, soft/hard limit относительно container memory;
  2. resource: нормализует service.namespace=han-chat, deployment.environment, service.version;
  3. attributes: удаляет/маскирует sensitive attributes;
  4. transform: нормализует route/status/error semantic conventions;
  5. filter: исключает health noise, debug events и запрещённые поля;
  6. probabilistic_sampler или tail sampling для traces;
  7. batch: bounded batch/timeout;
  8. при remote export — queued_retry/sending queue и file_storage extension.

memory_limiter не заменяется Docker OOM limit. При pressure Collector отбрасывает telemetry контролируемо и увеличивает otelcol_processor_refused_*.

3.4. Exporters

  • otlp/remote: TLS verify, endpoint и auth header из secret env/mount;
  • prometheus: optional pull endpoint только internal;
  • debug: только APP_ENV=test|acceptance, verbosity normal; production debug exporter по умолчанию выключен;
  • loki/otlphttp — только если выбран backend и его контракт закреплён.

Секрет exporter-а не должен появляться в rendered config, логах или /debug/configz. Config монтируется read-only; secret подставляется env.

3.5. Extensions

  • health_check — internal endpoint, используется Compose;
  • pprof/zpages — только при явном ops profile, internal network;
  • file_storage — persistent sending queue на volume otel-queue;
  • basicauth/oauth2client — если требует remote backend.

3.6. Принципиальная конфигурация

receivers:
  otlp:
    protocols:
      grpc: {endpoint: 0.0.0.0:4317}
      http: {endpoint: 0.0.0.0:4318}
  prometheus:
    config:
      scrape_configs:
        - job_name: otel-collector
          static_configs: [{targets: ["127.0.0.1:8888"]}]

processors:
  memory_limiter:
    check_interval: 1s
    limit_mib: 384
    spike_limit_mib: 96
  resource/common:
    attributes:
      - {key: service.namespace, value: han-chat, action: upsert}
      - {key: deployment.environment, value: "${env:APP_ENV}", action: upsert}
  attributes/redact:
    actions:
      - {key: http.request.header.authorization, action: delete}
      - {key: http.request.header.cookie, action: delete}
      - {key: url.query, action: delete}
      - {key: db.statement, action: delete}
  filter/noise:
    error_mode: ignore
    traces:
      span:
        - 'attributes["http.route"] == "/health/live"'
  batch:
    send_batch_size: 1024
    timeout: 5s

exporters:
  otlp/remote:
    endpoint: "${env:OTEL_REMOTE_ENDPOINT}"
    tls: {insecure: false}
    headers: {authorization: "${env:OTEL_REMOTE_AUTH_HEADER}"}

extensions:
  health_check: {endpoint: 0.0.0.0:13133}
  file_storage: {directory: /var/lib/otelcol/queue}

service:
  extensions: [health_check, file_storage]
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, resource/common, attributes/redact, filter/noise, batch]
      exporters: [otlp/remote]
    metrics:
      receivers: [otlp, prometheus]
      processors: [memory_limiter, resource/common, attributes/redact, batch]
      exporters: [otlp/remote]
    logs:
      receivers: [otlp]
      processors: [memory_limiter, resource/common, attributes/redact, filter/noise, batch]
      exporters: [otlp/remote]
  telemetry:
    metrics: {address: 0.0.0.0:8888}

Конкретная версия schema проверяется командой Collector validate; image закрепляется по digest. Значения memory/batch/queue — стартовые, не SLO.

4. Resource attributes и корреляция

Обязательные resource attributes:

  • service.name: nginx, api-backend, message-safety, bitrix-local-app, bitrix-sync, keycloak, redis, otel-collector;
  • service.namespace=han-chat;
  • service.version=<release-or-git-sha>;
  • deployment.environment=production-like|production;
  • host.name/service.instance.id без публичного IP.

Обязательные поля request-события:

  • request_id;
  • trace_id, span_id;
  • ux_session_id — nullable, только когда передан;
  • service.name;
  • environment либо canonical deployment.environment.

request_id формирует/валидирует nginx; сервис возвращает его клиенту и передаёт downstream. trace_id берётся из active span. ux_session_id не является auth и не должен использоваться как metric label.

5. W3C propagation

  • принимаются только валидные traceparent и опциональный tracestate;
  • nginx передаёт context в API; при edge instrumentation создаёт server span;
  • API создаёт child spans для PostgreSQL, Redis, S3, Safety, Open Lines и JWKS;
  • internal calls передают traceparent, tracestate, X-Request-ID;
  • baggage по умолчанию не принимается от внешнего клиента; если включён, allow-list исключает PII;
  • Bitrix24/S3 могут не вернуть context: внешний client span всё равно закрывается результатом;
  • async outbox/inbox связывается span link с исходным trace; новый worker trace не притворяется продолжением спустя долгий срок.

Frontend может отправлять валидный traceparent, но backend не доверяет его sampling/security атрибутам.

6. JSON stdout contract

Одна JSON-запись на строку UTF-8:

{
  "timestamp": "2026-07-10T09:00:00.123Z",
  "level": "INFO",
  "service.name": "api-backend",
  "service.version": "git-abcdef0",
  "environment": "production-like",
  "module": "message_service",
  "event": "message.delivery.completed",
  "message": "Message delivery completed",
  "request_id": "01J...",
  "trace_id": "32hex",
  "span_id": "16hex",
  "ux_session_id": "uuid-or-null",
  "route": "/api/v1/dialogs/{dialog_id}/messages",
  "method": "POST",
  "status_code": 201,
  "duration_ms": 742,
  "dependency": "bitrix-local-app",
  "outcome": "success",
  "error_code": null
}

Правила:

  • event — стабильная mnemonic, message — безопасное описание;
  • route — template, никогда raw URI с id/query;
  • stack trace допускается только в internal error log после redaction;
  • message text, callback body, SQL values и file content запрещены;
  • Docker driver ограничен 50m × 5, но это buffer, не retention backend;
  • multiline stack trace сериализуется полем JSON, не отдельными строками.

7. Redaction и data minimization

Удаляются или маскируются:

  • Authorization, Cookie, Set-Cookie, JWT, OAuth/code/refresh/access tokens;
  • raw OTP/mock code, Keycloak admin/client password;
  • phone/email/full name, device id, IP по policy (допустим HMAC/truncated);
  • message text, filenames с PII, document/file contents;
  • DSN/password, Redis URL, S3 keys;
  • presigned URL и любая query string;
  • Bitrix raw payload/download URL/application token;
  • db.statement с literals; предпочтительно operation/table, не SQL.

Redaction выполняется в SDK/logger до stdout, затем повторяется Collector processor. Collector не может считаться единственной защитой. Автотесты отправляют canary secrets/PII и требуют отсутствие во всех трёх сигналах.

8. Instrumentation по компонентам

8.1. FastAPI-сервисы

  • OpenTelemetry ASGI/FastAPI server spans с route template;
  • HTTPX client spans с sanitized host/method/status;
  • SQLAlchemy/asyncpg spans без параметров и raw statement;
  • Redis instrumentation с command name и DB index, без key/value;
  • boto/S3 spans: operation/bucket logical name, без object key/query;
  • background workers: span на claim/process/finalize, links на origin;
  • исключить /health/live из traces; readiness оставить в metrics и sampled logs.

8.2. PostgreSQL

Собираются pool wait/checked-out, transaction duration, error class, migrations revision, managed PG provider metrics (CPU, storage, connections, locks, replication/PITR state). user_id, SQL text и row data не labels.

8.3. Redis

redis_exporter подключается отдельным ACL user только на INFO, PING, безопасные latency/keyspace metrics. Нужны memory ratio, evictions, expirations, blocked/rejected clients, command latency, AOF status/rewrite, Pub/Sub buffers, key count/TTL агрегаты. Keys/values не экспортируются.

8.4. Keycloak

Включаются management metrics/JVM/HTTP/DB pool. Custom OTP provider публикует counters send/verify/limit/settings-cache без phone labels. Login events идут в JSON/audit с masked/HMAC destination. Public OIDC synthetic проверяется отдельно.

8.5. nginx

JSON access log содержит request_id, извлечённый trace_id, route class, method, normalized path, status, bytes, request/upstream duration/status, TLS version, cache status. $request с query не используется.

Collector filelog parser:

  • разбирает JSON, timestamp и severity;
  • переносит service.name=nginx;
  • превращает пустые/- в null;
  • route class нормализует в bounded set;
  • отбрасывает ACME/health success noise;
  • не парсит raw URI в labels.

Native nginx OTEL module предпочтителен, если image/version закреплены. Без него nginx только передаёт W3C context и коррелирует access log; первый server span создаёт API.

8.6. Host/Docker

CPU, load, memory/swap, disk usage/inodes/IO, network, container restarts/OOM, Docker daemon health и clock sync. Container name/version — bounded labels; container id не хранится как долгосрочный high-cardinality label.

9. Метрики бизнес-потоков

API и auth

  • han_http_requests_total{service,route,method,status_class};
  • han_http_request_duration_seconds;
  • han_auth_bootstrap_total{outcome};
  • han_ux_session_start_total{reason};
  • han_jwks_refresh_total{outcome};
  • han_rate_limit_decisions_total{scope,outcome}.

Message Safety

  • checks/verdicts по allow|deny|pending|error;
  • poll duration/count buckets, timeout и recovery backlog age;
  • stub mode info и terminal 400 отдельно, пока действует test-only контракт;
  • cache hit, Redis latency, task expired/not-found.

Open Lines/Bitrix

  • message submitted → delivered end-to-end latency;
  • local app outbound result/retry/ambiguous/DLQ;
  • inbox depth/oldest age/forward retries/duplicate;
  • OAuth time-to-expiry/refresh result;
  • connector desired/observed state;
  • Bitrix 429, circuit state, setup failure.

Files/S3

  • init/complete/promote/delete;
  • quarantine object age/orphans;
  • checksum/MIME/size reject;
  • presigned download issued;
  • S3 dependency latency/error by operation and logical bucket.

Frontend synthetic

  • public config/content;
  • OIDC discovery/authorization page;
  • WS handshake;
  • test-user end-to-end flow в отдельной тестовой identity без реального PII.

Никакие UUID/user/session/dialog/task/message id не labels. Они допустимы только в sampled logs/traces при принятой retention.

10. Dashboards

  1. Executive/SLO: availability, error budget burn, p50/p95/p99, message delivery, auth, active incidents.
  2. nginx edge: RPS, 4xx/5xx, upstream latency/status, 429, WS, TLS, cache.
  3. api-backend: routes, DB/Redis pools, JWKS, circuits, outbox/safety backlog, S3.
  4. message-safety: verdicts, pending/poll, task TTL, Redis, distribution stub outcomes.
  5. bitrix-local-app: install/OAuth, connector, outbound/inbox/DLQ, API/Bitrix latency.
  6. bitrix-sync: mode, DB probe, last success/staleness; нельзя показывать CRM sync как рабочий в stub.
  7. Keycloak: login/OTP/lockout, sessions/tokens, provider settings cache, JVM/DB.
  8. Redis: memory/evictions/AOF/latency/clients/keyspace.
  9. PostgreSQL/S3: provider metrics, storage, connections, backup/PITR, object errors.
  10. Business flow: guest config → OTP → bootstrap → session → dialog → safety → Open Lines → operator reply.
  11. Collector health: accepted/sent/refused/dropped, queue, retry, exporter errors, memory/CPU.

Каждая панель содержит release annotation, environment filter и links trace→logs по trace_id.

11. SLI, SLO и alerts

Значения — начальная production-like политика до load/product review:

SLI Initial SLO, 30 дней
HTTPS edge availability 99.9%
public config/content successful requests 99.9%
protected read API successful requests 99.5%
Keycloak login flow availability 99.5%
text message accepted и доставлен в Open Lines 99.0%
operator inbox applied без permanent loss 99.5%
p95 protected read API < 750 ms
p95 text send без внешнего rate limit < 5 s
telemetry Collector ingest availability 99.0%, не входит в business availability

Файловый send измеряется отдельно: p95 не должен превышать configured safety poll budget; user-cancel, safety deny, 4xx validation и edge abuse 429 не считаются server failure. 503/504 и unexpected 5xx считаются.

Paging alerts

  • multi-window burn: 14.4× за 5m/1h или 6× за 30m/6h;
  • edge/API 5xx >5% 5 минут;
  • text delivery failure >5% 10 минут;
  • oldest outbox/inbox/safety task >5 минут либо DLQ >0;
  • Keycloak login failures infrastructure class >10% 5 минут;
  • PostgreSQL unavailable/connection saturation >90%;
  • Redis unavailable, AOF error или sustained evictions;
  • Collector exporter queue >80%, dropped/refused telemetry >0 sustained;
  • TLS expiry <14 дней warning, <7 дней page;
  • disk >85% warning, >92% page; OOM/restart loop;
  • managed PG backup/PITR failure.

Ticket/warning alerts

  • p95 regression 20% release-over-release;
  • settings/JWKS cache stale;
  • bitrix-sync stub probe stale >150s;
  • OAuth expires <24h без успешного refresh;
  • quarantine orphan growth;
  • cardinality/ingest growth >2× baseline.

Alert содержит service, environment, symptom, dashboard, runbook, release и безопасный query; не содержит PII.

12. Sampling, cardinality и retention

Traces

  • errors/5xx, circuit, timeout, DLQ, safety final deny и slow requests — 100%;
  • обычные успешные requests — 510%;
  • health/ACME success — 0%;
  • tail sampling предпочтителен в Collector, но head sample SDK должен оставлять достаточно данных;
  • sampling decision передаётся W3C.

Metrics

Allow-list labels; route template вместо raw path; status class/known code; dependency enum. Cardinality budget: целевой <10 000 active series на MVP environment. CI проверяет запрещённые labels.

Retention initial

  • metrics: 30 дней high resolution, 13 месяцев downsampled при доступности backend;
  • traces: 7 дней, errors 14 дней;
  • technical logs: 14 дней, security/auth logs 30 дней;
  • audit han_app: 365 дней только как временное допущение до legal policy;
  • raw Bitrix callback не хранится в telemetry;
  • local Docker logs: не более 250 МБ/container и 5 файлов.

Legal retention/erasure имеет приоритет; изменение требует обновления policy и backup lifecycle.

13. Collector health и отказоустойчивость

Контролируются:

  • /health extension;
  • process CPU/RSS/restarts;
  • accepted/refused/sent/failed spans, points, records;
  • batch send size/latency;
  • exporter queue capacity/size, enqueue failures, retry age;
  • file storage usage/corruption;
  • scrape failures;
  • config reload/validation.

При remote outage queue хранится на otel-queue с bounded size/age. При заполнении отбрасываются сначала low-priority success traces/logs; приложение продолжает работу. Нельзя позволять queue заполнить системный диск.

14. Docker Compose

otel-collector:

  • pinned contrib image;
  • networks: только observability, а для scrape internal targets — минимально необходимая backend;
  • expose: 4317, 4318, 13133, 8888/8889;
  • без host ports;
  • config read-only, otel-queue volume rw;
  • non-root, read-only rootfs, tmpfs /tmp, drop capabilities, no-new-privileges;
  • initial limit: 0.5 CPU/512 MiB, queue disk 510 ГБ; уточнить load test;
  • healthcheck extension;
  • restart policy с backoff;
  • приложения имеют bounded non-blocking OTLP exporter queue.

Доступ к Docker socket запрещён. Для container metrics используется безопасный exporter/hostmetrics, а не unrestricted socket mount.

15. Security

  • OTLP receiver internal-only; при переходе между hosts — mTLS;
  • remote exporter только TLS verify, credentials least privilege;
  • Grafana/Prometheus/Loki/Tempo не публичны;
  • RBAC: viewer/operator/admin; audit доступа к logs/traces;
  • dashboards не показывают PII;
  • config/secret permissions 0400/0600;
  • dependency/image scan и SBOM;
  • защита от log injection: JSON encoding, control chars, bounded field lengths;
  • telemetry input не исполняет expressions из пользовательских значений;
  • регулярная secret-canary проверка и incident deletion procedure.

16. Runbooks

Collector not-ready

  1. docker compose ps otel-collector и bounded logs.
  2. Проверить config validation, memory/OOM, queue volume.
  3. Проверить DNS/TLS/auth remote exporter.
  4. Не рестартовать бесконечно при полной queue; сначала освободить/расширить безопасно.
  5. Бизнес-сервисы оставить работающими; подтвердить local JSON logs.
  6. После восстановления проверить drain и gap.

Telemetry отсутствует у одного сервиса

  1. Проверить service.name, endpoint/protocol и сеть observability.
  2. Проверить SDK queue/drop counters и clock.
  3. Отправить synthetic request с X-Request-ID.
  4. Найти его в stdout, Collector accepted и backend.
  5. Проверить sampling/filter/redaction rules.

Remote backend outage

  1. Подтвердить exporter errors, а не application outage.
  2. Оценить queue fill rate/time-to-full.
  3. Ограничить debug exporter; не включать verbose.
  4. При длительном outage увеличить sampling только через reviewed config.
  5. После восстановления подтвердить drain и создать incident note о потере данных.

Cardinality/ingest spike

  1. Найти новое metric/log attribute по release annotation.
  2. Отключить offending instrument/filter в Collector.
  3. Проверить raw path/id/user/session labels.
  4. Rollback instrumentation при риске стоимости/доступности.
  5. Добавить CI regression test.

Высокая latency сообщения

  1. Открыть trace по request id.
  2. Разделить API, Safety poll, S3, local app, Bitrix.
  3. Проверить circuit, queue age, DB pool и Redis.
  4. Не повторять ambiguous message без исходного idempotency key.
  5. Следовать runbook зависимого модуля.

Логи содержат секрет/PII

  1. Ограничить доступ и остановить offending export.
  2. Сохранить только incident metadata, не копировать значение.
  3. Ротировать скомпрометированный secret.
  4. Удалить данные по процедуре backend/provider.
  5. Исправить source redaction + Collector defense; добавить canary test.

17. Проверки и Definition of Done

  • Collector config проходит validate и запускается в едином Compose;
  • OTLP gRPC и HTTP принимают три сигнала;
  • все сервисы имеют правильные resource attributes;
  • request проходит nginx/API/Safety/Open Lines с одним request_id и связанным trace;
  • ux_session_id есть только где передан и не является label;
  • FastAPI/HTTPX/PG/Redis/S3 workers instrumented;
  • nginx JSON parsing и trace correlation проверены;
  • Redis/Keycloak/host/Collector metrics доступны;
  • dashboards и alerts provisioned из versioned files для выбранного telemetry backend; до его выбора это остаётся acceptance/TBD, а не выполненный production DoD;
  • remote outage, queue full, Collector restart и backend recovery rehearsed;
  • local profile, если включён, имеет volumes/retention/auth и не публикует порты;
  • secret/PII canary отсутствует в logs/traces/metrics;
  • cardinality и sampling tests проходят;
  • SLO queries воспроизводимы и исключения документированы;
  • runbooks связаны с alerts.

18. Допущения, TBD и конфликты

Решения

  • O1: обязательный архитектурный минимум — Collector; выбран self-hosted SigNoz на отдельной VM 192.168.0.5, доступный по приватному OTLP gRPC.
  • O2: Prometheus/Grafana/Loki/Tempo — отдельный operable profile, не скрытая обязательная нагрузка основной VM.
  • O3: JSON stdout — аварийный локальный buffer; audit App DB — durable.
  • O4: telemetry fail-open для business path, но потеря telemetry alertится.
  • O5: ID/PII не labels; source redaction обязательна до Collector.

TBD

  • O-TBD1 закрыт: self-hosted SigNoz, 192.168.0.5:4317, plaintext только внутри доверенной приватной сети; UI через SSH jump host.
  • O-TBD2: утвердить SLO/RPS/error-budget с product owner.
  • O-TBD3: legal retention/erasure и допустимость IP/user-agent.
  • O-TBD4: точные sampling и resource limits после load test.
  • O-TBD5: поддерживаемый nginx OTEL module и Keycloak native tracing по pinned versions.
  • O-TBD6: нужен ли local observability profile в первой VM.

Обнаруженные архитектурные конфликты

  1. arch-03 разрешает stdout/platform exporter как минимум, но production-like расследования и alerts без backend ограничены. Здесь remote OTLP backend рекомендован, но не объявлен выбранным: провайдер остаётся TBD.
  2. module-05 использует test-only terminal 400 и non-sticky verdict вместо canonical 403/sticky production verdict. Dashboards обязаны маркировать сервис stub; production SLO Safety на нём недостоверен.
  3. module-07 — только DB connectivity stub, тогда как arch-01/02 описывают полноценную CRM sync. Dashboard не должен показывать queue/CRM SLI, которых нет.
  4. Retention, RPO/RTO и production SLO открыты в module-01/04/06/08; значения этого документа являются initial ops policy, не закрывают legal/product TBD.
  5. Observability env (OTEL_REMOTE_*, service names, sampling/queue limits) добавлены в arch-04 и .env.example; sampling/queue limits уточняются после load test.

19. Ссылки на прототип и исходные документы