Releases: yamingmou/session-fork-core
Release list
v2.4.19 · 备份不再落错地方——每个入口都遵守你的设置
一句话
你设的备份目录,现在每个入口都遵守。
为什么值得升
说明文档里写着「备份默认落在你所用产品的目录里……想统一改到别处:设环境变量 FORK_BACKUP_DIR」。但有两处不遵守这条规则:
- 直接从 Python 调用时,备份会忽略你用的产品、一律写进 WorkBuddy 的目录 —— 文档承诺的「备份跟着产品走」在这种用法下不成立;
- 修复分支(
--fix)不认FORK_BACKUP_DIR,照旧写进固定位置。
如果你恰好用过其中任何一种,你的备份可能并不在你以为的地方。这一版起,所有会写备份的地方读的都是同一个设置:先看你设的 FORK_BACKUP_DIR,没设才按你所用产品的默认目录。
另外,如果你在 Python 里用这个库,它自报的版本号以前停在 0.1.0,与命令行 --version 对不上 —— 现在两者同源,不会再出现"两个地方报两个号"。
修了什么
--fix与直接从 Python 调用,写备份前都改为向你所用产品的适配器取目录。- 版本号收敛到单一来源:
import fork_core与fork --version报同一个值。 - 从源码构建时的打包脚本改用系统临时目录 —— 它以前固定用
/tmp,在原生 Windows 上会直接中断。 - 清掉一个从未被调用的备份函数与几处失效的导入。
你可以自己复核
- 版本号:按 tag 装一遍,两个地方应报同一个值 ——
pip install "git+https://github.com/yamingmou/session-fork-core.git@v2.4.19" fork --version python -c "import fork_core; print(fork_core.__version__)"
- 备份目录:把
FORK_BACKUP_DIR设到一个空目录,然后打一条分支、再修一次分支 —— 两次的备份都应落在你设的目录里,而默认目录不应新增文件。 - 真库体检:
python3 <技能目录>/scripts/create_branch.py --verify(无失败项;若有"需人工复核"项,通常是分支里记录了血缘关系,属正常)。
v2.4.18 · 说明文档只讲「你去的那条入口」——不再自相矛盾,也不再夹带内部术语
一句话
你(和你的 agent)读到的说明,现在只有一件事要说:每份文档只讲「你去的那条入口」。
为什么值得升
如果你是从技能市场装的这个技能,这一版替你修掉了一处会让人(和 agent)无所适从的地方。
以前那份说明里,紧挨着的两行给出了两套互斥的入口写法——一行说「下面的命令统一写成 WorkBuddy 形式」,下一行说「下面的命令统一写成 fork …(你已用 pip 装了本工具)」,还混着一条只在你没装 WorkBuddy 时才适用的安装命令。照着读的 agent 选哪条都可能踩空。
现在每份文档只保留它自己那一份说法。
另外,这份说明文档同时就是技能页的正文(在技能市场打开该技能时,页面「概述」显示的就是它)。以前它更像一份内部讲义——自称「执行契约」、写「给 AI 的执行规则」、列出内部验证等级、并复述我们的调试过程。这一版把这些清掉了:该有的规则一条没少,只是改用对读者说话的口吻。
修了什么
- 文档自相矛盾:文档源里的渠道标记有两处配对错误,导致「只在其他渠道适用」的两行留在了同一份文档里。现在标记成对,各渠道只保留自己那两行。
- 说明文档重写 71 处:去掉自我定位、内部术语、内部验证等级、过程叙述与版本考古。信息量与指令强度一字未减——硬规则(如「用户说了断点就必须用
--match/--line」)完整保留。 - 结构树补注:
tests/注明仅源码仓库有(安装包内不含该目录),避免读者按图索骥找不到。 - 新增构建期检查:渠道标记必须成对、且两渠道不交叉嵌套,否则构建中止——用它守住这类问题不再发生。
你可以自己复核
- 渠道自洽:在装回来的那份里执行
grep -nE "统一写成" SKILL.md—— 应当只剩一条(属于你所在渠道的那条),另一套说法不再出现。 - 不影响运行:本次只改文档与构建期检查,运行时代码零改动。
fork --version与fork --adapter <你的产品> --list照常工作即可。 - 我们这边的验证:双版本测试 11/11(Python 3.13.12 / 3.9.6)· 编译 · 产物与源一致性 · 真库体检无失败项(退出码 0)· 对外口径扫描全仓与两个渠道包 0 命中。
v2.4.17 · 措辞与命名整理(无功能变更)
一句话
措辞与命名整理,无功能变更:注释只陈述这个工具本身的技术依据,测试脚本改用更通用的命名。
为什么值得升
如果你不需要每个字都读一遍,这一版可以跳过——它不改变任何行为。
值得单独发一版,是因为源码注释与文档会随公开仓库和安装包一起发布,它们读起来应当只关于这个工具。
修了什么
- 6 个文件 18 处:去掉与本项目无关的引用,或换成本身可复用的技术判断(例:
(混用会看错位置,已有反例))。技术内容一字未删。 - 测试脚本
regress_fossils.py→regress_samples.py;配套的本地配置模板与忽略规则同步改名。
⚠️ 若你在用本地样本配置,需要把顶层键fossils改成samples(脚本读samples)。
你可以自己复核
python3 tests/regress_samples.py # 有本地样本配置时跑;没有会提示怎么启用
python3 scripts/build_skill.py --checkv2.4.15 · 体检不再「每打一条分支就常驻一条红」
一句话
fork --verify 以前会因为你正常用过某条分支(比如在里面写"我的父会话是谁")而永久报一条红,还告诉你"请修复后再发布"——这一版把要修的问题和看一眼就行的疑点分开了。
为什么值得升
--verify 是发布前的闸门。它原本只问一件事:"分支产物里还有源会话 id 吗?"——这问题本身没错,错在它分不清两种来源:引擎没改干净(真缺陷),和你自己在分支里记录了血缘(完全正常的内容)。两者在数据上同形。
后果是:只要你动过那条分支,闸门就常驻红。而闸门一旦总是红的,它就等于没有——真正的问题会被淹没在误报里,你和工具都会学会忽略它。
这一版把判据分层:
- 失败(拦截、退出码 1):引擎复制出来的那一段里有残留;
- 需复核(不拦、退出码 0):快照点之后你自己追加的内容里出现父会话 id——分项会写明有几处在正文、几处在工具输出或思维链。
修了什么
- 边界从"假设"变成"可核对":fork 时把复制出的前 N 行算一个哈希(
prefix_fp),随谱系一起存下(6 个产品后端全部落盘)。体检时重算比对,就能证明"这一段还是 fork 当时的原样"。⚠️ 旧分支没有这个指纹,体检会提示"无法证实前缀,建议重打该分支"——那是证据不足,不是错误。 - 一个坏行不再让整轮体检崩掉:以前遇到无法解析的行会整轮中断、其余检查全被跳过,而且报错还指向"检查器"而不是"哪一行坏了"。现在跳过它并点名行号,再按位置分档——落在复制区内 ⇒ 从严;在追加区 ⇒ 只提示复核。
- 前缀指纹改为只读前 N 行:真机最大的产物有 107MB,以前为了前几千行要把整份文件读进内存读两遍。
- 汇总项不再把自己算进"需复核"计数(真机上曾把 2 项报成 3 项)。
一句实话
这版放弃了一个硬拦形态:如果快照点被记小,那段被跳过的区域里藏着的真残留,就不再判"失败"。兜底有三条:① 创建期做整文件零残留硬校验(改写引擎出问题会在落位前就被拒);② 结构性 sessionId / session_id 残留检查完全不看边界;③ 前缀指纹能查出"边界之内被改动"。
我们一度加过一条更严的规则想补这个面("紧接快照点的若不是新 user 消息,就从严判失败"),最后没有采用:它挡不住那类形态里最现实的一种(快照点后就是 user 消息、正文里带父 id,照样落在追加区),却可能把合法内容判成失败——本机只有 WorkBuddy 有真实分支样本,其余 5 个后端的"追加首条是什么"没有证据。用一个挡不住问题、却可能误伤的新规则去换"看起来更严",不划算。
还有一处已知缺口(没解决,如实标出):结构性硬拦只认 sessionId / session_id。而 Codex 的会话 id 在 payload.thread_id、pi / OpenClaw 在 header.id(键名就叫 id,无法与消息级 id 按名字区分)。后果是偏漏检、不会误报——这些后端若在追加区出现"路由键=父 id",只会得到"需复核";复制区仍由不挑键名的字符串搜索兜住,那才是主拦截层。要不要升级为硬拦,请先按仓库里的普查脚本取证,不要凭字段名像不像就加(会凭空造出新的常驻红,正是本版要消灭的东西)。
你可以自己复核
fork --verify # 现在:无失败项 / N 项需复核 / 退出码 0想知道"有哪些键真的在承载会话 id"(上面的结论就是这么来的,只读):
python3 tools/routing-key-survey.py keys --projects ~/.workbuddy/projects
python3 tools/routing-key-survey.py branches --home ~CI 在 Linux / macOS / Windows 三平台跑全部测试。完整取舍记在 CHANGELOG。
v2.4.14 · Windows 从「跑第一条命令就崩」变成正常可用
一句话
这一版之前,Windows 用户装上它跑第一条命令就会崩——现在不会了。
为什么值得升
如果你在 Windows 上用,2.4.13 及更早的版本对你基本等于不可用:中文 Windows 的输出编码编不了提示里的 emoji,print 直接抛异常;而那行报错本身也含 emoji,于是二次崩——你只看到一行乱码和退出码 1,连"哪里错了"都看不出来。
比这个缺陷本身更值得说的,是它为什么能活到第 13 个版本:这个仓库此前全部只在 macOS 上人工测试。这类"只在目标平台才暴露"的问题,靠本机测试在结构上不可能被发现。所以这一版除了修它,还给仓库装上了三平台 CI(Linux / macOS / Windows)——每次改动都会在真 Windows 上跑一遍全部测试。这个修复本身就是它抓出来、并逐轮验证到底的——第一轮 CI 就把我第一版的修法否掉了(见下)。
修了什么
- Windows 输出:命令行入口起手把 stdout 固定为 UTF-8,仅当当前编码容纳不了中文/emoji 时(真控制台与已用 UTF-8 的终端不干预)。特意没有采用"把编不了的字符换成
?":在英文 Windows 下那会把全部中文变成问号,命令"成功"了、你读到的却是一屏?,比直接报错更难察觉。 - 技能说明:新增「平台差异」一节,给出 macOS/Linux/WSL 与原生 Windows 的命令对照,以及四条 Windows 实情——
python3在 Windows 上不保证存在(优先py -3)、python可能被 Microsoft Store 应用别名拦截、PowerShell 执行策略会拦住全局安装的命令行工具、WSL 与原生 Windows 的会话库互不共享。 - 技能声明:
requires.bins: ["python3"]的语义是"每一个都必须存在"——在 Windows 上会把技能误判为缺依赖。改为requires.anyBins(至少一个存在),这才是实际约束。 - Python 3.9:此前声称支持 3.9,但代码里用了 3.10 才有的写法 ⇒ 3.9 用户一 import 就报错。现在真的支持(已实测),而不是把声明改小。
- 构建:Windows 上此前无法构建(脚本自己打印的字符就会抛异常);产物换行符也固定为 LF,使跨平台构建结果可复现。
- 提示语里原本只写 macOS 的
⌘Q,现在同时给出 Windows 的做法(托盘图标退出后重开)。
你可以自己复核
Windows(本版的核心):
py -3 -m pip install --force-reinstall "git+https://github.com/yamingmou/session-fork-core.git@v2.4.14"
fork --list # 中文与 emoji 应正常显示;以前这条会以 UnicodeEncodeError 退出任意平台:
python3 tests/test_output_encoding.py # 编码回归(含负例:不加固时必须失败)
python3 scripts/build_skill.py --check # 技能说明与源一致仓库 CI 每次推送都会在 Linux / macOS / Windows 上跑全部测试;其中 Windows 那一路还额外验证「不设任何编码环境变量时也能正常输出」。
v2.4.13 · 修「说的和做的不一致」
一句话
这一版修的是"说的和做的不一致":--dry-run 到底写不写盘、权限声明缺不缺、英文读者有没有入口——把话说到与实现一致。
为什么值得升
--dry-run的说法此前自相矛盾:文档一处写它"零写入",另一处写它会写临时文件——实现取后者。照"零写入"理解去用,可能在一个禁止任何写入的环境里踩坑。现在三处统一说实话:不落位、不登记、不改源会话;会写一个临时文件用于磁盘字节校验,校验完清理(所以运行处需要写权限)。- 英文读者此前没有入口:技能说明里没有任何语言切换链接——英文使用者不知道还有英文版。现在顶部有了(指向英文与中文两版 README)。
- 权限声明从"只给人看"变成"也写给机器":补上
allowed-tools与metadata两个结构化字段。 - 副作用动作的提示更可靠:写文件、写索引、备份源会话、落位、回滚都会打印一行提示,且不会被静默开关关掉(只有非副作用提示可静音)。
修了什么
--dry-run的说明三处统一(含--help文本)。- 补
allowed-tools/metadata字段;每个模块头部加一行# role:文件地图(点明"本文件只是注册表 / 适配器,核心链路在engine.py")。 - 运行期提示新增"不可静音"档位,调用点铺到 备份 / 落位 / 回滚 / 写文件 / 写索引。
- 清掉文档与注释里会误导的权限相关字样(全网只剩一处真实调用)。
- 技能说明顶部加语言切换入口。
你可以自己复核
--dry-run的实际行为与提示(注意加不加FORK_QUIET的差别):
<入口> --session current --dry-run # 应打印 → 写入分支文件 / writing branch file: … 并给出 Verify : ✅ OK
FORK_QUIET=1 <入口> --session current --dry-run # 该提示**仍应显示**(副作用提示不可静音)--help里--dry-run的说明应与上面一致。- 8 个测试文件全通过;编译、构建一致性、真库体检、敏感信息扫描全部 0 残留。
完整变更记录见 CHANGELOG.md。
v2.4.12 · 按平台安全扫描整改:说清它动你哪些文件
一句话
这一版没有新功能——是我们"把自己说清楚":安装钉住版本、写明它到底动你哪些文件、修掉一处会让人做错操作的文档矛盾。
为什么值得升
- 以前照文档安装,今天和明天装到的可能不是一个东西:安装命令指向
main(一个会移动的分支)。本版改为钉住发布 tag —— 你装到的是你选定的那一版,可复现、可审计。 - 以前你(或任何评估这个工具的人)看不出它到底会动哪些文件:现在有「数据与权限边界」一节:读什么、写哪三处、明确不做什么(不联网、不上传、不读凭据、不提权、不装任何东西)。
- 文档里有一处会让人做错:
--fix在本技能与 OpenClaw 官方是两个不同的东西(一个是本技能的参数,一个是openclaw doctor --fix),此前两处混用,照文档操作可能在错的平台上跑错的命令。现已写明归属。 - 有副作用的动作开始"说话":创建分支文件、更新索引时,运行期会打印一行人类可读的提示,不再只有给开发者看的注释。
修了什么
- 安装 / 升级命令改用固定 tag;
chmod 444一律标注为给用户的建议(本技能不会代为修改文件权限)。 - 新增运行期用户可见提示(走 stderr;设
FORK_QUIET=1可静音)。 - 修掉文档末尾一处写死的版本号 —— 它此前停在 2.4.9,两版没跟上。
- ClawHub 上的简介改为英文:那个渠道的读者是 OpenClaw / agent 生态;SkillHub 与 WorkBuddy 开放平台仍用中文(中文简介保留在
description_zh)。
你可以自己复核
- 提示是否真的出现(同一命令,加不加
FORK_QUIET=1对比):
<入口> --session current --dry-run # 应打印 → 写入分支文件:…(新建,源会话不改动)
FORK_QUIET=1 <入口> --session current --dry-run # 该提示应当消失- 装到的是哪一版:
<入口> --version - 8 个测试文件全通过;编译、构建一致性、真库体检、敏感信息扫描全部 0 残留。
完整变更记录见 CHANGELOG.md。
v2.4.11 · 含被截断 emoji 的会话不再打不出分支
一句话
含"被截断 emoji"的会话,不再打不出分支。 以前这种会话打分支必失败,而报出来的错跟"消息里的字"看不出任何关系——一条看不见的坏字符,就能毁掉整次分叉。
为什么值得升
- 一个被截断的 emoji 就能毁掉整次分叉,而且报错完全指不到地方:会话里只要有一条消息的 emoji 从中间被截断(常见于从别处粘贴、或中间过了一道会截断文本的工具),那么无论这条会话多长、其余内容多正常,打分支都会直接失败,只抛一句
UnicodeEncodeError ... surrogates not allowed——既不说是第几行、也不说哪条消息。 - 修法不动你的内容:只把含该字符的那一行改用 JSON 转义形式写出,其余行一字不动。转义在 JSON 层是等价的,读回来仍是原来那个字符——不替换、不丢弃。
- 不是只修一个产品:6 个产品后端(WorkBuddy / Claude Code / Codex / pi / OpenClaw 的两种存储后端 / Hermes)的文件写出、数据库写入、索引写出三条路径全部覆盖。
修了什么
根因:写出产物时若遇到孤立代理(lone surrogate,即 emoji 的代理对被切开后留下的半个字符),直接以 UTF-8 编码写出会抛 UnicodeEncodeError,整份产物写不出来。现在改为:无法直接编码的那一行改用 JSON 转义写出,其余行保持原样。
实测(10 万行级真实会话):仅 1 行被转义,其余 19,194 行逐字符相同;序列化层净开销 +0.03 s(占整次分叉约 1%)。
有意不采用的两条路:surrogatepass(产物含非法 UTF-8 字节,宿主严格读会吞字)、backslashreplace(一旦再经一次序列化就退化成普通文本)。
诚实说明:这是我们自己没测到的一类数据
- 这个缺陷是用户实际踩到之后才定位的,不是我们自测发现的。此前的测试只覆盖"干净"的会话文本,没有一条用例包含这种被截断的字符——所以它一直是对的,也一直是绿的。
- 定位过程中还有一件值得写下来的事:修复代码自己一度把整包写挂——新函数的文档字符串里写到了这个字符的转义写法,被 Python 当成真的坏字符,导致整个包无法导入。是"编译 + 全量测试"当场拦下的。这条已经写进代码注释,防后人再踩。
你可以自己复核
对以前会失败的那条会话先预演(不写任何东西),应正常完成并打印 Verify : ✅ OK:
<入口> --session <id> --dry-run想确认产物没被"改内容":把分支里与源里同一条消息的文本比对,应当逐字相同。
本版新增针对性用例:含该字符的真实样本、孤高/孤低合成样本、合法 emoji 必须不被改写(防"修好一处、弄坏正常 emoji")、以及旧写法必须仍然报错(证明测到的是真问题,而不是空转)。8 个测试文件全通过。
完整变更记录见 CHANGELOG.md。
v2.4.10 · --session current 不再可能打到另一个对话
一句话
--session current 不再可能打到另一个对话:拿不到"你在哪个对话"的判据就明确报错,不猜。
为什么值得升
- 打分支不会再打到"别人的对话":
--session current现在只有两种结果——解析出你正在其中的那个对话,或者明确报错并告诉你该改用什么。不再有第三种:悄悄给你换一个看起来像的。 - 源会话名当场回显:输出新增
Source : <id> 「<会话名>」。此前只给 36 位十六进制 id,人根本看不出对不对;现在打完分支扫一眼名字就知道有没有打错。 - 旧行为没有删,只是不再冒充
current:确实想从"最近活跃的那个会话"打,用--session latest-working——名字终于说真话了。
修了什么
--session current 静默打到另一个对话(v2.4.5 起一直存在,2026-09-15 定位)。真实事故:同一个会话内 8 分钟两次完全同形态的命令,一次父会话是我正待在的那个对话(对),一次是另一个对话(错)——而两次输出都只给 36 位 id,人看不出差别。分版本:
| 版本 | current 的实际行为 |
|---|---|
| ≤ v2.4.6 | 一律取"库里最近一个 status='working' 的会话" |
| v2.4.7 / v2.4.8 | 同上——完全不看执行环境标识,并行开几个会话时必错 |
| v2.4.9 | 优先用执行环境标识;标识缺失或过期时仍回退到同一条 SQL ⇒ 本次事故就是这条支路 |
| v2.4.10 | 缺判据就报错,不猜 |
其余:
- 锚点预览不再打印系统注入块:
--dry-run里"锚定 Lxxx 的 user 消息「…」"此前取的是消息开头的字面量,而你发的消息首部常被系统塞入上下文块 ⇒ 打印出来是<system-reminder …>,你照样核对不出。现在取真正的人话。 --session latest-working补进--help,且不再被"这不像个 ID"的提示误伤。- 修掉文档里一个不存在的入口路径:WorkBuddy 版文档把长命令入口写死成
~/.workbuddy/skills/session-fork/scripts/create_branch.py,而实际安装目录可能带渠道后缀 ⇒ 照抄必报"找不到文件"。改为运行期取路径。 - 订正 v2.4.9 的变更说明:v2.4.9 里写着"标识过期则回退存储"——那句话把缺陷写成了特性,本次事故正是它描述的那个回退造成的。
你可以自己复核
在任意目录跑:
env -u CLAUDE_SESSION_ID -u CODEBUDDY_SESSION_ID -u BAGGAGE \
python3 scripts/create_branch.py --session current --dry-run
应报错并退出码 1,列出三条可用替代。旧版会静默挑一个会话继续——那就是事故现场。
其余验证:8 个测试文件全过(7 个适配器 + 本版新增的解析用例);负向验证确认排序用例真有拦截力;构建一致性、文档事实核验、敏感信息与写死路径扫描全部 0 残留。
⚠️ 如果你在用 v2.4.7 / v2.4.8 / v2.4.9
这三个版本的 --session current 可能打出另一个对话的分支,且输出只给 id、看不出来。建议升级;已打出的分支请核对 Source 行确认父会话是不是你要的那个。
v2.4.9 — 打分支从「上一轮结束」处岔开,切点可当场核对(含一处我们自查修掉的旧问题)
Warning
--session current 可能打出「另一个对话」的分支
--session current 的本义是"我正在其中的这个对话"。本版本会先读执行环境的会话标识,
但当标识缺失或过期时,会静默回退到"库里最近一个 status='working' 的会话"——
那不是你正在其中的对话。而当时输出只给 36 位十六进制 id、不给会话名,你无从核对。
真实事故:同一个会话内先后两次执行完全同形态的命令,一次打对本对话,一次打出了另一个对话的分支。
这个缺陷是用户肉眼发现的,不是我们的测试发现的——我们的测试里有一条把这个回退断言成了期望行为,所以一直全绿。
建议升级到 v2.4.10:
改为"缺判据就明确报错、不猜",并回显源会话名(Source : <id> 「<会话名>」)。
已用本版本打出的分支,请核对父会话是不是你要的那个。
打分支现在从「上一轮结束」处岔开 —— 而且切在哪,你能当场核对。
你在对话里说"打分支",新分支拿到的是上一轮为止的完整上下文:
"打分支"这句话本身、以及执行它时的过程(试跑、检查输出、脚本自己的回显)不会再跟着进新分支。
需要把当前内容连本轮一起带走时,--whole 一次性覆盖。
价值
- 分叉结果干净了:新分支从上一轮结束处岔开,只带走你真正想沿用的上下文——不再混入"打分支"这个动作自身产生的过程输出。
- 切在哪,你能当场核对:
--dry-run会打印走了哪种判定、锚在哪条消息、以及那条消息的原文(例如锚定 L14169 的 user 消息「Please continue with…」)。看一眼就知道切得对不对,不用信任。 - "整份复制"依然可用:需要把当前内容连本轮一起带走时,
--whole一次性覆盖。
实现
- 默认截断点分成两种语义,由执行环境自动判定(不再让"一种规则套所有场景"):
- 会话内打分支(脚本跑在被 fork 的那个会话里)→ 切在上一轮输出结束:最后一条 user 消息之前的最后一条完整 assistant 回复。
- 从外部执行(终端 / 定时任务 / 显式指定别家会话)→ 整份复制到末尾最后一条完整 assistant 回复。
- 适配器接口新增
running_session_id():报出"执行本脚本的进程处在哪个会话里"。默认实现读 Claude Code / WorkBuddy 系留在执行环境里的会话标识;无此信号的产品返回None,行为与旧版一致,需要时自行覆盖。 - 新增
--whole:在会话内强制"整份复制"。
修改
- 一处由我们自查发现并修掉的老问题:在"就在被分叉的那个会话里打分支"这一种用法下,新分支会多带上当前这一轮的内容;其他用法不受影响。
本版已修:会话内打分支改为切在上一轮输出结束,与"从外部执行"的整份复制分成两条明确语义——由执行环境自动判定,不需要你选。同时把文档里与之相符的旧表述一并订正。 --session current更准了:current的本义是"我正在其中的那个会话",原先靠存储里"最近一个活跃会话"去猜——并行会话 / 新开会话都会让它指错。现在优先用执行环境标识(并校验该会话确有记录,标识过期则回退存储,不拿它去撞"找不到")。
检查
- 此前两个真实分支现场用修复后的引擎复跑,切点均落到正确位置,且
--dry-run打印的锚点原文与人工核算一致。 - 6 个适配器测试全通过(
workbuddy/claude_code/codex/hermes/pi/openclaw×2 后端),其中workbuddy新增一组用例把上述两种用法钉成回归:整份语义 → L7 /会话内语义 → L2,以及退化情形(无 user 消息、单轮会话)明确退回整份。 - 基线回归(真实会话样本):用修复前的代码采基线、修复后再跑,4 条全部一致——证明"显式指定会话"这条路径逐字节零漂移,本版行为变更只发生在会话内的默认分支上。
- 你可以自己复核:在任意会话里跑
--dry-run,核对打印出的锚点行号与行原文,是不是"你说打分支"的那条消息。