# Правила и условия формирования кадров эпизодической памяти (ЭП)

## 1. Общая схема эпизодической памяти

ЭП — массив кадров в **строгой исторической последовательности**. Порядок не перемешивается; допускаются только изменение и удаление без нарушения порядка.

**Правило (кадр эпизода):**  
Стимул (образ FinalImage) → ответное действие (образ действия, ОД) → эффект (Effect) → ответный стимул оператора (при наличии).

**Содержимое кадра:**
- `perceptionNodeId` — ID конечной ветки дерева восприятия (условия);
- `stimulusImageId` — ID образа стимулов (FinalImage), вызвавшего реакцию;
- `actionImageId` — ID образа ответного действия (ОД);
- `effect` — разность `getDiffImportance()` «после» минус «до» (до активации стимула);
- `responseStimulusImageId` — ID образа ответного стимула оператора (если появился в период ожидания).

Ответное действие + ответный стимул образуют «учительское» правило: как оператор отвечает на действие Beast.

**Время ожидания ответа** — `response_waiting_period` в **пульсах** (по умолчанию 15). Закрытие по таймауту выполняется в `EpisodicMemory_onPulse` (вызов из puls.js). В течение периода ожидается либо ответный стимул оператора, либо фиксация эффекта. Кадры с незаполненным `effect` остаются на оптимизацию (например, во время сна).

---

## 2. Условия запуска формирования кадра ЭП

Формирование кадра ЭП **запускается только через ориентировочный рефлекс (ОР)**. Кадр создаётся когда:

1. **ОР сработал** — выбран «победитель» среди активных стимулов (наиболее актуальный образ).
2. **Выполнены условия ОР** (есть активные стимулы, ветка дерева, победитель, у победителя `samplesCount >= OR_well_known`; см. раздел 4).
3. Либо **идёт период ожидания** — тогда активация сначала обрабатывается как **ответный стимул** (без проверки `OR_well_known`), затем выполняется **второй полный проход ОР** с новым кадром ЭП и ФО (см. раздел 4). Либо периода ожидания нет — действуют обычные условия порога известности.

Вызов `save_episodic_memory(perceptionNodeId, stimulusImageId)` выполняется из ОР после блокировки рефлекса и вызова гиппокампа. **Кадр и прогресс-бар периода ожидания создаются при каждом таком срабатывании ОР** (не только при отсутствии значимости или в тестовом режиме).

---

## 3. Жизненный цикл кадра

1. **Создание (при срабатывании ОР):**
   - Закрывается предыдущий незакрытый кадр (если есть): перед `closeLastFrame` вызывается `episodicFrameFillRuleZerosForIncompleteClose(prev)` — в пустые поля ОД и ответного стимула пишется **0**; затем в `closeLastFrame` ответным стимулом предыдущего кадра становится **текущий** `stimulusImageId` (новый победитель ОР), вычисляется `effect` в [-10, +10].
   - В массив ЭП добавляется «пустой» кадр: заданы `perceptionNodeId`, `stimulusImageId`, `diffBefore` (из `PrevDiffForEpisode` / `getDiffImportance`), `actionImageId = null`, `effect = null`, `responseStimulusImageId = null`.
   - Устанавливаются `EpisodicMemory_waitingStartedAt` и счётчик пульсов ожидания; закрытие по таймауту выполняется в `EpisodicMemory_onPulse` (пульсы, не таймер). Прогресс-бар отображается только при активном ожидании в этой сессии (`waitingStartedAt != null` или показ 100% после закрытия с ответом).

2. **Заполнение ответным действием:**  
   Когда Beast выполняет реакцию (генетическую или условную), в последний кадр записывается `actionImageId` (образ действия) через `EpisodicMemory_setLastFrameActionFromActionId(actionId)`. Используется `stimulusImageId` уже записанный в кадре (чтобы кадр заполнялся и при отложенной реакции или снятых стимулах).

