Skip to content

[PR] feat(fastpath): v6 composite-identity incremental fastpath lane (full rework, #5576 line voided) - #5652

Merged
ranxianglei merged 57 commits into
masterfrom
2026-11-04_fastpath-v6-msgid
Nov 7, 2026
Merged

ranxianglei merged 57 commits into
masterfrom
2026-11-04_fastpath-v6-msgid

Conversation

@ranxianglei

@ranxianglei ranxianglei commented Nov 4, 2026 •

Copy link
Copy Markdown
Owner

Closes #5643
Closes #5664

What this changes

A fresh implementation of the msgid-identity-driven fastpath ("v6") from clean master — the earlier #5576 branch was voided by owner ruling and none of its code was ported. Contract: issue #5643 (P1–P9 rulings); this PR implements only the v6 lane scope (no M1 observation layer, no canonical rewrite).

Per-turn flow for a v6 cohort request (shim family carrying x-bili-plugin-conversation):

  1. Hard identity pre-gate. Fastpath participation now requires the full dual channel: the conversation carrier plus one real message id per body element. Four fault classes — channel missing, malformed list, width mismatch (|R| != T), echo/consistency break — REJECT the request with zero side effects (no table/ext/watermark write; rejected => no trace) and an ERROR log. No silent legacy fallback, no count-guessing, no content-signature guessing. Five strikes park the sid for 60 minutes, after which traffic falls back to the normal baseline path loudly rather than looping 400s.

  2. Matching by composite key. Server-minted world ids (pf_<hex12>), never client-supplied keys. Matching rules: echoed x-bili-pf-session (O(1) + spot-checked against carried ids), else a single global composite probe on (session carrier value, ledger_id) pairs, else mint a new world + one legal arm turn.

  3. Judgment = set difference only. NEW = carried ids not in the ledger; anything already known rides its frozen core untouched; a compaction turn (client shrank history) needs NO detection — surviving cores stay frozen, genuinely-new elements (the summary included) parse exactly like any other new element, wherever they sit. t is restamped to the current body total every evaluated response.

  4. Incremental parse of only the scattered NEW spans, rekeyed absolutely against the whole ledger so _N cluster numbers and wire indices match a full-parse byte-for-byte.

  5. Storage plane: schema v12 adds three append-only sidecar tables (pf_rows, pf_log, pf_ckpt) behind the existing sidecar mechanism; schema v13 adds the three render-plane tables (pf_render, pf_render_log, pf_render_ckpt) for the snapshot lane in item 7 — all pure CREATE IF NOT EXISTS, zero-byte migration, cascade-deleted with the session. Row+log commit is ONE SQLite transaction (mid-turn crash leaves zero trace); state is always fold(ckpt, log-after-ckpt); compaction (>=64 entries / >=64KB / 30min idle) happens in finalize with checksum-bound meta; session deletion cascades all worlds. Sidecar-unavailable nodes softly disable the v6 lane (baseline behavior unchanged).

  6. Client wire change: x-bili-pf-tail-ids now carries the FULL captured element-id list (one percent-encoded segment per element, body order) instead of the last k-1 tail slice; learned world ids echo back via x-bili-pf-session. Old-format servers keep working: v5 lanes ignore unknown-list widths and fall back to count-only mode, which still emits exactly x-bili-pf-count as before.

  7. Render-snapshot lane (fastpath v6 render snapshot plane: one-time full rewrite, steady-state rounds skip full view scan (#5643 sub-item) | fastpath v6 render 快照平面:全量改写只做一次,稳态轮跳过全视图扫描(#5643 子项) #5664, owner rulings 2026-11-04/11-05). On engaged v6 hit-turns, steady rounds no longer re-run the full-view pipeline scan: the frozen prefix rides previously-captured outbound core rows verbatim, and only the last W frozen cores (default 8) plus the new tail window pass through a bounded scratch kernel pass. Every green round re-verifies the window against the stored suffix at the post-rewrite core-form boundary (verifyRenderWindow); any red gate condition (arm turn, title-gen, plane unavailable, pressure >= 90% of model limit, snapshot-lane, blocks-active, fold-pending, absorb-active, ccr-on, markers, hydrate-failed, caps-mismatch, scheduled audit every Nth round, rows-misaligned) falls back to the untouched full legacy path for that one turn — structurally byte-identical to pre-change when red. No-recast regime (owner ruling 2026-11-05): any structural divergence requiring a stored-row rewrite KILLS the plane for that sid permanently (persisted kind='dead' verdict, survives restarts) and the session rides the legacy full path from then on — byte-safety comes from stopping, not repairing. Scheduled audit (every N engaged green rounds, default 8) forces one full legacy pass whose capture diff re-verifies the stored rows end-to-end and rebaselines the cumulative estimate bases; any legacy round IS an audit.

Config surface (AGENTS.md requirement)

knob kind default meaning
rollout.features.watermarkV6MsgId rollout feature (src/rollout.ts) OFF (percent: 0) enables the v6 lane for the bucketed cohort; env override BILI_ROLLOUT_WATERMARK_V6_MSG_ID=1. Percentage bucketing is nested under pluginFullResendWatermark (v6 cohorts are always inside the v5 feature population); env/config force overrides bypass the nesting.
rollout.features.watermarkV6Render rollout feature (src/rollout.ts) OFF (percent: 0) enables the render-snapshot plane (item 7) for a sub-cohort; env override BILI_ROLLOUT_WATERMARK_V6_RENDER=1. Nested inside watermarkV6MsgId (render cohorts are always inside the v6 population); requires the unified-storage sidecar (nodes without it stay on the baseline lanes unchanged).
BILI_PF_RENDER_WINDOW / BILI_PF_RENDER_AUDIT_EVERY env-only tunables (src/server/fastpath-v6-render.ts) 8 / 8 W = bounded render window (frozen cores per scratch pass, capped 64); N = scheduled-audit cadence in green rounds (capped 1024). Registered in LIFECYCLE.md §1 as experimental-lane facilities with the read point and retirement condition (promote to the standing surface when the lane goes GA, or delete with it); bilingual seeds in website/config-reference/env-only.yaml, rows in CONFIGURATION.md en/zh. Deliberately env-only while the lane is experimental: they are operator dials for a default-OFF lane, not user-facing behavior switches, so no config-file key is introduced until the lane graduates.

The existing pluginFullResendWatermark feature and its env are unchanged and continue serving all non-v6 traffic. The existing pluginFullResendWatermark feature and its env are unchanged and continue serving all non-v6 traffic.

Behavior notes worth flagging

  • Old (pre-Snapshot-Centric Compression Foundation: Single-Row Table as Source of Truth + Compression = Insert/Delete/Update Events | Snapshot中心化的压缩底座:单行表真源 + 压缩=对表的增删改事件(非增量车道,#5652/v6 线定位纠正) #5643) clients hitting a v6-enabled node: their partial/absent id lists hit the hard gate — width/malformed faults, five strikes, then 60-minute parking to baseline service. That loud stance is the contracted ruling (garbage-in must not silently corrupt); repo-internal shim clients ship the matching full-list emitter in this same PR.
  • Token accounting does not follow client compaction: the server view grows forward-only and keeps showing old cores even after the client compressed away its history (owner-accepted tradeoff of the pure-ignore ruling; the model context no longer shrinks with /compact).
  • Render-lane death is permanent per session-world (no-recast ruling): once a sid's render plane is killed (structural divergence, S4 checksum corruption, row-table inconsistency, unverifiable pre-existing snapshot) it never re-arms in any process; the session keeps working on the untouched legacy full path (bytes identical to pre-feature), it simply never gets the fast path again. This is the contracted owner ruling, not a fallback gap.
  • Render-lane estimate bases: cumulative per-plane sums (cast absolute, appended per round, rebaselined each audit) carry the frozen-prefix basis into the input estimates/output clamp; per-turn terms price only the new tail past the W window (review-round-2 fix b54b0bd).
  • Local regression note: four claude-native failures and four storage-engine-proofs golden-drift failures reproduce identically on pristine master in this sandbox (environment, verified via clean worktree); everything else in the touched surface is green locally, full-suite verdict delegates to CI.

Tests

Kernel untouched.

Fleet upgrade ordering (M1 from review)

Old shims talking to a v6-enabled node send the pre-F1 slice form → width/mismatch faults → per-session park (60 min) back to baseline. After this revision the residual mismatch shape narrows to over-window or stale-window lists only — same refuse-and-recover posture, no data mutation.

F1 landing (owner ruling): db6622e8 — fixed tail window N=64 (budget: measured host id segments ≤ ~70 bytes encoded across dsh/pi hex-dotted, opencode msg_+12hex, omp hints, wb uuid-without-dashes; 64×70 ≈ 4.5KB ≪ 16KB default × headroom 2); count retired from the lane; honest coverage boundary written into the #5643 contract (§3/§5: rewrites outside the carried window are NOT promised detectable — same class as the known total-unchanged mid-edit boundary); matrix line added for whole-window identity rewrite (with-echo → consistency-break fault storm → park; without-echo → legal re-arm, archive preserved).

bili-dev and others added 4 commits November 4, 2026 13:43
schema v11 (three append-only sidecar tables: pf_rows data plane +
pf_log/pf_ckpt metadata plane), UnifiedStore SQL methods (probe/meta/
commitTurn single-transaction double-plane/compact/hydrate/deleteAll),
UnifiedShadow passthroughs (mysql backend = null soft-degrade),
SessionStore facades in persist.ts. Raw host ids stored untruncated
(P9); state = fold(ckpt, log-after-ckpt) (P7); zero trace on mid-turn
crash via transaction rollback.
msgid-identity-driven fastpath rework per contract issue #5643 (old
#5576 line voided): server-minted pf_sid worlds keyed by
(sessionid,msgid) pairs, pure set-difference judgment over a FULL
element id list, scattered NEW-span parse with _N/wireIndex absolute
rekeying against the whole ledger, client compression ignored (NEW
may sit anywhere), and a hard identity pre-gate that REJECTS with zero
side effects on channel/malformed/width/consistency faults (no silent
legacy fallback, no count guessing, no signature fallback).

- fastpath-v6.ts: evaluateWatermarkV6/finalizeWatermarkV6, matching
  rules (echo O(1)+spot-check / composite probe / mint+arm), world
  mirrors (LRU-cached fold of ckpt+log, never ahead of disk), pending
  single-transaction commits (pf_rows + pf_log together), breaker
  5-strike / 60min parking with memory-first guard state, opportunistic
  L1 compaction in finalize, hydration path with S4 checksum aborts.
- rollout: new feature watermarkV6MsgId percent:0 (default OFF),
  nested under pluginFullResendWatermark bucketing.
- headers: x-bili-pf-session added to the upstream hop filter.
- prepare-openai: v6 evaluated before the v5 watermark lane (silently
  falls back when not engaged); V6Hit consumes the same field-rebuild
  path; finalize branches by evaluated source; snapshot pin skips the
  empty window of a no-progress hit.
- handle: FastpathV6IdentityFault mapped to a 400 JSON refusal at the
  prepared-pipeline call site (supresses raw forward); overflow refold
  fails open.
- storage facade completion: pfNeedsCompaction delegation through
  UnifiedShadow/SessionStore (soft degrade when sidecar unavailable).
…ho (#5643)

The chokepoint now rides the FULL captured element id list (one
percent-encoded segment per body element, body order, literal comma
separators) instead of the k-1 tail slice — the v6 server judges NEW
by set difference and the count claim keeps its last-stamped meaning
for v5 lanes. A learned x-bili-pf-session (server-minted world id)
is echoed back once received. Count-only mode (stamp known, nothing
captured) still emits exactly x-bili-pf-count as before. MAX_IDS
raised to 16k elements for long-hostory conversations.
…ectations

New tests/fastpath-v6-msgid.test.ts covering the #5643 matrix rows:
pure-append increment with frozen-core byte-parity vs full parse,
'?'-free full lists, cold-start arming via baseline pass, compaction
as pure ignore (forward-only view, summary judged only by ids),
scattered NEW parsing, identity-boundary re-mint with old-world
archive retention, three restart cycles across an L1 fold (hydration
oracle), echo-header O(1) matching, carrier rotation, fault classes
(incomplete/malformed/width/zero-resolve echo) with 5-strike parking
and time-travel recovery, cap handling, and session-deletion
cascade cleanup. Schema-head dependent suites updated for STORAGE_
SCHEMA_VERSION 10 -> 11 (v11 adds pf_rows/pf_log/pf_ckpt).
@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

📦 Built Package Artifact

Branch: 2026-11-04_fastpath-v6-msgid (6bd9a92)

Latest build — install this exact version

npm install -g billion-context@0.0.8426-pr.5652.5f10985

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
6bd9a92 billion-context@0.0.8426-pr.5652.5f10985 build
21ed8bc billion-context@0.0.8401-pr.5652.3123c9c build
c5ecd34 billion-context@0.0.8400-pr.5652.d0f58ca build
27c21ed billion-context@0.0.8399-pr.5652.a3c9647 build
635dcb2 billion-context@0.0.8397-pr.5652.907e145 build
61eb805 billion-context@0.0.8385-pr.5652.159f362 build
63d14ca billion-context@0.0.8361-pr.5652.3038f6d build
33c9e3b billion-context@0.0.8360-pr.5652.a185ed2 build
377edbd billion-context@0.0.8310-pr.5652.234ce87 build
686f1e0 billion-context@0.0.8294-pr.5652.57bc872 build

Download artifact

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

Install instructions are refreshed on each push.

@ranxianglei ranxianglei changed the title feat(fastpath): v6 composite-identity incremental fastpath lane (full rework, #5576 line voided) [PR] feat(fastpath): v6 composite-identity incremental fastpath lane (full rework, #5576 line voided) Nov 4, 2026
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

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

查重:不重复。 本 PR 是契约 issue #5643(镜像 #5645)的唯一实现 PR;open+closed 检索(fastpath / msgid / identity lane 关键词,近 7 天为主)未发现其他在途的 v6 实现。相邻线谱确认:#5576/#5578/#5579(v5 身份门线)已按 owner 裁定作废关闭、代码未移植(与本 PR 声明一致);#5575(M1 观测层)与本 PR 明确正交(本 PR 不含 M1);#5573(设计文档 issue)作为背景参考保持打开。

标签:dsh pi opencode omp + scope/wiring(请求管道/协议接线为主面,存储 v11 侧车表为配套平面)+ p3(feature,rollout 默认 OFF percent:0,非缺陷)——功能 PR 不打 bug 标。

开始深度审核:基线已核(PR base = 当前 master tip 23a826d,零落后,无 stale-base 风险),diff 总览 19 files / +2033/-59。下一步读 #5643 契约全文对照 P1–P9,再逐文件精读 + 回归清单。结论稍后按八问体例给出。

@ranxianglei

ranxianglei commented Nov 4, 2026 •

Copy link
Copy Markdown
Owner Author

(ai: sglang-gpu0/qwen3.8-27b)

总体结论:GO(附一项合并前必须落地的 wire-form 修订,已按 owner 裁定定稿)——结构面扎实:前代 B1 hydration 陷阱已被 §8-16/19 测试钉住、config surface 章节齐全、base 新鲜。证据均为本机实测(Node v25.9.0,@edba38af9→5db091e23),目标测试本地亲跑 22/22 绿。

F1 wire form 修订(owner 裁定 2026-11-04,本 PR 内落地后可合)

发现与机制链(保留作记录):

  • master 旧 form 有界:src/agent/pf-channel.ts:125 ids.slice(k-1) + MAX_IDS=2048;本 PR 改为无条件全量列表(L149),上限抬到 16384,emit/server 两侧均无字节预算;
  • stock Node http 默认 maxHeaderSize ≈16KB → id 数到约 500–1000 即在 dispatch 之前回裸 HTTP 431(本机两次复现,dispatch 不触发,gate/breaker/park 全部不可见);pfRequestHeaders 不受 v6 rollout 开关控制 ⇒ 该风险随 build 无条件生效。

owner 裁定(定稿形态):

  1. x-bili-pf-tail-ids 固定尾窗语义——只发最近 N 个元素 id(尾部切片,非"新增部分")。头长恒有界,431 从根上消失;server 对超窗 id 数 loud 拒绝即可,maxHeaderSize 无需调整;
  2. v6 车道不再读取 x-bili-pf-count(count 头在 v6 世界退役;v5 老车道的 count 逻辑原样保留,两世界互不污染);
  3. 诚实边界写入契约 §3:判定范围 = 尾窗逐条身份 + 账本链;窗口之前的前缀改动明确不保证检测(与既有"总数不变的中段改动看不出"同级已知边界),不得假装关死;
  4. 矩阵补一行:宿主压缩为整体重写型(历史重铸 id / 位置全移)时尾窗整段失配的正负两面(fault→5 strike→park 路径);
  5. N 的取值按真实流量 id 长度分布定(预算 = N × 实测最大段长 × 余量 2),定值后回填本节。
    落地清单:wire 注释 + §3.2 契约同步改写、emit 侧窗切 + server 侧窗口校验、矩阵正负行、本文回填实测值。此项在本 PR 关闭前完成,不是放量期事项。

F2 MAJOR(契约 vs 实现张力,待 owner 一句话):"?" 占位槽位 = 潜在永久 reject loop

  • emit 侧 src/agent/pf-channel.ts L117 对缺 id 槽位填 ?(注释自列 summary/persona/external shapes),仅当已知 id 为 0 才清整表;接收端 parseFullIdList(src/server/fastpath-v6.ts L284–300 一带)遇 ? 硬拒 ⇒ malformed ⇒ structured 400 + guard 计数;
  • tests/fastpath-v6-msgid.test.ts 只钉了孤立的 ? 拒绝行,没有"正常 append 回合含合法缺 id 元素"的行;若此类流量存在 ⇒ 5 strike → park 60min → 到期再犯循环,恰是压缩后会话的形状。
  • 待裁定问题:dsh/opencode/pi 的 msgId 信封是否保证 post-compaction 历史每个元素都有 id?保证 ⇒ F2 降 minor(emitter 改"有洞即清全表"不发 ?、补一行负面测试);不保证 ⇒ 修订 §3.2 加容错条款并同步契约与测试。

F3 已在评审期间被作者修复(commit 5db091e,已验证)

CI unused-exports 红(clearWatermarkV6 零引用)由作者推 5db091e 修复(保留函数 + 测试 teardown 钉清理契约)。本地 @5db091e23 复验:unused-export gate clean / tsc clean / fastpath-v6 + pf-channel 22/22 通过。

MINOR(记录不动手)

  • M1 fleet 顺序:旧版 shim 对新节点发旧 form ⇒ v6 车道判 width/malformed → 每会话 park 60min(每 TTL 可重复),契约允许但建议 PR body 写明升级顺序;F1 裁定(第 1 条)落地后此面收窄为仅"超窗/旧 slice 形"一种 mismatch。
  • M2 §7-A B-version ledger 单调增长(owner 已接受):宿主 /compact 后模型上下文缩小、上报 view 不缩——留档。

Clean 区(读过确认):identity hard gate 对 echo fabrication / cross-world probe 的拒绝;recordFault guard 写先于 throw(§8-12 零副作用成立);cohort admission 与运行时故障分离;config surface 章节完整;base = live master tip;kernel 未动;restart-hydration(B1 钉)本地实跑绿。

流程注记:feat + wire 面,人合并区,不 auto-merge;CI 以 5db091e 之后的新波次为准。

ework-ci and others added 2 commits November 4, 2026 15:34
… F1)

x-bili-pf-tail-ids now carries ONLY the last PF_TAIL_WINDOW (64) element
ids; server width gate becomes min(window,T); over-window lists are a
format-class refusal in the strict decoder; the lane stops reading
x-bili-pf-count (v5-only). The ledger keeps rows for out-of-window
prefixes WITHOUT identity — an explicit honest coverage boundary, not a
silent guarantee. New tail-window regression suite: long-history arm
(honest-boundary probe miss + cross-edge _N parity), width discipline
(over/under faults counted), and the demanded whole-rewrite matrix line
(with-echo fault storm → park vs without-echo legal re-arm with archive
preserved).

Closes part of owner ruling 2026-11-04 on PR #5652 review (#5643).
@ranxianglei

Copy link
Copy Markdown
Owner Author

F1 landed: da6885d9(已推,本 PR 内完成) ——对照评审裁定逐条:

  1. 固定尾窗 N=64。emit 端采集仍为全列表(体序),发请求只带最近 64 段——头长恒有界,长对话不再有任何撞 maxHeaderSize 的可能。N 回填推导:实测宿主 id 编码段长 ≤ ~70 字节(dsh/pi hex-dotted、opencode msg_+12hex、omp hints、wb uuid 去连字符 32hex),64×70≈4.5KB ≪ stock Node ~16KB × 余量2;对抗性满长 id 超限由格式类拒绝兜底,未动 maxHeaderSize。
  2. v6 车道不再读 count 头。x-bili-pf-count 仅 v5 老车道继续消费;emit 保持双发,存量 v5-only 节点对全窗列表按其既有逻辑自然降级(宽度对不上⇒回 count-only)。服务端数量检查改为 |msgid[]| ≠ min(窗口, T),超窗在 strict decoder 按格式类响亮拒绝。
  3. 诚实边界写入契约 Snapshot-Centric Compression Foundation: Single-Row Table as Source of Truth + Compression = Insert/Delete/Update Events | Snapshot中心化的压缩底座:单行表真源 + 压缩=对表的增删改事件(非增量车道,#5652/v6 线定位纠正) #5643(§3.2/§5 关键推论/§6 矩阵):判定范围=尾窗内逐条身份+账本链;窗口之前的前缀改动明确不保证检测(与"总数不变的中段改动看不出"同级已知边界)。落库形态=窗外前缀行存在但无身份可探,新增测试把该边界实钉成回归(probe 必空断言)。
  4. 整窗重写矩阵行已补(§8 行 23–25 + tests/fastpath-v6-tail-window.test.ts 三例全绿):带旧 echo ⇒ 一致性破裂故障 ×5 ⇒ park 60min、期间静默回落基线(evaluate null 不抛错循环、PARKED 日志在场);不带 echo ⇒ 规则③合法新 mint+旧世界档案 log 条目数逐条不变。本地全套 125 项绿+tsc 0,issue 正文已同步第四轮裁定横幅。
  5. M1 已写进 PR body「Fleet upgrade ordering」节:旧 shim 对新节点的最坏情形收窄为超窗/旧 slice 形一种 mismatch,拒绝+恢复姿态不变、零数据变更。

F2 待 owner 一句话:证据倾向 dsh/opencode/pi 的 msgId 信封不保证 post-compaction 全元素有 id(opencode 无 id 槽显式空串、dsh summary/persona 走保留前缀被滤出)。若属实推荐 §3.2 容错条款='?' 轮 soft-miss 落基线(不扣 breaker)、下一健康轮自愈;若能保证则降 minor(emitter 改有洞即清全表+负面测试行)。两条路都不动数据面,拍板后再动 emit 端那一处。

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

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

CI 自动修复车道 · 七问总结(本轮全部动作)

  1. 是什么问题:本 PR 先后两波 CI 红。第一波(head edba38a)unused-exports 门禁红;第二波(head 5db091e)三个测试分片(ubuntu 24/22、windows 22)各挂同一个测试 rolloutDecisions: sorted, one per registered feature, real install id,其余 3900+/1800+ 项全绿。

  2. 什么原因导致的:两处根因都与 PR 自身内容有关,与我的修复无关——

    • clearWatermarkV6(src/server/fastpath-v6.ts:948)是全仓零引用的死导出(teardown 配对函数,只定义了没接调用方),触发 audit: 全仓冗余审计与重构计划——server.ts 解体、客户端矩阵去重、死代码、AGENTS.md 模块图腐化 #1440 P6 导出卫生门禁;
    • PR 在 src/rollout.ts:80 注册了带 base: 嵌套的新特性 watermarkV6MsgId: { percent: 0, base: "pluginFullResendWatermark" },但存量测试 tests/rollout.test.ts:210 的断言仍假设「每个注册特性都走 bucketing 层(source=bucket)」——而解析器对 base 队列外的嵌套成员按设计报 off(src/rollout.ts:219)。base 是 5% 灰度,随机安装 id 落在队外概率 ≈95%,所以含该文件的每个分片几乎必挂。PR 只改了 src/rollout.ts(+14 行)没动这个测试文件,属漏配对的存量断言。
  3. 影响范围与严重程度:纯 CI/测试面问题,零运行时行为影响。不修则本 PR 永远无法转绿(每次 push 大概率复现);对用户无影响。

  4. 怎么修复的:两个最小机械修复,均已推入 PR 分支并在最终 head 上被 CI 验证——

    • 5db091e23:不删函数(它是 teardown 契约面,legacy 车道同款 clearWatermarkSeed 也是测试引用保活),在 tests/fastpath-v6-msgid.test.ts 补一条 teardown 测试钉住其清理语义(镜像+pending 清空、磁盘平面不动、幂等)——与 legacy 车道 tests/fastpath.test.ts:457 同一模式;
    • 1898ca1ea:把 tests/rollout.test.ts:210 的全量断言改为「仅对 base 队列排除的成员期望 off」,其余保持 bucket 不变;另用真实解析器对 4000 个随机 id 交叉核验两个分支(入队 205 / 出队 3795,0 失配),确认断言逻辑与解析器语义两侧一致,没有把测试放水成恒真。
  5. 是否有回归问题:无。两个 commit 都只改 tests/ 一个文件(21+/1- 和 7+/2-),未触碰任何 src/ 运行时代码、配置面、wire 形态或持久化格式。本地定向验证:unused-export 门禁 clean、tsc 全量 0 错、fastpath-v6 套件 10/10、rollout 套件 25/25。高危模式逐项过:无语义漂移、无吞错变化、无阈值/时序/输出格式漂移。

  6. 是否破坏缓存:不涉及——零运行时改动,前缀缓存/折叠/账本路径均未触碰。

  7. 是否改了设计方向/引入新配置:都没有。未动 wire form、未动 maxHeaderSize、未新增 env/config。评审裁定中的 F1(尾窗 N=64)已由作者在 da6885d9 自行落地,F2('?' 占位槽策略)仍在等 owner 一句话拍板——两者都不属 CI 车道范围,我未介入。

收工判定:当前 head da6885d9 全量 CI 已绿(37 success / 14 skipped / 0 failed,含此前挂掉的三个分片)。CI 侧无遗留红灯;剩余事项为作者/owner 域(F2 裁定、人工合并)。

…ole captured table ('?' never travels)

Owner ruling on the PR-review F2 question: proceed on the guarantee
branch (hosts keep EVERY element id-bearing post-compaction). Consequence
per the review: an id-less or invalid slot ANYWHERE in the span now clears
the stored table wholesale instead of riding as a '?' placeholder — the v6
hard gate treats '?' lists as malformed, so honest absence degrades safely
(v5 count-only) instead of poisoning the lane with a partial slice. The
PF_SLOT_UNKNOWN token is gone from the v6 capture path entirely (fastpath.ts
keeps its own for the v5 lane). Negative line: mixed spans emit no
tail-ids at all and the table re-arms once resolution goes fully healthy
again. If source analysis disproves the guarantee (issue filed for dsh /
opencode v1+v2 / pi), the sanctioned fallback is the contract §3.2
tolerance clause ('?' turns soft-miss without breaker strikes).
@ranxianglei

Copy link
Copy Markdown
Owner Author

F2 closed on the guarantee branch (owner ruling): ef35c98f pushed.

按裁定"压缩后也有 id"落地:

至此评审 F1+F2+M1+M2 全部处理完毕,PR 可进回归。

ci-check added 2 commits November 4, 2026 16:28
A failed arm registration (geometry mismatch / element transform failure / pfCommitTurn null) left x-bili-pf-session in the response headers while the plane holds nothing for that sid. The client's next-turn echo then hits 'echo references unknown pf_sid' -> identity-fault 400 five times in a row -> 60min breaker park, from a single transient plane hiccup at arm time. Drop the echo on every arm failure exit; keep the honest seq stamp so the client keeps learning T. Regression pin added in tests/fastpath-v6-msgid.test.ts (#5643 review finding).
Two review pins for #5643 matrix coverage gaps: (1) a failed arm commit hands out no world id and the next turn re-arms cleanly with a fresh sid instead of fault-looping into a park; (2) store.removeSession cascades every registered world through the in-TX session_ext registry sweep (pf_rows/pf_log/pf_ckpt all emptied) -- the real deletion path the facade-only pfDeleteForSession test does not exercise.
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

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

PR #5652 审核完成:方向正确、实现扎实;审核中发现 1 个真实缺陷已修复推入分支,1 个可用性隐患经你并行提交的 tail-window 改造后已在源头消除(我准备的服务器端配套改动不再需要、未推);另有 1 项契约偏差待你拍板(单独一条 🏷 决策评论)。

审核过程:通读契约 #5643(P1–P9、§4/§4.1 存储设计、§8 测试矩阵 22 行)→ 全 diff 逐文件精读(19 文件 +2033/-59)→ §8 矩阵逐行对账 → 本地定向验证(tsc / fastpath 家族+pf-channel+rollout 共 73 用例 / unused-exports 门禁 / Node 头部上限实测)。你期间推了 4 个 commit(tail-window wire form、clearWatermarkV6 pin、rollout pin、F2 guarantee branch),我的修复已 rebase 到最新 head。

已推入 PR 分支(基于 8375702,两个独立标注 commit):

  1. fix(fastpath-v6): suppress world-id echo when arm registration fails — arm 注册失败(几何不符 / 元素转换失败 / pfCommitTurn 返回 null)时响应头仍带 x-bili-pf-session,但存储层对该 sid 一无所知 → 客户端下一轮回显 → "echo references unknown pf_sid" → 连续 5 次 400 → 该会话被熔断停车 60 分钟。一次瞬时的存储抖动就变成故障风暴。修法:三个 arm 失败出口全部摘除 world-id 头(seq 戳保留,客户端继续学习 T),并加回归钉。
  2. test(fastpath-v6): pin arm-failure no-echo + real store deletion cascade — 补 §8 两处覆盖缺口:arm 失败不外泄 world id 且下一轮干净重新 arm;store.removeSession 走真实 in-TX registry 级联清空三张表(原测试只覆盖了 pfDeleteForSession facade,真实删除路径没有钉)。

未推入(弃用说明): 我原本准备把主代理 createServer 的请求头上限从 Node 默认 16KB 提到 2MB。实测背景(node 22.23.2):默认上限下 >16KB 的头部直接 431、无任何日志;旧的 full-list wire form 下长会话必然撞线——且 pf-channel 发列表不受 v6 开关控制,v6 关着也受影响。但你的 da6885d 把列表改为固定 64 槽尾窗后,典型 msgid 长度下头部 ≤~3KB,源头已解决;再抬全服务器上顶属于不必要的行为变更,故不推。(理论极端 64×512 字符 ≈33KB 仍超默认上限,实际宿主 msgid 达不到这个长度;如要零风险可加 maxHeaderSize,注意 node 22 上选项名是 maxHeaderSize——传 maxHeadersLength 会被静默忽略,这一点也实测过。)

回归审查(触碰路径的既有行为逐项结论):

  • v5 watermark 车道(GA 中):v6 评估入口只在 watermarkV6MsgId(percent:0 默认关)之后,关闭时 prepare-openai 路径逐字节不变;fastpath.ts(v5)逻辑零改动 → 保持,feature-off 行为有测试钉。
  • 全部插件车道的头部发射(pf-channel 共享状态机):tail-ids 内容从「末 k-1 切片」改为「末 min(64,T) 窗口」(da6885d);dsh 采集从逐槽 ? 占位改为任一槽无 id 即整表清空(ef35c98)→ 有意变更(契约 §9 初始队列设计 + 你的 F2 裁定),影响面见下方行为变更清单;对 v5 旧服务器:收到宽度不合格列表走静默 shape-miss(不计熔断、legacy 解析、一轮自愈),无损坏路径。
  • 统一存储:schema v10→v11 纯增量 CREATE TABLE IF NOT EXISTS(三表+两索引),存量行零迁移 → 保持;MySQL 后端 shadow sync===null → v6 车道软禁用(§7-A② 契约内行为)。
  • 会话删除路径:deleteSession 新增 in-TX 三表级联(仅当 session_ext registry 非空时生效)→ 有意新增,新测试已钉。
  • 请求管道错误处理:v6 身份故障映射为结构化 400(仅 v6 车道抛出);overflow 重折叠路径二次故障 fail-open(原始 400 原样放行)→ fail-fast 语义保持,无吞错。
  • 服务器全局行为:无变化(上条已述,头帽改动弃用)。

行为变更清单(旧→新 + 原因):

  1. x-bili-pf-tail-ids 内容:末 k-1 尾切片 → 末 min(64,T) 窗口(count 仍照常发射供 v5,v6 服务端不读)——身份判定需支持任意位置 NEW,尾切片不够;窗口同时约束头部体积。
  2. dsh 车道 msgid 采集:逐槽 ? 占位 → 任一槽无 id 整表清空(? 永不上线)——v6 严格解码器视 ? 为 malformed(F2 裁定)。
  3. 新响应头 x-bili-pf-session(v6 队列专属,转发上游前剥除)——O(1) world 匹配加速通道。
  4. 存储 schema v11 增量(pf_rows/pf_log/pf_ckpt)——§4.1 元数据平面。

测试有效性: 断言有牙——核心判定用与 openaiToCore 全量解析结果的字节级 deepEqual 作 oracle(_N 编号一致);故障行断言零副作用(三表/ext/水位全部不动)+ 计数器递增;B1 trap 有重启 hydrate 字节一致钉;banned-kind(hide/replace/archive)缺席断言防词汇回归。缺口(均不阻塞,建议后续跟踪):§8-13 承诺的 drift warn 诊断未实现(骑旧核由构造自然成立,诊断缺失);§8-17 seen-cap 2048 截断未钉;block/unarm 条目未写(契约 best-effort 逃生条款允许——「宁可视图多给」,折叠区由 kernel fold 管道继续治理,idx_pf_rows_core 暂闲置);§8-19 单轮重启而非跨 L1 折叠三轮。

CI: head 8375702 运行中——static-gates(ubuntu24)/mysql-contract/gate/version-guard 已绿,9 个 test shard 在跑,完成后跟帖。原红(unused-exports: clearWatermarkV6 死导出)已由你的 5db091e pin 解决,本地门禁验证 clean。

结构化八问:

  1. 是什么问题:实现 Snapshot-Centric Compression Foundation: Single-Row Table as Source of Truth + Compression = Insert/Delete/Update Events | Snapshot中心化的压缩底座:单行表真源 + 压缩=对表的增删改事件(非增量车道,#5652/v6 线定位纠正) #5643 契约——插件车道全量重发会话按 (sessionid,msgid) 复合身份识别消息、每轮只解析增量的 v6 快路径车道(治 [Bug][dsh] 20k-message / 81 MiB-inbound session: host aborted 6× in 2 h — the #3050 resident-AST OOM is not bounded by sessions.hardMaxBytes (Windows, 0.1.210) #5403 类全量解析常驻内存/CPU 问题)。
  2. 什么原因导致的(为何要建):宿主每轮重发完整历史,legacy 每轮整包 JSON.parse+全量转换+AST 驻留([Bug][dsh] 20k-message / 81 MiB-inbound session: host aborted 6× in 2 h — the #3050 resident-AST OOM is not bounded by sessions.hardMaxBytes (Windows, 0.1.210) #5403 OOM 生产者对);v5 水位靠计数+尾切片定身份,撑不住任意位置的结构性变化(compaction/换序/重插槽),契约把身份升级为复合对、几何降为辅助。
  3. 影响范围与严重程度:默认 OFF(percent:0,嵌套于 pluginFullResendWatermark),关闭时现有用户零影响;开启时仅 shim 族车道(x-bili-plugin-conversation)进 v6,其余车道不受影响。功能未启用,无现网严重度;启用后残余风险被硬门故障处理+5 连击停车兜住。
  4. 怎么修复的:按契约 P1–P9 落地——严格双通道预门(四类故障拒绝且零副作用)、world 三级匹配(echo O(1)/复合探针/铸新)、集合差唯一判据、增量 span 解析+绝对重键、三表 log-derived 元数据平面(rows+log 单事务、compaction 同事务带校验和)、t 诚实盖章。审核另修 arm 失败外泄 world id 一处(故障风暴根因)。
  5. 是否有回归问题:按上方回归审查清单逐项过——v5 车道、既有存储、删除路径、错误处理语义均保持或有意变更已披露;未发现无意回归。
  6. 是否破坏缓存:前缀缓存策略不变——v6 命中轮出站为账本序完整视图渲染(与全量解析 oracle 字节等价的测试钉);客户端压缩纯忽略(视图前向追加,反 [bug] DSH 桌面端 0.1.188:宿主原生压缩落地摧毁折叠基底 → 同一区间永久不可锚定、compress 连片失败并熔断(compaction-basic auto:false 仍无效) #2432 死亡螺旋);缓存/重试/增量游标失效策略均无改动。
  7. 是否改了设计方向:未转向——本 PR 即 Snapshot-Centric Compression Foundation: Single-Row Table as Source of Truth + Compression = Insert/Delete/Update Events | Snapshot中心化的压缩底座:单行表真源 + 压缩=对表的增删改事件(非增量车道,#5652/v6 线定位纠正) #5643 契约方向的实现;相对契约文本有一处从简:block/unarm 条目未写(best-effort 条款),折叠区可见性由 kernel fold 管道治理。
  8. 是否引入了新的配置:rollout.features.watermarkV6MsgId(默认 OFF,嵌套 pluginFullResendWatermark;env BILI_ROLLOUT_WATERMARK_V6_MSG_ID=1 走通用 rollout 约定,未新增 process.env 读取)。无其他配置面新增。

合并判定:建议 CI 全绿后由你验收合并。 feat + wire 形态 + 存储 schema v11 + rollout → 按 §7.4 属必须人工类别,我不能自动合并;审核视角方向、实现、测试均已过关,我的两处修复已推入,待拍板一项(见下条评论)不阻塞合并。另:PR 正文的 wire form 描述仍是 full-list 版本,与 da6885d 的 tail-window 不一致,建议合并前更新正文(作者描述我不代改)。

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

🔶 需要决策

背景一句话:PR #5652(v6 快路径)审核发现一处「实现 vs 契约」偏差——契约 §4.1.4 承诺命中轮常驻内存、不碰磁盘,实现是每轮从磁盘全量 hydrate 前缀。

待决问题:v6 命中轮每轮调用 loadWorldCores(src/server/fastpath-v6.ts:688/803),把该 world 的整个前缀从 pf_rows 读出并 JSON.parse 每个 core_json——正确性没问题(P7:缓存丢了只多付一次重载,视图字节一致有测试钉),但长会话下每轮付 MB 级 SQLite 读 + parse,与契约 §4.1.4「常驻 visible-core 数组,常路命中轮触碰数据面 0 次」及 #5403 的性能目标相悖。

选项(各带代价):

我的推荐:A。理由:功能默认 OFF(percent:0)、初始队列只有 shim 族车道、正确性不受影响;先小流量放量拿到真实命中轮规模数据,再决定常驻缓存的预算参数更稳。

不决定的默认行为:按 A 执行——该项不阻塞合并(CI 全绿 + 你验收即可合)。

附带(非阻塞,供参考):pf-channel 头注释声称头部体积 by-construction 有界、无需调 Node maxHeaderSize;理论极端(64 槽 × 512 字符 id ≈ 33KB)仍超 Node 默认 16KB 上限,实际宿主 msgid 达不到该长度。若想零风险,可在 src/server.ts createServer 加 maxHeaderSize: 2*1024*1024(注意:node 22 上选项名必须是 maxHeaderSize,传 maxHeadersLength 会被静默忽略——已实测)。我的建议:不动,保持现状。

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

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

CI 跟帖:head 8375702 全管线绿 —— 30/30 checks 通过(9 个 test shard:ubuntu/windows × node 22/24,加 static-gates×2、mysql-contract、gate、version-guard 等,0 failed)。原红项(unused-exports)已随你的 5db091e pin 解决。

PR 分支当前状态:你的 ef35c98(F2 guarantee branch)+ 我的两个审核修复(239f0a4 arm-failure echo 修复 / 8375702 测试钉)。等你验收合并;🔶 决策项(常驻核缓存 A/B)不阻塞合并,不回复则默认按 A 执行。

…r, not just ext

creditReset touched only the advisory ext replica while readGuard is
memory-first — a sound turn therefore did NOT actually clear this
process's fault streak: 4 faults + 1 healthy turn + 1 more fault parked
the session for 60m on a cumulative-but-not-consecutive fifth strike,
violating the five-CONSECUTIVE contract (§8). Fix resets guardMem
whenever a local copy exists (unconditionally — local state must not
depend on replica availability); cross-boot/cross-replica semantics of
the ext copy are unchanged. Regression test §8-12 pins both clear paths
(hit @842 and no-progress ride @721) and is proven discriminating
(fails pre-fix with early park).

@ranxianglei ranxianglei left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deep review of #5652 (v6 msgid identity lane + #5664 render-snapshot lane)

Method: full read of every changed hunk (fastpath-v6.ts, fastpath-v6-render.ts, prepare-openai.ts, handle.ts, persist.ts, store.ts, shadow.ts, schema.ts, budget.ts, headers.ts, rollout.ts, dsh-native.ts, pf-channel.ts, plugin.ts, docs/site/website yaml) + eight independent hostile sub-reviews (identity lane ×2, render lane ×2, test-coverage audit, docs-vs-code truth audit, integration seams ×2 — all completed) + regression tests and one bugfix appended on this branch during review.

Verdict up front: no blocking correctness defect found in the shipped default state (both lanes gated percent: 0, OFF by default; every degrade path verified fail-safe in the direction away from wrong bytes). Five items need your adjudication below — none was patched unilaterally because each is either explicitly pinned as tracked design work in this branch or a boundary you should consciously accept.

Design items for owner adjudication (no code change made)

A1. The apply tier mixes two coordinate systems — the already-pinned F9 item is the real exposure

reconcileLegacyDiverged's fine-grained apply tier credits a changed row when covered.has(i) where i is the dense row ordinal (src/server/fastpath-v6-render.ts:813-818), but boundCoveredPositions returns ledger positions from pfLedgerIds(sid) (src/server/fastpath-v6-render.ts:881-899), consumed at src/server/prepare-openai.ts:901. The two coincide only while no leading element was absorbed into systemText — which the table comment itself pins (fastpath-v6-render.ts:150-165: "#5652 review F9 tracks the coordinate-mix correction, and this comment flips with it").
Exposure when they diverge (absorbed-leading-system bodies / any future core-element→multi-row mapping):

  • shifted-down case: a genuinely fold-covered row is seen as unexplained → plane KILL (structural divergence) — fail-safe, costs the plane availability for that session;
  • overlap case: an unrelated changed row lands inside the shifted covered set → credited without kernel evidence → weakens the witness guarantee (bytes still came from the wire that just succeeded; bounded by the full-pass audit).
    Suggested resolution when you pick F9: build coverage in row coordinates at the capture site, or restrict the apply tier to sessions whose element↔row alignment is proven 1:1. Deliberately NOT touching this now — it is your pinned item and I did not want to race the ruling.

A2. Same root cause: rows-misaligned can go permanently red

After a witnessed rebase, dense row ordinals exceed identity maxPos under the same coordinate mix ⇒ the plane latches red forever and rides the legacy byte path (safe degradation, but the feature is dead for that sid and the reason string will confuse operators). Fixed by the same A1/F9 correction — listed separately because the operator-visible symptom differs.

A3. Please sign off the checksum scope (documented, direction-safe)

Row checksums cover the checkpoint meta, not payload bytes. A corrupted stored prefix therefore rides silently for at most N−1 green rounds (N = the audit cadence) until a full-pass round diverges and kills the plane. Bounded and terminates in kill, never in serving stale bytes to billing — but it IS "corrupt prefix served once-ish", so I'm asking for explicit acceptance rather than assuming it.

A4. Kill-permanence vs storage failure (soft-fail acknowledged, self-heal analyzed)

killRenderPlane's persistent write is try/catch-swallowed (src/server/fastpath-v6-render.ts:196-208): if storage is down at kill time, death binds only this process; the next process revives the plane until its own integrity checks re-fire. For structural-cause kills I traced that the on-disk condition survives, so the next process re-kills — acceptable. Residual: meta-only corruption invisible to captures keeps riding inside A3's window. Suggestion (either fine): add a restart re-kill test pinning the revive→re-kill path, or queue/retry the dead-row write. No change made.

A5. Rollout flag nesting — confirm intent (now pinned in code as "#5652 review F10" so nobody fixes it accidentally)

watermarkV6Render { percent: 0, base: "watermarkV6MsgId" } composes as nested-on-cohort, but the FORCE tier evaluates force(percent=0, base="pluginFullResendWatermark") against the parent plan — i.e., forcing v6 render also demands cohort membership of the other flag. This looks deliberate (force ≠ unconditional), and I pinned it with an explicit comment in src/rollout.ts (§3/§4 + RolloutPlan.base doc). If force should bypass nesting, say so and I'll flip the comment + tier.

Fixed on this branch during review (test/doc hardening + one availability-scoped bugfix)

commit what
61eb805 Pin v6 identity fault variants + client slot.v6 learn/echo/stale-retention (was untested fault surface)
40a6211 Markers render red reason: one-per-condition pins (red list was partly implicit)
3ee0d46 Docs corrected: pf_ckpt post-fold wording; exhaustive red-list stated; force-tier nesting qualified
635dcb2 Regression-pin inputEstBaseTokens base subtraction in budget math (legacy absent = byte-identical; non-usage sources ignore lastInputTokens; usage-grade baseline wins max() uncharged)
27c21ed Pin §7-A② soft-degrade node: sidecar down ⇒ lane disengages silently (never a 400), armed world untouched, reopen resumes with a hit
c5ecd34 Fixed a real MEDIUM bug found in review: creditReset cleared only the advisory ext replica while readGuard is memory-first, so a healthy turn did not actually clear this process's fault streak — 4 faults + 1 sound turn + 1 more fault parked the session 60m on a cumulative-but-not-consecutive 5th strike (violates the five-CONSECUTIVE contract, fastpath-v6.ts §8). Now resets the memory mirror whenever one exists; regression test §8-12 pins both clear paths (hit + no-progress ride) and is proven discriminating (fails pre-fix). Availability-scoped defect — baseline lanes kept serving throughout; no data-plane impact.

Remaining known-untested / hygiene (deliberately deferred, low value/risk): dead-sid exported registry listing shape; hydrate-failed permanent-red loop escalation (rides A2/A3 windows); docs could name in-body id duplication explicitly next to reorder/rewrite in the coverage-boundary note; refold cycles append 2 harmless pf_log rows each (bounded by pfCompact).

Verified OK (selection)

  • Non-cohort requests stay byte-identical: the v6 gate runs first and short-circuits; the old v5 gate only executes when v6 says "not mine" (prepare-openai.ts v6/v5 ordering + rollout percent 0).
  • Hard-gate 400s are produced outside the pipeline tail, which would otherwise forward the raw refused body (handle.ts refusal mapping).
  • Overflow-refold double evaluation is safe end-to-end: pass #1's commit is durable BEFORE forward (finalize inside prepare), so pass #2 re-evaluates against already-committed truth → empty set-diff → no-progress ride; an accidental duplicate insert would be a rolled-back tx (ledger PK + plain INSERT), never a clobber; the refolded body is fully materialized, so a still-overflowing retry bails on byte-equal comparison and passes the original 400 through.
  • Duplicate msgids cannot double-register or renumber (header-list dups rejected at parse; body-internal dups ride frozen under the documented P3 ignore boundary; pos = maxPos+1+k strictly increasing).
  • _N continuation numbering matches full-parse oracle byte-for-byte (content-hash base ids are neighbor-independent; occurrences counted in strict pos order); windowCores contains ONLY new-slot cores, empty array on rides, stale-leak sweep found none (mirror+pending evicted together; missing-pending serves baseline, never a stale window).
  • Stamp honesty holds on every path: T always comes from a fresh server-side scan stamped identically on arm/hit/degrade/finalize; refusals carry no v6 stamp; a stale-retained client stamp is inert (width gate recomputes server-side) — worst observable case is absence, never falsehood.
  • Every render-plane fault string funnels to kill-or-red; no fault path blesses bytes lacking kernel evidence, modulo A1's overlap corner and A3's window.

CI: gate jobs green on prior heads; full suite re-running on this head (local full-suite pass also in flight). Branch MERGEABLE (BEHIND master — routine rebase at merge time).

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

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

CI 自动修复(第 1/3 次):docs-sync 已修好并推上分支。查重:不重复——此 PR 首个 docs-sync 红,修复直接落在 PR 分支,未开新 issue。

七问:

  1. 是什么问题:PR [PR] feat(fastpath): v6 composite-identity incremental fastpath lane (full rework, #5576 line voided) #5652 的 CI docs-sync 红——配置参考文档的生成产物与种子文件不一致,job 在「重新生成后 diff 必须为空」这一步失败。
  2. 什么原因导致的:提交 3ee0d46c0([PR] feat(fastpath): v6 composite-identity incremental fastpath lane (full rework, #5576 line voided) #5652 review G)改了 website/config-reference/rollout.yaml 里 watermarkV6MsgId / watermarkV6Render 两行的措辞(force-tier 嵌套限定 + 红色清单补 not-engaged),但没有重跑生成器同步产物。master 上没有 watermarkV6* 条目,确认是本 PR 自己引入,不是继承 master 的红。
  3. 影响范围与严重程度:纯文档产物漂移,运行时行为零影响;但挡住合并门禁,必须修。严重度低,修法机械。
  4. 怎么修复的:本地跑 CI 同款命令 node tools/gen-config-docs.mjs generate,重新生成 CONFIGURATION.md / CONFIGURATION.zh-CN.md(各 2 行,内容就是种子声明的原文),独立 docs: 提交推到 PR 分支。期间分支又前进了一个代码提交(c5ecd34c5 Q5 修复),rebase 干净、rebase 后复验无漂移,最终 head = 21ed8bcd0。
  5. 是否有回归问题:无。只动生成产物,零代码/零配置/零行为变更;EN/ZH i18n key 集合相等(249 keys,生成器自校验通过);website/main.js 与 website/docs/index.html 无漂移。已在推送 head 上跑 CI 同款两步命令(generate + git diff --exit-code)实测通过。
  6. 是否破坏缓存:不涉及——与缓存/重试/游标/去重键无关。
  7. 是否改了设计方向/引入新配置:都没有。再生成文本中的「force tiers 按钉死设计绕过嵌套检查(F10 待 owner 裁定)」是 PR 作者种子文件里的既有表述,我只是把它同步进产物,未新增任何措辞或配置项。

判定:docs-sync 阻塞已解除,等新一轮 CI 确认后本 PR 侧无需再动手。

CI static-gates failed: 'msgs' implicitly any[] (TS7034/TS7005) — tests
are typechecked under noImplicitAny. Annotate CoreMessage[] explicitly;
npx tsc --noEmit clean afterwards.
@ranxianglei

Copy link
Copy Markdown
Owner Author

Deep review of #5652 (v6 msgid identity lane + #5664 render-snapshot lane)

Method: full read of every changed hunk (fastpath-v6.ts, fastpath-v6-render.ts, prepare-openai.ts, handle.ts, persist.ts, store.ts, shadow.ts, schema.ts, budget.ts, headers.ts, rollout.ts, dsh-native.ts, pf-channel.ts, plugin.ts, docs/site/website yaml) + eight independent hostile sub-reviews (identity lane ×2, render lane ×2, test-coverage audit, docs-vs-code truth audit, integration seams ×2 — all completed) + regression tests and one bugfix appended on this branch during review.

Verdict up front: no blocking correctness defect found in the shipped default state (both lanes gated percent: 0, OFF by default; every degrade path verified fail-safe in the direction away from wrong bytes). Five items need your adjudication below — none was patched unilaterally because each is either explicitly pinned as tracked design work in this branch or a boundary you should consciously accept.

Design items for owner adjudication (no code change made)

A1. The apply tier mixes two coordinate systems — the already-pinned F9 item is the real exposure

reconcileLegacyDiverged's fine-grained apply tier credits a changed row when covered.has(i) where i is the dense row ordinal (src/server/fastpath-v6-render.ts:813-818), but boundCoveredPositions returns ledger positions from pfLedgerIds(sid) (src/server/fastpath-v6-render.ts:881-899), consumed at src/server/prepare-openai.ts:901. The two coincide only while no leading element was absorbed into systemText — which the table comment itself pins (fastpath-v6-render.ts:150-165: "#5652 review F9 tracks the coordinate-mix correction, and this comment flips with it").
Exposure when they diverge (absorbed-leading-system bodies / any future core-element→multi-row mapping):

  • shifted-down case: a genuinely fold-covered row is seen as unexplained → plane KILL (structural divergence) — fail-safe, costs the plane availability for that session;
  • overlap case: an unrelated changed row lands inside the shifted covered set → credited without kernel evidence → weakens the witness guarantee (bytes still came from the wire that just succeeded; bounded by the full-pass audit).
    Suggested resolution when you pick F9: build coverage in row coordinates at the capture site, or restrict the apply tier to sessions whose element↔row alignment is proven 1:1. Deliberately NOT touching this now — it is your pinned item and I did not want to race the ruling.

A2. Same root cause: rows-misaligned can go permanently red

After a witnessed rebase, dense row ordinals exceed identity maxPos under the same coordinate mix ⇒ the plane latches red forever and rides the legacy byte path (safe degradation, but the feature is dead for that sid and the reason string will confuse operators). Fixed by the same A1/F9 correction — listed separately because the operator-visible symptom differs.

A3. Please sign off the checksum scope (documented, direction-safe)

Row checksums cover the checkpoint meta, not payload bytes. A corrupted stored prefix therefore rides silently for at most N−1 green rounds (N = the audit cadence) until a full-pass round diverges and kills the plane. Bounded and terminates in kill, never in serving stale bytes to billing — but it IS "corrupt prefix served once-ish", so I'm asking for explicit acceptance rather than assuming it.

A4. Kill-permanence vs storage failure (soft-fail acknowledged, self-heal analyzed)

killRenderPlane's persistent write is try/catch-swallowed (src/server/fastpath-v6-render.ts:196-208): if storage is down at kill time, death binds only this process; the next process revives the plane until its own integrity checks re-fire. For structural-cause kills I traced that the on-disk condition survives, so the next process re-kills — acceptable. Residual: meta-only corruption invisible to captures keeps riding inside A3's window. Suggestion (either fine): add a restart re-kill test pinning the revive→re-kill path, or queue/retry the dead-row write. No change made.

A5. Rollout flag nesting — confirm intent (now pinned in code as "#5652 review F10" so nobody fixes it accidentally)

watermarkV6Render { percent: 0, base: "watermarkV6MsgId" } composes as nested-on-cohort, but the FORCE tier evaluates force(percent=0, base="pluginFullResendWatermark") against the parent plan — i.e., forcing v6 render also demands cohort membership of the other flag. This looks deliberate (force ≠ unconditional), and I pinned it with an explicit comment in src/rollout.ts (§3/§4 + RolloutPlan.base doc). If force should bypass nesting, say so and I'll flip the comment + tier.

Fixed on this branch during review (test/doc hardening + one availability-scoped bugfix)

commit what
61eb805 Pin v6 identity fault variants + client slot.v6 learn/echo/stale-retention (was untested fault surface)
40a6211 Markers render red reason: one-per-condition pins (red list was partly implicit)
3ee0d46 Docs corrected: pf_ckpt post-fold wording; exhaustive red-list stated; force-tier nesting qualified
635dcb2 Regression-pin inputEstBaseTokens base subtraction in budget math (legacy absent = byte-identical; non-usage sources ignore lastInputTokens; usage-grade baseline wins max() uncharged)
27c21ed Pin §7-A② soft-degrade node: sidecar down ⇒ lane disengages silently (never a 400), armed world untouched, reopen resumes with a hit
c5ecd34 Fixed a real MEDIUM bug found in review: creditReset cleared only the advisory ext replica while readGuard is memory-first, so a healthy turn did not actually clear this process's fault streak — 4 faults + 1 sound turn + 1 more fault parked the session 60m on a cumulative-but-not-consecutive 5th strike (violates the five-CONSECUTIVE contract, fastpath-v6.ts §8). Now resets the memory mirror whenever one exists; regression test §8-12 pins both clear paths (hit + no-progress ride) and is proven discriminating (fails pre-fix). Availability-scoped defect — baseline lanes kept serving throughout; no data-plane impact.

Remaining known-untested / hygiene (deliberately deferred, low value/risk): dead-sid exported registry listing shape; hydrate-failed permanent-red loop escalation (rides A2/A3 windows); docs could name in-body id duplication explicitly next to reorder/rewrite in the coverage-boundary note; refold cycles append 2 harmless pf_log rows each (bounded by pfCompact).

Verified OK (selection)

  • Non-cohort requests stay byte-identical: the v6 gate runs first and short-circuits; the old v5 gate only executes when v6 says "not mine" (prepare-openai.ts v6/v5 ordering + rollout percent 0).
  • Hard-gate 400s are produced outside the pipeline tail, which would otherwise forward the raw refused body (handle.ts refusal mapping).
  • Overflow-refold double evaluation is safe end-to-end: pass fix: keep system prompt byte-stable for prefix cache #1's commit is durable BEFORE forward (finalize inside prepare), so pass fix: address all code review findings (condense, routing, session-id, dead code) #2 re-evaluates against already-committed truth → empty set-diff → no-progress ride; an accidental duplicate insert would be a rolled-back tx (ledger PK + plain INSERT), never a clobber; the refolded body is fully materialized, so a still-overflowing retry bails on byte-equal comparison and passes the original 400 through.
  • Duplicate msgids cannot double-register or renumber (header-list dups rejected at parse; body-internal dups ride frozen under the documented P3 ignore boundary; pos = maxPos+1+k strictly increasing).
  • _N continuation numbering matches full-parse oracle byte-for-byte (content-hash base ids are neighbor-independent; occurrences counted in strict pos order); windowCores contains ONLY new-slot cores, empty array on rides, stale-leak sweep found none (mirror+pending evicted together; missing-pending serves baseline, never a stale window).
  • Stamp honesty holds on every path: T always comes from a fresh server-side scan stamped identically on arm/hit/degrade/finalize; refusals carry no v6 stamp; a stale-retained client stamp is inert (width gate recomputes server-side) — worst observable case is absence, never falsehood.
  • Every render-plane fault string funnels to kill-or-red; no fault path blesses bytes lacking kernel evidence, modulo A1's overlap corner and A3's window.

CI: gate jobs green on prior heads; full suite re-running on this head (local full-suite pass also in flight). Branch MERGEABLE (BEHIND master — routine rebase at merge time).


Postscript (CI triage, after posting)

Two red jobs on the pre-fix head:

  • static-gates (4×) — npm run typecheck failed on my own review-added tests/issue5664-render-budget-base.test.ts (implicit any[]). Fixed in 6bd9a9280; tsc --noEmit clean locally before push.
  • test (ubuntu-latest, 22, 2) — lane matrix [openai] omp control keeps the surface died with SyntaxError: Unexpected end of JSON input inside the test's OWN loopback fixture upstream server (JSON.parse of a truncated request body, failureType: uncaughtException). tests/lane-decisions-matrix.test.ts is untouched by this PR, passes locally, and every sibling subtest (all anthropic lanes, all windows shards) passed in the same run — consistent with a one-off transport-level flake on that runner, not a code regression. Watching the re-run; if it recurs, the fixture parse should be hardened (wrap in try/catch → fail the subtest deterministically instead of crashing the worker).

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

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

CI 自动修复车道(attempt 1/3):两条 Windows 红腿 = 在档负载 flake 家族同签名,零代码改动,已触发重跑

查重:不重复——本 PR 首次出现这两条红腿;按政策不开新 issue,结论已记 #4599(含完整证据链)。

红腿签名(run 42332732529 @ head 6bd9a92,每 shard 仅 1 fail / ~1880-1900 tests,其余全矩阵绿):

  • test (windows-latest, 22, 2) → tests/wire-exit-matrix.test.ts:273「abort x proxy-openai-sse」closed=0 @21.4s
  • test (windows-latest, 24, 4) → tests/side-lane-invariants.test.ts「(B) main/side interleavings…(ordering independence)」TypeError: fetch failed

七问:

  1. 是什么问题:两个 Windows 测试分片各恰好一个子测试红,均为时序/网络类失败,非断言逻辑分歧。
  2. 什么原因导致的:Windows runner 高负载下的 flake——① 客户端中途 abort 后,上游 socket 的 teardown 未在 win32 专属预算内完成(ABORT_TEARDOWN_BUDGET_MS = 20000@win32 / 10000@其他,tests/wire-exit-matrix.test.ts:65);② 13 次连续起停双 server 的 harness 里某次 loopback fetch 被拒/重置(Node fetch 吞掉底层 errno)。两者都是 CI Control Center: Centralized CI Failure Handling & Status Sync (Comment all CI issues here; do not open new issues) | CI 总控: CI 失败集中处理与状态同步(所有 CI 问题在此评论, 勿开新 issue) #4599「在档」家族:① 与 floor 1042/[PR] fix: stop resident-pool evict/cold-load thrash that OOMs the proxy (#5782) #5783(openai-sse closed=0 @21.5s)、floor 1047(anthropic/responses ×2)、floor 1053(json @21.6s)、floor 1032/[PR] kernel: fold tool-call/result pairs by exact id at any distance (fixes the split-pair upstream-400 / folding-stuck family) #5758(×4 cells)逐字同签名;② 与 floor 1060/[PR] fix(resume): inherit timestamp ledger so resumed sessions re-render provider-cached tag bytes #5609(side-lane-invariants 'fetch failed',当时判 Windows 高负载 flake)同签名。历次该家族 rerun 均转绿。
  3. 影响范围与严重程度:仅影响这两条 CI 腿的信号,产品行为零影响。排除链:两文件均不在本 PR 任何提交 diff 内(仅随 master-sync merge 进入);同 head 下 ① 在 ubuntu-22/ubuntu-24/windows-24 三腿绿、② 在 ubuntu-22/ubuntu-24/windows-22 三腿绿;本地同树定向 wire-exit-matrix 8/8 + side-lane-invariants 15/15 全绿;master c3dfbe6 当期全绿(非继承,ci-fixes 已并入 master)。
  4. 怎么修复的:无机械缺陷可修,零推送——确认 runner 已将两腿分类为 concrete-assertion 不自动重试(不在四可恢复形状内),遂人工触发 rerun-failed-jobs(HTTP 201),两分片在干净 runner 上重新验证。
  5. 是否有回归问题:未引入任何回归——本轮零 diff;既有行为面(abort teardown 语义、side lane 顺序无关性)由本地定向套件与同 head 跨腿绿共同钉住。
  6. 是否破坏缓存:不涉及(纯 CI 处置,未触碰缓存/重试/游标逻辑)。
  7. 是否改了设计方向 / 引入新配置:均未。

另注:上一 head 的 ubuntu(22,2) lane-decisions-matrix flake(owner 审查 postscript 提到的那条)在本轮新 head 的全量 run 中已自然转绿,无需动作。

结论:重跑在途,等结果;若干净 runner 同签名再红,按在档口径升档(记 Windows 时序硬化候选、复发再立项)。#4599 已留一行结论。

@ranxianglei
ranxianglei merged commit ce8f92e into master Nov 7, 2026
91 of 93 checks passed
@github-actions

github-actions Bot commented Nov 7, 2026

Copy link
Copy Markdown
Contributor

📦 Merged Build Published

This merge to master was published as 0.0.1060-master.ce8f92e (rolling master tag).

npm install -g billion-context@0.0.1060-master.ce8f92e  # this exact build
npm install -g billion-context@master  # always the newest merged build

npm view billion-context@master prints the current version at any time.

Louie0806 added a commit to Louie0806/billion-context that referenced this pull request Nov 7, 2026
ranxianglei pushed a commit that referenced this pull request Nov 7, 2026
…er merge (#5826)

The merged fastpath-v6 wave (#5652/#5664/#5732) changed two pinned behaviors: PF_SLOT_UNKNOWN moved client->server (import fix), v6 F1 emits a fixed 64-id tail window instead of slicing at learned K, and v6 F2 makes any id-less/duplicate slot clear the whole captured table ('?' never travels). Re-pinned groups 3+4 of tests/msgid-rule-parity.test.ts to the post-merge verdicts with the ruling citations; added an over-cap case for the raised MAX_IDS (16384).
Louie0806 added a commit to Louie0806/billion-context that referenced this pull request Nov 7, 2026
…ed cap, render-snapshot plane

Upstream 2919794..ce8f92e (57 commits) lands three large planes:

- ranxianglei#5652 fastpath-v6 identity lane (c295f90 storage layer, d55a50c
  composite identity, 9c1fb86 full-list wire, da6885d fixed tail window,
  plus the review follow-ups)
- ranxianglei#5754 image-shed 64-item cap (6aed3b8)
- ranxianglei#5689 render-snapshot plane (acca4db schema v12, 6d3ca30 O(1) steady
  turns, 49ba14d seal-shut probe)
- ranxianglei#5721 witnessed rebase supplement

Overlap with this lane was four files. src/plugin.ts auto-merged (upstream
touches the handoff-reply import at :31 and handlePluginTool at :2337; this
lane owns the strip entry points at :22 / :61 / :2640..:4554). The two
CONFIGURATION files are generated and were regenerated from the seed.

One real conflict, in tests/issue4666-migration-dedup.test.ts line 158:
upstream re-swept the sqlite user_version pin to the literal 13, this lane had
already derived it. Kept the derived form -- that is the whole point of the
earlier sweep, and the literal is what goes stale on the next bump.

That conflict resolution exposed a latent bug of mine. 3eb22b1 ("pin the
mysql lock lane to the CURRENT schema version") derived the mysql stamp
assertions from STORAGE_SCHEMA_VERSION as well. When it was written both
numbers were 9; ranxianglei#5652/ranxianglei#5689 have since pushed the sqlite unified store to 13
while the MySQL backend stayed at 11, because the v12 identity plane and the
v13 render-snapshot plane are sqlite-only. The mysql-contract lane therefore
asserted "13" against a migrator that correctly stamps "11".

Fixed by exporting MYSQL_SCHEMA_VERSION from src/storage/mysql.ts and pointing
the four mysql-side assertions at it; the sqlite assertions keep deriving from
STORAGE_SCHEMA_VERSION. Verified String(MYSQL_SCHEMA_VERSION) is "11", i.e.
byte-identical to the literal upstream asserts.

Verification on the merge tree: issue5175 58/0, tag-echo 79/0,
issue2190-degen-close 32/0, golden-storage-render 5/0, storage-engine-proofs
12/0, native-compact-terminal 1/0, plugin-passthrough-tag-strip-chat 20/0,
issue4666-migration-dedup 2/0 (the three mysql cases skip without
BILI_MYSQL_TEST_DSN; no local MySQL or docker socket in this sandbox).
tsc --noEmit clean, all four gates exit 0, generated docs byte-identical.
@ranxianglei ranxianglei mentioned this pull request Nov 7, 2026
Louie0806 added a commit to Louie0806/billion-context that referenced this pull request Nov 7, 2026
…f the fastpath-v6 lane

Upstream c45ac21..bebc239 is a single revert: ranxianglei#5854 undoes ranxianglei#5652
(66aadbd "Revert feat(fastpath): v6 composite-identity incremental fastpath
lane"). 38 files, -5838/+684 on net: src/server/fastpath-v6.ts,
src/server/fastpath-v6-render.ts and their two test files are gone, and the
sqlite unified store drops back from schema v13 to v11.

That matters here for one specific reason. The previous sync resolved a
derivation conflict in tests/issue4666-migration-dedup.test.ts by keeping the
STACKED form, and the same merge added an export of MYSQL_SCHEMA_VERSION so
the mysql-side stamp assertions stop borrowing the sqlite number. The revert
collapses both numbers back to 11, which would have silently re-hidden the bug
that fix exists to prevent, so the split is kept: the sqlite user_version pin
keeps deriving from STORAGE_SCHEMA_VERSION, the four mysql stamp pins keep
using MYSQL_SCHEMA_VERSION. Both currently equal 11, but they are different
versions owned by different backends and will diverge again on the next plane.

Only one conflict this time, same line 159 as before: upstream reverts the
literal back to 11, this lane derives. Kept the derived form.

src/plugin.ts auto-merged (upstream removes the fastpath hooks, this lane owns
the strip entry points). The two CONFIGURATION files and the rollout/env-only
seed yaml are generated and were regenerated.

Verification on the merge tree: issue5175 58/0, tag-echo 79/0,
issue2190-degen-close 32/0, golden-storage-render 5/0, storage-engine-proofs
12/0, issue4666-migration-dedup 2/0. tsc --noEmit clean, four gates exit 0,
generated docs byte-identical.

Lane symbols all survived the revert: stripDriftResidue 6, isDraftDump 4,
containsRenderTagText 8, mayStartDegenerateRenderTag 6, DRIFT_BARE_MISMATCH 3,
DRAFT_CLOSE_TAIL 3.
nexusatemporal pushed a commit to nexusatemporal/billion-context that referenced this pull request Nov 7, 2026
…stpath-v6 code was reverted, ranxianglei#5854)

ranxianglei#5826 commit 33b2f82 re-pinned two msgid-rule-parity rows to the v6 F1/F2
rulings «after master merge»; revert ranxianglei#5854 then removed the fastpath-v6
code (ranxianglei#5652), leaving those pins asserting behavior that no longer exists —
master failed the same two rows on pure fb18e7e (verified via detached
worktree). This restores tests/msgid-rule-parity.test.ts to its bc44f77
state, i.e. exactly undoes the 33b2f82 hunks: PF_SLOT_UNKNOWN import back
to pf-channel.js, per-slot "?" rides-again semantics, K-sliced tail window,
and the removed OVER_CAP row (v6 MAX_IDS 16384 no longer applies).
ranxianglei pushed a commit that referenced this pull request Nov 7, 2026
…F2 ruling governs again

Master's 613d290 restored these pins to pre-v6 verdicts on the explicit
condition that 'fastpath-v6 code was reverted (#5854)'. This PR re-lands v6,
so per KDD #17 (deliberate divergences re-pinned consciously, with stated
rationale) the pins follow the code again:

- pf-channel e2e: F2 owner ruling (2026-11-04, PR #5652 review follow-up) —
  any hole/duplicate clears the WHOLE captured table; '?' never travels from
  the client. Pre-v6 '?'-slice verdicts replaced by count-only verdicts.
- pf-channel e2e: F1 fixed tail window (last <=64 ids) replaces K-based
  slicing; capture cap raised 2048 -> 16384 (cap still pinned via a 16385-id
  row so coverage does not shrink).
- dsh pfSlotIdsOf: same F2 whole-table-clear (was '?' slot list).
- PF_SLOT_UNKNOWN import moves from agent/pf-channel.js (constant removed
  client-side by F2) to server/fastpath.js (wire decoder still accepts legacy
  '?' segments from v5 traffic).
@github-actions github-actions Bot mentioned this pull request Nov 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment