Repository navigation
fix: survive a corrupt unified index by degrading to legacy-only (#2771) + storage-engine proof battery - #2772
Conversation
…); pin the storage engine's restart/rollback/CAS contracts
📦 Built Package ArtifactBranch: Option A — Install this exact build (recommended)npm install -g billion-context@0.0.3047-pr.2772.a8b0fc6This exact version is immutable and reproducible. The rolling Option B — Download artifact
tar xzf billion-context-pr2772.tgz
npm install -g packageInstall instructions are refreshed on each push. |
[bot] 🏷 Review 结论:可合(CI 矩阵跑完后即满足合并条件) 审了原 issue(#2771)、PR 自身 diff、触碰路径的既有行为清单。单 commit(fcac9e3),3 文件 +505/-3,无 kernel/、无版本行、无 lockfile 噪音,diff 每一行都与目的相关。 结构化八问
行为变更披露(按交付规则第 4 条):旧行为 = 损坏 index.db → 进程启动失败;新行为 = warn 日志 + 降级 legacy-only,读写走 legacy 路径正常。这就是本修复本身,旧值是缺陷不是特性。 测试有效性:corrupt-index 腿逐字节复现原 bug(前 512 字节写 0x5a → SQLITE_NOTADB),断言三件事都有牙:构造存活、legacy 回退 digest 与干净 full-mode 读逐字节相等、写继续工作;A/B 声明(去掉修复则测试死于构造)与代码路径一致。wire parity 的双 oracle(committed goldens + legacy-restart)和 dropFile 腿(删光 legacy 文件后索引必须自足)是真断言,非恒真。hermetic 隔离(BILI_CONFIG_FILE 指向空配置 + env 保存/恢复)、mkdtemp、慢腿带超时,确定性没问题。 §7.4 auto-merge 门禁:单模块修复 + 复现原 bug 的回归测试 + 不触 config/persistence/wire/kernel/版本 + 干净 diff + CI:全部 guard 作业绿(kernel/lane/config-surface/lock-sync/docs-sync/version/pi-subagents/docs-coverage/build-artifact/unused-exports);test 矩阵(ubuntu/windows × node 22/24)仍在跑,转绿后我跟进确认。 可合。 |
📦 Merged Build PublishedThis merge to master was published as npm install -g billion-context@0.0.278-master.690f7c7 # this exact build
npm install -g billion-context@master # always the newest merged build
|
…-fix test(storage): close index.db handles before rmrf — fix Windows EBUSY in storage-engine-proofs (#2772 follow-up)
…nxianglei#2772 follow-up) The four engine-proof tests that run under BILI_STORAGE_UNIFIED=shadow|full leaked their SessionStore shadow handles (cancelAll only cancels timers; it does not close the SQLite connection), so the rmrf(tmpdir) cleanup retried EBUSY for ~3s and then failed on windows-latest (Node 22/24). POSIX unlink tolerates open handles, which is why Linux never saw it. - loadFolded: cancelAll -> closeQuietly (the loader store is discarded right after loadSync; this was the leak shared by all four failing tests) - end-of-test read-only stores in the import-guard/rollback/corrupt legs: cancelAll -> closeQuietly - kept cancelAll at the corrupt-fallback read that is followed by writeNow (mid-test: the store must stay usable; its own closeQuietly follows at the end of the test)
Fixes #2771. Proof battery for the seams the #2690 coverage audit found unproven (issue #2671 refactor follow-up).
1. The bug (#2771, product fix)
A corrupt
index.db(crashed checkpoint / stray write) madeUnifiedStore.openthrowfile is not a databaseout ofmaybeOpen—SessionStoreconstruction died, so underBILI_STORAGE_UNIFIED=full|shadowthe ENTIRE proxy failed to boot, violating the sidecar's own "never break legacy" policy (record/viewForare try/catch-guarded; construction was not).Fix:
maybeOpennow wrapsUnifiedStore.openand returnsnullon failure (warn log, stay legacy-only). No auto-delete: the index may hold pinned checkpoint blobs (#2690 Phase 2a); the log says so.A/B: stash the fix → the corrupt-index proof dies at construction (
Error: file is not a database); with the fix → construction survives, the legacy fallback serves the byte-exact state, and writes keep working.2. The proof battery (tests/storage-engine-proofs.test.ts)
3. Findings along the way (no product change)
bs/bl/begap: the cacheLedger body-stability seam slots (大量缓存接缝事件导致缓存命中率大幅度降低 #2131) are in-memory, so exactly the FIRST post-restart ledger line loses itsbsclassification — identically under legacy and unified restarts (verified). Diagnostics-grade; persisting seam slots would be a product call, not a parity defect. Tracked in [Improvement] seam-slot pairing (bs/bl/be on ledger lines) is process-local — the first post-restart request loses its body-stability attribution #2773.lastMessagestail order once on a load→save cycle (summary carrier position). Self-normalizing fixed point, identical under both paths.flushAll()closes the sidecar by design (shutdown semantics) — the drive harness now accounts for that.Config surface
No changes (BILI_STORAGE_UNIFIED semantics untouched).
Kernel boundary
No changes under kernel/.