Files
dsh_ai1net_server/交付物/唤醒-统一唤醒出口-20260930.md
admin c1b5e4d966 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/ 知识文件,按口径入库)
2026-10-10 23:13:22 +08:00

7.9 KiB
Raw Permalink Blame History

统一唤醒出口(2026-09-30)

用户口径(本轮): 「自动任务(符合条件时)是通过 协作程序去唤醒 主会话,这样流程统一」 + 「技能里已写明『投递不靠自动任务』:这个过时了,现在允许自动任务」 落地物:goalctl.py wake(新)+ 两条排期改名/改提示词 + 技能侧过时规则纠偏。全文读数均为实测。


0. 结论(三行)

  1. 🔴 判据一句话:「唤醒(投递)」这个动作只有一个出口 = 协作程序;区别只在**"谁拨这一下"** —— 钩子(有会话在动时)/自动任务(谁都没动时的时钟缺口)。⇒ 这就是"流程统一"。
  2. 自动任务只准当闹钟:goalctl wake ⇒ collabd --tick。⛔ 不自己判条件、⛔ 不自己派活、⛔ 不自己起新会话 —— 除非闹钟报"没有可唤醒的对象",才降级。
  3. 技能侧那条旧规则(「投递 ⛔ 不靠自动任务排期」)已按用户口径改为「允许,但当闹钟」(4 处)。

1. 统一后的流程

                      ┌─ ① 宿主钩子(事件)──┐        ← 有会话在动时,够用
   需求在途 ──需要唤醒─┤                       ├─→ 协作程序(唯一唤醒出口)─→ reply 唤醒【主会话】
                      └─ ② 自动任务(时钟)────┘        ← 谁都没动时(唯一事件缺口)
                            (只拨钟:goalctl wake)
谁拨 何时用 拨完干什么
宿主钩子 有会话在动(上报/收尾/用户回话) 跑 --tick ⇒ 判断+投递
自动任务 谁都没动(钩子的唯一缺口) 跑 goalctl wake ⇒ 同一件事,同一出口

⇒ 条件判断只在协作程序一处(不散落在排期提示词里)—— 这正是用户要的"统一"。


2. 判定三分(=用户说的「符合条件时」)

闹钟(goalctl wake)输出 → 拨钟方该干什么:

闹钟输出 含义 拨钟方动作
✅ http 2xx 已投递 ⇒ 主会话被唤醒 结束(⛔ 不抢锁、⛔ 不派活、⛔ 不起会话)
✓ -(无待投)/same-item/too-soon 条件不符(没变化/刚投过) 结束(零打扰 —— 这就是"符合条件时才唤"的否定面)
⏸ target-busy 主会话已经在跑 结束 —— 🔴 绝不能降级(降级=同一件事干两遍)
⛔ disabled 本需求已停(wake_enable=false) 结束
🔴 main-not-live/no-main-session/no-live-session 没有可唤醒的对象 🔴 降级:拨钟方自己就是那个会话 ⇒ 抢域锁 + 按状态表干活
🔴 no-token/no-gateway 异常(没跑在宿主进程树里?) 报告一句,结束(需人看)

⚠️ target-busy 与"没有可唤醒的对象"必须分开 —— 前者是"已经在跑"(别插手),后者是"没人可跑"(要我顶上)。这两者混了,就会出现"同一件事被干两遍"或"没人干"。


3. 落地清单

# 动作 结果
1 新增 goalctl.py wake(唯一唤醒入口) 调 collabd.py --tick,把 deliver= 字段翻成人话 + 给判定三分(rc:0 结束/10 降级/2 异常)
2 两条排期改名为 [协作]-唤醒轮A/B · ai1net-dsh-server 🔴 必须带 [协作] —— 见 §4.1
3 两条提示词改为**「拨钟三分」** 默认动作=拨钟即结束;只有"降级"那一条路才抢锁干活
4 纠偏技能侧过时规则(4 处) 见 §5
5 自测 PASS 28 / FAIL 0

4. 两条会静默坏的易错点(🔴 本轮实测)

4.1 唤醒轮不能让自己被认成"主会话"

