Repository navigation
[PR] chore: empty PR (no changes) - #4801
Conversation
(ai: vllm-qwen/qwen3.8-27b) 查重:不重复——本条是空 PR 的 CI 验证通知,非缺陷报告;同类的上一次空 PR(#4725)已关闭,无在途重复项。 核对结果:
|
|
对这个做release 回归审核 |
dsh/omp send msgIds parallel to the WIRE (one id per message), but a multi-block assistant turn ([text, tool_use]) converts to TWO core rows, so the ids can never map 1:1 after conversion. The lane hard-400'd that shape — and since clients retry the identical shape and only understand 200/409/503, the conversation failed FOREVER once it happened. Now a post-conversion count mismatch drops that delta's client ids (derived ids pin the rows) and the turn applies; clean 1:1 deltas keep pinning. Found in the #4801 branch review (P0).
cloneSessionRows bumped a blob's refcount once per DISTINCT hash while every other path (ingest, delete, sweep) accounts per referencing row. A fork whose parent rows share one blob (one image on several messages, #3762 media mappings) walked out with a single ref for N rows; any later session delete then over-released and drove the refcount negative, and delete-on-zero GC swept bytes sessions still referenced — a fork could eat blobs it never owned. The MySQL twin had the same bug. Found in the #4801 branch review (P1). Tests: fork-clone-media-refcount.
The UNIQUE-collision repair deleted byte-identical blocker rows and their media mappings WITHOUT releasing their content refcounts — a permanent over-count, so those blobs could never be GC'd (#4800 delete-on-zero only reclaims exact accounting). Same for the MySQL twin. Found in the #4801 branch review (P1). Tests: unified-remap-collision.
…ot the per-request Signature The #1884 resign lane re-signs every request (Signature is an HMAC over the per-request date + body), so credentialFingerprint returned a UNIQUE identity per request: the #4204 429 governor's holds never matched (the APIG lane never throttled), the #3376 keepalive snapshot deleted itself after every forward, and #2131 cache attribution fragmented into one bucket per request. The stable credential on that line is the Access key id — fingerprint only that. Found in the #4801 branch review (P1).
…pelling server.ts prints usage-baseline=none when no floor is set; the gate's demote assertion matched only the numeric spelling and every no-baseline run failed line B. Found in the #4801 branch review.
208 → master 全量分支审查结果(5 路并行评审 + 实测验证)已直接修好并推进本分支的 5 个问题(均有回归测试,测试在修复前必挂、修复后全绿)1. 多内容块消息会让会话永久卡死(P0,最严重) 2. 分叉(fork)会偷吃别的会话还在用的图片/内容(P1) 3. #4793 的冲突清理漏还引用计数(P1) 4. APIG 签名通道的限流/缓存记账全部失灵(P1) 5. 发布门禁 B 线误报 需要你拍板的(没动,列出来讨论)
测试改动审计(防假绿)5 路评审里专门有一路审计测试改动:没有发现假绿。-719 行删除都是对已记录行为变更的诚实适配,大部分断言反而变严了。唯一建议:全量模式重启腿现在把引用数字和 cacheLedger 字段归一化掉了,补一条精确断言更稳(A1)。 验证情况
|
📦 Built Package ArtifactBranch: Latest build — install this exact versionnpm install -g [email protected]This exact version is immutable and reproducible. The rolling Recent builds (commit → version)
Download artifact
tar xzf billion-context-pr4801.tgz
npm install -g packageInstall instructions are refreshed on each push. |
master window commits 293ae65/de5e03659 bumped kernel/package.json to 0.0.165 without regenerating the lockfiles; lock-sync re-resolution then rewrites the stale recorded versions (root 0.0.163, kernel 0.0.164) and fails. Pure recorded-version sync via npm install --package-lock-only; no dependency or semantic change.
…iew) seqSpanById joined retired generations into a covered id's span, so an in-place edit (old generation tombstoned by the complete-log sweep, new one past max(seq)) widened stored block bounds across generations. Bounds describe the CURRENT replay — getMessages filters retired rows — so the point query now takes live rows only; a covered id with no live rows yields the -1 sentinel and the upsert keeps stored bounds (#4608). Second facet, same symptom: the sqlite re-save branch bound the PLAN-LOCAL b.startSeq/b.endSeq (positions in this plan's log) instead of the transcript-resolved bounds the fresh-insert branch uses; after generation turnover those no longer coincide and every re-save clobbered the durable interval with plan-relative numbers. Both branches now bind the same source. The mysql mirror already bound the resolved values. Regression pin: tests/block-bounds-live-only.test.ts (fails pre-fix).
…4801 review) putContentRef (sqlite) and the two cloneSessionRows refcount bump loops (mysql) were silent no-ops when the UPDATE matched nothing: the clone walked out with rows referencing a blob nobody counted, and every later delete released a ref nobody took — negative refcount lets delete-on-zero GC sweep bytes other sessions still reference. The mysql DDL declares no foreign keys, so dangling refs are reachable there; the sqlite DDL FK fires earlier at INSERT..SELECT, and the guard keeps both backends equivalent-loud for FK-less/corrupted-file shapes. Contract pin extends tests/fork-clone-media-refcount.test.ts: the clone refuses and leaves no partial child rows.
… credential (#4801 review) The wrapper never sends If-None-Match, so a 304 answers a request the upstream treated as revalidation anyway. The replay itself stays (availability-first: codex clients expect a complete 200 catalog), but savedAt resets on every replay, which would pin a stale catalog forever with zero trace if the gateway loops. One warn per credential key makes the loop visible.
…map-collision (#4801) The fixture's prepare() cast only declared run(), while contentRefcount/ mediaRows call .get() — a tsc error the image-lane typecheck gate caught on this head (the previous head never ran the job during the queue stall). Type-only; no runtime change.
… adoption Two gate-side causes behind the 15:22 rerun reds (neither is a product bug): 1. dsh's read tool elides the middle of results over ~8KB (head+tail kept). The single 441-line/90KB corpus read at t1 never delivered S07 (title at ~line 71), so both S07 recall checks measured a hole that predates the fold — and the elision also kept the t2 payload at ~13.6k, under the 16.4k text target, so preflight rightly skipped folding (#4288) and 'fold fired mid-session' went red on a turn that legitimately fit. t1 now enumerates 13 explicit 35-line read chunks. 2. The lineage assertion only matched the old adoption wording. A healthy fork with nothing fully-present takes the fresh-start path ('no fully-present blocks to adopt … starting fresh; lineage linked', #629/#3925) — that is same-lineage by design and now counts.
(ai: vllm-qwen/qwen3.8-27b) 独立审核结论:5 个修复全部确认为真根因、修法正确;5 个待拍板项已逐项给建议(其中 2 项已直接修好、带回归测试推进分支)一、对 5 个已修问题的独立复核(自己读 diff + 修复前代码实测必挂,非转述报告)1. P0 多内容块卡死(msgIds 数量不匹配)——确认真根因,修法正确。 独立验证了完整因果链:envelope gate(src/incremental-lane.ts:612-627)只在 wire 条数与 core 行数一致时才传 deltaIds;助手 [文本+工具调用] 一条 wire 消息合法展开成两行 core → 老代码对 length-mismatch 也回 400,而 dsh/omp 只处理 200/409/503、原样重试同形状请求 → 会话永久冻结。新代码把 400 收窄到身份投毒类原因(bad-entry/duplicate/reserved-prefix/control-or-space,src/msgid-pin.ts:28-46),length-mismatch 降级为放弃本批客户端 id、走内部派生 id;降级后前缀仍按 entry.msgs 重盖(:687),重启后派生 id 经统一表保持稳定。回归测试 tests/msgid-lane-flow.test.ts 第 6 条在修复前代码上实测挂(5p/1f),修复后全绿。✓ 2. P1 fork 偷吃引用计数——确认。 DISTINCT 去掉后按行 putContentRef(store.ts cloneSessionRows + mysql 镜像),与插入/释放纪律对齐;同一 blob 挂 N 行得 N 个引用,删除按行扣,不再负数→GC 误删他人在用的文件。tests/fork-clone-media-refcount.test.ts 两条(media 共享 blob / text CAS 双行)修复前均挂(0p/2f),修复后绿。✓ 3. P1 #4793 清理漏还引用——确认。 冲突清理删掉的 retired 重复行现在逐行归还 r.to + media hash 引用(store + mysql),否则永久 over-count、blob 永不 GC(#4800 delete-on-zero 依赖精确计数)。一个提交结构小瑕疵:#4793 源码改动在 5338283、其回归测试在 4135b82(同时刻拆两 commit),分支整体完整,不影响合并。测试修复前挂(2p/1f)、修复后绿。✓ 4. P1 HMAC 指纹——确认且格式逐字核对过。 src/cache-ledger.ts:653-671 用 5. 发布门禁 B 线正则——确认。 scripts/release-gate-local.mjs:479 改 另核了 cdac1c0(ci-fixes 带入的 persist.ts CCR restamp guard):contentStoreOf 会物化空 envelope 导致 storage-unified parity pin 在 full-mode 冷加载炸掉,guard 方向正确,属哨兵已有工作非新增。 二、5 个待拍板项的独立结论与建议1. 304 无条件回放——建议保留行为,观测已补(决策无关部分先修,commit 1b8a0ab)。 位置 src/server/codex-catalog-cache.ts:214-219:包装层从不发 If-None-Match,上游回 304 是把网关怪行为合法化成完整 200 目录。但范围极窄(仅 GET chatgpt.com/backend-api/codex/models + Bearer,载荷只是模型元数据),offline replay 与 304 回放是同一可用性设计,收紧伤 codex 车道可用性——按「可用性大于性能」保留。不过原 304 分支零日志:持续假 304 会静默把目录钉死(savedAt 不断刷新,maxAge 永不老化)。已加每 credential 一次的 warn(记录刷新前 age)。行为零变化,纯观测。 2. msgIds 预登记烧号(P2)——机制确认,推荐「幂等尾重放」,请你拍板。 我追了完整重试路径:applyTurn 在 forward 之前就地改写 entry.msgs(:666),异常 finally 不回滚。但常见失败路径其实自愈:forward 抛错时 ack header 未盖章(只在 2xx 盖,:749-766),客户端 sinceSeq 不变而 serverSeq 已前进 → :447-451 的 seq-mismatch 409 先于 claim-400 触发 → 客户端处理 409 → resync 全量重建(resync 下 claim 检查跳过)→ 恢复。真正的残留冻结需要两个条件同时成立:行已落库但 ack 未送达(ingest 后上游失败/进程崩溃)+ 客户端 id 跨重试确定性。选项:A 维持现状(残留窗口是否可接受取决于 dsh/omp 的 id 生成是否确定性,需车道侧证据);B 失败回滚 entry.msgs(复杂、易漏路径);C 幂等尾重放——重放与已落库尾部(identity+内容匹配 serverSeq-k..serverSeq-1)完全相同时按成功应答 appliedSeq,内容不符才硬 400(防错配保留)。推荐 C:把「同一批字节重放」从错误变成幂等操作,与存储层 idempotent re-receipt 语义一致,不需要客户端配合;代价中等(要读尾部行比对),不动架构。等你拍板后再做。 3. MySQL lastLiveSeq/cloneSessionRows 死代码(P2)——论断不成立,代码是活的。 证据链:shadow.ts:273-284 对 mysql 选择真实打开 MysqlBackend;shadow.ts:810-827 两个方法无条件委托 this.sync(plugin.ts:1543-1545 fork 端点无条件调用,persist.ts:1732-1755 wrapper 无后端门禁);mysql.ts:960 lastLiveSeq = MAX(seq) WHERE retired_at IS NULL(正确),cloneSessionRows 是完整事务实现(幂等重放 + lineage upsert)。精确表述应是:#4008 使 mysql2 为外部依赖,npm bundle 安装加载不了 mysql 后端,该路径实际只在 dev checkout 可达——不是死代码,是 dev-only opt-in。「fork 静默降级」也不成立:mysql 实现存在且被调用,只有返回 false 才有 debug log。此项无需改动。 4. seqSpanById 不过滤退休行——确认缺陷,已直接修好(commit e59e34a)。 store.ts 块边界点查询无 retired_at 过滤,块 start_seq/end_seq 跨代变宽;mysql 镜像同款。查的时候还发现第二个同机制缺陷:sqlite 的「已存在块」更新分支绑定的是 plan 本地 startSeq/endSeq 而非 transcript 解析出的 bStartSeq/bEndSeq(mysql 镜像本来就绑解析值 :610-611)——查询过滤对了,re-save 也会把 plan 本地值写回去覆盖。两处都修:查询加 5. putContentRef 缺失静默不计数——确认,已直接修好(commit 253010b)。 store.ts putContentRef 的 UPDATE...WHERE hash=? 不检查 changes,内容行缺失时静默少计;mysql 两处 bump 同款。两边都改成 affectedRows===0 即抛错(clone 事务回滚,fork 响亮失败 + debug log,替代静默腐蚀引用账)。诚实披露一层:sqlite DDL 有外键(messages.content_hash REFERENCES content(hash),schema.ts:144/:264),clone 的 INSERT..SELECT 会在 putContentRef 之前就触发 FK 报错——所以 sqlite 侧这个 guard 是纵深防御(FK 关闭/手工损坏场景),其回归测试在 sqlite 上是契约钉(clone 必须响亮拒绝且不落半截子会话行,修复前后都过);MySQL DDL 无任何 FOREIGN KEY 声明(grep 证实),缺失行真实可达,那边才是主战场。 测试改动审计(A1):同意你的判断,没发现假绿。归一化那条的具体规格:full-mode 重启腿应断言重启后的引用数字逐 identity 等于 ledger seq+1(citeNormBody 在 tests/golden-storage-drive.ts:652,driveWire oracle 是你写的,我不擅动)。没并进本车:这个 PR 每次 push 都烧一整轮 ci:full 队列,一条断言不值得——你认可规格后单独跟进即可。 三、CI 状态(独立核查)
四、结构化八问
判定:可合。 分支自身代码干净,定向 + 全矩阵(除继承红)全绿;剩余动作 = 哨兵把 #1492-B 收敛进 ci-fixes(#4599 已报)+ 你对第 2 项(msgIds 烧号,推荐幂等尾重放)拍板。 |
(ai: vllm-qwen/qwen3.8-27b) CI 失败分诊结论:14 个红 shard 全部是 master 级继承性失败,本 PR 零新增红;按政策未在分支上重复修,证据链已报 #4599。 查重:不重复——本条是该 PR 的 CI 失败处理(floor 2 的接单查重结论不变)。
收尾判定:本 PR 自身的 16 个 commit 干净、可合——待哨兵把 5 组继承红收敛进 ci-fixes(#4599 已报)后,merge ci-fixes 重跑即可转绿。本轮未 push。 |
…rker-N-r1 # Conflicts: # kernel/package-lock.json # package-lock.json
(ai: vllm-qwen/qwen3.8-27b) 冲突自动修复完成:已把 master 合入 PR 分支并推送(merge commit
|
📦 Merged Build PublishedThis merge to master was published as npm install -g [email protected] # this exact build
npm install -g billion-context@master # always the newest merged build
|
Conflict in src/server/codex-catalog-cache.ts (the 304 branch): master added a once-per-credential warn log while KEEPING the replay (availability-first stopgap, 1b8a0ab from the #4801 review); this branch replaces the replay with invalidate()+passthrough for off-spec unconditional 304s. Resolved by union of intent: - Unconditional 304 (no if-none-match/if-modified-since on the request): invalidate() + pass the raw response through (this PR's fix), plus master's once-per-credential warn so a gateway looping on the off-spec answer stays visible in the logs. - Conditional 304 (client sent a validator): unchanged negotiated revalidation — replay cached 200 and extend freshness. - Renamed replayNoted -> offSpec304Noted: nothing is replayed on the off-spec path anymore, the old name would lie. Behavior change vs current master (intended, this PR's purpose): an unconditional 304 previously replayed the cached catalog as a full 200 and extended its freshness; now the cache entry is dropped and the 304 is forwarded as-is, same treatment as every other unexpected status. Verified locally: npm run typecheck clean; targeted node --import tsx --test tests/codex-catalog-cache.test.ts 10/10 pass (includes both 304 case pins). Full-suite verdict = remote CI.
Empty PR as requested — one
--allow-emptycommit on master tip (931c66a2), zero file changes. Nothing to review or merge. Purpose: run the full CI matrix (ci:full) against current master.kernel-change: lockfile recorded-version sync only (acp-kernel 0.0.163→0.0.165 record lines), inherited verbatim from ci-fixes dfadc21 (#4599 sentinel); zero kernel SOURCE changes in this PR.