Files
dsh_ai1net_server/交付物/会话哑掉线-收尾报告-20261001.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

121 lines
9.0 KiB
Markdown
Raw 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-01)
> 线:多会话协作机制 · **会话哑掉** | 本棒会话:`345e6839`(自动化 · 阈值交接棒)
> 范围:上棒遗留 **4 项**(一件一件做,做完即停) | 并发锁:本轮持**全局独占**(机制层),**已释放**
## 一、结论(先读)
| # | 遗留项 | 结果 |
|---|---|---|
| 1 | `selftest.py` 补「会话哑掉」回归用例 | ✅ 已补 2 条;`python selftest.py` **PASS 37 / FAIL 0**(基线 35 + 新增 2) |
| 2 | `board_ext.py` 清退役文案 | ✅ 已清 **2 处**(详见 §三) |
| 3 | 已哑主会话 `f8a792ab` 的归属 | ⛔ **未动** —— 取证后**判不准**,按任务书报用户(详见 §四) |
| 4 | 报告 + 释放锁 | ✅ 本报告 + 锁已 `--release-exec` |
## 二、遗留 1:回归用例(⛔ 不碰生产)
新增到 `~/.workbuddy/skills/multi-session-collab/scripts/selftest.py`:
| 用例 | 判据 |
|---|---|
| 哑会话:诊断日志 ≥ 9.5 MiB ⇒ `_deaf_sids()` 判哑 | ① ≥9.5 MiB 判哑 ② **9,499,999 B(差 1 字节)不判哑**(边界)③ KB 级不判哑 ④ 结果**恰好只有那一条** |
| 哑会话:投递命中已哑目标 ⇒ `skipped=target-deaf` | ① 判读=`target-deaf` ② 投递台账**零增量** ③ 已把喊话落到 `NEED-USER.md` |
**怎么做到不碰生产**:`_deaf_sids()` 每次调用**现读** `CODEBUDDY_CONFIG_DIR` ⇒ 用例把它临时指到
`tmp/selftest/fake-cfg/`(用 `truncate` 建**稀疏文件**拿到 10 MiB 体积读数,不真写),跑完 **finally 还原**
(`_db()` 也读这变量,不还原会把后面的用例一起带偏)。元用例「本测试不碰生产」仍全绿。
## 三、遗留 2:`board_ext.py` 清掉的 2 处退役文案
文件:`E:/ProgramData/AIProject/ai1net-dsh-server/.workbuddy/collab/board_ext.py`
| 处 | 原文 | 改成 | 为什么 |
|---|---|---|---|
| 文件头 | `「手机接入」线的看板扩展` | `「本机协作」的看板扩展` | 「手机接入」是**已退役线名**(用户 2026-09-30:「后面也不叫手机接入」);现行目标名=`goal.json` 的「本机协作」 |
| chip① 标题 | `dsh-client · 设备接入 · 本地中转 :20090` | `dsh-plugin-ai1net · 设备接入 · 本地中转 :20090` | `dsh-client` 在此是**退役包名**:原 `@dsh-client/device-shim` 已退役,2026-09-29 归并进 `dsh-plugin-ai1net/lib/device-access.js`(模块⑥「设备接入」)⇒ 换成现承载方真名 |
**验证**:`py_compile` 过;直调 `build()` 打印面向用户文案 ⇒ **「手机接入」0 命中、「垫片」0 命中**,chip① 已显示新系统名。
**保留未动**(判据=有客观可判的取舍,⛔ 不擅自扩大):
- 「本地中转」是 2026-09-30「说人话」批量替换**有意**定下的说法(术语对照表 `| 本地反代 | 「本地中转」 |`)⇒ ⛔ 改回去会推翻那次决定。
- chip② `dsh-client · 覆盖网络节点 · 中继客户端` 属**另一条组件**(覆盖网络线),其系统名本轮**未取证** ⇒ ⛔ 不确定不改。
- `:20090` 裸端口是**真读数**(`netstat`/日志真值),⛔ 不是抽象词 ⇒ 保留。
## 四、遗留 3:`f8a792ab` 归属 —— ⛔ 未动,报用户
**取证(只读)**:
| 会话 | 标题 | 状态 | 诊断日志 |
|---|---|---|---|
| `f8a792ab` | 检查多会话协作机制并修复问题 | completed(08:55) | 今天 **10.0 MB ⇒ 已哑** 🔴 |
| `a202550c` | 主控 · 唤醒机制线 · … | completed(07:13) | 昨天 10.0 MB 🔴/**今天 4.2 MB(已轮转恢复)** |
| `345e6839` | 主控 · 协作机制 · 阈值交接收尾 | working | 1.8 MB ✅ |
- 协作登记 `collabd-state.json` 里 `roles.main = f8a792ab`(**陈旧**,它已结束且已哑)。
- **本会话 `345e6839` 就是唯一带「主控」前缀的活会话,而它是自动化会话**(`is_background_automation=1`,用户看不见、**不可接续**)。
⇒ **工作区当前没有任何「活的且可接续」的候选主会话** ⇒ 改认谁都是错的(把通知投给用户看不见的会话 = 比现在更糟)。
⇒ 按任务书「判不准 ⇒ 报用户,⛔ 不要自己动」:**本轮未改 roles、未归档任何会话**(宿主库 `sessions` 属活库,⛔ 更不碰)。
**🔴 需用户拍板的一件事**(下一节单列)。
## 五、本轮**新发现**(不在清单内,⛔ 未动手,仅登记)
`_deaf_sids()` 扫的是 **今天+昨天** 两个日期目录。而宿主日志是**按天分目录**(`logs/<日期>/sdk/conversations/`),
**昨天的文件是历史、永远不会再增长** ⇒ 任何「**昨天撞过 10 MiB 上限、今天已正常轮转**」的会话,会被**永久判哑**。
- 实证:`a202550c` 昨天 10,485,758 B、**今天 4,354,629 B(宿主今天仍在写它)** ⇒ 它**没哑**,却仍被判哑。
- 后果是**方向相反的新假绿**:本该投递的目标被拦下 ⇒ 通知落空。09:12 那条 `NEED-USER`(称 `a202550c` 已哑)即由此而来。
- 判据收窄的取舍(留给下一棒/用户):只认**最新一天**(今天)—— 好处是消除上述假阳性;代价是「跨天后还没写过日志」的会话当天扫不到(它当天没写 = 也没在增长,影响有限)。
- ⛔ 本轮**未改**:超出 4 项清单,且属机制层(改后须重跑 selftest)。
## 六、上一棒改动清单(⛔ 未 commit)
| 文件 | 改动 |
|---|---|
| `~/.workbuddy/skills/multi-session-collab/scripts/selftest.py` | +2 用例(+`_fake_cfg`/`_with_fake_cfg` 工具 + `DEAF_MIB` 常量) |
| `…/.workbuddy/collab/board_ext.py` | 2 处退役文案 |
锁状态:上一棒持全局独占 → 已 `--release-exec "会话哑掉收尾"`。
## 七、本棒(接续会话)已修:`_deaf_sids()` **永久判哑**(2026-10-01 09:2x–09:4x)
> 来源:本线**接续会话**(上一棒 `345e6839` 达阈值按 §1.5 G 开的接续会话,顶替主会话职能)。
> 锁:机制层 ⇒ **全局独占**。
**改了什么**(`~/.workbuddy/skills/multi-session-collab/scripts/collabd.py::_deaf_sids()`):
| | 旧 | 新 |
|---|---|---|
| 判据 | 今天+昨天 **任一** ≥9.5 MiB ⇒ 判哑 | **每个会话取它最新一天**那份日志 ≥9.5 MiB ⇒ 判哑 |
- 🔴 **旧写法的病**:宿主会话日志**按天分目录**、昨天那份**永不再增长** ⇒「昨天撞过上限、今天已正常轮转」的会话被**永久判哑** ⇒ 本该投出去的唤醒被**静默拦下**(方向相反的新假绿)。
- ⚠️ **今天的兜底保留**:某会话今天**没有**日志(宿主今天没写过它)⇒ 仍退到昨天那份判 —— 比"直接放行"保守。
**生产数据实测(只读,⛔ 未跑 `--tick`)**:
- 旧判据 7 条哑 → 新判据 6 条哑;**唯一被收窄掉的正是 `a202550c`**(昨天 10.49 MB / 今天 4.35 MB,宿主仍在写)✅
- `f8a792ab`(今日 10,485,715 B)**仍判哑** ✅ —— 第一轮那道闸没有被削掉。
- **副作用面=零**:主会话解析(旧 vs 新)**结果逐字相同**(`5f607d3e` · `prefix:主控`)。
**回归用例**(`scripts/selftest.py`):+1 条「只认最新一天」(昨 10 MB/今 4.2 MB ⇒ ⛔ 不判哑;今天才撞上限 ⇒ 判哑;只有昨天 ⇒ 仍判哑;含**精确集合**断言)。
- `_fake_cfg()` 增 `day_offset`(0=今天 / 1=昨天);`_prepare()` **每轮清空** `tmp/selftest/fake-cfg`(防"第二轮才红"的跨轮污染)。
- ✅ `python selftest.py` ⇒ **PASS 38 / FAIL 0**(基线 37 + 新增 1);连跑两次均绿。
**顺带修掉一条环境假红**(⛔ 与本次改动无关,是既有用例的前提覆盖不全):「僵尸对账」用例只靠 `adopted` 反推前提的**一半**,
而僵尸分支的完整前提是「除观察者外无人在跑」**∧「无 IN_PROGRESS 运行」** ⇒ **自动化会话跑本自测时**,它**自己**的
automation run 必然 `IN_PROGRESS` ⇒ 前提不成立却不 SKIP ⇒ **必然假红**(实测:收窄前整套 36/1,只有本条红)。
⇒ 照该用例既有的"前提不成立就 SKIP"姿势**补上后一半**(纯测试侧,⛔ 未动生产逻辑)。
### 七-b 本棒改动清单(⛔ 未 commit)
| 文件 | 改动 |
|---|---|
| `multi-session-collab/scripts/collabd.py` | `_deaf_sids()` 判据收窄为「每个会话只认最新一天」 |
| `multi-session-collab/scripts/selftest.py` | +1 用例「只认最新一天」;`_fake_cfg(day_offset)`;`_prepare()` 清 `fake-cfg`;僵尸用例补 SKIP 前提 |
⛔ **未做**(不属本棒清单,如实挂着):未 `commit`/`push`(未获指令);未把技能本机→服务器单向推(改的是**技能**,
两处落点 `~/.workbuddy/skills/` 与服务器副本需 md5 双端一致,留给后续按 §1.5 B 阶段 5 处理)。
锁状态:本棒持全局独占(机制层 `--claim-exec "5f607d3e"`)→ 已 `--release-exec "5f607d3e"`;服务器侧那把
`storyforge-e2e` 操作锁**属他人**,按 R9 未动。