3. **Завершение кадра:**
   - **Ответный стимул в период ожидания:** при активации стимула ОР **сначала** проверяет `EpisodicMemory_isInWaitingPeriod()`. Если истинно, текущий стимул считается ответом оператора — вызывается `closeLastFrame` с ответным образом (экспорт `EpisodicMemory_closeLastFrameWithResponse`). Порог `OR_well_known` для этого шага **не проверяется**. Затем открывается **новый** открытый кадр (`save_episodic_memory`) по образу ответа, выставляется флаг `OrientationReflex_resumeFullOrAfterWaitingResponse`, и ОР вызывается **повторно** в той же активации: второй проход — полный (гиппокамп, `stimuls_consciousness` с контекстом победителя ОР, снова `save_episodic_memory`), чтобы начался новый цикл ФО и корректный кадр ЭП без «тишины мысли», блокирующей победителя уже отобранного конкуренцией.
   - **Истечение периода без ответного стимула:** в `EpisodicMemory_onPulse` при достижении `response_waiting_period` пульсов кадр **закрывается** (`closeLastFrame`), а не удаляется. Если реакции не было (`actionImageId` всё ещё `null`), перед закрытием в поля правила проставляются **нули** (ОД и ответный стимул → 0), выставляются индикаторы «игнорирование / нет ответа», затем полный пайплайн закрытия включая **абстракции** (`AbstractImages_cloneFromEpisodeFrame`). Если реакция была, закрытие — с уже записанным `actionImageId`, без подстановки нуля в ОД.
   - У **закрытого** кадра `effect` **всегда число** в **[-10, +10]** (ограничение дельты `getDiffImportance` или 0 при отсутствии `diffBefore`).

Пока открыт кадр без `effect`, «чужой» стимул в основном сценарии трактуется как ответ оператора; после закрытия и открытия кадра по ответу сразу следует **полный** ОР (см. выше), а не только одно закрытие без ФО.

**Преемственность оценки эффекта (ЭП ↔ автоматизмы):** При закрытии кадра один и тот же вычисленный `effect` (после `clamp` в [-10,+10]) записывается в кадр ЭП и передаётся в штатный автоматизм ветки через `Automatizms_addUsefulnessSample(staff.id, last.effect)`. Оценка эффекта единая: не дублируется, не расходится между ЭП и автоматизмами.

**Абстракции:** см. раздел 9 ниже и `about_episodic_memory.md` («Связь с абстрактными образами»).

---

## 4. Ориентировочный рефлекс (ОР) и условия для ЭП

ОР вызывается при активации стимулов (например, по клику). **Порядок проверок в ОР:**

1. **Нет активных стимулов** — массив пуст (деактивация). ОР выходит **без сообщения**; уже созданный кадр ЭП и период ожидания не отменяются.
2. Нет ветки дерева восприятия / не выявлен победитель — выход с сообщением в тестовом режиме.
3. Регистрация экспозиции в семантической памяти (один раз за активацию).
4. **Проверка «второго полного прохода» после ответа:** если установлен `OrientationReflex_resumeFullOrAfterWaitingResponse`, флаг сбрасывается; порог `OR_well_known` **не проверяется**; выполняется полный путь как в п. 7 (контекст ОР передаётся в `stimuls_consciousness` с признаком победителя ОР — см. `about_conscience.md`).
5. **Иначе — проверка периода ожидания:** если `EpisodicMemory_isInWaitingPeriod()` истинно, действует ветка ответного стимула (закрытие кадра, открытие следующего, планирование п. 4, рекурсивный повтор `runOROnStimulusActivation`). Порог `OR_well_known` для ответного стимула **не применяется**.
6. **Затем** проверка порога известности: для образа-победителя `samplesCount < OR_well_known` (по умолчанию 10) — отказ в создании нового кадра, сообщение в тестовом режиме (в состоянии «Плохо» порог не действует; см. код `orientation_reflex.js`).
7. Иначе — блокировка рефлекса, гиппокамп, `stimuls_consciousness(orContext)`, вызов `save_episodic_memory(terminalNodeId, winnerId)`. Кадр и прогресс-бар создаются **всегда** при этом срабатывании ОР.

