update: 2026-08-11 code review findings + WebUI crash fix & 41s delay analysis (P10-1..P10-5, P4-1..P4-6)

This commit is contained in:
JianFeeeee
2026-08-11 10:30:58 +08:00
parent 7647b7dff8
commit 32e2fd521a

18
plan.md
View File

@ -44,6 +44,14 @@
- AUTO 链只有 4 槽13+ 配置模型不参与 AUTO且 webui 编辑链后无任何"健康复位"提示。
- 审计文件 jsonl 无限增长(当前 547KB`AppendAudit` 每事件一次文件 open。
### P10 全量代码审查发现2026-08-11全部核心文件通读后确认
- **P10-1已确认`handleSourcesAPI` 无 admin 校验**api.go:77-123全方法无 `reqRole` 检查,对比 `handleAdaptersAPI` api.go:21、`handleStatsAPI` api.go:138 均有)→ 任何 user 级 key 可 `GET /api/sources` 读取全部上游**明文 api_key**`config.Source.APIKey``json:"api_key"`config.go:42GET 分支直接返回 `g.core.Sources()`),并可 POST/DELETE 增删改源配置、篡改路由。**越权最高优先级修复项。**
- **P10-2推断`hasScopeModel` 不剥前缀**chat.go:219直接用原始模型串与 scope 比对 → 受限 user key 用 `zen:model` 前缀调用会被误判 403未实测待确认修复
- **P10-3已确认runtime.json 源无超时**JSON 源不序列化 timeout`mergedSources` 后 Timeout=0无限→ 生产 4 个源全部无超时;上游假死不返回时请求永久挂起、占满 `max_concurrent` 槽(历史上 2 条 120s `context canceled` 均为客户端主动断开)。补默认超时需注意 `http.Client.Timeout` 对 SSE 流式同样生效,需区分流式/非流式策略。
- **P10-4stats.go**:失败请求也计入配额消耗(`aggregateLocked` 无条件累计 tokens`nhour` 配额按整点小时桶粒度不精确(`WindowTokens` 按桶过滤user 视角 `Snapshot``by_status` 仍是全局分布(轻微泄露);`Record` 持 mu 时做文件 I/Oappend/rotate高 QPS 下有锁竞争。
- **P10-5scheduler.go**`Chat`/`ChatStream`/`Image` 重试次数受 `len(cands)` 限制MaxRetries 超出候选数时无效);`chainDrive` 有界等待期间重跑整档(硬失败会正确 break可接受
- **健全项(评审确认)**TryAcquire 忙不记分、chainDrive 硬失败正确打断等待、探活不污染调度状态、冷却必然到期自愈(无永久黑名单)、`ResolvePinned` 前缀解析41c9b0e与超时/退避公式5s·2ⁿ 封顶 30min正确。
---
## 二、目标架构(定稿)
@ -226,4 +234,12 @@ p==nil → 400/404!TryAcquire → 429 busy快速失败
- [x] **P3-52026-08-10测试**新增 `stats_test.go`by_status 断言轮转保留上限Record 路径轮转gateway 新增 `TestAutoStatesReportChainHealth`states 契约失败后 fail_count>0+coolingPUT 复位归零);`go vet ./...` + `go test ./...` 全绿。
- [x] **P3-62026-08-10WebUI 右键菜单无法关闭(用户实测)**:根因——`showCtx` 创建菜单后从未赋值 `ctxEl``hideCtx()` 恒为空操作),任何路径(点菜单项/点外部/二次右键)都关不掉;补 `ctxEl = w`,优先级页与密钥页共用 `showCtx` 一并修复(这也是最初版本就存在的 bug
- [ ] **P3-7**:推送 origin → 生产机 pull → `-tags luajit` 全量回归(含 P2-7→ 部署 `/usr/local/bin/llmsproxy` + 重启 service → 观察。
- [x] **P3-82026-08-11审计回放修复用户实测**:重启后统计只剩最后 3000 行≈5.3M tokens历史 273M 消失、且记录里全是 access 脏行——根因 `LoadAudit`:① 只取文件尾 3000 行(而 92% 行是每 3s 的 access 事件);② access/事件行type 空)被当请求灌入聚合;③ Scanner 默认 64KB 截断风险。修复:回放**全部真实请求行**进聚合(恢复 totals/配额窗口),仅视图环形缓冲限 maxRecs跳过 type 空的行;`sc.Buffer` 抬到 16MB。新增 `TestLoadAuditFullReplay`access/坏 JSON/超大行混合回放断言)。
- [x] **P3-82026-08-11审计回放修复用户实测**:重启后统计只剩最后 3000 行≈5.3M tokens历史 273M 消失、且记录里全是 access 脏行——根因 `LoadAudit`:① 只取文件尾 3000 行(而 92% 行是每 3s 的 access 事件);② access/事件行type 空)被当请求灌入聚合;③ Scanner 默认 64KB 截断风险。修复:回放**全部真实请求行**进聚合(恢复 totals/配额窗口),仅视图环形缓冲限 maxRecs跳过 type 空的行;`sc.Buffer` 抬到 16MB。新增 `TestLoadAuditFullReplay`access/坏 JSON/超大行混合回放断言)。
### Phase 4 — 2026-08-11 WebUI 修复与全量代码审查(今日会话)
- [x] **P4-12026-08-11WebUI 聊天"每次回复都失败"(用户实测)**:根因——`sendChat()``addMsg('assistant', '')` 未传 reason 参数 → `thinkEl`/`hintEl` 为 null → 首个携带 `reasoning_content` 的流式 chunk 到达时 index.html 抛 `Cannot set properties of null`,前端表现为请求失败。修复:`addMsg('assistant', '', true)` + 初始隐藏 think 框;提交 `7647b7d`,已推送并部署生产(服务 active、`/api/status` 正常),`go test ./internal/gateway/...` 通过。
- [x] **P4-22026-08-1141s AUTO 延迟归因**:审计 `09:54:42 stream lat=41810 model=deepseek-v4-flash-free src=zen ok=200 pt=17 ct=109`——链上调度仅 ~0.6stier1 qijiar 失败 lat=657ms 后顺延),其余 ~41s 为 zen 上游生成耗时(~380ms/token**非网关调度问题**。
- [x] **P4-32026-08-11全量代码审查**provider.go812 行)/stats.go459 行)/scheduler.go398 行)/registry.go258 行)/api.go/chat.go/server.go/config 全部通读完毕,确认 P10-1~P10-5见上
- [ ] **P4-4**`handleSourcesAPI` 补 admin 校验P10-1一行仿 api.go:21— 待用户确认后实施。
- [ ] **P4-5**`hasScopeModel` 剥前缀比对P10-2— 待确认。
- [ ] **P4-6**runtime 源默认超时策略P10-3区分流式/非流式)— 待确认。