feat(memory): rotate repo memory files by size without compaction (#239)

* feat(memory-syncer): rotate files by 50KB size, dedup across files

* docs(memory-skill): document file rotation, remove inline compaction

---------

Co-authored-by: opencode-agent <agent@opencode.local>
This commit is contained in:
Sergey 2026-08-03 18:01:41 +03:00 committed by GitHub
parent b3aac737eb
commit 52343e2a78
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 30 additions and 16 deletions

View file

@ -80,24 +80,31 @@ Even if there are no durable records, the receipt is mandatory:
This confirms the memory-sync phase was executed (audit trail).
### Дедуп перед записью (ОБЯЗАТЕЛЬНО)
### Выбор файла для записи (ОБЯЗАТЕЛЬНО перед записью)
Перед добавлением записи — прочитай существующий файл. Если похожая запись уже есть (та же гоча/паттерн/root cause) → обнови существующую (bump `updated` в frontmatter, дополни детали если нужно), НЕ добавляй новую. Дубликаты раздули файлы до 600+ KB.
Память репо — один или несколько файлов по пути `<memory_dir>/repos/{host}/{org}/{repo}*.md`:
- первый файл: `{repo}.md`
- последующие (когда первый заморожен по размеру): `{repo}-002.md`, `{repo}-003.md`, ... (3-значный sequential, не по дате)
Пример: если «ffmpeg drawbox не поддерживает W/H» уже записан в PR#50 — не добавляй новую запись в PR#120 с той же гочей. Обнови `updated` и допиши нюанс если он есть.
Порог ротации: **50 KB** (soft). Файл с размером ≥ 50 KB считается замороженным — новые записи в него НЕ пишутся.
## Compaction
Перед записью:
1. Найди все файлы репо: `ls -la <memory_dir>/repos/{host}/{org}/{repo}*.md` (или `find`).
2. Активный файл = **первый существующий** с размером < 50 KB (не последний созданный, а первый по имени `{repo}.md`, затем `{repo}-002.md` ...). Проверяй размер через `ls -la` (или `wc -c`).
3. Если все существующие файлы ≥ 50 KB → создай следующий по sequential нумерации: `{repo}-NNN.md` где NNN — следующий свободный номер (3-значный: 002, 003, 004...). Скопируй frontmatter из предыдущего файла с обновлёнными `created` (текущая дата) и `updated` (текущая дата); `summary` можно сузить под содержимое нового файла; `tags`/`importance`/`related` — без изменений.
4. Новый репо без файлов → создай первый `{repo}.md` с нуля (текущее поведение).
Если после записи файл > 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
### Дедуп across files (ОБЯЗАТЕЛЬНО перед записью)
Критерий выкидывания: «поможет ли это в следующий раз когда я полезу в этот код?» Нет → выкидывай.
Перед добавлением новой записи — ищи дубликат по **всем** `repo*.md` (включая замороженные ≥ 50 KB):
1. `rg "<ключевая фраза гочи/паттерна>" <memory_dir>/repos/{host}/{org}/{repo}*.md` — ripgrep рекурсивно по всем файлам репо.
2. Если похожая запись найдена в **любом** файле (включая замороженный) → обнови её **in-place там же** (bump `updated` в frontmatter того файла, дополни детали если нужно), НЕ добавляй новую в активный файл.
3. Новые записи (не найденные как дубликат) → только в активный файл (см. выбор файла выше).
4. Замороженные файлы редактируемы для dedup (обновление существующих строк, bump `updated` в их frontmatter). Новые записи в замороженный файл — НЕ пишутся.
Дубликаты раздули файлы до 600+ KB. Каждая гоча/паттерн/root cause = одна запись в одном файле, не по одной на каждый PR где упоминалась.
Пример: если «ffmpeg drawbox не поддерживает W/H» уже записан в `youtube-soft.md` (≥ 50 KB, заморожен) в PR#50 — не добавляй новую запись в `youtube-soft-002.md` в PR#120 с той же гочей. Открой `youtube-soft.md`, обнови существующую строку, bump `updated` в frontmatter `youtube-soft.md`, допиши нюанс если он есть.
## Save
@ -108,7 +115,7 @@ This confirms the memory-sync phase was executed (audit trail).
1. NEVER call `git push`, `git commit`, `git add` — they are not in the allow-list and will be denied by the catch-all rule.
2. NEVER checkout branches or pull — you operate on the current state of the default branch (already merged).
3. ONLY edit files under `<memory_dir>/repos/{host}/{org}/{repo}.md`.
3. ONLY edit files under `<memory_dir>/repos/{host}/{org}/{repo}*.md` (активный файл + замороженные для dedup). НЕ создавай файлы вне этого pattern'а.
4. Read PR body via `gh pr view <N> --json body,title`. Optionally read `docs/decisions/*-pr-<N>-*.md` if exists (historical ADR). Do NOT read docs/handoff/ — handoff files are deprecated.
5. Receipt is mandatory even if no durable records found.
6. If memory file doesn't exist — create it with proper frontmatter (title, tags, summary, created, updated, importance).

View file

@ -106,9 +106,16 @@ Default: `/root/.local/share/opencode/opencode-memory` (переопределя
Перед добавлением записи — прочитай существующий файл. Если факт уже записан — обнови запись (bump `updated` в frontmatter, дополни детали если нужно). **НЕ создавай дубликаты.** Дубликаты раздули файлы до 600+ KB. Каждая гоча/паттерн/root cause = одна запись, не по одной на каждый PR где упоминалась.
### Лимит 100 KB
### Ротация файлов (50 KB)
Если после записи файл > 100 KB → компрессировать: прочитай все старые записи, оставь только durable (gotchas, паттерны, root causes, ADR-указатели), выкинь не-durable (changelog-дампы, статусы, хроника событий, receipts с повторяющимся содержанием, метрики PR). Tags-строка < 500 символов, summary < 500 символов. Цель держать файл < 100 KB.
Память репо ротируется по размеру вместо inline compaction:
- один репо → один или несколько файлов по пути `{memory-dir}/repos/{host}/{org}/{repo}*.md`
- первый файл: `{repo}.md`; последующие (когда первый заморожен): `{repo}-002.md`, `{repo}-003.md`, ... (3-значный sequential, не по дате)
- порог ротации: **50 KB** (soft). Файл с размером ≥ 50 KB считается замороженным — новые записи в него НЕ пишутся, открывается следующий файл
- замороженные файлы остаются редактируемыми для dedup (обновление существующих гоч, bump `updated` в их frontmatter); новые записи в замороженный файл — НЕ пишутся
- `memory-syncer` выбирает активный файл (первый существующий с размером < 50 KB) перед каждой записью и ищет дубликаты по всем `repo*.md` (включая замороженные) см. `memory-syncer` agent
Inline compaction удалён: память = durable выжимка (сжимать некуда), git = бесконечный backup (без отдельных archive-файлов). Receipts остаются в файлах (audit trail). Существующие большие файлы (`youtube-soft.md` 112 KB, `opencode.md` 80 KB, `opencode-config.md` 64 KB) миграции не требуют — при следующей записи откроется `-002.md`.
### Квитанция ставится всегда