# Проект BeastJS – реализация существа на гомеостатических принципах

Глава 1: Введение и фундаментальные принципы

Проект BEAST (Browser-based Embodied Agent Simulation and Testing) представляет собой браузерное приложение, моделирующее индивидуальную адаптивность. Его цель — не создание «работающего существа», а формализация и реализация теории адаптивных систем в виде программного кода. Проект служит инструментом для изучения и отладки архитектуры, где каждая деталь поведения системы является следствием строгих, документированных и выполняемых алгоритмов.

В папке /demos/ проекта BEAST есть демо для показа реализованных принципов.

1.1. Назначение проекта

Проект BEAST позиционируется как наиболее адекватный способ реализации теории индивидуальной адаптивности. Аналогично тому, как математика формализует физические законы, BEAST служит формализацией для теории адаптивных систем. Код выступает не просто как продукт, а как спецификация и схема работы системы, позволяя тестировать, модифицировать и отлаживать адаптивное поведение.

В рамках проекта сознательно исключены сложные вербальные интерфейсы (распознавание фраз, символы, тон сообщений). Фокус сделан на базовых слоях: гомеостаз, базовые контексты, стимулы, рефлексы, дерево условий, семантическая и эпизодическая память, процесс осознания и автоматизмы. Это позволяет удерживать систему в границах управляемой сложности, сосредоточившись на ядре адаптивности.

1.2. Ядро архитектуры: от организма к сознанию

Архитектура BEAST построена вокруг иерархической модели, где каждый новый слой абстрагирует и усложняет поведение предыдущего.

1. Гомеостаз (тело): Базовый уровень, представленный виталами (_1_Genetic_vitals). Это набор параметров (Раны, Голод, Стресс и т.д.), значения которых динамически меняются (shift) с каждым пульсом. Состояние виталов определяет интегральную значимость состояния организма (IntergalConditionImportance) и его базовое состояние: Плохо (1), Норма (2), Хорошо (3) (BadNormWell).
2. Контекст (эмоция): На основе выхода виталов из нормы активируются базовые контексты (_2_Genetic_basic_styles) — поведенческие паттерны (Страх, Агрессия, Игра, Любопытство, Покой и др.). Их комбинация формирует «эмоцию» (EmotionId), которая, вместе с базовым состоянием и текущим стимулом, задает ветку дерева восприятия (_7_perception_tree). Эта ветка (branchId) является ключевым идентификатором условий, в которых находится система.
3. Стимулы и рефлексы (вход-выход): Оператор взаимодействует с системой через кнопки-стимулы (_3_perception). Комбинация активных стимулов образует конечный образ (FinalImageId). В ответ на стимулы срабатывают генетические рефлексы (_5_Genetic__reflexes), запуская базовые действия (Плачет, Ест). Эти действия регистрируются как образы действия (ОД) (_10_actions_image). Система также способна формировать условные рефлексы (_5_2_synonyms_reflexes), связывая конечный образ с действием в определенном контексте.
4. Память (опыт): Каждое взаимодействие с миром оставляет след.

- Семантическая память (_6_semantic_memory) запоминает, насколько значим (meanImportance) тот или иной стимул в определенных условиях (базовое состояние + эмоция). Это основа для оценки «полезности» или «вредности» стимула.
- Эпизодическая память (_10_Episodic_memory) фиксирует правила: стимул → действие → эффект (effect). Каждый кадр памяти — это цепочка «условия (ветка) → действие → последствие (изменение значимости)». Если оператор отвечает своим стимулом в период ожидания, это фиксируется как «учительское правило» (responseStimulusImageId).

5. Осознание (сознание): Это центральный процесс, управляющий поведением. Он организован как реестр циклов осмысления (ConsciousnessCycles) и итеративный диспетчер (consciousness_dispatcher.js).

- Ориентировочный рефлекс (ОР) (_8_Hippocampus) является спусковым крючком. Он выбирает наиболее актуальный стимул из всех активных, оценивая его новизну и значимость. При успешном прохождении порога (OR_well_known) он запускает процесс осознания (stimuls_consciousness) и создает кадр эпизодической памяти.
- Уровень 1 (элементарный) пытается найти готовый ответ: либо позитивное правило из ЭП, либо штатный автоматизм для данной ветки.
- Уровень 2 (conscience_level_2.js) вступает в игру, если нет готового решения. Здесь определяется цель: либо выживание (критический витал, резкое ухудшение), либо более сложные цели из жизненного опыта (лучшее правило с положительным эффектом). Здесь же обрабатывается ответ оператора, полученный после действия.
- Уровень 3 (conscience_level_3.js) — это пайплайн поиска сложных решений, включающий ментальные автоматизмы, правила из семантической структуры абстракций и учительский fallback. Он строго управляется гейтом ожидания, чтобы не запускать повторный поиск, пока не получена обратная связь.
- Уровень 4 (conscience_level_4.js, gestalt.js) — это гештальт-уровень, работающий с долгоживущими доминантами (нерешенными задачами) и кросс-цикловыми аналогиями через буфер резонанса.

1.3. Время: Дискретный пульс

Фундаментальной единицей времени в BEAST является пульс (puls.js). Это искусственное, дискретное время, в котором выполняется большая часть системных процессов.

- Каждый пульс обновляет виталы, активирует контексты, обрабатывает генетические и условные рефлексы, а также дает шаг диспетчеру циклов осознания.
- Важные процессы, связанные с ожиданием (например, период ожидания ответа оператора в ЭП), измеряются именно в пульсах, а не в реальном времени. Это обеспечивает детерминированность и предсказуемость, позволяя избежать проблем с асинхронностью и таймерами.
- Все процессы, которые должны происходить синхронно с изменениями состояния (например, регистрация эффекта после действия), привязаны к пульсу, что исключает состояние гонки между событиями пользовательского интерфейса и внутренней логикой.

1.4. Ключевые понятия

- Виталы (VitalsArr) — параметры состояния организма, изменяющиеся со временем. Их значение и скорость изменения (shift) заданы генетически.
- Базовые контексты (BasicContexts) — поведенческие/эмоциональные режимы, активируемые выходящими из нормы виталами. Определяют «настрой» системы.
- Конечный образ (FinalImageId) — уникальный идентификатор для каждой комбинации активных стимулов.
- Условия — набор из базового состояния (BadNormWell) и эмоции (EmotionId), определяющий контекст, в котором стимул воспринимается.
- Ветка дерева (perceptionNodeId) — полный путь из 6 уровней (базовое состояние → эмоция → стимул → ...), уникальный идентификатор ситуации.
- Образ действия (ОД, ActionImageId) — абстракция действия, которая может включать одно или несколько базовых действий.
- Эффект (effect) — количественная оценка изменения интегральной значимости состояния после совершения действия. Диапазон [-10, +10].
- Автоматизм — правило, привязанное к ветке дерева (branchId), которое предписывает выполнить определенный ОД при активации этой ветки. Имеет полезность (usefulness).
- Гештальт — долгоживущая доминанта (нерешенная задача), связанная с образом цели. Способна накапливать аналогии и приводить к инсайтам.

Глава 2: Пульс и поток обработки: от стимула к действию (исправленная версия)

В этой главе мы проследим путь сигнала в системе BEAST — от момента нажатия оператором кнопки стимула до финального изменения состояния системы (действия, обновления памяти, смены контекста). Это позволит понять, как дискретный пульс синхронизирует все компоненты и обеспечивает целостность поведения.

2.1. Жизненный цикл пульса

Центральный цикл системы реализован в файле beast/puls.js. Это рекурсивная функция sep_of_puls(), которая имитирует «сердцебиение» существа, вызывая себя с задержкой в 1 секунду (или меньше, если обработка заняла больше времени). Каждый пульс — это строго определенная последовательность шагов:

