mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-14 12:02:27 +08:00
对首轮修复的对抗式审计发现并修复以下问题: 1. failover 判定污染(真实回归风险):handler 以 "Forward 前后 c.Writer.Size() 是否变化" 判定响应是否已写出并据此放弃换号。心跳注释 字节会使该判定恒真,compact 请求一旦在上游等待期间发过心跳,上游 429/5xx 将不再 failover。新增 OpenAICompactKeepaliveAdjustedWrittenSize(扣除心跳字节、互斥锁下 一致读取、仅心跳字节归一化为未写哨兵 -1),快照、failover 比较与 openAIForwardErrorAlreadyCommunicated 三处判定统一改用该口径;无心跳 请求完全等价于原 c.Writer.Size()。 2. 并发写竞争:心跳 goroutine 与未被显式拦截的写回路径(Forward 内部 本地拒绝等)存在 ResponseWriter 数据竞争。StartOpenAICompactSSE- Keepalive 现将 c.Writer 替换为 openAICompactKeepaliveWriter:写侧 方法(Header/Write/WriteString/WriteHeader/WriteHeaderNow/Flush) 先在互斥锁下停拍,读侧(Status/Size/Written)仅加锁不停拍——任何 请求侧响应构造与心跳从构造上互斥,热路径状态读取不误杀心跳。 3. 语义拦截补齐:rejectIfCyberSessionBlocked(在用户槽位长等待之后 执行的直接 c.JSON)与 writeOpenAIFastPolicyBlockedResponse 在心跳 提交后降级为 response.failed 终止事件;未提交时先停拍再写 JSON, 状态码语义不变。失败事件 errType 参数化(permission_error 等)。 4. reconstruct 混合形态:done 事件存在但 compaction 只在 output_item.added 中时也要补入;done 已含 compaction 时跳过 added, 避免无 id 可去重时收集两份(Codex 要求恰好一个)。 5. 观测性:logOpenAIRemoteCompactOutcome 对心跳提交后的失败(wire 200) 以 GetOpsStreamError 纠正 outcome,不再误记 succeeded。 新增 5 个测试:failover 口径不变式、包装器停拍语义(-race)、fast policy 提交前后两态、混合 done/added 形态(含去重)。 Refs #3887 #3777