resolve_main() 的兜底判据是:本工作区里 last_activity_at 最新、且标题不含 [协作] 的那条。

🔴 刚起的唤醒轮活动时间必然最新 ⇒ 必然被选中 ⇒ 协作程序把通知投给唤醒轮自己 ⇒ 主会话永远收不到。

  • 为什么原名会中招:排期名 [本机协作]-唤醒轮A 里并不含 [协作] 这个子串(它是 [本机协作])⇒ 排除判据不生效。
  • 修法(已做):排期名带 [协作] ⇒ 会话标题继承排期名 ⇒ 被排除。 ✅

4.2 主会话标题必须以 主控 开头(不能加方括号)

代码判的是 title.strip().startswith("主控");实测有条会话标题是 [主控]-[机制线]-… ⇒ 判 False ⇒ 只能靠"最近活动"兜底 ⇒ 本工作区任何一条会话活动更新就可能把它顶掉。 ⇒ 命名一律用 主控 · …(⛔ 别写成 [主控] · …)。这条 SKILL.md §354 已登记,此处再次坐实。


5. 技能侧过时规则纠偏(用户:「这个过时了,现在允许自动任务」)

文件 原话 改成
references/architecture.md §4 「三种节奏(触发源 = 宿主钩子;⛔ 不引入任何周期排期、⛔ 不靠常驻)」 四种节奏 + 新增 §4.0「④ 自动任务:允许,但只准当闹钟」(含判定三分、target-busy 禁降级)
同上 §4.1 结论 「…排期更是多余」+「代价:真正的全员静止期间通知不会自己飞出去」 「排期不是多余,它专补"谁都没动"这个唯一的事件缺口」;旧"代价"已被 ④ 补上
scripts/collabd.py 模块用法注释 「投递=宿主钩子唤起,⛔ 不靠排期」 加「同日用户改口:允许自动任务」+ deliver= 判读三分
scripts/collabd.py --tick 注释块 「⛔ 不靠自动任务排期」 追加「2026-09-30 用户改口(取代本句)…」
scripts/selftest.py 注释 「投递⛔ 不靠自动化排期」 标注已改口,并写明下面两条约束与"谁拨这一下"无关、仍然有效

🔴 注意:改的是触发源,不是约束。这三条一条都没放松: ① --once 不许消费队列 ② --tick 投不出去就不许消费队列 ③ 投递方唯一。


6. 验证记录(实测)

═══ 拨闹钟 · 协作程序判条件并投递(20:27:44)═══
   协作程序结论:tick: item=- awaiting=- phase=- deliver=- consume=- park=-
✓ 判定:**没有需要投的东西**(队列无新变化 / 无停滞)⇒ 静默。
⇒ 本轮**就此结束**(这就是「符合条件时才唤」的否定面 —— 零打扰)。
wake rc=0
  • 已实测两条分支:静默(deliver=-) 与 已停(wake_enable=false 直接返回)。
  • "投成"与"降级"两条走的是协作程序既有且已实战过的代码路径(_deliver_str 的 delivered / skipped),本轮未人为制造(⛔ 不扰动生产队列)。
  • 技能自测:PASS 28 / FAIL 0;顺带清掉 py_compile 生成的 __pycache__(技能侧自测的硬项泄漏,已消除)。

7. 能力边界(诚实说)

  • 🔴 能被唤醒的前提是"主会话此刻 live"。实测 worker 寿命 30 s–6 min(干完活就回收)⇒ 大概率不 live ⇒ 闹钟会报"没有可唤醒的对象" ⇒ 降级。
  • ⇒ 要真做到"唤醒统一走协作程序",得让主会话保持活着(把那个窗口开着),否则多数时候仍落在降级路径上。
  • ⚠️ 降级不是绕过统一:省掉的只是一次投递,判断规则仍来自同一张状态表。
  • ⚠️ 本机"需求↔工作区"仍是 1:1(goal.json 单份)。

8. 图

见同目录 唤醒-统一唤醒出口-20260930-图.html(① 统一后的流程:两个拨钟方 → 一个出口;② 判定三分图:target-busy ≠ 没有可唤醒对象)。