chore(工作区): 全量入库 + 补齐 .gitignore(以工作区为准)
- 变更规模:新增 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/ 知识文件,按口径入库)
This commit is contained in:
1 parent
30b46dbd0c
commit
c1b5e4d966
735 files changed
+153192
-2415
No files matched your search
@@ -0,0 +1,276 @@
|
||||
# 自动化执行记忆 · fb113c35(「查唤醒为什么断」接续棒)
|
||||
|
||||
## 2026-09-30 12:0x–12:2x(第 1 次执行)
|
||||
|
||||
**任务**:只查「唤起主会话的定时闹钟为什么停」,读完即停,⛔ 不扩范围。
|
||||
|
||||
**结论(一句话)**:**不是断了,是从头到尾一次都没响过。** 网关 `scheduled-tasks` 在 WorkBuddy 桌面端是**死能力**:
|
||||
宿主硬编码 `CODEBUDDY_DISABLE_CRON=1` ⇒ CLI 调度器 `start()` 第一行 return;且 `start()` 是唯一 `setStorageDir()` 处 ⇒
|
||||
`durable:true` 的写入是**静默空操作**(仍回 `200+id`)。⇒ 三条任务全部无效。
|
||||
|
||||
**关键读数**:
|
||||
- `tmp/supervise-inbox/_wake.stamp` **不存在**(`b08da6c4` 11:47 / `91f8baeb` 11:53 都没来过)
|
||||
- `CODEBUDDY_DISABLE_CRON='1'`;源码出处 `app.asar /main/code-cache.js` 的 `buildAgentCliRuntimeEnv()` + `buildCliEnvFromResolved()`
|
||||
- `.codebuddy/scheduled_tasks.json` 全盘不存在
|
||||
- 实测:non-durable POST 立刻可见(**进程内**,各口互不可见);durable POST 立刻不可见且不落盘
|
||||
- 真网关=**56975**(pid 50716),uptime≈41,850s **未重启**;旧读数 `28317` 是**别家服务**(假线索)
|
||||
- 本机 **3 个** 网关口:55283 / 56510 / 56975 —— `_gw_port()` 升序取首个 ⇒ 实际命中 **55283**(非主会话宿主)
|
||||
|
||||
**产出**:`交付物/查唤醒为什么断-结论-20260930.md`(含泳道图 + 事故链图)
|
||||
**附带修正**:`gateway-schedules.json` 现役清空、3 条入 `_历史` 标死因;技能 `workbuddy-extension-surface` → v1.8.0(§1.4 加硬阻断)
|
||||
**未做**:⛔ 未重启网关/宿主;未动 8788 看板与中继客户端;口令未落盘未回显;探测任务已全清。
|
||||
**待用户拍板**:5 分钟级唤醒做不到(自动化最小 1 小时);1 小时级可行=自动化 + `/sessions/{id}/reply`。
|
||||
|
||||
**下次若再跑这条线**:
|
||||
1. ⛔ 别再试网关 `scheduled-tasks`(已定案死能力)
|
||||
2. 先读 `交付物/查唤醒为什么断-结论-20260930.md`,别重做取证
|
||||
3. 若要"叫醒闲置会话",正解=自动化(最小 1 小时)调 `POST /api/v1/sessions/{id}/reply`;先问用户
|
||||
|
||||
---
|
||||
|
||||
## 2026-09-30 12:2x(同会话续做 · 用户追加三问)
|
||||
|
||||
**追加需求**(同一条线,用户连问):① 唤醒节点在看板消失 ② 看板没把本会话识别为主会话 ③「可以重启」④ **「要把其他看板服务关了 避免打架」**
|
||||
|
||||
**①②已修**:`board_ext.py::_triggers()` 无现役时回落 `_历史` 并强制不绿、标「通道已停用」;`board.py::project_scope()` 改用与 `collabd.py` 同款的 `_resolve_main()`(按工作区 +「主控」前缀)⇒ 看板 `main_sid8=6ecf6d98`。
|
||||
|
||||
**④ 的结论(本次重点)**:清点后**只有 1 个看板服务**(8788/PID 29648),**没有"其他"可关**。但查出了真根因:
|
||||
🔴 **Windows 上 `SO_REUSEADDR` 允许同端口重复绑定且不报错**(`ThreadingHTTPServer` 默认 `allow_reuse_address=1`)
|
||||
⇒ 多个 `board.py --serve` **静默并存**、同一 URL 被**随机**应答 ⇒ 快照/代码版本**打架**(判决性实验:8788 已占用时第二个实例照样打印「看板已起」)。
|
||||
|
||||
**已落地护栏**:`board.py` 起前探 `/healthz` 签名(`"ok"` + `"snapshots"`)⇒ 已有就**拒绝启动**;新增 `--takeover`;
|
||||
`stop-collab.py` 新增 **④ 看板服务**(列全所有实例并可一键停)。文档:`pitfalls.md` **P0-9** + `architecture.md`/`SKILL.md`「当前结论」+ 技能 **v1.1.1**。
|
||||
回归自测 **PASS 28 / FAIL 0**。⛔ 未重启现役看板(只改启动期逻辑,快照内容未变)。
|
||||
|
||||
**产出**:`交付物/看板多实例打架-排查与护栏-20260930.md`(含泳道图 + 事故链图 + 防线盘点)
|
||||
|
||||
**下次若再遇到"看板内容是旧的/不对"**:
|
||||
1. **先数实例**:`netstat -ano | grep 127.0.0.1:8788 | grep LISTENING`(多行=并存)+ `stop-collab.py` 看 ④ 项
|
||||
2. ⛔ **别拿"日志没报 10048"当"没有重复"** —— 没有报错正是这个坑的特征
|
||||
3. 换代码重启用 `board.py --serve 8788 --takeover`,⛔ 别裸起第二个
|
||||
4. ⛔ 别顺势关掉 `allow_reuse_address`(强杀后会留 TIME_WAIT ⇒ 重启必失败)
|
||||
5. ⚠️ 遗留未处理:`stop-collab.py::_gw_port()` 会把 `20090`(设备接入垫片)误认成网关(真网关 56975)—— 本轮登记册为空所以没误删,建议另开一棒核。
|
||||
|
||||
---
|
||||
|
||||
## 2026-09-30 12:3x(同会话续做 · 「唤醒」方案分析 + 官方文档)
|
||||
|
||||
**需求**:分析唤醒的解决方式;查官方文档;若没办法,能否"用一个会话当主会话 + 手机给当前会话发消息"唤醒。(用户补:手机是经 **gateway** 连的。)
|
||||
|
||||
**官方文档结论**:
|
||||
- `Automation-Guide`:自动化=**本地**定时;**没有分钟级**(只举每周/每月);官方只写"时间规则"("条件触发"是非官方说法,**未证实**)。
|
||||
- `WeixinBot-Guide` / `Wecom-Guide`:🔴 **官方有"手机发消息→电脑执行"**,且 **「助理(远程任务):仅一个会话,所有远程指令集中处理」** ⇒ **就是用户设想的形态**。企微支持群聊 @机器人。版本门槛 ≥4.6.4,**本机 5.6.2 ✅**,但**未启用**。
|
||||
- ⇒ **官方没有第三条时间通道**:定时(≥1h)+ 手机发消息(人驱动,粒度任意)。
|
||||
|
||||
**本机实测(只读)**:口令在环境|垫片 20090 在听|网关 56975 活着、`cwd` 正是本工作区|🔴 **`/sessions/live` = `fe146dd9`(writerOccupied),不是主会话 `6ecf6d98`**。
|
||||
|
||||
**判定**:用户方案 **✅ 可行**(通路已建成、V2 已验收);**唯一硬前提 = 目标必须是 live**(否则 409,且不许抢 writer)。**5 分钟级自动**只能靠**外部定时器**走同一条 443 通道。
|
||||
|
||||
**产出**:`交付物/唤醒的解决方式-官方文档核对与方案分析-20260930.md`
|
||||
|
||||
**下次若再碰"唤醒"**:
|
||||
1. 先跑 `GET /api/v1/sessions/live`(读)—— **"主会话"是不是 live 决定手机能否投到**;不是 live ⇒ 什么都别试,先让桌面上打开它
|
||||
2. ⛔ 非 live 时**不要**改走 ACP 借用(writer 占用时夺不了,T2 禁止抢)
|
||||
3. ⛔ 别再指望网关 `scheduled-tasks`/分钟级自动化/钩子做定时
|
||||
4. 官方那条(微信/企微助理)与自研 443 通道是**两条路**,助理**只能进它自己那一个会话**、cwd 也不在本项目
|
||||
|
||||
---
|
||||
|
||||
## 2026-09-30 13:0x(同会话续做 · 用户提出「间隔 5 分钟自动运行的会话」)
|
||||
|
||||
**用户原话**:「明白了 这个方案 一个会话不能多个主会话同时执行,所以还是只能回到 自动任务, 考虑在主会话 工作区下创建 间隔5分钟自动运行的会话」
|
||||
|
||||
**判定:做不到**(源码级,非推断)。报告 §11 已写全,技能 `workbuddy-extension-surface` → **v1.8.1**(§1.4 加「自动化最小 1 小时的源码级依据」表)。
|
||||
- **粒度不存在**:`app.asar /main/log-acl-guard.js` `parseRRule` 的 `FREQ` 是**硬白名单**(HOURLY/DAILY/WEEKLY/MONTHLY/YEARLY);全包 `MINUTELY`/`SECONDLY` **命中 0**;源码注明三处实现必须同步改;`HOURLY` 的 `formatRRule` 不产出 `BYMINUTE` ⇒ 一律落整点。
|
||||
- **代价**:一次自动化运行=一个**新会话**(`automation_runs` **74/74**)⇒ 5 分钟 = **288 会话/天**。
|
||||
- **关键一条**:自动任务会话 **≠** 唤醒主会话;要真唤醒仍须 `reply`,而 `reply` **只认 live** ⇒ 绕回同一硬前提。
|
||||
|
||||
**三档**:① 1 小时自动化(现成)|② 外部定时器走 443 通道(**唯一能 5 分钟且 0 新会话**,需单独评审)|③ 手改 DB 塞 BYMINUTE(⚠️未验证,会成幽灵任务风险)。
|
||||
|
||||
**未做**:⛔ 未创建任何自动化(属"需用户确认"类,⛔ 不自行建)|⛔ 未手改 DB|⛔ 未发 reply。
|
||||
|
||||
**下次若再碰这条线**:
|
||||
1. ⛔ 别再试"5 分钟自动化" —— 已定案做不到(`FREQ` 硬白名单,源码级)
|
||||
2. 直接读 `交付物/唤醒的解决方式-官方文档核对与方案分析-20260930.md` **§11**,别重做取证
|
||||
3. 用户若仍要 5 分钟 ⇒ 唯一出路是**外部定时器 + 443 通道**(档 ②),报用户拍板
|
||||
4. ⚠️ "主会话必须 live"是绕不过的硬前提
|
||||
|
||||
---
|
||||
|
||||
## 2026-09-30 12:5x(同会话续做 · 本机 gateway 直连「唤醒」实测)
|
||||
|
||||
**用户指令**:不用走代理,把唤醒做成程序调用**本机** WorkBuddy gateway,**就用当前会话**测试。
|
||||
|
||||
**结果:通了。** 成品 `$WS/.workbuddy/collab/wake-session.py`(零依赖,枚举回环口→三判据指纹→取 live→按 `live.sessionId==目标` 匹配→`reply`)。
|
||||
本会话 `6ecf6d98` 的网关=**`127.0.0.1:59486`**(pid 52460)⇒ **HTTP 200 `{"delivered":true}`**。
|
||||
|
||||
**两条必记**:
|
||||
1. 🔴 **判指纹 ⛔ 不能带凭据**(带 `x-access-token` ⇒ `/health` 从 401 变 200 ⇒ 判据全灭)。这条同时是「真网关 vs 垫片 20090」的唯一分水岭。
|
||||
2. 🔴 **`delivered:true` ≠ 已唤醒** —— busy ⇒ 入队等空闲边界;⚠️ **本棒唯一未决项=那条注入消息是否真作为用户消息现身**(下一棒第一件事可核)。
|
||||
|
||||
**口径修正**:本机 3 个网关口**各服务一个 live 会话** ⇒ 必须按 live 会话匹配,⛔ 升序取第一个必错。
|
||||
|
||||
**结论变更**:用户补充「会话后台任务能给自己发消息」=对,且它跑在 WorkBuddy 进程树内 ⇒ **能继承口令** ⇒ **5 分钟唤醒从"做不到"变"可达(零新会话)"**;⚠️ 与 T1 有字面冲突(完全静默即满足本意)⇒ 须用户拍板。
|
||||
|
||||
**下次若再碰这条线**:
|
||||
1. 直接用 `wake-session.py --list` 现查网关(⛔ 别记端口),再 `--session current --dry-run` 验前置
|
||||
2. ⛔ 别带凭据判指纹;⛔ 别把 `delivered:true` 当"会话已醒"
|
||||
3. 先读 `交付物/唤醒-本机网关直连测试-20260930.md`
|
||||
|
||||
---
|
||||
|
||||
## 2026-09-30 12:5x–13:0x(同会话续做 · 「唤醒」两条线都实测闭合)
|
||||
|
||||
**用户两条追加指令**:① 「先用 gateway 那条线测试…都在本机环境处理即可,把唤醒做成程序调用本机 workbuddy gateway,就用当前会话测试」② 「不考虑 gateway,专门做『会话创建后台任务』的方案评估测试」
|
||||
|
||||
**① gateway 线(已完成)**:`.workbuddy/collab/wake-session.py`(现查端口 → 三判据指纹 → 按 `live.sessionId==目标` 精确匹配 → `POST /reply`),对本会话 `59486` 实测 **HTTP 200 `{"delivered":true}`**。
|
||||
两条硬教训:**判指纹 ⛔ 不能带凭据**(带 `x-access-token` 时 `/health` 由 401 变 200,判据全灭;而这正是「真网关 vs 垫片 20090」的唯一分水岭)|**本机并存多个网关口、每个只服务自己那一个 live 会话** ⇒ 必须按 live 匹配。
|
||||
|
||||
**② 后台任务线(已完成,4 组对照)**:A(有输出)/ B(**0 字节静默**)/ C(中途输出 + 静默完成)/ D(`sleep 300` 静默)。全部一次性任务。
|
||||
🔴 **三条定死**:**唤醒 =「任务完成」事件,与 stdout 无关**(B 静默也唤醒;C 的中途 2 次输出都没唤醒)|**静默安全**|**300 s 不被沙箱回收**。
|
||||
⛔ **头号推论**:**常驻循环 + 周期 echo 当不了脉冲**(永不完成 ⇒ 永不唤醒)。
|
||||
✅ **纠正旧因果**:09-29 的"看着像卡"**不是**"输出唤醒导致" ⇒ 是**输出把转录推过 10 MiB ⇒ diagnostic-log dropped**。
|
||||
|
||||
**产出**:`交付物/唤醒-会话自建后台任务方案评估-20260930.md` + `交付物/唤醒-本机网关直连测试-20260930.md`;技能 `workbuddy-extension-surface` → **v1.8.3**。
|
||||
|
||||
**下次若再碰「唤醒」**:
|
||||
1. 先问:"要唤醒**哪个**会话?它现在 **live** 吗?"(live 是 gateway 路的硬前提;后台任务路只唤醒**自己**)
|
||||
2. ⛔ 别再试 5 分钟级别的**自动化**(rrule 硬白名单,最小 1 小时);⛔ 别试网关 `scheduled-tasks`(桌面端死能力)
|
||||
3. 要 5 分钟 ⇒ 三条已实测路: gateway `reply`(0 新会话)/会话自建**一次性** `sleep N` 后台任务(0 新会话,绑会话)/外部定时器
|
||||
4. ⛔ **别用常驻循环 + 周期 echo**(实测不唤醒);常驻必须完全静默且靠它自己调 `reply`
|
||||
5. ⚠️ 本会话转录日志 12:26 起已冻结(10 MiB 天花板)⇒ 别再拿它当"体积度量"
|
||||
|
||||
## 2026-09-30 13:0x(同会话续做 · 追问「能不能持续」→ 实测闭环)
|
||||
|
||||
**用户两问**:①「后台任务不能持续运行吗」②「一次性任务完成后继续创建,这样就能持续?」
|
||||
|
||||
**🔴 结论(两件事必须分开)**:
|
||||
- **能长跑**:后台任务进程**不随本轮结束被杀**(实测 E1:上轮起的常驻静默心跳循环,跨轮仍在跳)。
|
||||
- **但长跑 ≠ 唤醒**:唤醒只认「完成」⇒ 常驻循环永不完成 ⇒ 永不被唤醒(同一实验里它吐过心跳,`updated_at` 没动)。
|
||||
- ⛔ **自举续命两条路都堵**:任务内 `nohup &` ⇒ detached spawn 死;任务内循环 ⇒ 不完成。
|
||||
- ⛔ **持久化兜底封死**:沙箱回收子进程 + 程序黑名单(`wsl/wslconfig/wmic/sc/reg/schtasks`)⇒ 常驻唯一可行起法=**会话后台任务 + stdout 全重定向**。
|
||||
- ✅ **链式续棒成立**:第 1 棒 `fired 13:09:12`(唤醒)→ **我在那一轮起第 2 棒** → `fired 13:10:31`(照样唤醒)。代价=**每棒一轮 AI**(5 分钟=288 轮/天)。
|
||||
- ⇒ 想"常驻也能唤醒"⇒ 只有**它在循环里主动调 `reply`**(两线汇合)。新工具 `.workbuddy/collab/wake-pulse.sh <秒数>`。
|
||||
|
||||
**收尾**:⛔ 未让链继续跑(演示到第 2 棒即停);E1 已 kill;`ps` 无残留;技能 → v1.8.4。
|
||||
|
||||
---
|
||||
|
||||
## 2026-09-30 17:2x–17:5x(同会话续做 · 用户:「能否伪造 hook 执行 上报给主会话,破解一下」)
|
||||
|
||||
**🔴 结论:不用伪造 —— 官方本来就有「空闲」钩子事件。**
|
||||
|
||||
**一、三条「外部程序→任意会话」通道本棒全部实测判负**(⛔ 后人别再重做):
|
||||
① `/sessions/{id}/reply` 只认 live,非 live ⇒ `parkInQueue`+`hasWaiter=false`(4.5 h 无反应);
|
||||
② `/jobs/{id}/reply` 写 `jobs/<id>/inbox/*.json` 但 **worker 从不 drain**(400 ms 轮询+目录监听,9 min 整窗零动作);
|
||||
③ `stop→reply(pending)→respawn`:pending 真写出 ✅、respawn 真消费 ✅、文本真 unshift 进 `["--resume",sid]` ✅,**但 worker 卡 `resuming…`**;**换未删除会话 A/B 对照同样卡**(否掉"靶子已删除""cwd 争用")。
|
||||
✅ 顺带探明原语:`POST /api/v1/runs` + `{id,type:"message",text}` ⇒ 202 `{runId}`,`[GatewayAcpBridge] got session …`(绑"网关自己服务的会话",仍需 live)|`/api/v1/process/start`|`/api/v1/team/messages/send`(成员 2 s 轮询)。
|
||||
|
||||
**二、突破:idle 钩子(源码原文)** —— `resetIdleTimer` 里 `setTimeout(… executeNotificationHooks(L,"CodeBuddy is waiting for your input", IDLE_PROMPT), 6e4)`
|
||||
⇒ **会话空闲满 60 s ⇒ 宿主自己 spawn `Notification` 钩子**(`notification_type="idle_prompt"`);matcher 用 `^idle_prompt$`;天然闸门=忙/有后台任务就不发;同族 `permission_prompt`/`auth_success`。
|
||||
**为什么=无人值守**:触发=宿主自己的 60 s 定时器|唤醒对象=**会话自己**(不用切窗口)|子进程 ⇒ 零 token、不产生新会话。
|
||||
**能上报已实测**:探针日志 `gateway_password_present: true` + `CODEBUDDY_SESSION_ID` 在环境里 ⇒ 可走 `wake-session.py` 投回自己;触发那刻**正 idle** ⇒ `hasWaiter=true` ⇒ **即时生效**。⚠️ 别混 PTY 服务那个空闲定时器(`CODEBUDDY_PTY_IDLE_TIMEOUT_MS`)。
|
||||
|
||||
**三、已落地(安全可逆零注入)**:`.workbuddy/tools/idle-hook-probe.py`(只记一行 JSON;自测 rc=0 ✅)+ **项目级** `.codebuddy/settings.json`(⛔ 不装全局);全局配置未改、已备份 `settings.json.bak-idleprobe-20260930-175112`;本轮 3 个实验 worker 全 `stopped`、`GET /jobs` 活跃 0、无残留进程 ✅。
|
||||
|
||||
**四、未坐实 + 待拍板**:⚠️「60 s 空闲→真 spawn」仍为源码级(本会话整轮在跑工具,不可能 idle;新建项目级 settings 可能要新会话才加载)⇒ **下一步:在本工作区新起的会话空闲 ≥60 s 后,读 `tmp/_idle_hook_probe.jsonl` 是否新增行**(无行 ⇒ 退路改全局 `Notification`)。
|
||||
🔴 **待用户拍板(一轮一问)**:要不要把探针升级为「空闲即唤醒主会话」?代价=约每 60 s 一轮、最坏 **1440 轮/天**;倾向**先只留探针**。若开必须三道闸门(总开关文件/同会话退避/唤醒后只做一件可判的事),⛔ 不做无限自唤醒、⛔ 不挂全局。
|
||||
|
||||
**五、教训**:🔴 判"通没通"只认**端到端跑出了一轮**,⛔ 不许拿 200/`delivered:true`/`active:true` 当闭环。
|
||||
|
||||
**技能**:`workbuddy-extension-surface` → **v1.8.6**(新增 §1.3b)。产出:`交付物/唤醒-idle钩子破解-20260930.md`。
|
||||
|
||||
---
|
||||
|
||||
## 2026-09-30 17:55(同上条会话 · 🔴 反转)
|
||||
|
||||
**事件**:17:49 用 `POST /api/v1/runs` 投出的自检文本,**17:55 真的作为「用户消息」送到本会话**。
|
||||
|
||||
**⇒ 上一轮的判词错了**:`runs` **不是**「busy 挂住不动」⇒ 正确=**「会话忙时排队,一旦空闲立刻交付」**(会话就此跑起一轮)。
|
||||
🔴 `active:true` ≠ 挂死,是**在等交付时机**。**外部程序可以叫醒会话、不需要人切窗口** —— 这条能力**成立**。
|
||||
🔴 与 `sessions/{id}/reply` 的分水岭=**有没有消费者**(`runs` 走 `GatewayAcpBridge`,waiter 真被消费;`reply` 非 live 只是 `parkInQueue`)。
|
||||
⚠️ **本棒教训(我又踩了一次)**:拿 `active:true` 判"死" —— **判据永远只认「端到端跑出了一轮」**。
|
||||
|
||||
**idle 钩子负向读数**:本会话 17:52→17:55 有 ~2.5 分钟真空闲窗(>60 s),`tmp/_idle_hook_probe.jsonl` **无新增行** ⇒ **项目级 `.codebuddy/settings.json` 对已运行会话不生效**(全局的是热生效)。⇒ 待新会话坐实,或经确认后改挂全局。
|
||||
|
||||
**待拍板已更新为三选项**:① 只留探针(倾向)|② **外部定时器 → `runs`**(投递半已证实可用,缺的只是定时器)|③ idle 钩子 → `runs` 自己(闭环但最坏 1440 轮/天,且要先解决装哪里)。
|
||||
|
||||
**已改档案**:报告 §0/§1(§1.5)/§5/§7 + 技能 §1.3b + 当日记忆。⛔ 未改全局配置、⛔ 未开任何自动唤醒。
|
||||
|
||||
---
|
||||
|
||||
## 2026-09-30 18:03–18:25(同会话续做 · 用户:「创建接续主会话后 能否在接续主会话上继续这个机制,旧的主会话停」)
|
||||
|
||||
**结论(三句)**:
|
||||
1. ✅ **能,创建那一刻就自动换了** —— 新起的「接续主会话」`67dfd365`(一次性自动化 `42be9561`,18:11 起、18:12 跑完)一出现,`resolve_main()` 立刻从 `fe146dd9` 切到它(依据 `prefix:主控`)。**零额外动作。**
|
||||
2. 🔴 **换不换只看一件事:`roles` 里登记为 main 的那条,此刻在不在活会话集合里。** 在 ⇒ **钉死**(实测场景④⑤:新主会话被完全无视);不在 ⇒ 立刻换。⚠️ **另一条老会话开着不影响**。
|
||||
3. 🔴 **换过去 ≠ 投得进去** —— 新主会话跑时自带网关口(`64766`,`live=67dfd365`),**跑完口即消失** ⇒ 现在投递被拒 `no-live-match`。⇒ **交接必须交给"正在跑 / 已被打开"的会话**,这正是历史上"静默断链"的成因。
|
||||
|
||||
**两个真缺陷(⛔ 本棒未改:机制层、须独占锁、属额外发现 ⇒ 只报告)**:
|
||||
- **A|前缀判据不认方括号**:代码 `startswith("主控")`,实际标题是 `[主控]-…` ⇒ 判 False ⇒ 主会话只能靠"最近活动"兜底 ⇒ **本工作区任何一条会话活动更新就静默顶掉它**。
|
||||
- **B|「登记还活着」短路压过「显式前缀」** ⇒ 旧窗口还开着,新主会话**永远接管不了**(正确优先级应是 显式前缀 > 登记 > 最近活动)。
|
||||
|
||||
**已排除的疑似缺陷**:`discover_gateways()` 看 2 口 vs `--list` 看 3 口 ⇒ **不是缺陷**(前者按 `cwd==本工作区` 过滤)。
|
||||
|
||||
**产出**:`交付物/唤醒交接-机制能否跟着换主会话-20260930.md`(泳道图+事故链图)|`tmp/_resolve_probe.py`/`_resolve_probe2.py`(只读)|`tmp/_handover/67dfd365-receipt.md`(新主会话自己的回执)。技能 `multi-session-collab` → **v1.1.2**(新增 §1.4b)。
|
||||
|
||||
**⛔ 未做**:未改共用机制代码、未改任何配置、未删会话、未动锁。
|
||||
⚠️ **留下的状态**:机制现指向 `67dfd365`(休眠中)⇒ 下次投递会报"主会话不在活会话里"并**拒投(loud,不静默)**。回退:把它的标题改掉、不再以 `主控` 开头即可。
|
||||
|
||||
**下次若再碰「交接/换主会话」**:
|
||||
1. 直接读 `交付物/唤醒交接-机制能否跟着换主会话-20260930.md`,别重做取证
|
||||
2. 判据一句话:**`roles:main` 那条还在不在活会话里** —— 在就钉死,不在就换
|
||||
3. ⛔ 别再新建带方括号的 `[主控]` 标题(会静默降级)
|
||||
4. 若要修 A/B ⇒ 属机制层,**必须拿独占锁、单独一棒**;`collabd.py` 的 `resolve_main` §1545 / `_follow_main` §1598 / `_deliver_str` §938
|
||||
|
||||
---
|
||||
|
||||
## 2026-09-30 18:27–18:45(同会话续做 · 「上下文到量就开接续会话的机制没运行,强化一下」)
|
||||
|
||||
**🔴 根因(实物证据)**:脚本没坏,**触发源被整段删掉**。`settings.json` 在 **09-26 21:17** 被一次无关改动**清空整个 `hooks` 段**(备份 `bak-decision-20260927-233116` 的 `hooks = {}` 为证)⇒ `stop-dialog-guard.py`(水位/收口唯一触发源)+ 另外三个闸门一起掉线 ⇒ **静默 4 天**(guard 日志最后一行 09-26 19:19)。
|
||||
🔑 **机制事实**:水位告警走 **`UserPromptSubmit`** 事件(`Stop` 那条只拦征询句收尾,且本机日志 `Stop`×0 ⇒ 从未生效)。
|
||||
|
||||
**为什么没被发现**:guard 自带 `path_health()` 读 `~/.workbuddy`(**本机真根是 `CODEBUDDY_CONFIG_DIR=E:/ProgramData/.workbuddy`**)⇒ 恒静默;`state.py` 当时没有钩子注册这一节。
|
||||
|
||||
**已做**:① `settings.json` 补回 `UserPromptSubmit → stop-dialog-guard.py`(⛔ 命令**不加 `-E`**);备份 `bak-restoreGuard-20260930-183244` ② `state.py` 加 **§5.5【闸门】自检**(关键闸门挂没挂 + 在册清单 + 钩子路径 exists,认 `CODEBUDDY_CONFIG_DIR`)③ 端到端实测:喂模拟载荷 ⇒ 正确输出 `additionalContext`(20 万告警 + 24.5 万 token 读数)。
|
||||
|
||||
**产出**:`交付物/接续机制未运行的根因与强化-20260930.md`|技能 `workbuddy-extension-surface` → **v1.8.7**(§1.3c)。
|
||||
|
||||
**下次若再碰「钩子机制突然不工作」**:
|
||||
1. 先跑 `state.py` 看 `[闸门]` 一行;再 `tail -5 <该钩子的日志>`,**最后一行时间 = 它停止工作的时刻**
|
||||
2. 与同目录 `settings.json.bak-*` 比对 **mtime + `hooks` 内容** ⇒ 定位"哪一刻被清空"
|
||||
3. ⛔ 别只改配置就算完 —— **必须喂模拟载荷端到端实测**(判据只认"钩子真的产出了注入")
|
||||
4. ⛔ 装钩子命令**别加 `-E`**;⛔ 读配置别只认 `~/.workbuddy`
|
||||
|
||||
---
|
||||
|
||||
## 2026-09-30 18:37(同会话 · 收口汇报)
|
||||
|
||||
**本棒性质**:无新动作,只做**复述结论 + 交付 + 收口**。state.py 复核:`[锁] 空闲✅`、`[闸门] ✅ 关键闸门在册 | PreToolUse×2 SessionEnd×2 SessionStart×1 UserPromptSubmit×3`。
|
||||
**交付**:`交付物/接续机制未运行的根因与强化-20260930.md`、`交付物/唤醒交接-机制能否跟着换主会话-20260930.md`(含泳道图+事故链图)。
|
||||
**唯一待拍板(一轮一问)**:另外三个闸门(锁纪律 / 技能加载 / 输出限流)是否一并补回?默认=**先只保接续机制**(已按此执行)。
|
||||
⛔ 未动:另外三个闸门、`stop-dialog-guard.py`、`67dfd365` 的指向、锁(已释放)。
|
||||
|
||||
---
|
||||
|
||||
## 2026-09-30 18:40–18:55(同会话 · 用户拍板「A」⇒ 三闸门已补回)
|
||||
|
||||
**用户原话**:「**A**」。⇒ 除接续机制外,另外三个闸门**一并补回**并逐条端到端跑通。
|
||||
|
||||
**注册表复原法(⛔ 别凭记忆抄)**:去 `归档/**/settings.json.bak*` 找**唯一还留着完整 `hooks`** 的那份**逐字复原**
|
||||
(本次=`归档/文档整理/dsh-server-docs-微调-20260924/settings.json.bak`,mtime 09-24 06:01)。补回 4 条:
|
||||
`PreToolUse(Write|Edit)→lock-guard-hook`|`PreToolUse(Bash|Read)→bash-output-guard`|`SessionStart(startup|resume)→lock-guard-hook`|`UserPromptSubmit→skill-load-guard`。
|
||||
现状 `✅ 关键闸门在册 | PreToolUse×4 SessionEnd×2 SessionStart×2 UserPromptSubmit×4`(12 条 exists 全绿)。
|
||||
|
||||
**端到端证据**:我自己的 Edit/Write 触发 `lock-hook.log` 18:40:24/25/31;自己的 Bash 触发 `bash-guard.log` 18:40:34/46;
|
||||
直喂 3.6 MB 文件 ⇒ `deny`+等价写法;4.6 KB ⇒ 放行;`skill-load-guard` 直喂点名载荷 ⇒ 产出 `additionalContext`。
|
||||
|
||||
**🔴 两处体检缺陷已修**(`stop-dialog-guard.py`):① `path_health()` 认 `CODEBUDDY_CONFIG_DIR`(原先恒静默)② `guard_health()` 加 `_fresh()` 只认近 24h(原先拿 09-26 陈旧 DENY 报"最近 4 次被拦")。
|
||||
⇒ **本轮开场那条【门禁自检】是假警报**,⛔ 别据此把 `bash-guard-mode` 写 `off`。
|
||||
|
||||
**下次若再碰「闸门/钩子」**:
|
||||
1. 先跑 `state.py` 看 `[闸门]` 两行(在册数 + **四条日志最后一行时间**)——陈旧=掉线,别只看注册表
|
||||
2. 补注册表去向 `归档/**/settings.json.bak*` 找完整副本,⛔ 不凭记忆;`matcher` 必须与脚本分支一致(`bash-output-guard` 要 `Bash|Read`)
|
||||
3. 遇【门禁自检】先核**时间戳**再动作
|
||||
4. ⛔ 别加 `-E`;⛔ 别信"必须完全重启"(实测热生效)
|
||||
|
||||
Reference in new issue
Block a user