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

9.2 KiB
Raw Permalink Blame History

唤醒 · 双排期实现方式 + 状态→动作表(2026-09-30 20:2x)

线:机制线 · 唤醒机制 | 域:ai1net-dsh-server/ 上游:交付物/唤醒-无人值守可行性-20260930.md(判定「叫醒旧会话无路」) 配图:交付物/唤醒-双排期实现方式与状态动作表-20260930-图.html


0. 一句话

唤醒 = 到点由宿主起一个「新会话」,它第 0 步跑状态、抢域锁,然后按【状态表】决定干什么。 每个项目挂 2 条每小时排期、相位错开 30 分钟 ⇒ 实际每 30 分钟有一次唤醒;互斥靠同一条域锁(抢不到就退),所以两条不会重复干活。 🔴 这对排期不是常驻的 —— 它从属于「目标」:下口令启动,目标完成或有阻碍时一起暂停(§4)。


1. 四条硬事实(本机实测,⛔ 别重做)

# 事实 证据
1 相位 = 建立/启用那一刻 20:03:42 建 ⇒ 下次 21:03:42;改 rrule 后 20:04:03 ⇒ 下次 21:04:03
2 只改提示词不重算相位 改完提示词后 nextRunAt 与改前逐毫秒相同(…458318)
3 暂停时相位被清空 PAUSED 的行 next_run_at = NULL(对照 1eaf45c3)⇒ 重新启用时又会按"启用那一刻"重算 ⇒ 两条必须错开启用 30 分钟
4 分钟写不死:BYMINUTE 被接受但被忽略;BYHOUR 列表被直接拒绝("must be an integer") 建 FREQ=HOURLY;INTERVAL=1;BYMINUTE=30 ⇒ 仍按建立时刻触发

⇒ "错开半小时"只能靠"两条相隔 30 分钟落地"得到,写不进规则里。


2. 落地配方

2.1 建立(一次性,每个项目建一次)

步 动作 备注
1 建唤醒轮 A、B:FREQ=HOURLY;INTERVAL=1,cwds = 该项目(逐字同形:正斜杠),status 先给 PAUSED 两条的提示词里写死同一把域锁+状态表(见 §5)
2 把两条的 id 写进彼此的提示词(自我暂停要用) 本项目 id 见下表

本项目已建立:

角色 automation id 当前
唤醒轮 A caca9a89-fa82-48e1-a55c-7e0f3a06bd48 PAUSED(已建好,待口令启用)
唤醒轮 B 16bec5ce-98c0-470c-afa9-6f5a06218068 PAUSED(同上)

2.2 🔴 启动(每次下达「执行 XXX 目标」时,三件事一起做)

步 动作 为什么
1 把 A 置 ACTIVE 它的相位 = 此刻
2 排一条一次性排期(+30 分钟)去把 B 置 ACTIVE 这样 B 的相位 = A+30 分钟;这就是"错开半小时"的唯一手段
3 用 mode=list 核对两条 nextRunAt 相差 ≈30 分钟 不对 ⇒ 重复第 1、2 步(先暂停 A 再启用)

⚠️ 那条 +30 分钟的启动棒是一次性、用完即废,⛔ 不要长期留着。

2.3 停止(目标完成 或 有阻碍)

把 A、B 一起置 PAUSED。两种触发都成立:

  • AI 自动:唤醒轮自己判到"② 卡在用户"或"③ 目标已收口" ⇒ 它自己把两条暂停(§3);
  • 人/主会话:目标验收全过或决定作废 ⇒ 由收口的那个会话暂停。

⛔ 唤醒轮不许把自己从 PAUSED 启回来 —— 只有「执行 XXX 目标」这道口令能启。


3. 🔴【核心】状态 → 动作表

唤醒轮抢到锁之后,只认这四种状态;判不准一律按 ③ 处理。

# 状态 判据(怎么认) 该干什么 ⛔ 不许
① 有缺口 链断了/有明确且已定死的下一步(不是"应该再研究研究") 写一行排期把下一棒接上(新棒 id 只从工具返回值取)⇒ 回一句结论、结束 不许一次派多棒;不许派"再调研一下"
② 卡在需要用户 缺凭据/缺真机/缺审批/有 NEED-USER.md 或 blocked 项 ⛔ 不派棒(派了=空转链条);把"要用户做什么"写成可执行一句话(要哪台机器、要哪句授权)报出来;然后把 A、B 一起置 PAUSED,结束 不许"受阻就硬派别的棒"
③ 无缺口/目标已收口 队列空/没有客观可判的下一步 一句话说明"无缺口",结束。若确认"当前没有任何在途目标" ⇒ 把 A、B 一起置 PAUSED ⛔ 不造活;⛔ 不做巡检/体检/日报
④ 判不准 —— 按 ③ 处理(宁可空转一轮) 不许"先干点什么看看"

另外两条前置状态(抢锁之前就决定):

