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

BRIDGE LOCK & FACKEL - 多个实例的协调
==========================================================

截至：2026-02-23 v1.0.0 (ENT-45)

概述
==========
BACH Bridge (claude_bridge) 使用两个锁定级别来确保
一次只有一个网桥实例处于活动状态：

  级别 1 — 锁定文件（本地）：防止同一台 PC 上的两个实例
  级别 2 — TORCH 系统（全局）：防止通过 OneDrive 进行并行操作

两个级别都是独立且相互补充的。


级别 1：锁定文件
===================
文件：%TEMP%\bach_bridge.lock（本地临时文件夹）

机制：
  - 启动时：msvcrt 文件锁定 bach_bridge.lock
  -同一台电脑上的第二个实例：检测到锁定→退出
  - 干净退出时：锁定被释放并且文件被删除
  - 如果发生崩溃：锁定仍然存在（操作系统在进程终止后立即释放它）

必要时：始终 - 即使在没有 OneDrive 的单个系统上也是如此。


级别 2：TORCH 系统
=======================
表：bach.db 中的bridge_session_lock（通过 OneDrive 同步）

  必要时：
    仅当相同的 bach.db 通过 OneDrive（或其他同步服务）时
    在多台 PC 上共享。否则两座桥会同时出现
    写入同一个数据库 → 冲突、重复消息、竞争条件。

    对于纯本地 BACH（无同步），锁定文件就足够了。火炬系统
    但它也没有什么坏处——它总是在没有其他电脑胜出的情况下获胜
    竞争。

  心跳：
    - 活动守护进程每 60 秒发送一次心跳（数据库中的时间戳）
    - 无心跳 > 5 分钟 → 火炬被视为已过期（碰撞保护）

  强制接管（ENT-45，自 2026 年 2 月 23 日起）：
    - 最后一个请求火炬的人得到它 - 总是
    - 不再出现“被阻止”错误
    - 旧持有者通过心跳故障自动接收信号


割炬丢失：过期
=======================
当 PC-B 从 PC-A 接管割炬时：

  1. PC-B将pc_name='PC-B'写入bridge_session_lock
  2. PC-A：下一次心跳失败（更新0行）
  3. PC-A 检查：check_fackel_mine() → False
  4. PC-A 日志：“火炬丢失：PC-B 已拿走火炬”
  5. PC-A 发送 Telegram 消息：“火炬已移交给 PC-B”
  6. PC-A：命令关闭，退出代码 2 (FACKEL_LOST)
  7. PC-A 上的托盘：检测到退出代码 2 → 不重新启动 → 托盘退出


TRAY-LOCK
=========
文件：%TEMP%\bach_bridge_tray.lock

  - 防止同一台电脑上有两个托盘实例
  - 由守护进程用来检查托盘是否仍在运行
    （托盘耦合：托盘死亡时守护进程退出）
  - 在托盘的最后一个块中被删除（干净退出时）
  - 如果托盘崩溃：锁保持→守护程序检测到死托盘
    下一次检查后（每 30 秒）并退出


守护进程的退出代码
=======================
  0 正常退出（用户选择“退出”）
  启动时出现 1 个错误（锁被占用或类似）
  2 FACKEL_LOST — Torch 被另一台 PC 接管
      → 托盘不会在退出代码 2 处重新启动守护进程


架构：连接器 VS。 BRIDGE
====================================
Bridge (claude_bridge) 是唯一拥有自己的服务
守护进程需要协调。

连接器（telegram_connector.py、discord_connector.py 等）是
没有自己的守护进程的纯适配器模块 - 它们由桥守护进程使用
被称为并且不需要自己的锁/火炬系统。

  Bridge 守护进程 → 有锁文件 + torch
  telegram_connector.py → 适配器，无锁
  Discord_connector.py → 适配器，无锁
  signal_connector.py → 适配器，无锁
  homeassistant_connector.py → 适配器，无锁


诊断
========
  检查割炬状态：
    蟒蛇-c“
    导入sqlite3，json
    从 pathlib 导入路径
    db = Path('数据/bach.db')
    conn = sqlite3.connect（str（db））
    rows = conn.execute('SELECT * FROMbridge_session_lock').fetchall()
    对于行中的 r： print(r)
    “

  桥接日志：
    数据/日志/claude_bridge.log

  相关日志消息：
    “获得火炬：火炬被夺取（从 X 强制接管）”——正常接管
    “TORCH LOST：X 夺走了火炬”——这台 PC 失败了
    “心跳失败（数据库问题）” — 简短的数据库错误


相关决策
=========================
  ENT-45 照明弹：强制接管，退出代码 2，托盘自动终止
  SQ013 桥实施
