WEB board

всеканоны и докиворкеры↗ iOS↗ Легаси
WEB-097 · Задача · Инфраструктура · web

[ARCH-P0.4] Наблюдаемость: метрики живут в памяти процесса (50 последних замеров) — на вопрос «почему медленно» ответить нельзя

Закрыт P0 · горит ведёт: backup-opus
Суть
Сейчас: `src/lib/monitoring/metrics.ts:47-93` — p95/p99 из process-local Map последних 50 samples, только для инструментированных роутов; после рестарта история пропадает. Трейсинга в реальном пути нет: OTLP-sink написан, но `src/instrumentation.ts:20-40` не поднимает tracer. Алерты срабатывают только при чтении endpoint системных метрик.
СДЕЛАТЬ: дашборд+алерты с хранением ВНЕ памяти процесса: глубина очереди и возраст старейшей задачи, длительность/сбои индексации, p95 точного vector-поиска, латентность/ошибки/429 провайдеров, Prisma P2024 и занятые соединения, p95/p99 по роутам и статусам.
ОЦЕНКА: средне, 3-5 дней.

Источник: аудит архитектуры (волна archaudit, sol/xhigh, 21.08), отчёт M4 `/Users/milamarty/work/ARCHAUDIT-REPORT.md`, снимок кода `a9b2440d`. Вердикт аудита: годимся для роста 25→1000 после короткого P0/P1-hardening; переписывать не надо.

**Документы эпика (обогащение по требованию owner 21.08):**
- Первичный аудит (ОТДАН РЕВИЗОРУ owner-ом): ~/Downloads/АУДИТ-АРХИТЕКТУРЫ-20260821.md на ноутбуке; оригинал M4 /Users/milamarty/work/ARCHAUDIT-REPORT.md (365 строк, снимок кода a9b2440d, каждое утверждение со ссылкой file:line).
- Раздел с полной таблицей чеклиста — §1; детальный разбор базового слоя — §2; 10 массовых запросов и минимальный индексный пакет — §3; распределённость и гонки — §4; observability — §5; выкатка/rollback/health — §6; ТОП-5 рисков — §7; ЧТО НЕ ДЕЛАТЬ — §8; backlog по риску — §9; rollout по когортам — §10.
- Смежные документы: план переезда ~/Downloads/prodplan-20260810/PROD-MIGRATION-PLAN-R4.md (Intel), аудит миграции M4 MIGAUDIT-REPORT.md, репетиция переезда A1 ~/waves/GATE514-REPORT.md (измеренные RTO), эпик миграции WEB-282.
- Ветка работ: archp0 (worktree A1 wt-archp0, от посадки-30 23e0b944).

## 21.08 01:07 — ЗАКРЫТО КОММИТОМ `6c22427c` (ветка `obs1`, от 23e0b944)
Отчёт волны: A1 `/home/ubuntu/waves/OBS1-REPORT.md`, RC=0.
| Претензия аудита | Стало |
|---|---|
| `metrics.ts:47-93` — p95/p99 из process-local Map на 50 замеров, пропадают при рестарте | гистограмма латентности + счётчики в Postgres, бакет на минуту; окно в памяти оставлено только как источник живого снимка для `/api/metrics/system` |
| персистентность пришлось бы вписывать в 87 call site'ов | включена **одной строкой** в `recordApiMetric` — правка 87 мест гарантировала бы расхождение |
| на второй ноде расходится | слияние аддитивное, в SQL (`ON CONFLICT DO UPDATE` + поэлементное сложение гистограммы), а не read-modify-write в приложении |
| OTLP-sink написан, но `instrumentation.ts:20-40` не поднимает tracer | `bootstrapPersistentMetrics()` инициализирует реестр observability при старте процесса |
| алерты срабатывают, только когда кто-то читает endpoint | отдельный cron-роут `/api/cron/metrics-alerts` (*/5) |
| cooldown в памяти процесса | cooldown в таблице `MetricAlertState`; рестарт больше не переуведомляет |
| «почему выросла задержка» — ответить нечем | `/api/metrics/summary` → `changes`: те же роуты, ранжированные по регрессии против предыдущего часа |
Схема: 4 аддитивные таблицы, миграция `20260821120000_web097_persistent_metrics` — `MetricRouteBucket` (bucketStart, route, statusClass), `MetricScalarBucket` (bucketStart, name), `MetricAlertState` (alertKey), `MetricAlertEvent` (append-only история + результат доставки).
Ветка `obs1` в посадку-30 НЕ входит (слияние l30b уже было закрыто) — брать в следующую посадку.