№ | Шаг | Описание
1 | Фиксация «нулевой» значимости | Вызов getDiffImportance() сохраняет текущее состояние в PrevDiffForEpisode для будущего расчета эффекта ЭП
2 | Сохранение в IndexedDB | runIndexedDBSavesForPulse() — все модули с флагом dirty записывают свое состояние
3 | Инкремент пульса | Cur_puls_val++, обновление UI и localStorage
4 | Тик эпизодической памяти | EpisodicMemory_onPulse() — счетчик ожидания ответа, закрытие кадра по таймауту
5 | Обновление виталов | performSensorOperations() — сдвиг значений по shift, учет активных стимулов
6 | Обновление контекстов | getActiveBasicContexts() — расчет BadVitalsValue, выбор BasicContextsActived, обновление BadNormWell
7 | Обновление UI | Контексты, ветка дерева, инфокартина (Info_updateFromPerceptionTree)
8 | Стартовый цикл (пульс 3) | Если нет главного цикла, создается начальный цикл осмысления со стимулом 0
9 | Диспетчер сознания | dispetchConsciousnessThinking() — шаг главного цикла, шаг фоновых (раз в 5 пульсов)
10 | Рефлексы | processGeneticReflexes() — отложенные, условные, генетические рефлексы
11 | Сброс флага УР | EpisodicMemory_skipConditionalReflexFormation = false
12 | Визуализация пульса | Мигание зеленого кружка в UI

2.2. Ориентировочный рефлекс (ОР) как спусковой крючок

ОР (orientation_reflex.js) запускается при любом изменении набора активных стимулов (клик по кнопке). Это центральный механизм выбора того, на что обратить внимание.

2.2.1. Алгоритм выбора победителя

Шаг 1: Сбор кандидатов

Полный набор активных стимулов → FinalImageId (образ полной картины)

Каждый активный стимул отдельно → FinalImageId (образ одного стимула)

Шаг 2: Расчет актуальности для каждого кандидата

text

Копировать

Скачать

актуальность = новизна × значимость

Компонент | Формула | Примечание
Новизна | (meanImportance × samplesCount) / 10 | Если нет семантики → 1. Умножается на коэффициент отсутствующих уровней дерева (×2, ×3, ×4, ×5, ×6)
Значимость | meanImportance из семантики | Если нет → (сумма importance виталов) / (количество виталов × 20)
Множитель цепочки ЭП | ×2 + 1 | Для стимулов из суффикса кадров с реакциями (≥2 кадра подряд)

Шаг 3: Конкуренция и гистерезис

У всех кандидатов, кроме прошлого победителя, вычитается OR_HYSTERESIS = 0.5

Если активна «Важная проблема» (ImportantProblem), гистерезис удваивается (×2)

Стимулы из приоритетной цепочки ЭП не подвергаются гистерезису

Шаг 4: Пороговые проверки после выбора победителя

Проверка | Условие | Действие
Период ожидания ЭП | EpisodicMemory_isInWaitingPeriod() = true | Закрыть текущий кадр с ответом = победитель, открыть новый кадр по победителю, запустить повторный ОР (второй проход)
Достаточность опыта | samplesCount < OR_well_known (10) | Не создавать кадр ЭП, не запускать ФО. Исключения: состояние «Плохо» (well=1), стимулы Еда/Вода (1001, 1002)
Регистрация семантики | Всегда | Вызов registerSemanticSample для накопления статистики значимости

Шаг 5: Запуск полного цикла (если все проверки пройдены)

Сохранение победителя в гиппокампе (actual_stimul_ID)

Блокировка рефлексов на 2 пульса (setBlockedReflex)

Добавление в очередь отложенных рефлексов (addBlockedReflexToQueue) с привязкой к branchId

Вызов stimuls_consciousness(context) — вход в процесс осознания

Создание кадра эпизодической памяти (save_episodic_memory)

2.3. Процесс осознания: от входа до действия

Функция stimuls_consciousness (conscious_attention_channel.js) — это шлюз, который определяет, стоит ли прерывать текущую мысль новым стимулом.

2.3.1. Порог прерывания («тишина мысли»)

Если есть активный главный цикл осмысления и он еще не помечен expired, новый стимул конкурирует с ним:

Базовый порог:

text

Копировать

Скачать

эффективная_значимость_стимула ≥ thinkingImportance_главного × INTERRUPT_THRESHOLD_ATTENTION_RATIO (1.5)

Модификаторы эффективной значимости:

Ситуация | Модификатор
Тема/ситуация стимула ≠ теме/ситуации главного цикла | × 0.5
Активна «Важная проблема» (ImportantProblem) | × 0.5
Стимул из приоритетной цепочки ЭП | нет проверки порога
Стимул — победитель ОР (orientationReflexWinner) | нет проверки порога

Если значимость стимула недостаточна, вызов stimuls_consciousness завершается без создания нового цикла.

2.3.2. Создание цикла осмысления

Если порог преодолен:

Текущий главный цикл (если есть) пушится в стек прерываний (ConsciousnessBackgroundStack)

Создается новый цикл (Consciousness_createCycle) с весом (weight) = значимости стимула

Новый цикл становится главным (Consciousness_setMainCycle)

2.3.3. Элементарный проход (уровни 1–2)

Новый цикл сразу же выполняет Consciousness_runElementary:

Уровень 1 — Поиск автоматического решения:

Ветка | Условие | Действие
Позитивное правило ЭП | Семантика стимула < 0 и есть правило в ЭП для родительской ветки с effect > 0 | Запуск автоматизма через info_automatismWithEpisodeFeedbackAndExpireCycle
Штатный автоматизм | Есть автоматизм для ветки с isDefault=true и usefulness ≥ 0 | Запуск автоматизма

Уровень 2 — Постановка цели и решение (если автоматизм не запущен):

Фиксация unsolved_problem = актуальный стимул

Вызов conscience_level_2(context)

Определение цели (приоритет сверху вниз):

Приоритет | Тип цели | Условие | Действие
1 | Выживание | isShockState или suddenChange или criticalVital | Поиск жизненного опыта с positive usefulness → автоматизм; если нет — цепочка по Target_rule_stack; если нет — умолчательная цель «Плачь»
2 | Жизненный опыт | Есть цель для ветки с effect > 0 | Запуск автоматизма по этому ОД
3 | Смысл (meaning) | Значимость стимула > 3 и нет цели по ветке | Прогноз по ЭП, обновление гештальта, усиление абстракций
4 | Нет цели | Исчерпаны варианты | Режим passive у цикла

Если автоматизм запущен на любом из этих уровней:

Цикл помечается expired и переводится в фоновые

Устанавливается флаг awaitingAutomatismEpisodeFeedback = true

В EpisodicMemory_pendingFeedbackAutomatizmId записывается ID запущенного автоматизма

Цикл ожидает ответа оператора (закрытия кадра ЭП)

2.4. Рефлексы на пульсе: генетические и условные

Обработка рефлексов (processGeneticReflexes) происходит на каждом пульсе после диспетчера сознания. Это гарантирует, что если осознание уже запустило автоматизм, рефлекс по той же ветке не сработает.

2.4.1. Порядок обработки

Очередь | Что обрабатывается | Как
1. Отложенные рефлексы | Рефлексы, заблокированные ОР на 2 пульса | Выполняются, если не были удалены (removeDelayedReflexesForBranch) при запуске автоматизма
2. Условные рефлексы | synonyms_tryRunReflexes() | Проверка зрелых рефлексов (tryCount > 3) с совпадением stimulIds и контекста
3. Генетические рефлексы | Сравнение текущих и предыдущих активных стимулов | Для каждого нового стимула из карт рефлексов выбирается действие

2.4.2. Формирование условных рефлексов

Условный рефлекс создается при вызове synonyms_onGeneticActionFired (из startAction), если:

Источник действия — не 'synonym' (не повторный запуск по УР)

Нет флага noConditionalReflex (рефлекс не был заблокирован ОР)

Нет периода ожидания ЭП

Активных стимулов больше одного (чтобы было что сочетать)

Структура условного рефлекса:

context: строка "well:id1,id2" — состояние + базовые контексты

stimulIds: массив глобальных ID стимулов, которые были активны кроме вызвавшего реакцию

actionId: ID базового действия

tryCount: число сочетаний (порог зрелости = 3)

isReady: флаг готовности (становится true при tryCount > 3)

2.5. Действие и регистрация в памяти

startAction (genetic_reflexes_engine.js) — финальная точка, где действие становится фактом.

