Files
dsh_ai1net_server/交付物/投递链路-真因定位-20261002.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

77 lines
6.4 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-10-02 09:45–09:56
- 定位会话:本会话(用户直呼)
- 一句话:**真因不是「没有跟进会话」,而是「名册里的跟进会话都没在跑」** —— 而机制把这句记成了 `no-follow-session`(字面像"没有"),**这个错名把两天的排查带偏了**。
---
## 一、真因(六层证据链,同一路径插桩实测)
| # | 环节 | 实测读数 | 判读 |
|---|---|---|---|
| 1 | 目标类别表 | `_goal_topics()` = `['会话协作自检', '机制排查与修复']` | 正常 |
| 2 | 跟进名册 | `_scan_follows()` = 6 条;`by_topic` 两个类别都有 | 正常 |
| 3 | 候选解析 | `follow_for_topic(...)` ⇒ `cand=['57f58ecf']` | 正常 |
| 4 | **活会话** | `discover_gateways()` 只有 **1** 条:主会话 `3f43ce71` | **候选不在其中** |
| 5 | 判读 | `why='follow-not-live'` | **准确** |
| 6 | 落库 | `_deliver_str` 记 `skipped='no-follow-session'` | 🔴 **错名** |
插桩原文(`tmp/_tick_instrument.py`,与 `--tick` 同一条调用路径):
```
[SCAN] arg=None -> topics=['会话协作自检', '机制排查与修复'] sids=6 by_topic={两类别都有} err=''
[FFT] topic='' live=['3f43ce71'] -> sid=- why='follow-not-live' cand=['57f58ecf']
[RESULT] deliver={'skipped': 'no-follow-session'}
```
⇒ **卡点在第 4 层**:名册里的 `[跟进]`(`57f58ecf`、`6ab1463e`)**全部是 `completed` 状态**,不在活会话里。
## 二、错名的来源(`collabd.py:1545-1558`)
```python
if g is None:
if _want == "": # ← 只看"有没有解析出 sid",⛔ 不看 why
_n = len(_rft.get("all") or [])
if _n: need_user("…找到 %d 条 `[跟进]-…`,都不活…")
else: need_user("…一条 `[跟进]-…` 都没有…")
info["skipped"] = "no-follow-session" # ← 两种情况都记成这个名字
else:
need_user("跟进会话 %s 此刻不在活会话里…")
info["skipped"] = "follow-not-live"
```
`follow_for_topic()` 本来**算得准**(`:2674` 会返回 `why ∈ {在, no-follow-session, follow-not-live}`),
但 `_deliver_str` **丢弃了 `why`**,只按 `_want == ""` 分档 ⇒ 把两种完全不同的情况合并成一个名字:
- **(a) 真·一条跟进会话都没有**(候选集空 ⇒ `why='no-follow-session'`)
- **(b) 有跟进会话,但都不在跑**(候选非空 ⇒ `why='follow-not-live'`)← **当前就是这种**
⚠️ **代价**:日志与 `NEED-USER.md` 都写成「一条都没有/请建一条」,与事实(**有 6 条,只是没在跑**)相反 ⇒ 排查方向被引向"再多起一条跟进会话",而**多起不管用**。
## 三、叠加故障:`goal.json` 被批量清空(已还原)
- **现象**:`tmp/supervise-inbox/` 下 `goal.json`、`queue.json`、`queue.md`、`NEXT.md`、`ledger.jsonl`、`status.md`、`needs-ai.json`、`runs.watermark`、`_collabd.log` **全部消失**;`NEED-USER.md` 由 16473 B 被重写成 419 B。目录 mtime 09:45→09:49。
- **判定**:**`_collabd.log` 里一行清理记录都没有** ⇒ **不是常驻程序干的**,是外部(一条会话或人);清空发生在 S9 那条协作会话交活的时间窗内(S9 09:40:25 报 done)。
- **后果**:类别表一空,判读从**准确的** `follow-not-live` **恶化**成真·`no-follow-session`,`NEED-USER.md` 的解像话术也跟着错(喊「请把「(默认类别)」那条拉起来」)。
- **已处置**:按逐字副本还原 —— 源 `.workbuddy/collab/bak-goalctl-20261001/goal.json`(10-01 22:29),`md5 = 459bd66138b9069870a34acfc0e3208f`(两侧一致);还原后 `_goal_topics()` 立即恢复两类别、`follow_for_topic` 三问全部回到 `follow-not-live`。现场证据留 `tmp/_goal_restore_20261002/`。
- **说明**:`queue.json` / `NEXT.md` 由常驻程序每轮重算,**无需**恢复;`goal.json` 是**唯一由人写入**的输入源,所以只有它必须还原。
## 四、对「给换新会话和跟进都挂一个后台任务」的判断
1. **原理成立**:投得进去的窗口 = **目标会话当时正在运行**(=它有自己的网关口、是那个口的 live 会话)。历史上真投成过 **3 次**(10-02 01:48→`cbf76e13`@60346、02:56→`ba7b24e8`@57555、04:06→`19e6e204`@49765,`http=200 ok=true`),三次端口全不同。⇒「一直在跑」确实「一直在 live」。
2. **但你 2026-10-01 已明令禁止**(`architecture.md:142`):⛔ 禁止把长跑服务放进**会话后台任务**(理由:每轮输出唤醒宿主 ⇒ 会话**永不空闲** ⇒ 你看到"卡死";**历史已复现 6 次**)⇒「让唤醒会话自己挂后台时钟」**也在禁区,⛔ 不是备选方案**。
3. **且今天已换成不需要它的做法**:时钟不再由会话承担,改由**常驻程序**(`collabd --supervise`)承担,宿主那条 `[唤醒]` 小时排期降级为「引擎全静默时的复活兜底」(`architecture.md:139-141`,S8 治本)。常驻被回收后,下一次事件由 `--tick` 顺手 `ensure_supervise()` 补起 —— **本文件写就期间实测过一次自愈**(停掉 pid 48000 ⇒ 09:54:07 自动起 pid 10448)。
**⇒ 净结论:给会话挂后台任务既被禁止、也已不必要;当前病灶(第 4 层)要治的是「那条 `[跟进]` 会话为什么不在跑」,而不是「没人给它挂时钟」。**
## 五、待办
1. 🔴 **修 `_deliver_str` 的分档**:把 `follow_for_topic` 的 `why` 透传进 `skipped`,让 `follow-not-live` 与 `no-follow-session` 分开记档,并让 `need_user` 文本与之一致(**仅改可读性,⛔ 不改行为**)。改前先查 `board.py` / `selftest.py` / 各判读脚本对该字符串的依赖。
2. **追踪 `goal.json` 被清空的来源**:`_collabd.log` 零记录 ⇒ 外部所为;建议给 `tmp/supervise-inbox/` 的删除动作加一道留痕。
3. **跟进会话的"活着"机制**(S9 复核单已提):要么长期活(=挂后台任务,**被禁**),要么「收完一件能被续起」(=排期,但**只新建不复用** ⇒ 会话堆叠)。两条各撞一条硬约束,⛔ 按现口径不动,等一句话。
---
**取证脚本**(只读,均在 `tmp/`):`_tick_instrument.py`(同路径插桩)、`_tick_trace.py`(全链路中间量)、`_gt_probe.py`(`goal.json` 与类别表)、`_gt_probe.py` 等。