- 变更规模:新增 514 / 修改 62 / 重命名 155 / 删除 4(归档重组与文档轮次) - .gitignore 修:`归档/**/db-cwd归一-备份-*/` —— 原规则写绝对层级(归档/db-cwd归一-…), 目录搬进 归档/配置与备份/ 后**静默失效**,43 MB 的 DB 备份又变成未跟踪 - .gitignore 补:嵌套 git 内部数据(归档/内嵌git-20261008/、归档/skills-git-旧线-20261007/dotgit-原样移出/) - .gitignore 补:运行态与部署副本(.workbuddy/collab/、.workbuddy/tools/、.workbuddy/.load-pending、.workbuddy/tmp-*) - .gitignore 补:备份件(*.bak-*) - 未跟踪文件从 2190 降到 890(其余为 归档/ 归档件与 .workbuddy/memory/ 知识文件,按口径入库)
47 KiB
接续包 · 会话机制合并技能包(任务 2/3/4 + 归档)— 2026-10-01
§0 状态(最新行在最上)
时间 会话 发生了什么 2026-10-01 20:0x–20:1x 会话协作看板调整与自检-20261001(机制层 ⇒ 全局独占锁)✅ ① 看板按最新架构调整(常驻口径回归): assets/board.html/scripts/board.py/scripts/board_ext.py三处把 09-30 的「钩子按需唤起/跑完即退/不是常驻进程/没有启动-停止这回事」全部改回 常驻投递 口径(用户 10-01 定案「协作与投递一直运行(常驻)」+「定时任务的方案已经废弃了」);prog_by不再猜调用方(戳上分不出常驻还是钩子)⇒ 只报轮次名;帮助文本补 四类会话 + 接续=形态。⚠️ 易漏点:看板扩展件不是从包里读的(board.py按配置读<工作区>/.workbuddy/collab/board_ext.py)⇒ 只改包内不生效,已cp同步、两份 md5 一致;board.html相反、由包内提供即生效。
✅ 三步验证全绿:语法 / 渲染桩 FAIL 0/45(双目标样本 0/48)/ 几何 FAIL 0/7。
✅ ② 用协作机制跑「检查会话协作是否运行正常」(goalctl declare⇒collabd --once⇒--tick):结论=机械部分可用、投递链不通。可用:两轮rc=0、目标/类别接线正确、digest/queue/TO-MAIN 都能生成、整包自测 PASS 39/FAIL 0。不通:--tick判deliver=target-deaf(登记主会话f8a792ab-…不响应;投递台账最后一条 08:55 ⇒ 停了 ~11 小时)|常驻投递未拉起(--supervise没跑、guard.stop挂着)|声明目标 ≠ 产生工作(队列 0 件、digest「没有可派的任务」)|台账不随目标切换(新目标下仍反馈旧类别的 M5/M6/M7,关键路径写「M5 → M6」)|验收判据不绑目标(declare换名时旧判据原样留着 ⇒ 新目标一声明就被判"全过",实测 20:09)。
✅ 顺手修掉 4 个真缺陷:①preflight-lock.sh未登记技能包 ⇒ 改技能包一律误判【D】未归类、提示"先定域"(正解是"独占")⇒ 改技能包开不了工(本轮开工即撞)⇒ 补'\.workbuddy/skills/'(包内+库内两处同源,bash -n均过、行尾各保持);②goalctl.py工作区按__file__推层级 ⇒ 不带环境变量静默指向…/.workbuddy/skills⇒ 改DSH_COLLAB_WS→DSH_WS_ROOT→cwd,落空才回落并醒目告警;③ 同文件加静默陷阱告警(换目标名不给--kpi⇒ 提示旧判据会留下);④state.py抢锁路径提示scripts/不存在(实际07-scripts/)。
🔴 途中揪出并修掉 1 个真缺陷:tmp/render-check.mjs的BOARD还指向已退役已归档的skills/multi-session-collab/⇒ 唯一的看板回归工具一跑就崩。⚠️ 结构性遗留(未动):看板回归工具住在tmp/(按规矩要清的草稿区)⇒ 清掉后"改完看板怎么验"这条路就断了。
⚠️ 一处自伤已修正:board_ext.py文案里嵌了 ASCII 双引号 ⇒ 截断字符串 ⇒--manifest报语法失败 1(⚠️ 而--verify仍全绿 —— 覆盖面不同,--manifest才是语法闸)。
✅ 验收:--manifest34 文件 / 0 失败|--verify全绿|board_ext.py/goalctl.py包内与工作区副本 md5 一致|项目配置_默认形态已同步四类口径。✅ 锁:机制层 ⇒ 不带--domains独占,收尾走dsh.py close反序释放。⚠️ 仍未做:常驻投递未拉起、主会话仍target-deaf、8788 看板未起。2026-10-01 19:5x 会话类别口径修正-20261001(机制层 ⇒ 全局独占锁)🔴 用户订正会话类别口径(本轮唯一依据):「接续会话 不是单独的一类会话,是这几类会话到达阈值时 创建的接续会话,这里的第4类应该是 队列上报的跟进会话(之前考虑只让主会话管目标和方向,队列上报的会话 让专门的 跟进会话处理)」⇒ 订正了我上一轮(19:1x)的错答(我答"四类=主/协作/唤醒/接续",把"接续"当成第 4 类了)。
🔴 正确口径:四类 = ① 主会话 ② 协作会话 ③ 唤醒会话 ④「队列上报的跟进会话」;「接续会话」是「形态」、⛔ 不是第 5 类 —— 任一类撞阈值时由它自己建出下一棒,角色继承被接续的那条(主会话的接续仍是主会话候选)。
✅ 一次改齐(⛔ 不许只改一半):architecture.md(结论表两行/§2.3 第1级角色改四类含[跟进]/§2.3.0b ② 换标题+定性块/🆕 新增 §2.3.0c 第④类/「需求内闭环」作废框/§9 补 ⑦)·pitfalls.md(🆕 P0-11)·collab.md §4(三"角色"→四"类别")·collab-detail.md(三处:命名前缀/第四形态/§12「主体」vs「会话类别」两轴消歧)·SKILL.md(description+ §2 铁律两条 +last_change)· 项目MEMORY.md对应行(⚠️ 原已 7,956 字符超上限 ⇒ 同步压缩三处、净 -4,守住「只减不增」)。
🔴 两处判据缺口只登记、⛔ 未擅自改(触碰"用户定案"域,须先拍板):① 解析器把「接续」一律判 worker ⇒ 主会话的接续被吞掉(⚠️ 当初这么做是为堵自指死结 ⇒ 正解不是"改成未知",那会重新打开死结);② 第④类[跟进]全库零命中(落地清单已写进 §2.3.0c)。
🔴 实测(⛔ 别用假读数):不带COLLABD_CONFIG直接 import ⇒cand=0="没配置",⛔ 不是"逻辑坏了";带COLLABD_CONFIG=<工作区>/.workbuddy/collab/collabd.config.json复跑 ⇒ 8 条会话全role=worker、cand=0,resolve_main → {"sid":"","source":"no-register"}⇒ 主会话候选 0。⚠️ 「自测全绿 ⇒ 判据没问题」是错的:那条用例只喂合成样本。
✅ 验收:--manifest34 文件 / 0 失败|--verify全绿(10 条接线rc=0/collabd --where指包内 / selftest PASS 39 / FAIL 0)|manifest.md行尾 CRLF / 0 裸 LF、表内 34 行、磁盘缺失 0。✅ 锁:已--release-exec "会话类别口径修正-20261001"释放。2026-10-01 19:0x 常驻定案统一-20261001(同一会话续棒 · 收尾)✅ 补完最后一处盘符清零: scripts/lock/preflight-lock.sh+scripts/hooks/lock-guard-hook.py(技能包与文档库07-scripts/各一份)。🔴 结论:两份「有意不一致」,⛔ 别当 bug 修平 —— 判据是位置:包内那份住在技能包里、推不出文档库根 ⇒ 走roots.env+(lock-guard-hook.py的)末位字面量兜底;库内那份住在<文档库>/07-scripts/⇒ 按__file__上溯两级即文档库根(已改,库内自此零盘符)。已写进manifest.md做永久说明;规范化行尾后difflib比对确认唯一差异就是引导块,py_compile/bash -n均过。
✅ 固化install.py --manifest(本轮为"重算逐文件表"又手搓了一次一次性脚本,上轮也是)—— 只重写表 + 计数行 + 重算时间,⛔ 不碰上方散文;行尾随原文件(本表是 CRLF,写成 LF 会造成无声的全文件 diff;实测保持 81 CRLF / 0 裸 LF)。
🔴 顺手揪出并修掉一个「静默假绿」:scripts/selftest.py:617的t_tick_wired用例写死了项目绝对路径(<某工作区>/.workbuddy/tools/wb-result-hook.py)—— 既违反用户本轮规则,又因宿主接线已改指包内而恒走"文件不在,跳过" ⇒ 看着绿、其实什么都没验;已改按包内相对路径取hooks/wb-result-hook.py,该用例从"跳过"变真检(4 项实跑通过)。
✅ 重算 + 复验:--manifest34 文件 / 语法失败 0|--verify全绿(10 条接线rc=0/collabd --where/ selftest PASS 39 / FAIL 0)|包内无tmp/、无__pycache__(证实缺陷 ① 的修法真生效)。
🔴 两条如实登记的遗留:①<工作区>/.workbuddy/tools/wb-result-hook.py是陈旧死件(35,975 B vs 包内 37,837 B;宿主三条接线实测全指包内)——按"未经确认不删他人文件"留在原地,登记为 P2 清理候选;② 一把陈旧域锁属[协作]N9复测-2248(09-29 22:48,域ai1net-dsh-anywhere)——--release-exec回显「另有 1 把锁属他人,按 R9 未动」,只能由持有者本人释放。
✅ 锁:因本轮属机制层故按规矩不带--domains独占(故无域锁目录);已--release-exec "常驻定案统一-20261001"释放,回显「✓ 已释放全局执行锁」,.exec-lock已消失。⚠️ 仍未起常驻投递(--supervise未拉),guard自 09-29 23:59 停着,8788 看板未运行 —— 阻滞项是"四道闸门不全(无NEXT.md)",⛔ 非本轮改动引入。2026-10-01 18:5x 常驻定案统一-20261001✅ 常驻定案已全量传导(用户原话:「协作与投递一直运行(常驻) 因为可能不是所有 队列都是钩子产生的 ,而且定时任务的方案已经废弃了」)—— 改 architecture.md(结论表 + §2⑤ + §3 + §4 抬头 + §4.0/§4.1 作废框 + §5-1 + §8 + §9 新增教训)、collab.md§3/§8、deploy.md(结论表 + §0 + §2 步骤 ③④⑤ + 验收 6/7 + §5 重写)、rules.md§6、pitfalls.mdP0-3、collab-detail.md头部作废横幅、SKILL.md铁律、项目层CODEBUDDY.md §1.5 D/E与MEMORY.md。
✅ 按用户新规则「技能中要用相对路径」审计整包 —— 查出自述与实现不符:SKILL.md写「各脚本先读roots.env」,实际只有 9 份装了引导块 ⇒ 补齐 7 个非钩子脚本(共 16 份)+ 盘符字面量清零(配置目录→~/.workbuddy;工作区→DSH_WS_ROOT/cwd;覆盖网 glob→DSH_OVERLAY_LOG_GLOB,⚠️ 原写死的E:/dsh-worker-dev本机不存在=假警报源);roots.env增写CODEBUDDY_CONFIG_DIR。
🔴 修掉 2 个真缺陷:①wb-result-hook.py的_WS_ROOT按3×dirname(__file__)推 ⇒ 包内这份推出来就是技能包自己 ⇒ 钩子把包当工作区、包内长出tmp/(同文件里本有正确的resolve_ws()⇒ 同一事实两套实现)⇒ 改为复用resolve_ws()+ 未知工作区即停手;② 重定向 + GBK ⇒print("⛔…")抛异常 ⇒ 顶层记fatal、整轮失败(实测连续 4 次)—— 🔴 这正是常驻的拦路石(常驻必须重定向 stdout)⇒ 7 份加输出编码兜底 +log()在配置缺失时拒写。
✅ 验收:--apply真装(带备份)|--verify全绿(10 条接线rc=0/collabd --where/ selftest PASS 39 / FAIL 0)|清单 34 文件 / 0 失败|复现原路径 0 次fatal、包内干净|工作区 4 份副本逐字节对齐。
⚠️ 行为变更(如实登记):钩子驱动的投递由"静默崩"变真会跑;当前无NEXT.md⇒ 四道闸门不全 ⇒ 实际不会投出消息。2026-10-01 18:2x 技能整合检查与瘦身-20261001✅ 整合独立复核全过( install.py --verify全绿:10 条钩子空载荷rc=0、collabd --where解析到包内、selftest PASS 39 / FAIL 0;两个原技能已在<工作区>/归档/技能-退役-20261001/;活文件零旧技能名残留)+ ✅ 包瘦身(collab-detail.md删原件 YAML 变更流水 9.4 KB + 加读法索引;manifest.md去流水账、修已过期的「未了①」;taskgraph/pitfalls两处旧抬头改指;工作区goalctl.py旧文案对齐包内;清__pycache__×2 +hooks/bak-*+ 包内tmp/⇒ 包 1,098,918 → 1,000,604 B)。
🔴 途中修掉 1 个真缺陷:install.py --verify跑collabd --where未指定 cwd ⇒ 按调用者 cwd 推导工作区 ⇒ 把技能包自己当工作区、在包内写出tmp/supervise-inbox/(这正是包内总冒出tmp/的根因)⇒ 已改为在临时目录里跑 ②③ 并收尾清理,复跑确认不再重生。
🔴 上抛(⛔ 未擅自改):architecture.md的「当前结论」表 + §5-1 说「投递必须常驻/已回退 09-29 版」,而同文件 §4 抬头、collab.md §3、deploy.md §7、项目层MEMORY.md都说「钩子事件驱动 + 自动任务拨钟、⛔ 不常驻」⇒ 同一文件内自相矛盾且与项目状态层相反;按该文件 §9 自己写的教训条款(⛔ 不得擅自改"用户定案")留待用户拍板。2026-10-01 16:5x 会话机制合并包-收尾2-20261001✅ §9.3 解阻并做完:包内 board.py --serve 8788 --takeover接管(旧 PID 21084 停、新 PID 35068;healthz ok:true、/board.json真实快照)⇒ 两个原技能目录已用os.rename移入归档/技能-退役-20261001/(agent-operating-rules原样保留)⇒ 三项复测全过(钩子空载荷rc=0;goalctl._collabd()与wb-result-hook._collabd_ctx()运行时都解析到<包>/scripts/collabd.py;install.py --verify全绿 PASS 39 / FAIL 0)。
🔴 ② 有界实验(会话日志自愈)= 可行:真实会话里对本会话自己的<sid>.log做os.rename一次成功,宿主紧邻下一次读数即重建同名文件并继续写入 ⇒ 推翻当天早些时候「句柄常开、间隙不可改名」的结论(那条只证明"正在写的那一瞬"不可改名)⇒ 已把「硬档就地回收」接进session-log-guard.py(包内 +07-scripts原件同语义同步;空载荷rc=0、--verify全绿、验收通道端到端跑出RECYCLE真记录)。
🔴 ③ 缺口(已写清、⛔ 未擅自改):哑掉检测只覆盖"不许投+不当主会话",没有"重排";且哑会话仍被reconcile()计入"在跑" ⇒ 反而挡住「执行者已消失 ⇒ 待重派」这条唯一的重排入口(详见 §9.7)。
⚠️ §9.5(load_cfg报真实原因)本轮未做(留作独立小活)。2026-10-01 16:0x 会话机制合并包-收尾-20261001✅ §9.1 指针全改( CODEBUDDY.md/工作区MEMORY.md/用户级MEMORY.md/board_ext.py/协同监管棒-SOP.md/agent-operating-rules×4 处)+ ✅ §9.2 打包(归档/技能-退役-20261001.tar.gz· 377,103 B · 22 条目 · 含两份SKILL.md)+ ✅ §9.4 清单重算(33 文件 / 0 失败)+ 🔴 §9.3 阻塞,已按规矩回滚(见下)。
🔴 途中发现并修掉一个结构性缺陷:原multi-session-collab/SKILL.md(96,723 B)根本没被并入包,而包内architecture/deploy/pitfalls/taskgraph.md四份都写着「主干判据在SKILL.md §x」⇒ 8 处悬空引用(§0.05/§0.5.2/§0.5.4/§0.5.5/§1.3/§1.4a/§3/§6实测只存在于原文件)。已逐字带进references/collab-detail.md(头部写明「以architecture.md为准」)+ 8 处全改指 + 清掉另 9 处旧名/旧路径活文本。(判定「看板卡住」≠ 本包坏了)2026-10-01 15:40 会话机制合并包-任务4-5-6✅ §3 第 5 条完成(补齐 references/{collab,rules,forensics}.md三份,从架构/坑/任务图 + 两个原技能原文提炼,⛔ 非空壳) + ✅ §3 第 4a 条完成(两处硬编码回落路径已改指新包:goalctl.py:_collabd()与wb-result-hook.py:_collabd_ctx()—— 新落点优先、旧落点留作过渡兜底,并已cp同步包内副本 + 重打roots.env补丁;实测两者都解析到<包>/scripts/collabd.py、空载荷rc=0)。🔴 因会话诊断日志到 8.06 MiB(硬档)停手 ⇒ 第 4b/4c/4d、第 6 条留给下一棒(见 §9)。2026-10-01 15:1x 会话机制合并包-任务234b✅ §3 第 1、2、3 条全部做完:① install.py两处缺陷已修并沙箱验收全过(含原先🔴的第 3、4 项)②--verify全绿(钩子 10/10rc=0、collabd --where正常、selftest PASS 39 / FAIL 0)③ 🔴 真机--apply已执行:全局钩子已从07-scripts切到包内(0 条残留旧指向、decision_bridge4 条原样保留),装后自检全绿、闸门日志实测在推进 ⇒ 本包现已是主技能。
⚠️ 途中修掉 1 个真阻塞缺陷 + 1 个生产回归(见 §8)。⛔ 未做:§3 第 4 条(归档原技能+改 2 处回落路径)、第 5 条(3 份 references)、第 6 条收尾。2026-10-01 14:59 会话机制合并包-任务234🔴 硬档停手(日志 8.02 MiB / 10 MiB)。包已可用、沙箱验收 5 项过了 4 项;⛔ 未做:真机 --apply、--verify、归档原技能、3 份 references。install.py 有 2 处已定位未修的缺陷(见 §3 第 1 条)。2026-10-01 14:2x 会话机制合并包-任务0✅ 任务 0(方案落盘)+ 任务 1(建包骨架 27 文件,全 cp)完成。🔴 本包 §1 = 已实测的现状(⛔ 不要重跑);§2 = 已验/未验;§3 = 未做完的活(按序);§4 = ⛔ 不要重做;§6 = 硬阻塞点(先读)。
§1 已实测的现状(直接引用,⛔ 不要再跑一遍)
1.1 用户原话与目标(2026-10-01 两轮)
第一轮:「整合 会话机制相关技能为一个skill包 , 在将多会话协作机制 也整合到这个技能包,要求换一台电脑的 workbuddy 上运行也能自动完成配置,让所有会话遵循 会话机制,并且可独立使用 多会话协作」 第二轮:「1、检查 和测试 整合技能所有功能是否正常,确认后将整合技能作为主技能 使用,原技能全部打包存放」
1.2 包现状 ~/.workbuddy/skills/session-mechanism/(已建成)
- 30 个文件:
SKILL.md(新写 · 两段式:会话机制/多会话协作)+install.py(新写)+references/(architecture/deploy/pitfalls/taskgraph/manifest)+scripts/hooks/(6) +scripts/lock/(4) +scripts/collab/(10) +scripts/forensics/(1) +assets/(2)。 - 机制脚本一律
cp拷入(⛔ 无mv),源路径全部原样可用;md5 与源逐字节一致(清单references/manifest.md)。 references/manifest.md含逐文件 provenance + 「暂未纳入」清单(tools/ 监控成本类 16 项、collab/ 排期文件、全部*.bak-*)——⛔ 不是遗漏,是判定不纳入。
1.3 🔴 本轮最重要的技术发现(推翻接续包 §3.4 第 4 条)
原设计「唯一实现放包内 + 07-scripts/<同名> 改转发壳」在本机不可行,两条硬事实:
- 9 个机制脚本里 8 个按自身位置推导根目录(实测行号):
handoff-guard.sh:37ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"/preflight-lock.sh:25同型 /handoff-status.py:14dirname(dirname(__file__))/session-log-guard.py:107stop-dialog-guard.py:74bash-output-guard.py:43skill-load-guard.py:139(WS_FALLBACK上溯)/lock-guard-hook.py:41(env+硬编码默认)。 ⇒ 改壳会改$0、mv会改__file__⇒ 锁根从/d/github/.../dsh-server-docs直接挪到~/.workbuddy/skills⇒ 锁目录全错。 这正是wb-result-hook.pydocstring 记过的原事故:「一次搬迁后指错 ⇒ 台账静默写到别处而测试全绿」。 - 🔴
settings.json的 hook 条目没有env字段(实测 schema:{matcher, hooks:[{type,command,timeout}]})⇒ 无法靠钩子向脚本注入环境变量。
解法(本轮已落地):包内脚本根目录外置 —— 新增 <包根>/roots.env(install.py 生成),脚本先读它、再回落按位置推导。
已打补丁 8 份(全部语法通过):handoff-guard.sh preflight-lock.sh handoff-status.py session-log-guard.py stop-dialog-guard.py bash-output-guard.py skill-load-guard.py lock-guard-hook.py + wb-result-hook.py(WB_RESULT_HOOK_WS 增加 DSH_WS_ROOT 回落)。
补丁器(一次性脚本,⛔ 不入库):$WS/tmp/inv-20261001/patch-roots.py(精确锚点替换,锚点必须唯一命中,幂等)。
1.4 归档原技能的真实依赖(⛔ 直接归档会打碎协作机制)
grep 实测:两个原技能被引用很多,但只有 2 处是真实代码依赖(其余是文档/记忆):
$WS/.workbuddy/collab/goalctl.py:460→base / "skills" / "multi-session-collab" / "scripts" / "collabd.py"(已支持COLLABD_SCRIPTenv 覆盖)$WS/.workbuddy/tools/wb-result-hook.py:247→r"E:/ProgramData/.workbuddy/skills/multi-session-collab/scripts/collabd.py"(已支持COLLABD_PATHenv 覆盖) ⇒ 归档前必须把这两处的回落路径加/改指到新包(scripts/collab/collabd.py),并重新同步包内副本。 ⚠️wb-result-hook.py是全局钩子(PreToolUse ^Bash$+UserPromptSubmit+SessionEnd三条接线都指向它,实测)⇒ 改它 = 改所有会话每次工具调用都会过的钩子;改完必须立即用空载荷复测rc=0。
1.5 install.py 现状(核心交付物,已写但未定稿)
- 用法:
--dry-run/--apply/--verify/--uninstall;--workspace/--docs-root/--code-repo。 - 自解析:
sys.executable+CODEBUDDY_CONFIG_DIR(⛔ 无硬编码 python 路径、⛔ 无硬编码盘符)。 - 声明表驱动 10 条接线(
HOOKS),⛔ 显式排除decision_bridge.py的 4 条(属ai1net-decision-laya另一条线);--dry-run会打印被排除条数供目视核对。 - 幂等(先删自己的旧条目再插,按脚本名认旧落点)/写前备份/
--uninstall还原/写install.log/写roots.env/工作区初始化(由 example 生成,已存在则不覆盖)。 - 判语:「
--apply每次都备份 ⇒ 最新那份其实是已装状态」 ——--uninstall必须挑最早那份不含本包痕迹的备份(本轮已就此改成 fail-closed:挑不到就拒做,⛔ 不拿已装状态糊弄)。
§2 沙箱验收:已过 4 项 / 未过 1 项(⛔ 不要再重跑前 4 项)
做法:把 settings.json 拷进沙箱目录,用 CODEBUDDY_CONFIG_DIR=<沙箱> 跑 —— 现场全局配置零风险。
| # | 判据 | 结果 |
|---|---|---|
| 1 | --dry-run 不写盘 + diff 与预期一致 |
✅ 过:rc=0;删旧 10 条(07-scripts/tools)、增新 10 条;沙箱 settings.json md5 装前=装后(未写盘);被排除 4 条 |
| 1b | 幂等:连装两遍零改动 | ✅ 过:第二遍 md5 与第一遍完全相同,diff 行数 0 |
| 1c | 结构核对 | ✅ 过:总接线 14 条;指向 07-scripts 的机制钩子 = 0;decision_bridge 4 条原样保留;无重复条目(按 command 计数出现的 4 个"重复"是同一脚本挂在不同事件上,正常) |
| 2 | --verify(6 钩子空载荷 rc=0 + collabd --where + selftest) |
⬜ 未做 |
| 3 | --uninstall 后与装前逐字节相同 |
✅ 过(15:15 复测):-orig 固定名备份 + 微秒时间戳备份 ⇒ --uninstall 还原后 cmp 逐字节相同;改名/换目录场景同样通过。修法已落地见 §3 第 1 条 |
| 4 | 包拷到另一个目录再 --apply ⇒ 接线指向新路径 |
✅ 过(15:15 复测):改名包 --apply ⇒ 10 条全指向新路径、07-scripts 残留 0、decision_bridge 4 条保留;--uninstall 逐字节还原。判据已按包实际路径(运行时从 __file__ 推导)判"是否已接管" |
沙箱现成可复用:$WS/tmp/inv-20261001/sbx-settings/(settings.json + 日志),⛔ 不要删,接着用。
§3 未做完的活(按序做,一次只做一件)
🔴 进度(2026-10-01 15:1x):第 1、2、3 条 ✅ 已完成(明细见下);下一条从第 4 条开始。
1、✅【已修 · 15:15】install.py 两处缺陷
a. 备份唯一化 + 原状备份单列:首次安装(当前 settings.json 无本包痕迹)时写 settings.json.bak-session-mechanism-orig,已存在则⛔不覆盖;其后每次 --apply 写带微秒的时间戳备份。--uninstall 优先用 -orig。
b. "自己的痕迹"改按脚本名判:本轮已往包内加了 has_our_trace(text)(按 OWN_BASENAMES 判)但尚未接线 ⇒ 把 --uninstall 与其它判"痕迹"的地方从 OWN_MARK(路径片段)改成 has_our_trace()。
2、✅【已过 · 15:15】--verify:包内 10 条钩子空载荷全 rc=0;collabd.py --where rc=0 且正确报出配置来源;selftest.py PASS 39 / FAIL 0。⚠️ 无 COLLABD_CONFIG 时 --where 仍 rc=0(回落 DEFAULTS 并明确标注)⇒ ⛔ 别把"没配置"读成"包坏了"。
3、✅【已执行 · 15:15】真机 --apply(= 用户要的「作为主技能使用」)
"$PY" "<包>/install.py" --apply --docs-root "D:/github/dsh_shenxian/dsh-server-docs"
装完立刻 --verify;⚠️ 这一步会把全局钩子从 07-scripts 切到包内 ⇒ 影响所有正在跑的会话的每一次工具调用 ⇒ 动手前一句话说明、装完立刻复测、异常立刻 --uninstall。
4、归档原技能(用户明确要求)
a. 先按 §1.4 改那 2 处回落路径 → 指向新包,并重新 cp 同步包内副本;改完空载荷复测 rc=0。
b. 打包:tar -czf "$WS/归档/技能-退役-20261001.tar.gz" -C ~/.workbuddy/skills multi-session-collab workbuddy-session-forensics
c. 然后才从 ~/.workbuddy/skills/ 移走那两个目录(⚠️ 移走前确认 agent-operating-rules 仍在,它是声明依赖,⛔ 不并、⛔ 不移)。
d. 改指针:$WS/CODEBUDDY.md 头部「协作机制:唯一权威 ⇒ multi-session-collab/references/architecture.md」改指新包;.workbuddy/memory/MEMORY.md 内同型指针一并改。
5、补 3 份 references(SKILL.md 已引用,现在是指向空处):references/{collab,rules,forensics}.md。
⚠️ ⛔ 不要写空壳(写空壳=文档说谎);从包内已有的 architecture.md/pitfalls.md/taskgraph.md 与 multi-session-collab 原文提炼。
6、收尾:references/manifest.md 重算(改过补丁)→ 更新本接续包 §0 → 今日日志 → 三层沉淀 → 反序释放锁。
§4 ⛔ 不要重做 / 不要碰
- ⛔ 不要重跑:三源目录盘点(§1.2/1.3 已实测)、
install.py沙箱前 4 项验收(§2 已过)、patch-roots.py(幂等,已跑)。 - ⛔ 不要
mv机制脚本;⛔ 不要做转发壳(§1.3 已证不可行 —— 会挪走锁根)。 - ⛔ 不要动
decision_bridge.py所在线(ai1net-decision-laya)—— 它只是恰好出现在同一张钩子表里(4 条)。 - ⛔ 不要动自动化排期(用户明令)。⚠️ 唯一例外=本包自己登记的接续会话。
- ⛔ 不要在会话里起常驻后台任务(会把日志推过 10 MiB ⇒ 界面静默哑掉)。
- ⛔ 不许报未经实测的系数;本包只写"实测到的计数/字节"。
- ⛔ 不要在没有沙箱验证的情况下直接改现场
settings.json。 - ⛔ 不要删
$WS/tmp/inv-20261001/(含补丁器、构建清单脚本、沙箱)。
§5 关键路径与命令
PY = E:/ProgramData/.workbuddy/binaries/python/versions/3.13.12/python.exe
WS = E:/ProgramData/AIProject/ai1net-dsh-server
DOC = D:/github/dsh_shenxian/dsh-server-docs
PKG = E:/ProgramData/.workbuddy/skills/session-mechanism
BASH = E:/ProgramData/.workbuddy/binaries/PortableGit/versions/1.2.0/usr/bin/bash.exe # ⚠️ 裸 bash 会落到 WSL ⇒ 假阴性
锁(机制层=独占,⛔ 不带 --domains):
bash "$DOC/07-scripts/handoff-guard.sh" --claim-exec "<会话名>"
释放:--release → --release-exec "<会话名>"
§6 本机踩坑(已踩到,⛔ 别再踩)
- 🔴
subprocess.run(["bash", …])在本机落到 WSL 启动器 ⇒ 输出 UTF-8 乱码、路径里/被吃 ⇒bash -n假阴性(脚本明明没错却报 FAIL)。必须显式用$BASH。 - ⚠️
ls -1 目录A 目录B | sort把两个目录的输出合并排序(无分组标题)⇒ 极易误读成"某目录是空的"。多目录必须分开列。 - ⚠️ 补丁器踩到过两次:把 Python 引导块插进
.sh;引导块插在from __future__ import之前(有的文件把__future__放在注释区之后,⛔ 不能只跳过文件开头)。两处都已修,规则:引导块只插.py,且插到"全文件最后一个__future__之后"。 - ⚠️ 沙箱备份同秒同名被覆盖 ⇒ 原状备份必须单列(§3 第 1.a 条)。
- ⚠️
settings.json的 hook 条目无env字段(实测 schema)⇒ 别指望用 env 给钩子传参。
§7 验收判据(全过才算交付)
install.py --dry-rundiff 与预期一致;真装后再跑一遍零改动。→ ✅ 已过(沙箱)- 装机后
--verify:包内钩子空载荷全rc=0;collabd --where正确;selftest见FAIL 0。→ ⬜ 未做 --uninstall后与装前备份逐字节相同(cmp)。→ 🔴 未过(修法 §3.1)- 包拷到另一目录再装 ⇒ 接线指向新路径且
--verify全绿。→ ⚠️ 部分(§2 #4) - 原技能归档后:
goalctl.py与wb-result-hook.py仍能定位到collabd.py(改路径后复测rc=0);CODEBUDDY.md指针已改指新包。
§8 本轮(15:05–15:15)实测记录 —— ⛔ 别重做
8.1 🔴 新发现①:包内脚本目录层级放错 ⇒ --verify 恒红(已修)
- 现象:
--verify的 selftest PASS 32 / FAIL 7,7 项全是FileNotFoundError; 同一个 selftest 从原件(multi-session-collab/scripts/selftest.py)跑是 PASS 39 / FAIL 0。 - 真因:
board.py与selftest.py按HERE.parent / "assets"与HERE.parent / "scripts"定位 —— 它们假设自己在<技能>/scripts/这一层。包把它们放进了scripts/collab/⇒ 两个路径双双落空。 - 修法(对机制脚本零改动):把 11 个协作脚本拉平到
<包>/scripts/顶层,删掉collab/子目录 ⇒ 实测立刻 PASS 39 / FAIL 0。 - 🔴 教训(写进规矩):拷脚本必须拷到
scripts/顶层,⛔ 不要再建组子目录 (hooks/lock/forensics/可以留,因为它们靠roots.env定位、不依赖../assets)。 - 牵连改动:
install.py --verify两处路径、SKILL.md一处路径、references/manifest.md全表。
8.2 🔴 新发现②:工作区协作配置是坏 JSON ⇒ collabd 静默回落 DEFAULTS(已修)
- 现象:
collabd.py --where报「未找到部署配置(…不存在)」,但文件明明在。 - 真因:
$WS/.workbuddy/collab/collabd.config.json第 53 行把"按工作区分线"写成了 ASCII 双引号(夹在 JSON 字符串里)⇒json.loads抛JSONDecodeError; 而load_cfg()的except Exception: pass静默吞掉,于是回落 DEFAULTS 并谎报"不存在"。 - 影响面(实测对比):DEFAULTS 下
LIVE/TG指向tmp/supervise-inbox/{realtime.md,taskgraph.json}—— 两个文件都不存在;配置文件里指的才是真落点交付物/本机协作-实时状态.md、交付物/任务图.json(都在,13:48 还被写过)。⇒ 这是当天 13:55 的一次编辑引入的回归 (13:48 还在正常写交付物/本机协作-实时状态.md)。 - 修法:改成中文引号
「」;已json.loads校验通过,--where现已正确报出配置来源 = …collabd.config.json。原坏件备份在<WS>/.workbuddy/collab/bak-collabd-config-20261001/。 - ⚠️ 遗留(⛔ 本轮未动,留给下一棒判):
collabd.load_cfg()对"文件存在但解析失败" 既不区分也不告警,还谎报"不存在"。建议改成报出真实原因(解析失败 ≠ 不存在), 否则下一次同样的手误还会静默降级。改它要同时改两处(07-scripts原件 + 包内副本)并保持同步。
8.3 真机切换的实测读数(15:13:17 执行)
- 切换前
settings.jsonmd57dca0aeb798e52728dc93dce2e7804b8;-orig原状备份已写~/.workbuddy/settings.json.bak-session-mechanism-orig。 - 切换后:总接线 14、指向
07-scripts0、指向包内 10、decision_bridge4(原样保留)。 - ✅ 语义等价性已逐条核对:事件 / matcher / 额外参数(含
-S)/ 超时 / 解释器 全一致,只有脚本目录不同。 - ✅ 端到端取证:装后
bash-guard.log由 15:13:16 → 15:13:39 且新增event=PreToolUse行、stop-dialog-guard.log同步推进、state.py报「关键闸门在册」⇒ 包内钩子在生产链路真跑。 - 回滚:
python <包>/install.py --uninstall(-orig已就位,逐字节还原已验收)。
8.4 下一棒从哪开始
- §3 第 4 条(归档原技能):⚠️ 必须先改
goalctl.py:460与wb-result-hook.py:247两处回落路径 → 指向<包>/scripts/collabd.py,并重新cp同步包内副本,改完空载荷复测rc=0; 再打包归档/技能-退役-20261001.tar.gz;最后才移目录(⚠️ 确认agent-operating-rules仍在 ⇒ ⛔ 不并、不移)。 - §3 第 5 条:补
references/{collab,rules,forensics}.md(⛔ 不许写空壳)。 - §3 第 6 条收尾:本接续包 §0 / 日志 / 三层沉淀 / 反序释放锁。
- 可选:处理 8.2 的遗留(
load_cfg报真实原因)。
§9 下一棒剩余步骤(从 4b 开始 · 逐条做 · 一次一件)
🔴 本轮(15:40)已完成:§3 第 1、2、3、5 条 + 第 4a 条(两处回落路径)。日志硬档停手,剩余如下的机械动作。 ⛔ 先读 §4「不要重做 / 不要碰」清单;⛔ 仍不要重跑盘点与沙箱验收。
9.1 第 4d 条 · 先改指针(★ 必须在 4c 之前 —— 否则目录一移走,指针就悬空)
需要改指的活文件(其余命中都在 traces/ / changes-detail/ / modify_backup/ / 归档/ / 历史日志里,⛔ 不要动):
$WS/CODEBUDDY.md头部「协作机制:唯一权威 ⇒multi-session-collab/references/architecture.md」⇒ 改指~/.workbuddy/skills/session-mechanism/references/architecture.md。$WS/.workbuddy/memory/MEMORY.md里同型指针(multi-session-collab §0.5.5/§1.4a那条)⇒ 改指新包同名位置(references/collab.md/references/architecture.md)。~/.workbuddy/MEMORY.md(跨项目长期记忆)里的 1 处引用。$WS/.workbuddy/collab/board_ext.py里 1 处(multi-session-collab/scripts/board.py契约注释)。$WS/交付物/任务图.json与$WS/交付物/协同监管棒-SOP.md各 1 处。- 检查
~/.workbuddy/skills/agent-operating-rules/SKILL.md是否也有引用(本轮未确认)。 ⚠️交付物/下的历史过程件(多会话协同*-20260929.md等)⇒ ⛔ 不改正文,按其自身规矩只加头部状态块指向新包。
9.2 第 4b 条 · 打包
tar -czf "$WS/归档/技能-退役-20261001.tar.gz" -C ~/.workbuddy/skills multi-session-collab workbuddy-session-forensics
(⚠️ 打包前确认 4d 已做完。)
9.3 第 4c 条 · 移走两个原技能目录 —— ✅ 2026-10-01 16:5x 已做完(正解=先让包内看板 --takeover 接管,再移)
✅ 实测结果(第 5 棒):把顺序改成「① 包内 board 接管(=一并完成"停旧+起新")→ ②
os.rename移目录 → ③ 复测」 —— 比原计划的「先停 → 移 → 再启」更安全:新代码先验证可用,失败还能立刻回退旧实例(此时目录尚未动)。
- ①
"$PY" "<包>/scripts/board.py" --serve 8788 --takeover(cwd=<包>/scripts,envCOLLABD_CONFIG=<WS>/.workbuddy/collab/collabd.config.json) ⇒ 输出✓ 接管:已停旧看板 PID 21084(成功);新 PID 35068;/healthz{"ok":true}、/HTTP 200 / 84,874 B、/board.json是真实快照(goal+V1–V5 都在)⇒ 只有 1 个实例在听 8788。- ②
os.rename两个目录 →归档/技能-退役-20261001/(⛔ 不用mv)⇒ 一次成功(旧实例句柄随停进程释放)。- ③ 三项复测全过(读数见 §0 最新行)。 ⚠️ 启动方式:本机唯一可行=会话后台任务 + stdout 全重定向(
> <WS>/tmp/board-serve.out.log 2>&1);旧实例(08:05 起的那个)也是同款血统、存活 9 小时 ⇒ 该模式在本机实测 durable。
🔴 2026-10-01 16:0x 实测:
os.rename移multi-session-collab恒失败WinError 5/32, 而每个文件单独改名都成功 ⇒ 定位到multi-session-collab/scripts/被另一个进程占用。 占用者=看板服务 PID 21084:命令行python board.py --serve 8788 --takeover(相对路径 ⇒ cwd 就在该scripts/), 起于 08:05:56,端口 8788 实测在听、HTTP 200 / 84,874 B(=board.html)⇒ 它是活的、是用户正在看的看板。 ⛔ 不可强移(会打断看板);按 §9.3 规矩已回滚:workbuddy-session-forensics移回原地、multi-session-collab未被改动。 ⇒ 正解(三步,按序): ① 停看板(结束 PID 21084,或它自己的 stop 入口); ②python os.rename把两个目录移到$WS/归档/技能-退役-20261001/(tar 已在 §9.2 完成,⛔ 不必重打); ③ 用包内路径重启看板:"$PY" "<包>/scripts/board.py" --serve 8788 --takeover(cwd 设<包>/scripts), 起来后复测HTTP 200+ 三个读数(钩子空载荷rc=0、goalctl→<包>/scripts/collabd.py、install.py --verify全绿)。 ⚠️ 教训(值得写进技能):归档一个「被服务依赖的技能目录」时,先查有没有进程正跑在里面 (判据=相对路径启动的服务 ⇒ cwd 即句柄),否则会得出"移不动=权限问题"的错误结论。
- ⚠️ 移走前确认
agent-operating-rules仍在~/.workbuddy/skills/—— 它是声明依赖,⛔ 不并、⛔ 不移。 - 用 python
os.rename移,⛔ 不用mv(见 §6 第 1 条)。 - 移走后立刻复测:
wb-result-hook.py空载荷rc=0、goalctl.py能解析到<包>/scripts/collabd.py、install.py --verify全绿。 🔴 这两个脚本的回落路径已在本轮改成新包优先,所以移走原技能后仍应正常;若异常 ⇒ 立刻把目录移回来报障。
9.4 第 6 条 · 收尾
references/manifest.md 重算(本轮已重算过一次,4a 又改了 goalctl.py/wb-result-hook.py 两份 md5 ⇒ 必须再算)→ 更新本接续包 §0 → 当日日志 → 三层沉淀 → 反序释放锁(--release → --release-exec "<会话名>")。
9.5 可选(低优先)
collabd.load_cfg() 对「配置存在但解析失败」不区分、还谎报"不存在" ⇒ 建议改成报真实原因;要同时改 07-scripts 原件与包内副本并保持同步。
9.6 候选(本轮登记 · 由用户质疑引出)—— ✅ 2026-10-01 16:5x 已实测并落地,见 §9.7
用户问「工具日志不是已经拦截了吗」⇒ 核实结论:session-log-guard.py 只叫停、不降速(零删改动作,只注入提醒);10 MiB 上限真实(当日已有 6 个会话日志卡在 10,485,7xx B)。
⇒ 候选:把「会话中途回收日志」做成正式机制(重命名让宿主重建),使会话不必因撞顶而停手。
⚠️ 上手前必须先实测两条:① 宿主正在写时改名是否安全(现有证据只覆盖冻结日志);② 丢掉被拒写的那段诊断内容的代价是否可接受。
⛔ 未实测前⛔ 不要写进机制、⛔ 不要报"已经解决"。
§9.7 第 5 棒结果(2026-10-01 16:5x)—— ② 有界实验 + ③ 缺口
A. ②「会话日志自愈」—— ✅ 可行,已接入机制
实测(真实会话,非 scratch)
- 对本会话自己的
logs/2026-10-01/sdk/conversations/63f5e790-….log做 一次os.rename⇒ 成功(无WinError 32/5)。 - 紧邻的下一次读数:原文件名已回来(宿主重建,50,073 B)且继续增长;旧件冻结在 1,728,992 B。
- ⇒ 判语:宿主不是"句柄常开",而是每次日志批写开-写-关 ⇒ 工具调用的间隙里句柄是关着的。 ⚠️ 当天更早那条"不可改名"的结论只对"正在被写的那一瞬"成立(scratch 复现里子进程一直在 append)。
落地(机制改动 · 只动了 1 份文件)
- 位置:
<包>/scripts/hooks/session-log-guard.py(+ 文档库原件07-scripts/session-log-guard.py同语义同步)。 - 规则:到硬档(8 MiB)先试一次就地回收 —— 把
<sid>.log改名为<sid>.log.recycled-<YYYYMMDD-HHMMSS>⇒ 成功:复位本会话档位(不复位则后半程再也报不出来)+ 注入 ♻️ 提示("可继续、不必停手"),直接结束; ⇒ 失败:一个字都不改,逐字退回原「停手+建接续」口径(fail-safe)。 - 收窄与防撞:⛔ 只动本会话自己那一份(
_log_path按session_id精确拼名);⛔ 只试一次(放在档位去重之后 ⇒ 每个档位天然只试一次),⛔ 不 sleep、不重试、不降级成删/截断。 - 与清扫器不冲突:后缀不以
.log结尾 ⇒wb-logcap-sweep.py的*.log匹配天然不重叠(不会被二次搬运)。 - 开关:
DSH_SLG_NO_RECYCLE=1⇒ 只关回收、保留软/硬档叫停。 - 验收(都做过):空载荷
rc=0零输出 ✅|真实形状载荷(未达档)rc=0零输出 ✅|install.py --verify全绿 PASS 39 / FAIL 0 ✅| 验收通道(tmp/.session-log-guard.verify.json收窄到本会话 sid)端到端跑出真记录RECYCLE|size=279862 B|…log -> …log.recycled-20261001-165257+ ♻️ 注入 1,077 B ✅(跑完立即删除通道文件,已复核不存在)。 - ⚠️ 途中修掉 1 个真缺陷:
_recycle_note里字面量97.8%未转义 ⇒ 抛TypeError: not enough arguments for format string(回收仍生效、只是提示发不出;已在两副本改%%并加注释)。 - ⚠️ 另一处已修:
_recycle的阈值必须传实际生效的hard(⛔ 不写死模块常量),否则验收通道只能验"叫停"、验不到"回收"。
遗留(⛔ 本轮未做)
- 回收后那一轮会话会不会自己继续,仍未验证(本轮只证明了"写入不中断",没证明"已失败的那轮会重跑")。 ⇒ 仍必须靠 §B 的「哑掉 → 重排」兜底 —— 但恢复写入已把"沉默窗口"从"永久"压到"≤ 1 分钟(清扫器周期)"。
- 回收阈值暂定=硬档(8 MiB),⛔ 未验证"更低阈值(如 5 MiB)是否更优"(更低=更频繁改名、更高=更逼近平台上限)。
B. ③「日志撞顶 ⇒ 哑掉」这一型的覆盖情况 —— 🔴 部分覆盖,缺口已定位,⛔ 未改代码
已有的覆盖(都在 collabd.py,均已实测在跑)
- 检测:
_deaf_sids()—— 取每个会话最新一天的日志,≥ 9.5 MiB判哑(只读,扫不到=空集)。 - 不许投:两条投递路径(
_deliver_str≈1016 行、另一条 ≈1133 行)命中哑 ⇒skipped="target-deaf"+need_user(...)⇒ 不记假绿,并把"该点哪一下"落到NEED-USER.md。 - 不当主会话:
_pick_live()(≈1902 行)把哑会话从"主会话候选"里剔除。
🔴 缺口(没有"重排"这一层)
- 处置动作只有"喊用户换会话"(
need_user原文:「请把主会话换到一条新会话(旧的那条只能弃用)」)⇒ 恢复链条要靠人。 - 🔴 更糟的是它会反过来挡住唯一那条重排入口:
reconcile()(≈2190 行)的僵尸判据是 「台账running且除观察者外无人在跑、且无IN_PROGRESS」才标blocked+待主会话重派。 而哑会话若在宿主库里仍记working(会话被冻在半途)⇒ 它被当成"有人还在跑" ⇒ 僵尸判据永不触发 ⇒ 形成死角:既投不进去、又不判死、也没人重派。 (注:若哑会话在库里已转成completed,僵尸判据可以触发 —— 所以是"条件性覆盖",不是全无。) - 且
collabd.py自身设计上就不派活/不开新会话(其 docstring 第 12 行明写),⛔ 不能指望它自动补一条接续。
最小修法(⛔ 本轮未实施**,留给下一棒/用户点头)**
- 在
reconcile()里把_deaf_sids()命中者从"在跑"集合里剔除(即"哑会话不算执行者"):allrun剔掉哑 ⇒ ① 它们不再被"启动对账收编"成running(投不进去的会话本来就不该算执行者); ② 僵尸判据得以触发 ⇒ 标blocked+block_reason="…待主会话重派"⇒ 队列里看得见,主会话/监管棒才会重派。 - 量级:一处改动(约 1–2 行),复用现成的
_deaf_sids(),⛔ 不新增常驻、⛔ 不动排期、⛔ 不新增阈值。 - ⚠️ 注意比较口径:
_deaf_sids()返回完整 sid,而reconcile里me用的是前 8 位 ⇒ 剔哑时要按完整 sid 比。 - ⚠️ 前置:先把 ② 的回收跑一段时间(它把撞顶概率大幅压低)⇒ 再决定这条兜底要不要上(它只服务"已经哑了"的存量与漏网)。
- ⛔ 另有一条已排除的做法:让
collabd直接开接续会话 —— 违反它自己的设计约束(不派活/不开新会话),且触"⛔ 不要动自动化排期"。
C. 本轮 ⛔ 未做(明确不碰)
- §9.5
collabd.load_cfg()对"配置存在但解析失败"不区分、还谎报"不存在"(要同时改07-scripts原件与包内副本)。 - 自动化排期、
decision_bridge那条线、wb-logcap-sweep.py与计划任务WorkBuddy-LogCapSweep(⛔ 一个字没动)。