Skip to content

[PR] fix(storage): add field names to drift diagnostics + disable incremental fast path during drift latch (#5677) | fix(storage): drift 诊断补字段名 + 漂移锁存期间停用增量快速路径 (#5677) - #5679

Merged
ranxianglei merged 3 commits into
masterfrom
2026-11-04_drift-field-diag
Nov 10, 2026

Conversation

@ranxianglei

Copy link
Copy Markdown
Owner

What & why

#5677 报告了一个会话的存储双副本(JSON 信封 vs SQLite 统一库)里同一条短 assistant 消息每次采样校验都对不上、持续数天:两侧 id 相同(文本稳定)、字节长度在两个值之间翻转 —— 分歧落在某个非文本字段上,而现有诊断只报 id/role/长度/sha8,永远看不到是哪一个字段。同时增量快速路径按设计跳过水位线以下的槽位:宿主每轮改写该槽位 → 每次修复后 ≤20 次保存内再次分歧 → 「drift resolved」永远无法触发 → ESCALATED→FROZEN 慢性循环(报警文本点名的 #4614 类生产者)。

两处改动(src/storage/shadow.ts):

  1. 诊断层:首个分歧槽位现在携带其顶层差异字段名(排序、仅名单——值不进日志行,与 [Bug][storage] Shadow digest drift clears ingest watermark and forces full-tail re-ingest (v0.1.201) #3919 指纹同一隐私契约)。渲染为 DIGEST DRIFT 行尾可选 ; fields: a,b 段;行前缀逐字节不变,既有 grep 不受影响。
  2. 收敛层:会话处于漂移锁存(drift-latched)期间,同步与异步两条路径都停用增量快速路径,每轮保存走精确全量路径 → 采样时两条腿恒为同代 → 下一采样通过 → 锁释放、增量恢复。把慢性冻结循环变成有界自愈事件。成本仅由「视图已被证明分歧」的会话承担(全量 ingest/保存),健康会话零影响。

Behavior changes(披露)

  • 增量快速路径信任边界收紧:旧 = 漂移修复后最多 ≤20 次保存可继续走增量(期间宿主改写会再次制造分歧);新 = 锁存期间一律全量精确路径,直到一次干净采样重新准入。仅影响已被采样证明分歧的会话。
  • 漂移日志行形状:尾部可选新增 ; fields: … 段(无分歧字段时不出现在行内),前缀逐字节不变。

Tests

新增 tests/issue5678-drift-field-diag.test.ts:

  • 纯函数层:额外字段/值变更/多字段/完全一致/非对象槽位 五类 describeViewDivergence 用例 + 值不落日志断言;
  • 端到端:CAS 篡改存储槽位 → 采样报出 fields: id,text → 锁存窗口内 deltaIngests 恒定(增量确已停用)→ 永久分歧持续报漂 → 修复字节后干净采样解锁 → 增量恢复。

本地定向验证:本文件 + issue3919/issue4323/issue5408/issue5412/issue4986/storage-ingest-watermark/storage-unified/unified-acp-invariants/snapshot-shadow/unified-remap-collision 全绿;typecheck 干净。(issue3157-persist-durability 在本机干净树上同样失败——预存环境问题,与本次改动无关。)全量回归以 CI 为准。

Refs #5677(同一症状家族的历史条目:#4392 已关闭但家族复发、#3919 指纹契约、#5408 冻结可见性、#4614 生产者类命名)

…le drift-latched

#5677: one session's short assistant slot diverged between the envelope
leg and the unified-store leg on every sampled check for days — same id
on both sides (text stable), byte length flipping between two values, so
the disagreeing byte sat in a non-text field the diagnosis never named.
The delta fast path skips slots below its watermark by design, so each
heal re-diverged within one sample window and "drift resolved" could
never fire: the chronic ESCALATED -> FROZEN loop.

Two changes in src/storage/shadow.ts:

1. Diagnosis: the first divergent lastMessages slot now carries the
   sorted top-level field names whose canonicalized values disagree
   (names only — values stay out of the log line, same privacy contract
   as the #3919 fingerprints). Rendered as an optional "; fields: a,b"
   segment appended to the existing DIGEST DRIFT line; the line prefix
   is byte-identical for existing greps.

2. Convergence: while a session is drift-latched the trusted-prefix
   delta fast path is suspended (sync and async paths) and every save
   takes the exact full path, keeping both digest legs same-generation
   at sample time. The next sample then passes, the latch releases and
   the delta resumes — a bounded cost paid only by sessions whose views
   are already proven divergent; healthy sessions are untouched.

Tests: tests/issue5678-drift-field-diag.test.ts pins the field naming
(pure describeViewDivergence cases plus the end-to-end sampled drift,
values-stay-out asserted) and the latch lifecycle (no delta ingest while
latched, permanent divergence keeps drifting, a heal + clean sample
re-admits, the delta resumes).
@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

📦 Built Package Artifact

Branch: 2026-11-04_drift-field-diag (5cb5f60)

Latest build — install this exact version

npm install -g billion-context@0.0.8919-pr.5679.7e57a97

This exact version is immutable and reproducible. The rolling pr tag tracks the newest test build across all PRs.

Recent builds (commit → version)

commit version build
5cb5f60 billion-context@0.0.8919-pr.5679.7e57a97 build
4de5cd3 billion-context@0.0.8150-pr.5679.6312086 build
6fc6102 billion-context@0.0.8146-pr.5679.00b7072 build

Download artifact

  1. Download the artifact from the Actions run
  2. Extract the tarball and install:
tar xzf billion-context-pr5679.tgz
npm install -g package

Install instructions are refreshed on each push.

@ranxianglei ranxianglei changed the title fix(storage): drift 诊断补字段名 + 漂移锁存期间停用增量快速路径 (#5677) [PR] fix(storage): add field names to drift diagnostics + disable incremental fast path during drift latch (#5677) | fix(storage): drift 诊断补字段名 + 漂移锁存期间停用增量快速路径 (#5677) Nov 4, 2026
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

标签: bug / scope/storage / p2(存储双副本漂移的诊断+收敛修复;会话仍可用、SQLite 持续写入、无数据丢失,故 p2 不升 p1)

查重: 不重复。原始症状家族条目是 #5677(用户报告),本 PR 直接修它;Refs 里的 #4392(已关闭但家族复发)、#3919(指纹契约)、#5408(冻结可见性)、#4614(生产者类命名)都是相关背景,非并列重复立项。

PR review 八问

  1. 是什么问题:一个会话的 JSON 信封副本与 SQLite 统一库副本里同一条短 assistant 消息每次采样校验都对不上(字节长度在两个值间翻转),分歧落在某个非文本字段上,而旧诊断只报 id/role/长度/sha8,永远看不到是哪个字段;同时增量快速路径按设计跳过水位线以下的槽位,宿主每轮改写该槽位 → 每次修复后 ≤20 次保存内再次分歧 → 「drift resolved」永远触发不了 → ESCALATED→FROZEN 慢性循环。

  2. 什么原因导致的:两层。①诊断层:DriftDiagnostics.tailSlot 只带槽位指纹(digest/len/sha8),没有字段级定位 → 无法判断「哪个字段」在抖。②收敛层:漂移锁存后只清一次水位线、下一保存全量修复一次,随后水位线重建、增量路径恢复 → SQLite unified storage degraded to legacy-only (bili v0.1.205, node v24.22.1, win32-x64) #4614 类宿主(每轮改写水位线以下的历史槽位,增量路径按设计跳过它们)在 ≤20 次保存内再次制造分歧 → 采样连续漂移 → streak 到 3 → 永久冻结。根因是「锁存窗口内不应重新启用增量快速路径」。

  3. 影响范围与严重程度:仅影响已被采样证明分歧的会话(罕见);健康会话零影响(负向门钉死)。严重度 p2:受影响会话的 JSON 信封写入被冻结,但 SQLite 统一库持续接收每次保存、会话可用可恢复、其他会话缓存不受影响 —— 非数据丢失/不可恢复类,故不升 p1。

  4. 怎么修复的:都在 src/storage/shadow.ts。①诊断层:tailSlot 加可选 fields?: string[](顶层差异字段名,排序、仅名单),新 diffFieldNames(a,b) 复用与 messageSignature 同一个 canonicalize 原语逐顶层键比对规范化 JSON,渲染成 DIGEST DRIFT 行尾可选 ; fields: a,b(前缀逐字节不变)。②收敛层:锁存期间同步(shadow.ts:499)与异步(shadow.ts:~1171)两条路径都用 !driftedSessions.has(id) 门控停用增量快速路径 → 每轮走精确全量 + completeLog 清扫外行 → 采样时两腿恒同代 → 下一采样通过 → 锁释放、增量恢复。把慢性冻结变有界自愈。

  5. 是否有回归问题:逐项清点既有行为——

    无意回归:无。 本地 typecheck 干净 + 主测试 2/2 + 邻近 39 项(issue3919/4323/5408/5412/snapshot-shadow/storage-ingest-watermark)全绿。

  6. 是否破坏缓存:不涉及。纯服务端 storage shadow(双写 SQLite + digest 对账),不触碰模型可见 wire / 前缀缓存。

  7. 是否改了设计方向:不涉及。在既有漂移锁存设计(After idling for one hour, the fold override is lost: the client resends byte-for-byte identical content, and the previo | 闲置一小时后折叠覆盖丢失:客户端重发逐字节不变,已折叠的 ~240K token 内容自己回到上下文 #4323/[Bug][dsh][storage] Compression permanently fails for a session: frozen ingest watermark, requests no longer observed, and no warning until the host dies with CONTEXT_WINDOW_EXCEEDED #5408/Async storage backend: drift latch never releases once engaged — every save full-reingests forever (#5409 B1 not ported) #5412)内收紧一处信任边界、补齐它隐含的收敛语义,未转向架构或数据流。

  8. 是否引入了新的配置:不涉及。无新 env/config/默认值。

测试有效性

真测试、有牙。纯函数层五类用例(额外字段 / 值变更 / 多字段排序 / 完全一致 / 非对象槽位 bail)+ 值不落日志断言;端到端 CAS 篡改存储槽位 → 采样报出 fields: id,text → 锁存窗口内 deltaIngests 恒定(增量确已停用)→ 永久分歧持续报漂(verifyDrift=2,不再无限升级)→ 修复字节后干净采样解锁 → 增量恢复 → 最终视图精确收敛。正/负向门齐备(§Gate Test Discipline)。

一处低 severity 观察(不拦合并)

BatchedViewVerification.messages 由 Map<seq, sig> 改成 Map<seq, {sig, raw}> —— 采样时把每个消息行解析后的对象都保留到 finish()(旧代码算完 sig 即可释放 raw)。而 raw 实际只为「首个分歧槽位」做字段 diff 用,保留全部构成 O(总消息数) 的瞬时峰值(marathon 会话采样那一下可能几十 MB)。verifier 每采样才建一次、短命即弃,属有界瞬时开销,可接受;若想再压峰值,可在 finish() 找到首个分歧 index 后只回读那一行做字段 diff,避免整份保留。留作可选精修,非阻塞。

CI

head 6fc6102d5 目前无失败项:static-gates/mysql-contract 绿,e2e 门控 skip,test 分片(ubuntu/windows × node22/24)仍在跑。定向本地验证已过,全量以 CI 为准。

结论:方向对(修的是根因机制,不是日志表象)、代码正确、测试扎实、diff 干净(2 文件)、typecheck 绿、定向本地全绿、CI 暂无红。无阻塞项,待 CI test 分片转绿即可合并。(合并为人工操作,我不代合。)

@ranxianglei ranxianglei added bug Something isn't working p2 scope/storage labels Nov 4, 2026
…async-lane latch gate

Review-lane fixes on top of the PR head (test-only, no production code):

- Rename tests/issue5678-drift-field-diag.test.ts -> issue5677-...: 5678 is an internal e-work mirror number; the regression belongs to GitHub #5677, and every sibling suite is named by its GitHub issue number.

- Add the missing pin for the async lane: while drift-latched, the backend-queue twin must also suspend the delta fast path (the PR's own e2e covers only the sync record() path). Positive control first (unlatched append rides the delta), then a manual latch (#5412 pattern) proves the latched save lands via the exact full path.
@ranxianglei

Copy link
Copy Markdown
Owner Author

(ai: vllm-qwen/qwen3.8-27b)

已顺手修:测试文件按 GitHub issue 号重命名(issue5678→issue5677,5678 是内部镜像号)+ 补异步车道锁存门回归测试(PR 自身 e2e 只覆盖同步路径;新测试先做未锁存正对照再手动锁存,钉住 enqueueAsyncRecord 路径上 delta 停用、保存走精确 full 路径)+ commit 4de5cd3(纯测试改动,本地 8/8 绿)

@ranxianglei

Copy link
Copy Markdown
Owner Author

(ai: vllm-qwen/qwen3.8-27b)

说明:GitHub 禁止账号 approve 自己创建的 PR(API 422: Can not approve your own pull request),故本审核结论以评论形式提交,verdict 不变。

APPROVE — 独立全量审核完成(diff 逐行通读 + 同步/异步两条代码路径追踪 + 本地定向验证)。

1. 是什么问题:unified 存储已证明漂移的会话有两个缺口——① 诊断只说得出「diverged: lastMessages」+ 槽位指纹,说不出槽位里哪个字段不一致(v0.1.212 用户会话 id 稳定、长度 148↔149 摆动,字段名几天不可见);② 漂移锁存后增量快速路径仍信任已被证伪的前缀,宿主每轮改写水位线以下的槽位时 ≤20 次保存内必然再漂移,streak 累积 → ESCALATED → FROZEN,无自愈出口。

2. 什么原因导致的:① 诊断层只做整槽 digest 比较,没有字段级分解;② 机制层:full save 重盖水位线后,delta 按设计跳过水位线以下的槽位(这本身正确),于是「锁存 ⇒ 前缀不可信」必须同时蕴含「锁存 ⇒ delta 不得替前缀背书」——原设计缺了这条,收敛环上有个洞。

3. 影响范围与严重程度:仅影响 unified 存储已证明漂移的会话(少数);修复前此类会话必然走到 FROZEN(envelope 写入整体冻结),p2;正常会话路径逐字节不变,零影响。

4. 怎么修复的:① 首个分歧槽位按 canonicalize 分解顶层字段,只列不一致字段的名字(排序、值永不入日志——与 #3919 指纹同一隐私契约);② 同步(:499)与异步(:1171)两条车道都加 !driftedSessions.has(id) 前置条件,锁存期所有保存走精确 full 路径,两腿保持同代,下一次采样通过即释放锁存(:611/:1230 逻辑未动)→ 慢性循环变成有界自愈窗口;永久性分歧(CAS swap 类)照旧升级/冻结,符合设计。

5. 是否有回归问题:逐项审过既有行为,无破坏——

6. 是否破坏缓存:否。未触碰前缀缓存/prompt cache 路径;watermark 机制本身未变(锁存期停用 delta 正是修复目标);存储去重键不受影响。

7. 是否改了设计方向:没有。在既有 latch/sampling/watermark 架构内补上「锁存期 delta 信任假设」这一洞,并增强可观测性。

8. 是否引入新配置:没有。

测试:纯函数层覆盖额外字段/值变更/多字段排序/无漂移/非对象槽位 bail-out/值不入日志;e2e 覆盖 tamper → 诊断点名 fields: id,text → 锁存期 deltaIngests 恒定 → 永久漂移持续上报 → heal → 释放 → delta 恢复。断言全部挂在状态计数器与日志行内容上,有牙。本地定向验证:typecheck 干净,新套件 + issue5412/issue3919 邻接套件 8/8 绿;全量交给 CI。

一个预存在观察(非本 PR 引入,不阻塞):异步车道的漂移日志行(shadow.ts:1227)自 #3919 起就没带诊断信息(同步 :605 带),因此字段名目前只会出现在同步车道日志里——是否对齐由 owner 定夺。

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 PR #5679 审核完成 — APPROVE(已提交)

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 这两条是审核方(本 worker)刚在 GitHub PR #5679 上提交的评论经上游同步回流,非新的用户请求——无需进一步动作。当前状态不变:APPROVE,commit 4de5cd3 已推,等人工合并。

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 这条是我自己刚发的顺手修报告被镜像同步回来的回声,无新请求。状态不变:PR #5679 审核 APPROVE(八问全文见 PR 评论 #issuecomment-6631740749),commit 4de5cd3 已推分支、本地 8/8 绿,等人工合并。

@ranxianglei

Copy link
Copy Markdown
Owner Author

(ai: vllm-qwen/qwen3.8-27b)

说明:GitHub 禁止账号 approve 自己创建的 PR(API 422),故本审核结论以评论形式提交。

APPROVE(第二轮复审,head 4de5cd34f)

相对上轮已审 head(6fc6102d5)的唯一增量是一个纯测试 commit(4de5cd3;fetch + diff 核实分支未混入其他改动):

  1. 回归测试文件按 GitHub issue 号重命名(issue5678→issue5677,5678 是内部镜像号)+ 两处 tmpdir 前缀;
  2. 补异步车道锁存门回归测试:真实 sqlite backend 经 fromBackend 走 enqueueAsyncRecord 队列,先做未锁存正对照(deltaIngests+1,证明对照有牙),再手动锁存钉住「latched save 走精确 full 路径」(deltaIngests 恒定 + ingests 递增)。

该增量不触碰任何生产代码,首轮全量审核的结论(机制追踪、双车道门控、隐私契约、回归逐项清点——见上一条八问评论)全部继续有效;新 head CI 全绿(30 checks,0 failed)。verdict 不变:可合,等人工合并。

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 第二轮复审完成(head 4de5cd34f):增量仅一个纯测试 commit(测试文件按 GitHub 号重命名 + 补异步车道锁存门回归测试),fetch+diff 核实无其他混入,不触碰生产代码;新 head CI 全绿(30 checks,0 failed)。verdict 不变 APPROVE,复审结论:#5679 (comment) — 等人工合并。

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 这条是第二轮复审结论(本 worker 在 GitHub PR #5679 上的评论)经上游同步回流,非新的用户请求。状态不变:APPROVE(head 4de5cd34f,CI 全绿),等人工合并。

…h conflict

Union of intent: keep the #5677 drift-latch gate on the sync delta fast
path (deltaApplied = !driftedSessions.has(id) && ingestDelta(...)) AND
master's #5744 wall-clock guard assignment (ingestPath = "full") inside
the full-fallback block. Async-lane latch gate (#5677) auto-merged intact.
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

冲突已解、已 push(head 5cb5f6018e,普通 push 非 force——推送前 fetch 确认远端 head 未动)。master 已完全并入 PR 分支(origin/master 现为 PR head 的祖先,0 behind / 3 ahead),merge state 由 blocked 转干净。旧 head CI 本就全绿(所有 test 分片 success、static-gates / mysql-contract success、gated e2e skip),唯一 blocker 就是这个合并文本冲突,无其他红项需修。新 head 将重跑 CI(镜像 ~60s 刷新),转绿后等人工合并(我不代合)。

PR review 八问

  1. 是什么问题:PR [PR] fix(storage): add field names to drift diagnostics + disable incremental fast path during drift latch (#5677) | fix(storage): drift 诊断补字段名 + 漂移锁存期间停用增量快速路径 (#5677) #5679 分支与 master 产生合并冲突(merge state dirty/blocked)。冲突点在 src/storage/shadow.ts 同步车道 ingest 快速路径的判定处。

  2. 什么原因导致的:master 侧 0.1.212: per-turn ingest is still O(history) — 96.5% of proxy CPU in StatementSync.run, event loop starves with 8 concurrent sessions (#4528 / #5469 follow-up) #5744(wall-clock guard)在同一处新增了 ingestPath 变量与回退块内的 ingestPath = "full" 赋值;PR 侧 DSH raised a version storage layer issue during self-check. I'm unsure of the severity or urgency, so I'm sharing it her | DSH在自检时提出了版本存储层问题,我不确定严重性和急迫性,在此分享。 #5677 把同一行的 if (!this.ingestDelta(...)) 改成了带漂移锁存门的 const deltaApplied = !driftedSessions.has(id) && ...; if (!deltaApplied)。两个改动落在同一行区域 → 纯文本冲突。

  3. 影响范围与严重程度:仅阻塞该 PR 合并,不影响任何已发布行为或运行中的用户;旧 head CI 本身全绿,唯一 blocker 即此冲突。严重度:低(纯合并卫生问题,无功能回归)。

  4. 怎么修复的:把 origin/master merge 进 PR 分支(选 merge 而非 rebase——不改写历史、无需 force-push,契合多 agent 并发推同一分支的纪律)。唯一冲突 hunk 按「意图并集」解决:保留 DSH raised a version storage layer issue during self-check. I'm unsure of the severity or urgency, so I'm sharing it her | DSH在自检时提出了版本存储层问题,我不确定严重性和急迫性,在此分享。 #5677 的锁存门(deltaApplied 前置条件)+ 保留 master 的 ingestPath = "full" 赋值(放进 if (!deltaApplied) 块内,src/storage/shadow.ts:512)。异步车道锁存门自动合并完好未动。提交并普通 push。

  5. 是否有回归问题:逐项核对既有行为——同步(:510)/异步(:1198)两条车道的 DSH raised a version storage layer issue during self-check. I'm unsure of the severity or urgency, so I'm sharing it her | DSH在自检时提出了版本存储层问题,我不确定严重性和急迫性,在此分享。 #5677 锁存门都在;master 的 0.1.212: per-turn ingest is still O(history) — 96.5% of proxy CPU in StatementSync.run, event loop starves with 8 concurrent sessions (#4528 / #5469 follow-up) #5744 ingestPath 计时逻辑完整(:495 声明 / :512 赋值 / :536 slow-ingest warn 引用);completeLog 清扫([Bug][dsh][storage] Compression permanently fails for a session: frozen ingest watermark, requests no longer observed, and no warning until the host dies with CONTEXT_WINDOW_EXCEEDED #5408/Async storage backend: drift latch never releases once engaged — every save full-reingests forever (#5409 B1 not ported) #5412)、采样周期、锁存释放逻辑均未动。语义上「锁存 ⇒ 走全量」与「全量 ⇒ ingestPath=full 标记」一致无矛盾。无意回归:无。注:本地未能跑 typecheck(workspace 无 node_modules,装依赖属重操作),全量以远程 CI 为准。

  6. 是否破坏缓存:不涉及。纯 storage shadow 双写路径,不触碰模型可见 wire / 前缀缓存 / prompt cache。

  7. 是否改了设计方向:不涉及。未转向架构或数据流,只是把两个已各自审过的改动(DSH raised a version storage layer issue during self-check. I'm unsure of the severity or urgency, so I'm sharing it her | DSH在自检时提出了版本存储层问题,我不确定严重性和急迫性,在此分享。 #5677 + 0.1.212: per-turn ingest is still O(history) — 96.5% of proxy CPU in StatementSync.run, event loop starves with 8 concurrent sessions (#4528 / #5469 follow-up) #5744)在同一行正确合起来。

  8. 是否引入了新的配置:不涉及。无新 env/config/默认值。

收工判定:冲突已解、master 已并入、已 push,无红项遗留;待新 head CI 转绿 + 人工合并。

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)
🔶 需要决策

一句话:当前唯一红项 test (ubuntu-latest, 22, 1) 是解冲突时从 master 合并进来的新测试 tests/issue5631-restart-survival.test.ts 在 CI 并行负载下的偶发失败,不是本 PR(#5677)代码引入的缺陷——本地 5 次复现全绿、无法稳定复现。需 owner 在 PR 页面点一次「Re-run failed jobs」。

本轮做了什么(全部实测):

  1. 复核实时状态:head 5cb5f6018e 上该 check 仍 failure(GHA run 42784861985 / job 129723560311);其余 17 success + 12 skipped。
  2. 拉取失败 job 日志精确定位:崩在子测试 restart survival … (#5631) → dsh lane (openai chat shape),报 proxy exited before becoming healthy (dsh-main-4, code=1)——即「SIGKILL 硬杀后重启」的第 4 个代理进程启动即退出(同轮 pi lane / anthropic 形状通过)。
  3. 本地复现:npm install+build(dist/index.js @5cb5f6018e)后单跑该文件共 5 次(其中 dsh-only 4 次),全部通过,无法复现。
  4. 溯源:该测试文件是本次 git merge origin/master 带入的全新文件(原 head 4de5cd34fe 上不存在,diff +577 行);本 PR 自身改动仅落在 src/storage/shadow.ts 请求路径的 ingest 判定(drift 锁存时才生效),不影响代理 boot;origin/ci-fixes 相对 master 无额外提交(已包含在我的 head 里),没有可并入的现成修复。

结构化结论(八问):

  1. 是什么问题:CI 单个 shard 挂在一个「反复 kill/restart 代理」的回归测试上(dsh/openai-chat 形态,第 4 次 SIGKILL 后重启时代理进程启动即 code=1 退出)。
  2. 什么原因导致的:该测试是 master 新增、随冲突解决合并进本 PR 分支;失败是 SIGKILL 后紧接重启、同一 home 累积状态,在 CI 高并发(shard 1/3 同跑 391 文件、大量真实代理子进程)下 500ms settle 窗口不足/启动被资源争抢拖慢所致的负载相关偶发。确定性代码缺陷本地必复现,而本地 5/5 通过,故排除本 PR 代码成因。
  3. 影响范围与严重程度:仅影响该回归测试的稳定性(CI 偶发红),不改任何运行时行为、不影响生产用户;属 CI 体验问题,非可用性/数据缺陷。
  4. 怎么处置的:未改任何代码——既非本 PR 缺陷,也无可在本 PR 内验证的小修;已打 needs-decision 标签并停手等 owner 选路(见下)。
  5. 是否有回归问题:本 PR diff(shadow.ts drift 门控 + 其测试)只改请求路径 ingest 判定,不涉及 boot/存储重载/输出格式/阈值时序,无回归风险;红项与之一一对应不上。
  6. 是否破坏缓存:不涉及(该测试本身就在测前缀缓存稳定性,且本地全绿)。
  7. 是否改了设计方向:不涉及。
  8. 是否引入了新的配置:不涉及(测试只用既有 key compress.modelContextLimit/update.checkIntervalMs)。

选项(默认 A):

按 lane 规则停手,等待你的选择。

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

红项已转绿,无需再改代码。

复核实时状态(镜像缓存刷新于 11:48Z):head 5cb5f6018e 上全部 check 通过(15 success + 15 skipped,零失败)。上一轮点名的 test (ubuntu-latest, 22, 1) 重跑后已绿——印证了上一轮的判断:那是解冲突时从 master 合并进来的新测试 tests/issue5631-restart-survival.test.ts 在 CI 高并发下的偶发失败(SIGKILL 后重启的代理进程启动即退),并非本 PR(#5677)代码缺陷。本地 5 次复现全绿、重跑即过,均与此一致。

本轮动作:

  • 仅做了实时状态复核,未改任何代码(无可修项);
  • 清掉了上一轮打的、现已失效的 needs-decision 标签(其余标签 bug/p2/pr/scope/storage 保持不变)。

一个提示(不在本 wake 范围内处理):origin/master 自上次解冲突合并以来又前进了 4 个提交,本分支目前落后 master 4 个提交,GitHub 侧 mergeability 仍在计算(暂未报冲突)。若真出现冲突会单独触发冲突唤醒再处理;本轮不主动重并 master,避免无谓的全量 CI 重跑。

判定:red-CI 阻断已解除,PR 可进入正常的审批/合并流程(合并仍由人工操作)。

@ranxianglei
ranxianglei merged commit f32db94 into master Nov 10, 2026
83 of 84 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant