- 变更规模:新增 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/ 知识文件,按口径入库)
150 lines
13 KiB
Markdown
150 lines
13 KiB
Markdown
# 多会话执行 · 一页纸(怎么派活、怎么收活、怎么不干等)
|
||
|
||
> 🔴🔴 **2026-10-03 07:2x 状态块(本条为准,排在下面所有小节之上)——「上报/投递」整套退役**
|
||
>
|
||
> · ⛔ **投递已真删**(`supervise()` 203→71 行、`wake_enable` true→false)⇒ **§3 里"唯一投递方"那半条作废**、
|
||
> §4 的**唤醒会话/跟进会话两类已整套退役**(⇒ **§4 现只剩两类:主会话 + 协作会话**)。
|
||
> · ✅ **现行机制只有两条腿**:**接收**=`--report` 写 `tasks.json` 四态台账(唯一权威);
|
||
> **处理**=建 `[检查]-…` 排期(`maybe_spawn_check_agent()`,唯一载体=常驻 `--supervise`)。⛔ **没有"推送"这一环**。
|
||
> · 🔴 **「常驻投递」这个角色名也别再用** —— 角色本来就叫「**协作程序**」,"常驻"是**运行形态、不是角色名**。
|
||
> · ⇒ 逐条改未做(散在 4 份约 200 处);**冲突时以本块 + `architecture.md` 当前结论节为准**。
|
||
> 机制细节 ⇒ `SKILL.md` 文首 10-03 状态块;坑 ⇒ `pitfalls.md` P0-35 ~ P0-38。
|
||
|
||
> ⚠️ **深度以 `references/architecture.md` 为唯一权威**(本文件是**入口与判据**,⛔ 不另立第二份架构)。
|
||
> 踩过的坑以 `references/pitfalls.md` 为准;任务图细则见 `references/taskgraph.md`。
|
||
|
||
## 1 一句话
|
||
|
||
**派活用自动化(唯一能开新会话的通道)|收结果直读宿主库(0 token)|机械判定下沉到本地只读脚本|AI 只在需要判断时被叫起|用任务图 + 关键路径防干等。**
|
||
|
||
## 2 四条通道(哪件事走哪条 —— 走错就是最大的浪费来源)
|
||
|
||
1. **派活 ⇒ 只能走自动化**。宿主钩子**开不了新会话**,这是硬事实;所以「叫起下一个干活的人」只有自动化这一条路。
|
||
2. **收结果 ⇒ 直读宿主库**(`automation_runs` 等,宿主已把各线结论写好)。⛔ 不要为了"问一句进展"去叫一个会话 —— 那是 0 收益的开销。
|
||
3. **机械判定 ⇒ 下沉到本地只读脚本**(`collabd.py --once` 等)。这类事不需要 AI 判断,⛔ 不要占用会话。
|
||
4. **人只看一个看板** ⇒ 只读旁路观测,异步、可延迟,**⛔ 不许影响程序执行**。
|
||
|
||
## 3 节奏:常驻为主,钩子作补充
|
||
|
||
- 🔴 **触发源 = 常驻的执行检查 + 投递**(09-29 定案,**2026-10-01 用户再确认**:「**协作与投递一直运行(常驻)**」)。
|
||
理由:**⛔ 不是所有队列都由钩子产生** ⇒ 纯事件驱动**会漏**。
|
||
- ⛔ **自动任务("当闹钟")方案已废弃**(用户 2026-10-01:「**定时任务的方案已经废弃了**」)⇒ ⛔ 不要再建。
|
||
- `collabd.py --once` = **投影轮**(维护队列,**不投递、不推进**)。
|
||
- `collabd.py --tick` = **投递轮**,🔴 **唯一投递方 / 唯一推进方** ⇒ **由常驻投递按周期跑**。
|
||
- 🟡 **宿主钩子只作补充**(事件驱动的即时性),⛔ **不是主路径,⛔ 不得用它取代常驻**。
|
||
|
||
## 4 四个"会话类别",别混(🔴 2026-10-01 用户口径 · 由「三个角色」改)
|
||
|
||
> 🔴 **四类都在同一个工作区**(`config.workspace` 那一个目录),**靠标题两级前缀区分**(第 1 级=角色、第 2 级=任务类别),⛔ **不按 `cwd`、⛔ 不按 `workspaces` 表**。
|
||
|
||
- **主会话**:🔴 **只管目标和方向**(判断与派活)。它是**解析出来的、不是登记出来的** —— 三层规则全在 `resolve_main()` 一处(见 `architecture.md §7`)。🔴 **只由用户触发**,⛔ 不接机制推送。
|
||
- **执行会话**:承接具体活。看板上=**下面那个虚线大框**里那一排(有几个排几个;一个都没有时画**虚线空框**,⛔ 不许省略整层)。
|
||
- **唤醒会话**:🔴 三条硬定性 —— **本质还是会话** / **独立会话(⛔ 不在主会话上处理)** / **随需求确定时才创建**。看板上它在**主会话下面那一行(`RW`)左格**、与右格**跟进会话等宽**,靠**位置**区分、位置不变;「还没建」是**正常态**、⛔ 不是故障。
|
||
- 🆕 **队列上报的跟进会话**:🔴 用户 2026-10-01 口径 —— **主会话只管目标和方向**,「**队列上报的会话 让专门的 跟进会话处理**」。✅ **投递路由已落地**:按件的类别选「**跟进会话**」(`follow_for_topic()`),**⛔ 绝不投主会话**;连一条跟进都解析不出/已有但不活 ⇒ **喊用户**(⛔ **不降级投主会话**)⇒ 详见 `architecture.md §2.3.0c`。
|
||
|
||
🔴 **看板上的两个「虚线大框」= 分组,⛔ 不是节点、也⛔ 不是新一层**:
|
||
上面那个框住「**主会话 + 唤醒会话 + 跟进会话**」(=**用户那一面 + 机制那一面**),下面那个框住**执行会话**;
|
||
**两个大框之间只有一条线 = ① 派活**(⛔ 不再从主会话画多条扇形线出去)。⚠️ 改框宽/改格宽必须**重算框**(框由该排布局现推,⛔ 不写死)。
|
||
⇒ 位置、形状、命名沿革与两道自检:`collab-detail.md §0.5.5`;布局常量与两道自检:`architecture.md §2.3.0c-2`。
|
||
|
||
### 4.1 🔴🔴 **开工清单:主会话开工时**必须**把三类会话建齐**(用户 2026-10-01 明令)
|
||
|
||
> 用户原话:「**开始会话完成需求的时候,主会话需要创建 唤醒会话 以及根据分工类别 创建 协作会话
|
||
> 和 跟进会话呢 不然整个机制跑不起来**」
|
||
|
||
| 该建什么 | 标题形态 | 少建 ⇒ 断在哪 |
|
||
|---|---|---|
|
||
| **唤醒会话** | `[唤醒]-<类别>-<具体>` | 没人推 → 需求停在原地(实测 3.5 h 零成果) |
|
||
| **执行会话**(**每个分工类别一条**) | `[协作]-<类别>-<具体>` | 没人干 → 该类别解析不出承接者 |
|
||
| **跟进会话** | `[跟进]-<类别>-<具体>` | 没人收 → 队列上报全挤回主会话 |
|
||
|
||
**三条硬约束**:① **只有自动化能开新会话** ⇒ "建会话"=**登记一条自动化**,⛔ 不是自己 spawn;
|
||
② 标题**第 2 级必须带方括号**、值取 `goal.json` 的 `topics`(⛔ 用 `short` ⇒ 静默漏管);
|
||
③ **"还没建"是正常态**,但**开工就必须建**,看板上如实显示成灰 ○。
|
||
⇒ 细则与踩坑:`architecture.md §2.3.0d`。
|
||
|
||
### 4.1b 🔴🔴 **缺会话 ⇒ 自动拉起**(用户 2026-10-02 口径 · **运行期也要做**,⛔ 不只是开工那一刻)
|
||
|
||
> 用户原话(触发面,逐字):「**是用户说 使用协作会话方式 完成目标 或 继续完成目标**」
|
||
|
||
- **触发**:用户说这两句(等价说法「继续执行」也认),**或**队列堵住(投递报 `follow-not-live` / `no-follow-session`)。
|
||
- **动作**:**先查齐备度** ⇒ **缺 ⇒ 自动拉起**。
|
||
⛔ **不许**写 `NEED-USER.md` 请用户自己去开一条会话 —— 那是把机制该干的活推给人。
|
||
- 🔴 **齐备度怎么算(2026-10-02 订正)**:**协作/唤醒按类别**各算一条;**跟进是全类别唯一席位**——
|
||
`collabd.py --gap` 对它**不按类别分桶**(桶键恒 `(follow, "")`),一个工作区从头到尾只应有**一条**活的
|
||
跟进会话。⛔ 别按类别建出 N 条 `[跟进]-[<类别>]-…`(本棒初版就建错成 2 条,已订正)。
|
||
- **判据 + 现成参数**:`python scripts/collabd.py --gap`(只读)⇒ 列出缺口 + 每条该建的排期
|
||
(name / prompt / scheduleType / scheduledAt / cwds)。硬缺=**跟进/协作**会话没有活着的;
|
||
**唤醒**会话算"软缺"(用户定性「随需求确定时才创建」)。
|
||
- **谁执行**:**会话**(`automation_update`)。⛔ 脚本**不许**写 `automations` 表(双红线)
|
||
⇒ 这是唯一通路,也是"自动"的全部含义。
|
||
- **怎么送到会话**:钩子 `wb-result-hook.py` 在 `UserPromptSubmit` 把缺口**注入当前会话上下文**
|
||
(零 token;触发词命中即查,否则 120 s 节流查一次)⇒ 用户照常说那句话即可,**什么都不用做**。
|
||
|
||
🔴 **「接续会话」⛔ 不是第 5 类,是「形态」**:上面**任一类**撞到阈值(上下文/日志)时,**由它自己**建出下一棒 —— **角色继承被接续的那条**(主会话的接续仍是主会话候选)。详见 `architecture.md §2.3.0b`。
|
||
🔴 **接续棒必须带类别**(`接续 · [<类别>] · <具体>` 或标题里出现类别名)——
|
||
否则归属判据(角色+**类别子串**)认不出它,它会被**静默漏管**(不进看板、`--ready-next` 也不算它在跑)。
|
||
⚠️ 主会话的续棒要**保住 `主控` 前缀**(`主控 · <类别> · 接续自 <id8>`)—— 否则它被判成干活的棒,
|
||
主会话候选会**变空**(P0-11 实测踩过)。
|
||
|
||
### 4.2 🔴🔴 **接续退位:建出下一棒之后,把前棒**退场**(用户 2026-10-01 立)
|
||
|
||
> 用户原话:「**通过接续会话的时候,如何处理过期的会话,避免越堆越多**」
|
||
|
||
**为什么必需**:接续=会话自己建下一棒,而**前棒不会自动消失** —— 它在宿主库里永远是
|
||
一条 `completed` 记录、标题同族。实测本工作区**已堆 5 条**「接续 · 会话机制合并…」⇒
|
||
看板与状态稿每轮都为旧棒占位,**真在跑的棒被埋在里面**(越用越糊)。
|
||
|
||
**两条退场路径**(⛔ 一条都不许少):
|
||
|
||
| 路径 | 怎么做 | 什么时候生效 |
|
||
|---|---|---|
|
||
| **显式**(准确) | 建出下一棒后立刻 `collabd.py --retire self --by <接棒会话id> --why 接续` | **立刻** |
|
||
| **窗口兜底** | 自动:`completed` 且超 `session_live_min`(默认 90)分钟未动 | 等窗口到 |
|
||
|
||
⛔ **两条闸门都绕开 `working`**(在跑的棒一定要摊在版面上)+ **主会话是版面锚点**(⛔ 不按窗口抽掉)。
|
||
⛔ **退场 ≠ 删除**:宿主库原样在、`retired.json` 全留痕(**可逆、可追溯**)⇒ 但**必须报数**
|
||
(看板/状态稿都会写「已收起 N 条」—— 收起而不说=读者把"收起了"读成"本来就没有",同族红线)。
|
||
⚠️ **前棒中途死掉时显式那步不会发生** ⇒ 靠窗口兜底收(同"每小时兜底唤醒"的设计口径)。
|
||
|
||
### 4.3 🔴 主会话生病了就**换一条**,别指望它自愈
|
||
|
||
- **哑会话**(诊断日志撞 ~10 MiB ⇒ 宿主拒写 ⇒ **界面永远刷不出内容**)**照样在"活会话"列表里**
|
||
⇒ 判据必须是「**活着 ∧ 不哑**」(`_pick_live()` 同时管这两条,`resolve_main` 的**每条路**都得走它)。
|
||
- **处置(标准 runbook)**:把 `<sid>.log`(连同 `.log.1`)**改名挪开**(⛔ 不删,用 Python `os.rename`,
|
||
⛔ 别用 `mv`)⇒ 宿主数十秒内重建并恢复写入 ⇒ 详见 `references/forensics.md §4`。
|
||
⚠️ **它必然复发**(每个会话涨到上限都会重演)⇒ 靠扫描器 + 钩子兜底。
|
||
- **换主会话的逃生口**:`collabd.py --declare --role main` —— 🔴 它的语义是「**换**」:
|
||
会把**其它登记为 main 的一律降级为 worker**(一个工作区一条主会话)+ **明确说出口**。
|
||
⛔ 旧语义是"加",等于**什么也没换**(`_main_sid()` 取第一条 main,而 Python dict
|
||
对已存在的键赋值**不改位置** ⇒ 老那条永远排前面,逃生口形同虚设 —— 2026-10-01 实测踩到)。
|
||
|
||
🔴 **两个极易踩的读数坑**:
|
||
1. **唤醒会话的读数源是 `sessions` 表**(标题前缀 `[唤醒]`),⛔ 不是 `automations` 表。
|
||
2. 🔴 **自动唤醒任务 / 协作轮的排期名必须带 `[协作]` 前缀** —— 否则会被 `resolve_main` 认成"主会话",**通知投给它自己**。
|
||
⚠️ 🔴 **2026-10-02 标注(⛔ 不是口径变更)**:本规则**只在「唤醒用排期」这个代偿形态下才有对象** —— 定案的唤醒时钟是**常驻投递**(⛔ 不开会话、没有排期名);⛔ 别因为这条规则在,就反过来认定「唤醒本该用排期」。
|
||
|
||
## 5 一次派活要带什么(模板要点)
|
||
|
||
1. **开工第 0 步:抢域锁**(域按**显式 domain** 切,⛔ 不按 cwd、⛔ 不按工作区)。
|
||
2. **本轮只做一件事,做完即停**(无人值守必写;否则它会一路做下去把预算烧光)。
|
||
3. **收尾自判**:还有缺口 ⇒ 接下一棒;`blocked` ⇒ ⛔ 不接,改喊用户。
|
||
4. 任务细节⛔ **不要抄进 prompt**(prompt 只写"去哪读",⛔ 不复制正文)—— 抄进去等于每轮都全量重发。
|
||
|
||
## 6 反馈协议与唤醒(防"干等"与"空转")
|
||
|
||
- **反馈协议 = 单条 + 握手**(⛔ 不是群发、⛔ 不是广播)。
|
||
- **唤醒 = 三条件合取**才触发(条件见 `architecture.md §2.2`)。
|
||
- **需求内闭环**:一个需求内的活由该需求自己的会话闭环收口(定义见 `architecture.md`「需求内闭环」节)。
|
||
- 🔴 **防"空转链条"**:**「只是排了下一棒」≠「有成果」**。判完成必须看**产出物**,⛔ 不看任务图节点标了 `done`(那是两件事)。
|
||
|
||
## 7 任务图(防干等的核心件)
|
||
|
||
细则 ⇒ `references/taskgraph.md`(文件格式、`collabd.py taskgraph()` 算法、四条派活规则、维护纪律)。
|
||
一句话:**关键路径单线化 ⇒ 必须拆**,否则整条链被一个慢节点卡住,其他人全在干等。
|
||
|
||
## 8 加东西之前必须过的判据
|
||
|
||
`architecture.md §6`「加东西前必须过的判据(防打转)」。⛔ 没过的就⛔ 不要加。
|
||
⚠️ 但**「协作与投递的常驻」是已定案项**,⛔ **不得拿"进程数=0"去否它**(2026-09-30 踩过:丢掉唤醒时钟 ⇒ 用户点破"成摆设")。
|