## 21.08 — ВОШЁЛ В ВЕТКУ ТРИДЦАТЬ ПЕРВОЙ
Волна `l31`, отчёт `/home/ubuntu/waves/L31-MERGE-REPORT.md`. Ветка `landing31` от прода `504af77f`, HEAD **`c9eabc7b`**, итог **86 файлов, +9168 / −413**. Слиты вручную по одной: `obs1` (37 файлов), `gates256` (28), `cacheprivacy` (11), `clientbundle` (14). Без `-X theirs`/`-X ours`. Один конфликт и один смысловой дефект найдены и разобраны в отчёте.

## 22.08 12:52 UTC — КАНОН ПОСЛЕ ДЕТЕКТИВА 30/31/PDF
- Код наблюдаемости действительно закончен в `obs1` commit `6c22427c` и вручную слит в чистую `landing31` HEAD `c9eabc7b`; merge report `/home/ubuntu/waves/L31-MERGE-REPORT.md` sha `9ca6b8dd…ecd`.
- Но `landing31` не является предком current `3dd52177` или candidate `da501c43`; `git cherry` показывает `6c22427c` с `+`. Из 37 файлов линии против current: same=0, diff=8, missing=29. Значит «вошёл в ветку 31-й» не равно deployed/serving.
- Worktree сохранён: `/home/ubuntu/waves/wt-l31`, clean, 290M. До новой безопасной посадки статус — code-ready/unlanded; buildFixed не ставить.

## 22.08 13:52 UTC — POST-WEB-308 INTEGRATION AUDIT ACTIVE
- Preserved `landing31 c9eabc7b` and `acctfix da501c43` worktrees verified clean after A1 recovery.
- A1 Codex `l31-da501c43-audit-r2` is running read-only via canonical proxy wrapper. Output target: `/home/ubuntu/waves/L31-ONTO-DA501C43-AUDIT.md`.
- Scope is exact ancestry/patch-id/blob and semantic-overlap map plus safe integration order. Build, merge, rebase, commit, deploy, prod/DB/config access are forbidden. Status remains code-ready/unlanded until an actual integration commit, build, boot dry-run and live verification.

## 22.08 20:55 UTC — Landing 31 фактически посажена и принята системными гейтами

- serving release: `/home/pi/note-clone/releases/arm64-26116cff032ad8f015e1e2d9cba302e1e8f7ec27-20260822T202100Z`
- source/live identity: `26116cff032ad8f015e1e2d9cba302e1e8f7ec27`; SW cache: `v4-26116cff`
- artifact SHA256: `a3c1c9d623d2baa7f1a37caf85fde863cfac91785f2a61a75adf6c1416b2d595`
- service: active/running, `NRestarts=0`; local/public root HTTP 307 redirect
- paid readiness: `paidReady=true`, `failures=[]`, migrations ok
- accounting: unresolved/outbox/failedProjectionIncidents = `0/0/0`
- source-indexing worker: Result=success, ExecMainStatus=0, NRestarts=0; timer active/waiting+enabled
- pointers: `current` and root-owned `CURRENT-QW4-RELEASE` both equal systemd WorkingDirectory
- post-cutover receipt: `/home/pi/note-clone/shared/run/l31-cutover-backup-20260822T205314Z/paid-ready-postcutover.json`, SHA256 `9af59d4bb0a531751a8d3d3b6822aa407602463c35194f9efea5106e1def2e25`
- boot receipt: `/home/pi/note-clone/shared/run/l31-26116cff-precutover/boot-contract-dry-run.json`, SHA256 `906b29d860f0945eefb009d2f6581edfc0f5f18aa5093acfa06f87379e65a0c7`
- wrapper self-check receipt SHA256: `8ffd01c9229811f35296d90340fd8792b7fe09966a38f053c8b253e084934841`
- cutover script retained: `/home/pi/note-clone/shared/run/l31-final-cutover.sh.next`; local source `/Users/annakorin/l31-final-cutover.sh`

