## TG 转发器白名单关键词阻断信号（2026-06-25 发现并修复）

### 架构决策（2026-06-25 用户确认）
**转发器只做透传，规则过滤在 agent 侧处理。** 用户明确要求："收所有的消息，在处理消息这边来处理规则过滤吧。"

理由：源频道信号格式可能变化，转发器关键词正则维护成本高、调试困难。Agent 侧用 LLM 判断消息类型更灵活、更鲁棒。

当前配置：
- 转发器白名单正则：`.*`（全放行）
- Agent channel_prompts：先分类(A/B/C/D)，只有交易信号/确认/平仓才处理，非交易消息忽略

### 信号链路
```
实盘监控(3805472665) → TelegramForwarder(Docker, .*=全放行) → 交易信号群(-1003966251111) → channel_prompts → agent 分类+处理
```

### channel_prompts 消息分类逻辑
群消息到达 agent 后先判断类型：
- **A类（交易信号）** — 含币种+方向+仓位 → 调 trade_signal_handler.py → 推荐方案推送到 TG+QQ
- **B类（确认/取消）** — Y/N/确认/取消 → 执行或取消待确认交易
- **C类（平仓）** — 含平仓/止盈/止损/close → 调 okx_position_advisor.py --close
- **D类（非交易消息）** — 广告/闲聊/图片/表情 → 不做任何操作，不回复，不推送

### 诊断步骤（转发器层面）
```bash
# 1. 确认转发器是否收到消息
docker logs telegram-forwarder --since 2h | grep "处理转发规则"
# 应看到"从 实盘监控 转发到: 交易信号"

# 2. 确认是否被关键词拦截（正常情况下 .*=全放行，不应出现）
docker logs telegram-forwarder --since 2h | grep "不转发"

# 3. 查看当前关键词配置
docker cp telegram-forwarder:/app/db/forward.db /tmp/forward.db
sqlite3 /tmp/forward.db "SELECT * FROM keywords;"
# 输出: id|rule_id|keyword|is_regex|is_blacklist
# is_blacklist=0 = 白名单（必须匹配才放行）
# is_blacklist=1 = 黑名单（匹配才拦截）
```

### 修复步骤（如果关键词再次被改错）
```bash
# 1. 导出数据库
docker cp telegram-forwarder:/app/db/forward.db /tmp/forward.db

# 2. 清除所有白名单关键词，设为全放行
sqlite3 /tmp/forward.db "DELETE FROM keywords WHERE rule_id=1 AND is_blacklist=0;"
sqlite3 /tmp/forward.db "INSERT INTO keywords (rule_id, keyword, is_regex, is_blacklist) VALUES (1, '.*', 1, 0);"

# 3. 验证
sqlite3 /tmp/forward.db "SELECT * FROM keywords;"

# 4. 导回数据库并重启
docker cp /tmp/forward.db telegram-forwarder:/app/db/forward.db
docker restart telegram-forwarder
```

### 关键词表结构
| 列 | 含义 |
|---|------|
| id | 自增主键 |
| rule_id | 关联 forward_rules.id |
| keyword | 关键词文本或正则表达式 |
| is_regex | 1=正则, 0=普通文本 |
| is_blacklist | 1=黑名单(匹配才拦截), 0=白名单(匹配才放行) |

### 转发器 Bot 命令（备用方案）
转发器 bot 支持管理命令，但需要通过 Telegram bot 发送（不能从 agent 内发，与 gateway getUpdates 冲突）：
- `/list_keyword` 或 `/lk` — 列出关键词
- `/add_regex <pattern>` 或 `/ar <pattern>` — 添加正则关键词
- `/remove_keyword_by_id <id>` 或 `/rkbi <id>` — 按 ID 删除
- `/switch` 或 `/sw` — 切换黑白名单模式

### 预防
- 定期检查转发器日志：`docker logs telegram-forwarder --since 1d | grep "不转发"`
- 转发器数据库路径：`/app/db/forward.db`（Docker 内），`docker cp` 导出→编辑→导回→重启
- 容器内无 sqlite3 CLI，用 `sqlite3` 命令需在宿主机操作（先 docker cp 出来）

## Gateway 日志诊断（2026-06-25 补充）

Gateway 日志存储在 `~/.hermes/logs/gateway.log`，但**文件是二进制格式**（混合了二进制和文本数据）。不能用 `cat` 或 `tail` 直接读取，必须用 `strings` 提取文本：

```bash
# 查看最新日志
strings ~/.hermes/logs/gateway.log | tail -30

# 查看特定群的消息
strings ~/.hermes/logs/gateway.log | grep "1003966251111" | tail -10

# 查看 inbound 消息
strings ~/.hermes/logs/gateway.log | grep "inbound message" | tail -10

# 查看连接状态
strings ~/.hermes/logs/gateway.log | grep "Connected to"

# 查看错误
strings ~/.hermes/logs/gateway.log | grep -iE "error|exception|failed" | tail -10
```

journalctl 也有日志但可能不完整（特别是 gateway 重启后旧日志可能丢失）：
```bash
journalctl --user -u hermes-gateway --since "1 hour ago" --no-pager
```

**诊断顺序**：先用 `strings ~/.hermes/logs/gateway.log` 看完整日志，再用 journalctl 补充。journalctl 可能只有 systemd 级别的日志（启动/停止/重启），没有应用级日志。

## Memory 死循环（2026-06-24 发现）