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

122 lines
9.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 唤醒机制 · 角色与情况全表(2026-09-30 20:3x)
> 线:机制线 · 唤醒机制 | 域:`ai1net-dsh-server/`
> 上位:`~/.workbuddy/skills/multi-session-collab/references/architecture.md`(**五主体**唯一权威)|本文件是它在「唤醒」这一块的**展开**
> 兄弟件:`交付物/唤醒-双排期实现方式与状态动作表-20260930.md`(配方+状态表)|`交付物/唤醒-无人值守可行性-20260930.md`(为什么叫不醒旧会话)
---
## 0. 结论:**唤醒轮不是新角色,是「主会话」的定时、不可接续实例**
架构里只有 5 个主体。唤醒轮**不增加第 6 个主体** —— 它扮演的就是「主会话」:
- 与用户那个主会话**职责完全相同**(判断 + 派活);
- 唯一区别:**它不可接续**(用户回不到它;它跑完即死)。
🔴 **一条分界线(本文件最重要的一句)**:
> **派活(写排期、开会话)只属于「会话」** —— 也就是**主会话**和**唤醒轮**。
> **协作程序**(`collabd`)与**投递**:⛔ **永不派活、永不开会话**(architecture §1 硬边界)。
> ⇒ 把唤醒轮误当成"协作程序的一部分"就会得出"它不许派活"的错误结论 —— 它是**会话**,**可以派活**。
---
## 1. 角色卡(谁是谁)
| 角色 | 是不是会话 | 只做什么 | ⛔ 不做什么 |
|---|---|---|---|
| **用户** | — | 看**一个**看板;拍**边界外**的板(授权/放行/花钱/对外承诺) | ⛔ 不管过程、⛔ 不必催进度 |
| **主会话**(可接续) | ✅ 是,**用户对接的那个** | 判断 + 派活 + 接口令(启停唤醒轮)+ 向用户报告 | ⛔ 不做机械判定;⛔ 不搬砖(除非最靠前那步自己就能做) |
| **唤醒轮**(A/B 两条定时排期起的) | ✅ 是,**临时且不可接续** | 抢锁 → 按【状态表】只做 **①接棒 / ②报告并停 / ③退出 / ④按③** | ⛔ 不造活、⛔ 不巡检体检、⛔ 不启自己、⛔ 不接管别人的锁、⛔ **不拍边界外的板** |
| **协作会话**(每棒 worker) | ✅ 是 | 一棒一线、一次一件;**做完即上报** | ⛔ 不跨线;⛔ 不夹带;⛔ 不常驻 |
| **协作程序**(`collabd`) | ❌ 否,程序 | 台账/判定/告警/看板/单例 | 🔴 **⛔ 不派活**(不写排期、不开会话) |
| **投递** | ❌ 否,程序/钩子 | 逐条读队列 ⇒ 有变化就**告诉主会话**;机械判定 | ⛔ 不开会话、⛔ 不派活、⛔ 口令不落盘 |
| **宿主(WorkBuddy 本体)** | ❌ 地基 | 提供四样:**状态**/**调度**(唯一能开新会话的通道)/**事件**(钩子)/**互斥**(域锁) | ⛔ 不是"主体",⛔ 不参与判断 |
### 1.1 🔴 「可接续 / 不可接续」决定了能动多大的手
| | 主会话(可接续) | 唤醒轮(不可接续) |
|---|---|---|
| 能否被用户中途插话 | ✅ 能(用户就在里面) | ❌ 不能(用户不知道它存在) |
| 允许做的判断 | **全部**,含无客观优劣的偏好 | **只允许"机械可判"的**:有客观可判的优劣 ⇒ 自决;没有 ⇒ **必须走 ②** |
| 典型可自决 | 选型、路径、命名、调参、部署、排查方法 | ①接棒(下一步已定死)/③退出 |
| 典型必须停下 | —— | 要不要改方向、要不要花钱、要不要对外承诺、要用户凭据 |
| 产出去向 | 直接回给用户 | 写台账/看板 + 一条报告(用户下次回主会话才看到) |
⇒ **判据一句话**:**这个判断有客观可判的优劣吗?** 有 ⇒ 唤醒轮自己拍;没有 ⇒ ② 停下、报告。
---
## 2. 【核心】完整情况表(情形 → 各角色各干什么)
### A. 目标生命周期层(🔴 用户 09-30 定:唤醒轮从属于目标)
| 情形 | 主会话(可接续) | 唤醒轮(A/B) | 协作程序 / 投递 |
|---|---|---|---|
| **A1 下达「执行 XXX 目标」** | 接口令:定目标 + **启动唤醒轮**(A 即刻启用 + 排 +30 分钟启 B) | 尚未醒 | 记台账 |
| **A2 目标在途·有缺口** | 判断缺口、派关键那棒 | 每 30 分钟醒一次 ⇒ 抢锁 → **①写一行排期接棒** | 投递把变化告诉主会话 |
| **A3 目标在途·暂时无缺口(等外部/等数据)** | 说明在等什么 | **③ 一句话退出**(⛔ 不造活) | 保持台账 |
| **A4 卡在需要用户** | 把"要你做什么"报告到用户面前 | **② 不派棒+报告+把 A/B 一起暂停** | 落 `NEED-USER.md` |
| **A5 目标完成(验收全过)** | 收口:宣布完成,暂停 A/B | 若它先发现 ⇒ **③ 收口 + 暂停 A/B** | 台账置已完成 |
| **A6 目标作废/换目标** | 换 `goal.json`,**删**旧目标的两条排期,按新目标重开一对 | —— | 台账清旧目标 |
| **A7 用户放行/继续** | 重新下「执行 XXX 目标」口令 ⇒ 重新启用 + **校准相位** | 保持 PAUSED 直到被启用(⛔ 不许自启) | 台账恢复 |
| **A8 用户另开新目标(旧目标还在途)** | 🔴 **先处理旧目标**(收口或显式挂起)⇒ 再开新的;⛔ 不许两对唤醒轮同时跑同一项目 | —— | 台账两条并行(须显式) |
### B. 唤醒轮运行时层(抢锁前后)
| 情形 | 主会话 | 唤醒轮 | 备注 |
|---|---|---|---|
| **B1 抢到锁 + ①有缺口** | —— | 写**一行**排期(新棒 id **只从工具返回值取**)⇒ 释放锁 ⇒ 回一句 | 一次只派一棒 |
| **B2 抢到锁 + ②卡在用户** | 用户回话时直接接手 | ⛔ 不派棒;写清"要你做什么";**A、B 一起 PAUSED**;释放锁 | 派了=空转链条 |
| **B3 抢到锁 + ③无缺口** | —— | 一句话结束;**确认无在途目标 ⇒ A、B 一起 PAUSED** | 空转是**正常出口**,不丢人 |
| **B4 抢到锁 + ④判不准** | —— | 按 ③ 处理 | 宁可空转,⛔ 不许造活 |
| **B5 抢不到锁** | —— | **立即结束**(有人正在推进=天然去抖) | ⛔ 不等待/不接管/不删别人的锁(R9) |
| **B6 上一棒的产物没验收/棒死掉了** | 验收并判缺口 | 若"验收这一步"已定死判据 ⇒ 可直接派复验棒(属①);否则 ⇒ ②/③ | 判据看"下一步是否已定死" |
| **B7 两条撞在同一分钟** | —— | 一条抢到、另一条 B5 退出 | 相位漂移的表现,按 §3 校准 |
### C. 机制健康层
| 情形 | 主会话 | 唤醒轮 | 怎么办 |
|---|---|---|---|
| **C1 相位漂移**(两条不再差 ≈30 分钟) | 重做启用(全停 → A 即刻 → B 隔 30 分钟) | 无感 | 查 `automation_update mode=list` 的 `nextRunAt` |
| **C2 宿主重启** | 复查两条状态 | 排期表由宿主持久化,重启后仍按 `next_run_at` 跑 | ⚠️ 已知 `004f6bc2` 的 `next_run_at` 曾**停在过去** ⇒ 重启后必查一次 |
| **C3 排期被误删** | 按 §配方重建一对 | —— | ⚠️ **删除是软删**:`status` 仍是 ACTIVE、只有 `deleted_at` 有值 ⇒ **判"还在不在跑"看 `deleted_at`** |
| **C4 钩子不 spawn** | 查宿主日志 `[HookExecutor] spawn` | 不受影响(唤醒轮走排期,不走钩子) | —— |
| **C5 唤醒轮自己起不来**(会话创建失败) | 查 `automation_runs` 有无 `ACCEPTED` 行 | —— | 排期本身还在,下个整点半再试 |
| **C6 真·全员静止(没人在)** | —— | **这正是唤醒轮存在的意义**:它自己就是一个新会话,不依赖任何"活着的会话" | 这就是唯一能破静默的东西 |
### D. 异常与红线层(⛔ 一律先停手)
| 情形 | 主会话 | 唤醒轮 |
|---|---|---|
| **D1 锁持有者疑似已死/卡住** | 报告用户,**处置权只属用户** | ⛔ **绝对禁止**删锁/接管(R9)=唯一合规是停手+报告 |
| **D2 发现别人正在改的文件** | 归属不明 ⇒ 只报告、不动手 | 同上(R7-边界) |
| **D3 需要用户凭据/审批** | 向用户要 | ② 停下报告(⛔ 不许自己找) |
| **D4 需要重启宿主/改全局配置** | 先问用户 | ⛔ 硬禁止,直接 ② |
| **D5 发现是对外动作(发布/承诺)** | 当轮问用户 | ⛔ 禁止(上一轮同意不算数) |
---
## 3. 口径(启停 · 相位 · 锁)
| 项 | 口径 |
|---|---|
| **启动** | A 即刻 `ACTIVE` + 排一条 **+30 分钟**的一次性排期去启用 B(用完即废)⇒ 两条相位差 ≈30 分钟 |
| **停止** | A、B **一起** `PAUSED`(唤醒轮判到 ②/③ 自己停;完成/作废由收口会话停) |
| **重启** | **只有**「执行 XXX 目标」口令能启;⛔ 唤醒轮不许自启 |
| **相位** | = 建立/启用那一刻;`PAUSED` 时为空;⛔ 分钟写不进规则(`BYMINUTE` 被忽略) |
| **互斥** | 两条抢**同一把域锁**(`--domains <项目>/`);⛔ 抢不到就退,⛔ 不接管 |
| **粒度** | 30 分钟(宿主只认 HOURLY/DAILY/WEEKLY/MONTHLY/YEARLY) |
---
## 4. 一句速记
> **用户拍边界外的板|主会话(含唤醒轮这个实例)判断+派活|协作会话干活+上报|协作程序管台账|投递管通知 —— 唤醒轮只是"被定时叫起来的主会话",跑完就死、不许自启、不许造活。**
---
## 5. 遗留
1. 🔴 `multi-session-collab/references/architecture.md` **§4 仍写「⛔ 不引入任何周期排期」**(旧定案)⇒ 与本文件冲突,**待更正**。§1 五主体表也宜加一句"唤醒轮=主会话的定时实例"。
2. 其他项目尚未复制配方(用户说的是"后续每个项目")⇒ 照 §配方 三步抄。