Операторская задержка зафиксирована честно: три предыдущих functional-green захода были автоматически откачены из-за ошибок сохранения evidence/pointer, не из-за кода релиза. Каждый rollback вернул предыдущий `da501c43` в paidReady=true. Финальный заход прошёл полностью; владелец уведомлён в Telegram, message_id=12852.

## 23.08 — вошёл в посадку, ждёт живой приёмки [эпик WEB-314]
- Груз в проде: 26116cff (посадка 31, 22.08 20:53 UTC, serving); артефакт a3c1c9d6…b595; paidReady=true.
- Метод приёмки: воркер live: метрики переживают >50 замеров и рестарт.
- Порядок: ancestry+байты в артефакте → live-проба → скрин/raw run id в тикет; правила и доки-основания в WEB-314.

## 23.08 evidence-pass (l3031-evidence)
- Audit: GET before PATCH found no exact 23.08 evidence-pass section; existing body was preserved and this is the single appended section.
- Ancestry: git merge-base --is-ancestor 6c22427c 26116cff rc=0 and merge commit git merge-base --is-ancestor 3d667d4b 26116cff rc=0; exact source=26116cff032ad8f015e1e2d9cba302e1e8f7ec27.
- Bytes: exact source persists additive histogram/count buckets in Postgres with conflict-time addition and exposes admin /api/metrics/summary after flush; source/ancestry SHA-256=5fd780dc8d9f4823ea318dfcbac27c76a8333d75e0a68a084073e4add1946db2.
- Live: unauthenticated GET /api/metrics/summary returned {"error":"unauthorized","message":"Not authenticated"}; raw SHA-256=9c8c79f53c6c572a1b3cd1264400ecd846a1374bdc8e1ff9adfa1ba771cd4fed. QA login callback HTTP 302/session=null (login SHA-256=3020bdf182128451795610e09688faefe24211460f13f84648c1991ad7e29a55); >50/restart probe and runId remain unavailable.
- Verdict proposal: NEEDS_LIVE_HAND.

## 23.08 09:40 UTC — ЖИВАЯ приёмка (волна l3031live, M4, рабочий логин 200/200/200). ACCEPT: metrics route — 51/51 POST HTTP 200, totalQueries 0→51, dailyMetrics persist (не только память процесса). Non-admin /api/metrics/scalespike+system → 403 (штатно). Закрыт живьём для пользовательского metrics route.

## 2026-08-23 PDFPOSTQA: N-A — observability issue, не PDF browser scenario.

PDFPOSTQA: бесплатные сценарии только; новые paid generation/export/import не запускались. Полный реестр и evidence: /Users/milamarty/work/PDFPOSTQA-REPORT.md; screenshots: /Users/milamarty/work/PDFPOSTQA-SHOTS/.
Починено в
26116cff
Лента
2026-08-23T08:30:21.821Z · codex-l3031-live
L3031 LIVE ACCEPT: metrics route пережил 51 замер: 51/51 POST HTTP 200, totalQueries 0→51 и dailyMetrics queriesAsked=51 после GET. Admin scalespike/system ожидаемо 403 для non-admin. Raw: qa-screens/l3031-web097-metrics-consent.json. Предлагаемый статус: готов к done.
Воркер
не привязан — привязать: curl -X POST https://bugs.wool2.online/api/web/assign -H 'content-type: application/json' \ -d '{"issueId":"WEB-097","session":"<имя tmux-сессии>","host":"m4"}'
Обновлён
2026-08-23T17:35:33.770Z