# 唤醒 · 「上报给主会话」到底是不是唤醒 + 门控该归谁(2026-09-30) > 起因(用户原话):**「会话协作项目中有任何会话在执行时,唤醒定时任务跳过处理(应该是通过 hook),无任何协作队列无任务,且无任何会话执行时,检查目标状态(完成:同时暂停,阻碍:反馈给协作程序 同时暂停,未完成:反馈给协作程序),这样等队列信息上报给主会话时 是不是就唤醒了」** > 判据:文中每条都标了源码位置(`~/.workbuddy/skills/multi-session-collab/scripts/collabd.py`)。 --- ## 0. 结论(三行) 1. **是** —— 但前提是**主会话此刻活着**。因为在这套机制里,**「上报」不是写文件,是投递**;投递落地 ⇒ 主会话多跑一轮 ⇒ 这就是唤醒。 2. **主会话已退出 ⇒ 投不出去 ⇒ 不会唤醒**。那一格只能由**唤醒轮**(自动任务起新会话)覆盖。 3. 你这条规则里,**"有会话在执行就跳过""无队列才查目标""目标三态判定"大半已经是现成实现**(协作程序 `supervise()` / `_deliver_str`);真正**缺**的是两格:**「完成/阻碍 ⇒ 自动暂停」** 与 **「有队列但无会话执行 ⇒ 派棒」**。 --- ## 1. 把「上报」拆成三段 —— 只有第二段会唤醒 | # | 段 | 具体动作 | 会不会唤醒谁 | |---|---|---|---| | ① | **内容** | 写 `tasks.json`(队列本体)、`TO_MAIN.md`(投影)、`blocked.json`、`NEED-USER.md` | ❌ **一个人都叫不起来**(纯落盘) | | ② | **投递** | 钩子 → `POST /api/v1/sessions/<主会话>/reply {text}`(`collabd.py:1058`) | ✅ **这才是唤醒**:主会话多跑一轮 | | ③ | **起会话** | 自动任务(唤醒轮) | ✅ 主会话不在时的**唯一**通道 | > 判据:`supervise()` 先写 `TO_MAIN.md`(`collabd.py:1770`),**紧接着**才 `_deliver_str(txt, "上报·单条", st)`(`collabd.py:1777`)。 > ⇒ **只做了 ① 没做 ②,等于没上报。** 你问的"上报时是不是就唤醒了",答案取决于走没走 ②。 --- ## 2. 你的表述 vs 现有实现(逐格对照) | 你的表述 | 现有实现(位置) | 状态 | |---|---|---| | 有会话在执行 ⇒ 跳过 | `_session_status(目标)=="working"` ⇒ `target-busy` **延后**(`collabd.py:1050`) | ✅ 已有 | | 队列无任务 | `tasks.json` 四态 `pending/running/done/blocked`,**唯一权威**(`collabd.py:852`) | ✅ 已有 | | 无任何会话执行 | 宿主库 `sessions.status='working'`(`_main_state` `collabd.py:1616`;`reconcile` `collabd.py:1644`) | ✅ 已有 | | 检查目标状态 | `goals_open()`:台账非 done **∪** 任务图非 done **∪** `goal.json.acceptance_state` 任一非 pass(`collabd.py:1403`,三路取并集) | ✅ 判据已有 | | 完成 ⇒ 同时暂停 A、B | 现有只有「任务图全 done ⇒ `skipped=all-done` 不再投递」(`collabd.py:754`)——**它⛔不会去暂停自动任务** | 🔴 **缺** | | 阻碍 ⇒ 反馈协作程序 + 暂停 | `task_report(state="blocked", reason=…)`/`need_user()`(`collabd.py:878`/`728`) | ⚠️ 接口有;⛔ 见 §3-② | | 未完成 ⇒ 反馈协作程序 | `goals_open()==True` ⇒ 写差距;现有只在"有活可派/僵住"时才报(`collabd.py:786-798`) | ⚠️ 部分 | | **有队列任务 且 无会话执行** | —— | 🔴 **你的规则没定义这一格** —— 而这正是**最该动**的那一格(有活没人干) | --- ## 3. 落地必须先知道的三个硬约束(源码级) 1. **`reply` 只认 live** ⇒ 主会话退出后投不出去;程序此时**拒绝盲投**(不投给任意会话),只按**工作区**解析,解析不出就 `need_user("找不到主会话…")`(`collabd.py:1038-1049`)。 ⇒ **"上报即唤醒"对已退出的主会话结构性不成立**,且程序的处置是**喊人**,不是自己想办法。 2. **队列只有「投递方」才配改**(`mutate`,`collabd.py:1690-1696`):`--tick`(宿主钩子)是唯一推进方;`--once`/常驻只做投影。⛔ 唤醒轮**不许手改 `tasks.json`**,要用 `task_report` 口径上报,否则会重演「把待反馈项消费掉却不投递」的静默丢件。 3. **"跳过"是零 token 的**:投递前的否决(`same-item` 内容哈希去重 / `too-soon` 最小间隔 300s / `target-busy`)都在**钩子进程内**完成,不碰会话、不烧 token(`collabd.py:960-967`)。⚠️ 但钩子**拦不住自动任务起会话**——automation 无条件触发,所以唤醒轮"起来后发现有人在跑就立刻退"仍靠**域锁**。 --- ## 4. 完整闭环:两半合起来才闭合 | 主会话此刻 | 谁把它叫起来 | 延迟 | 成本 | |---|---|---|---| | **活着 · 空闲** | 钩子**投递**(`reply`) | 秒级~分钟 | 到投递前零 token | | **活着 · 执行中** | **不打扰**(`target-busy` 延后,等它空闲) | 等它空 | — | | **已退出**(worker 已回收) | **唤醒轮**(自动任务起新会话) | ≤30 分钟 | **一个新会话** | > ⇒ 所以「等队列信息上报给主会话时就醒了」——**对"活着"那行成立,对"已退出"那行不成立**;后者靠唤醒轮。 ⚠️ **代价(源码里写着的一句话,必须知道)**:`collabd.py:857-860` 注释—— > 「每次投递都会唤起主会话跑一轮 ⇒ 用户发消息撞 busy ⇒ 体感"卡"」 ⇒ **"上报即唤醒"=会占用主会话 ⇒ 必须节流**。现有的四道节流:**单条+握手**(一次只反馈一条,等它执行完才发下一条)/**内容哈希去重**/**最小间隔 300s**/**真停滞门槛 15 分钟**(`HEARTBEAT_MIN_IDLE`,有进展一条都不发)。⛔ 落地时不许把这四道拆掉。 --- ## 5. 落地:要补的两格(其余照抄现成) ``` 唤醒轮起来 → ① 抢域锁(抢不到 = 有人在推进 ⇒ 立即结束,零成本跳过) → ② 读队列 tmp/supervise-inbox/tasks.json → ③ 读会话:宿主库 sessions.status='working'(cwd=本工作区,排除自己) → ④ 读目标:tasks.json 非 done ∪ taskgraph.json 非 done ∪ goal.json.acceptance_state 任一非 pass ``` | 格 | 条件 | 动作 | |---|---|---| | A | 有队列任务(pending/running)**且** 无会话执行 | **派一棒**(起一个会话去干)← 🔴 **你原规则缺的这格** | | B | 无队列 **且** 无会话执行 · 目标**未完成** | 把差距写进 `tmp/supervise-inbox/`(⛔ 不手改 `tasks.json`) | | C | 无队列 **且** 无会话执行 · 目标**有阻碍** | 写清"要用户做什么" + **A、B 两条排期一起置 `PAUSED`** | | D | 无队列 **且** 无会话执行 · 目标**已完成** | **A、B 两条排期一起置 `PAUSED`** ← 🔴 **现成实现没有这一格** | | E | 判不准 | 按 B 处理(宁可空转一轮,⛔ 不许造活) | **A/B 排期 id**(自我暂停时用;⛔ 只改 `status`,不动 `rrule`): - 唤醒轮 A `caca9a89-fa82-48e1-a55c-7e0f3a06bd48` | 唤醒轮 B `16bec5ce-98c0-470c-afa9-6f5a06218068` --- ## 6. 一句话速记 > **上报(写文件)≠ 唤醒;投递(钩子把文字推进活着的会话)才=唤醒。** > 主会话活着 ⇒ 秒级唤醒(但要节流,否则把它顶"卡");主会话退出 ⇒ 钩子也没了,只剩唤醒轮起新会话(≤30 分钟)。 > 判据一句:**"有会话在执行就跳过"= `sessions.status=='working'` 或 域锁被占。** --- ## 附:图 见同目录 `唤醒-上报即唤醒与门控归属-20260930-图.html`(① 三段拆解图:标出哪一段才唤醒;② 门控矩阵图:标红两格缺失)。