# Session handoff — 2026-05-29 (этап 5 slepok routing protection)

**Сессия:** ~05:00-08:00 МСК 29.05.2026. Тема: продолжение этапа 5 slepok-routing-protection, обнаружились побочные блокеры (SSH-фильтр YC backbone) и **2 реальных P1-сигнала** на проде (audit-chain race + webhook storm 256k).

**Для следующей сессии:** прочитай этот файл первым. Все артефакты этой сессии (планы, workflow, текст YC support) — по ссылкам ниже.

---

## 1. Состояние трёх параллельных треков

### Трек A — этап 5 slepok-routing-protection (Stage 4 на проде, Stage 5 ждёт окна)

| Чек | Статус |
|---|---|
| Stage 4 выкачен на боевой | ✅ 28.05.2026 ~20:32 МСК |
| Orphan-rekey post-deploy (Task 4.2) | ✅ Проверено 29.05 ~05:14 МСК через `gh workflow run artisan-run.yml -f command="supplier:rekey-orphans --dry-run"` → **`No orphan SMS supplier_projects found. Nothing to migrate.`** — миграция R-17 не нужна |
| 7-дневное окно мониторинга 29.05→04.06 | 🔄 День 1 пройден с 2 findings (см. трек B); далее автоматически |
| Stage 5 переключение `online → batch` | ⏸ Ориентир **04.06.2026**, но **сдвинется на ~07.06** после починки findings (хотя строго говоря batch findings не блокирует) |

**Чек-лист этапа 5:** [`docs/superpowers/plans/2026-05-29-stage5-monitoring-checklist.md`](../plans/2026-05-29-stage5-monitoring-checklist.md)

**Автомонитор:** [`/.github/workflows/stage5-daily-monitor.yml`](../../../.github/workflows/stage5-daily-monitor.yml) — cron `0 6 * * *` (06:00 UTC = 09:00 МСК) до 05.06.2026, гонит 3 артизан-проверки + 4 SQL-сигнала, результат в job summary + artifact.

### Трек B — Findings (день 1, P1)

| Finding | Root cause | План починки | Срок |
|---|---|---|---|
| 1. audit-chain mismatch на `activity_log_y2026_m05` (id=599) и `balance_transactions_y2026_m05` (id=462) | Race condition в `audit_chain_hash()` trigger: concurrent webhook handler'ы получают одинаковый prev_log_hash → ветвление цепи | [`docs/superpowers/plans/2026-05-29-audit-chain-race-fix.md`](../plans/2026-05-29-audit-chain-race-fix.md) — 4 task'а, 4-6 часов TDD | Желательно до Stage 5 (152-ФЗ compliance) |
| 2. failed_webhook_jobs 256k за 30ч, 99.99% от 2 застрявших supplier_leads id=1110, 1157 | Поставщик шлёт B1+SMS combo (phone `7933***4038`, проект «&lt;client-project&gt;.рф»), constraint `chk_supplier_projects_b1_not_for_sms` запрещает → app кидает Exception → 3 retries → 1 failed_webhook_jobs row; повторяется ~25k раз/час | [`docs/superpowers/plans/2026-05-29-supplier-webhook-fast-fail-and-stuck-cleanup.md`](../plans/2026-05-29-supplier-webhook-fast-fail-and-stuck-cleanup.md) — 4 task'а, 1-2 часа кода + 5 мин cleanup | Срочный cleanup 1110/1157, fast-fail код параллельно с Stage 5 окном |

**Findings полные сырые данные:**

- Round 1: GH Actions run `26613816587` (initial dry-run) + `26614806008` (daily-monitor signals)
- Round 2: run `26614116925..26614124092` (3-х параллельный day-1 check)
- Round 3 investigation: run `26616154527` (audit-chain) → `26616453653` (схема race-condition) → `26616602381` (full SELECT *)

### Трек C — Инфраструктура: SSH-фильтр YC backbone