Действие | Что происходит
UI | Обновление блока «Активность Beast» с названием действия и значимостью стимула
Режим | Info_setMode('target') — перевод инфокартины в целевой режим
Образ действия | ActionsImage_registerReaction(finalImageId, actionId) — создание/дополнение ОД
Эпизодическая память | EpisodicMemory_setLastFrameActionFromActionId(actionId) — запись действия в открытый кадр
Условные рефлексы (обучение) | synonyms_onGeneticActionFired(stimId, sourceType, actionId) — при выполнении условий
Пролонгированные действия | Регистрация в prolongedActions (есть в ActionProlongator) для последующего влияния на виталы

2.6. Закрытие кадра ЭП и оценка эффекта

Закрытие кадра — момент получения обратной связи. Может произойти тремя способами:

Способ | Триггер | Действие
Ответ оператора | Активация стимула в период ожидания | closeLastFrame(стимул_ответа) — кадр закрывается с ответным стимулом
Таймаут | Истечение response_waiting_period пульсов | closeLastFrame(null) — если не было действия, в кадр пишется 0
Новый ОР | Новый победитель ОР при открытом кадре | Закрытие предыдущего кадра с ответом = новый победитель

2.6.1. Что происходит в closeLastFrame

Шаг 1: Вычисление эффекта

text

Копировать

Скачать

effect = clamp(diffAfter - diffBefore, -10, +10)

Если diffBefore недоступен → effect = 0.

Шаг 2: Заполнение «дырок» в правиле
Если к моменту закрытия в кадре нет ОД или ответного стимула → записывается 0 (маркер «не было»).

Шаг 3: Единая оценка эффекта

Запись effect в кадр ЭП

Передача effect в штатный автоматизм ветки: Automatizms_addUsefulnessSample(automatizmId, effect)

Шаг 4: Уведомление модулей

Модуль | Вызов | Что делает
Гештальт | Gestalt_onEpisodeFeedbackClosed() | Добавляет сигнатуру в буфер резонанса, обновляет статус гештальта
Абстракции | AbstractImages_cloneFromEpisodeFrame() | Создает/усиливает клоны восприятия и действия
Ментальные правила | MentalRules_registerFromEpisodeFrame() | Усредняет правило по абстракции

Шаг 5: Обработка ответа оператора (если был ответ)

Если кадр закрыт ответным стимулом и это был автоматизм:

Цикл получает automatismOperatorAnswerReceived = true

lastAutomatismEpisodeEffect = effect

На следующем шаге runOneStep вызывается conscience_level_2 с _operatorAnswerCycleOnly = true

2.7. Сводная таблица потока данных

Этап | Место в коде | Вход | Выход
Активация стимула | stimuls_ui.js → клик по кнопке | stimId | Обновление Active*Stimuls, вызов OrientationReflex_runOnStimulusActivation()
Ориентировочный рефлекс | orientation_reflex.js | Активные стимулы, семантика, виталы | Победитель (winnerId), регистрация семантики, возможно создание кадра ЭП
Осознание (вход) | conscious_attention_channel.js | Контекст (winnerId, branchId) | Новый цикл ФО, запуск runElementary
Уровень 1–2 | conscious_attention_channel.js | Цикл, актуальный стимул | Запуск автоматизма (если найден), иначе unsolved_problem
Уровень 2 (цели) | conscience_level_2.js | unsolved_problem, инфокартина | Определение цели, запуск автоматизма или переход в passive
Рефлексы | genetic_reflexes_engine.js | Активные стимулы (на пульсе) | Выполнение действий, регистрация в ЭП, формирование УР
Закрытие кадра | episodic_memory.js | Ответ оператора или таймаут | Запись effect, уведомление абстракций и гештальта
Ответ оператора | conscience_level_2.js | effect, закрытый кадр | Обновление абстракций, полезности цели, завершение цикла ожидания

Глава 3: Модели памяти и абстракции: от эпизода к знанию

В этой главе мы разберем, как система BEAST трансформирует конкретный опыт в обобщенные знания. Ключевое различие, реализованное в архитектуре: эпизодическая память хранит последовательности событий (что за чем следовало), а семантическая память и абстракции фиксируют устойчивые связи и значимость, отделяя суть от контекста.

3.1. Три уровня памяти

Уровень | Где хранится | Что хранит | Ключ (идентификатор)
Семантическая | SemanticMemory, SemanticMemoryIndex | Значимость (meanImportance) образа стимула в данных условиях | (well, emotionId, finalImageId)
Эпизодическая | Episodes | Правила: условия → стимул → действие → эффект → ответ оператора | Индекс в массиве (порядок важен)
Абстракции (клоны) | AbstractPerceptionImages, AbstractActionImages | Клоны жестких образов, их semanticStructure — правила по ветке+ситуации | (perceptionNodeId, stimulusImageId) или (perceptionNodeId, actionImageId)

3.2. Семантическая память: значимость образа

Семантическая память отвечает на вопрос: «насколько этот стимул важен в данных обстоятельствах?».

3.2.1. Структура записи

javascript

Копировать

Скачать

{

wellNormaBad: 1|2|3, // состояние: Плохо/Норма/Хорошо

emotionId: number, // ID эмоции (сочетание базовых контекстов)

finalImageId: number, // ID образа стимула

meanImportance: number, // средняя значимость (усредненный effect)

samplesCount: number, // число наблюдений

lastImportance: number // последнее зафиксированное значение

}

3.2.2. Формирование записи

Семантическая запись создается или обновляется в двух местах:

Сценарий | Вызов | Особенность
Активация стимула (ОР) | registerSemanticSample (всегда) | Фиксирует значимость стимула ДО того, как система на него отреагировала
Закрытие кадра ЭП | addUsefulnessSample → AbstractImages_clone... | Клоны абстракций усредняют значимость по effect

Важно: Семантика регистрируется при каждой активации стимула, даже если ОР не создал кадр ЭП (например, из-за недостаточного samplesCount). Это обеспечивает накопление опыта.

3.2.3. Механизм «лупы» значимости

При слабой семантике (|meanImportance| ≤ 0.5) и отсутствии выхода виталов из нормы (BadVitalsValue все 0) система усиливает слабый сигнал:

text

Копировать

Скачать

усиленный_эффект = normalizeValue(clamp(LastDiffImportanceRaw × 5, -3, +3))

Это позволяет «расслышать» слабые, но значимые изменения в спокойном состоянии, не искажая семантику при стрессе.

3.2.4. Использование семантики

Где используется | Цель
ОР | Расчет новизны и значимости стимула, порог OR_well_known
Уровень 3 ФО | При meanImportance < 0 — блокировка мотора по правилу ЭП
Модели понимания | getImageUnderstandingModel для UI-диалога по клику на «i»

3.3. Эпизодическая память: правила и их закрытие

Эпизодическая память хранит кадры — записи о том, что произошло: в каких условиях, какой стимул, какое действие, какой эффект, и как ответил оператор.

3.3.1. Структура кадра

javascript

Копировать

Скачать

{

perceptionNodeId: number, // ID ветки дерева (условия)

stimulusImageId: number, // ID образа стимула

situationId: number, // ID ситуации (из дерева ситуаций)

actionImageId: number|null, // ID образа действия (null — еще не выполнено)

effect: number|null, // эффект (-10..+10, null — кадр открыт)

responseStimulusImageId: number|null, // ответ оператора (null — нет ответа)

diffBefore: number, // значимость ДО активации (для расчета effect)

createdAt: number // timestamp

}

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

Этап | Что происходит
Создание | При срабатывании ОР (после прохождения порога) → save_episodic_memory. Кадр открыт (effect = null). Устанавливается EpisodicMemory_waitingStartedAt и счетчик пульсов ожидания.
Заполнение действием | При выполнении любого действия (startAction) → setLastFrameActionFromActionId. Действие записывается в открытый кадр.
Закрытие | Ответ оператора, таймаут или новый ОР → closeLastFrame. Вычисляется effect, записывается ответный стимул (если был).
Нулевое правило | Если к моменту закрытия нет ОД или ответа → в поля пишется 0 (кадр остается в истории, не удаляется).

3.3.3. Период ожидания ответа

Период ожидания — это интервал (в пульсах, по умолчанию 15), в течение которого система ждет ответа оператора на свое действие.

Ключевые правила периода ожидания:

