fix(memory): cleanup bloat and make memory-syncer self-maintaining (#167)
* fix(memory-syncer): enforce dedup, strict distillation, 100KB compaction, frontmatter fix * docs(handoff): add handoff and ADR-070 for memory cleanup and self-maintaining * docs(handoff): set PR number 167 * docs(handoff): fix Pending/Watch out sections + remove stale ADR comment * fix(memory-syncer): encoding artifact and trailing newlines --------- Co-authored-by: opencode-agent <agent@opencode.local>
This commit is contained in:
parent
27db3851b6
commit
6977a9130a
4 changed files with 123 additions and 6 deletions
|
|
@ -48,15 +48,19 @@ You are **read-only on the repository** and **write-only on memory**. You CANNOT
|
|||
|
||||
## Distillation
|
||||
|
||||
Distill durable-only records from the handoff:
|
||||
Distill durable-only records from the handoff. **Критерий durable: «поможет ли это в следующий раз когда я полезу в этот код?» Да → durable. Нет → НЕ пиши.**
|
||||
|
||||
Durable (записывай):
|
||||
- gotchas / workarounds (non-obvious behavior)
|
||||
- patterns, repository conventions
|
||||
- pointers: «for X use Y, careful with Z»
|
||||
- root causes of bugs
|
||||
- ADR pointers: `- [date, PR#N] ADR-NN: <суть> → docs/decisions/NN-title.md` (do NOT copy ADR content — only the pointer)
|
||||
|
||||
DO NOT distill: statuses, «currently working on», current tasks, ephemeral context.
|
||||
НЕ durable (НЕ записывай):
|
||||
- статусы, «сейчас работаем над», текущие таски, ephemeral контекст
|
||||
- **changelog-дампы**: «PR#N: добавили X», «PR#N: починили Y» — это changelog, код уже документирует что было сделано. Только неочевидные знания: gotchas, паттерны, root causes, ADR-указатели.
|
||||
- хроника событий, «x тестов passed», coverage %, количества файлов/коммитов — это метрики PR, не знания.
|
||||
|
||||
### Format
|
||||
|
||||
|
|
@ -76,9 +80,24 @@ Even if there are no durable records, the receipt is mandatory:
|
|||
|
||||
This confirms the memory-sync phase was executed (audit trail).
|
||||
|
||||
### Edit instead of duplicate
|
||||
### Дедуп перед записью (ОБЯЗАТЕЛЬНО)
|
||||
|
||||
If a fact is already recorded — update the entry (bump `updated` in frontmatter). Do not create duplicates.
|
||||
Перед добавлением записи — прочитай существующий файл. Если похожая запись уже есть (та же гоча/паттерн/root cause) → обнови существующую (bump `updated` в frontmatter, дополни детали если нужно), НЕ добавляй новую. Дубликаты раздули файлы до 600+ KB.
|
||||
|
||||
Пример: если «ffmpeg drawbox не поддерживает W/H» уже записан в PR#50 — не добавляй новую запись в PR#120 с той же гочей. Обнови `updated` и допиши нюанс если он есть.
|
||||
|
||||
## Compaction
|
||||
|
||||
Если после записи файл > 100 KB → компрессировать:
|
||||
1. Прочитай все старые записи
|
||||
2. Оставь только durable (gotchas, паттерны, root causes, ADR-указатели)
|
||||
3. Выкинь не-durable (changelog-дампы «PR#N: добавили X», статусы, хроника событий, receipts с повторяющимся содержанием, метрики PR)
|
||||
4. Объедини дубликаты (одна гоча → одна запись, bump `updated`)
|
||||
5. Tags-строку усечь до < 500 символов (оставить самые релевантные теги)
|
||||
6. Summary усечь до разумного размера (< 500 символов)
|
||||
7. Цель — держать файл < 100 KB
|
||||
|
||||
Критерий выкидывания: «поможет ли это в следующий раз когда я полезу в этот код?» Нет → выкидывай.
|
||||
|
||||
## Save
|
||||
|
||||
|
|
@ -97,6 +116,7 @@ If a fact is already recorded — update the entry (bump `updated` in frontmatte
|
|||
8. Для статуса PR используй нативный tool `pipeline-status` (НЕ bash `python3 .../pipeline-status.py` — детерминированный deny-rule, см. ADR-019).
|
||||
9. НЕ используй `git -C <path>` — работай в текущем cwd (memory-syncer читает уже смерженный default branch).
|
||||
10. НЕ делай `git checkout`/`git pull` — работаешь на уже смерженном default branch, переключаться не нужно.
|
||||
11. **Фронт-матч фикс**: если frontmatter целевого файла сломан (битые отступы в `updated:`/`related:`, невалидные `importance: 3`/`5`/`NA` вместо `high`/`medium`/`low`, лишние `---` разделители) → починить при записи. Valid `importance` values: `high` | `medium` | `low`. Frontmatter keys без отступов (`^(\w+):` требует `^` в начале строки).
|
||||
|
||||
## Bug Discovery
|
||||
|
||||
|
|
|
|||
|
|
@ -102,9 +102,13 @@ Default: `/root/.local/share/opencode/opencode-memory` (переопределя
|
|||
|
||||
Не копируй содержание ADR — только указатель на файл.
|
||||
|
||||
### Править вместо дублирования
|
||||
### Править вместо дублирования (ОБЯЗАТЕЛЬНО)
|
||||
|
||||
Если факт уже записан — обнови запись (bump `updated` в frontmatter). Не создавай дубликаты.
|
||||
Перед добавлением записи — прочитай существующий файл. Если факт уже записан — обнови запись (bump `updated` в frontmatter, дополни детали если нужно). **НЕ создавай дубликаты.** Дубликаты раздули файлы до 600+ KB. Каждая гоча/паттерн/root cause = одна запись, не по одной на каждый PR где упоминалась.
|
||||
|
||||
### Лимит 100 KB
|
||||
|
||||
Если после записи файл > 100 KB → компрессировать: прочитай все старые записи, оставь только durable (gotchas, паттерны, root causes, ADR-указатели), выкинь не-durable (changelog-дампы, статусы, хроника событий, receipts с повторяющимся содержанием, метрики PR). Tags-строка < 500 символов, summary < 500 символов. Цель — держать файл < 100 KB.
|
||||
|
||||
### Квитанция ставится всегда
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
# ADR-070: Make memory-syncer self-maintaining (dedup, strict distillation, 100KB compaction)
|
||||
|
||||
## Статус
|
||||
Accepted (2026-07-31)
|
||||
|
||||
## Контекст
|
||||
|
||||
Memory-файлы в `~/.local/share/opencode/opencode-memory/` раздулись до неконтролируемых размеров:
|
||||
- `video_uniq.md` = 623 KB / 1104 строк (584 changelog-дампов на 60 PR)
|
||||
- `opencode.md` = 135 KB / 298 строк (20 HTML-комментариев-мусора)
|
||||
- 4 файла-дубликата в `repos/` (старый путь) вместо `repos/github.com/slaid098/` (правильный путь per SKILL.md)
|
||||
- Битый frontmatter в 3 файлах (отступы 2 пробела, `importance: 3`/`5` вместо `high`/`medium`/`low`)
|
||||
|
||||
Корень проблемы: `memory-syncer.md` агент имел секцию «Edit instead of duplicate» как рекомендацию (не обязательное правило), не имел критерия durable (что записывать vs что НЕ записывать), не имел лимита размера файла и процедуры компрессии. Каждый PR добавлял changelog-дампы («PR#N: добавили X») вместо durable knowledge (gotchas, паттерны, root causes), receipts дублировали содержание записей.
|
||||
|
||||
## Решение
|
||||
|
||||
1. **Дедуп перед записью — ОБЯЗАТЕЛЬНО**: перед добавлением записи memory-syncer читает существующий файл. Если похожая запись уже есть (та же гоча/паттерн/root cause) → обновляет существующую (bump `updated`), НЕ добавляет новую. Дубликаты = root cause раздутия.
|
||||
|
||||
2. **Строгая дистилляция с критерием durable**: «поможет ли это в следующий раз когда я полезу в этот код?» Да → durable. Нет → НЕ пиши. Явный запрет changelog-дампов («PR#N: добавили X» — это changelog, код уже документирует), метрик PR (тестов passed, coverage %), хроники событий.
|
||||
|
||||
3. **Лимит 100 KB + Compaction**: если после записи файл > 100 KB → компрессировать (прочитать все старые записи, оставить durable, выкинуть не-durable, объединить дубликаты, усечь tags/summary). Цель — держать файл < 100 KB.
|
||||
|
||||
4. **Фронт-матч фикс при записи**: если frontmatter сломан (битые отступы, невалидные importance) → починить. Valid `importance`: `high` | `medium` | `low`.
|
||||
|
||||
5. **SKILL.md синхронизирован**: правило «править вместо дублирования» сделано обязательным (было рекомендацией), добавлен лимит 100 KB.
|
||||
|
||||
6. **Зеркало `~/.config/opencode/`** синхронизировано с repo-local `.opencode/` (cp + diff проверка).
|
||||
|
||||
## Альтернативы
|
||||
|
||||
1. **Только разовая чистка без фикса корня** — отклонено: файлы раздуются снова при следующем PR. Issue #166 явно требовал оба типа работы.
|
||||
2. **Автоматическая компрессия в memory-save tool** — отклонено: memory-save = commit + reindex, не должен модифицировать содержимое файлов. Компрессия = ответственность memory-syncer агента (контекст handoff нужен для решения что durable).
|
||||
3. **Лимит 50 KB** (жёстче) — отклонено: video_uniq.md после дистилляции = 25 KB, но репо с 60+ PR могут legitimately иметь ~80 KB durable knowledge. 100 KB = баланс.
|
||||
4. **Запрет receipts** — отклонено: receipts обязательны (audit trail что memory-sync фаза выполнена). Убрано только дублирование содержания в receipts (receipts с повторяющимся содержанием выкидываются при компакции, короткие receipts «— (нет durable-записей)» остаются).
|
||||
58
docs/handoff/pr-167-memory-cleanup-and-self-maintaining.md
Normal file
58
docs/handoff/pr-167-memory-cleanup-and-self-maintaining.md
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
---
|
||||
pr: 167
|
||||
title: fix(memory): cleanup bloat and make memory-syncer self-maintaining
|
||||
---
|
||||
|
||||
## Что сделано
|
||||
|
||||
### Часть 1: Разовая чистка файлов памяти (`~/.local/share/opencode/opencode-memory/`)
|
||||
|
||||
**1.1 Миграция 4 дубликатов путей** (repos/ → repos/github.com/slaid098/):
|
||||
- `antidetect-browser-mcp.md` — новый файл = надмножество (содержит все записи + handoff digest), старый удалён (`git rm`).
|
||||
- `digital_factory.md` — старый = architectural overview, новый = cross-project Telethon gotcha. Объединены: полный architectural overview + durable Telethon gotcha в правильный путь, старый удалён.
|
||||
- `opencode-voice-dictation.md` — старый = архитектурный обзор (Stack, Architecture, Gotchas), новый = PR digests PR#29-#39. Объединены: архитектурный обзор + PR digests + gotchas в правильный путь, старый удалён.
|
||||
- `slaid098-dev.md` — старый = ранняя версия (Key conventions: centralized tests, Biome config, NO pre-commit, legacy-peer-deps), новый = надмножество PR digests PR#68-#93. Уникальные conventions из старого добавлены в новый как секция "Key conventions", старый удалён.
|
||||
|
||||
**1.2 Фикс битого frontmatter**:
|
||||
- `repos/github.com/slaid098/telesoft.md` — отступы 2 пробела в `updated:`/`related:` → 0 пробелов.
|
||||
- `repos/code_keeper_api.md` — `importance: 3` → `importance: medium`.
|
||||
- `repos/youtube_comments.md` — `importance: 5` → `importance: low`.
|
||||
|
||||
**1.3 Удаление HTML-мусора**:
|
||||
- `repos/github.com/slaid098/opencode.md` — удалены 20 HTML-комментариев `<!-- updated: ... PR#N handoff digest -->` + лишние `---` разделители (строки 11-30).
|
||||
|
||||
**1.4 Дистилляция video_uniq.md**:
|
||||
- 623 KB / 1104 строк → 25 KB / 150 строк (96% сокращение).
|
||||
- Сохранены durable: ffmpeg gotchas (drawbox in_w/in_h, crop iw/ih post-scale, amix normalize=0, x265 несовместимости), pydantic model_copy no validation, frozen-safe paths, filter chain order, pHash testing (hash_size=16), pool-mechanism, channel loop resilience.
|
||||
- Выкинуты не-durable: 584 changelog-дампов («PR#N: добавили X»), receipts с повторяющимся содержанием, метрики PR (тестов passed, coverage %), хроника событий.
|
||||
- Tags усечены ~1.5 KB → ~200 символов, summary ~2.5 KB → ~400 символов.
|
||||
|
||||
**1.5 memory-save** — commit + reindex + push в memory-репо выполнен.
|
||||
|
||||
### Часть 2: Фикс корня — расширение memory-syncer (в репо)
|
||||
|
||||
**2.1 `.opencode/agents/memory-syncer.md`**:
|
||||
- **Дедуп перед записью** (ОБЯЗАТЕЛЬНО) — новая подсекция в Distillation: «Перед добавлением записи — прочитай существующий файл. Если похожая запись уже есть → обнови существующую (bump `updated`), НЕ добавляй новую.»
|
||||
- **Строгая дистилляция** — усиlena секция Distillation: явный критерий durable («поможет ли это в следующий раз когда я полезу в этот код?»), запрет changelog-дампов («НЕ записывай что было сделано в PR — это changelog, код уже документирует»), запрет метрик PR (тестов passed, coverage %).
|
||||
- **Лимит 100 KB** — новая секция «Compaction»: «Если после записи файл > 100 KB → компрессировать: прочитай все старые записи, оставь только durable, выкинь не-durable. Tags < 500 символов, summary < 500 символов.»
|
||||
- **Фронт-матч фикс** — новое правило 11 в Rules: «Если frontmatter целевого файла сломан (битые отступы, невалидные importance) → починить при записи.»
|
||||
|
||||
**2.2 `.opencode/skills/memory/SKILL.md`**:
|
||||
- Правило «править вместо дублирования» сделано ОБЯЗАТЕЛЬНЫМ (было рекомендацией) + объяснение (дубликаты раздули файлы до 600+ KB).
|
||||
- Добавлен лимит 100 KB с процедурой компрессии.
|
||||
|
||||
**2.3 Синхронизация зеркала**: `cp` в `~/.config/opencode/agents/memory-syncer.md` и `~/.config/opencode/skills/memory/SKILL.md`, проверка идентичности через `diff`.
|
||||
|
||||
## Почему
|
||||
|
||||
Память раздулась до неконтролируемых размеров (video_uniq.md = 623 KB / 1104 строк, opencode.md = 135 KB). Корень проблемы — memory-syncer агент не имел инструкций для дедупликации и компрессии, писал changelog-дампы вместо durable knowledge. Issue #166 требовал: (1) разовую чистку раздутых файлов, (2) фикс корня — сделать memory-syncer self-maintaining чтобы файлы не раздувались снова.
|
||||
|
||||
## Pending
|
||||
|
||||
— (PR завершён, closes #166; разовая чистка + фикс корня выполнены)
|
||||
|
||||
## Watch out
|
||||
|
||||
- Изменения файлов памяти (`~/.local/share/opencode/opencode-memory/`) НЕ в diff этого PR — они живут в отдельном memory-репо (commit + push через `memory-save`). В этом репо видны только фикс корня (`.opencode/agents/memory-syncer.md`, `.opencode/skills/memory/SKILL.md`).
|
||||
- Зеркало `~/.config/opencode/` синхронизировано вручную (`cp` + `diff`). Если кто-то правит `.opencode/` без синхронизации зеркала — drift.
|
||||
- Новое правило 100 KB compaction: первая компакция большого файла (например video_uniq.md 623 KB) может занять заметное время на чтение всех старых записей.
|
||||
Loading…
Add table
Reference in a new issue