Skip to content

[PR] fix: name the win32 READONLY index.db open failure; drop the delete advice under OS-level refusals (#4614) - #4625

Merged
ranxianglei merged 11 commits into
masterfrom
2026-10-25_readonly-open-hint
Oct 30, 2026
Merged

ranxianglei merged 11 commits into
masterfrom
2026-10-25_readonly-open-hint

Conversation

@ranxianglei

Copy link
Copy Markdown
Owner

Follows #4614 (sub-defect A: diagnostic gap). Not auto-closing — the issue's root cause (why this machine's index.db stopped accepting writes) and its drift facet are still under triage.

What

Field report (#4614, v0.1.205 win32-x64): an EXISTING index.db that was writable until 14:27 fails to open at the next boot with attempt to write a readonly database and degrades to legacy-only. That is the #3823 failure class (OS-level write refusal: Windows integrity control / MIC No-Write-Up on a DSH-spawned low-integrity child, AV lock, exclusive concurrent writer) surfacing differently once the file already exists — open succeeds read-only, the first write is refused → SQLITE_READONLY instead of CANTOPEN. But sqliteOpenFailureHint only recognized the CANTOPEN string, so:

  1. the /__bili/status degrade reason carried zero actionable info for this signature;
  2. the degrade warn line still appended ; delete the file to reset the index — actively harmful here: in unified-full mode index.db may hold the only copy of recent session state for a session whose JSON envelope writes were frozen by drift escalation.

Change

  • sqliteOpenFailureHint gains the READONLY signature branch (win32-only, same platform doctrine as [PR] fix(storage): name OS-level suspects in win32 CANTOPEN degrade output (#3823) #3855): names the integrity-label suspect, gives icacls label-check + recursive Low re-labeling commands, AV/concurrent-writer suspects, and an explicit do-NOT-delete warning.
  • The degrade tail now drops the delete advice whenever an OS-level hint fires (CANTOPEN included — previously the line said "deleting will not clear a lock" AND "delete the file" in the same sentence); genuine corrupt-file failures and non-win32 keep it unchanged.

Behavior change disclosure (old → new)

  • OLD: any non-engine open failure logged ... staying legacy-only <hint?>; delete the file to reset the index — including when the win32 CANTOPEN hint had just said deletion cannot help.
  • NEW: when sqliteOpenFailureHint fires (win32 × CANTOPEN or READONLY), the log line ends with the hint only; the delete suffix appears only for un-hinted failures (corrupt file etc.). Log wording only — no protocol/config/persistence/wire change. Diagnostics (runtime-status) pick up the READONLY hint automatically via the shared function.

Tests (targeted green locally; full suite = CI)

tests/storage-cantopen-hint.test.ts 3→8 cases, both directions pinned per #3617:

  • unit: win32×READONLY hint content (platform/integrity/icacls/do-NOT-delete); linux+darwin silent on READONLY;
  • wiring: a 0444 regular index.db deterministically reproduces the field-reported READONLY degrade (skip under root/win32 where permission bits don't bind);
  • wiring: stubbed-win32 CANTOPEN — hint present in reason AND delete advice ABSENT from the degrade line (the negative pin);
  • wiring: native-platform CANTOPEN — win32 keeps suppression, non-win32 keeps the delete advice (positive pin).

typecheck clean; node --import tsx --test tests/storage-cantopen-hint.test.ts 8/8.

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

📦 Built Package Artifact

Branch: 2026-10-25_readonly-open-hint (516d2ca)

Latest build — install this exact version

npm install -g billion-context@0.0.6829-pr.4625.47515a6

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
516d2ca billion-context@0.0.6829-pr.4625.47515a6 build
3a4d076 billion-context@0.0.6166-pr.4625.258ae4f build
c3d4bb6 billion-context@0.0.6079-pr.4625.3e5ff5f build
1740a82 billion-context@0.0.5981-pr.4625.5f28aee build
14f6593 billion-context@0.0.5879-pr.4625.6223747 build
f71d643 billion-context@0.0.5812-pr.4625.10ea12d build
2f90338 billion-context@0.0.5660-pr.4625.dd92558 build
43addbf billion-context@0.0.5621-pr.4625.4d28809 build
bef53e1 billion-context@0.0.5617-pr.4625.9dded4e build
a4e1422 billion-context@0.0.5610-pr.4625.ea32ed1 build

Download artifact

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

Install instructions are refreshed on each push.

@ranxianglei ranxianglei changed the title fix: name the win32 READONLY index.db open failure; drop the delete advice under OS-level refusals (#4614) [PR] fix: name the win32 READONLY index.db open failure; drop the delete advice under OS-level refusals (#4614) Oct 24, 2026
ci-check added 2 commits October 25, 2026 07:11
…ot this PR's

master 146b34f fails the unused-exports gate on this exact line
(INTERNAL_ONLY src/agent/client-build-note.ts: ClientBuildCheck): the
type-only export #4545 introduced was missed by the 4d34abf de-export
sweep. This PR touches none of it — every PR rebased past that master
inherits the red (#4599 storm log). Same one-word fix as #4606 commit 1
and the in-branch precedents (#4607/#4595/#4540/#4618/#4622): drop the
leading export on a symbol referenced only within its own file. Drop
this commit when rebasing after #4606 merges.
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

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

查重结论:不重复。 本 PR 是 #4614 子缺陷 A(诊断缺口)在该线程承诺的交付物;与已关闭的 #3823 同属一个失败域(OS 级拒写)但签名不同(CANTOPEN vs READONLY)——签名不同正是旧提示落空的原因,不构成重复;子缺陷 B(漂移面)按约定留在 #4614 等 owner 拍板,本 PR 只搭车其日志措辞小修。

标签: bug、dsh、scope/storage、p2(理由:存储诊断面缺陷;现场来自 dsh 拉起的 win32 低完整性子进程车道;严重度=排障盲区+误导性建议的数据风险窗口,不是可用性停摆——降级本身是设计内兜底)。


独立审核(PR 侧重新做过,不复读 issue 结论)

① 方向关:根因判断成立且打到了点上。提示函数(#3855)当年只为「文件不存在」形态的 CANTOPEN 字符串写的;文件已存在后同一机制换字符串出场(打开成功、第一次写入被拒 → SQLITE_READONLY),字符串匹配落空 = 矩阵缺一格,不是症状层修补。我独立核实了前提:bili 从不以只读方式开库(普通 DatabaseSync,无 readOnly 标志),所以 READONLY 只能是 OS 拒绝首写;提示文本给的是嫌疑名单(完整性标签/AV/并发写者)+ 已验证过的 icacls 处置剧本(#3823 同款),不断言未证实的具体根因——认识论姿态正确,因为 #4614 的确切归属还等取证。

② 回归关(逐格清点 degrade 路径既有行为矩阵,读了改动前代码而非只看 diff):

场景 旧 新 判定
无引擎(no-engine) 无尾部 无尾部 保持
win32 × CANTOPEN hint + 删除建议(自相矛盾句) 仅 hint 有意变更,已披露
win32 × READONLY 仅删除建议(有害) 仅 hint 有意变更,已披露
win32 × 其他(真损坏等) 删除建议 删除建议 保持
非 win32 × 任意 删除建议 删除建议 保持

CANTOPEN 分支文本逐字未动;sqliteOpenFailureHint 全仓仅两个消费点(degrade warn 行 + runtime-status.ts:189 的 reason 拼接),后者经共享函数自动获得 READONLY 提示,属预期收益;「delete the file to reset」全仓仅一处残留且已被新三元控制。高危模式逐项过:无阈值/时序/输出格式漂移(仅日志措辞)、无 fail-fast 变吞错(recordSidecarOpenFailure + return null 原样保留)、无缓存/重试/游标面触碰;两种压缩模式均正交(存储层,plugin/proxy 共用同一 SessionStore 构造路径)。第二个 commit(bef53e1,升级告警措辞)核实为纯日志:冻结行为原文保留,只把「usually means MULTIPLE instances」断言改为点名两个已知生产者,#4614 floor 6 承诺的三个选项都需要的部分,测试钉住双假设。

③ 代码关:正则风格与既有 CANTOPEN 分支一致(case-insensitive 子串,SQLite 错误文本跨版本稳定);提示文本含可执行命令(查标签 + 递归 Low 重打标)与明确的 do-NOT-delete 及理由;注释更新与代码事实相符(不再出现「删文件解不了锁」同句后又建议删文件);无 as any/console.error,走 loggerLog。告警里「delta fast path skips them by design」的机制断言我核过:增量快路径对水位线之下的原位改写是 #3133 的设计内放行,点名它作已知生产者在机制层面准确(具体字节差仍等 #4614 取证第 7 项,措辞未越界)。

④ 测试有效性:8 例全部有牙、双向钉死(#3617)——单测断言具体 token(win32/readonly/integrity/icacls/do NOT delete)而非恒真;非 win32 静默钉 linux+darwin 两平台;wiring 用 0444 真实文件确定性复现 READONLY 降级(非 mock),root/win32 跳过理由写明(win32 分支由平台 stub 单测补位,诚实边界不留假绿);stub-win32 CANTOPEN 负向钉正是旧 bug 形状(hint 在场 ∧ 删除建议缺席),谁把无条件后缀加回来它就红;drift 告警新增 #4614 生产者断言与既有 #394 断言并存。本地实测:两文件 14/14 绿,typecheck 干净。

⑤ diff 整洁度:4 文件每行都服务于目的(fix + 测试 + CHANGELOG 条目,条目位置核实在 [Unreleased]→Fixed 顶部)。另:审核中我发现并处理了一条 CI 红(见下),独立标注 commit,不属于本 PR 内容但按风暴惯例必须披露。

结构化八问

  1. 是什么问题:win32 上「已存在的 index.db 打开后首写被 OS 拒绝」(READONLY 形态)拿不到任何可操作诊断,warn 行还附一条在 full 模式下可能销毁会话状态唯一副本的删除建议。
  2. 什么原因导致的:失败类有两个错误字符串,提示函数只为其中一个(CANTOPEN)写了分支;文件存在与否决定哪个字符串出场,匹配落空后通用删除后缀无条件兜底。
  3. 影响范围与严重程度:所有以 READONLY 形态降级的 win32 安装(SQLite unified storage degraded to legacy-only (bili v0.1.205, node v24.22.1, win32-x64) #4614 报告者即其一);程度=排障无出口 + 有害建议拖长数据风险窗口,压缩功能本身不受影响(降级是设计内兜底)。
  4. 怎么修复的:把共享提示函数的签名矩阵补全到该类第二个签名(平台教义不变,win32-only),并把删除后缀从无条件尾部改成「仅当无 OS 级 hint 触发时输出」——建议与失败类别匹配:OS 拒写→点名嫌疑+禁删;真损坏→保留删除建议。
  5. 是否有回归问题:上表矩阵逐格审过,仅两个已披露格变化;CANTOPEN 文本逐字不变;损坏文件与非 win32 场景删除建议双向测试钉死;reason 面经共享函数自动获得提示属预期。无协议/配置/持久化/wire 变更。
  6. 是否破坏缓存:不涉及(日志/诊断字符串)。
  7. 是否改了设计方向:不涉及——扩展既有 [PR] fix(storage): name OS-level suspects in win32 CANTOPEN degrade output (#3823) #3855 提示教义,无新机制。
  8. 是否引入新配置:无。

CI 分账(head 43addbf,我推送的)

收工判定:PR 自身范围内 ready-to-merge;合并按钮当前被仓库级死锁挡住(required checks × born-red 集群,owner 决策中),与本 PR 质量无关。#4606 落地后 rebase 丢弃我的 CI 小修 commit、重触发,预期全绿。

@ranxianglei ranxianglei added bug Something isn't working dsh p2 scope/storage labels Oct 24, 2026
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

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

CI 自动修复车道(ci-worker-r1)判定:被指派的红已解决(继承性,修在分支上),残留红为已知继承项,分支无需再动

白话结论:这个 PR 自己的代码没问题——被转发的那条红(unused-exports)是 master 自带的遗留僵尸导出,本 PR diff 完全不碰那个文件。修复已在分支上(并行会话推了 43addbff4,与我独立推导出的最小修法逐字节相同),我在该 head 上逐项复核过。剩余 11 个 test 分片红同样是继承(master 测试预检 tripwire,一行真实用例都没跑),即 #4599 盘点第 2 条,#4606 在修。

八问

  1. 是什么问题:被指派的 unused-exports 报 src/agent/client-build-note.ts 导出了一个没人用的类型(ClientBuildCheck)。但本 PR diff 不触及该文件(两分支间该文件 diff 为 0 行),master tip 146b34f27 自身 CI(job 120993296611)以逐字节同一报错行失败——继承性红,不是本 PR 引入。
  2. 什么原因导致的:[PR] dsh lane: note in-session when running an unverified @deepseek-ai/dsh client build (soft, exact-match) #4545 落 master 时留下一个仅本文件内部使用的 type-only export,此前的一轮 de-export 清扫(4d34abf)漏了它;凡 rebase 过该 master 的 PR 都继承这条红。根因在 master 侧。
  3. 影响范围与严重程度:信号级(CI 检查矩阵失去信号),非用户功能问题;本 PR 自身功能(win32 READONLY index.db 打开失败命名 + OS 级拒绝下删掉 delete 建议)不受影响。
  4. 怎么修复的:一词修法——去掉 ClientBuildCheck 前导 export(checker 对 INTERNAL_ONLY 类的规定修法)。说明:我动手期间并行会话已先行推送同一修复 43addbff4;我核对两边 diff 逐字节一致后丢弃了自己的重复 commit,保留在途版本。新 head 上逐项复核:本地 unused-export gate: clean (6 waived)、tsc --noEmit 绿、tests/storage-cantopen-hint.test.ts 8/8;CI check-run 确认 head 43addbff4 的 unused-exports 已绿。
  5. 是否有回归问题:无。被去 export 的符号全仓零外部引用(grep 仅本文件内 5 处使用,且无 d.ts surface 依赖);纯可见性收窄,行为零变化。原 PR 本身只动日志措辞(PR 正文已按旧→新披露),无协议/配置/持久化/wire 变化。
  6. 是否破坏缓存:不涉及。
  7. 是否改了设计方向:没有。
  8. 是否引入了新的配置:没有。

残留红(继承,分支侧不再夹带):11 个 test 分片全部死在同一条预检自检行——process-spawning test files missing from LIVE_FILES in scripts/run-ci-tests.mjs: tests/issue3890-parent-gone-confirm-drain.test.ts(抽验 ubuntu-22 shard 1 日志 job 121019152639,报错行与 #4599 盘点第 2 条逐字一致,分片跑测试前即退出、零真实失败)。修复载体 = #4606 提交 2(Fixes #4604);#4606 合入后本分支 rebase(顺带丢弃重复的 de-export commit,其 commit message 已注明)重触发即全绿。按几行级小修纪律,不在本分支再叠一份重复登记。

收工判定:自动修复车道任务完成——指派红已解决并复核,残留红已判继承并在 #4599 有条目(floor 64 已记本 PR 状态)。分支就绪,等 #4606 合并 → rebase → 重触发。

@github-actions

Copy link
Copy Markdown
Contributor

📦 Merged Build Published

This merge to master was published as 0.0.918-master.ea5f125 (rolling master tag).

npm install -g billion-context@0.0.918-master.ea5f125  # 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working dsh p2 scope/storage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant