makecindy / makecindy/cindy

原生分类器故障观察器在缺 session header / 反解失败时静默漏检,无任何日志线索

Open
#1,579 1 comment 0 reactions 1 assignee Claimed by @zqchris View on GitHub
bug
Dominant language
TypeScript
Stars
2.7k
Forks
401
Avg merge
21h 48m
Merged PRs (30d)
776

Description

## 现象

原生分类器故障检测依赖两个前置条件,任一不满足就**静默漏检**:故障永远不会升级到 Cindy fallback,会话被留在无限 fail-closed,且日志里连一条 warn 都没有。

## 代码位置

`apps/desktop/src/main/maker-host/claude-auto-permission-fallback.ts:184`:

```ts
const sdkSessionId = ctx.requestHeaders['x-claude-code-session-id'];
if (!sdkSessionId) return undefined;
const sessionId = resolveSessionId(sdkSessionId);
if (!sessionId || !isClaudeAutoClassifierRequest(ctx.requestBody)) return undefined;
```

两个 silent return:

1. **请求头缺失** —— 上游若不回传 `x-claude-code-session-id`(SDK 版本差异、代理链改写、某些错误响应本就不带原请求头),直接返回
2. **反解失败** —— `resolveSessionId(sdkSessionId)` 返回 null(映射尚未建立、会话刚 resume、映射表被清理)时同样直接返回

成功路径 :165 也有同一处依赖,拿不到 header 时连"恢复清零"都不会发生。

此外整个观察器挂在 `anthropic-compat-proxy` 的响应管道上,**不经该 proxy 的路由天然不在覆盖范围内**。

## 为什么值得改

这条链路是 Auto 档唯一的自救通道。它一旦漏检,用户遇到的就是本仓库里已经反馈过的形态:工具一直被拒、没有弹窗、重启无效——而且因为是 silent return,排障时日志里没有任何线索指向这里。

`isClaudeAutoClassifierRequest` 的双判据(system 前缀 + max_tokens 上界)本身有详尽注释和防漏检设计,说明这块的漏检风险已经被认真考虑过;但它前面这两个 early return 没有同等的可观测性。

## 建议改法(保持独立)

1. 两处 silent return 加**限流后的** debug/warn 日志(带 status、是否有 header、反解结果),让"分类器在报错但我们没识别出来"这件事在日志里可见
2. `resolveSessionId` 失败时,考虑用一个二级兜底:若该 proxy 会话只对应唯一活跃 Auto 档会话,可按 fallback 归属;否则维持现状不猜
3. 补一条"分类器错误响应总数 vs 成功识别数"的计数器,挂在已有的 `FallbackCounters`(:241)上,偏差过大即说明识别规则失效

第 1、3 条纯属可观测性,零行为变化,可以先合。

## 独立性

只碰 `claude-auto-permission-fallback.ts` 一个文件,不依赖其他 auto-review issue。

## 验证

- 构造缺失 `x-claude-code-session-id` 的错误响应,确认日志有记录且不刷屏
- 确认计数器能反映识别率

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.