Skip to content

[PR] fix(storage): block interval bounds survive post-fold resaves (#4592) - #4607

Merged
ranxianglei merged 13 commits into
masterfrom
2026-10-25_block-bounds-preserve
Oct 25, 2026
Merged

ranxianglei merged 13 commits into
masterfrom
2026-10-25_block-bounds-preserve

Conversation

@ranxianglei

@ranxianglei ranxianglei commented Oct 24, 2026 •

Copy link
Copy Markdown
Owner

这是啥问题

折叠发生后,客户端下一轮重发的是折叠后的视图(不含已被覆盖的原文)。重入库时,当前批次解析不出这些 id 的 seq 区间(-1/-1 "未知"),旧逻辑的 upsert 会把之前已经解析好的真实区间抹掉。存储里块区间证据(#4335/#4346 落的 start_seq/end_seq)在每次折叠后的第一轮保存就退化回未知。

修复

  • src/storage/store.ts 两个块 upsert 的 ON CONFLICT DO UPDATE:start_seq/end_seq 改为 CASE WHEN excluded.≥0 THEN excluded ELSE 保留现值 END —— 区间证据一旦解析即持久,未知侧(-1)不再覆盖。
  • src/storage/mysql.ts twin(IF(VALUES(...) >= 0, ...) 同语义)。
  • ghost 覆盖(从未解析过)保持诚实缺口,不伪造区间。

验证

  • 新增 tests/storage-block-bounds-preserve.test.ts 2/2:①折叠后重存(批次不含 covered raws)区间保持 0..2(旧行为抹回 -1/-1);②ghost 保持未知。
  • 家族:storage-unified 14 / orphan-representable 1 / state-fields 2 / archive-gc 5 / full-flip 10 全绿;typecheck 0。
  • docker 狗粮端到端 6/6 ALL GREEN(真实构建服务端,插件+代理双车道):该 bug 就是在狗粮里被 proxy lane: fold lands and outbound is server-rendered 断言抓到的。

Closes #4608

@ranxianglei ranxianglei changed the title fix(storage): block interval bounds survive post-fold resaves (#4592) [PR] fix(storage): block interval bounds survive post-fold resaves (#4592) Oct 24, 2026
@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

📦 Built Package Artifact

Branch: 2026-10-25_block-bounds-preserve (dc37010)

Latest build — install this exact version

npm install -g [email protected]

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
dc37010 [email protected] build
6931798 [email protected] build
218871e [email protected] build
c560a2a [email protected] build
589314c [email protected] build
1e4a6e3 [email protected] build

Download artifact

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

Install instructions are refreshed on each push.

A post-fold client resend carries the folded view, not the covered raws,
so the next ingest batch re-derives -1/-1 'unknown' for the same block and
the upsert clobbered previously-resolved interval evidence. Bounds are now
durable: the upsert keeps the stored start_seq/end_seq whenever the
incoming side is unknown (sqlite CASE + mysql IF twin). Ghost coverage
never fabricates a resolved interval. Found end-to-end by the docker
dogfood harness (plugin + proxy lanes, real built server).
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

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

CI 修复(unused-exports)——继承性 master-red,已在分支上顺手修掉。

  1. 是什么问题:本 PR 的 unused-exports 门禁红,报 INTERNAL_ONLY src/agent/client-build-note.ts: ClientBuildCheck。
  2. 什么原因导致:不是本 PR 引入——是 master 自身的 born-red:[PR] dsh lane: note in-session when running an unverified @deepseek-ai/dsh client build (soft, exact-match) #4545 train(4863922)引入的 type-only 导出 ClientBuildCheck 零外部引用,且漏在 4d34abf 的去导出清扫之外(fix(ci): master unused-exports is red — ClientBuildCheck is exported but only used inside its own file #4602);CI 检查的是 PR×master 合并视图,所以每个 rebase 到 tip 的 PR 都继承这条红。
  3. 影响范围与严重程度:仅 CI 门禁面——master tip 上所有 PR 的 unused-exports job 必红,阻塞合入判定;运行时零影响(type-only、全仓无引用)。
  4. 怎么修复的:在本分支加一个独立标注 commit(c560a2a3b)去掉该类型别名前的 export(标识符在模块内仍可见),与 [PR] fix(ci): drop the unused export of ClientBuildCheck #4603/[PR] fix(pi): inline mode now intercepts codex Responses WebSocket traffic (#4526) #4559 分支的修法完全一致——按「宁可大家都修得一样也不要炸资源」纪律,在途 PR 里顺手重复修而非等 [PR] fix(ci): drop the unused export of ClientBuildCheck #4603 合入。
  5. 是否有回归问题:无。改动一行、纯去导出:全仓 grep 确认无任何外部 import;本地跑 node scripts/check-unused-exports.mjs → ✓ unused-export gate: clean (6 waived);不涉及任何行为/语义路径。
  6. 是否破坏缓存:不涉及。
  7. 是否改了设计方向:不涉及。
  8. 是否引入了新的配置:不涉及。

判定:修复已 push 到 PR 分支(head 现为 c560a2a3b),等 CI 重触发;本 PR 自身(storage 块区间保持)无需再动。master 侧的同名红由 #4603 收敛,已在 #4599 留了一行结论。

@ranxianglei ranxianglei added bug Something isn't working 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)

查重: 不重复 —— 本 PR 对应唯一机制 issue #4608(折叠后重存抹掉已解析的块区间边界);与 #4316/#4335/#4346(区间记账/来源)是上下游关系,非重复。无其他在途 PR 修同一问题。

标签: bug / scope/storage / p2(缺陷类;存储层——统一存储 blocks 表区间证据持久化;当前尚无消费方依赖区间证据做渲染分窗/重锚,不破坏现有可用性,故 p2 非 p1)。主题类别 E(存储层)。

⚠️ 先报一处引用错误:PR 正文写 Closes #4592,但 #4592 是「zcode风控问题」(zcode 405 报告),与本修复无关;真正的 issue 是 #4608(其 1L 明确写了「修复 PR:#4607」,commit message 也标的是 #4608)。按现状合并会误关无关的 zcode issue、而真正修好的 #4608 反而留开。按小问题直接修处理,我会在 PR 分支上把正文与 CHANGELOG 的引用改到 #4608。

正在走 review(方向/回归/代码/测试四个关),结论随后按八问体例给出。

ci-check added 2 commits October 25, 2026 02:13
… comments

Completes the label correction started in 218871e (which fixed the CHANGELOG
entry): the two explanatory comments on the interval-preserve upserts still
cited #4592 (an unrelated zcode risk-control issue); the correct issue is
#4608.
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

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

审查结论:代码可合入。CI 目前只被继承性 master 红(test 矩阵 LIVE_FILES tripwire,#4604)挡住,等 #4606 合入后 rebase/重触发即可。

结构化八问

  1. 是什么问题:折叠后第一轮重存时,存储里已解析好的块区间证据(start_seq/end_seq)被抹回未知(-1/-1),之后每轮都停留在未知状态。
  2. 什么原因导致的:折叠轮客户端重发的是折叠后视图(不含已覆盖原文),该批次解析不出 covered raws 的 seq 区间;旧 upsert 对已存在行无条件用本批次的值覆盖,未知(-1/-1)就把之前解析出的真实区间抹掉了。根因在 upsert 的冲突语义,不在解析侧。
  3. 影响范围与严重程度:所有发生折叠且后续有重存的统一存储会话;块区间证据([PR] #4316 Layer 3 (number directly mapped to canonical seq) PR 1/3: Fold-overwrite into real seq range | #4316 层3(编号直连正史 seq)PR 1/3:折叠覆盖写入真实 seq 区间 #4335/[PR] storage: seq ledger foundations — block interval bounds + ledgerSeq ref stamping (#4316 layer 3, phase 1) #4346 落的列)从第二轮起永久退化。当前这些列尚无决策型消费者(属证据面),所以是「证据质量退化 + 下游功能(渲染窗口化/重锚/fork 继承)的地基受损」,不是在线故障——p2 合理。docker 狗粮 e2e 的 proxy lane: fold lands and outbound is server-rendered 断言就是被它打红的。
  4. 怎么修复的:在写入决策点改冲突语义——两个后端(sqlite CASE WHEN excluded.>=0 … ELSE 保留现值 / mysql IF(VALUES(...) >= 0, …) 同语义)都让「未知不再覆盖已知」,新解析出的 ≥0 区间仍可正常更新;从未解析过的 ghost 块保持诚实缺口,不伪造区间。修的是产生缺陷的机制本身(疏),不是在读取端补猜。
  5. 是否有回归问题:审过 start_seq/end_seq 的全部 5 条写路径:store.ts 已有行 upsert(有意变更)、store.ts 新行 upsert(占位 [0,0] 行为不变)、store.ts 归档恢复 insBlock(ON CONFLICT DO NOTHING,从不更新,未触碰)、mysql.ts upsert(有意变更,twin 同语义)、mysql.ts 导入(INSERT IGNORE,从不更新,未触碰)。高危模式逐项过:无 fail-fast→吞错、无阈值/时序漂移、无输出格式变化;唯一语义变化即下述披露项。「保留旧值会不会保住过期区间」想过一轮:只有当批次解析失败(-1)时才保留,而上一批的真实证据永远比「未知」更接近事实;一旦某批重新解析出真实区间(≥0)会照常覆盖,不存在锁死。
  6. 是否破坏缓存:不涉及——前缀缓存、重试、增量游标、去重键均不受影响;改动只在存储层证据列的写回语义。
  7. 是否改了设计方向:没有。仍是统一存储 + ingest 规划器产计划、upsert 落库的老架构,只改了 ON CONFLICT 的取值规则;双后端一致性纪律保持。
  8. 是否引入新配置:无。

行为变更披露(旧值→新值):blocks.start_seq/end_seq 的持久化语义从「每轮按当次批次能解析到什么就写成什么(可回退到 -1/-1)」变为「单调证据:一旦解析出真实区间即持久,未知(-1)永不覆盖已知;新的 ≥0 证据仍正常刷新」。这是本 PR 的目的所在,但属于既有存储行为的有意变更,按规披露。

验证证据

  • 负控制(修法有效性):在未打补丁的 master worktree 里跑新增回归测试,测试①以症状原样失败({"start_seq":-1,"end_seq":-1}),测试②通过——测试有牙,不是恒真断言。
  • PR head 本地定向:新增 2 例 + storage-unified/orphan-representable/state-fields/archive-gc/full-flip 家族共 34 pass / 0 fail / 1 skip(mysql e2e 需 docker);typecheck 干净;unused-exports 门禁 clean(6 waived)。
  • 作者侧 docker 狗粮端到端 6/6 ALL GREEN(插件+代理双车道,真实构建服务端)——采信为作者报告。
  • 全量回归以 CI test 矩阵为准,见下。

顺手小修(已直接做,独立标注 commit)

CI 状态说明

判定:可合入——代码与测试层面闭环完整、方向正确;合并时机等 #4606 落地后 rebase/重触发,让 test 矩阵给出一次真信号再合。

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

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

CI 判定(attempt 2/2):11 个 test 分片全部是继承性 master-red,非本 PR 引入——不在分支内自修,等 #4606 合入。

  1. 是什么问题:新 head 6931798dd(在 c560a2a3b 之上叠的两个 docs 提交)push 后,11 个 test 分片(ubuntu/windows × node 22/24)全红。
  2. 什么原因导致:独立拉日志核实(run 40120471200,ubuntu-22 shard 1,job 120950754807,日志第 189 行):每个分片都死在 pretest 自检——process-spawning test files missing from LIVE_FILES in scripts/run-ci-tests.mjs: tests/issue3890-parent-gone-confirm-drain.test.ts,一行测试都没跑。这是 master 自身的 born-red([PR] merge: tier-5 train — dsh prepare/streaming domain (7 PRs: bili_final terminal marker, auto-fold storm gate, wire-only guard) #4590 train 新增的起子进程测试文件未登记进 LIVE_FILES,CI Control Center: Centralized CI Failure Handling & Status Sync (Comment all CI issues here; do not open new issues) | CI 总控: CI 失败集中处理与状态同步(所有 CI 问题在此评论, 勿开新 issue) #4599 盘点第 2 条),与本 PR 的 storage diff 无关;顶上两个新提交只改注释/changelog 引用,不触及任何测试路径。
  3. 影响范围与严重程度:所有基于 master tip 的 PR 检查矩阵信号失效(信号级问题);运行时零影响。
  4. 为什么不直接在分支里修:①修复已在 [PR] fix(ci): clear the two master-red gates in one branch — unused-exports (#4602) + the #3890 LIVE_FILES tripwire (#4604) #4606 提交 2 集中承载(Fixes fix(ci): every test shard is red — tests/issue3890-parent-gone-confirm-drain.test.ts spawns processes but is missing from LIVE_FILES #4604),PR 仍 open、master head 仍是 146b34f27;按「一个根因一个 PR」+ 本帖前轮先例(CI Control Center: Centralized CI Failure Handling & Status Sync (Comment all CI issues here; do not open new issues) | CI 总控: CI 失败集中处理与状态同步(所有 CI 问题在此评论, 勿开新 issue) #4599 对 [PR] fix(storage): block interval bounds survive post-fold resaves (#4592) #4607 的同签名结论),不夹带重复 commit;②更关键——即使登记了 tripwire,分片会开始真跑测试,而按哨兵盘点还有约 35 个跨 12 文件的 born-red 用例(kernel/storage/快照渲染敏感面)会显形转红,单修 tripwire 换不来绿,那批需按机制逐个 triage,超出 auto-fix 车道的权限与范围。
  5. 是否有回归问题:本轮未引入任何代码改动(上一轮 de-export 已验证零引用、门禁 clean;两个 docs 提交纯注释)。
  6. 是否破坏缓存:不涉及。
  7. 是否改了设计方向:不涉及。
  8. 是否引入了新的配置:不涉及。

判定/下一步:auto-fix 到此为止(2/2 用尽)。转绿路径 = owner 合并 #4606 → 本分支 rebase 到 master(遇与 #4606 提交 1 重复的 ClientBuildCheck de-export commit 直接丢弃)→ 重触发;born-red 集群由 #4599 总控清单另行跟踪。

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

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

收工摘要(完整审查结论见上方八问回复,此处只报最终状态):

无其他待办;等 #4606 合入后 rebase 重触发即可给出真信号供合并。

ranxianglei pushed a commit that referenced this pull request Oct 24, 2026
…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.
Zhishulo and others added 5 commits October 25, 2026 09:35
…est (master born-red, #4599 sentinel)

The tier-5 train added generationBoundaryActive as injectSystem's 9th parameter
and updated every caller except this test's 'active' case: its trailing true
landed in mcpDialectNote, so the note never appeared and the assertion must fail.
Identical one-line fix already committed on PR #4559's branch (e82ccd7); drop
that commit when rebasing whichever way merges first.
…s site (#4598, #4599 sentinel)

pages.yml has failed 75/75 runs since landing: actions/configure-pages@v5 gets
'Get Pages site failed ... Not Found' because GitHub Pages was never enabled on
this repo (the earlier enablement:true attempt was reverted without a recorded
reason — not re-applied here). Stop-the-bleed per #4598 option 1: drop the push
trigger, keep manual workflow_dispatch so the deploy path stays intact and no
website push red-lines master again. Final direction (re-enable Pages vs retire
the workflow vs in-install serving) awaits owner decision.
…ne-rewrite (#4599 sentinel)

The #3719 Updates tab stayed routed (PAGES/route/loadUpdates in client.ts)
but its topbar anchor was dropped when #3536 rewrote the whole topbar line,
making nav.updates a dead catalog key (web-i18n born-red on every PR head).
Restored at the original position (after logs); identical to the sibling fix
on the panel-blog branch (900c09c), adapted to master (no blog anchor yet).
ci-check added 4 commits October 25, 2026 09:58
…4427 Windows red, #4599 sentinel)

maskPathsForPublish keyed off os.homedir() alone. On Windows that reads
%USERPROFILE% while git-bash-style tool output carries $HOME paths, so the
publish-boundary identity leak masked one spelling and leaked the other
(#4427 suite red on windows shards only). Now masks the deduped set of
os.homedir() + $HOME + %USERPROFILE%; POSIX behavior unchanged (values
dedupe to one root), anchored-flank semantics preserved.
… restamp flag (#4599 sentinel)

Deliberate persisted-state change: 380ef4d (#4316 layer 3 PR3/3) added the
one-time refLedgerAligned boolean to session state. All four wire digests are
UNCHANGED; only the metadata section digest moved (+refLedgerAligned state
key). Regen per the suite's own protocol (justification recorded here and in
the ci-fixes PR body).
…wed-load interface (#4599 sentinel)

#D5-5 changed buildView to call store.unifiedMessageIdRows() +
store.unifiedUncoveredRows(id, intervals) first; the pre-existing fake stores
(only unifiedTailSeqs/unifiedTailViewRows) threw TypeError, caught by the
by-design degrade net as transcript-error, turning every render-expecting
assertion red (chain 6/6, verif replay). Extended both real-JS fakes and the
symbolic harness portImpls (__method_unifiedMessageIdRows /
__method_unifiedUncoveredRows) to mirror SessionStore semantics.
@ranxianglei
ranxianglei merged commit 64fc732 into master Oct 25, 2026
39 of 49 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

📦 Merged Build Published

This merge to master was published as 0.0.828-master.64fc732 (rolling master tag).

npm install -g [email protected]  # 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 p2 scope/storage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Post-fold resaves erase resolved block interval bounds | 折叠后重存会把已解析的块区间边界抹回未知(-1/-1)

2 participants