**Период ожидания:** `isInWaitingPeriod()` возвращает true только если `EpisodicMemory_waitingStartedAt != null` и последний кадр без effect и счётчик пульсов не достиг лимита. Незакрытый кадр, загруженный из IndexedDB после обновления страницы, не считается активным ожиданием (waitingStartedAt не восстанавливается), чтобы первый клик создавал новый кадр с прогресс-баром от 0%.

---

## 5. Режим тестирования формирования ЭП

Включается кнопкой «т» в блоке «Активная ветка дерева восприятия». Флаг: `global.EpisodicMemory_testMode`.

**В тестовом режиме:**

- При **деактивации** (нет активных стимулов) сообщение **не показывается** — это нормальное действие.
- При **отказе** в создании нового кадра (когда период ожидания не активен) выводятся причины:
  - нет функций дерева восприятия или образов;
  - не найдена или не создана ветка дерева восприятия;
  - не выявлен наиболее актуальный стимул среди кандидатов;
  - опыт семантической значимости слабый (samplesCount < OR_well_known) — **не применяется к ответному стимулу в период ожидания**.
- При **начале формирования кадра** — «Начат процесс формирования кадра ЭП. Стимул: (детализация). Ожидание ответа или реакции. Прогресс-бар периода ожидания запущен.»
- При **фиксации ответного действия** (реакция Beast) — «Активирован образ стимула: (детализация). Вызвавшая реакция: (детализация). Период ожидания ответа начат.»
- При **появлении ответного стимула в период ожидания** — «Стимул в периоде ожидания: (детализация). Кадр эпизода завершен и записан.»
- При **истечении периода без реакции** — кадр **закрывается с нулями** в правиле; в тестовом режиме сообщение поясняет, что эпизод записан и абстракция восприятия усиливается по эффекту (формулировка — в коде `episodic_memory.js`).

Прогресс-бар отображается при активном ожидании в этой сессии независимо от тестового режима. В тестовом режиме добавляются только пошаговые сообщения.

---

## 6. Условные рефлексы в контексте ориентировочного рефлекса

**Правило:** если стимул **привлёк ориентировочный рефлекс**, по нему **не запускается процесс образования условного рефлекса**.

**Механизм:**

1. ОР при срабатывании **блокирует** выполнение генетического (или условного) рефлекса на 2 пульса (`OR_BLOCK_PULSES`). Рефлекс не выполняется сразу, а помещается в очередь отложенных рефлексов (`delayedReflexes`).
2. При постановке в очередь и при последующем выполнении отложенного рефлекса в событие записывается флаг **`noConditionalReflex: true`**.
3. Когда отложенный рефлекс выполняется, в `startAction` передаётся опция `noConditionalReflex: true`. При этой опции **не вызывается** `synonyms_onGeneticActionFired` — подсистема условных (синонимических) рефлексов не получает сигнал для формирования или усиления условного рефлекса по данному стимулу.

Таким образом, стимул, который привлёк ОР (т.е. по которому рефлекс был задержан), не участвует в образовании условного рефлекса; условные рефлексы формируются только по стимулам, по которым рефлекс сработал без блокировки ОР.

---

## 7. Связные цепочки кадров: приоритет перед «обрывающими» стимулами

**Мотивация.** Несколько кадров ЭП подряд могут образовать смысловую цепочку (например: действие → ответ оператора → следующий стимул). Стимулы, входящие в такую цепочку, не должны проигрывать конкуренцию посторонним активным стимулам, у которых нет зафиксированной реакции или которые не продолжают сценарий ожидания ответа — иначе цепочка постоянно обрывается.

**Определение (суффикс цепочки).** От конца массива `Episodes` идём назад и считаем подряд кадры, у **каждого** из которых задан ненулевой `actionImageId` (реакция уже привязана к кадру). Если длина такого суффикса **≥** `EpisodicMemory_chainPriorityMinFrames` (по умолчанию **2**), все `stimulusImageId` и ненулевые `responseStimulusImageId` этих кадров помечаются как стимулы **приоритета цепочки**.

**Реализация.**

- `EpisodicMemory_getChainPriorityStimulusSet()` — словарь id стимулов приоритета или `null`, если цепочки нет.
- `EpisodicMemory_isStimulusEpisodicChainPriority(finalImageId)` — проверка одного стимула.

