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

6.4 KiB
Raw Blame History

投递链路真因定位 · 「投不进跟进会话」到底卡在哪

  • 定位时间: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)

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 等。