[2026-09-29] eagle: personal/index.md personal/plans/zulip-decommission.md personal/projects/zulip-router.md personal/tech/docker-mac-disk-issues.md personal/tech/zulip-message-history.md

This commit is contained in:
Alexey Martemyanov committed 2026-09-29 12:51:07 +06:00
1 parent e75cf79e79
commit 62f19eeecb
5 files changed
+342

No files matched your search

+3
View File
@@ -146,6 +146,9 @@ Hub: [[personal/projects/media-pipeline-tracker-parsers|Media Pipeline Roadmap]]
- [[personal/tech/yandex-music-api|🎵 Yandex Music API — выгрузка библиотеки]]
- [[personal/tech/music-broken-toload|🗑 Аудио на перезагрузку — битые и DRM-файлы]]
- [[personal/tech/music-library-gap-analysis|🎵 Skill: дельта стриминг ↔ NAS (списки для Lidarr)]]
- [[personal/tech/zulip-message-history|💬 История Zulip в SQLite — поиск старой переписки]]
- [[personal/tech/docker-mac-disk-issues|🐳 Docker на Mac — диск VM, build cache, чистка]]
- [[personal/tech/hermes-whale-mattermost-transport|🐋 Hermes Whale — транспорт Mattermost]]
---
+101
View File
@@ -0,0 +1,101 @@
# План: вывод Zulip из эксплуатации (decommission)
_Создан: 2026-09-29_
## Цель
Снести Zulip-стек на Mac (Colima Docker), **сохранив историю переписки**.
Транспорт Hermes уже переехал на Mattermost — Zulip держится только ради истории.
## Состояние
| Этап | Статус |
|---|---|
| 1. Выгрузка истории в SQLite | ✅ сделано 2026-09-29 |
| 2. Верификация целостности | ✅ сделано |
| 3. Правка ссылок на Zulip DB в скиллах/SOUL | ⏳ план согласован, ждёт выбора варианта |
| 4. Снос стека | ⛔ не начато |
**Артефакт этапа 1:** `~/Documents/zulip_message_history.sqlite` (78.1 MB, 134 734 сообщения)
→ инструкция по поиску в [[tech/zulip-message-history]]
## Решение: формат истории
Рассматривались три варианта:
| Вариант | Плюсы | Минусы | Итог |
|---|---|---|---|
| `pg_dump` (custom format) | полный бэкап, восстановим одной командой | нечитаем без psql; тянет за собой весь Postgres | ❌ отклонён |
| Экспорт в markdown-файлы по тредам | читаемо в Obsidian, grep-абельно | 197 файлов, ломает структуру при правках, нет поиска по тексту | ❌ отклонён |
| **SQLite + FTS5** | один файл, структура тредов через FK, полнотекстовый поиск | нужен `sqlite3` CLI | ✅ **выбран** |
**Явное указание Alex:** «никаких вложений и меты. только история переписки».
Поэтому pg_dump, volume `zulip_zulip-data`, аплоады и аватары в выгрузку не попали.
## Открытый вопрос (шаг 3) — правка ссылок на Zulip DB
Найдено **7 групп файлов**, ссылающихся на `zulip-db-forensics` / `psql` к Zulip.
После сноса эти инструкции станут нерабочими.
| # | Файл | Ссылок |
|---|---|---|
| 1 | `~/.hermes/hermes-whale/SOUL.md:36` | 1 |
| 2 | `~/.hermes/hermes-whale/memories/USER.md` | 1 |
| 3 | `skills/software-development/zulip-db-forensics/SKILL.md` | основной |
| 4 | `skills/software-development/zulip-thread-handoff/SKILL.md` | 4 |
| 5 | `skills/software-development/zulip-bot-routing/SKILL.md` | 6 |
| 6 | `skills/software-development/project-progress-audit/SKILL.md` | 3 |
| 7 | `eagle-dashboard`, `systematic-debugging`, `personal-os-daily-brief`, `zfs-panic-recovery`, `htpc-steam-shortcuts` | по 1 |
**Предложенные варианты:**
- **A (чисто)** — переименовать скилл `zulip-db-forensics` → `message-history-search`,
перевести все 7 групп на SQLite. ~10 файлов.
- **B (минимально)** — только `SOUL.md` + `USER.md` + блок «ИСТОЧНИК = SQLite» в скилл. 3 файла.
- **C (гибрид, рекомендован)** — `SOUL.md` + `USER.md` + переписать тело
`zulip-db-forensics/SKILL.md` на SQLite, **имя скилла не менять** (8 входящих ссылок
переименование сломает без выгоды), в остальных файлах заменить только psql-команды.
**Решение не принято** — ждёт ответа Alex.
## Шаг 4 — снос (выполнять ПОСЛЕ шага 3)
```bash
cd ~/Developer/zulip
docker compose down
docker volume rm zulip_zulip-data zulip_zulip-pgdata zulip_zulip-rabbitmq zulip_zulip-redis
docker rmi zulip/docker-zulip:11.6-0
```
### 🔴 Порядок важен: сначала зависимости
1. **`zulip-router`** (`~/Developer/zulip-router/`, порт 8090) — поллит Zulip Events API.
Снести/остановить **до** Zulip, иначе словит restart-loop на мёртвом API.
2. **Hermes `platforms: zulip`** в `~/.hermes/config.yaml` — уже не используется (транспорт
Mattermost), но платформа в конфиге останется висеть. Убрать или выключить.
3. **Bot-роутинг** (Валера/Клавдий/Eagle/Кит webhook `host.docker.internal:8644-8645`) —
уходит вместе с Zulip. Balda-боты остаются без транспорта.
### Что освободится
| Ресурс | Объём |
|---|---|
| Образ `zulip/docker-zulip:11.6-0` | 3.84 GB |
| Volume `zulip_zulip-pgdata` | 503 MB (на диске) |
| Volume `zulip_zulip-data` | 38.1 MB |
| Контейнеры (5 шт) | ~260 MB |
## Проверка перед сносом (обязательно)
- [ ] `sqlite3 ~/Documents/zulip_message_history.sqlite "PRAGMA integrity_check;"` → `ok`
- [ ] `count(*)` из `messages` = **134 734**
- [ ] FTS-запрос по известному слову возвращает результаты
- [ ] Файл продублирован вне Mac (Time Machine / Kraken / NAS) — **не сделано**,
Alex не подтвердил необходимость
## Связанные документы
- [[tech/zulip-message-history]] — SQLite с историей и инструкция по поиску
- [[projects/zulip-router]] — архитектура роутера, конфиг ботов
- [[tech/hermes-whale-mattermost-transport]] — текущий транспорт Hermes
- [[tech/docker-mac-disk-issues]] — контекст: почему Zulip тормозил
+5
View File
@@ -2,6 +2,11 @@
_Последнее обновление: 2026-06-19 (forward_trigger, sender_email, data, stream_id — payload идентичен Zulip outgoing webhook)_
> ⚠️ **2026-09-29: роутер — кандидат на снос.** Zulip выводится из эксплуатации,
> история переписки выгружена в SQLite. Роутер поллит Zulip Events API и без Zulip
> уйдёт в restart-loop — сносить его нужно РАНЬШЕ стека Zulip.
> См. [[tech/zulip-message-history]] и [[plans/zulip-decommission]].
## Цель
Event-роутер между Zulip и balda-ботами (Валера, Клавдий).
+6
View File
@@ -104,6 +104,8 @@ colima ssh -- df -h /dev/vdb1
- [[projects/balda/setup]] — Balda агенты (Валера, Клавдий)
- [[how-to/hermes-eagle-mac]] — Hermes на Mac, Zulip Docker стек (RabbitMQ pitfall про Khepri)
- [[how-to/openmediavault-rpi5]] — build cache на RPi (та же проблема ENOSPC)
- [[plans/zulip-decommission]] — план сноса Zulip с сохранением истории
- [[tech/zulip-message-history]] — история переписки в SQLite (для поиска)
## ✅ Чистка 2026-09-29 — освобождено 41 ГБ
@@ -208,6 +210,10 @@ docker ps --format '{{.Names}} {{.Image}}' | grep -i balda # → пусто
⚠️ **На Kraken ничего не снесено** — там `balda-executor-mcp` работает,
текущий рабочий образ `balda-mm:0.1.15-pr8-480ec821-runtime210`.
> 📌 **2026-09-29 (позже в тот же день):** история Zulip выгружена в SQLite и
> Zulip готовится к сносу — см. [[tech/zulip-message-history]] и
> [[plans/zulip-decommission]]. Контейнеры `zulip-*` из списка ниже — кандидаты на удаление.
### Живые контейнеры (16, все рабочие)
+227
View File
@@ -0,0 +1,227 @@
# Zulip Message History — SQLite (поиск истории переписки)
_Создано: 2026-09-29_
## Что это
Вся история переписки Zulip (134 734 сообщения, 197 тредов, 11 стримов) выгружена в
**один SQLite-файл**. Zulip как транспорт выводится из эксплуатации — история остаётся
в этом файле.
| Параметр | Значение |
|---|---|
| **Файл** | `~/Documents/zulip_message_history.sqlite` |
| Размер | 78.1 MB |
| Сообщений | **134 734** (134 688 в стримах + 46 личек) |
| Стримов | 11 |
| Тредов (`topics`) | 197 |
| Источник | `zulip-database-1` (Postgres 14, `~/Developer/zulip/docker-compose.yml`) |
| Снимок на | 2026-09-29 |
| Бэкап | `~/backup/zulip-final/` (см. §Бэкапы) |
## Схема
```sql
streams (id, name) -- 11 каналов
topics (id, stream_id → streams.id, name) -- 197 тредов
messages (id, topic_id → topics.id, kind, sender,
sender_email, date_sent, content) -- 134 734
messages_fts (fts5: content, content='messages') -- полнотекстовый поиск
```
- `kind` = `stream` | `dm`
- `content` — **markdown-исходник** Zulip (не HTML-рендер); HTML был в `rendered_content`
и в дамп не попал осознанно
- `date_sent` — ISO-8601 UTC (`2026-09-29 06:29:41.829084+00`)
### Индексы
| Индекс | Назначение |
|---|---|
| `messages_fts` (FTS5) | поиск по тексту через `MATCH` |
| `idx_messages_topic` | сообщения одного треда |
| `idx_messages_date` | диапазон по датам |
| `idx_topics_stream` | треды одного стрима |
## Как искать историю (главное)
```bash
DB=~/Documents/zulip_message_history.sqlite
```
### 1. Поиск по тексту
```bash
sqlite3 "$DB" "
SELECT s.name AS stream, t.name AS topic, m.sender, m.date_sent,
substr(m.content, 1, 3000) AS content
FROM messages_fts f
JOIN messages m ON m.id = f.rowid
JOIN topics t ON t.id = m.topic_id
JOIN streams s ON s.id = t.stream_id
WHERE messages_fts MATCH 'docker jellyfin'
ORDER BY m.date_sent DESC LIMIT 30;"
```
### 2. Список тредов с количеством сообщений
```bash
sqlite3 -column -header "$DB" "
SELECT s.name AS stream, t.name AS topic, count(*) AS msgs
FROM messages m
JOIN topics t ON t.id = m.topic_id
JOIN streams s ON s.id = t.stream_id
GROUP BY t.id ORDER BY msgs DESC;"
```
### 3. Прочитать тред целиком
```bash
sqlite3 "$DB" "
SELECT m.date_sent || ' | ' || m.sender || char(10) || m.content || char(10) || '==='
FROM messages m
WHERE m.topic_id = (SELECT id FROM topics WHERE name = 'Home assistant setup' LIMIT 1)
ORDER BY m.date_sent;"
```
### 4. Найти сообщения конкретного человека по ключевым словам
```bash
sqlite3 "$DB" "
SELECT t.name, m.date_sent, substr(m.content,1,500)
FROM messages m JOIN topics t ON t.id = m.topic_id
WHERE m.sender = 'Alex' AND m.content LIKE '%план%'
ORDER BY m.date_sent DESC LIMIT 20;"
```
### ⚠️ FTS5-синтаксис
Токенизатор — `unicode61` (дефолт): поиск по **целым словам**, стемминга нет.
| Хочу | Запрос |
|---|---|
| слово `docker` | `MATCH 'docker'` |
| префикс `dock…` | `MATCH 'dock*'` |
| фраза | `MATCH '"zulip router"'` |
| AND | `MATCH 'docker jellyfin'` |
| OR | `MATCH 'docker OR jellyfin'` |
| НЕ | `MATCH 'docker NOT podman'` |
`собрал` **не** найдёт `собрать` — стемминга нет. Для поиска по подстроке внутри слова
нужен `trigram`-токенизатор (не включён; пересборка FTS-таблицы).
## Стримы и треды (снимок)
| Стрим | Сообщений | Тредов |
|---|---|---|
| personal | 111 534 | 95 |
| master | 7 630 | 29 |
| projects | 7 524 | 20 |
| executor | 7 355 | 32 |
| Zulip | 432 | 1 |
| daily-brief | 182 | 12 |
| general | 15 | 1 |
| inbox | 14 | 3 |
| journal | 1 | 1 |
| focus | 1 | 1 |
| Direct messages | 46 | 2 |
Крупнейшие треды (personal): `Home assistant setup` 12 196 · `truenas jellyfin` 12 059 ·
`Балда/валера` 9 454 · `ZONT Config compiler` 6 585 · `✔ media toolbox setup` 6 198.
## 🔴 Ограничение — база не живая
Файл — **снимок на 2026-09-29**. После сноса Zulip новые сообщения сюда не попадают.
Живой поиск свежей переписки — только в Mattermost (`hermes-maintenance`,
`a6nyh77eyjbn5c1owh1i8eebee`). Разделять явно: «историческое (до 29.09)» → SQLite;
«что обсуждали вчера» → Mattermost.
## Как это было сделано (воспроизводимо)
1. **Экспорт из Postgres в CSV.** Ключ — `\copy` (не `COPY`), потому что `COPY` через
`docker exec` требует прав на файл внутри контейнера, а `\copy` пишет в stdout.
Колонки: `id, kind, stream, topic, dm_user_id, sender, sender_email, date_sent, content`.
```bash
docker exec zulip-database-1 psql -U zulip -d zulip -c "\copy (
SELECT m.id, 'stream' AS kind, s.name AS stream, m.subject AS topic, 0 AS dm_user_id,
u.full_name AS sender, u.email AS sender_email, m.date_sent, m.content
FROM zerver_message m
JOIN zerver_recipient r ON r.id = m.recipient_id
JOIN zerver_stream s ON s.id = r.type_id
JOIN zerver_userprofile u ON u.id = m.sender_id
WHERE r.type = 2 ORDER BY m.id
) TO STDOUT WITH (FORMAT csv, HEADER false)" > /tmp/zulip-export/messages.csv
```
Личные сообщения (`r.type = 1`) — отдельным запросом в `dms.csv`, топик = `DM user #<id>`.
В БД лички в `zerver_recipient.type_id = 1`, у них нет `subject` — отсюда синтетический топик.
2. **Сборка SQLite** — скрипт `build_sqlite.py` (Python stdlib `csv` + `sqlite3`), создаёт
таблицы, наполняет `streams`/`topics`/`messages`, строит индексы и наполняет FTS5.
3. **Верификация** — `PRAGMA integrity_check`, `PRAGMA foreign_key_check`,
`count(*)` против Postgres, FTS-запрос по реальному слову.
### 🔴 Питфоллы, которые стоили времени
- **TSV рвётся на многострочном контенте.** Первый заход был с `-A -F$'\t'` → вместо
134 688 строк получилось **486 751** (переносы строк внутри сообщений режут TSV).
Решение: `WITH (FORMAT csv)` — кавычки экранируют переносы корректно. `wc -l` на CSV
всё равно покажет завышенное число переносов — это ожидаемо, **считать строки нужно
парсером, а не `wc`**.
- **`rendered_content` — это HTML.** Для читаемой истории нужен `content` (markdown).
HTML-дамп бесполезен без рендера.
- **`content` может содержать что угодно** — включая NUL и гигантские блоки кода.
В `build_sqlite.py` нужен `csv.field_size_limit(50MB)`, иначе падает на больших сообщениях.
- **CSV-колонок было 9, а проверял на 8** — первая сборка дала 0 сообщений и
134 734 ошибки «bad field count». Читать позиционно по факту заголовка, не по памяти.
## Бэкапы
| Что | Где |
|---|---|
| SQLite (история) | `~/Documents/zulip_message_history.sqlite` |
| CSV-дампы | `/tmp/zulip-export/messages.csv` (56 MB), `dms.csv` (18 KB) |
| Compose + env Zulip | `~/Developer/zulip/docker-compose.yml`, `.env.zulip` |
## Что НЕ выгружалось (осознанно, по указанию Alex)
Только переписка + структура тредов. Вне выгрузки:
- вложения/аплоады (`volume zulip_zulip-data`, 38.1 MB — `uploads/`, `certs/`)
- аватары, реакции, подписки, метаданные организаций
- настройки стримов, права, история изменений сообщений
Если понадобится картинка из старого треда — её в SQLite нет, она была в volume.
## Снос Zulip — чек-лист
⚠️ **Пока не выполнено.** Файл сделан как страховка перед сносом.
```bash
cd ~/Developer/zulip
docker compose down
docker volume rm zulip_zulip-data zulip_zulip-pgdata zulip_zulip-rabbitmq zulip_zulip-redis
docker rmi zulip/docker-zulip:11.6-0 # ~3.84 GB
```
Стек: `zulip-zulip-1` (`zulip/docker-zulip:11.6-0`, порты 8000/8443), `zulip-database-1`
(`zulip/zulip-postgresql:14`), `zulip-rabbitmq-1`, `zulip-memcached-1`, `zulip-redis-1`.
Объём volumes ≈ 1.1 GB (pgdata 503 MB на диске, БД 439 MB; data 38 MB).
### ⚠️ Зависимости, которые сломаются
| Компонент | Что будет |
|---|---|
| `zulip-router` (Go, `~/Developer/zulip-router/`) | мёртвый — поллит Zulip Events API. Убрать из compose, иначе restart-loop |
| `zulip-bot-routing` (Еagle/Кит/Валера/Клавдий webhook) | маршрутизация в Zulip перестанет работать |
| Hermes `platforms: zulip` в `~/.hermes/config.yaml` | платформа отвалится; транспорт уже переехал на Mattermost |
## Связанные документы
- [[projects/zulip-router]] — архитектура event-роутера (Go), конфиг ботов
- [[tech/hermes-whale-mattermost-transport]] — текущий транспорт Hermes
- [[how-to/hermes-eagle-mac]] — Hermes на Mac, Zulip Docker стек, RabbitMQ/Khepri pitfall
- [[tech/docker-mac-disk-issues]] — почему Zulip тормозил (переполнение диска VM)
- [[plans/zulip-decommission]] — план вывода Zulip из эксплуатации