Repository navigation
[PR] Add bili sessions orphan-sweep: remove provably-foreign collapsed blocks from upgraded sessions (D2, #5308) - #5334
ranxianglei wants to merge 4 commits into
Conversation
…WN_FINGERPRINT in LIFECYCLE.md (#4599) The lifecycle-ledger-guard job fails on every tree containing master since c8d7a80 (#4788 phase 2) and fc53fd4 (#4125): two BILI_* env vars read from src/ were never registered in LIFECYCLE.md, so every PR based on current master goes red within seconds (first observed on #5037). Backfill only, no code change: BILI_SESSION_CONTENT_STORE_PIN -> section 1 transition ledger (escape hatch for #4788 phase 2 idle-fold, default fold); BILI_SPAWN_FINGERPRINT -> section 2.2 internal spawn channel (#4125 spawner-side entry-script hash, launcher to child).
…(D2, #5308) A collapsed block committed under a shared conversation id during the <=v0.1.208 era reappears forever in the parent session after an upgrade: the #2695 e-gate exemption shelters it (never-present substrate never accrues a death streak) while the render side keeps it active on any covered-id collision. No wire-side path reaps it. Add a host-side maintenance sweep (bili sessions orphan-sweep [id] [--fix]) that flags blocks whose covered ids have ZERO overlap with their own session's unified-store transcript (active + retired rows) - provably foreign. Dry-run by default; --fix archives via a metadata-backed exclusion list that buildSession honors on load (reversible, no kstate rewrite). Legit folds always retain their covered rows, so they are never swept.
📦 Built Package ArtifactBranch: Latest build — install this exact versionnpm install -g billion-context@0.0.7472-pr.5334.2c0aa80This exact version is immutable and reproducible. The rolling Recent builds (commit → version)
Download artifact
tar xzf billion-context-pr5334.tgz
npm install -g packageInstall instructions are refreshed on each push. |
bili sessions orphan-sweep: remove provably-foreign collapsed blocks from upgraded sessions (D2, #5308)bili sessions orphan-sweep: remove provably-foreign collapsed blocks from upgraded sessions (D2, #5308)
(ai: vllm-qwen/qwen3.8-27b) 查重: 不重复 —— 本 PR 是 #5308-D2(#5095「孤儿块清理」第 2 项)的唯一实现;按失败签名与关键词检索 open+closed issue/PR,无并行工作。 标签: bug + scope/storage + p2(从原 p1 下调:这是 ≤v0.1.208 时代的有限存量污染,不是缓存泄露类只增不减的失控增长;受影响会话仍可用、有绕行,符合 p2 口径)+ 保留 pr。 中间状态(代码审核已完成,CI 红分账已完成):
修复合入后等 CI 重跑,再给最终八问结论。 |
…inding, OrphanSweepPlan) The two helper interfaces are only used inside src/orphan-sweep.ts; the module-boundary surface is detectOrphanBlocks/applyOrphanSweep/OrphanSweepResult. Self-introduced violation of the #2643-era gate on this PR branch (the other finding, CodexWindowSource, is inherited master red awaiting ci-fixes).
(ai: vllm-qwen/qwen3.8-27b) 最终结论(八问)
CI 现状与处置(head 29fde22 → 新 head 2d8f680 已推送):3 条静态门红 = 双树本地复跑分账——unused-exports 里 2 条本 PR 自带(OrphanBlockFinding/OrphanSweepPlan 无模块边界引用)已按门禁处方在分支修掉(commit 978ab77);lifecycle-ledger-guard 继承红已 merge ci-fixes@0371089db 转绿(本地 OK);docs-sync(#5319 ±"chat" 种子漂移)与 CodexWindowSource 两条继承红待哨兵收敛进 ci-fixes,已在 #4599 留言。test 矩阵此前因门红被 skip,尚无全量套件判定——等收敛后重跑即为终审证据(本地未跑全量,遵本地测试纪律)。 判定:代码本身审核通过、可合;当前被 2 条继承红阻塞,哨兵把 docs-sync 种子修复与 CodexWindowSource 收敛进 ci-fixes 后,分支再 merge 一次即可全绿合入。 |
What this fixes (D2 of #5095, tracked as #5308)
A collapsed block committed under a shared conversation id during the ≤v0.1.208 era reappears forever in the parent session after upgrading to ≥v0.1.209:
#2695zombie-reap exemption shelters it. A block whose covered substrate was never verified present on this session's wire keepse==0, so it never accrues a death streak and is never reaped (src/fold-reconcile.ts). That exemption exists exactly so healthy proxy-mode folds (whose covered ids are permanently replaced by the anchor and never reappear) are not reaped. A foreign block from the shared-id era has the same signature — "covered ids never on this session's wire" — so the same exemption gives it permanent shelter.kernel/src/sync.tsstillPresent) keeps the block active as long as any covered-id hash collides with the current request or its anchor is present — which happens readily when the parent and the dead child read the same files. So the foreign summary keeps being re-rendered into the parent transcript, polluting context indefinitely.h_hash (notacp_summary_bN), so no proxy-side stale-copy drop can remove it afterward. There is no automatic cleanup path for provably-foreign legacy blocks.Only upgraded sessions that lived through ≤v0.1.208 are affected (the lane split in #4774 / #5184 / #5163 means new foreign blocks can no longer be produced).
The fix — host-side sweep, option A (owner-pre-approved in #5095 / #5308)
New command
bili sessions orphan-sweep [id] [--fix] [--json]:--fixarchives.--fixrecords each swept block insession.metadata.orphanExcludedBlocks(blockId →{at, reason}) and persists it to the session'sindex.dbrow (advancingupdated_atso the write wins the full-mode load staleness guard).buildSessiondrops listed blocks on load. No kstate rewrite, no schema change — deleting the entry restores the block. Idempotent (already-excluded blocks are filtered out before detection).BILI_STORAGE_UNIFIED=full); in shadow/legacy mode it degrades to read-only reporting and refuses to perform ("cannot prove", never guess).This clears the b33-class stock. Option B (block carries creation-time conversation-key lineage — precise, no heuristic) is a kernel-boundary design item tracked separately: it needs a
kernel-changedeclaration + owner approval and is deliberately out of scope here.Config surface
New CLI subcommand (no new env var, no new config-file field):
bili sessions orphan-sweep [id] [--fix] [--json]bili sessions <sub>next torm/archive/restore, reusing the existing--fixperform-token convention frombili doctor --fix.--fix. Gated on full unified storage. Reversible.Placement note: the issue proposed this as "
bili doctor --fix孤儿块清扫". I placed it underbili sessionsbecause (a) it operates on individual sessions' blocks, matchingsessions rm/archive/restore; (b)doctor --fixcurrently means dsh-ledger repair specifically, and overloading it would blur semantics. Same capability, same--fixtoken, better home — trivial to move underdoctorif you prefer.Behavior change
None at runtime. The sweep runs only when explicitly invoked. The single load-path change —
buildSessionnow filters out blocks listed inmetadata.orphanExcludedBlocks— is a no-op fast path when that key is absent (the default for every existing session), so loading behavior for all current sessions is unchanged until an operator runsorphan-sweep --fix. Old→new:state: mergeState(parsed.state)→state: filterExcludedOrphanBlocks(mergeState(parsed.state), metadata?.orphanExcludedBlocks); identical output whenever the exclusion list is empty.Verification
tsc --noEmitclean on current master (rebased ontof6e69aee1; the intervening commits touchedkernel/, so a full rebuild + typecheck ran).tests/orphan-sweep.test.tsgreen against a real full-mode session: a zero-overlap block is flagged while an overlapping fold is not (both directions, Test Blind Spot Retrospective: Reinforcing Negative Assertion Discipline, Tightening Fake Upstream Strictness, Thin Inst | 测试盲区复盘:补反向断言纪律、假上游严格化、薄安装冒烟、形态矩阵与生命周期覆盖 #3617 gate discipline); dry-run is a no-op;--fixarchives only the foreign block; reload confirms the foreign block is gone and the legit one stays; idempotent; reversible.tests/compress-from-store.test.ts(thebuildSessionload path) still 4/4.Closes #5308
Related: #5095 (source, D1 closed) · #5184 / #5163 (D1 two-layer fix) · #2695 (e-gate origin) · #3640 (anchor parking) · #4774 (lane split)