Persistence scope — что переживает петлю

Технический механизм петли времени: тег persistence_scope на событии определяет, что сбрасывается при loop reset и что сохраняется навсегда.

Петля сбрасывает мир — но не персонажей. Чтобы система умела это различать, каждое событие (в целевой модели) несёт тег persistence_scope. При свёртке мира (loop reset) фильтр оставляет только события текущего loop_id плюс те, что помечены как постоянные.


Три тега

persistence_scopeЧто означаетСбрасывается?
loopСостояние мира: инвентарь, позиции NPC, сюжетные флаги, лутДа — при reset
characterПамять персонажа: уровни, навыки, выученные спеллы, личные фактыНет — переходит в следующую петлю
metaМета-сюжет: НПС «помнит, что кто-то делал», последствия не для мира, но для памятиНет

Loop reset = создание нового loop_id. Запросы следующей петли автоматически фильтруют out все scope='loop' события прошлых петель.

Что есть в проде сейчас

В коде scope не реализован как явное поле. Вместо него — неявная привязка через данные:

  • Транзакции (деньги, предметы) привязаны к loop_number + day_in_loop — при «просмотре прошлой петли» просто фильтруется по loop_number. Фактически это scope='loop'.
  • Хроники персонажа — отдельная таблица chronicles, привязанная к node_id (PC-нода). При новой петле хроники не удаляются — они накапливаются. Фактически это scope='character'.
  • Нода персонажа (уровни, поля чарлиста) — один живой snapshot, не лог. Обновления перезаписывают. Это самое грубое место: нет журнала «каким был чарлист в начале петли 3».

Линейная модель: одна активная петля

Сейчас система линейна: одна active (status=current) петля, остальные past. Прошлые петли read-only — их данные видны в хрониках и в ленте бухгалтерии, но не редактируются.

Ветвление петель (branch_id) зарезервировано для будущего. В целевой архитектуре поле branch_id с дефолтом 'main' прошито в схему events. При linear gameplay branch_id везде 'main' — это ничего не стоит и не мешает.

Что означает loop reset технически

  1. DM создаёт новую loop-ноду с incremented number и статусом current.
  2. Предыдущая петля переходит в past.
  3. Starter setup (spec-012) запускается по новой петле: каждый PC получает стартовый набор транзакций (scope='loop' — сбрасываемые).
  4. Запросы автоматически фильтруются по loop_number — «вид» мира обновляется без удаления данных.

Прошлые петли как архив

Всё, что было в прошлых петлях, остаётся в БД. Петли past — это хроника кампании. Future «time-travel UI» позволит просматривать состояние мира на любой день любой петли — без дополнительных миграций, просто фильтрацией по loop_number.


loop-as-core.md — нарратив и структура петли. → event-sourcing.md — почему append-only, а не обновления записей. → roadmap/generic-events-table.md — переход к явному полю persistence_scope в универсальном events логе.