WEB board

всеканоны и докиворкеры↗ iOS↗ Легаси
WEB-470 · Задача · — · web

Репетиция аварии (DR-rehearsal) на Oracle A2 из бэкапов Hetzner Storage Box — фаза 1: сайт + БД + воркеры; замер RPO/RTO против целей 5 мин / 15 мин (owner GO 02.09 07:46Z «Да планируй»)

В работе P1 · важно ведёт: — эпик: WEB-282
Суть
## Суть одной фразой
Репетиция аварии на A2 из бэкапов Hetzner (фаза 1: сайт + БД + воркеры) с замером RPO/RTO против целей владельца 5 мин / 15 мин.

## Где мы сейчас (13.09.2026)
Фазы 1/1b/1c выполнены: RESTORE PASS (t_restore 232с), тёплый путь RTO 4–7 мин (бюджет ≤8), холодный 16–17 мин. Но ПОЛНЫЙ чистый прогон до /api/ready/paid=200 со свежим замером RPO/RTO НЕ проведён. Замер 04.09: точка ~24 мин позади (цель RPO 5), распаковка 14.5 мин (цель RTO 15) — цели НЕ достигнуты. env-pack на дефект сортировки — проверено, дефекта нет (имена timestamp-first).

## Хронология
Фаза 1 (02.09 ручная) → 1b (1196→1210→1218→GO 1222, l91 9ad68bc2) → 1c (1257/1269→GO 1277, warm-pull) → репетиция r1c RESTORE PASS t_restore 232с → дефект приложения (1361/1404) → 04.09 invalidated (точка ~24 мин / распаковка 14.5 мин) → мойки 12.09 (3566) и 13.09 (3631): остаётся полный прогон до paid=200.

## Карта документов и кода
/usr/local/libexec/hetzbk-{restore,rehearse,warm-pull,env-pack,publish-*}; отчёты ACCDRREHEARSAL*, HETZBKWARMBASE*; брифы 1775 (ретенция), 1776 (каденция манифеста); HA-RUNBOOK.md (A2), RESURRECTION-RUNBOOK.md (Storage Box).

## Остаток
- Полный прогон репетиции до /api/ready/paid=200 с JSON rehearsal-<run-id>.json (rto_total/rpo_seconds) — волна/координатор (прод A2, ⛔ мойке).
- Завести приёмку 1775 (ретенция) — координатор.
- Дождаться 1776 (каденция манифеста) — координатор.

## Критерий закрытия
Свежий прогон до paid=200 с rpo_seconds ≤ 300 и rto_total ≤ 900 по тёплому пути + приёмка 1775 GO + 1776 завершена.
---
_история_ — прежний текст тела (до 13.09.2026) координатор сохраняет ниже этой строки без изменений (append-only по WEB-449).

---

## история (тело до 13.09.2026)

Репетиция аварии (DR-rehearsal) на Oracle A2 из бэкапов Hetzner Storage Box — фаза 1: сайт + БД + воркеры; замер RPO/RTO против целей 5 мин / 15 мин (owner GO 02.09 07:46Z «Да планируй»)

Контекст: пункт эпика миграции WEB-282 «резерв вне Oracle»: AWS EC2 квота не выдана; Hetzner ARM (CAX) не продаётся (ответ поддержки 02.09 + проверка консоли: недоступен во всех локациях; x86 CX23 5.49€ доступен). Решение с owner-ом: репетицию восстановления делать на A2 (ARM, честно к артефактам), покупку x86 не делать; «резерв вне Oracle» остаётся открытым.

Ограничения: A2 живой пассив (nc-a2 :3010 l81b, standby PG 55433 — реплика A1, туннели a1-tunnel 55432/6379) НЕ трогать; репетиция в песочнице: PG-кластер на 55481 (hetzbk-restore --port), приложение на 3012, Redis отдельный порт/DB; никакого DNS/UFW/промоута; split-brain запрещён (две активные копии — никогда).

План фазы 1: (0) предпосылки на A2: /etc/hetzbk (env, keys/backup.pass, ssh/storagebox) — секреты переносятся ssh-пайпом A1→A2 без печати; /usr/local/libexec/hetzbk-* + lib; (1) hetzbk-restore --base <последний base> --manifest <последний> --target /var/lib/postgresql/16/rehearsal --target-lsn <LSN на момент T0> --port 55481 → замер времени (RTO-часть БД) и отставания (RPO = T0 − последний WAL на Storage Box); (2) артефакт релиза l89 с Storage Box (после WEB-469: залить) → распаковать в /home/ubuntu/rehearsal/releases, env из шаблона CONFIG-TEMPLATE + секреты (ЧТО из секретов не в бэкапе — зафиксировать как находку), enforce-обёртка + подписанная активация (нужна подпись owner-ключом на ноуте под identity A2-rehearsal); (3) старт на :3012 → /api/health, /api/ready, /api/ready/paid (ожидаем posture по факту), воркер индексации в dry-run; (4) отчёт: таймлайн, RPO/RTO, список находок (чего не хватает в бэкапе), стоимость; (5) снести песочницу.
Фаза 2 (отдельный тикет после фазы 1): телефония (Asterisk из /home/pi/ag-voice — не в релизе), мессенджеры (Telegram-сессии/Signal — одна активная копия!), почта (MX/DNS).

Доки: A2 /home/ubuntu/HA-RUNBOOK.md (промоут A2 — НЕ то же, что репетиция), Storage Box /home/app-artifact/RESURRECTION-RUNBOOK.md (25.08), /usr/local/libexec/hetzbk-restore (A1). Память: owner-recovery-targets-20260821, hetzner-primary-backup-decision, a2-standby-db-replica.

## ЭВОЛЮЦИЯ 04.09.2026 (карта для нулевого агента)
**Якорь прода:** живая линия **l103**, коммит **d91ebefe740ae83484c1de16710f2e6a68610432**, флип **13:51Z 04.09**. Раньше в этот же день: l101 `d825eb0d`, l102 `1b081c5a`. Ветка линии в репозитории-базе `/home/ubuntu/nc` на A1: `l103-line` (проверено `git branch -a --contains d91ebefe...` → `l103-line`).
**Доска:** живая доска — `web-board.sqlite` + HTTP API `http://127.0.0.1:8787/api/web/*` на M1 (`ssh poolpooly@192.168.1.74`). НЕ `board.sqlite` (это iOS/легаси, таблицы `issues`/`ios_issues`, 2225 строк, ключи другие).

### СЕЙЧАС
Репетиция аварии из бэкапов Hetzner Storage Box за 04.09 продвинулась на 4 блокера подряд. Первые три сняты, четвёртый (проигрывание WAL) вскрыт, первопричина доказана, фикс отдан в волну. До конца репетиция ещё не доходила.

### ЧЕТЫРЕ БЛОКЕРА В ПОРЯДКЕ ВСКРЫТИЯ
1. Для живой линии не был опубликован env-пакет (без него репетиция стартовать не может).
2. Артефакт релиза НЕ ВЫЖИВАЛ на хранилище.
3. Префлайт отвергал значение порт-контракта.
4. Проигрывание WAL падает с `FATAL rc=96` (открыт, диагностирован).

### ПРИЧИНА #2 — ДОКАЗАНА: публикация сама удаляет только что опубликованный релиз
Лог: `ARTIFACT retention removed release_id=l102-1b081c5a keep=5`, непосредственно перед ним подряд:
`rm .../ready`, `rm .../att-build.json`, `rm .../artifact.tar.gz.sha256`, `rm .../artifact.tar.gz`, `rmdir .../l102-1b081c5a`.

Код (A1, `/usr/local/libexec/hetzbk-publish-artifact`, 5170 байт, mtime 2026-09-03 05:49):
- строка **85**: `# Release IDs are intentionally timestamp-first in the runbook. Only complete`
- строка **96**: `' | LC_ALL=C sort -r)` — листинг релизов сортируется по имени в обратном порядке
- строка **104**: `log "ARTIFACT retention removed release_id=$old keep=5"`

Разрыв между комментарием и реальностью: реальные release_id — **line-first** (`l102-1b081c5a`), а не timestamp-first. При `sort -r` свежий релиз оказывается ПОСЛЕДНИМ в списке и вычищается ПЕРВЫМ.

Доказательство экспериментом: опубликовали → листинг каталога релизов на хранилище ПУСТ; опубликовали копией скрипта с отключённой ретенцией → все четыре файла (`artifact.tar.gz`, `artifact.tar.gz.sha256`, `att-build.json`, `ready`) на месте.

**Тот же класс рядом, проверить:** `/usr/local/libexec/hetzbk-env-pack` строка **346** `# The remote namespace is timestamp-first by contract, so lexical descending`, строка **355** `... | LC_ALL=C sort -r)`, строка **362** `log "ENV PACK retention removed package=$old keep=10"`. Если имена env-пакетов тоже не timestamp-first — блокер #1 («нет env-пакета для живой линии») объясняется тем же дефектом.

### ПРИЧИНА #4 — ДОКАЗАНА: не разрыв WAL, а рассинхрон каденций
Сообщение: `FATAL rc=96 WAL manifest has a gap before latest archive end at segment 000000010000000300000023`.
Разрыва НЕТ: сегменты …00000022, …00000023, …00000024 присутствуют и на Storage Box, и в `manifest-20260904T141231Z/manifest.tsv`.
Настоящая причина: манифесты публикуются примерно раз в час (наблюдённые метки 10:12, 11:13, 12:13, 13:12, 14:12), а WAL-сегменты архивируются каждые 3–4 минуты. Цель `latest`, вычисленная по ЖИВОМУ архиву, принципиально не может валидироваться против ЧАСОВОГО манифеста — «gap» будет всегда.

### РЕШЕНИЕ OWNER (04.09)
1. Цель восстановления брать ИЗ МАНИФЕСТА, а не из живого архива.
2. Поднять частоту публикации манифеста ближе к каденции архивирования WAL.

### ЦЕЛИ ВОССТАНОВЛЕНИЯ — НЕ ВЫПОЛНЕНЫ
Цели owner: RPO 5 минут, RTO 15 минут. Замер утра 04.09: ближайшая восстановимая точка ~**24 минуты** позади; одна только распаковка базы съела **14.5 минуты** (то есть весь бюджет RTO уходит на распаковку, до старта служб дело не доходит).

### ЧТО СДЕЛАНО И ГДЕ
- Волна **`1775-hetzbkretention`** (ретенция артефактов) — ЗАВЕРШЕНА на A1. `/home/ubuntu/waves/queue/dispatcher.log`: `2026-09-04T14:24:01Z started: label=1775-hetzbkretention route=codex model=gpt-5.6-luna effort=xhigh` → `2026-09-04T14:36:21Z done: label=1775-hetzbkretention brief=1775-hetzbkretention-brief.md cleaned=1`. Бриф уехал в `/home/ubuntu/waves/queue/done/1775-hetzbkretention-brief.md`. **Приёмка НЕ заведена.**
- Волна **`1776-manifestcadence`** (каденция манифеста) — ИДЁТ. `2026-09-04T14:57:51Z started: label=1776-manifestcadence route=codex model=gpt-5.6-luna effort=xhigh running=1`; файл `/home/ubuntu/waves/queue/running/1776-manifestcadence-brief.md.run`.
- В l103 уже лежит смежная правка: `d91ebefe fix(hetzbk): clean interrupted artifact manifest sidecars`.

### ЧТО ОСТАЛОСЬ — КОНКРЕТНЫЕ ДЕЙСТВИЯ
1. Завести приёмку 1775. Позитив: опубликовать релиз и СРАЗУ сделать листинг каталога релизов на Storage Box — должны быть все 4 файла, а в логе НЕ должно быть `ARTIFACT retention removed` для только что созданного release_id. **Негатив (обязателен):** опубликовать 6 релизов подряд — удалиться должен САМЫЙ СТАРЫЙ, а не самый новый.
2. Проверить `hetzbk-env-pack:346-362` на тот же дефект сортировки; если он там есть — закрыть тем же кругом.
3. После 1776 — прогнать репетицию до конца и заново замерить RPO/RTO против целей 5/15.

### ЛОВУШКИ
- Симптом выглядит как «публикация не сработала», хотя публикация отработала: смотреть НЕ на шаг публикации, а на шаг ретенции сразу после него.
- «Gap в WAL» — ложное сообщение. Не идти искать потерянные сегменты: их нет, они на месте. Искать несовпадение каденций.
- Репетиция ≠ промоут A2. Промоут описан в `/home/ubuntu/HA-RUNBOOK.md` на A2 — это другая процедура.
- Скрипты живут в `/usr/local/libexec/` и правятся под root. **У волн root нет** — установку на хост делает координатор, а не волна. Бриф, требующий от волны установки на хост, будет отклонён по невозможности.
- Не трогать `hetzbk-*.bak-*` — это откатные копии (`hetzbk-rehearse.bak-20260904`, `hetzbk-base.bak-retain5-20260901`, `hetzbk-restore.bak-20260901`, `hetzbk-wal-stream.bak-20260901`).

---

## ДОПИСКА 05.09.2026 ~00:15 IST (18:45Z 04.09) — координатор: вердикты дня 04.09
Правила обогащения: WEB-449. Эта секция ДОПИСАНА в конец (append-only), ничего выше не перезаписано.

**Ленты дня 04.09 (время UTC / IST = UTC+5:30):**
- **l101 `d825eb0d`** — флип **08:47Z / 14:17 IST**. Девять ранее принятых изменений + фикс realtime-сокета, который отдавал 500 с l96.
- **l102 `1b081c5a`** — флип **11:18Z / 16:48 IST**. Этап C движка, фикс окна цитат, мобильные боковые панели, преflight окна восстановления бэкапа.
- **l103 `d91ebefe`** — флип **13:51Z / 19:21 IST**. Перебазированная работа по ролям, фикс диалога приглашения, фикс контура бэкапа.
- **l104 `4d858be7`** — флип **18:03Z / 23:33 IST**. Проводка движка, регрессионный тест телеграм-бота, фикс ретенции бэкапа.

**Якорь прода на момент записи: линия l104, коммит `4d858be7`.** Отдельных тикетов-линий для l101–l104 на доске НЕТ — журнал посадок ведётся здесь и в [[WEB-320]].

### ВЕРДИКТ ДНЯ: четыре блокера сняты подряд, фикс ретенции сел в l104, цели восстановления НЕ достигнуты
**Кто:** координатор + волны бэкап-контура. **Когда:** 04.09. **Коммит фикса ретенции:** `0b2d6aed`, сел в **l104 `4d858be7`** (18:03Z / 23:33 IST).

### ЧЕТЫРЕ БЛОКЕРА, СНЯТЫЕ СЕГОДНЯ (в порядке вскрытия)
1. Для живой линии **не публиковался пакет окружения**.
2. **Релизный артефакт не выживал на хранилище**.
3. **Преflight отвергал значение контракта порта**.
4. **Проигрывание WAL**.

### БЛОКЕР 2 — ПЕРВОПРИЧИНА ДОКАЗАНА
Шаг публикации сам же и удаляет только что опубликованный релиз: **цикл ретенции сортирует имена релизов в обратном порядке, предполагая, что id начинаются с метки времени, тогда как реальные id начинаются с номера линии** (line-first). При обратной сортировке «самым старым» оказывается самый свежий.

Улика в логе: `ARTIFACT retention removed release_id=l102-1b081c5a keep=5` — **сразу после успешной публикации**.

**Как доказано (воспроизводимо):** опубликовали → сделали листинг хранилища (**пусто**) → опубликовали через копию скрипта с выключенной ретенцией (**все четыре файла на месте**).