Ситуация | Поведение
Стимул в период ожидания | Стимул трактуется как ответ оператора (не проверяется OR_well_known). Текущий кадр закрывается с этим ответом, создается новый кадр по ответу, запускается повторный полный ОР.
Истечение периода | Кадр закрывается (closeLastFrame(null)). Если действия не было — actionImageId = 0.
Нет ответа, но действие было | Кадр закрывается, эффект вычисляется, абстракции обновляются.
Прогресс-бар | Отображается только при waitingStartedAt != null (активное ожидание в этой сессии). После обновления страницы не восстанавливается.

3.3.4. Приоритет цепочек кадров

Если в конце массива Episodes есть ≥ 2 кадра подряд, у каждого из которых есть actionImageId (реакция), эти стимулы получают приоритет:

Где проявляется | Механизм
В ОР | Не вычитается гистерезис, актуальность усиливается (×2 + 1)
В ФО | Не применяются понижающие множители (несовпадение темы/ситуации, ImportantProblem), порог прерывания — как у равной значимости (ratio = 1)

Это позволяет не обрывать смысловую цепочку (например, действие → ответ → следующий стимул) посторонними стимулами.

3.4. Абстракции: клоны жестких образов

Абстракции — это «клоны» жестких образов восприятия и действия, которые живут в префронтальной коре (в терминах модели) и могут свободно комбинироваться, в отличие от своих жестких прототипов.

3.4.1. Два типа клонов

Тип | Массив | Ключ | Создается при
Клон восприятия | AbstractPerceptionImages | perceptionNodeId + stimulusImageId | Закрытии кадра ЭП (всегда)
Клон действия | AbstractActionImages | perceptionNodeId + actionImageId | Закрытии кадра ЭП (только если actionImageId > 0)

3.4.2. Структура клона

javascript

Копировать

Скачать

{

id: number,

perceptionNodeId: number, // ветка дерева

stimulusImageId: number, // жесткий образ (для клона восприятия)

actionImageId: number, // жесткий ОД (для клона действия)

meanImportance: number, // средняя значимость (усредненный effect)

count: number, // число усреднений

createdAt: number,

lastUsedAt: number,

semanticStructure: { // правила для этой абстракции

frames: [

{

perceptionNodeId: number,

situationId: number,

ruleKind: 'episodic' | 'teacher' | 'fantasy',

stimulusImageId: number,

actionImageId: number|null,

effect: number|null,

responseStimulusImageId: number|null,

updatedAt: number

},

// ...

]

}

}

3.4.3. Семантическая структура (semanticStructure)

semanticStructure — это набор правил, привязанных к конкретным условиям (ветка + ситуация). Для каждой такой пары условий может быть только один кадр.

Приоритет правил:

ruleKind | Приоритет | Когда создается
teacher | Наивысший | Кадр ЭП с responseStimulusImageId > 0
episodic | Средний | Кадр ЭП без ответа оператора
fantasy | Низший | Цепочка пассивного фантазирования (info_new_abstract_semantic)

Если для одних условий уже есть учительское правило, fantasy-правило не перезаписывает его. Для episodic-правила выбор идет по большему effect.

3.4.4. Использование абстракций

Где используется | Что делает
Уровень 3 (shortcut) | AbstractImages_findRuleFrameMatchingContext — поиск правила по (ветка, ситуация, стимул). Если найдено и значимость положительна (effect > 0 или ruleKind === 'teacher'), запускается автоматизм.
Ответ оператора | AbstractImages_applyEpisodeEffectToSemanticContextAbstractions — усредняет meanImportance клонов, если есть совпадающий кадр в semanticStructure.
Цель «значение» | AbstractImages_boostSemanticRulesForAction — усредняет meanImportance всех абстракций, в чьем semanticStructure есть правило с данным ОД.
Учительский fallback (ур.3) | AbstractImages_activateTeacherRuleOnAbstractions — создает учительский слот в semanticStructure для текущих условий.

3.5. Ментальные автоматизмы и символы

Над клонами надстраивается еще один уровень абстракции — символы (Abstractions) и ментальные автоматизмы (MentalAutomatizms).

3.5.1. Структуры ментального уровня

Структура | Назначение | Ключевые поля
MentalActionImage | Ментальный образ действия | sourceActionImageId (исходный ОД), abstractActionIds (символы)
MentalEpisodeRule | Ментальное правило | perceptionNodeId, stimulusImageId, abstractionId, meanEffect
MentalAutomatizm | Ментальный автоматизм | themeId, situationId, mentalActionImageId, usefulness
Abstraction | Символ верхнего уровня | id, может хранить любую структуру (пока заготовка)

3.5.2. Формирование ментальных правил

Ментальное правило создается при вызове MentalRules_registerFromEpisodeFrame из closeLastFrame:

javascript

Копировать

Скачать

// abstractClone = { abstractPerceptionId, abstractActionId }

var absId = abstractClone.abstractActionId || abstractClone.abstractPerceptionId;

MentalRules_addSample(pn, stim, absId, effect);

То есть ментальное правило привязывается к абстракции (клону восприятия или действия), а не к жесткому образу.

3.5.3. Создание ментального автоматизма

После ответа оператора, при effect > 0 и наличии кадра в semanticStructure, вызывается MentalAutomatizms_tryCreateFromSemanticStructureRule:

1. Находит кадр в semanticStructure по (ветка, ситуация, стимул)
2. Получает ID абстракции действия (или восприятия)
3. Создает MentalActionImage с этой абстракцией
4. Создает или обновляет MentalAutomatizm для пары (ветка, ситуация)
5. Назначает его штатным (isDefault = true)

3.6. Сводная таблица: от эпизода к абстракции

Этап | Вход | Обработка | Выход
Закрытие кадра | Кадр ЭП с effect | AbstractImages_cloneFromEpisodeFrame | Клон восприятия (всегда) + клон действия (если есть ОД)
Обновление semanticStructure | Кадр ЭП + клон | AbstractImages_upsertSemanticRuleFromEpisodeFrame | Правило (episodic/teacher) в semanticStructure клона
Учительский fallback (ур.3) | Текущие условия + учительский кадр | AbstractImages_activateTeacherRuleOnAbstractions | Учительский слот в semanticStructure клонов
Ответ оператора | effect + совпадение semanticStructure | AbstractImages_applyEpisodeEffect... | Усреднение meanImportance клонов
Цель «значение» | Прогноз по ЭП | AbstractImages_boostSemanticRulesForAction | Усреднение meanImportance абстракций с данным ОД
Ментальное правило | Кадр ЭП + абстракция | MentalRules_registerFromEpisodeFrame | Запись в MentalEpisodeRules
Ментальный автоматизм | Положительный effect + semanticStructure | MentalAutomatizms_tryCreateFrom... | Запись в MentalAutomatizms, штатный для (ветка, ситуация)

3.7. Схема потока: от эпизода к абстракции

Этап 1: Закрытие кадра ЭП

Кадр ЭП (perceptionNodeId, stimulusImageId, actionImageId, effect)

│

▼

┌─────────────────────────────────────────────────────────────────┐

│ AbstractImages_cloneFromEpisodeFrame │

├─────────────────────────────────────────────────────────────────┤

│ 1. clonePerception(perceptionNodeId, stimulusImageId, effect) │

│ → обновляет meanImportance клона восприятия │

│ 2. если actionImageId > 0: │

│ cloneAction(perceptionNodeId, actionImageId, effect) │

│ → обновляет meanImportance клона действия │

│ 3. AbstractImages_upsertSemanticRuleFromEpisodeFrame │

│ → добавляет/обновляет правило в semanticStructure клонов │

│ 4. MentalRules_registerFromEpisodeFrame │

│ → создает ментальное правило по абстракции │

└─────────────────────────────────────────────────────────────────┘

Этап 2: Использование абстракций в ФО

text

Копировать

Скачать

Текущие условия (perceptionNodeId, situationId, actualStimulusImageId)

│

▼

┌─────────────────────────────────────────────────────────────────┐

│ AbstractImages_findRuleFrameMatchingContext │

├─────────────────────────────────────────────────────────────────┤

│ Поиск в AbstractPerceptionImages: │

│ - perceptionNodeId == текущий │

│ - stimulusImageId == actualStimulusImageId │

│ - в semanticStructure.frames: │

│ perceptionNodeId == текущий │

│ situationId == текущий │