| Чек | Статус |
|---|---|
| Диагностика | ✅ Подтверждено через 2 раунда workflow на проде: фильтр НЕ на сервере (whitelist в fail2ban + iptables INPUT ACCEPT + пакетный-фильтр addr-set-sshd без нас + hosts.deny пуст + sshd_config без AllowUsers). Наш TCP-handshake проходит (middlebox отвечает), но banner не доходит до sshd-процесса. Фильтр на стороне YC. |
| Попытка Cloudflare WARP | ❌ Exit 1603 на `ConfigureServiceCA`, две попытки. **Windows Server 2022 Standard Evaluation не поддерживает WARP** (не пытаться второй раз). |
| Обход через GitHub Actions runner | ✅ [`.github/workflows/artisan-run.yml`](../../../.github/workflows/artisan-run.yml) — whitelist read-only/dry-run команд + confirm_apply=true для mutating. Базовая команда: `gh workflow run artisan-run.yml -f command="<artisan>"`. |
| YC support ticket для постоянного фикса | ✅ Текст готов: [`docs/support/2026-05-29-yc-ssh-filter-ticket.md`](../../support/2026-05-29-yc-ssh-filter-ticket.md). **Заказчик** копирует «Тело обращения», шлёт со своего `Sasha261185@yandex.ru` через консоль YC → Поддержка. Срок ответа 1-3 рабочих дня. |

---

## 2. Что от заказчика ждёт действия

| Действие | Когда | Где |
|---|---|---|
| Отправить YC support текст | Сейчас (1-3 дня на ответ YC) | Текст в `docs/support/2026-05-29-yc-ssh-filter-ticket.md` § «Тело обращения» |
| Утвердить план починки Finding 1 (audit-chain race) | До Stage 5 переключения | План в `docs/superpowers/plans/2026-05-29-audit-chain-race-fix.md` |
| Утвердить план починки Finding 2 (webhook storm) | ASAP (cleanup 1110/1157 — 5 мин) | План в `docs/superpowers/plans/2026-05-29-supplier-webhook-fast-fail-and-stuck-cleanup.md` |
| Решить с поставщиком про B1+«ваши деньги» SMS-mapping | Параллельно с Finding 2 fix | Out-of-scope этого плана, бизнес-задача |
| Проверять автоотчёты автомонитора по утрам | Ежедневно 29.05-04.06 | GH Actions → workflow `Stage 5 daily monitor` → последний run → Summary tab |

---

## 3. Какую команду в следующей сессии вероятно дать первой

| Команда заказчика | Что Claude сделает |
|---|---|
| **«память дамп»** или **«memory dump»** | Применит entries из §5 этого файла (4 memory-файла + MEMORY.md index update) |
| **«чини finding 2»** | Открывает план Finding 2, исполняет Task 1 (cleanup 1110/1157 через SQL-runner) — 5 минут |
| **«чини finding 1»** | Открывает план Finding 1, начинает с Task 1 (воспроизводящий тест race-condition) — отдельная PR-сессия |
| **«как там этап 5»** | Берёт последний автомонитор run, смотрит сигналы, сравнивает с триггерами в чек-листе, докладывает GO/NO-GO |
| **«SSH теперь работает»** (YC снял фильтр) | Проверяет `ssh -i ~/.ssh/liderra_deploy ubuntu@111.88.246.137 'echo OK'`, обновляет память про YC fix |

---

## 4. Список созданных артефактов сессии

**Workflows (`.github/workflows/`):**

- `artisan-run.yml` — универсальный артизан-runner с whitelist
- `ssh-diagnose.yml` — диагностика SSH-блока (17 проверок)
- `stage5-daily-monitor.yml` — автоматический cron-мониторинг
- `stage5-investigate-day1.yml` — three-round расследование findings (последний state — round 3 schema discovery)

**Docs:**

- `docs/superpowers/plans/2026-05-29-stage5-monitoring-checklist.md`
- `docs/superpowers/plans/2026-05-29-audit-chain-race-fix.md`
- `docs/superpowers/plans/2026-05-29-supplier-webhook-fast-fail-and-stuck-cleanup.md`
- `docs/support/2026-05-29-yc-ssh-filter-ticket.md`
- `docs/superpowers/handoffs/2026-05-29-session-handoff.md` (этот файл)

**Не сохранено в git / не обновлено (нужен memory dump в новой сессии):**

- 4 memory entries — см. §5 ниже

---

## 5. Готовые memory entries для копирования в новой сессии

В следующей сессии при команде «memory dump» применить эти entries:

### 5.1 — `memory/feedback_warp_server_2022_eval.md` (новая)

