Repository navigation
fix(forgetting): the report must say what actually happened - #194
Merged
Merged
Conversation
Three places stated more than is true, in code, in the audit trail, and in the
restore report.
Both purge scripts opened with "Every removed row is copied to
`archived_memories`". False: only episodes and core facts are archived;
`epi_nodes`, `epi_edges` and `epi_tags` are deleted outright. A node's content is
derived text — it already lives in an episode or a fact — and there is no restore
route for a node, so there is nothing a restore could return. The new docstrings
say exactly that, and state the cost plainly: after the purge the graph cannot be
rebuilt from the archive.
`purge_speaker_layer_leaks` then wrote one audit row per deleted node claiming
`archive: archived_memories:speaker_layer_leak` — the log asserted a bin copy that
does not exist. The node row now records `{"deleted": true, "table": "epi_nodes"}`
and no `archive` key, so a scan of audit_log can never infer a bin copy. The
"EVERY REMOVAL LEAVES A TRAIL" claim is corrected to match reality: facts, episodes
and nodes get a trail; edges and tags go with their node and leave none of their
own.
The restore report had the opposite defect — it said a value came back when it did
not. `EpisodicMemory.save` dedups on `(layer, user_id, summary)` and returns the
surviving row untouched, so a restore over an existing episode keeps that row's own
`created_at` and `emotional_weight`; the archive's values never land. Measured:
archived time 1700000000.0, surviving row 1700099999.0, and the report listed
`created_at` as returned. `_restore_episode` now reads the surviving row back and
reports any field that did not apply in `not_recorded`.
That read-back is the same question in both modes. In dry_run the report used to
stay optimistic — it claimed the time and weight would come back while the real
pass then said they did not. That is the drift the core branch fixed for the key
check, where the question is asked in both modes so preview and pass cannot answer
differently. Dry_run now runs the exact dedup query `save()` would run and reports
the same `not_recorded` as the pass, without writing anything.
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Что
Три места говорили больше, чем правда.
1. Оба скрипта открывались фразой «Every removed row is copied to
archived_memories». Это неверно: архивируются только эпизоды и факты, аepi_nodes/epi_edges/epi_tagsудаляются без архива. Контент узла — производный текст (он уже живёт в эпизоде или факте), и маршрута восстановления для узла нет, так что возвращать нечего. Новые докстринги говорят ровно это и честно называют цену: после прогона граф не восстанавливается из архива.2.
purge_speaker_layer_leaksписал на каждый удалённый узел audit-строку сarchive: archived_memories:speaker_layer_leak— журнал утверждал, что есть копия в корзине, а её нет. Теперь запись узла:{"deleted": true, "table": "epi_nodes"}, без ключаarchive. Утверждение «EVERY REMOVAL LEAVES A TRAIL» исправлено: трек есть у фактов, эпизодов и узлов; рёбра и теги уходят вместе с узлом без собственного трека. Существующие записиaudit_logне переписываются.3. Отчёт восстановления говорил обратное — что значение вернулось, хотя не вернулось.
EpisodicMemory.saveдедуплицирует по(layer, user_id, summary)и возвращает существующую строку как есть, поэтому её собственныеcreated_at/emotional_weightостаются. Замер: архивное время 1700000000.0, выжившая строка 1700099999.0 — отчёт утверждал, что время вернулось._restore_episodeтеперь читает выжившую строку обратно и сообщает неприменившиеся поля вnot_recorded.И это же чтение происходит в обоих режимах. В
dry_runотчёт оставался оптимистичным: обещал, что время и вес вернутся, а реальный проход потом говорил, что нет. Это тот самый дрейф, который веткаcore_memoryзакрыла для проверки ключа, задавая вопрос в обоих режимах.dry_runтеперь выполняет ровно тот дедуп-запрос, что иsave(), и сообщает тот жеnot_recorded, ничего не записывая.Проверка
dry_runи реальный проход дают идентичныйnot_recorded, выжившая строка хранит своё время;Вне объёма
memory_type=None→ честный отказunroutable, измерено — не дефект. Архивация графа — отдельное решение.