│ stimulusImageId == actualStimulusImageId │

│ actionImageId != null │

└─────────────────────────────────────────────────────────────────┘

│

▼

┌─────────────────────────────────────────────────────────────────┐

│ conscience_level_3_semanticStructureFrameAllowsMotor │

├─────────────────────────────────────────────────────────────────┤

│ Разрешает мотор, если: │

│ - ruleKind === 'teacher' │

│ - ИЛИ responseStimulusImageId > 0 │

│ - ИЛИ effect > 0 (для episodic) │

└─────────────────────────────────────────────────────────────────┘

Этап 3: Создание ментального автоматизма

Ответ оператора: effect > 0

│

▼

┌─────────────────────────────────────────────────────────────────┐

│ MentalAutomatizms_tryCreateFromSemanticStructureRule │

├─────────────────────────────────────────────────────────────────┤

│ 1. Найти кадр в semanticStructure по (ветка, ситуация, стимул) │

│ 2. findAbstractActionRecordId(ветка, ОД из кадра) │

│ 3. MentalActionImages_getOrCreate(ОД, [abstractActionId]) │

│ 4. MentalAutomatizms_create(themeId=ветка, │

│ situationId, │

│ mentalActionImageId, │

│ usefulness=effect) │

│ 5. MentalAutomatizms_setDefault(id) │

└─────────────────────────────────────────────────────────────────┘

Глава 4: Гештальты и уровень 4 — доминанты и инсайты

В этой главе мы разберем самый высокий уровень осознания в BEAST — уровень 4, реализованный через механизм гештальтов. Если эпизодическая память фиксирует что было, а абстракции обобщают как это работает, то гештальты отвечают на вопрос: «какая проблема еще не решена и что мы о ней знаем?».

4.1. Что такое гештальт в BEAST

Гештальт — это долгоживущая доминанта, запись о нерешенной задаче. В отличие от кадра эпизодической памяти (который фиксирует произошедшее), гештальт живет дольше одного цикла осмысления и может накапливать информацию о попытках решения.

Ключевые свойства гештальта:

- Привязан к образу цели (goalImageId)
- Хранит список опробованных автоматизмов (automatismIds)
- Имеет статус (от 0 = «новый» до 3 = «успешно закрыт»)
- Накапливает аналогии (analogyPool) — предложения решений из других циклов
- Может порождать инсайты — события, меняющие понимание задачи

4.2. Структура данных

Поле | Тип | Назначение
id | number | Уникальный идентификатор
problemTreeId | number | Ветка дерева восприятия (условия проблемы)
situationId | number | Ситуация (из дерева ситуаций)
goalImageId | number | Образ цели (из GoalImagesLife) — уникальный ключ
automatismIds | number[] | ID опробованных моторных автоматизмов
status | 0–4 | 0=новый, 1=начато, 2=частично, 3=закрыт успехом, 4=архив
lastInsightPuls | number | Пульс последнего инсайта
lastInsightKind | string | Тип инсайта ('pre', 'local', 'analogy', 'feedback')
insightChainCount | number | Счетчик инсайтов (для статистики)
analogyPool | array | Хвост предложений аналогий (ограниченного размера)

Важное правило: на один goalImageId может быть только один гештальт. Если задача решена (status=3), новая запись для той же цели не создается (пока не реализовано переоткрытие).

4.3. Статусы гештальта

Статус | Значение | Когда устанавливается
0 (NEW) | Заведен, нет устойчивого решения | При создании записи
1 (STARTED) | Начато, есть кандидаты | При первом инсайте (аналогия, резонанс)
2 (PARTIAL) | Частичное решение | При положительном фидбеке (effect > 0, но ниже порога закрытия)
3 (CLOSED_SUCCESS) | Успешно закрыт | При effect ≥ 6 (сильный положительный эффект)
4 (ARCHIVED) | Архив (зарезервировано) | —

4.4. Буфер резонанса (GestaltResonanceBuffer)

Это FIFO-очередь сигнатур закрытых кадров ЭП. Каждая сигнатура — это «слепок» успешного (или неуспешного) опыта, который может быть использован для аналогий.

Структура сигнатуры:

javascript

Копировать

Скачать

{

id: number, // порядковый номер сигнатуры

atPuls: number, // пульс создания

sourceCycleId: number, // ID цикла, в котором произошло закрытие

goalImageId: number, // цель цикла (если была)

problemTreeId: number, // ветка проблемы

situationId: number, // ситуация

perceptionNodeId: number, // ветка восприятия

automatismId: number, // ID автоматизма, который сработал

actionImageId: number, // ОД, который был выполнен

effect: number, // эффект (от -10 до +10)

kind: string // 'positive_feedback' | 'non_positive'

}

Правила буфера:

- Максимальный размер: 48 записей
- При превышении — вытесняются самые старые
- Заполняется только при закрытии кадра ЭП (в closeLastFrame)

4.5. Инсайты и аналогии

4.5.1. Что считается инсайтом

Инсайт — это событие, в котором система связывает образ цели гештальта с конкретным кандидатом решения (автоматизмом, аналогией), изменяя понимание задачи.

Типы инсайтов:

Тип | Источник | Когда возникает
pre | Предварительный | При effect ≤ 0 — переинтерпретация
local | Локальный | Внутри цикла-хозяина (цель «значение», прогноз по ЭП)
analogy | Аналогия | При совпадении сигнатуры буфера с открытым гештальтом
feedback | Обратная связь | При закрытии кадра ЭП с effect > 0

4.5.2. Механизм аналогии (резонанс)

При каждом тике уровня 4 для главного цикла выполняется Gestalt_processResonanceBufferForCycle:

1. Перебираются все сигнатуры в буфере с effect > 0
2. Для каждого открытого гештальта (status < 3) вычисляется score сходства:

- +1.0 — если совпадает goalImageId
- +0.28 — если совпадает problemTreeId
- +0.35 — если совпадает situationId
- +0.12 — если effect > 0

3. Если score ≥ 0.55:

- Автоматизм из сигнатуры добавляется в automatismIds гештальта (если еще не было)
- Запись добавляется в analogyPool (ограничен 16 записями)
- Если статус гештальта 0 → меняется на 1 (STARTED) с инсайтом 'analogy'
- Если статус 1 → фиксируется инсайт 'analogy' (уточнение)

4.5.3. Инсайт из обратной связи

При закрытии кадра ЭП (Gestalt_onEpisodeFeedbackClosed):

- Если effect ≥ 6 → гештальт закрывается (status = 3), инсайт 'feedback'
- Если effect > 0 и статус ≤ 1 → статус становится PARTIAL (2), инсайт 'feedback'
- Если effect ≤ 0 → фиксируется инсайт 'pre' (переинтерпретация)

4.5.4. Инсайт из цели «значение»

В уровне 2, при прогнозе по ЭП для цели «значение», вызывается Gestalt_bumpFromMeaningForecast:

- Если открытый гештальт имеет goalImageId = meaningGoalId или в его automatismIds есть автоматизм с данным ОД
- Статус повышается: 0→1, 1→2, 2→подкрепление
- Фиксируется инсайт 'local'

4.6. Интеграция с уровнями осознания

Точка вызова | Функция | Что делает
Начало ур.3 | Gestalt_prepareContextForCycle | Помещает в global.GestaltContextForLevel3 снимок открытого гештальта для текущего цикла (если есть цель)
Тик ур.4 | Gestalt_onConsciousnessTick | Обрабатывает резонанс для главного цикла, обновляет контекст
Закрытие кадра ЭП | Gestalt_onEpisodeFeedbackClosed | Добавляет сигнатуру в буфер, обновляет статус гештальта по цели цикла ожидания
Цель «значение» (ур.2) | Gestalt_bumpFromMeaningForecast | Повышает статус гештальта при прогнозе

Важно: Гештальты не запускают мотор сами по себе. Они только:

- Накапливают информацию о попытках
- Обновляют свой статус
- Предоставляют контекст для уровня 3 (GestaltContextForLevel3)

4.7. Поток данных: от сигнатуры к инсайту

Этап 1: Закрытие кадра ЭП добавляет сигнатуру в буфер

text

Копировать

Скачать

closeLastFrame()

│

▼

Gestalt_onEpisodeFeedbackClosed()