**Фикс `0b2d6aed` принят и сел в l104. ВАЖНАЯ ОГОВОРКА: он НЕ едет с артефактом** — standalone-пакет не несёт скриптов `infra/`. То есть посадка линии сама по себе фикс на хост не доставляет; установка на хост остаётся отдельным действием координатора (у волн нет root).

### БЛОКЕР 4 — «GAP В WAL» ОКАЗАЛСЯ ЛОЖНЫМ СООБЩЕНИЕМ
Отказ: `rc=96 WAL manifest has a gap before latest archive end at segment 000000010000000300000023`.
**Разрыва нет:** сегменты 22, 23, 24 присутствуют И на хранилище, И в манифесте.

**Настоящая причина — рассогласование каденций:** манифесты публикуются **раз в час** (10:12, 11:13, 12:13, 13:12, 14:12), а сегменты WAL архивируются **каждые 3–4 минуты**. Цель восстановления, вычисленная по живому архиву, физически не может пройти валидацию против часового манифеста.

Затем следующий прогон упал **в обратную сторону**: цель оказалась РАНЬШЕ стартового сегмента базы — потому что базовые копии снимаются раз в час и уходят вперёд.

**РЕШЕНИЕ ВЛАДЕЛЬЦА:** брать цель восстановления **ИЗ МАНИФЕСТА** и **повысить частоту публикации манифестов**.

### ЦЕЛИ ВОССТАНОВЛЕНИЯ — НЕ ВЫПОЛНЕНЫ
- Ближайшая восстановимая точка — **~24 минуты позади** при цели RPO **5 минут**.
- Только распаковка базы — **14.5 минут** при бюджете RTO **15 минут** (то есть весь бюджет съедает один шаг).

### ЛОВУШКИ (повтор, чтобы не потерять)
- Симптом выглядит как «публикация не сработала», хотя публикация отработала — смотреть на шаг ретенции СРАЗУ ПОСЛЕ публикации.
- «Gap в WAL» — ложная диагностика. Не искать потерянные сегменты, искать рассогласование каденций.
- Фикс в линии ≠ фикс на хосте: `infra/`-скрипты не едут в standalone-пакете.

