# Portability: UNIVERSAL
# Last validated: 2026-05-17
# Next review: 2027-05-17

BRIDGE LOCK & FACKEL — координация для нескольких экземпляров
==========================================================

По состоянию на: 2026-02-23, версия 1.0.0 (ENT-45)

ОБЗОР
==========
Мост BACH (claude_bridge) использует два уровня блокировки для обеспечения
что одновременно активен только ОДИН экземпляр моста:

  Уровень 1 — БЛОКИРОВКА ФАЙЛА (локальный): предотвращает создание двух экземпляров на одном компьютере.
  Уровень 2 — СИСТЕМА TORCH (глобальный): предотвращает параллельную работу через OneDrive 

Оба уровня независимы и дополняют друг друга.


УРОВЕНЬ 1: БЛОКИРОВКА ФАЙЛА
===================
Файл: %TEMP%\bach_bridge.lock (локальная временная папка)

Механизм:
  - При запуске: блокировка файла msvcrt на bach_bridge.lock.
  - Второй экземпляр на том же компьютере: обнаруживает блокировку → выходит.
  - При чистом выходе: блокировка снимается и файл удаляется.
  - В случае сбоя: Блокировка сохраняется (ОС снимает ее, как только процесс завершается)

При необходимости: ВСЕГДА - даже в отдельных системах без OneDrive.


УРОВЕНЬ 2: СИСТЕМА TORCH
=======================
Таблица: Bridge_session_lock в bach.db (синхронизируется через OneDrive)

  При необходимости:
    Только если тот же bach.db находится через OneDrive (или другую службу синхронизации).
    общий доступ к нескольким компьютерам. Иначе два моста были бы одновременно.
    запись в одну и ту же БД → конфликты, дублирующиеся сообщения, состояния гонки.

    Для чисто локального BACH (без синхронизации) достаточно файла блокировки. Система факела
    Но это тоже не повредит — просто он всегда побеждает, когда ни один другой компьютер этого не делает.
    соревнуется.

  Сердцебиение:
    - Активный демон отправляет пульс каждые 60 с (отметка времени в БД)
    - Нет пульса > 5 минут → Факел считается просроченным (защита от сбоев)

  Принудительный захват (ENT-45, от 23 февраля 2026 г.):
    - Последний, кто запросит факел, получит его - всегда
    - Больше нет «заблокированной» ошибки
    - Старый держатель автоматически получает сигнал через сбой контрольного сигнала 


 ПОТЕРЯ ФАКЕЛА: ИСТЕКА СРОКА
=======================
 Когда ПК-B принимает факел от ПК-А: 

  1. PC-B записывает pc_name='PC-B' в Bridge_session_lock.
  2. ПК-A: сбой следующего контрольного сигнала (обновлено 0 строк)
  3. PC-A проверяет: check_fackel_mine() → False
  4. Журналы ПК-А: «ФАКЕЛ ПОТЕРЯЛ: ПК-Б забрал факел»
  5. ПК-А отправляет сообщение в Telegram: «Факел передан ПК-Б».
  6. ПК-А: приказное завершение работы, код выхода 2 (FACKEL_LOST)
  7. Лоток на ПК-A: обнаруживает код выхода 2 → нет перезапуска → лоток выходит 


TRAY-LOCK
=========
Файл: %TEMP%\bach_bridge_tray.lock

  - Предотвращает использование двух экземпляров лотка на одном компьютере.
  - Используется демоном для проверки, работает ли лоток.
    (Соединение лотка: демон выходит из строя, когда лоток умирает)
  - Удаляется в блокеfinally трея (при выходе начисто)
  - Если лоток выходит из строя: Блокировка остается → Демон обнаруживает неработающий лоток
    после очередной проверки (каждые 30 с) и выходит 


КОДЫ ВЫХОДА ДЕМОНА
=======================
  0 Обычный выход (выбран пользователем «Выход»)
  1 ошибка при запуске (замок занят или что-то подобное)
  2 FACKEL_LOST — Факел захвачен другим компьютером
      → Трей НЕ перезапускает демон при коде выхода 2


АРХИТЕКТУРА: КОННЕКТОРЫ VS. BRIDGE
====================================
Мост (claude_bridge) — единственный сервис, имеющий собственный
Процесс демона требует координации.

Коннекторы (telegram_connector.py, discord_connector.py и т. д.)
чистые модули-адаптеры без собственного демона — они используются демоном моста
звонят и не нуждаются в собственной системе замка/фонаря.

  Демон моста → имеет файл блокировки + факел
  telegram_connector.py → адаптер, без блокировки
  discord_connector.py → адаптер, без блокировки
  signal_connector.py → адаптер, без блокировки
  homeassistant_connector.py → адаптер, без блокировки


ДИАГНОСТИКА
========
  Проверьте состояние горелки:
    питон -с "
    импортировать sqlite3, json
    из пути импорта pathlib
    db = Путь('данные/bach.db')
    conn = sqlite3.connect(str(db))
    rows = conn.execute('SELECT * FROM Bridge_session_lock').fetchall()
    для r в строках: print(r)
    "

  Журнал моста:
    данные/журналы/claude_bridge.log

  Соответствующие сообщения журнала:
    «Факел получен: Факел взят (принудительный захват от X)» — нормальный захват
    «ФАКЕЛ ПОТЕРЯЛ: X взял факел» — этот компьютер проигрывает
    «Ошибка контрольного сигнала (проблема с БД)» — короткая ошибка БД


СВЯЗАННЫЕ РЕШЕНИЯ
=========================
  Раструб ЭНТ-45: принудительное переключение, код выхода 2, самозакрытие лотка
  SQ013 Реализация моста
