- 变更规模:新增 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/ 知识文件,按口径入库)
11 KiB
接续包 · 唤醒机制探索(2026-09-30 18:55 立)
🔴 状态块(2026-09-30 19:5x 加 · 由接续棒
a202550c回填): §1 第 3 棒(worker 退出后能否被外部叫起)已作答 ⇒ 判定:🔴 不能(叫醒旧会话)/能(无人值守地新起一个会话)。 定稿 ⇒交付物/唤醒-无人值守可行性-20260930.md(判定+泳道图+事故链图)+ 同名-图.html;冲突以定稿为准。 三条硬结论(一句话各一):① 网关口长在 worker 进程里 ⇒ worker 退出端口就消失;②POST /api/v1/runs不选会话(id只当消息 id,路由先取宿主自己的primarySession)⇒ 对别的活网关投递只会落到投递方自己的会话;③ 宿主不自愈(activated 条目意外退出只写 warn),唯一有效的复活动因在桌面端 pipe 上 ⇒ 外部接不上。 🔴 连带影响:§3 的"三选项"要重读 —— 方案 ③(idle 钩子→runs)不具备无人值守所需稳定性(worker 典型寿命仅 30 s–6 min,实测),已降级为可选兜底;主干改为 A 自动化派棒。 ⛔ §2 #3c 要更新:worker 自行退出不是偶发,是常态(三天计数 40 / 55 / 28)。 ⚠️ 唯一能改判定的未知量:code=1静默退出是"回合结束被主动回收"还是"崩溃"(未做,留下一棒)。
工作线:机制线 · 唤醒机制探索 上一棒:会话
6ecf6d98(标题[主控]-[机制线]-接续:查「唤醒」为什么断) ✅ 上一棒已完成:一次性自动化8d046fb3-be7e-410c-8ae6-239113e780a9(19:00 起,会话706d2476) ⇒ 结论:idle 钩子"成立",全天唯一一次真触发18:55:00.210;并修正了本包 §2 #2 的旧结论。产出交付物/唤醒-idle钩子坐实-20260930.md。 🔴 下一棒已登记:一次性自动化b68e2b24-0964-400c-b7d8-be097211d23d名称:主控 · 唤醒机制线 · 棒:worker 退出后能否被外部叫起(无人值守决定性一问)|排期:2026-09-30 19:33|cwd:E:/ProgramData/AIProject/ai1net-dsh-server(id 取自工具返回值,⛔ 手写 id 一律无效) 本包位置:E:/ProgramData/AIProject/ai1net-dsh-server/接续包_唤醒机制探索_20260930.md
⚠️ 状态块(2026-09-30 19:1x 加 · 由接续棒 706d2476 回填)
本包 §1 目标已达成 ✅ —— 结论:idle 钩子「成立」,已端到端坐实(18:55:00.210 宿主真实 spawn)。
定稿 ⇒ 交付物/唤醒-idle钩子坐实-20260930.md(含泳道图+事故链图)。冲突以定稿为准。
⛔ 本包 §2 有两行已被推翻,别再沿用:
| §2 条目 | 处置 |
|---|---|
| #1「idle 钩子至今 0 次真实触发」 | 更新:17:51–18:54 期间仍成立;18:55:00 起 = 1 次真实触发 |
| #2「项目级配置对已运行会话不生效」 | ⛔ 判错,撤销。真因=hasLiveBackgroundTask() 被一个 12:17:45 起、18:38:13 才死的后台任务压了 6h20m(闸门不过只重装表、零日志)。项目级钩子对已跑会话确实生效(本会话 12:00 起跑、钩子 17:51 才挂,仍触发成功) |
| #2 附带的两个"空闲窗"(17:52→17:55 / 18:50→18:52) | ⛔ 都不成立:前者该会话全程在跑工具;后者到期时刻状态=tool_executing |
🔑 "空闲"的正确判据(⛔ 不是"没收到用户消息 60 s"):状态机 idle + 该会话无 pending/running 后台任务,且计时器每次 addHistory 都重置(回合进行中永不计时)。
🔴 #2 的这条错如果没被拦下,会让后续棒去改全局配置(一个既非必要、又属"改全局"的动作)—— 这正是本状态块存在的意义。
🔴 下一棒已换:一次性自动化 98fb060b-81e2-4daf-ba1f-d0e522246e80(主控 · 唤醒机制线 · 复现验证棒,排期 2026-09-30 19:15,cwds 正斜杠)。
其唯一目标=验证 §9 那条可复现预测(session_id=706d2476 的探针行是否在"+60 秒"出现)。§3 的"唤醒落地三选项"仍待用户拍板。
§1 本包唯一目标的演进(两棒已了,第三棒在跑)
✅ 第 2 棒(已完成,19:00):idle 钩子成立
全天唯一一次宿主真触发在 18:55:00.210(宿主日志 [HookExecutor] spawn,可复核)。两道隐形闸门:
① 状态机必须 idle(每次 addHistory 都重置 60 s 计时器)② 该会话无 pending/running 后台任务(hasLiveBackgroundTask())。
闸门不过 ⇒ 只重装表、零日志 —— 这就是它之前"看起来从没工作过"的真因(被一个 12:17 起的僵尸后台任务压了 6h20m)。
判据只认端到端:探针 tmp/_idle_hook_probe.jsonl 出现宿主新增行(⛔ 手工自测那行不算),且落在真实 >60 s 空闲窗内。
🔴 第 3 棒(已登记,19:33):worker 退出后能否被外部叫起(无人值守决定性一问)
- 要答:worker 退出(今天实测到
activated prewarm entry exited unexpectedly (code=1)一波 3 个)后 —— 网关口还在不在?POST /api/v1/runs是排队、报错、还是真把它拉起来跑一轮?若拉不起来,是否只剩"每次唤醒都新起会话"? - 为什么决定性:idle 钩子路线的前提是"会话活着且空闲";外部定时器→
runs路线若拉不活,则"无人值守"的成本前提被推翻。
§2 已经定死的结论(⛔ 别再重做取证)
| # | 结论 | 级别 |
|---|---|---|
| 1 | ✅ idle 钩子成立(已坐实,含唯一一次真触发 18:55:00.210)—— |
实测(第 2 棒) |
| 2 | 🔴 |
实测(第 2 棒修正) |
| 3 | 钩子热生效(改完 settings.json 不重启宿主,下一次调用就生效) |
实测 |
| 3b | idle 钩子的两道闸门:① 状态机 = idle(每次 addHistory 重置 60 s)② 无 pending/running 后台任务;不过闸 ⇒ 只重装表、零日志 |
源码 + 实测 |
| 3c | ⚠️ 宿主 worker 会自行退出:19:09–19:11 一波 3 个会话 activated prewarm entry exited unexpectedly (code=1) ⇒ 计时器随之消失 |
实测(第 2 棒附带) |
| 3d | 取证四件套(判"机制为何不触发"必须齐):[addHistory] COMPLETED|[SessionRunStateMachine] transition|[BashTool] background task …|[HookExecutor] spawn,再加会话进程存活;缺一件都⛔ 不许下"机制不成立" |
实测 |
| 4 | 5 分钟级自动化做不到(源码级:parseRRule 的 FREQ 是硬白名单 HOURLY/DAILY/WEEKLY/MONTHLY/YEARLY) |
源码级 |
| 5 | 网关 scheduled-tasks 在桌面端是死能力(宿主硬编码 CODEBUDDY_DISABLE_CRON=1) |
源码级 |
| 6 | POST /api/v1/runs 投递成立:会话忙时排队、空闲即交付 ⇒ 外部程序可以叫醒会话,不需人切窗口 |
实测(17:49 投、17:55 真到) |
| 7 | POST /sessions/{id}/reply 只认 live;非 live ⇒ parkInQueue(4.5 h 无反应) |
实测判负 |
| 8 | /jobs/{id}/reply 写 inbox,worker 从不 drain |
实测判负 |
| 9 | stop→reply(pending)→respawn:pending/respawn/unshift 都成,worker 卡 resuming… |
实测判负 |
| 10 | 唤醒 =「任务完成」事件,与 stdout 无关;后台任务静默安全、300 s 不被回收 | 实测 |
| 11 | ⛔ 常驻循环 + 周期 echo 当不了脉冲(永不完成 ⇒ 永不唤醒) | 实测 |
| 12 | 交接唯一触发条件 = 「登记为 main 的那条在不在活会话集合里」;在 ⇒ 钉死,不在 ⇒ 换 | 实测 |
§3 未决 / 待用户拍板
- 🔴 唤醒落地三选项(上一棒已问,用户未答):
- ① 只留探针(上一棒的倾向)
- ② 外部定时器 → 网关
runs(唯一能 5 分钟且 0 新会话,需单独评审) - ③ idle 钩子 →
runs自己(闭环但最坏 1440 轮/天,且要先解决"装哪里")
- idle 探针装哪里:项目级不生效 ⇒ 候选是改挂全局
E:\ProgramData\.workbuddy\settings.json的Notification。 ⚠️ 属"改全局配置",动手前必须先问用户(本棒边界已写死)。 resolve_main的前缀判据缺陷 A/B(机制层,须独占锁、单独一棒):- A|前缀判据不认方括号(代码
startswith("主控")而实际标题常是[主控]-…) - B|「登记还活着」短路压过显式前缀(正确优先级应为 显式前缀 > 登记 > 最近活动)
- A|前缀判据不认方括号(代码
stop-collab.py::_gw_port()会把20090(设备接入垫片)误认成网关(真网关 56975)。
§4 当前状态与命令
- 协作机制现指向休眠中的主会话
67dfd365⇒ 投递会「拒投(loud)」。⛔ 别动它、别改它标题。 本棒新会话标题以主控开头 ⇒ 它一跑起来resolve_main()会自动切到它(走prefix:主控)。 ⚠️ 一次性自动化起的会话跑完即completed:它作为 main 只在运行期间有效;要长期接管须在桌面上打开它。 - 四条闸门已全部补回且当天有真实调用(收口 / 技能 / 限流 / 锁)。
state.py的[闸门]段一行看全。 - 开工三件套:
python E:\ProgramData\AIProject\ai1net-dsh-server\state.py bash "D:/github/dsh_shenxian/dsh-server-docs/07-scripts/handoff-guard.sh" --claim-exec "<会话名>" bash "D:/github/dsh_shenxian/dsh-server-docs/07-scripts/handoff-guard.sh" --release-exec "<会话名>"
§5 出处(按需读,别整读)
交付物/查唤醒为什么断-结论-20260930.md|交付物/唤醒的解决方式-官方文档核对与方案分析-20260930.md(§11="5 分钟做不到"的源码依据)交付物/唤醒-本机网关直连测试-20260930.md|交付物/唤醒-会话自建后台任务方案评估-20260930.md交付物/唤醒-idle钩子破解-20260930.md|交付物/唤醒交接-机制能否跟着换主会话-20260930.md|交付物/补回三个闸门-20260930.md- 历史全文:
.workbuddy/memory/2026-09-30.md(同日多棒都在里面,按小节标题找)|自动化记忆:.workbuddy/memory/automations/fb113c35-2cbe-45f0-afb3-4dbf0b1b4ea6/memory.md - 探针脚本:
.workbuddy/tools/idle-hook-probe.py|探针数据:tmp/_idle_hook_probe.jsonl|项目级配置:.codebuddy/settings.json