## ДЛЯ НУЛЕВОГО АГЕНТА (обновлено 2026-09-05 UTC)
- **Суть одной строкой:** Репетиция аварии (DR-rehearsal) на Oracle A2 из бэкапов Hetzner Storage Box — фаза 1: сайт + БД + воркеры; замер RPO/RTO против целей 5 мин / 15 мин (owner GO 02.09 07:46Z «Да планируй»)
- **Текущее состояние:** статус: review; Репетиция аварии (DR-rehearsal) на Oracle A2 из бэкапов Hetzner Storage Box — фаза 1: сайт + БД + воркеры; замер RPO/RTO против целей 5 мин / 15 мин (owner GO 02.09 07:46Z «Да планируй») | Контекст: пункт эпика миграции WEB-282 «резерв вне Oracle»: AWS EC2 квота не выдана; Hetzner ARM (CAX) не продаётся (ответ поддержки 02.09 + проверка консоли: недоступен во всех локациях; x86 CX23 5.49€ доступен). Решение с owner-ом: репетицию восстановления делать на A2 (ARM, честно к артефактам… | Ограничения: A2 живой пассив (nc-a2 :3010 l81b, standby PG 55433 — реплика A1, туннели a1-tunnel 55432/6379) НЕ трогать; репетиция в песочнице: PG-кластер на 55481 (hetzbk-restore --port), приложение на 3012, Redis отдельный порт/DB; никакого DNS/UFW/промоута; split-brain запрещён (две активные к… | План фазы 1: (0) предпосылки на A2: /etc/hetzbk (env, keys/backup.pass, ssh/storagebox) — секреты переносятся ssh-пайпом A1→A2 без печати; /usr/local/libexec/hetzbk- + lib; (1) hetzbk-restore --base <последний base --manifest <последний --target /var/lib/postgresql/16/rehearsal --target-lsn <LSN … | Доки: A2 /home/ubuntu/HA-RUNBOOK.md (промоут A2 — НЕ то же, что репетиция), Storage Box /home/app-artifact/RESURRECTION-RUNBOOK.md (25.08), /usr/local/libexec/hetzbk-restore (A1). Память: owner-recovery-targets-20260821, hetzner-primary-backup-decision, a2-standby-db-replica. | Якорь прода: живая линия l103, коммит d91ebefe740ae83484c1de16710f2e6a68610432, флип 13:51Z 04.09. Раньше в этот же день: l101 d825eb0d, l102 1b081c5a. Ветка линии в репозитории-базе /home/ubuntu/nc на A1: l103-line (проверено git branch -a --contains d91ebefe... → l103-line). | Репетиция аварии из бэкапов Hetzner Storage Box за 04.09 продвинулась на 4 блокера подряд. Первые три сняты, четвёртый (проигрывание WAL) вскрыт, первопричина доказана, фикс отдан в волну. До конца репетиция ещё не доходила. | Лог: ARTIFACT retention removed releaseid=l102-1b081c5a keep=5, непосредственно перед ним подряд:
- **Кто работал:**
- 2026-09-02T09:47:50.580Z — Fable — [02.09 10:20Z Фабл] Фаза 1 СТАРТОВАЛА на A2: набор hetzbk (скрипты + /etc/hetzbk секреты + knownhosts storage box) перенесён с A1 ssh-пайпом под пользователем hetzbk (без печати); настройки прод-PG сняты в /var/lib/hetzb
- 2026-09-02T09:57:08.723Z — Fable — [02.09 10:55Z Фабл] НАХОДКА репетиции (первый прогон restore на A2 упал): /usr/local/libexec/hetzbk-restore после WAL coverage PASS качает ВСЕ wal-строки манифеста (цикл while read … kind=wal … remoteget, строки ~337–349
- 2026-09-02T10:19:14.474Z — Fable — [02.09 11:50Z Фабл] ФАЗА 1 РЕПЕТИЦИИ — РЕЗУЛЬТАТ (A2, песочница, живая реплика/пассив не тронуты): • Вход: base-20260902T090057Z + manifest-20260902T091306Z + wal-partial до целевого LSN 2/541C7DD8 (снят на проде ~09:49 
- 2026-09-02T11:30:07.897Z — Fable — [A1 11:30 Фабл] Фаза 1b запущена как волна 1196-drrehearsal1b на M4 (ветка от web469hetzbk3-1190 = l90 + hetzbk v3): скрипт infra/hetzbk/bin/hetzbk-rehearse (restore → артефакт → env-пакет → redis/app transient units → h
- 2026-09-02T12:42:20.274Z — Fable — [A1 13:00 Фабл] Приёмка 1203-accdrrehearsal1b (M4, дерево от e4af4675): NO-GO — 3 блокера: (1) JSON без канонических ключей rpo/rto (есть rtototal/rpolsn/rposeconds); (2) нет ${VAR:?}-защиты у rm -rf во всём пакете (hetz
- 2026-09-02T12:57:56.753Z — Fable — [A1 13:25 Фабл] Корректировка 1210-drrehearsal1b2 сдана: 8914106b30aebaf3d32a966b2db71d6109e7350b (rpo/rto числовые ключи; ${VAR:?} у всех rm -rf в пакете + grep-тест; APPUIDARGS инициализирован; suite 10→13). Повторная 
- 2026-09-02T13:18:38.694Z — Fable — [A1 13:12 Фабл] Повторная приёмка 1215-accdrrehearsal1b2: NO-GO — три блокера 1203 закрыты (rpo/rto числовые; все 20 rm -rf с :?-guard; fallback без User проходит), но teardown не идемпотентен: второй --teardown при отсу
- 2026-09-02T13:29:36.083Z — Fable — [A1 13:35 Фабл] 1218-drrehearsal1b3 сдана: d6cd351eb9f3a95c16513385bd6955f387c1c8cf (teardowninternal: явный if + return 0; хвостовых ]] && в функциях нет). Повторная приёмка 1222-accdrrehearsal1b3 (M4). Ветка на A2/A1 m
- 2026-09-02T13:40:38.381Z — Fable — [A1 13:42 Фабл] Повторная приёмка 1222-accdrrehearsal1b3 (M4): GO — teardown идемпотентен (0/0, без root 0, чужой root → отказ), хвостовых ]] && нет, прежние блокеры без регресса, тесты пакета зелёные. Cherry-pick в l91 
- 2026-09-02T13:49:00.278Z — Fable — [A1 13:55 Фабл] Слияние 1223-hetzbkmerge сдано: 8879df52 (age-alert cea6cc30+bdd668cc → DR e4af4675/8914106b/d6cd351e cherry-pick -x → merge-fix закрытия test-функций). Единственный конфликт — tests/testhetzbk.sh. Подозр
- 2026-09-02T13:57:42.878Z — Fable — [A1 13:58 Фабл] Приёмка 1227-acchetzbkmerge (A1): GO — наборы тестов обеих линий присутствуют и вызываются (таблица в ACCHETZBKMERGE-REPORT.md §«Состав тестов»), merge-fix 8879df52 — только закрытие функций/guard-ы, логи
- 2026-09-02T14:12:26.031Z — Fable — [A1 14:12 Фабл] ПОСАЖЕНО l91 на прод A1: release arm64-l91-20260902T140416Z, run l91-9ad68bc2, sourceCommit 9ad68bc261c833e792bc17523245975e15f48612, артефакт sha 96b3466b…dc3f; ready TRUE (boot/database/release/drain ok
- 2026-09-02T14:40:27.408Z — Fable — [A1 14:40 Фабл] Фаза 1b на живом A1: install.sh из дерева l91 (backup ops-backups/hetzbk-live-20260902T142912Z), hetzbk-env-pack.timer включён; ПЕРВЫЙ ШИФРОВАННЫЙ ENV-ПАКЕТ на Storage Box: /home/walg-nc/hetzbk-prod-a1/en
- 2026-09-02T15:27:27.425Z — Fable — [A1 15:28 Фабл] Приёмка 1250-acchetzbkagealert3 (A1): age-alert-часть (PGBIN psql, quiet sftp, baseage в секундах, SuccessExitStatus=2) прошла; NO-GO по env-pack: обязательные пути shared/.env.local и shared/run/<line/ о
- 2026-09-02T15:36:55.929Z — Fable — [A1 15:36 Фабл] СОСТОЯНИЕ для нулевого агента (ответ owner-у на «закончился ли стресс-тест»): ФАЗА 1 (ручная, 02.09 ~10:18 A1) закончена — sandbox A2 (PG 55481, app :3012) из бэкапов Storage Box, paid=true; RPO факт 3–6 
- 2026-09-02T15:39:03.136Z — Fable — [A1 15:45 Фабл] Корректировка 1255-hetzbkagealert4 сдана: cccd2ba6 (HETZBKENVFILES с суффиксом ! = required + HETZBKENVREQUIREDFILES; required отсутствуют → FATAL rc=4 без архива; optional → WARN). Повторная приёмка 1258
- 2026-09-02T15:52:52.419Z — Fable — [A1 15:55 Фабл] Приёмка 1258-acchetzbkagealert4 = GO (отчёт A1 /home/ubuntu/waves/ACCHETZBKAGEALERT4-REPORT.md): NO-GO 1250 закрыт — обязательные env-пути (.env, .env.local, shared/run/<line/) больше не проходят как WARN
- 2026-09-02T16:13:51.050Z — Fable — [A1 16:25 Фабл] Фаза 1c сдана: волна 1257-hetzbkwarmbase (M4), коммит 1435c215 (ветка hetzbkwarmbase-1257 поверх принятой hetzbkagealert4-1255). Что внутри: hetzbk-warm-pull (только при HETZBKROLE=passive; тянет новейший
- 2026-09-02T16:35:27.403Z — Fable — [A1 16:40 Фабл] Фаза 1c: приёмка 1267-acchetzbkwarmbase = NO-GO (A1 /home/ubuntu/waves/ACCHETZBKWARMBASE-REPORT.md). Прошло: role guard (rc=8, ExecCondition), идемпотентный pull (5 get, повтор unchanged), битый sha/обрез
- 2026-09-02T17:01:50.876Z — Fable — [A1 17:08 Фабл] Фаза 1c, корректировка после NO-GO 1267 сдана: волна 1269-hetzbkwarmbase2, коммит c669d65ee1 (ветка hetzbkwarmbase2-1269 = 1257r 98a74bf + c669d65e, база принятой hetzbkagealert4-1255). Закрыто: B1 restor
- 2026-09-02T17:20:48.908Z — Fable — [A1 17:40 Фабл] Фаза 1c: приёмка 1277-acchetzbkwarmbase2 = GO (A1 /home/ubuntu/waves/ACCHETZBKWARMBASE2-REPORT.md): B1 manifest-first restore, B2 --dry-run без побочных эффектов, B3 ноль remote за base при валидной warm-
- 2026-09-02T17:27:30.840Z — Fable — [A1 17:52 Фабл] Фаза 1c ВКЛЮЧЕНА на A2: hetzbk c669d65e установлен (A2 passive, A1 active), hetzbk-warm-pull.timer включён; первая тёплая копия: WARM PULL committed base-20260902T170039Z, 1.17 ГБ за 91 с. Проверка: hetzb
- 2026-09-02T17:46:08.891Z — Fable — [A1 17:50 Фабл] Репетиция 1c r1c-20260902T1733Z на A2: warm-путь сработал (basesource=warm, распаковка + 3 WAL-сегмента + partial, PG стартовал ~через 5,5 мин от t0 — против 16 мин холодного пути), но упала rc=95 «restor
- 2026-09-02T17:52:42.931Z — Fable — [A1 18:12 Фабл] Корень провала репетиции 1c ПОДТВЕРЖДЁН репродукцией с сохранённой песочницей (A2 /var/lib/hetzbk/restore/dbg1c/restore-postgres.log): PG «starting point-in-time recovery to LSN 2/80FFFFFF» → сегмент 80 в
- 2026-09-02T18:00:48.514Z — Fable — [A1 18:10 Фабл] Owner 02.09 18:08: «арбитр аренды (A2) — участник процесса: нужна его бэкап-копия, чтобы не пилить заново; топология и документы «как развернуть всё» — рядом с бэкапом или папкой на том же Hetzner». → (1)
- 2026-09-02T18:12:53.991Z — Fable — [A1 18:35 Фабл] Волна 1290-hetzbkwarmbase3 сдана: коммит edf070d639 (ветка hetzbkwarmbase3-1290 поверх принятой 1269). Заявлено: «latest» без синтетической recoverytargetlsn (promote до конца WAL), отказ до старта PG при
- 2026-09-02T18:39:32.659Z — Fable — [A1 18:45 Фабл] Линии hetzbk 1255 (env-pack required) и warm-base 1269 (manifest-first restore) ПОСАЖЕНЫ в прод l92 (9bee5955) как часть репо; на A1/A2 уже стояли из принятых деревьев. Осталось: 1305 (приёмка фикса «late
- 2026-09-02T18:51:13.326Z — Fable — [A1 19:00 Фабл] Приёмка 1305-acchetzbkwarmbase3 = NO-GO (A1 /home/ubuntu/waves/ACCHETZBKWARMBASE3-REPORT.md): PASS — latest без синтетической цели, exact-latest, границы сегментов, падение PG/timeout/сохранение evidence,
- 2026-09-02T19:37:05.723Z — Fable — [A1 20:30 Фабл] Волна 1314-hetzbkwarmbase4 сдана: коммит 585818ecb6 (publisher публикует реальную границу WAL в partial; restore судит по pointer bytes и допускает preallocated 16 MiB; честное копирование evidence; rule1
- 2026-09-02T20:22:03.350Z — Fable — [A1 20:25 Фабл] 1299-drdocspack сдана: коммит 14672d63ef (M4) — пакет DR-документации (топология, восстановление с нуля, две линии DR: A2 takeover vs Hetzner restore, БД/миграции, dev/prod, вопросы owner-а 02.09) в docs/
- 2026-09-02T20:34:08.253Z — Fable — [A1 20:45 Фабл] Репетиция 1c на A2 с принятым кругом 4 (1314, установлен на A1/A2): run r1c-20260902T203100Z. Результат: RESTORE PASS — база из тёплой копии base-20260902T200104Z (warm) + manifest-20260902T201219Z, walse
- 2026-09-02T20:37:23.052Z — Fable — [A1 20:40 Фабл] Закрыл два пробела посадки: (1) HETZBKENVLINE на A1 указывал на l91 → переведён на l93-02d032e4, env-pack прогнан (retention 10); (2) артефакт приложения l93 опубликован на Storage Box: /home/app-artifact
- 2026-09-02T20:51:20.634Z — Fable — [A1 20:55 Фабл] Репетиция l93 r1c-20260902T204000Z: RESTORE PASS повторно (trestore 232 с), артефакт/энв-пак l93 подхвачены (app/shared/run/l93-02d032e4 распакован), но стадия приложения упала: hetzbk-rehearse берёт Exec
- 2026-09-02T20:59:16.442Z — Fable — [A1 21:00 Фабл] Приёмка 1338-accdrdocspack = NO-GO (M4, 6 критических находок: bare dry-run команды невыполнимы, критические факты не заполнены, предметная полнота отсутствует, имена units не дают топологии, Storage Box 
- 2026-09-02T21:02:09.544Z — Fable — [A1 21:05 Фабл] Репетиции r1c-20260902T204000Z и …205500Z: RESTORE PASS ×2 (trestore 232 с), стадия приложения падает и с обходом: hetzbk-rehearse:333 перебивает HETZBKREHEARSALAPPCOMMAND значением из шаблона nc-a2.servi
- 2026-09-02T22:00:10.146Z — Fable — [A1 22:45 Фабл] Волна 1361-hetzbkwarmbase5 сдана: коммит e1977830a2 (приоритет источников команды старта приложения, preflight template↔line, раскладка releases/<name, критерий PASS = /api/health + /api/ready, tappstart/
- 2026-09-02T22:46:47.084Z — Fable — [A1 01:35 Фабл] Приёмка 1390-accdrdocspack2 = NO-GO (M4, отчёт /Users/milamarty/waves/ACCDRDOCSPACK2-REPORT.md): круг 2 убрал bare-вызовы и литеральные placeholders, но обе DR-линии имеют детерминированные точки остановк
- 2026-09-02T22:48:53.713Z — Fable — [A1 01:50 Фабл] Приёмка 1382-acchetzbkwarmbase5 = NO-GO формально: функционал круга 5 (приоритет команды старта, preflight template↔line, раскладка releases/<name, PASS по /api/health+/api/ready, RTO) доказан, регрессии 
- 2026-09-02T23:50:55.215Z — Fable — [A1 05:40 Фабл] Волна 1404-hetzbkwarmbase6 сдана: коммит 4b667525f8 (APPSTARTNS используется для tappstart, shellcheck чист). Приёмка 1421 (A1, Sol medium, в очереди) → install на A2/A1 → репетиция l94 (r1c) с полным RTO
- 2026-09-03T00:14:44.541Z — Fable — [A1 07:05 Фабл] Волна 1402-drdocspack3 сдана (перезапуск после потери worktree): коммит 346f1018cd (6 required fixes, evidence land-l93/l94.sh + publish-release). Приёмка 1429 (M4, Sol high, в очереди) → публикация docs/
- 2026-09-03T00:36:23.329Z — Fable — [A1 09:00 Фабл] Приёмка 1429-accdrdocspack3 = NO-GO (M4, отчёт /Users/milamarty/waves/ACCDRDOCSPACK3-REPORT.md): fixes 4 (env-pack с service-identity/embedding-integrity) и 5 (один artifact key = line-id) закрыты; открыт
- 2026-09-03T01:51:14.973Z — Fable — [M4 11:35 Фабл] Волна 1436-drdocspack4 сдана (6320e132, шесть required fixes, testhetzbk 19 passed) → приёмка 1444 (M4, Sol). В брифе приёмки: сверить с разрывом раскладки репетиции (WEB-469 круг 7).
- 2026-09-03T02:47:52.869Z — Fable — [M4 Фабл] Приёмка 1444-accdrdocspack4 = NO-GO (6320e132): fixes 1,2,3,5,6 закрыты; fix 4 нет — takeover B не самодостаточен (нет точных источников A2 unit/drop-in/landing и материализации артефакта в раскладку релиза), н
- 2026-09-03T03:06:48.667Z — Fable — [Фабл] Волна 1453-drdocspack5 сдана: коммит a3505dd1 (находка репетиции 03.09 занесена, B2 самодостаточен, переход с l81). Приёмка 1457 (M4, Sol medium) в очереди.
- 2026-09-03T03:11:48.282Z — Fable — [M4 Фабл] Приёмка 1457-accdrdocspack5 = GO (независимая, Sol): находка репетиции 03.09 занесена, takeover B самодостаточен, переход с l81 описан и покрыт тестом. Коммит a3505dd1 → в l95-candidate (docs/tests); публикация
- 2026-09-03T03:13:29.992Z — Fable — [A2 Фабл] Опубликовано рядом с бэкапами Hetzner: $HETZBKREMOTEROOT/docs/docs-l94-b1962b8d-20260903T031243Z.tar (+ .tar.sha256; docs/dr из a3505dd1, git archive; sha256 25c49deb…). Cherry-pick в l95: линия (18 коммитов от
- 2026-09-03T16:16:09.991Z — coordinator — 03.09 21:45 IST. Круг 13 hetzbk сдан на M4 коммитом df979b2a10e2cec1336995376fc0c4ba8b505f1b (отчёт /Users/milamarty/waves/HETZBK13-REPORT.md), НО M4 (192.168.1.110) сейчас недоступен по сети — ping 100% потерь, ssh тайм
- 2026-09-03T19:13:19.194Z — coordinator — Статус 03.09 19:12Z: круг 13 (df979b2a) был сдан на M4, но M4 упал — коммит и отчёт оказались заперты, приёмка не ставилась ~2 часа. M4 перезапущен owner-ом, приёмка круга 13 запущена (волна 1591 на M4). Напоминание конт
- 2026-09-03T22:36:19.569Z — coordinator — Круг 14 сдан: коммит 1aabe101 «document intentional shellcheck diagnostics». Напоминание: круг 13 (df979b2a) закрыл ФУНКЦИОНАЛЬНЫЙ блокер — внутренний разрыв WAL обнаруживается, ретрай включается, вечный разрыв даёт 3×re
- 2026-09-03T22:59:33.248Z — coordinator — Приёмка круга 14 (волна 1603 на M4) = GO для 1aabe101. Единственный блокер круга 13 — буквальный shellcheck -x — закрыт: rc=0 по всем семи .sh, функциональная часть не затронута, остальные обязательные проверки PASS. Стр
- 2026-09-03T23:14:05.492Z — coordinator — Живой прогон репетиции на A2 по линии l97-9d69d2a0 (после GO приёмки круга 14): rc=95 на старте восстановленного PostgreSQL. Расписка: pgctl -w start (дефолт 60 с) объявил 'server did not start in time', при этом в логе 
- 2026-09-04T00:09:42.211Z — coordinator — Круг 15 сдан: коммит 72e654cd — чинит ДВА дефекта инструмента, найденных живым прогоном 03.09: (1) pgctl -w start с дефолтом 60 с объявлял ложный провал, пока PostgreSQL реально поднимался (pre-fsync 39.98 с, pgctl statu
- 2026-09-04T15:08:17.132Z — coordinator — 04.09 координатор: в body добавлен блок «ЭВОЛЮЦИЯ 04.09.2026» — состояние, причина с доказательством, что село, что осталось, ловушки.
- 2026-09-04T22:58:41.917Z — координатор — Резервный контур A1, 22:57Z 04.09. (1) Скрипты /usr/local/libexec/hetzbk- стояли от 03.09, тогда как в линии l105 сидели принятые правки (hetzbk-restore +500 строк, hetzbk-rehearse +340, wal-stream +17) — посадка релиза 
- 2026-09-04T23:31:46.901Z — координатор — HETZBKMERGE (1875, A2) — GO, commit fc0fb6deab3c99425acea1164cbca027df07dd93 на базе l105: оба принятых фикса удержания (88521289f HETZBK26; c3019164 + a9b16c593 MANIFESTCADENCE2, приёмка ACCMANIFESTCADENCE3 GO) сведены 
- 2026-09-04T23:51:41.685Z — координатор — ACCHETZBKMERGE (1876, A1) — VERDICT=NO-GO для fc0fb6de. Подтвердилось: ретеншн по publishedat работает и уже на линии (вклад кандидата — диагностика); точка восстановления из манифеста; 6/6 и 2/2 новых теста зелёные (на 
- 2026-09-05T00:28:49.649Z — координатор — HETZBKMERGE2 (1880, A2) — VERDICT=GO, commit 1fa1318b878eeb37567e06b1badbd54860e782d3 (два коммита поверх fc0fb6de), bundle HETZBKMERGE2.bundle sha c45d0003…. Все шесть замечаний приёмки круга 1 закрыты: корень awk-сравн
- 2026-09-05T00:53:24.350Z — координатор — ACCHETZBKMERGE2 (1885, A2, opus) — VERDICT=GO для 1fa1318b878eeb37567e06b1badbd54860e782d3 (5 коммитов поверх l105, cherry-pick диапазона переигран начисто, дерево тождественно). Блокер круга 1 снят и проверен независимо
- 2026-09-05T01:28:25.713Z — координатор — Pi-standby (WEB-490) 01:21Z: FAIL rc=27 base/manifest disagree (manifest-20260904T221225Z vs base-20260905T010052Z) — подтверждает класс дефекта выбора точки/манифеста; ждёт посадки 1fa1318b (l107). Правила: WEB-449.
- 2026-09-05T01:41:11.748Z — координатор — KNOWN ISSUES / ТРАБЛШУТИНГ (правило владельца 05.09: в каждом тикете — чтобы смены не спотыкались об одно место): (1) restore --target-lsn latest выбирает цель ЗА концом манифеста и печатает RESTORE PASS → корень: awk ср
- 2026-09-05T17:35:28.651Z — fable-coordinator — [2026-09-05 17:40Z] Ревизия доски (волна 2040 boardtriage, M1, luna): статус → review. Основание: owner GO на DR-rehearsal есть, посадка и прогон не подтверждены. Если работа жива — верни статус и напиши в тикет, какая в
- **Ветки/бандлы/отчёты:** /home/ubuntu/waves/queue/dispatcher.log:, /home/ubuntu/waves/queue/done/1775-hetzbkretention-brief.md., /home/ubuntu/waves/queue/running/1776-manifestcadence-brief.md.run., /home/ubuntu/waves/ACCHETZBKAGEALERT4-REPORT.md, /Users/milamarty/waves/HETZBKWARMBASE-REPORT.md, /home/ubuntu/waves/ACCHETZBKWARMBASE-REPORT.md, /home/ubuntu/waves/HETZBKWARMBASE2-REPORT.md, /home/ubuntu/waves/ACCHETZBKWARMBASE2-REPORT.md; sha: 20260821, d91ebefe740ae83484c1de16710f2e6a68610432, d825eb0d, 1b081c5a, d91ebefe, 000000010000000300000023, 00000022, 00000023
- **KNOWN ISSUES / ТРАБЛШУТИНГ:**
- Контекст: пункт эпика миграции WEB-282 «резерв вне Oracle»: AWS EC2 квота не выдана; Hetzner ARM (CAX) не продаётся (ответ поддержки 02.09 + проверка консоли: недоступен во всех локациях; x86 CX23 5.49€ доступен). Решение с owner-ом: репетицию восстановления делать на A2 (ARM, честно к артефактам…
- План фазы 1: (0) предпосылки на A2: /etc/hetzbk (env, keys/backup.pass, ssh/storagebox) — секреты переносятся ssh-пайпом A1→A2 без печати; /usr/local/libexec/hetzbk- + lib; (1) hetzbk-restore --base <последний base --manifest <последний --target /var/lib/postgresql/16/rehearsal --target-lsn <LSN …
- Якорь прода: живая линия l103, коммит d91ebefe740ae83484c1de16710f2e6a68610432, флип 13:51Z 04.09. Раньше в этот же день: l101 d825eb0d, l102 1b081c5a. Ветка линии в репозитории-базе /home/ubuntu/nc на A1: l103-line (проверено git branch -a --contains d91ebefe... → l103-line).
- Репетиция аварии из бэкапов Hetzner Storage Box за 04.09 продвинулась на 4 блокера подряд. Первые три сняты, четвёртый (проигрывание WAL) вскрыт, первопричина доказана, фикс отдан в волну. До конца репетиция ещё не доходила.
- ПРИЧИНА 2 — ДОКАЗАНА: публикация сама удаляет только что опубликованный релиз
- Тот же класс рядом, проверить: /usr/local/libexec/hetzbk-env-pack строка 346 The remote namespace is timestamp-first by contract, so lexical descending, строка 355 ... | LCALL=C sort -r), строка 362 log "ENV PACK retention removed package=$old keep=10". Если имена env-пакетов тоже не timestamp-fi…
- ПРИЧИНА 4 — ДОКАЗАНА: не разрыв WAL, а рассинхрон каденций
- Настоящая причина: манифесты публикуются примерно раз в час (наблюдённые метки 10:12, 11:13, 12:13, 13:12, 14:12), а WAL-сегменты архивируются каждые 3–4 минуты. Цель latest, вычисленная по ЖИВОМУ архиву, принципиально не может валидироваться против ЧАСОВОГО манифеста — «gap» будет всегда.
- **Эволюция:**
- 2026-09-02 → [02.09 10:20Z Фабл] Фаза 1 СТАРТОВАЛА на A2: набор hetzbk (скрипты + /etc/hetzbk секреты + knownhosts storage box) перенесён с A1 ssh-пайпом под пользователем hetzbk (без печати); настройки прод-PG сняты в /var/lib/hetzbk/prod-pg-settings-20260902.tsv (11 пара
- 2026-09-02 → [02.09 10:55Z Фабл] НАХОДКА репетиции (первый прогон restore на A2 упал): /usr/local/libexec/hetzbk-restore после WAL coverage PASS качает ВСЕ wal-строки манифеста (цикл while read … kind=wal … remoteget, строки ~337–349), а не диапазон basestart..target; мани
- 2026-09-02 → [02.09 11:50Z Фабл] ФАЗА 1 РЕПЕТИЦИИ — РЕЗУЛЬТАТ (A2, песочница, живая реплика/пассив не тронуты): • Вход: base-20260902T090057Z + manifest-20260902T091306Z + wal-partial до целевого LSN 2/541C7DD8 (снят на проде ~09:49 UTC A1). Артефакт l89 со Storage Box (sh
- 2026-09-02 → [A1 11:30 Фабл] Фаза 1b запущена как волна 1196-drrehearsal1b на M4 (ветка от web469hetzbk3-1190 = l90 + hetzbk v3): скрипт infra/hetzbk/bin/hetzbk-rehearse (restore → артефакт → env-пакет → redis/app transient units → health/ready/paid → JSON-таймлайн RPO/RTO
- 2026-09-02 → [A1 13:00 Фабл] Приёмка 1203-accdrrehearsal1b (M4, дерево от e4af4675): NO-GO — 3 блокера: (1) JSON без канонических ключей rpo/rto (есть rtototal/rpolsn/rposeconds); (2) нет ${VAR:?}-защиты у rm -rf во всём пакете (hetzbk-rehearse:128/268 + base/env-pack/unpa
- 2026-09-02 → [A1 13:25 Фабл] Корректировка 1210-drrehearsal1b2 сдана: 8914106b30aebaf3d32a966b2db71d6109e7350b (rpo/rto числовые ключи; ${VAR:?} у всех rm -rf в пакете + grep-тест; APPUIDARGS инициализирован; suite 10→13). Повторная приёмка 1215-accdrrehearsal1b2 (M4). Лин
- 2026-09-02 → [A1 13:12 Фабл] Повторная приёмка 1215-accdrrehearsal1b2: NO-GO — три блокера 1203 закрыты (rpo/rto числовые; все 20 rm -rf с :?-guard; fallback без User проходит), но teardown не идемпотентен: второй --teardown при отсутствующем root возвращает 1 (hetzbk-rehe
- 2026-09-02 → [A1 13:35 Фабл] 1218-drrehearsal1b3 сдана: d6cd351eb9f3a95c16513385bd6955f387c1c8cf (teardowninternal: явный if + return 0; хвостовых ]] && в функциях нет). Повторная приёмка 1222-accdrrehearsal1b3 (M4). Ветка на A2/A1 mirrors; в l91 после GO (пересечение с ag
- 2026-09-02 → [A1 13:42 Фабл] Повторная приёмка 1222-accdrrehearsal1b3 (M4): GO — teardown идемпотентен (0/0, без root 0, чужой root → отказ), хвостовых ]] && нет, прежние блокеры без регресса, тесты пакета зелёные. Cherry-pick в l91 упёрся в конфликт с принятой age-alert л
- 2026-09-02 → [A1 13:55 Фабл] Слияние 1223-hetzbkmerge сдано: 8879df52 (age-alert cea6cc30+bdd668cc → DR e4af4675/8914106b/d6cd351e cherry-pick -x → merge-fix закрытия test-функций). Единственный конфликт — tests/testhetzbk.sh. Подозрение: «14 passed» = ровно DR-набор, тест
- Репетиция аварии (DR-rehearsal) на Oracle A2 из бэкапов Hetzner Storage Box — фаза 1: сайт + БД + воркеры; замер RPO/RTO против целей 5 мин / 15 мин (owner GO 02.09 07:46Z «Да планируй»)
- Контекст: пункт эпика миграции WEB-282 «резерв вне Oracle»: AWS EC2 квота не выдана; Hetzner ARM (CAX) не продаётся (ответ поддержки 02.09 + проверка консоли: недоступен во всех локациях; x86 CX23 5.49€ доступен). Решение с owner-ом: репетицию восстановления делать на A2 (ARM, честно к артефактам…
- Доки: A2 /home/ubuntu/HA-RUNBOOK.md (промоут A2 — НЕ то же, что репетиция), Storage Box /home/app-artifact/RESURRECTION-RUNBOOK.md (25.08), /usr/local/libexec/hetzbk-restore (A1). Память: owner-recovery-targets-20260821, hetzner-primary-backup-decision, a2-standby-db-replica.
- ЭВОЛЮЦИЯ 04.09.2026 (карта для нулевого агента)
- Якорь прода: живая линия l103, коммит d91ebefe740ae83484c1de16710f2e6a68610432, флип 13:51Z 04.09. Раньше в этот же день: l101 d825eb0d, l102 1b081c5a. Ветка линии в репозитории-базе /home/ubuntu/nc на A1: l103-line (проверено git branch -a --contains d91ebefe... → l103-line).
- Репетиция аварии из бэкапов Hetzner Storage Box за 04.09 продвинулась на 4 блокера подряд. Первые три сняты, четвёртый (проигрывание WAL) вскрыт, первопричина доказана, фикс отдан в волну. До конца репетиция ещё не доходила.
- **Следующий шаг:** Репетиция аварии (DR-rehearsal) на Oracle A2 из бэкапов Hetzner Storage Box — фаза 1: сайт + БД + воркеры; замер RPO/RTO против целей 5 мин / 15 мин (owner GO 02.09 07:46Z «Да планируй») | Контекст: пункт эпика миграции WEB-282 «резерв вне Oracle»: AWS EC2 квота не выдана; Hetzner ARM (CAX) не продаётся (ответ поддержки 02.09 + проверка консоли: недоступен во всех локациях; x86 CX23 5.49€ доступен). Решение с owner-ом: репетицию восстановления делать на A2 (ARM, честно к артефактам…


## Актуализация координатора 2026-09-26 12:01Z [refresh-20260926-roles-capacity]
Правила обогащения: WEB-449.

Уточнение статуса для следующего агента:5049 принят только как offline recovery kit. Независимая копия, replay и полная DR репетиция NOT_RUN по последнему подтверждённому handoff; новых доказательств этих испытаний нет. Завершённый kit не равен доказанному восстановлению. В текущих назначениях исполнителя recovery нет. Его приёмка не является обязательным условием запуска CPU ступеней. Следующий ответственный — координатор, отдельное practical execution после проверки ресурсов; не считать это уже запущенной работой.

КАРТА ДОКУМЕНТОВ / доказательства: ноутбук:/Users/annakorin/nc-ops-scripts/HANDOFF-LIVE.md (контроли26.09); см. WEB-470, WEB-655, WEB-648
Лента
2026-09-02T09:47:50.580Z · Fable
[02.09 10:20Z Фабл] Фаза 1 СТАРТОВАЛА на A2: набор hetzbk (скрипты + /etc/hetzbk секреты + known_hosts storage box) перенесён с A1 ssh-пайпом под пользователем hetzbk (без печати); настройки прод-PG сняты в /var/lib/hetzbk/prod-pg-settings-20260902.tsv (11 параметров); T0 LSN прода = 2/541C7DD8 (~10:20Z); запущено `hetzbk-restore --base base-20260902T090057Z --manifest manifest-20260902T091306Z --target /var/lib/hetzbk/restore/rehearsal --target-lsn 2/541C7DD8 --port 55481 --start` (лог /var/lib/hetzbk/logs/restore-rehearsal-20260902.log). Живая реплика 55433 и nc-a2 не тронуты. Следующее: приложение l89 из артефакта Storage Box на :3012 против 55481, замер RPO/RTO.
2026-09-02T09:57:08.723Z · Fable
[02.09 10:55Z Фабл] НАХОДКА репетиции (первый прогон restore на A2 упал): /usr/local/libexec/hetzbk-restore после `WAL coverage PASS` качает ВСЕ wal-строки манифеста (цикл `while read … kind=wal … remote_get`, строки ~337–349), а не диапазон base_start..target; манифест содержит старые сегменты (0000000100000000000000F4…), которые ретенция уже удалила со Storage Box → `File … not found` → восстановление невозможно из последнего base без ручной правки. На A2 копия скрипта пропатчена (skip сегментов < BASE_START_SEG и ≥ PARTIAL_SEGMENT; оригинал сохранён как hetzbk-restore.orig-a1-20260902), живой A1 не тронут; перезапуск восстановления идёт (лог restore-rehearsal-20260902b.log). Для WEB-469 (волна 1182/приёмка): перенести фикс в репо + тест «манифест с удалёнными старыми сегментами → restore проходит»; также манифест не должен перечислять сегменты, удалённые ретенцией (или ретенция должна публиковать новый манифест).
2026-09-02T10:19:14.474Z · Fable
[02.09 11:50Z Фабл] ФАЗА 1 РЕПЕТИЦИИ — РЕЗУЛЬТАТ (A2, песочница, живая реплика/пассив не тронуты):
• Вход: base-20260902T090057Z + manifest-20260902T091306Z + wal-partial до целевого LSN 2/541C7DD8 (снят на проде ~09:49 UTC A1). Артефакт l89 со Storage Box (sha OK), wrappers/spend-runtime/подписанная активация — с A1 (rehearsal/run), env — производный от A2 /home/ubuntu/prod/shared (DATABASE_URL→55481, REDIS→6380 локальный).
• БД: hetzbk-restore #1 УПАЛ (качает все wal-строки манифеста, старые удалены ретенцией) → патч копии скрипта на A2 → #2: WAL coverage PASS, данные восстановлены; `--start` упал на правах (/var/lib/hetzbk 750 для postgres) → chmod 755 + ручной pg_ctl → «consistent recovery state», redo done at 2/541C7DD8, новый timeline 2, `database system is ready`. Последняя транзакция в бэкапе: 09:46:31Z; последний TerminalSpendEvent 09:43:20Z; счётчики: User 19/19, Source 1948/1948, TerminalSpendEvent 3385/3387, LedgerEntry 6201/6203 (2 события/2 записи после 09:43 не в бэкапе).
• RPO факт ≈ 3–6 мин (каданс wal-partial 240 с + задержка публикации) — на границе цели 5 мин; стриминг полных сегментов даёт 16 МБ-гранулярность, partial-снимки — единственное, что даёт минуты.
• RTO факт: подготовка среды (набор+секреты на A2, артефакт, env, unit) ~25 мин ручной работы (сделано заранее — при аварии это часть RTO!); restore #2 ≈16 мин (скачивание base 5 ГБ + WAL + расшифровка), старт БД <1 мин, приложение: health 200 через 4 с, /api/ready = boot-env (как на проде), paid после одного spend-reconcile = TRUE (enforce_ready). Итого без подготовки ≈17 мин против цели 15; с подготовкой ≈45 мин.
• Находки: (1) hetzbk-restore не умеет восстанавливаться из последнего base без патча (WEB-469, в приёмке 1186); (2) права /var/lib/hetzbk ломают --start; (3) секреты/env, spend-runtime, подписанная активация, wrappers НЕ в бэкапе на Storage Box — восстановление опирается на A2-реплику env и A1 (при потере обоих — не восстановить; нужен зашифрованный env-пакет на Storage Box); (4) таймеры (reconcile/tasks/indexing) и nginx/TLS/DNS не в объёме — RTO «до пользователей» больше; (5) артефакты релизов не публикуются автоматически (в 1186).
• Следующее: фаза 1b — автоматизировать шаги (скрипт rehearsal на A2 из hetzbk-restore + unit-шаблон), зашифрованный env-пакет на Storage Box, повторить с секундомером; фаза 2 — телефония/мессенджеры/почта (отдельный тикет). Песочница оставлена на A2 (:55481/:3012) до конца дня для проверок, потом снести.
2026-09-02T11:30:07.897Z · Fable
[A1 11:30 Фабл] Фаза 1b запущена как волна 1196-drrehearsal1b на M4 (ветка от web469hetzbk3-1190 = l90 + hetzbk v3): скрипт infra/hetzbk/bin/hetzbk-rehearse (restore → артефакт → env-пакет → redis/app transient units → health/ready/paid → JSON-таймлайн RPO/RTO → --teardown), hetzbk-env-pack/unpack (шифрованный tar env+run/<line>+apply.conf на Storage Box, aes-256 с той же парольной фразой, ретенция 10, таймер раз в час) + README + тесты (pack/unpack round-trip, битый sha, dry-run). Ожидание: после посадки в l91 повторить фазу 1 по секундомеру на A2 и сравнить с 25+17 мин ручного прогона; цель RPO 5 / RTO 15. Песочница A2 (:55481/:3012) стоит до вечера.
2026-09-02T12:42:20.274Z · Fable
[A1 13:00 Фабл] Приёмка 1203-accdrrehearsal1b (M4, дерево от e4af4675): **NO-GO** — 3 блокера: (1) JSON без канонических ключей rpo/rto (есть rto_total/rpo_lsn/rpo_seconds); (2) нет ${VAR:?}-защиты у rm -rf во всём пакете (hetzbk-rehearse:128/268 + base/env-pack/unpack/verify/wal-stream/publish/artifact-unpack/lib); (3) fallback HETZBK_REHEARSAL_APP_COMMAND без User → APP_UID_ARGS unbound под set -u (exit 127, строка 342). Остальное (dry-run без побочных эффектов, teardown в пределах root с marker-ом, round-trip env-pack, битый sha → отказ, ретенция 10, таймер/units, таймлайн) подтверждено. Корректировка — волна 1210-drrehearsal1b2 (M4, один коммит поверх e4af4675) → повторная приёмка → l91/l92.
2026-09-02T12:57:56.753Z · Fable
[A1 13:25 Фабл] Корректировка 1210-drrehearsal1b2 сдана: 8914106b30aebaf3d32a966b2db71d6109e7350b (rpo/rto числовые ключи; `${VAR:?}` у всех rm -rf в пакете + grep-тест; APP_UID_ARGS инициализирован; suite 10→13). Повторная приёмка 1215-accdrrehearsal1b2 (M4). Линия на A2 (nc-build drrehearsal1b2-1210) и A1 mirrors/lines; в l91 — после GO (пересекается с age-alert по infra/hetzbk — cherry-pick с разрешением).
2026-09-02T13:18:38.694Z · Fable
[A1 13:12 Фабл] Повторная приёмка 1215-accdrrehearsal1b2: **NO-GO** — три блокера 1203 закрыты (rpo/rto числовые; все 20 rm -rf с :?-guard; fallback без User проходит), но teardown не идемпотентен: второй --teardown при отсутствующем root возвращает 1 (hetzbk-rehearse:128 — `[[ -e … ]] && rm -rf` как последняя команда функции). Корректировка 1218-drrehearsal1b3 (M4, поверх 8914106b) + тест на двойной teardown и grep хвостовых `]] &&` во всём пакете.
2026-09-02T13:29:36.083Z · Fable
[A1 13:35 Фабл] 1218-drrehearsal1b3 сдана: d6cd351eb9f3a95c16513385bd6955f387c1c8cf (teardown_internal: явный if + return 0; хвостовых `]] &&` в функциях нет). Повторная приёмка 1222-accdrrehearsal1b3 (M4). Ветка на A2/A1 mirrors; в l91 после GO (пересечение с age-alert по infra/hetzbk — cherry-pick с разрешением; если не влезет в l91 — l92).
2026-09-02T13:40:38.381Z · Fable
[A1 13:42 Фабл] Повторная приёмка 1222-accdrrehearsal1b3 (M4): **GO** — teardown идемпотентен (0/0, без root 0, чужой root → отказ), хвостовых `]] &&` нет, прежние блокеры без регресса, тесты пакета зелёные. Cherry-pick в l91 упёрся в конфликт с принятой age-alert линией (infra/hetzbk/tests/test_hetzbk.sh — обе добавили тесты) → волна 1223-hetzbkmerge (A1) сливает обе линии; в l91, если успеет до сборки, иначе l92 (для прод-приложения не критично — это ops-пакет). Для реального прогона фазы 1b на A2 нужны (из отчёта): root, /etc/hetzbk env + backup.pass + pgpass + ssh key, remote base.ready/manifest/artifact/env-package, owner-approved nc-a2.service и HETZBK_RESTORE_SETTINGS_FILE — всё это на A2 уже есть с фазы 1, кроме env-package (появится после посадки таймера hetzbk-env-pack на A1).
2026-09-02T13:49:00.278Z · Fable
[A1 13:55 Фабл] Слияние 1223-hetzbkmerge сдано: 8879df52 (age-alert cea6cc30+bdd668cc → DR e4af4675/8914106b/d6cd351e cherry-pick -x → merge-fix закрытия test-функций). Единственный конфликт — tests/test_hetzbk.sh. Подозрение: «14 passed» = ровно DR-набор, тесты age-alert могли потеряться → приёмка 1227-acchetzbkmerge (A1) сверяет наборы обеих линий построчно. Cherry-pick в l91-candidate выполнен (pre-GO, откатится при NO-GO).
2026-09-02T13:57:42.878Z · Fable
[A1 13:58 Фабл] Приёмка 1227-acchetzbkmerge (A1): **GO** — наборы тестов обеих линий присутствуют и вызываются (таблица в ACCHETZBKMERGE-REPORT.md §«Состав тестов»), merge-fix 8879df52 — только закрытие функций/guard-ы, логика age-alert/rehearse не тронута; все проверки зелёные. Итог: infra/hetzbk в l91-candidate (9ad68bc2) = v3 + age-alert (position-based, pg_unreachable) + репетиция аварии 1b (hetzbk-rehearse, env-pack/unpack, таймер). После посадки l91: `install.sh` на A1 и A2 → `hetzbk-env-pack.timer` → первый env-пакет на Storage Box → фаза 1b по секундомеру на A2.
2026-09-02T14:12:26.031Z · Fable
[A1 14:12 Фабл] ПОСАЖЕНО l91 на прод A1: release arm64-l91-20260902T140416Z, run l91-9ad68bc2, sourceCommit 9ad68bc261c833e792bc17523245975e15f48612, артефакт sha 96b3466b…dc3f; ready TRUE (boot/database/release/drain ok), paid TRUE enforce_ready, public 200, live-sha 9ad68bc2; SIP-стек перезапущен (readiness 200/200, монитор аренды пережил рестарт: 2 poll-failed, LOST=0). Откат: land-l90 run/l90-26da36fa (nc-a1.service.bak-l90). hetzbk-rehearse/env-pack в дереве l91 → после install.sh: env-pack.timer на A1 → первый пакет на Storage Box → фаза 1b по секундомеру на A2.
2026-09-02T14:40:27.408Z · Fable
[A1 14:40 Фабл] Фаза 1b на живом A1: install.sh из дерева l91 (backup ops-backups/hetzbk-live-20260902T142912Z), hetzbk-env-pack.timer включён; ПЕРВЫЙ ШИФРОВАННЫЙ ENV-ПАКЕТ на Storage Box: /home/walg-nc/hetzbk-prod-a1/env/env-l91-9ad68bc2-20260902T143753Z.tar.enc (30 752 байт + .sha256, retention 10) — находка №3 фазы 1 закрыта. Потребовалось на живом: unit от root (drop-in user.conf — hetzbk не читает shared/.env), HETZBK_ENV_LINE=l91-9ad68bc2 (имя run-каталога), symlink /home/ubuntu/prod/apply.conf → nc-a1-indexing.service.d/apply.conf, копия flip-cron.secret в run/<line>/ — всё это ушло в корректировку 1237 (конфигурируемый список файлов, warn вместо FATAL для необязательных). Песочница репетиции на A2 снесена (порты 55481/3012/6380 свободны, диск A2 48%); hetzbk-rehearse установлен на A2 — реальный прогон 1b после 1237.
2026-09-02T15:27:27.425Z · Fable
[A1 15:28 Фабл] Приёмка 1250-acchetzbkagealert3 (A1): age-alert-часть (PG_BIN psql, quiet sftp, base_age в секундах, SuccessExitStatus=2) прошла; **NO-GO** по env-pack: обязательные пути shared/.env.local и shared/run/<line>/ обрабатываются как optional WARN — при одном .env пакет коммитится rc=0 (неполный env-пакет). Корректировка 1255-hetzbkagealert4 (A1): required → FATAL rc=4 без архива, optional → WARN, тесты. После GO — install.sh на A1/A2 и снятие ручных заплаток.
2026-09-02T15:36:55.929Z · Fable
[A1 15:36 Фабл] СОСТОЯНИЕ для нулевого агента (ответ owner-у на «закончился ли стресс-тест»): ФАЗА 1 (ручная, 02.09 ~10:18 A1) закончена — sandbox A2 (PG 55481, app :3012) из бэкапов Storage Box, paid=true; RPO факт 3–6 мин (цель 5), RTO ≈17 мин + ~25 мин подготовки (цель 15) — цели НЕ выполнены на холодном пути. ФАЗА 1b (скрипт hetzbk-rehearse + env-pack): волна 1196 → круги 1203/1215/1222 → GO; live-фиксы 1237 → 1250 NO-GO (required-пути) → 1255 (идёт); env-pack.timer на A1 включён, первый пакет env-l91-9ad68bc2-20260902T143753Z.tar.enc на Storage Box; реальный прогон по секундомеру на A2 — после посадки 1255 (install.sh). ФАЗА 1c (предложение для выигрыша минут): тёплая локальная копия последнего hourly base на A2 (таймер pull со Storage Box) → restore с локального диска ≈3–5 мин → RTO ≈6–8 мин; wal-partial каданс 240 с → 60 с → RPO ≤2 мин. Горячий путь: A2 standby-реплика 55433 (RPO≈0, RTO≈2 мин) — уточнить у owner-а, к какому пути относятся цели 5/15 (память owner-recovery-targets-20260821). Отчёты: DRREHEARSAL1B*-REPORT.md, ACCDRREHEARSAL1B*-REPORT.md (M4), память dr-rehearsal-phase1-20260902.
2026-09-02T15:39:03.136Z · Fable
[A1 15:45 Фабл] Корректировка 1255-hetzbkagealert4 сдана: cccd2ba6 (HETZBK_ENV_FILES с суффиксом `!` = required + HETZBK_ENV_REQUIRED_FILES; required отсутствуют → FATAL rc=4 без архива; optional → WARN). Повторная приёмка 1258-acchetzbkagealert4 (A1) с шимами (счётчик remote-вызовов при FATAL). Ветка на A2/A1 mirrors → после GO install.sh на A1/A2, снятие ручных заплаток, реальный прогон фазы 1b на A2 по секундомеру.
2026-09-02T15:52:52.419Z · Fable
[A1 15:55 Фабл] Приёмка 1258-acchetzbkagealert4 = GO (отчёт A1 /home/ubuntu/waves/ACCHETZBKAGEALERT4-REPORT.md): NO-GO 1250 закрыт — обязательные env-пути (.env, .env.local, shared/run/<line>/) больше не проходят как WARN, env-pack падает при их отсутствии; unit hetzbk-env-pack.service штатно User=root; install.sh ставит 13 скриптов, 11 units и библиотеку. Линия hetzbkagealert4-1255 (cccd2ba6d2; цепочка 1199→1208→1237→1255 поверх hetzbkmerge-1223). Дальше: (1) установка из дерева 1255 на A1 и A2 + снятие ручных патчей (symlink apply.conf, дубликат flip-cron.secret, drop-in user.conf), HETZBK_ENV_LINE=l91-9ad68bc2; (2) cherry-pick в l92-candidate; (3) повторная репетиция фазы 1 с секундомером после тёплой копии base (волна 1257 на M4, WEB-470). Owner-у 15:45 объяснено: это линия «Oracle пропал → Hetzner на новую машину»; линия «A1 сгорел → A2 подхватывает» будет репетироваться отдельно.
2026-09-02T16:13:51.050Z · Fable
[A1 16:25 Фабл] Фаза 1c сдана: волна 1257-hetzbkwarmbase (M4), коммит 1435c215 (ветка hetzbkwarmbase-1257 поверх принятой hetzbkagealert4-1255). Что внутри: hetzbk-warm-pull (только при HETZBK_ROLE=passive; тянет новейший base.ready на A2, проверяет sha/шифр, идемпотентно, с ретенцией) + hetzbk-warm-pull.service/.timer (каждые 10 мин, ExecCondition по роли); hetzbk-restore берёт локальную тёплую копию при совпадении base-id, иначе remote; дефолт WAL-partial 60 с (RPO ≤2 мин). Ожидание автора: распаковка 5 GiB ≈3–5 мин, RTO ≈4–7 мин (бюджет ≤8) против ≈16–17 мин по холодному пути. Тесты автора: shell 16 + warm 2, shellcheck чисто. Отчёт: M4 /Users/milamarty/waves/HETZBKWARMBASE-REPORT.md (копия A1 /home/ubuntu/waves/). Дальше: приёмка 1267-acchetzbkwarmbase (A1, другой verifier: role guard, битый bundle, fallback, каденс) → install на A2 + timer → первая тёплая копия → репетиция 1c с секундомером (RPO/RTO против целей 5/15 owner-а) → cherry-pick в l92-candidate. Бандл: A1 /home/ubuntu/mirrors/lines/hetzbkwarmbase-1257.bundle; A2 nc-build ref hetzbkwarmbase-1257/head.
2026-09-02T16:35:27.403Z · Fable
[A1 16:40 Фабл] Фаза 1c: приёмка 1267-acchetzbkwarmbase = NO-GO (A1 /home/ubuntu/waves/ACCHETZBKWARMBASE-REPORT.md). Прошло: role guard (rc=8, ExecCondition), идемпотентный pull (5 get, повтор unchanged), битый sha/обрезанный cipher rc=41 без порчи прежних копий, retention 2. Блокеры: B1 restore выбирает warm/remote по --base до чтения manifest (старый warm + новый manifest → FATAL rc=89 вместо нового base); B2 нет hetzbk-restore --dry-run; B3 критерий уточнён координатором: ноль remote-обращений за base (manifest/WAL с remote штатно) — документировать; B4 единственный example = passive (небезопасно для A1) → нужны active-safe и a2-passive примеры. Примечание: авторская волна 1257 (M4) стояла на hetzbkagealert3-1237, не на принятой 1255 — перебазировано координатором в hetzbkwarmbase-1257r = 98a74bf11b (чисто), это база корректировки. → волна 1269-hetzbkwarmbase2 (A1): manifest-first restore, --dry-run, примеры env, retention всегда, шимы приёмки в регресс. После GO: install на A2 + warm-pull.timer → первая копия → restore --dry-run (base_source=warm) → репетиция 1c с секундомером против целей 5/15.
2026-09-02T17:01:50.876Z · Fable
[A1 17:08 Фабл] Фаза 1c, корректировка после NO-GO 1267 сдана: волна 1269-hetzbkwarmbase2, коммит c669d65ee1 (ветка hetzbkwarmbase2-1269 = 1257r 98a74bf + c669d65e, база принятой hetzbkagealert4-1255). Закрыто: B1 restore manifest-authoritative (сначала manifest → base id → warm при валидном sha, иначе remote; чужой --base → отказ до распаковки); B2 hetzbk-restore --dry-run (manifest проверяется, base/WAL не качаются, каталоги не создаются); B3 критерий «ноль remote за base, manifest/WAL с remote штатно» закреплён в README и тестом; B4 два примера env: active-safe (A1) и a2-passive (A2); retention вызывается и при status=unchanged. Тесты: shell 17 + warm 2 + перенесённые шимы приёмки 1267 = 10, shellcheck чисто. Отчёт: A1 /home/ubuntu/waves/HETZBKWARMBASE2-REPORT.md (раздел «рецепт включения на A2»). Дальше: приёмка 1277-acchetzbkwarmbase2 (A1, другой verifier) → GO → install на A2 + hetzbk-warm-pull.timer → первая тёплая копия → restore --dry-run = warm → репетиция 1c с секундомером (цели owner-а RPO 5 / RTO 15; бюджет 1c RTO ≤ 8) → cherry-pick в l92-candidate. Бандл: A1 /home/ubuntu/mirrors/lines/hetzbkwarmbase2-1269.bundle; A2 ref hetzbkwarmbase2-1269/head.
2026-09-02T17:20:48.908Z · Fable
[A1 17:40 Фабл] Фаза 1c: приёмка 1277-acchetzbkwarmbase2 = GO (A1 /home/ubuntu/waves/ACCHETZBKWARMBASE2-REPORT.md): B1 manifest-first restore, B2 --dry-run без побочных эффектов, B3 ноль remote за base при валидной warm-копии, B4 active-safe/a2-passive примеры, retention при unchanged — свои шимы приёмщика, регресс 17+2+10, shellcheck. Коммит c669d65ee1 принят. Дальше (координатор): cherry-pick 98a74bf1 + c669d65e в l92-candidate (A2); установка на A2 из принятого дерева + env passive (HETZBK_ROLE=passive, HETZBK_WARM_DIR, retention 2) + enable --now hetzbk-warm-pull.timer → первая тёплая копия → hetzbk-restore --dry-run = base_source=warm; на A1 — обновление кода с active-safe env; затем репетиция 1c с секундомером против целей owner-а (RPO 5 / RTO 15; бюджет 1c ≤ 8 мин).
2026-09-02T17:27:30.840Z · Fable
[A1 17:52 Фабл] Фаза 1c ВКЛЮЧЕНА на A2: hetzbk c669d65e установлен (A2 passive, A1 active), hetzbk-warm-pull.timer включён; первая тёплая копия: WARM PULL committed base-20260902T170039Z, 1.17 ГБ за 91 с. Проверка: `hetzbk-restore --dry-run --manifest manifest-20260902T171249Z --target-lsn 2/805A5CD8` → base_source=warm, warm_sha256=valid, wal_range …F4..…7F (396 сегментов). Находка при включении: ручные запуски от root (утренняя репетиция) оставили root-owned catalog.tsv и logs/hetzbk.log → unit (User=hetzbk) падал «Permission denied»; починено chown, правило: hetzbk-инструменты руками только `sudo -u hetzbk`. Дальше: репетиция 1c с секундомером (hetzbk-rehearse на A2, метрики из отчёта приёмки 1277) → RPO/RTO против целей owner-а 5/15 и бюджета 1c ≤ 8 мин.
2026-09-02T17:46:08.891Z · Fable
[A1 17:50 Фабл] Репетиция 1c r1c-20260902T1733Z на A2: warm-путь сработал (base_source=warm, распаковка + 3 WAL-сегмента + partial, PG стартовал ~через 5,5 мин от t0 — против 16 мин холодного пути), но упала rc=95 «restored PostgreSQL did not leave recovery within 180s» на 613-й секунде. Корень (по коду, подтверждаю репродукцией с сохранённой песочницей): hetzbk-rehearse резолвит target «latest» как конец сегмента (2/80FFFFFF; hetzbk-rehearse:226–229) — а сегмент 80 = текущий partial, WAL в нём короче → PostgreSQL с recovery_target_lsn за концом WAL завершает recovery до цели и останавливается; цикл ожидания (hetzbk-restore:509–520) не отличает «PG упал» от «в recovery» и ждёт 180 с; песочница удаляется вместе с PG-логом. До этого — 4 ложных старта из-за окружения A2 (env не загружен, stray rehearsal root, нет pg_settings capture — снят read-only с прода в /etc/hetzbk/pg_settings на A1/A2, root без known_hosts Storage Box) — всё починено и записано. → волна 1290-hetzbkwarmbase3 (A1): latest = до конца архива без синтетической цели (promote), явный LSN за пределами WAL → отказ до старта, ожидание recovery выходит сразу при падении PG с хвостом лога, песочница при провале сохраняет логи. Затем повтор репетиции с секундомером.
2026-09-02T17:52:42.931Z · Fable
[A1 18:12 Фабл] Корень провала репетиции 1c ПОДТВЕРЖДЁН репродукцией с сохранённой песочницей (A2 /var/lib/hetzbk/restore/dbg1c/restore-postgres.log): PG «starting point-in-time recovery to LSN 2/80FFFFFF» → сегмент 80 восстановлен → «invalid record length at 2/808E7B08» → «redo done at 2/808E7A20» → FATAL «recovery ended before configured recovery target was reached» → shutdown 17:48:33; скрипт ждал до 17:51:33. Вторая находка: coverage-проверка видит partial-снимок сегмента 80 как 16 MiB (snapshot_bytes=16777216) и считает target покрытым — надо учитывать реальную длину partial из pointer. Тайминг warm-пути: data-dir fsync ~55 с на 5 ГБ, consistent через 1 с после redo, PG read-only через ~4 мин от старта restore → бюджет 1c (≤8 мин) достижим после фикса. Дополнения переданы в бриф 1290-hetzbkwarmbase3 (A1, очередь).
2026-09-02T18:00:48.514Z · Fable
[A1 18:10 Фабл] Owner 02.09 18:08: «арбитр аренды (A2) — участник процесса: нужна его бэкап-копия, чтобы не пилить заново; топология и документы «как развернуть всё» — рядом с бэкапом или папкой на том же Hetzner». → (1) в бриф 1291-web405a2authority добавлено: состояние authority (key custody, журнал/epoch, конфиг, SSH-pin) в зашифрованный пакет на Storage Box через hetzbk env-pack/authority-pack + процедура восстановления authority на новом хосте с тестом; (2) новая волна 1299-drdocspack (A1): docs/dr/ в репо (TOPOLOGY, RESTORE-FROM-ZERO, SECRETS-INVENTORY без значений, CHECKLIST) + hetzbk-docs-pack (service/timer, секрет-скан fail-closed, publish в ${HETZBK_REMOTE_ROOT}/docs/ с retention, ссылка из restore/rehearse --dry-run).
2026-09-02T18:12:53.991Z · Fable
[A1 18:35 Фабл] Волна 1290-hetzbkwarmbase3 сдана: коммит edf070d639 (ветка hetzbkwarmbase3-1290 поверх принятой 1269). Заявлено: «latest» без синтетической recovery_target_lsn (promote до конца WAL), отказ до старта PG при LSN за пределами WAL, coverage по реальной длине partial (pointer bytes, не 16 MiB снимок), немедленный выход при падении PG с хвостом лога, логи песочницы сохраняются. Отчёт: A1 /home/ubuntu/waves/HETZBKWARMBASE3-REPORT.md. Дальше: приёмка 1305-acchetzbkwarmbase3 (A1) → GO → install на A2/A1 → повтор репетиции 1c с секундомером (ожидание по warm-пути: PG read-only ~4 мин от старта restore → бюджет ≤8 мин) → cherry-pick в l92-candidate. Бандл: A1 /home/ubuntu/mirrors/lines/hetzbkwarmbase3-1290.bundle; A2 ref hetzbkwarmbase3-1290/head.
2026-09-02T18:39:32.659Z · Fable
[A1 18:45 Фабл] Линии hetzbk 1255 (env-pack required) и warm-base 1269 (manifest-first restore) ПОСАЖЕНЫ в прод l92 (9bee5955) как часть репо; на A1/A2 уже стояли из принятых деревьев. Осталось: 1305 (приёмка фикса «latest») → повтор репетиции 1c с секундомером; 1299 DR-доки; 1300 authority-pack.
2026-09-02T18:51:13.326Z · Fable
[A1 19:00 Фабл] Приёмка 1305-acchetzbkwarmbase3 = NO-GO (A1 /home/ubuntu/waves/ACCHETZBKWARMBASE3-REPORT.md): PASS — latest без синтетической цели, exact-latest, границы сегментов, падение PG/timeout/сохранение evidence, регресс; блокеры: B1 — publisher (hetzbk-wal-stream:105,197–200) публикует stat preallocated partial (16 MiB) как bytes/snapshot_bytes, а restore (hetzbk-restore:619–620) требует равенства физического размера → на реальном потоке pointer не может сообщить логическую границу, а offset внутри диапазона получает rc=93; авторский тест использовал физически укороченный partial и не ловил это; B2 — rule10: `cp … 2>/dev/null || true` с ложным copied_log при неудаче копирования PG-лога. → волна 1314-hetzbkwarmbase4 (A1): publisher вычисляет реальную границу WAL (pg_waldump/скан страниц), pointer bytes=логическая граница + snapshot_bytes=физический размер, restore допускает preallocated 16 MiB и судит по bytes, регресс на реальном 16-MiB partial в обе стороны, честное копирование evidence; rule10-скан всего infra/hetzbk.
2026-09-02T19:37:05.723Z · Fable
[A1 20:30 Фабл] Волна 1314-hetzbkwarmbase4 сдана: коммит 585818ecb6 (publisher публикует реальную границу WAL в partial; restore судит по pointer bytes и допускает preallocated 16 MiB; честное копирование evidence; rule10-скан). Отчёт: A1 /home/ubuntu/waves/HETZBKWARMBASE4-REPORT.md. Дальше: приёмка 1328-acchetzbkwarmbase4 (A1) → GO → install на A2/A1 → повтор репетиции 1c с секундомером → l93/l94. Бандл: A1 mirrors/lines/hetzbkwarmbase4-1314.bundle; A2 ref hetzbkwarmbase4-1314/head.
2026-09-02T20:22:03.350Z · Fable
[A1 20:25 Фабл] 1299-drdocspack сдана: коммит 14672d63ef (M4) — пакет DR-документации (топология, восстановление с нуля, две линии DR: A2 takeover vs Hetzner restore, БД/миграции, dev/prod, вопросы owner-а 02.09) в docs/dr. Дальше: приёмка на M4 → публикация папки docs/ рядом с бэкапами на Storage Box.
2026-09-02T20:34:08.253Z · Fable
[A1 20:45 Фабл] Репетиция 1c на A2 с принятым кругом 4 (1314, установлен на A1/A2): run r1c-20260902T203100Z. Результат: RESTORE PASS — база из тёплой копии base-20260902T200104Z (warm) + manifest-20260902T201219Z, wal_segments=3, target=latest, партиальный сегмент 000000010000000200000095 принят (дефект rc=95 из 1290/1305 закрыт), t_restore=231 с (из них pg_start 185 с). Дальше упало на стадии приложения: на Storage Box нет /home/app-artifact/l92-9bee5955/{artifact.tar.gz,sha256,att-build.json,ready} — публикация артефакта приложения (hetzbk-publish-artifact) не выполнялась ни для l92, ни для l93 (нет таймера/шага в посадке). Улики: A2 /home/ubuntu/rehearsal-evidence/r1c-20260902T203100Z/. Дальше: опубликовать артефакт l93 (текущий прод) через hetzbk-publish-artifact, добавить шаг публикации в runbook посадки (land-l9x.sh после flip), повторить репетицию для l93 = полный RTO (БД + приложение + Redis).
2026-09-02T20:37:23.052Z · Fable
[A1 20:40 Фабл] Закрыл два пробела посадки: (1) HETZBK_ENV_LINE на A1 указывал на l91 → переведён на l93-02d032e4, env-pack прогнан (retention 10); (2) артефакт приложения l93 опубликован на Storage Box: /home/app-artifact/l93-02d032e4/{artifact.tar.gz, .sha256, att-build.json, ready}, 227 МБ за 42 с, через новый /home/ubuntu/hetzbk-publish-release.sh (составная аттестация: sha256 тарбола + build-attestation + подписанная spend-activation; копии в ops-backups и ~/nc-ops-scripts на ноуте). В runbook посадки l94: после flip — publish-release + HETZBK_ENV_LINE + env-pack. Репетиция 1c для l93 запущена на A2: r1c-20260902T204000Z.
2026-09-02T20:51:20.634Z · Fable
[A1 20:55 Фабл] Репетиция l93 r1c-20260902T204000Z: RESTORE PASS повторно (t_restore 232 с), артефакт/энв-пак l93 подхвачены (app/shared/run/l93-02d032e4 распакован), но стадия приложения упала: hetzbk-rehearse берёт ExecStart из шаблона /etc/systemd/system/nc-a2.service, а он на A2 застыл на l81 (enforce-start-l81.sh) → CHDIR fail. Обход: HETZBK_REHEARSAL_APP_COMMAND=/home/ubuntu/prod/shared/run/l93-02d032e4/enforce-start-l93.sh в /etc/hetzbk/hetzbk.env на A2; перезапуск r1c-20260902T205500Z. Дефект линии для круга 5 (WEB-470): команду старта приложения выводить из распакованного env-пака (shared/run/<line>/enforce-start-*.sh), а не из локального юнита A2; плюс проверка «шаблон соответствует line» до restore. Улики: A2 /home/ubuntu/rehearsal-evidence/r1c-20260902T204000Z/.
2026-09-02T20:59:16.442Z · Fable
[A1 21:00 Фабл] Приёмка 1338-accdrdocspack = NO-GO (M4, 6 критических находок: bare dry-run команды невыполнимы, критические факты не заполнены, предметная полнота отсутствует, имена units не дают топологии, Storage Box layout противоречив, sync-контракта нет). Круг 2 = волна 1359-drdocspack2 (M4) с фактами из живой конфигурации (списки units/путей/env-ключей снимаю и кладу в бриф).
2026-09-02T21:02:09.544Z · Fable
[A1 21:05 Фабл] Репетиции r1c-20260902T204000Z и …205500Z: RESTORE PASS ×2 (t_restore 232 с), стадия приложения падает и с обходом: hetzbk-rehearse:333 перебивает HETZBK_REHEARSAL_APP_COMMAND значением из шаблона nc-a2.service (l81), плюс раскладка распакованного артефакта ($APP_ROOT/…) не совпадает с ожидаемой enforce-скриптами (prod/releases/<name>). Итог: стадия приложения репетиции НИКОГДА не проходила — это дефект линии, не конфигурации. Круг 5 = волна 1361-hetzbkwarmbase5 (A1, Luna xhigh, от 585818ec): приоритет источников команды старта, preflight template↔line, раскладка releases/<name>, критерий PASS = /api/health 200 + /api/ready. Улики: A2 /home/ubuntu/rehearsal-evidence/r1c-*/ (state, restore-log, app-unit.log, app-layout.txt). Полный RTO пока = RTO базы (≈4 мин от тёплой копии) + неизмеренное приложение.
2026-09-02T22:00:10.146Z · Fable
[A1 22:45 Фабл] Волна 1361-hetzbkwarmbase5 сдана: коммит e1977830a2 (приоритет источников команды старта приложения, preflight template↔line, раскладка releases/<name>, критерий PASS = /api/health + /api/ready, t_app_start/t_ready). Отчёт: A1 /home/ubuntu/waves/HETZBKWARMBASE5-REPORT.md. Дальше: приёмка 1382-acchetzbkwarmbase5 (A1, Sol high, в очереди) → install на A2/A1 → репетиция l93 с полным RTO (база ≈4 мин + приложение).
2026-09-02T22:46:47.084Z · Fable
[A1 01:35 Фабл] Приёмка 1390-accdrdocspack2 = NO-GO (M4, отчёт /Users/milamarty/waves/ACCDRDOCSPACK2-REPORT.md): круг 2 убрал bare-вызовы и литеральные placeholders, но обе DR-линии имеют детерминированные точки остановки при сухом прогоне; env-pack не содержит service-identity.env и embedding-integrity.env; единый artifact layout (release-id vs line) и provenance ряда фактов не доказаны. 6 required fixes: bootstrap hetzbk.env/ключей до юнитов; точный source/SHA land-l9x.sh + staging→canonical release dir + download-команды; в takeover l93 landing/bootcontract до promote, precheck терпим к inactive units; service identity path + оба env-файла в обязательный pack с тестом; один artifact child key везде; источники для всех фактов + timer windows/retention в sync matrix. Круг 3 = волна 1402-drdocspack3 (M4) с приложенными land-l93/l94.sh и hetzbk-publish-release.sh как evidence.
2026-09-02T22:48:53.713Z · Fable
[A1 01:50 Фабл] Приёмка 1382-acchetzbkwarmbase5 = NO-GO формально: функционал круга 5 (приоритет команды старта, preflight template↔line, раскладка releases/<name>, PASS по /api/health+/api/ready, RTO) доказан, регрессии 1305/1314/1328 зелёные; единственный блокер — ShellCheck SC2034: APP_START_NS не используется (hetzbk-rehearse:472). Круг 6 = волна 1404-hetzbkwarmbase6 (A1, Luna medium): использовать APP_START_NS для t_app_start, shellcheck warning-level чист → приёмка → install на A2/A1 → репетиция l93 с полным RTO.
2026-09-02T23:50:55.215Z · Fable
[A1 05:40 Фабл] Волна 1404-hetzbkwarmbase6 сдана: коммит 4b667525f8 (APP_START_NS используется для t_app_start, shellcheck чист). Приёмка 1421 (A1, Sol medium, в очереди) → install на A2/A1 → репетиция l94 (r1c) с полным RTO (база + приложение).
2026-09-03T00:14:44.541Z · Fable
[A1 07:05 Фабл] Волна 1402-drdocspack3 сдана (перезапуск после потери worktree): коммит 346f1018cd (6 required fixes, evidence land-l93/l94.sh + publish-release). Приёмка 1429 (M4, Sol high, в очереди) → публикация docs/dr на Storage Box.
2026-09-03T00:36:23.329Z · Fable
[A1 09:00 Фабл] Приёмка 1429-accdrdocspack3 = NO-GO (M4, отчёт /Users/milamarty/waves/ACCDRDOCSPACK3-REPORT.md): fixes 4 (env-pack с service-identity/embedding-integrity) и 5 (один artifact key = line-id) закрыты; открыты 1 (LINE_ID в root bootstrap scope + тест fenced A1 block), 2 (fail-closed материализация env, посадка на fresh host без предыдущего дерева, SHA wrappers), 3 (DSN в A5 SQL checks), 6 (sync matrix: retention window + фактические строки). Круг 4 = волна 1436-drdocspack4 (M4, Luna xhigh, от 346f1018) с новыми фактами (прод l94, authority §1–§2, телефония).
2026-09-03T01:51:14.973Z · Fable
[M4 11:35 Фабл] Волна 1436-drdocspack4 сдана (6320e132, шесть required fixes, test_hetzbk 19 passed) → приёмка 1444 (M4, Sol). В брифе приёмки: сверить с разрывом раскладки репетиции (WEB-469 круг 7).
2026-09-03T02:47:52.869Z · Fable
[M4 Фабл] Приёмка 1444-accdrdocspack4 = NO-GO (6320e132): fixes 1,2,3,5,6 закрыты; fix 4 нет — takeover B не самодостаточен (нет точных источников A2 unit/drop-in/landing и материализации артефакта в раскладку релиза), нет безопасного перехода с фактического l81 runtime на l94 (fresh-only env-install над непустым shared), и находка репетиции 03.09 (раскладка rehearse ≠ прод, нет flip-*.secret; WEB-469 круг 7) не занесена. Круг 5 = волна 1453 (M4, Luna high) с фактами 03.09 как external input.
2026-09-03T03:06:48.667Z · Fable
[Фабл] Волна 1453-drdocspack5 сдана: коммит a3505dd1 (находка репетиции 03.09 занесена, B2 самодостаточен, переход с l81). Приёмка 1457 (M4, Sol medium) в очереди.
2026-09-03T03:11:48.282Z · Fable
[M4 Фабл] Приёмка 1457-accdrdocspack5 = GO (независимая, Sol): находка репетиции 03.09 занесена, takeover B самодостаточен, переход с l81 описан и покрыт тестом. Коммит a3505dd1 → в l95-candidate (docs/tests); публикация DR-доков рядом с бэкапами Hetzner — следующим шагом по рецепту отчёта.
2026-09-03T03:13:29.992Z · Fable
[A2 Фабл] Опубликовано рядом с бэкапами Hetzner: $HETZBK_REMOTE_ROOT/docs/docs-l94-b1962b8d-20260903T031243Z.tar (+ .tar.sha256; docs/dr из a3505dd1, git archive; sha256 25c49deb…). Cherry-pick в l95: линия (18 коммитов от 3179a54e) КОНФЛИКТУЕТ в 14 файлах infra/hetzbk/* с hetzbk-линией (круги 5–7, WEB-469) — обе разошлись от одной базы → после приёмки круга 7 отдельная волна объединения (l95hetzbkunify), l95 пока собирается без docs/hetzbk линий. Канонический hetzbk-docs-pack — после объединения.
2026-09-03T16:16:09.991Z · coordinator
03.09 21:45 IST. Круг 13 hetzbk сдан на M4 коммитом df979b2a10e2cec1336995376fc0c4ba8b505f1b (отчёт /Users/milamarty/waves/HETZBK13-REPORT.md), НО M4 (192.168.1.110) сейчас недоступен по сети — ping 100% потерь, ssh таймаут. Коммит проверен на достижимость и НЕ найден нигде больше: /home/ubuntu/nc и /home/ubuntu/nc-video-engine на A1, /home/wave/nc-mirror на A1, /home/ubuntu/nc-build и /home/ubuntu/nc-waves на A2 — везде «could not get object info». Приёмку круга 13 поставить НЕ на чем: и коммит, и отчёт автора, и контракт ACCHETZBK12-REPORT.md заперты на M4. Волна НЕ ставилась намеренно, чтобы не плодить приёмку без дерева. Как только M4 вернётся: (1) вынуть df979b2a бандлом от базы, которая есть у получателя, (2) скопировать HETZBK13-REPORT.md и ACCHETZBK12-REPORT.md, (3) поставить независимую приёмку на A2 (только шимы, без живого Storage Box, обязательный shellcheck — в круге 12 его пропустили).
2026-09-03T19:13:19.194Z · coordinator
Статус 03.09 19:12Z: круг 13 (df979b2a) был сдан на M4, но M4 упал — коммит и отчёт оказались заперты, приёмка не ставилась ~2 часа. M4 перезапущен owner-ом, приёмка круга 13 запущена (волна 1591 на M4). Напоминание контекста: приёмка круга 12 (ACCHETZBK12) забраковала его потому, что внутренний разрыв WAL не обнаруживался ВООБЩЕ (validate_latest_coverage, строки 492-494), из-за чего добавленный в круге 12 ретрай не включался никогда. Порядок дальше: приёмка 13 → установка на A2 (ROLE=passive) → живой прогон hetzbk-rehearse на линии l96-98a23c70 (запускаю после того, как A2 освободится от сборки l97) → по rc=0 закрываю WEB-082.
2026-09-03T22:36:19.569Z · coordinator
Круг 14 сдан: коммит 1aabe101 «document intentional shellcheck diagnostics». Напоминание: круг 13 (df979b2a) закрыл ФУНКЦИОНАЛЬНЫЙ блокер — внутренний разрыв WAL обнаруживается, ретрай включается, вечный разрыв даёт 3×retry и fatal rc=96 — и получил NO-GO только по shellcheck. Приёмка круга 14 = волна 1603-acchetzbk14 на M4: shellcheck -x rc=0 своим прогоном, каждая директива disable проверяется по существу, функциональные тесты в обоих деревьях сравниваются. При GO — установка на A2/A1 и живая репетиция на линии l97-9d69d2a0.
2026-09-03T22:59:33.248Z · coordinator
Приёмка круга 14 (волна 1603 на M4) = GO для 1aabe101. Единственный блокер круга 13 — буквальный shellcheck -x — закрыт: rc=0 по всем семи .sh, функциональная часть не затронута, остальные обязательные проверки PASS. Строка переноса: l98: cherry-pick df979b2a..1aabe101. Коммит вынут бандлом с M4 и загружен в /home/ubuntu/nc как hetzbk14-line (M4 сегодня уже один раз запирал принятые коммиты, когда упал). ⚠️ ВНИМАНИЕ при установке: команды из отчёта включают `cp infra/hetzbk/examples/hetzbk.env*.example /etc/hetzbk/hetzbk.env` — на A1 и A2 УЖЕ лежат рабочие hetzbk.env с owner-approved значениями (HETZBK_ENV_LINE, HETZBK_ENV_ATTESTATION_FILE и креды), их перезапись сломает работающие бэкапы. Ставить, сохраняя существующий env.
2026-09-03T23:14:05.492Z · coordinator
Живой прогон репетиции на A2 по линии l97-9d69d2a0 (после GO приёмки круга 14): rc=95 на старте восстановленного PostgreSQL. Расписка: pg_ctl -w start (дефолт 60 с) объявил 'server did not start in time', при этом в логе самого PostgreSQL видно, что сервер ЖИВ и поднимается: 'starting PostgreSQL 16.15', 'listening on 127.0.0.1:55481', 'database system was interrupted; last known up at 22:01:45', 'syncing data directory (pre-fsync), elapsed time: 39.98 s'; pg_ctl status при этом отвечает 'server is running (PID 442392)'. То есть провал ложный: инструмент не дождался. Улики: /var/lib/hetzbk/logs/rehearsal-acc14-20260903T225541Z-restore.log, дерево сохранено в /var/lib/hetzbk/rehearsal/pg. Немедленное действие: перезапуск прогона с PGCTLTIMEOUT=900 и HETZBK_RECOVERY_TIMEOUT_SECONDS=900 (идёт). Требование в круг 15: pg_ctl должен запускаться с явным -t по размеру каталога или через настраиваемую переменную; ошибка 'не стартовал' и 'стартует дольше таймаута' должны различаться, а evidence — включать статус pg_ctl (он уже показывал running).
2026-09-04T00:09:42.211Z · coordinator
Круг 15 сдан: коммит 72e654cd — чинит ДВА дефекта инструмента, найденных живым прогоном 03.09: (1) pg_ctl -w start с дефолтом 60 с объявлял ложный провал, пока PostgreSQL реально поднимался (pre-fsync 39.98 с, pg_ctl status = running); (2) проба здоровья ходила на 127.0.0.1:3012 и получала origin-lock host-not-allowed, потому что приложение стартует с восстановленным ПРОДОВЫМ окружением. Приёмка = волна 1624 на M4. В брифе отдельно: команды установки НЕ должны слепо копировать example поверх /etc/hetzbk/hetzbk.env — там owner-approved значения.
2026-09-04T15:08:17.132Z · coordinator
04.09 координатор: в body добавлен блок «ЭВОЛЮЦИЯ 04.09.2026» — состояние, причина с доказательством, что село, что осталось, ловушки.
2026-09-04T22:58:41.917Z · координатор
Резервный контур A1, 22:57Z 04.09. (1) Скрипты /usr/local/libexec/hetzbk-* стояли от 03.09, тогда как в линии l105 сидели принятые правки (hetzbk-restore +500 строк, hetzbk-rehearse +340, wal-stream +17) — посадка релиза /usr/local не трогает. Установлены все из дерева l105 штатным infra/hetzbk/install.sh, юниты совпадали, hetzbk-wal-stream перезапущен: streaming at 3/3C000000, NRestarts=0. Бэкап старых: /home/ubuntu/prod/shared/hetzbk-bak-20260904/. (2) Retention-фикс издателя стоит: /usr/local/lib/hetzbk-lib.sh 08ef4759…, hetzbk-publish-artifact f7c6ff79… (по блоку из L104QAR2). Неиспользуемая копия libexec/hetzbk-lib.sh удалена. (3) Приёмка MANIFESTCADENCE2 (c3019164, restore-target из манифеста) круга 2 — NO-GO только из-за отсутствия бандла; бандл создан (git bundle требует ref, не raw SHA) sha256 41c4810f…, доставлен на A2, приёмка круг 3 = волна 1872. (4) Конфликт: принятый HETZBK26 (88521289f, retain by ready chronology) и c3019164 (retain by publication time) правят один файл hetzbk-publish-artifact — после приёмки нужна волна слияния, в l106 — только согласованный вариант. Репетиция по-прежнему на паузе до этого. Правила: WEB-449.
2026-09-04T23:31:46.901Z · координатор
HETZBKMERGE (1875, A2) — GO, commit fc0fb6deab3c99425acea1164cbca027df07dd93 на базе l105: оба принятых фикса удержания (88521289f HETZBK26; c3019164 + a9b16c593 MANIFESTCADENCE2, приёмка ACCMANIFESTCADENCE3 GO) сведены в один результат. Вывод автора: смысловое ядро обоих уже на линии через 4d858be7 (l104, cherry-pick 0b2d6aed) — издатель на проде (f7c6ff79) уже сортирует по published_at, исключает текущий релиз; снятие l94 23:05Z — следствие. Независимая приёмка → 1876-acchetzbkmerge (A1, bundle sha 33197002…). Резервный контур: l105 опубликован (remote /home/app-artifact/l105-1185ca25, 241351389 байт), env-pack env-l105-1185ca25-20260904T230624Z.tar.enc (sha e597497f…), HETZBK_ENV_LINE=l105-1185ca25, Pi-standby warm-pull → status=OK line=l105-1185ca25. Правила: WEB-449.
2026-09-04T23:51:41.685Z · координатор
ACCHETZBKMERGE (1876, A1) — VERDICT=NO-GO для fc0fb6de. Подтвердилось: ретеншн по published_at работает и уже на линии (вклад кандидата — диагностика); точка восстановления из манифеста; 6/6 и 2/2 новых теста зелёные (на базе 4/6, 0/2 красные). БЛОКЕР — регресс `hetzbk-restore --target-lsn latest`: на манифесте, заканчивающемся сегментом …0003/…0004, цель выбирается на 1–2 сегмента дальше опубликованного WAL (effective_target_lsn=0/05FFFFFF при границе 0/04000000), печатается RESTORE PASS rc=0, а в конфиг пишется недостижимый recovery_target_lsn с promote — кластер не промоутится. Корень: manifest_has_segment() сравнивает 24-значные имена сегментов через awk как числа (схлопывание ~1e16 в double); дефект предсуществующий, но базу защищал min(MAX_MANIFEST_END_LSN, WINDOW_END_LSN), который кандидат снял. Тесты кандидата ловят только формы …0001/…0002. Смежно: тот же awk перекрывает одиночную дыру в манифесте (rc=0 и на базе). Сопутствующее: кадэнс манифестов 24→360/сутки без ветки manifest в hetzbk-retention; wal-partial убран из восстановления — RPO ~60 с → 240 с (изменение поведения прода). Отчёт: /home/ubuntu/waves/ACCHETZBKMERGE-REPORT.md (§2 блокер, §7 условия GO). Круг 2 автора = 1880-hetzbkmerge2 (A2, opus): строковое сравнение, вернуть страховку, latest не дальше последнего сегмента, ретеншн манифестов/клапан кадэнса, решение по wal-partial с явной строкой про RPO. Правила: WEB-449.
2026-09-05T00:28:49.649Z · координатор
HETZBKMERGE2 (1880, A2) — VERDICT=GO, commit 1fa1318b878eeb37567e06b1badbd54860e782d3 (два коммита поверх fc0fb6de), bundle HETZBKMERGE2.bundle sha c45d0003…. Все шесть замечаний приёмки круга 1 закрыты: корень awk-сравнения 24-значных имён WAL как чисел (>2^53) воспроизведён однострочником; (1) принадлежность сегмента манифесту — строковое сравнение через ассоциативный массив bash; (2) возвращена страховка min(MAX_MANIFEST_END_LSN, WINDOW_END_LSN) с тестом на копии с awk-дефектом; (3) барьер: до записи recovery_target_lsn проверка физического наличия каждого сегмента, иначе rc=96 вместо RESTORE PASS (promote при коротком архиве не падает, а не промоутится). Формы …0001…0006. Независимая приёмка → 1885-acchetzbkmerge2 (A2, opus; главное — latest на …0003/…0004, дыра, wal-partial/RPO, ретеншн манифестов). Правила: WEB-449.
2026-09-05T00:53:24.350Z · координатор
ACCHETZBKMERGE2 (1885, A2, opus) — VERDICT=GO для 1fa1318b878eeb37567e06b1badbd54860e782d3 (5 коммитов поверх l105, cherry-pick диапазона переигран начисто, дерево тождественно). Блокер круга 1 снят и проверен независимо на собственной фикстуре (awk-сравнение имён WAL-сегментов как double >2^53): строковое сравнение, страховка min(MAX_MANIFEST_END_LSN, WINDOW_END_LSN), барьер физического наличия сегментов (rc=96 вместо RESTORE PASS). Кандидат → l107 (l106 уже в сборке). После посадки: установить скрипты из дерева на A1 (infra/hetzbk/install.sh) и снять паузу репетиции — тогда RPO/RTO замер. Правила: WEB-449.
2026-09-05T01:28:25.713Z · координатор
Pi-standby (WEB-490) 01:21Z: FAIL rc=27 base/manifest disagree (manifest-20260904T221225Z vs base-20260905T010052Z) — подтверждает класс дефекта выбора точки/манифеста; ждёт посадки 1fa1318b (l107). Правила: WEB-449.
2026-09-05T01:41:11.748Z · координатор
KNOWN ISSUES / ТРАБЛШУТИНГ (правило владельца 05.09: в каждом тикете — чтобы смены не спотыкались об одно место):
(1) restore --target-lsn latest выбирает цель ЗА концом манифеста и печатает RESTORE PASS → корень: awk сравнивал 24-значные hex-имена WAL как числа (>2^53 схлопываются); проверка: фикстура манифеста, заканчивающегося …0003/…0004, `latest` должен упереться в последний сегмент, недостижимая цель → rc=96; лечение 1fa1318b (l107). (2) Издатель удалял свежий релиз: сортировка release_id как timestamp (l94 < l105 лексически) → сортировка по published_at из ready-маркера, текущий release_id исключён (на l105+). (3) Скрипты /usr/local/libexec/hetzbk-* НЕ обновляются посадкой → после каждой линии `sudo bash infra/hetzbk/install.sh` из wt-lNNN-migrate + `systemctl restart hetzbk-wal-stream` (проверка: `cmp` каждого bin с деревом, wal-stream «starting log streaming at …»). (4) Публикация релиза: `hetzbk-publish-release <NAME> <lNNN-sha8> <sha256> --release-dir … --start-wrapper … --required-files <полные относительные пути: pem:inner.sh:spend-runtime:spend-activation:flip-cap.secret:flip-cron.secret>`; composite пишется в /home/ubuntu/att-build-composite.json (перенести в lNNN-artifact/), затем HETZBK_ENV_LINE/HETZBK_ENV_ATTESTATION_FILE в /etc/hetzbk/hetzbk.env → `systemctl start hetzbk-env-pack`. (5) Кадэнс манифестов 360/сутки без ретеншна — открыто (круг 2 обещал ветку manifest). (6) git bundle с raw-SHA → «Refusing to create empty bundle»: нужен ref (`git update-ref refs/bundles/x <sha>`). Память: second-backend…, l105/l106-landing-facts, hetzbk-local-staging-unbounded.
2026-09-05T17:35:28.651Z · fable-coordinator
[2026-09-05 17:40Z] Ревизия доски (волна 2040 boardtriage, M1, luna): статус → review. Основание: owner GO на DR-rehearsal есть, посадка и прогон не подтверждены. Если работа жива — верни статус и напиши в тикет, какая волна её ведёт.
2026-09-10T18:55:03.750Z · coordinator
BOARD-WASH-20260910:WAVE-3339
По поручению владельца 18:43Z назначена исполнительская волна 3339 (infra), Codex gpt-5.6-luna xhigh, A1. Полная история карточки и база l115c 1ad52e16b доставлены, brief-guard и проверка Git-базы пройдены. Задача: проверить существующую сдачу, устранить остатки, передать бандл и доказательства. Финальная приёмка и посадка остаются за координатором. Запуск группы подтверждён в журнале диспетчера.
КАРТА ДОКУМЕНТОВ: ноут /Users/annakorin/nc-ops-scripts/board-wash-20260910/3339-wash-infra-brief.md; A1 /home/wave/waves/inputs/board-wash-20260910/infra-tickets.json; ожидаемый отчёт /home/wave/waves/3339WASHINFRA-REPORT.md. Правила обогащения: WEB-449.
2026-09-12T22:17:55.088Z · coordinator
[12.09 22:17Z координатор] МОЙКА 12.09 (3566-wash-g1-infra): репетиция восстановления прошла фазы 1/1b/1c, но до конца с чистым замером RPO/RTO не дошла. Скрипты hetzbk-rehearse/restore/warm-pull в дереве есть. Остаток: полный прогон до конца и новый замер против целей 5/15. Статус не меняю.
Остаток: Полный прогон репетиции до конца с новым замером RPO/RTO против целей 5/15.; Завести приёмку 1775 (ретенция) и дождаться 1776 (каденция манифеста).; Проверить hetzbk-env-pack на тот же дефект сортировки.
Отчёт: /Users/milamarty/waves/3566WASH*-REPORT.md (M4), копия nc-ops-scripts/shift-20260912-resume/wash-20260912/collected/. Проверка по исходнику прода l115g (9c8a9762).
2026-09-13T08:06:04.368Z · coordinator
[13.09 08:06Z координатор] РАЗБОР 13.09 (волна 3631, DeepSeek): Фазы 1/1b/1c прошли и автоматизированы, RESTORE PASS был, но до конца с чистым замером RPO/RTO репетиция не дошла: на 04.09 точка ~24 мин позади, распаковка 14.5 мин — цели 5/15 не достигнуты. Осталось немного: полный прогон по ранбуку до paid=200 и свежие цифры. Отдельно проверил env-pack на тот же дефект сортировки, что чинили в publish-artifact — тут дефекта нет, имена пакетов timestamp-first, можно закрывать записью. Приёмку ретенции 1775 завести, каденцию манифеста 1776 дождаться.
Остаток: Полный прогон репетиции до конца (до /api/ready/paid = 200, не только RESTORE PASS) с новым замером RPO/RTO против 5/15.; Завести приёмку 1775 (ретенция) и дождаться 1776 (каденция манифеста).; Проверить hetzbk-env-pack на тот же дефект сортировки (по выводам волны — дефекта нет).
Предложение: Полный прогон по ранбуку (RESULT.md): tee логов, JSON rehearsal-<run-id>.json с base_source=warm и числовыми rto_total/rpo_seconds, разложение t_restore/t_pg_start/t_app_health/t_paid, затем --teardown --run-id. RTO честно считать только по тёплому пути (4-7 мин), холодный 16-17 мин фиксировать как known issue. env-pack на дефект сортировки — проверено: имена timestamp-first, sort -r корректен (де
Материалы: shift-20260912-resume/colM2|colP2/ (RESULT.md — ранбуки и спецификации). Статус не меняю.
2026-09-13T10:45:16.963Z · coordinator
[13.09 10:45Z координатор] Мойка доски, волна 3653. RETURN: фазы 1/1b/1c выполнены, RESTORE PASS (t_restore 232с), тёплый путь RTO 4–7 мин, но чистый замер RPO/RTO до /api/ready/paid=200 не снят (04.09: точка ~24 мин позади / распаковка 14.5 мин — цели 5/15 не выполнены). Остаток: полный прогон на A2 + приёмка 1775 + 1776 — вне прав мойки. Статус не меняю.
2026-09-13T11:16:21.987Z · coordinator
[13.09 11:16Z координатор] См. комментарий к парной карточке: волна 3672 выдала сценарий репетиции от имитации потери до проверки платного пути, с критериями успеха и отказа на каждом шаге и отдельной методикой замера. Прогон — работа координатора, он требует боевых машин.
2026-09-13T14:01:06.794Z · coordinator
[13.09 14:01Z координатор] Волна 3712. [13.09 11:5xZ координатор] Волна 3712 выдала исполнимый документ для координатора — DR-RUNBOOK.md (12 шагов, из них 6 меняющих состояние, каждый с откатом; тёплый путь бюджет 4–7 мин против цели 15, холодный 16–17 мин фиксируется как known issue) и PREPARE-BEFORE.md (доступы/каталоги/место/окно). Проверка доведена до платного пути: /api/ready/paid=200 с paid=true (enforce_ready после spend-reconcile) + сверка count(LedgerEntry)==count(TerminalSpendEvent) + сходимость счётчиков с продом до T0. Замер: RPO=T0_wall−published_at ≤300с, RTO=t_paid (одно число от T0, не сумма подшагов). Сам прогон — работа координатора на боевых машинах (A2), у волны нет root/SSH; свежего числового замера по-прежнему нет. Статус не меняю.
2026-09-14T15:16:32.194Z · coordinator
[14.09 15:16Z координатор] # WEB-470 - блок для вставки

Источники, проверенные отсюда: тело тикета из live API; все 67 комментариев из локального `web-board.sqlite`, последний комментарий `id=4793` от 2026-09-13T14:01:06.794Z. Статус на live API при финальной сверке: `in_progress`. A2/Hetzner/paid-ready live отсюда не проверялись.

## Что болит словами пользователя

Нужно доказать, что после аварии можно поднять сайт, БД и воркеры на Oracle A2 из бэкапов Hetzner с измеренными RPO/RTO, а не держать набор частичных восстановлений.

## Что уже сделано и чем доказано

По истории: фазы 1/1b/1c прошли большой цикл. Есть RESTORE PASS из warm base с `t_restore=232s` в теле и близкое значение в комментариях; есть warm-pull на A2, artifact/env line, DR docs/runbook и исправления manifest/latest. Комментарии фиксируют, что отдельные ошибки были найдены и закрывались по кругам: загрузка лишних WAL, partial WAL boundary, artifact missing, start command/layout, awk-сравнение WAL names.

## Что осталось

Нет свежего clean full rehearsal до `/api/ready/paid = 200` с JSON, где есть `base_source=warm`, полный `rto_total`, `rpo_seconds` и факт paid-ready. Также остаются связки с acceptance 1775/1776 и WEB-082. Живой прогон на A2 с M1 не проверен.

## Противоречия между комментариями

Ранние “RESTORE PASS”, “RPO 3-6” и “warm path 4-7” отменяются как закрывающие доказательства поздними комментариями `id=4361`, `id=4556`, `id=4661`, `id=4793`: restore сам по себе был частичным, application/paid-ready stage не доказан, а измерение 04.09 не проходило целевые RPO/RTO.

## С ЧЕГО НАЧАТЬ НУЛЕВОМУ АГЕНТУ

Смотреть: `infra/hetzbk/`, DR runbook wave 3712, warm-pull на A2, последние comments `id=4361`, `id=4556`, `id=4661`, `id=4793`, плюс WEB-082. Первый шаг: подготовить и провести один полный read-only/sandbox rehearsal на A2 из warm base, с заранее заданным JSON-форматом доказательств.

Готово: в тикете приложен свежий rehearsal JSON с RPO/RTO, paid-ready, source base, точкой восстановления, командами и RC; acceptance 1775/1776 обновлены или явно вынесены.

Нельзя: трогать prod-БД, принимать restore PASS без app/paid-ready, перезаписывать `/etc/hetzbk/hetzbk.env`, считать зелёный manifest cadence доказательством восстановления.

Размер: несколько смен. Большим это делает live A2/backup rehearsal, связь с acceptance 1775/1776, root/host-действия и необходимость paid-ready proof.

## Закрытие и связи

Не закрыто. Сильное пересечение с WEB-082: WEB-470 исполняет DR-репетицию, WEB-082 держит backup/immutable gate.
2026-09-15T22:05:58.183Z · coordinator
ENRICH-4132-WEB-470
```markdown
## ДЕЛЬТА ОБОГАЩЕНИЯ — 2026-09-15T21:54Z, M1/4132 (DeepSeek Flash 4.1, read-only аудит), VERDICT=DRAFT_DELTA

### 1. Вердикт
Якорь в теле — l103 `d91ebefe` (04.09) — отстал примерно на семь линий. Живая линия —
**l115o `68e25d8df5ae8263c5ac5466353631f57a17cfcc`**. Полный чистый прогон до
`/api/ready/paid=200` со свежим замером RPO/RTO по-прежнему НЕ проведён.

### 2. КАРТА ДОКАЗАТЕЛЬСТВ
- Тело: фазы 1/1b/1c выполнены; RESTORE PASS `t_restore 232с`; тёплый путь RTO 4–7 мин
  (бюджет ≤8), холодный 16–17 мин; замер 04.09 инвалидирован (точка ~24 мин позади при цели
  RPO 5; распаковка 14.5 мин при цели RTO 15) — **цели НЕ достигнуты**.
- Тело: env-pack на дефект сортировки проверен, дефекта нет (имена timestamp-first).
- Тело/доска WEB-470 id 4793 (2026-09-13T14:01:06.794Z), волна 3712: исполнимый `DR-RUNBOOK.md`
  (12 шагов, 6 меняющих состояние, каждый с откатом) + `PREPARE-BEFORE.md`; проверка доведена
  до платного пути: `/api/ready/paid=200` с `paid=true` (enforce_ready после spend-reconcile) +
  сверка `count(LedgerEntry) == count(TerminalSpendEvent)` + сходимость счётчиков с продом до T0.
  Замер определён строго: `RPO = T0_wall − published_at ≤ 300с`, `RTO = t_paid` (одно число от T0,
  не сумма подшагов).
- HANDOFF-LIVE.md §7 строка 650: `/var/lib/hetzbk` (37 ГБ, резервные копии, RPO5/RTO15)
  НЕ трогать при расчистке диска.
- HANDOFF-LIVE.md строка 647: стенд замеров остановлен координатором (иначе посадка бы не прошла);
  прежним способом поднимать нельзя. **Это прямо ограничивает DR-прогон.**
- Доска WEB-470 id 5041 (2026-09-14T15:16:32.194Z): A2/Hetzner/paid-ready живьём отсюда не проверялись.

### 3. ЭВОЛЮЦИЯ / ПОПРАВКИ (append-only)
- Якорь: l103 `d91ebefe` → **l115o `68e25d8df5ae8263c5ac5466353631f57a17cfcc`**.
- Определение замера уточнено волной 3712 (единое `RTO = t_paid` от T0, не сумма подшагов;
  `RPO = T0_wall − published_at`). Прежние формулировки не использовать.
- Ограничение: стенд замеров на A2 остановлен; для нового прогона нужен другой способ подъёма
  (ждёт решения/машины).
- НЕ ПРОВЕРЕНО ОТСЮДА: живое состояние A2, Hetzner, paid-ready.

### 4. KNOWN ISSUES / ТРАБЛШУТИНГ
1. **Частичные восстановления принимаются за доказанный DR.**
   - Симптом: есть RESTORE PASS и числа RTO/RPO, но прогона до денежного пути на текущей
     линии нет.
   - Проверка за 2 минуты: найти в карточке receipt прогона, в котором есть одновременно
     `/api/ready/paid=200` с `paid=true`, сверка `count(LedgerEntry) == count(TerminalSpendEvent)`
     и явные `T0_wall`, `published_at`, `t_paid` → без этих полей прогон не засчитывается.
   - Причина: прогон дорогой и требует свободной машины и места.
   - Лечение/статус: провести один полный прогон по `DR-RUNBOOK.md`; цель RPO 5 / RTO 15
     остаётся недостигнутой до него.
   - Ссылки: тело; доска WEB-470 id 4793, id 5041.
2. **Стенд замеров остановлен и прежним способом не поднимается.**
   - Симптом: прогон негде выполнить.
   - Проверка за 2 минуты: проверить, поднят ли стенд и разрешён ли способ его подъёма →
     если нет, прогон не начинать.
   - Причина: стенд мешал посадке l115o и был остановлен.
   - Лечение/статус: дождаться нового способа/машины — координатор.
   - Ссылка: HANDOFF-LIVE.md строка 647.

### 5. ТЕКУЩИЙ ОСТАТОК (ответственный)
1. Один полный чистый прогон до `/api/ready/paid=200` со свежим замером RPO/RTO — координатор
   (после появления пригодного стенда).
2. Достижение целей владельца RPO 5 / RTO 15 — отдельная работа по итогам прогона.
3. Не трогать `/var/lib/hetzbk` при расчистке диска — координатор (постоянно).

### 6. ПЕРВЫЙ ШАГ НУЛЕВОГО АГЕНТА (без агентов)
Открыть `DR-RUNBOOK.md` и `PREPARE-BEFORE.md`, проверить по `PREPARE-BEFORE.md` доступы,
каталоги, место и окно. Если стенда нет — не начинать прогон, а записать в карточку, чего
именно не хватает. Сверить якорь тела с живым `/api/ready`.
```

---
2026-09-22T18:13:43.577Z · triage-neo
РЕШЕНИЕ=in_progress
ОСНОВАНИЕ=2026-09-15, ENRICH-4132: полный чистый прогон до /api/ready/paid=200 со свежим RPO/RTO не проведён; раздел «ТЕКУЩИЙ ОСТАТОК (ответственный)» назначает координатора
ЧТО НУЖНО=Координатору выполнить один полный прогон по DR-RUNBOOK после появления пригодной среды и приложить свежий JSON с RPO/RTO и paid=200; затем получить приёмку
triage-neo 4608
2026-09-23T12:42:42.358Z · triage-neo
РЕШЕНИЕ=in_progress
ОСНОВАНИЕ=2026-09-15, ENRICH-4132: полного чистого прогона до /api/ready/paid=200 со свежими RPO/RTO нет; цели 5/15 не доказаны.
ЧТО НУЖНО=первый шаг: координатору выполнить один полный DR-RUNBOOK-прогон и приложить свежий JSON с RPO/RTO, base_source=warm и paid=200; triage-neo 4712
2026-09-24T14:25:48.093Z · coordinator
[24.09 14:25Z координатор] Связано: WEB-686 — файлы пользователей прода не копируются (Pi-копия устарела). Карта всех копий приложена в WEB-686 и лежит у координатора nc-ops-scripts/BACKUP-MAP.md. 24.09: ящик 95 % → base прорежены 508→66, base ежедневно 03:10 UTC, порог возраста 26 ч.
Воркер
не проверен 3339-wash-infra A1 движение в панели: неизвестно
Подключиться и смотреть/перехватить руками. Колесо мыши листает; клавишами — Ctrl-b затем [, выход из прокрутки q. Отсоединиться — Ctrl-b затем d:
Прочитать историю панели без подключения — листается и ищется (/ поиск, q выход), воркеру не помешает:
Обновлён
2026-09-26T12:01:51.350Z