Skip to content

fix: persona-lineage follow requires candidates to hold refs (#2948) - #2950

Merged
ranxianglei merged 1 commit into
masterfrom
2026-10-13_persona-lineage-ref-guard
Oct 17, 2026
Merged

ranxianglei merged 1 commit into
masterfrom
2026-10-13_persona-lineage-ref-guard

Conversation

@ranxianglei

Copy link
Copy Markdown
Owner

Closes #2948

问题

livePersonaDescendant(#2719,v0.1.193 起)按「新鲜度 + 流量」选择重定向目标,不检查目标是否持有 refs。DSH auto-review 插件在每个工具调用前发固定 system(REVIEW_POLICY)+ 新扁平 blob 的 aux 请求 → 永久新鲜的 |sub:<fp> aux lane(生产会话 1574 次请求、ref 注册表恒空)。宿主盖章的管理调用(compress/decompress/acp_status)被重定向过去后全部 every ref is unknown to this session(highest ref=none)——手动压缩整会话失效,而自动折叠仍在父 lane 正常工作(静默失败)。

版本二分证据(issue 正文):同会话 0.1.192 三次 outcome=applied 成功;0.1.195(首个含 livePersonaDescendant 的版本)起 13 次 highest ref=none,全部伴随重定向日志行。

#2942/#2944 修的是 fork 成因(身份层),不触及本条的路由机制:personaDescendantsOf 的前缀匹配对任何 |sub: key 形状(|sub:<fp> / 未来的 |sub:aux)同样命中。

修法

personaDescendantsOf(src/plugin.ts)候选过滤增加一条:候选必须持有可用 refs(state.messageRefs.byRef 非空,house idiom 同 stream.ts compressibleSpanHint)。管理调用只能由拥有 ref 空间的会话服务——空注册表的 lane 无论多新鲜都服务不了任何一次 compress/decompress/acp_status。在候选层过滤(而非选中后拒绝)保证先滤后选:持 refs 的兄弟 lane 仍胜过更新的无 refs aux lane,#2601 的合法 follow 语义完整保留。

witness 路径(personaLineageWitness)不动:witness 是出站工具调用的铸造证据,天然指向持有该 ref 空间的会话。

行为变更披露

宿主盖章管理调用的重定向候选集收窄:新鲜但零 refs 的 |sub: 后代不再被跟随(修复前这类目标必然导致每次管理调用失败)。唯一被改变的行为就是缺陷本身;有 refs 的后代路由行为字节不变(#2601 套件全绿)。

测试

新 tests/issue2948-aux-lane-lineage-guard.test.ts(hermetic rig,真 proxy):

  1. 事故形状:父 lane 持 refs + 无 refs aux lane(流量 1574、lastSeen 更新)→ nativeCaller 调用留在父 lane,不出现 |sub:;
  2. 防过度修正:真实 fork(断链 model switch,持 refs)+ 比它更新的无 refs aux lane → 仍跟随持 refs 的 fork(filter-then-pick 钉死)。

本地验证:两测试在 pre-fix 代码上均失败(stash 实证)、post-fix 通过;typecheck 干净;定向套件 54/54 绿(新 2 + #2601×2 全量 + dsh-persona-fingerprint/continuity + side-lane-invariants/truth-table + dsh-title-side-lane + issue2817-crosswire)。全局回归交 CI。

livePersonaDescendant selected its target on freshness + traffic alone, so host-stamped management calls (compress/decompress/acp_status) were redirected onto ref-less aux lanes — dsh auto-review blobs fork onto their own |sub: lane and carry perpetual traffic without ever rendering the main conversation. Every redirected compress then died with 'every ref is unknown to this session' (highest ref=none) while auto-fold kept working on the parent: manual compression dead for the whole conversation, silently.

personaDescendantsOf now filters candidates on non-empty state.messageRefs.byRef. A ref-holding sibling still wins over a fresher ref-less one (filter-then-pick), so the intended #2601 follow is preserved. New hermetic suite pins both directions and fails on the pre-fix code.
@github-actions

Copy link
Copy Markdown
Contributor

📦 Built Package Artifact

Branch: 2026-10-13_persona-lineage-ref-guard (aaafd26)

Option A — Install this exact build (recommended)

npm install -g billion-context@0.0.3325-pr.2950.939a9cb

This exact version is immutable and reproducible. The rolling pr tag tracks the newest test build across all PRs.

Option B — Download artifact

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

Install instructions are refreshed on each push.

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

PR #2950 审查结论(fix: persona-lineage follow requires candidates to hold refs)

审查对象:完整 diff(src/plugin.ts 一处候选谓词 + 新测试文件 200 行)、调用点链、类型形状、既有行为清点、master 漂移、本地定向验证。

① 是什么问题:livePersonaDescendant(#2719)按「新鲜度 + 流量」选重定向目标,不检查目标是否持有 refs。DSH auto-review 的 aux lane(|sub:<fp>,固定 system + 每工具调用前新 blob)永久新鲜、流量大(生产 1574 次请求)、ref 注册表恒空——宿主盖章的管理调用(compress/decompress/acp_status)被重定向过去后全部 every ref is unknown to this session(highest ref=none),手动压缩整会话静默失效,而自动折叠在父 lane 照常工作。

② 什么原因导致的:路由层(会话选择)的候选谓词缺一条必要条件——「能服务这次调用」。aux lane 的存在本身合法(身份层,#2942/#2944 已修 fork 成因),但「新鲜度 + 流量」只是流量代理指标,不能替代「持有 ref 空间」这一硬条件;前缀匹配对任何 |sub: key 形状同样命中,所以路由机制与 fork 成因修复互不覆盖。

③ 影响范围与严重程度:dsh 宿主开 auto-review 的场景(以及任何未来复用同一 id 发高频固定-system side 请求的宿主);触发条件 = 管理调用落在「无 refs 后代 lane 比父 lane 更新鲜」的窗口内。严重度:手动压缩完全不可用(非部分降级),且为静默失败——自动折叠继续工作,用户直到手动压缩才发现。版本二分实锤(0.1.192 ×3 applied vs 0.1.195 ×13 highest-ref=none)。

④ 怎么修复的:在 personaDescendantsOf(src/plugin.ts)候选过滤处加一条合取 holdsRefs(s)(state.messageRefs.byRef 非空)——先滤后选,而非选中后拒绝。机制层面:管理调用只能由拥有该会话 ref 空间的会话服务,这是候选资格而非排序偏好,所以放在谓词层才能保住 #2601 语义(持 refs 的兄弟 lane 仍胜过更新的无 refs aux lane)。witness 路径(personaLineageWitness)刻意不动:witness 是出站工具调用的铸造证据,天然指向持有该 ref 空间的会话——我逐行核对了该函数,确认零改动。

⑤ 是否有回归问题:无。逐项清点过既有行为:

⑥ 是否破坏缓存:不涉及。纯路由决策的候选集收窄,不触及前缀缓存、重试策略、增量游标、去重键。

⑦ 是否改了设计方向:不改。仍是「跟随 lineage」,只是给候选集补上缺失的必要条件(必须能服务管理调用)——是补全机制的完备性,不是转向。

⑧ 是否引入新配置:不涉及。无新 env/config/默认值。

本地验证(定向,符合本地测试纪律):

CI:静态门禁全绿(kernel-guard / pi-subagents-guard / build-artifact 等 15/19),test 矩阵 4 job(ubuntu/windows × node 22/24)进行中(17:39 UTC 起,暂无失败)。

结论:可合并。 修法打在根因上(路由候选谓词缺硬条件),范围最小(一个谓词 + 文档注释 + 一个测试文件),唯一被改变的行为就是缺陷本身且已披露,测试有牙。待 CI 全绿即可合。

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

补充:CI 已全绿——19/19 check runs success(含 ubuntu/windows × node 22/24 四个 test 矩阵 job,17:50 UTC 完成)。审查结论维持不变:可合并,等待人工 merge。

@ranxianglei

Copy link
Copy Markdown
Owner Author

Merge-decision note (from the #2948 thread): a THIRD independent reproduction just landed on the LATEST release v0.1.196 (d64139f9c, release PR #2962) — no released tag contains this fix (aaafd26dc lives only on this PR branch), so the continued repro is expected and confirms the gap.

Its session-store forensics add one implementation-level confirmation for this PR: the aux lane carries 68–87 BLOCKED entries in state.messageRefs.byRaw while byRef stays at 0. Any byRaw-based "holds some ref record" guard would have missed that lane; this PR's byRef-only check is the sharp criterion (blocked entries are unusable for compress/decompress by construction).

The reporter's same-direction local dist patch validated end-to-end in their environment: 0 redirects after, compress recovered (5 blocks, ~332K tokens saved). Details in #2948.

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

收到,这条补充证据与我的审查结论互相印证,三点确认:

  1. byRef 判据的现场实锤:会话存储取证(aux lane byRaw 有 68–87 条 BLOCKED、byRef 恒 0)与我在代码层的核对一致——blocked 消息只以 BLOCKED_REF 写入 byRaw,从不进 byRef(src/plugin.ts:1238-1240)。因此任何基于 byRaw「有记录就算持有」的守卫都会把这类 aux lane 误判为可服务目标;本 PR 的 byRef-only 检查正是排掉这一误判的锐利判据。修法正确性又多了一层生产数据背书。
  2. v0.1.196 上的第三次复现属预期:aaafd26dc 只存在于本 PR 分支,没有任何已发布 tag 含此修复——继续复现恰好证明缺口仍在,不构成对本 PR 的反证。
  3. 状态不变:审查通过(八问结论见上一条回复)、本地定向验证 54/54 + 测试牙齿独立复验、CI 19/19 全绿。等待人工合并;合并后随下一个版本发布(发版需要你批准,批准后我来切 release PR)。

@github-actions

Copy link
Copy Markdown
Contributor

📦 Merged Build Published

This merge to master was published as 0.0.548-master.5de1219 (rolling master tag).

npm install -g billion-context@0.0.548-master.5de1219  # 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

None yet

Projects

None yet

1 participant