# Конфликты и сводки

> Как MMW показывает расхождения между версиями одного факта и почему сводка не прячет нерешённые конфликты.

Из этой страницы вы узнаете:

1. когда запись получает статус `conflict` и почему MMW ничего не перезаписывает молча;
2. как сделать сводку через `derived_from`, чтобы она не скрывала противоречий;
3. как разрешить конфликт.

Пример на всю страницу: в понедельник агент Анны сохранил, что staging выкатывается через systemd-юнит `app-staging`. В четверг агент Бориса сохранил, что staging теперь выкатывается через Docker Compose. Кто прав — решать людям, а не памяти.

## Когда возникает конфликт

Записи сравниваются по `fact_key`. Если в одной рабочей области есть несколько записей с одинаковым ключом, но разным **содержимым или хешем источника**, все они получают статус `conflict`.

```text
  workspace default, fact_key = deploy.staging.method
  ────────────────────────────────────────────────────────────────
  A  пн  «через systemd-юнит app-staging»          → conflict
  B  чт  «через Docker Compose, сервис staging»    → conflict
```

- **Ничего не перезаписывается.** `remember` всегда добавляет новую запись, даже с тем же ключом. Старая версия остаётся и помечается.
- **Конфликт виден обеим сторонам.** Помечается не только старая, но и новая запись: сервер не знает, какая из них верна.
- **Новейшая версия — первой.** В `search` самая новая запись с этим ключом стоит выше старых, даже если старая совпадает с запросом лучше. Если запросу соответствует только старая версия, новая подтягивается в выдачу рядом с ней. У старых версий поле `superseded_by` содержит ID новейшей.
- **Одинаковый текст — не конфликт.** Если та же формулировка сохранена повторно с тем же хешем источника, расхождения нет.
- **Тот же текст с новым хешем — конфликт.** Если документ изменился и вы пересохранили факт с новым `source_hash`, не удалив старый, версии разойдутся по хешу. Сначала удалите старое — см. [Источник и свежесть](/memory/source-and-freshness/).
- **Границы.** Сравниваются только записи одной рабочей области, которые вы можете видеть. Записи без `fact_key` в конфликт не попадают.

## Что видит агент

```json title="search: «как выкатывается staging»"
[
  {
    "id": "b3e1…",
    "content": "staging выкатывается через Docker Compose, сервис staging",
    "fact_key": "deploy.staging.method",
    "status": "conflict",
    "created_at": "2026-10-08T14:03:00+00:00"
  },
  {
    "id": "a7d2…",
    "content": "staging выкатывается через systemd-юнит app-staging",
    "fact_key": "deploy.staging.method",
    "status": "conflict",
    "superseded_by": "b3e1…",
    "created_at": "2026-10-05T09:12:00+00:00"
  }
]
```

Новейшая версия — это подсказка, а не вердикт. Если новую запись сохранили как исправление, это видно по `superseded_by`; если нет уверенности, правильная реакция агента — не выбирать вариант по дате, а сказать человеку: «В памяти два противоречащих факта о выкатке staging: от 5 и от 8 октября. Какой актуален?»

## Сводки: derived_from

Со временем записей становится много, и агент сжимает их в сводку. Чтобы сводка не стала «чистой» версией с потерянными противоречиями, передайте ID исходных записей в `derived_from`:

```json title="remember"
{
  "content": "Итоги недели по деплою: staging переводится на Docker Compose; миграции запускаются make migrate до выкатки",
  "fact_key": "deploy.weekly-summary.2026-w41",
  "derived_from": ["a7d2…", "b3e1…", "c9f0…"]
}
```

- в `derived_from` — до 50 ID, и только существующих записей, которые вы видите; иначе ошибка `derived_from contains unknown memory ids`;
- в результатах `search` у сводки есть поле `derived_from` со списком источников;
- **сводка наследует худший статус** своих источников: если хоть один из них в `conflict` или `stale`, сводка тоже. Наследование проходит до трёх уровней (сводка сводок тоже видит проблему).

В нашем примере сводка получит статус `conflict`, хотя её собственный текст ни с чем не спорит: противоречие в её основе не решено.

## Как разрешить конфликт

1. **Выясните, какая версия верна.** Спросите человека или перечитайте источник. Не решайте по дате: более новая запись не обязательно правильная.

2. **Удалите неверную версию** через `forget` по её ID:

   ```json title="forget"
   { "memory_id": "a7d2…", "workspace": "default" }
   ```

   Удаление мягкое: запись пропадает из поиска и графа, факт удаления остаётся для аудита.

3. **Проверьте результат.** В следующем `search` запись B уже `unverified`: у ключа осталась одна версия.

4. **Обновите сводку при необходимости.** Удалённые источники больше не влияют на статус сводки, поэтому, если у остальных источников всё в порядке, она тоже станет `unverified`. Но её текст мог опираться на неверную версию — если так, сохраните новую сводку и удалите старую.

Не «решайте» конфликт, сохраняя третью запись с тем же ключом: это просто третья версия, и все три будут в `conflict`. Конфликт исчезает, только когда у ключа остаётся одна версия содержимого.

## Конфликт и архивариус

[Архивариус](/memory/archivist/) работает рядом, но иначе. Он может заметить, что новая запись опровергает одну из недавних, даже без общего `fact_key`, — и пометить старую как `stale`, понизив её уверенность. Ничего при этом не удаляется. Конфликт по `fact_key` — строгое правило сервера, а отметки архивариуса — оценка модели.

## Что дальше
