Repository navigation
[PR] fix: link anonymous forks to their parent so skipped fold-inheritance heals across a restart - #3951
[PR] fix: link anonymous forks to their parent so skipped fold-inheritance heals across a restart#3951ranxianglei wants to merge 3 commits into
Conversation
📦 Built Package ArtifactBranch: Option A — Install this exact build (recommended)npm install -g [email protected]This exact version is immutable and reproducible. The rolling Option B — Download artifact
tar xzf billion-context-pr3951.tgz
npm install -g packageInstall instructions are refreshed on each push. |
… heals across a restart (#3925 -> #3011 C9) Proxy-mode anonymous forks ('new session from here' with no session id) were detected at the first request (prefix-affinity LCP >= 3, via='new', reason='forked') but only fed into maybeAdoptForkBlocks — which bails silently when forkAdoption is off (the default). No lineage metadata was recorded, so neither the startup sweep (reconcileDerivedLineage iterates derivedFromSessionId entries only) nor the read-time decompress/search_context parent walk could ever recover the lost block state. The child replayed the whole parent history (including the parent's compress tool calls), context re-inflated, and search_context reported 'no compressed blocks'. - record derivedFrom/derivedFromSessionId on every detected anonymous fork whose parent loads (memory or disk), before the outcome branches, and make it durable immediately (writeNow) like persistLineageLinkNow (#2986); a bili restart then lets the existing sweep inherit the parent's fully- present blocks, and read-time search/decompress fall back to the parent chain for free - on the disabled bail, persist a forkAdoptionSkipped marker {parentId, blocks, tok} and upgrade the log to warn so the degradation is visible - acp_status (no-scope views) prints one FORK ADOPTION SKIPPED line naming the parent, the block/tok counts and how to enable adoption; suppressed once the child has any active block; malformed markers are ignored - success path sets derivedBlocksAdopted = true (#3351 discipline) Behavior changes (old -> new): - anon fork children: no persistent lineage -> persistent parent link even when adoption is off (enables restart healing + read-time fallback) - bail log: info -> warn - acp_status: gains the conditional warning line (additive display) - success path: derivedBlocksAdopted now set (sweep skip already held via blocks > 0; marker keeps the gate consistent) The forkAdoption default itself is deliberately untouched here — flipping it is a product decision tracked in #3011. Refs #3925, #3011, #3025
… rename linked->justLinked Review pass on this PR found two small flaws: - The status line told users to 'set forkAdoption: true and restart', but the startup sweep is gated by resumeInheritance (on by default), NOT by forkAdoption — a plain restart already heals the session under defaults. Reworded: restart heals now; forkAdoption:true makes future forks adopt at first request instead of waiting for a restart. - linked -> justLinked in maybeAdoptForkBlocks: the old name read as 'already linked' while it means 'link just created'.
dbb1fb9 to
fe92959
Compare
(ai: vllm-qwen/qwen3.8-27b) 查重: 不重复。本 PR 是伞 issue #4266 第 ⑥ 项(proxy-lane 匿名 fork 零折叠)的缓解切片——#3025 清单里的 C9,复现 #3925(已按重复关闭并入 #3011)。与同家族其余在途 PR 机制正交、无重叠:#3024(409 快照)、#3039(CHILD_CONFLICT latch)、#4223(DSH native 入口诊断)、#4263(DashScope 溢出)、#4345(能力探测瞬态)。 标签: 审核结论: 可合并(人工审核 lane——§7.4 会话血缘逻辑,不走 auto-merge)。已 rebase 到当前 master 并补了一个 review 小修 commit(fe92959),详见下文。 结构化八问
行为变更披露(old → new)
审核操作记录
收工判定:可合并——机制正确、回归清单干净、测试双向钉住;待 CI 绿确认后由人合入(我不代合)。 |
(ai: vllm-qwen/qwen3.8-27b) CI 进度补报:新 head fe92959 上 9/10 条 lane 已绿(e2e-native-dsh / e2e-local-registry / e2e-native-opencode / e2e-fake-codex / e2e-native-pi / e2e-codex-persona / e2e-pi-codex-ws / e2e-dsh-plugin-lane / Windows codex overlay 全部 success)。主 |
CI unused-exports gate failed on this branch: ForkAdoptionSkipped was exported but never imported anywhere (tests reference it via ReturnType<typeof forkAdoptionSkippedOf>). Drop the leading export per the gate's INTERNAL_ONLY remedy. Verified locally: gate clean, typecheck clean, targeted suites 10/10.
(ai: vllm-qwen/qwen3.8-27b) CI 补报 ②:主 |
|
(ai: zhipuai-lb/glm-5.3) 已并入 #4590。关单收尾;误判请 reopen。 |
What & why
Proxy-mode anonymous forks ("new session from here" when the client sends no session id) are detected at the first request by prefix-affinity (LCP >= 3,
via:"new",reason:"forked") but were only fed intomaybeAdoptForkBlocks— which bails silently whenforkAdoptionis off (the default). No lineage metadata was recorded at all, so neither existing recovery path could ever see the fork:reconcileDerivedLineage) iterates sessions carryingmetadata.derivedFromSessionIdonly;decompress/search_contextparent walk follows the same field.Result: a child of a folded parent replayed the entire parent history (including the parent's own
compresstool calls), context re-inflated (the whole folded span showed up compressible again), andsearch_contextreported "no compressed blocks". It stayed broken across restarts too — after a restart the child's replay matches its OWN stored chain (via:"match"), so fork detection never re-fires. Repro + full evidence: #3925 (closed as duplicate of #3011; tracked there as checklist item C9 in #3025).Changes
writeNow(same rationale aspersistLineageLinkNow, [Bug] 血缘元数据落盘窗口:derivedFromSessionId 可能未持久化(非优雅退出/多实例覆写),kind 子会话永久孤儿 #2986). A bili restart then lets the EXISTING startup sweep inherit the parent's fully-present blocks, and read-time search/decompress fall back to the parent chain for free — no new search mechanism.forkAdoptionSkipped {parentId, blocks, tok}marker; log upgraded info -> warn.acp_status(no-scope views): one conditionalFORK ADOPTION SKIPPEDline naming the parent, the block/tok counts and how to enable adoption; suppressed once the child has any active block; malformed markers ignored.derivedBlocksAdopted = true(Forked child permanently loses block inheritance when its registered parent had no blocks at first contact (weak-link gate closes unconditionally) | 注册父会话在子会话首触时还没有折叠块,子会话将永久失去块继承(弱链接门无条件关闭) #3351 discipline — the gate closes only on real block adoption).Adoption semantics are unchanged: raw-id set intersection, no positional fuzzy matching, copy-on-fork deep copy. A mis-guessed parent (two chains sharing a 3-item prefix) can at most be searched read-only, never adopted from.
Behavior changes (old -> new)
derivedFromSessionIdwhenever the parent loads, even when adoption is offderivedBlocksAdopted = trueDeliberately NOT included
Flipping the
forkAdoptiondefault (the root cause of the report) is a product decision — options A/B/C are on the table in the #3011 thread for owner sign-off. This PR makes the off-by-default state diagnosable and self-healing instead of permanent and invisible.Testing
tests/fork-adoption.test.ts(new D2 assertions in both scenarios),tests/acp-status.test.ts(new negative / positive / malformed / suppression rows), plus adjacenttests/lineage-reconcile-boot.test.ts(boot-sweep AC9 intact) andtests/issue1333-derived-inheritance.test.ts— 23/23 pass; typecheck clean. Full suite = CI.Refs #3925 (duplicate of #3011), #3011, #3025 (C9). No config-surface change; no kernel change; touches session-lineage logic -> human review lane (AGENTS.md 7.4).