```yaml
---
name: warp-server-2022-eval-infeasible
description: Cloudflare WARP не устанавливается на этой dev-машине (Windows Server 2022 Standard Evaluation) — exit 1603 на ConfigureServiceCA шаге MSI; не пытаться второй раз
metadata:
  type: feedback
---
```

**Body:** WARP install проваливался 2 раза (29.05.2026 ~05:00 UTC) с одинаковым exit 1603 на `CustomAction ConfigureServiceCA returned actual error code 1603`. LaunchCondition pass'нул (т.е. MSI не считает Server SKU явным блокером), падение на регистрации службы в SCM. Очистка residual `WarpJITSvc` + reg keys не помогла. **Не предлагать WARP как путь решения** на этой машине. Альтернативы: GH Actions workflow паттерн (работает), YC support ticket (фундаментальный фикс), Tailscale (поддерживает Server SKUs, не пробовал).

**Why:** Two confirmed failed attempts with same error point, removing rationalization for trying a third time.

**How to apply:** Если встаёт вопрос «как поменять egress IP с dev для обхода прод-блокировки» — сразу к alternative вариантам без WARP.

Links: [[project_stage5_findings]], [[feedback_github_actions_deploy]].

### 5.2 — `memory/project_artisan_run_workflow.md` (новая)

```yaml
---
name: artisan-run-workflow
description: GH Actions workflow `.github/workflows/artisan-run.yml` — единственный канал артизан-команд на проде пока SSH-фильтр YC не снят; whitelist read-only/dry-run + confirm_apply=true для mutating
metadata:
  type: project
---
```

**Body:** На проде liderra.ru артизан-команды запускаются через `gh workflow run artisan-run.yml -f command="<команда>" [-f confirm_apply=true]`. Whitelist read-only: migrate:status, route:list, schedule:list, queue:listen --help, about, env:show, config:show, cache:table, view:cache, optimize:status, snapshot:backfill, scheduler:check-heartbeats, incidents:watch-failures, supplier:rekey-orphans --dry-run, audit:verify-chains. Whitelist mutating (требует confirm_apply=true): supplier:rekey-orphans (без --dry-run), cache:clear, view:clear, config:clear, route:clear, optimize:clear, optimize, queue:restart, partitions:create-months, partitions:drop-old. Команда передаётся через base64-encoding для сохранения пробелов в SSH. Output в job summary + artifact (retention 30 дней).

**Why:** Прямой SSH с dev-IP 89.144.17.119 заблокирован YC backbone-фильтром (TCP-handshake проходит, banner не доходит до sshd). GH Actions runner — внешний по отношению к YC, его IP не блокируется. После того как YC support снимет фильтр — workflow остаётся как backup.

**How to apply:** Любая прод-операция через артизан (debug, migrate:status, supplier команды) — через `gh workflow run artisan-run.yml`. Расширять whitelist при необходимости. Для произвольного SQL — нужен отдельный SQL-runner workflow (см. план Finding 2 Task 1 Step 1).

Links: [[feedback_warp_server_2022_eval]], [[feedback_github_actions_deploy]].

### 5.3 — `memory/project_stage5_findings.md` (новая)

```yaml
---
name: stage5-findings-2026-05-29
description: День 1 мониторинга этапа 5 (29.05.2026) нашёл 2 P1 — audit_chain_hash race condition (битые цепи в _y2026_m05 партициях) + webhook storm 256k от 2 застрявших supplier_leads id=1110/1157 (B1+SMS combo, constraint chk режет); ни один не блокирует переключение в batch, но желательно починить
metadata:
  type: project
---
```

**Body:**

**Finding 1 (audit-chain race):** `audit:verify-chains` показывает 6 mismatch в `activity_log_y2026_m05` (first id=599, 25.05 15:30:44 UTC) и 6 в `balance_transactions_y2026_m05` (first id=462). Колонка hash — `log_hash bytea`. Триггер `audit_chain_hash()` на месте. Root cause: trigger читает `prev_log_hash` без блокировки → concurrent INSERT'ы (5 за 2 секунды в id 597-601) получают одинаковый prev_hash → ветвление. Last validator success = 25.05 01:00 UTC. План фикса: `docs/superpowers/plans/2026-05-29-audit-chain-race-fix.md` (advisory lock в trigger + artisan `audit:rebuild-chain --partition=X --from-id=N`).