状态 判据 动作
锁被占 抢域锁失败 立即结束(有人正在推进)⛔ 不等待、⛔ 不接管、⛔ 不删别人的锁(R9)
相位漂移 两条 nextRunAt 不再相差 ≈30 分钟,或停在过去 按 §2.2 重做启用;⚠️ 已见过 004f6bc2 的 next_run_at 停在 09-28 23:19 ⇒ 漂移真会发生

4. 目标生命周期 × 唤醒轮(🔴 2026-09-30 20:2x 用户定:「由执行 XXX 目标的口令同时启动,完成或有阻碍时同时暂停」)

目标处于 唤醒轮 A/B 谁执行
下达「执行 XXX 目标」 一起启动(A 即刻 + 排一条 +30 分钟启 B ⇒ 相位错开 30 分钟) 接口令的会话
在途(有缺口) 保持 ACTIVE;每 30 分钟一次唤醒,按 ① 接棒 唤醒轮自己
有阻碍(卡在用户) 一起暂停 + 报告"需要用户做什么" 唤醒轮自己(不必等人)
完成(验收全过)/作废 一起暂停(作废则 delete 两条) 收口会话
用户放行/继续 重新下"执行 XXX 目标"口令 ⇒ 重新启用并校准相位 接口令的会话

⇒ 净效果:只有"目标真的在途"时才烧唤醒轮;收口或受阻即刻停 ⇒ 空转轮总量可控(§6)。


5. 唤醒轮提示词(模板,已写进 A/B 两条)

你是本工作区(<WS>)的唤醒轮 <A|B>。本轮只做一件事,做完即停。
🔴 唤醒 = 起一个「新会话」(⛔ 不是叫醒旧会话 —— 旧会话的网关口随进程消失)
🔴 本排期从属于「目标」:只有"正在执行某个目标"期间才该 ACTIVE;完成或有阻碍 ⇒ 一起停

第 0 步(必做,先跑再说话)
1. 跑状态:<PY> <WS>/state.py
2. 抢域锁:handoff-guard.sh --claim-exec "唤醒轮<A|B>" --domains <项目>/
   抢不到 ⇒ 立刻结束(天然去抖)。⛔ 不等待、⛔ 不接管、⛔ 不删别人的锁

抢到锁之后:按【状态表】动作
 ①有缺口→写一行排期接棒(id 只取返回值) ②卡在用户→⛔不派棒,只报告,然后把 A/B 一起置 PAUSED
 ③无缺口/已收口→⛔不造活,一句话结束;确认无在途目标则把 A/B 一起置 PAUSED ④判不准→按③

本对排期 id(自我暂停用;⛔ 只改 status,不动 rrule):A=<id_a> B=<id_b>
重启规则:只有「执行 XXX 目标」口令能启用,⛔ 自己不许把自己启回来

硬约束:⛔ 不重启宿主/服务|⛔ 不改全局 settings.json|⛔ 不起常驻长跑任务
|⛔ 不 kill 任何会话|⛔ 不投递消息给用户其它会话|收尾必须 --release-exec

6. 代价(如实登记,⛔ 不粉饰)

项 数
在途期间频率 每项目 2 次/小时 ⇒ 48 次/天
收口/受阻后 0 次(一起暂停)⇒ 这是本方案相对"常驻排期"的关键优势
每次唤醒成本 一轮完整会话(哪怕③空转出口也要"跑状态+抢锁+回一句")
粒度下限 30 分钟(宿主只认 HOURLY/DAILY/WEEKLY/MONTHLY/YEARLY,5 分钟级做不到)
与旧文档的冲突 ~/.workbuddy/skills/multi-session-collab/references/architecture.md §4 现写着「⛔ 不引入任何周期排期」(依据用户 09-30 原话「又给我整到自动任务去了」)。本方案是用户 09-30 20:02 后的新指令,取代那一条 ⇒ 该文件 §4 需更正,⛔ 不改则文档与实现打架

7. 校准与撤销

  • 查相位:automation_update mode=list 读两条 nextRunAt(应相差 ≈30 分钟;PAUSED 时为空,属正常)。
  • 校准:按 §2.2 重做启用(先全暂停,再 A 即刻、B 隔 30 分钟);或对某一条 delete + create 重建。
  • 撤销:mode=delete 删两条 ⇒ 回到"只有收尾自判"的旧形态。⛔ 删锁/接管仍禁止(R9)。 ⚠️ 删除是软删:行仍留在 automations 表里、status 仍是 ACTIVE,只是写了 deleted_at(调度器按它排除)⇒ 判断"是否还在跑"要看 deleted_at IS NULL,⛔ 别只看 status。
  • ⚠️ 别用 SQL 直接改 automations 表(宿主持有;一律走 automation_update)。

8. 出处

  • 判定上游:交付物/唤醒-无人值守可行性-20260930.md(§3 源码判据 / §6 worker 存活时长 / §7 替代路径)
  • 宿主表(只读):E:/ProgramData/.workbuddy/workbuddy.db → automations(next_run_at/status)/automation_runs(实际触发时刻)
  • 技能:~/.workbuddy/skills/multi-session-collab/(§4 节奏章待更正)