review round1 的 p1/p2 收口(commit 5967272 之后)。 p1:旧实现 `warmed` 只在 2xx 之后才翻 ⇒ 注释里写的「只在第一次成功响应之前」 实际是「服务坏着的全部时间」。reviewer 实测「接受连接但永不回包」时**每次**调用 都等满 30s(fail-fast 变 fail-slow):审查 20s 预算被一次吃光、索引写入拖成 8×30s、开机探针阻塞 30s。 - `warmupLeft` 改为**一次性许可**(CompareAndSwap 取走即失效,成败都算花掉) ⇒ 挂死时只有第一个请求慢一次,此后一律 DefaultRequestTimeout。 - `warmupTimeout` 30s → 8s:与常态 5s 同一量级(≤2×),且严格小于审查总预算 20s(一次冷启动不许吃光整轮);两条界都由 TestDefaultRequestTimeout 守住。 - 放宽被花掉且没成功时留一条 WARN(事后可复核「第一个请求」这个判据)。 - 更正两处自述:api.go 的「不会被 30s 拖住」与 budget.go 的不变式说明(批次形状 永远按稳态超时推导;冷启动只放宽第一个请求的截止时刻)。 - p2:删掉零调用者的 `WithRequestTimeout` —— 单次超时只允许改常量,批次上限与它 同源并由编译期/常量断言复核。 p2:试算轮在向量源不可用时 `RecallMode` 与「没有候选可比」同为空串。 - `recallLedger` 增 `unavailable` 计数 + `noteUnavailable()`(strictRecall 失败 那一笔记一笔);试算汇总行新增 `recall_unavailable_partitions`,**成败都记**。 - 不扩 `recallMode` 取值集合:失败那一路不序列化 result(响应是 500 tidy_recall_unavailable),新取值只会出现在日志里却要动一次契约,不划算。 测试:三种失败形态 × 两次调用的耗时断言(连接被拒 / 500 / 永不回包), 试算轮的「不可用」与「没候选」两态日志断言;两处变异自证(warmupTimeout 调回 30s ⇒ TestDefaultRequestTimeout 红;去掉 noteUnavailable ⇒ 试算汇总行退化成 recall_mode="" + recall_unavailable_partitions=0)。
5967272
M9(EMBRECALL)。故障机制(M6 + 本次复测):客户端 5s 单次超时先放弃,服务端仍在 算那一批 ⇒ 本机 llama.cpp 被自己顶住 ⇒ 后续每个请求(含写向量索引的单条请求) 排队到自己的超时 ⇒ 召回全线降级。 - embedding/budget.go(新):把「一次请求的耗时上界 ≤ 单次超时的一半」写成不变式, 批上限(条数 4 / 字符 480)与 5s 超时由**同一个不等式**解出;实测依据与复跑命令 写进注释(空闲态摊销曲线 1→0.19s / 8→1.1s / 12→1.3s / 64→8.5s,约 50ms 固定 + 2.7~3.9ms/字符,n≥32 起有数倍放大 ⇒ 余量取一半)。 - embedding/api.go:Embed 按同一对上限**自己切片**(不变式与调用方无关);冷启动 首次调用单独给 warmupTimeout,拿到第一个成功响应后立刻回常态超时。 - memory/tidy_config.go:tidyEmbedBatch = embedding.DefaultBatchLimit(同源), 并加编译期断言 —— 调回 64 会直接编译失败(constant -60 overflows uint)。 - memory/tidy.go | tidy_recall.go | tidy_dryrun.go:recall_mode 改报**实际发生** 的来源(""=本轮没候选可比 / embedding / lexical / mixed),新增 recall_degraded_partitions;试算轮 RecallMode 同口径(M6 medium finding)。 - 测试:embedding 侧用「实测曲线 + 会睡够时间的假客户端」钉住两态 (批内 < 超时 ⇒ 不降级;旧配对 64 条 ⇒ 必然超时),并断言 abandoned == 0; memory 侧钉住降级/健康/没候选三态与试算轮的如实上报。 不改 preinsert*、不改 .env、不动判定规则与任何阈值。
背景:入库前审查链路一直整条超时(日志每 ~20s 一条 WARN),异步那层 (含刚装好的 T1)从未成功跑过。 - 新增 endpoint.go:把「连接语义上不可靠」的回环别名规范化成 127.0.0.1 (localhost 大小写不敏感 / 0.0.0.0 / 空主机),只替换 Host,不碰 path / query / fragment / userinfo;显式 [::1] 与真实主机名逐字不动 - Embed 加独立短超时 DefaultRequestTimeout = 5s(远小于审查 20s 预算): 卡住的调用快速失败并走既有「降级到词项余弦」的路径,把预算留给 T1 - .env.example 示例地址 localhost -> 127.0.0.1(未注释行键数 69 -> 69,无增删) - 跨包测试钉住 5s 严格小于审查总预算 诚实边界(子代理实测,推翻了主代理原先的 IPv6 根因推断): - Go 客户端走 localhost 实测约 57ms、curl 约 0.2s ⇒「localhost -> ::1 等满 20s 预算」这条链不成立;更可能是单槽 llama.cpp 的吞吐/争用 (一批 64 条约 2.1~2.9s,审查 201 条约 8~10s,再叠 T1 8s 顶满预算) - 规范化在任何环境下都无害,5s 快速失败对这个真因对症;但真因 (容量/争用)需要另排切片,已记入工作小结