│

├── Gestalt_pushResonanceSignature() → добавляет сигнатуру в буфер (FIFO)

│

└── Если есть goalImageId у цикла ожидания:

├── Найти гештальт по goalImageId

├── appendAutomatismIfNew() — добавить automatismId в список опробованных

├── Если effect ≥ 6 → status = 3 (CLOSED_SUCCESS), инсайт 'feedback'

├── Если effect > 0 и статус ≤ 1 → status = 2 (PARTIAL), инсайт 'feedback'

└── Если effect ≤ 0 → инсайт 'pre'

Этап 2: Тик уровня 4 обрабатывает резонанс

text

Копировать

Скачать

conscience_level_4_runFromChannel()

│

▼

Gestalt_onConsciousnessTick(cycle) // только для главного цикла

│

├── Gestalt_bindActiveMaster(cycle) → находит/создает гештальт по goalImageId

│

└── Gestalt_processResonanceBufferForCycle(cycle)

│

├── Для каждой сигнатуры с effect > 0:

│ └── Для каждого открытого гештальта:

│ ├── score = сходство сигнатуры с гештальтом

│ ├── если score ≥ 0.55:

│ │ ├── appendAutomatismIfNew() — добавить автоматизм

│ │ ├── добавить в analogyPool

│ │ └── если статус 0 → 1 (инсайт 'analogy')

│ │ если статус 1 → инсайт 'analogy' (уточнение)

│ └── обновить problemTreeId/situationId если они были 0

│

└── Gestalt_prepareContextForCycle(cycle) → обновить контекст для ур.3

Этап 3: Уровень 3 получает контекст гештальта

text

Копировать

Скачать

conscience_level_3_runFromChannel()

│

▼

Gestalt_prepareContextForCycle(cycle)

│

└── global.GestaltContextForLevel3 = {

gestaltId, goalImageId, gestaltStatus, problemTreeId, situationId

}

4.8. Интерфейс оператора

В строке «Информационная картина» отображаются индикаторы:

Индикатор | Назначение | По клику
гешт: N | Число записей гештальтов | Info_showGestaltsList() — список ID
— | — | По ID → Info_showGestaltDetail() — детализация (статус, automatismIds, analogyPool)

Детализация гештальта включает:

- ID и статус
- Связанный образ цели (кликабельный)
- Ветка (problemTreeId) и ситуация (situationId)
- Список опробованных автоматизмов (кликабельные ID)
- Последний инсайт (kind, пульс, счетчик)
- analogyPool (JSON)

4.9. Сводка ключевых констант

Константа | Значение | Назначение
MAX_RESONANCE_BUFFER | 48 | Максимальный размер FIFO-очереди сигнатур
MAX_ANALOGY_POOL | 16 | Максимальный размер analogyPool у гештальта
EFFECT_STRONG_CLOSE | 6 | Порог effect для закрытия гештальта (status 3)
RESONANCE_SCORE_INSIGHT | 0.55 | Минимальный score для инсайта по аналогии

4.10. Текущие границы реализации

1. Нет переоткрытия гештальта: если задача решена (status=3), новая запись для той же цели не создается. При повторном возникновении проблемы поведение не определено.
2. Нет полноценной «сборки» гештальта: analogyPool накапливает аналогии, но не строит из них новое правило.
3. Гештальты не влияют на выбор цели: они только предоставляют контекст для уровня 3, но не могут сами инициировать смену цели.
4. Нет механизма «забывания»: гештальты с status=4 (архив) не удаляются и не чистятся.

Глава 5: Персистенция и сохранение состояния

В этой главе мы рассмотрим, как BEAST сохраняет свое состояние между сессиями и как оператор может сохранять/загружать «память» существа в файл. Система использует гибридный подход: IndexedDB для автоматического фонового сохранения и File System Access API для экспорта/импорта полных снимков.

5.1. Две стратегии сохранения

Стратегия | Механизм | Назначение | Частота
Автоматическое | IndexedDB | Сохранение состояния между перезагрузками страницы | При каждом изменении данных (dirty-флаги)
Ручное | File System Access API | Экспорт/импорт полной памяти в файл | По команде оператора (кнопки «Сохранить»/«Загрузить»)

5.2. IndexedDB: автоматическое фоновое сохранение

5.2.1. Архитектура сохранения

В sys/IndexedDB/indexeddb.js реализована обертка над IndexedDB и механизм регистрации «сохранялок». Каждый модуль, которому нужно сохранять состояние, регистрирует функцию через registerIndexedDBSaver.

Принцип работы:

- На каждом пульсе вызывается runIndexedDBSavesForPulse()
- Выполняются все зарегистрированные функции
- Каждый модуль сам решает, нужно ли сохраняться (через dirty-флаг)

5.2.2. Модули с автоматическим сохранением

Модуль | База данных | Хранилище | Когда сохраняется
Семантическая память | BEAST_DB | semantic_state | При изменении семантики (registerSemanticSample)
Дерево восприятия | BEAST_PerceptionTree_DB | perception_tree_state | При добавлении нового узла
Условные рефлексы | BEAST_UR_DB | conditional_reflexes_state | При создании/усилении УР
Эпизодическая память | BEAST_Episodes_DB | episodes_state | При создании/закрытии кадра
Образы действия | BEAST_ActionImages_DB | action_images_state | При создании/обновлении ОД
Автоматизмы | BEAST_Automatizms_DB | automatizms_state | При создании/обновлении автоматизма
Цели (GoalImagesLife) | BEAST_Goals_DB | goals_state | При добавлении/обновлении цели
Абстракции | BEAST_AbstractImages_DB | abstract_images_state | При создании/обновлении клонов
Гештальты | BEAST_Gestalt_DB | gestalt_state | При изменении статуса, добавлении аналогий
Ситуации и темы | BEAST_SituationsTree_DB | situations_tree_state | При создании новых образов

5.2.3. Оптимизация: dirty-флаг и подпись состояния

Каждый модуль использует три переменные для оптимизации:

Переменная | Назначение
*Dirty (например, epDirty) | Флаг, указывающий, что данные изменились с момента последнего сохранения
last*SavedSig | Подпись последнего сохраненного состояния (JSON-строка)
serializeState() | Функция, возвращающая текущее состояние для сохранения

Алгоритм сохранения:

1. Если !dirty → выход (ничего не изменилось)
2. state = serializeState()
3. sig = JSON.stringify(state)
4. Если sig === lastSavedSig → выход (состояние не изменилось по сути)
5. Иначе: сохранить в IndexedDB, обновить lastSavedSig, сбросить dirty

Это предотвращает лишние записи, когда данные изменились, но их семантическое содержание осталось тем же (например, обновился lastUsedAt).

5.2.4. Резервное копирование в localStorage

Для абстракций (abstract_images.js) реализован механизм резервирования:

- При успешной записи в IndexedDB состояние дублируется в localStorage (ключ BEAST_AbstractImages_LS)
- При загрузке: если в IndexedDB нет данных, но есть в localStorage, восстанавливаем оттуда
- Это страхует от потери данных при сбоях IndexedDB

5.3. Сохранение в файл: полный снимок памяти

5.3.1. Реестр сохраняемых модулей

В date/saving_ui.js определен реестр BEAST.persistentModules. Каждый модуль регистрируется с тремя компонентами:

javascript

Копировать

Скачать

{

key: 'SemanticState', // ключ в JSON-файле

serialize: function() { ... }, // возвращает состояние для сохранения

apply: function(data) { ... } // применяет загруженное состояние

}

Зарегистрированные модули:

Ключ | Модуль | Что сохраняется
Cur_puls_val | puls.js | Счетчик пульсов
VitalsValues | vitals.js | Значения виталов
SemanticState | semantic_memory.js | Вся семантическая память
ConditionalReflexesState | synonyms_reflexes.js | Условные рефлексы
PerceptionTreeState | perception_tree.js | Дерево восприятия
ActionImagesState | actions_image.js | Образы действия
EpisodesState | episodic_memory.js | Кадры ЭП
AutomatizmsState | automatizms.js | Моторные автоматизмы
GoalImagesState | goals.js | Образы целей
SituationsTreeState | situatioms_tree.js | Ситуации и темы
MentalAutomatizmsState | mental_automatism.js | Ментальные автоматизмы
AbstractImagesState | abstract_images.js | Абстракции (клоны)