**Ориентировочный рефлекс** (`findMostActualStimulus`): для кандидата с приоритетом цепочки **не** вычитается гистерезис относительно прошлого победителя; актуальность **повышается** (линейное масштабирование + смещение), чтобы при прочих равных выигрывал стимул, продолжающий сценарий ЭП.

**ФО, главный цикл** (`stimuls_consciousness`): понижение конкурирующего стимула («тишина мыслей») и сравнение с порогом `INTERRUPT_THRESHOLD_ATTENTION_RATIO` действуют **только пока есть главный цикл и он ещё не помечен `expired`**. Если главного нет или он уже завершён, эти ограничения не применяются.

Дополнительно:

- стимул **приоритета цепочки** ЭП — как и раньше: не применяются множитель несовпадения темы/ситуации и штраф при `ImportantProblem`, порог прерывания берётся с коэффициентом **1.0**;
- стимул, переданный из ОР как **победитель конкуренции** (`orientationReflexWinner` в контексте), **не отсекается** порогом «тишины мыслей» относительно текущего главного цикла: иначе ОР выбрал бы актуальный стимул, а ФО не создал бы новый цикл.

Один изолированный кадр с реакцией приоритета не даёт: нужны **минимум два** подряд кадра в суффиксе.

---

## 8. Сводка ключевых констант и флагов

| Параметр | Описание | Значение по умолчанию |
|----------|----------|----------------------|
| `response_waiting_period` | Длительность периода ожидания ответа (**в пульсах**) | 15 |
| `OR_well_known` | Порог числа семантических образцов для **начала** нового процесса ОР/ЭП (не для ответного стимула) | 10 |
| `EpisodicMemory_testMode` | Режим пошаговых сообщений по формированию ЭП | false |
| `OR_BLOCK_PULSES` | Число пульсов блокировки рефлекса после ОР | 2 |
| `EpisodicMemory_chainPriorityMinFrames` | Мин. длина суффикса кадров с `actionImageId` для приоритета цепочки в ОР/ФО | 2 |

**Прогресс-бар:** виден только при `EpisodicMemory_waitingStartedAt != null` или `EpisodicMemory_barShowCompletePulsesLeft > 0` (активное ожидание в этой сессии или показ 100% после закрытия с ответом). После обновления страницы не отображается до первой активации стимула, запустившей ОР.

**isInWaitingPeriod():** возвращает true только при `EpisodicMemory_waitingStartedAt != null` (ожидание начато в этой сессии). Загруженный из IndexedDB незакрытый кадр не даёт true, чтобы первый клик после обновления создавал новый кадр с прогресс-баром от 0%.

Файлы реализации: `_10_Episodic_memory/episodic_memory.js`, `_8_Hippocampus/orientation_reflex.js`, `_7_perception_tree/perception_tree.js`, `_5_Genetic__reflexes/genetic_reflexes_engine.js`.

---

## 9. Эффект, нули в полях правила, абстракции (краткая сводка)

| Момент | Поведение |
|--------|-----------|
| Закрытие кадра | `effect` ∈ [-10, +10], всегда число; см. `clampEpisodeFrameEffect` |
| Нет ОД или нет ответа к моменту закрытия | `episodicFrameFillRuleZerosForIncompleteClose` → в пустые поля **0** (в истории не `null` в закрытом кадре для этих слотов) |
| Таймаут, реакции не было | Не `ep.pop`: нули + `closeLastFrame(null)` + абстракции / ментальные правила |
| Новый ОР при открытом предыдущем кадре | Нули на предыдущем при необходимости + `closeLastFrame(новый стимул)` |
| Сохранение compact | `"0"` в action/response читается как **0**, не как `null` (`parseIntOrNull`) |
| `abstract_images.js` | Всегда вызов из `closeLastFrame`; клон ОД только если `actionImageId` ненулевой; **0** = не клонировать действие |

Реализация: `episodic_memory.js` (`closeLastFrame`, `EpisodicMemory_onPulse`, `episodicFrameFillRuleZerosForIncompleteClose`), `abstract_images.js`, `mental_automatism.js` (`MentalRules_registerFromEpisodeFrame`).