**Finding 2 (webhook storm):** failed_webhook_jobs накопил 256818 строк total, 163k за 24h. **Только 2 supplier_lead_id** дают 99.99%: id=1110 (152464) и id=1157 (104318), оба `phone=7933***4038, platform=B1, project=B1_&lt;client-project&gt;.рф`, error «B1 platform does not support SMS signals» (constraint `chk_supplier_projects_b1_not_for_sms`). Поставщик ретраит ~25k/час. План фикса: `docs/superpowers/plans/2026-05-29-supplier-webhook-fast-fail-and-stuck-cleanup.md` (cleanup 1110/1157 через SQL-runner + fast-fail в job handler).

**Impact на этап 5:** Stage 5 переключение `online → batch` НЕ блокируется ни одним findings. Batch даже снижает частоту race-condition'ов (вместо real-time concurrent webhooks → batch раз в день, low concurrency). Финальный срок: Finding 2 cleanup сейчас, Finding 1 fix отдельным PR-окном, Stage 5 переключение ~07.06.

**Why:** Без записи этого в память — следующая сессия не будет знать что эти 2 P1 уже расследованы до root cause и есть готовые планы.

**How to apply:** При вопросе «как там этап 5» — проверять через `gh workflow run stage5-daily-monitor.yml`, смотреть auxiliary signals (failed_webhook_jobs count + scheduler_heartbeats consecutive_failures), сравнивать с этими known findings. Если найдены НОВЫЕ паттерны — отдельная инвестигация.

Links: [[project_slepok_protection]], [[artisan-run-workflow]], [[project_supplier_webhook_fixes]].

### 5.4 — `MEMORY.md` index updates

Добавить новые строки в MEMORY.md:

```markdown
- [WARP infeasible on Server 2022 Eval](feedback_warp_server_2022_eval.md) — НОВОЕ 29.05.2026: Cloudflare WARP не ставится (exit 1603 ConfigureServiceCA), не пытаться второй раз; альтернатива — GH Actions workflow паттерн
- [Artisan-run workflow](project_artisan_run_workflow.md) — НОВОЕ 29.05.2026: `gh workflow run artisan-run.yml -f command="..."` — единственный канал артизан на проде пока SSH фильтр YC не снят; whitelist read-only + confirm_apply=true для mutating; base64-encoding команды
- [Stage 5 findings (day 1)](project_stage5_findings.md) — НОВОЕ 29.05.2026: 2 P1 — audit_chain_hash race в _y2026_m05 партициях + webhook storm 256k от 2 застрявших supplier_leads (B1+SMS); планы починки готовы, Stage 5 не блокируется
```

---

## 6. Что в этой сессии НЕ удалось

- ❌ Cloudflare WARP — exit 1603, не Server 2022 Eval совместимо.
- ⏸ Memory entries не записаны (требуется override «memory dump», который в этом ходе заказчик не дал — отложено в новую сессию).
- ⏸ Стиль работы «максимально самостоятельно» прерывался каждые 2-3 действия из-за override-механики хуков (срочно / ремонт инфраструктуры / chain-override). Это **нормально** для prod-affecting операций, но утомительно. Если в новой сессии Stage 5 действия — стоит начинать с явного «ремонт инфраструктуры» в первом промпте от заказчика чтобы избежать loop'а.

---

## 7. Ссылки на оригинал сырых данных

- Investigation Round 1 (artifact `investigate-day1`): https://github.com/CoralMinister/lidpotok/actions/runs/26613816587
- Round 2 (`investigate-day1-round2`): https://github.com/CoralMinister/lidpotok/actions/runs/26616453653
- Round 3 (`investigate-day1-round3`): https://github.com/CoralMinister/lidpotok/actions/runs/26616602381
- Daily monitor first run: https://github.com/CoralMinister/lidpotok/actions/runs/26614806008
- Diagnose SSH 1: https://github.com/CoralMinister/lidpotok/actions/runs/26613016471
- Diagnose SSH 2: https://github.com/CoralMinister/lidpotok/actions/runs/26613087121

Артифакты хранятся 14-30 дней — если понадобится после, переснять через `stage5-investigate-day1.yml` workflow_dispatch.