5.3.2. Процесс сохранения в файл

Кнопка «Сохранить»:

1. Вызывается handle_save_memory_click(collect_memory_data)
2. collect_memory_data() проходит по всем модулям в persistentModules, вызывает serialize(), собирает результат в объект
3. save_all_memory(data) использует File System Access API:

- Вызывается window.showSaveFilePicker() с предложенным именем beast_memory.json
- Используется сохраненная папка (startIn из IndexedDB) для удобства
- Данные записываются в файл

4. При успехе — уведомление оператора

Кнопка «Загрузить»:

1. Вызывается load_all_memory()
2. window.showOpenFilePicker() открывает диалог выбора файла
3. Файл читается, парсится как JSON
4. apply_loaded_memory(loaded) проходит по модулям, для каждого вызывает apply(loaded[mod.key])
5. Собирает ошибки и уведомляет оператора

5.3.3. Запоминание последней папки

В semantic_memory.js реализованы функции для сохранения и загрузки последней выбранной папки:

- saveLastMemoryDirectory(dirHandle) — сохраняет FileSystemDirectoryHandle в IndexedDB
- loadLastMemoryDirectory() — загружает handle для использования как startIn в диалогах

Это позволяет при повторном сохранении/загрузке открывать диалог в той же папке.

5.4. Сохранение перед закрытием

В date/saving_before_closing/saving_before_closing.js реализован механизм обнаружения аварийного завершения.

5.4.1. Флаг was_emergency_shutdown

Значение | Значение
true | Предыдущая сессия завершилась аварийно (браузер/компьютер завис, вкладка «убита»)
false | Предыдущая сессия завершилась штатно

Механизм:

1. При загрузке страницы флаг устанавливается в true (предполагаем, что завершение будет аварийным)
2. При штатном закрытии (событие beforeunload) вызывается saving_before_closing() (заглушка) и флаг сбрасывается в false
3. Если браузер «падает» до вызова обработчика, флаг остается true
4. При следующем запуске можно проверить get_was_emergency_shutdown() и выполнить восстановление

5.4.2. Сохранение флага

Флаг дублируется в localStorage (ключ was_emergency_shutdown), чтобы сохраняться между перезагрузками страницы.

5.5. Индикатор сохранения

В index.html реализован визуальный индикатор (синий кружок), который загорается при любой операции записи (IndexedDB или файл).

Механизм:

- showSaveIndicator() — увеличивает счетчик saveCount, показывает индикатор
- hideSaveIndicator() — уменьшает счетчик, скрывает индикатор только при saveCount === 0
- Минимальное время показа — 300 мс (чтобы индикатор не мигал при быстрых операциях)

Где вызывается:

- В IndexedDBModule.put() — при записи в IndexedDB
- В save_all_memory() — при сохранении в файл

5.6. Сводка ключевых функций

Функция | Модуль | Назначение
registerIndexedDBSaver(fn) | indexeddb.js | Регистрация функции для вызова на каждом пульсе
runIndexedDBSavesForPulse() | indexeddb.js | Вызов всех зарегистрированных функций
IndexedDBModule.put() | indexeddb.js | Запись в IndexedDB (с индикатором)
IndexedDBModule.get() | indexeddb.js | Чтение из IndexedDB
collect_memory_data() | saving_ui.js | Сбор данных от всех модулей для сохранения в файл
apply_loaded_memory(loaded) | saving_ui.js | Применение загруженных данных ко всем модулям
handle_save_memory_click() | saving_all.js | Обработчик кнопки «Сохранить»
load_all_memory() | saving_all.js | Загрузка из файла
saveLastMemoryDirectory() | semantic_memory.js | Сохранение последней папки в IndexedDB
init_saving_before_closing() | saving_before_closing.js | Инициализация обработчика закрытия

5.7. Порядок восстановления при загрузке

1. HTML загружается → выполняются скрипты в порядке, заданном в index.html
2. Модули инициализируются:

- Каждый модуль при загрузке вызывает свою функцию load*FromIndexedDB()
- Данные восстанавливаются асинхронно

3. Пульс 1–2: семантика, контексты, дерево восстанавливаются
4. Пульс 3: создается начальный цикл осмысления, если нет активного
5. Если загружен файл вручную:

- load_all_memory() → apply_loaded_memory()
- Данные из файла имеют приоритет над IndexedDB (перезаписывают)
- Все UI-индикаторы обновляются

Важно: При загрузке из файла порядок применения данных важен. Например, сначала должны загрузиться ActionImagesState (ОД), потом GoalImagesState (цели, которые ссылаются на ОД), иначе ссылки могут быть не восстановлены.

5.8. Схема потока сохранения

Автоматическое сохранение (на пульсе):

1. Пульс начинается
2. runIndexedDBSavesForPulse() вызывается
3. Для каждого зарегистрированного модуля:

- Проверка dirty-флага
- Сериализация и сравнение подписи
- При изменении → запись в IndexedDB

4. Пульс продолжается

Ручное сохранение (кнопка):

1. Оператор нажимает «Сохранить»
2. collect_memory_data() проходит по persistentModules:

- Для каждого вызывает serialize()
- Собирает результат в объект

3. save_all_memory(data):

- Загружает последнюю папку из IndexedDB
- Показывает диалог выбора файла
- Записывает JSON
- Сохраняет выбранный файл/папку как «последнюю»

4. Уведомление об успехе

Ручная загрузка (кнопка):

1. Оператор нажимает «Загрузить»
2. load_all_memory():

- Загружает последнюю папку из IndexedDB
- Показывает диалог выбора файла
- Читает и парсит JSON

3. apply_loaded_memory(loaded) проходит по persistentModules:

- Для каждого вызывает apply(loaded[mod.key]) (если ключ есть)
- Собирает ошибки

4. Уведомление об успехе или частичном успехе

Глава 6: Оценка архитектуры и направления развития

В этой главе мы подведем итоги анализа архитектуры BEAST, оценим ее сильные стороны, выявим ограничения и наметим возможные направления дальнейшего развития. Это не список багов, а рефлексия над тем, как текущая реализация соответствует заявленным целям и где есть пространство для улучшения.

6.1. Сильные стороны архитектуры

6.1.1. Дискретное время как фундамент детерминизма

Привязка всех процессов к пульсу — одно из самых сильных архитектурных решений. Это позволяет:

Преимущество | Пояснение
Предсказуемость | Нет race conditions между UI-событиями и фоновыми процессами
Отладка | Состояние системы в любой момент можно описать как функцию номера пульса
ЭП-ожидание | Период ожидания ответа измеряется в пульсах, а не в реальном времени, что исключает рассинхрон при зависании вкладки
Синхронность | Все модули обновляются в едином такте, нет «полуобновленных» состояний

6.1.2. Разделение ролей памяти

Трехуровневая система памяти (семантическая, эпизодическая, абстракции) имеет четкое разделение ответственности:

Тип памяти | Что хранит | Когда обновляется | Использование
Семантическая | Значимость образа в условиях | При каждой активации стимула | ОР (новизна, порог), Уровень 3 (демотиватор)
Эпизодическая | Последовательности: стимул → действие → эффект → ответ | При срабатывании ОР | Правила для ФО, цепочки приоритета, учительские правила
Абстракции | Обобщенные правила по ветке+ситуации | При закрытии кадра ЭП | Shortcut в Уровне 3, ментальные автоматизмы

Такое разделение позволяет избежать дублирования и обеспечивает единый источник истины для каждого типа знаний.

6.1.3. Единая оценка эффекта

Ключевое архитектурное решение — effect вычисляется один раз в closeLastFrame и передается во все заинтересованные модули:

- Кадр ЭП получает effect для истории
- Автоматизм ветки получает effect через addUsefulnessSample (усреднение полезности)
- Абстракции получают effect для обновления meanImportance
- Гештальт получает effect для оценки успешности закрытия

Это исключает расхождение оценок между разными подсистемами.

6.1.4. Гейты ожидания в Уровне 3

Механизм awaitingAutomatismEpisodeFeedback предотвращает повторный поиск правил, пока система ждет ответа на уже запущенный автоматизм. Это важно, потому что:

