Skip to content

fix(forgetting): the bin's label decides the table a restore writes into - #192

Merged
Cipher208 merged 1 commit into
masterfrom
fix/archive-label-routes-home
Nov 4, 2026
Merged

Cipher208 merged 1 commit into
masterfrom
fix/archive-label-routes-home

Conversation

@Cipher208

Copy link
Copy Markdown
Owner

Что

purge_speaker_layer_leaks архивировал эпизод с memory_type="episodes". route_of называет таблицу, откуда строка пришла, и ждёт единственное число episode; всё незнакомое падает в дефолт core_memory. Restore положил бы summary эпизода в core_memory.

строк с меткой "episodes" в живых базах 0 во всех трёх
значит дефект латентный, но replay вернул бы класс
проверено end-to-end план episodes=1 → apply → restore → episodes=1, core_memory=0, created_at сохранён

Второй дефект, найденный при проверке первого

После #191 restore переносит created_at, если в корзине есть original_created_at. Но _CARRIED_INTO_EPISODES — статический набор, поэтому not_recorded продолжал перечислять created_at как потерянный для строки, у которой время восстановлено.

not_recorded — это ровно то, что читает вызывающий, чтобы понять границы undo. Он занижал то, что вернулось.

_carried_into_episodes(row) теперь отвечает по строке: created_at входит в набор только если original_created_at есть и не NULL. Проверка идёт через row.keys(), а не "col" in row — на sqlite3.Row последнее смотрит значения и молча даёт False. Бин без колонки ведёт себя как NULL, что и означает.

Аудит всех меток

Прошли все memory_type=, которые пишутся в репозитории:

метка route_of верно
episode (7 сайтов) episodes да
core_memory (2 сайта) core_memory да
fact/question/log/goal/memory_kind core_memory да
project_archive None да, restore-пути нет
graph:<node_type> None да, у графа нет таблицы возврата
не задана (rag/conflict.py) None да, честный отказ

Других уводящих не туда нет.

Проверка

  • 2859 passed;
  • ruff check чисто, ruff format 755 файлов, mypy 42 = baseline;
  • blind verifier: 7/7 PASS, дефектов нет. Отдельно проверено: бин без колонки original_created_at восстанавливается и честно сообщает created_at; 0.0 считается записанным временем; откат каждой правки роняет свой тест.

Найдено, не тронуто

memory_type="core_memory" возвращает строку в правильную таблицу, но _restore_core кладёт эту метку в memory_kind → memory_kind="core_memory", что не валидный kind. Следствия: type-aware decay такие строки пропускает, kind-фильтрованные выборки их не видят. Порча тихая — схема голый TEXT. Отдельная находка со своим решением.

`purge_speaker_layer_leaks` archived an episode with `memory_type="episodes"`.
`route_of` names the TABLE the row came from and expects the singular `episode`;
anything it does not recognise falls through to the `core_memory` default. A
restore would therefore have written an episode's summary into `core_memory`.
Measured on the live bases, no row carries the wrong label, so the defect was
latent — but any replay that reintroduces the leak class would have produced
them. Fixed end-to-end: the episode now lands back in `episodes`.

While proving that, a second and opposite error turned up. Since #191 the restore
carries `created_at` when the bin recorded it, but `_CARRIED_INTO_EPISODES` is a
static set, so `not_recorded` still listed `created_at` as lost for a row whose
time WAS restored. That report is exactly what a caller reads to learn the limits
of undo, so it was understating what came back.

`_carried_into_episodes(row)` now answers per row: `created_at` joins the carried
set only when `original_created_at` is present and not NULL. The check goes
through `row.keys()` rather than `"col" in row` — on a `sqlite3.Row` the latter
tests VALUES and silently answers False — and a bin older than the column behaves
like NULL, which is what it means.

Audited every `memory_type=` written in the repository: no other label routes to
the wrong table. `graph:*` and `project_archive` are refused by design, the
`memory_kind` values and `core_memory` all route to `core_memory`, and a missing
label is refused rather than guessed.

Not fixed here, reported instead: `memory_type="core_memory"` routes to the right
table but `_restore_core` writes that label into `memory_kind`, which is not a
valid kind — such rows are skipped by type-aware decay and invisible to
kind-filtered reads. That is a separate finding with its own decision.
@coderabbitai

coderabbitai Bot commented Nov 4, 2026

Copy link
Copy Markdown

Important

  • Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@github-actions github-actions Bot added the fix label Nov 4, 2026
@Cipher208
Cipher208 merged commit c328b92 into master Nov 4, 2026
19 checks passed
@Cipher208
Cipher208 deleted the fix/archive-label-routes-home branch November 4, 2026 08:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant