From 62f19eeecbafc7f20923972b15c2c4e5eb75339f Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Tue, 29 Sep 2026 12:51:07 +0600 Subject: [PATCH] [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 --- personal/index.md | 3 + personal/plans/zulip-decommission.md | 101 +++++++++++ personal/projects/zulip-router.md | 5 + personal/tech/docker-mac-disk-issues.md | 6 + personal/tech/zulip-message-history.md | 227 ++++++++++++++++++++++++ 5 files changed, 342 insertions(+) create mode 100644 personal/plans/zulip-decommission.md create mode 100644 personal/tech/zulip-message-history.md diff --git a/personal/index.md b/personal/index.md index 629fedfd..7d0b1cce 100755 --- a/personal/index.md +++ b/personal/index.md @@ -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]] --- diff --git a/personal/plans/zulip-decommission.md b/personal/plans/zulip-decommission.md new file mode 100644 index 00000000..f40a91b1 --- /dev/null +++ b/personal/plans/zulip-decommission.md @@ -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 тормозил diff --git a/personal/projects/zulip-router.md b/personal/projects/zulip-router.md index de02e472..61105664 100755 --- a/personal/projects/zulip-router.md +++ b/personal/projects/zulip-router.md @@ -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-ботами (Валера, Клавдий). diff --git a/personal/tech/docker-mac-disk-issues.md b/personal/tech/docker-mac-disk-issues.md index 4cbb0ca8..46146211 100755 --- a/personal/tech/docker-mac-disk-issues.md +++ b/personal/tech/docker-mac-disk-issues.md @@ -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, все рабочие) diff --git a/personal/tech/zulip-message-history.md b/personal/tech/zulip-message-history.md new file mode 100644 index 00000000..8e67c6c1 --- /dev/null +++ b/personal/tech/zulip-message-history.md @@ -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 #`. + В БД лички в `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 из эксплуатации