- Без этого гейта в каждом пульсе запускался бы новый поиск, и при отсутствии немедленного ответа система «решала бы», что правила нет
- Гейт удерживает цикл в состоянии ожидания до получения обратной связи
- После ответа оператора conscience_level_2 обрабатывает результат, а не уровень 3

6.1.5. Приоритет цепочек ЭП

Механизм, при котором стимулы из суффикса кадров с реакциями (≥2 подряд) получают приоритет в ОР и ФО, решает проблему обрыва смысловых последовательностей:

- Если система выполняет действие, получает ответ оператора и готовится к следующему шагу, посторонний стимул не может прервать эту цепочку
- Гистерезис не вычитается, множители несовпадения не применяются
- Это критически важно для сценариев «обучения с учителем», где важна последовательность: стимул → действие → ответ → следующий стимул

6.1.6. Преемственность абстракций

Система абстракций (AbstractPerceptionImages, AbstractActionImages) обеспечивает плавный переход от конкретных эпизодов к обобщенным правилам:

- Каждый кадр ЭП создает или усиливает клоны восприятия и действия
- Усреднение meanImportance накапливает статистику значимости
- semanticStructure хранит правила, привязанные к конкретным условиям (ветка + ситуация)
- Учительские правила имеют приоритет над эпизодическими
- Fantasy-правила (из пассивного фантазирования) не перезаписывают учительские

6.2. Ограничения и точки напряжения

6.2.1. Вербальные уровни дерева не используются

Дерево восприятия имеет 6 уровней, но уровни 4–6 (ToneMoodID, SimbolID, PhraseID) всегда 0. Это наследие архитектуры OLD_CODE, где предполагался вербальный ввод. В текущей реализации эти уровни не заполняются, но структура поддерживается для совместимости.

Влияние: Потенциальная сложность дерева не используется, но и не мешает. При расширении (например, добавлении невербальных тональных маркеров) эти уровни могут получить смысл.

6.2.2. Нет механизма «забывания»

Ни один из массивов памяти не имеет автоматической обрезки по времени или релевантности:

Массив | Потенциальная проблема
Episodes | Растет бесконечно, может замедлить загрузку и сохранение
SemanticMemory | Старые, неактуальные значимости не вытесняются
GoalImagesLife | Цели с отрицательным effect не удаляются
GestaltArr | Закрытые гештальты (status=3) не архивируются и не удаляются

В проекте есть ограничение MAX_CYCLES = 100 для циклов осмысления, но для массивов памяти таких ограничений нет.

6.2.3. Линейный поиск в условных рефлексах

synonyms_tryRunReflexes() каждый пульс перебирает весь массив SynonymReflexes для поиска подходящего. При росте числа УР (сотни и тысячи) это может стать узким местом.

Потенциальное решение: Индекс по ключу context + activeIdsKey для O(1) доступа.

6.2.4. Гештальты не влияют на выбор цели

Гештальты предоставляют контекст для уровня 3 (GestaltContextForLevel3), но не могут сами иницировать смену цели или запуск автоматизма. Это ограничение делает гештальты «пассивными» накопителями информации, а не активными участниками принятия решений.

6.2.5. Отсутствие переоткрытия гештальта

Если гештальт закрыт успехом (status=3), новая запись для той же цели не создается. При повторном возникновении той же проблемы система не будет знать, что задача уже решалась. Это ограничивает способность к обучению на собственном опыте.

6.2.6. Ручная загрузка файла может нарушить целостность ссылок

При загрузке из файла порядок применения данных важен. Если, например, GoalImagesState загрузится раньше ActionImagesState, ссылки на несуществующие ОД будут временно битыми. Хотя после загрузки всех модулей ссылки восстанавливаются, в момент применения может возникнуть временная несогласованность.

6.3. Эффективность: что работает хорошо

Аспект | Оценка | Пояснение
Семантический доступ | O(1) | Индекс SemanticMemoryIndex[well][emotionId][finalImageId]
Поиск кадров ЭП по условиям | O(n) | Линейный обход, но ограниченный (last 10 для UI, выборка по ключам для поиска правил)
Абстракции и semanticStructure | O(1) | Индексы byPerceptionKey, byActionKey
Дерево восприятия | O(1) | Индекс pathIndex по пути из 6 уровней
Автоматизмы по ветке | O(1) | Индекс byBranchId
Условные рефлексы | O(n) | Линейный обход (потенциальное узкое место)

6.4. Направления развития

6.4.1. Механизм забывания и консолидации

Предложение: Добавить в каждый модуль памяти порог размера и стратегию вытеснения:

- Episodes: ограничить длину (например, 500 последних кадров) или реализовать «сжатие» — объединение похожих кадров
- SemanticMemory: добавить параметр «свежести» — при lastUsedAt старше N пульсов снижать вес или удалять
- GoalImagesLife: удалять цели с отрицательным effect и низким count
- GestaltArr: архивировать гештальты с status=3 после N пульсов без использования

6.4.2. Индексация условных рефлексов

Предложение: Построить индекс для быстрого поиска УР:

javascript

Копировать

Скачать

// Ключ: context + activeIdsKey

var urIndex = new Map();

function rebuildUrIndex() {

urIndex.clear();

for (var ur of global.SynonymReflexes) {

if (!ur.isReady) continue;

var key = ur.context + '|' + activeIdsKey(ur.stimulIds);

if (!urIndex.has(key)) urIndex.set(key, []);

urIndex.get(key).push(ur);

}

}

При каждой активации стимулов поиск будет O(1) по хешу, а не O(n) по всему массиву.

6.4.3. Активные гештальты

Предложение: Дать гештальтам возможность влиять на выбор цели и запуск автоматизмов:

- При выборе цели в уровне 2 учитывать не только GoalImagesLife, но и открытые гештальты
- Если для текущей ветки+ситуации есть гештальт с analogyPool, предлагать автоматизмы из аналогий
- При положительном фидбеке повышать статус гештальта; при отрицательном — понижать

6.4.4. Переоткрытие гештальтов

Предложение: При повторном возникновении проблемы для уже закрытой цели:

- Если статус гештальта 3, но прошло N пульсов без использования → сбросить статус в 1 или 2
- Или создать новый гештальт с той же целью, но с пометкой reopened

6.4.5. Нормализация порядка загрузки

Предложение: В apply_loaded_memory реализовать сортировку модулей по зависимостям:

javascript

Копировать

Скачать

var order = [

'ActionImagesState', // сначала ОД

'GoalImagesState', // потом цели, ссылающиеся на ОД

'AutomatizmsState', // автоматизмы, ссылающиеся на ОД

// ... остальные

];

Или в каждом модуле указать массив dependsOn для автоматического разрешения порядка.

6.4.6. Расширение уровней 4–6 дерева

Предложение: Использовать уровни 4–6 для невербальных измерений, не связанных с речью:

- ToneMoodID — тональность текущего контекста (например, «торжественно», «игриво», «тревожно»)
- SimbolID — простые символьные метки (например, «опасно», «безопасно», «интересно»)
- PhraseID — зарезервировать для будущих расширений

Это позволит использовать существующую структуру дерева для более тонкой дифференциации контекста.

6.4.7. Консолидация фантазийных цепочек в сон

Сейчас механизм info_new_abstract_semantic переносит фантазийные цепочки (fantasizmArr) в semanticStructure абстракций, но вызывается только вручную. Предложение: Интегрировать этот вызов в «сон» — период, когда нет активных стимулов и цикл находится в пассивном режиме более N пульсов.

6.5. Заключение

Архитектура BEAST представляет собой стройную реализацию теории индивидуальной адаптивности. Ключевые решения — дискретное время, разделение типов памяти, единая оценка эффекта, гейты ожидания — обеспечивают предсказуемость и целостность системы. Система абстракций и гештальтов создает основу для обобщения опыта и кросс-цикловых аналогий.

Основные ограничения связаны с отсутствием механизмов забывания, потенциальной O(n) сложностью некоторых операций и пассивной ролью гештальтов. Эти ограничения не критичны для текущих масштабов, но определяют направления развития при усложнении системы.

Проект успешно выполняет свою основную задачу: быть рабочей спецификацией теории адаптивности, где каждый алгоритм реализован, документирован и может быть протестирован.