Files
dsh_ai1net_server/.workbuddy/memory/2026-09-下4.md
T
admin ce8e6ceed9 chore(工作区): 纳入版本控制基线(回收 411 MB 过程产物)
回收 411 MB(470 M → 58.8 M),全部经回收站,可恢复:
- 待清理/(146.2 M,含 relay 分片 128 M 与 42 项过程目录)
- tmp/(32.4 M,按接续棒命名的过程临时区)
- .workbuddy/tmp/(39.5 M)
- 4 份 workbuddy.db 冗余副本(101 M,09-23 事故的坏副本 / 抢救产物)
- tmp/im16/gw/centrifugo 二进制(63.9 M,可重下)+ 缓存残留

入库范围:常驻规则(CODEBUDDY.md / README.md / state.py)、在途接续入口与
接续包、docs/、交付物/、交接单/、归档/、scripts/、.codebuddy/、
.workbuddy/memory/;共 398 件,其中 >60 KB 的 26 件全为文档。

排除(.gitignore):tmp/、待清理/、运行态日志与缓存、*.db 与 DB 备份整目录、
打包二进制(*.tar.gz / *.tgz)、记忆修复前备份。
2026-09-24 07:51:03 +08:00

514 lines
47 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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-09(第 5 片)
> ⚠️ **本目录日志已按【月】分片**(2026-09-15 用户定,单文件 ≤50 KB):同月续片 `2026-09.md` / `2026-09-下.md` / `2026-09-下2.md` / `2026-09-下3.md` / `2026-09-下4.md` / `2026-09-下5.md` / `2026-09-下6.md` / `2026-09-下7.md` / `2026-09-下8.md` / `2026-09-下9.md` / `2026-09-下10.md` / `2026-09-下11.md` / `2026-09-下12.md` / `2026-09-下13.md` / `2026-09-下14.md` / `2026-09-下15.md` / `2026-09-下16.md` / `2026-09-下17.md` / `2026-09-下18.md` / `2026-09-下19.md` / `2026-09-下20.md` / `2026-09-下21.md` / `2026-09-下22.md` / `2026-09-下23.md`
> **写入约定**:一律 append 到**当月最后一片**;该片超 50 KB ⇒ 新建 `2026-09-下N.md`;⛔ **不要再按日新建 `2026-09-DD.md`**。
> **覆盖来源**:2026-09-12.md
> **上一片**:`2026-09-下3.md` **下一片**:`2026-09-下5.md`
---
## T02 执行完毕(08:26-08:50)
**用户**:「确认开始执行」→ 执行 T02(文档库收尾)。
**任务 A 编号消歧 ✅**
- **脚本正则改了 8 处**(单子列 6 处 —— **漏了 `index_status`/`ref` 的键转换与 `%02d` 格式化**;键改字符串后 `%02d` 会 TypeError,必须同改)
- **闸门验证**(未改名先复跑):audit 唯一差异 = 新号 `37a` 被判悬空(预期);manifest 归一化后 11 条差异**全部更准确**(9 条零填充 `1`→`'01'` + `03` 的 refs 4→2 因单子示例文本被 `int` 误并 + `16` 的 refs 24→25 因去掉 `\b` 修复漏匹配)
- **`git mv` 改名 4 份**(git 识别 R 重命名、历史保留)+ 4 个标题号改写
- **引用修正 28 处 / 14 文件**(单子估 27/13 **偏少**):37a 7 / 37b 1 / 38a 9 / 38b 6 + 53 自身 3 处描述改写 + T02 示例 2 处
**任务 B INDEX 瘦身 ✅**:**28,809 → 7,468 字符**(-74%;后续微调最终 **7,583**);明细表压三列、删"路径/日期/证据"列;§三/§四 精简;§五/§六 保留
**事实校正 8 + 1 处**:L6("服务器唯一源 / 脚本已删除" → 双端模型 + 脚本在用)|L7(本机工作区**写反了**)|L8 更新|§二 重复行合并|缺号 48|§五 HEAD `8355e99`→`ebe8075`|§六 下一号 20→**61**|**另修 README 技能工作副本路径** → **`E:\ProgramData\.workbuddy\skills\`**(`.workbuddy` 已迁 E 盘)
**验收 6/6**:A audit exit 0|B 7,468|C items 78 + `37a/37b/38a/38b` 有 refs/tier|D 裸旧号 **0**|E 双端一致 **108/108**|F T01 仍"待办"
**归档**:T02 → `archive/交接单-已完成/`(用 `mv`,因 `交接单/` 未纳管 git)+ 交接单 README 状态行 + INDEX §四 登记
**⚠️ 协作发现**:**另一会话在活跃工作** —— 08:36 新增 **T03**(`plugin_package` 7 插件整合投放)并更新交接单 README(**它已把 T02 标为"已完成"并留"待归档"待办** → 协作良好);**T01 决策点 1 我 07:16 写的"已定"完整保留**(无冲突)。
## 协作问题:两会话并行写入(08:50-09:10)
**用户问**:「两个会话同时执行造成冲突,如何解决比较好」。
**诊断(实证)**:
- **根因不是"合并难",而是"并行写没有互斥"** —— 现有约定(交接单 README §三 7 条)只覆盖「**同一单子**的冲突域」→ **跨单子仍会撞共享文件**(`INDEX`/`README`/`BRIEF`/`03-路线图`/`交接单 README`/`SKILL.md`)
- **且**:文档库 **HEAD 停在 `43e4ae9`(档案 56)+ 未提交 25 项** → **长期不提交 = 零冲突检测能力**(无法靠 pull/merge 发现撞车)
**今天实际发生**:
| 文件 | 另一会话 | 我 | 结果 |
|---|---|---|---|
| `T01-…md` | 07:22 改 | 07:16 改(决策点)| ✅ 我的保留(**侥幸**)|
| `交接单/README.md` | 08:36 改(登记 T03)| 08:41 改(T02 归档行)| ✅ 双赢(**我读了它的最新版再改**)|
| `T03-…md` | 08:36 新建 | 08:39 scp 同步 | ✅ 无冲突 |
| `INDEX.md` | 未动 | 08:41 **整文件 Write 重写** | ✅ 无冲突 —— **但这是最危险的一步** |
**方案**:
1. **已落地** ✅:`交接单/README.md` §三 新增**第 0 条「先确认没有别的会话在写同一文件」**(4 步:① 查 git 状态 + `docs-sync-check.sh` ② 看 mtime 比自己上次见到的新 = 别人刚动过 → **先读再改** ③ **共享文件只用 Edit 精确替换、禁整文件 Write** ④ **改完立即 commit(本机,不 push)**);已同步双端(md5 一致)
2. **建议分工(单一写者)**:`交接单/*.md` 新单 = 规划会话;`交接单/README.md` 状态表 = 执行会话;`04-调整方案/` + `INDEX` + `BRIEF` + `README` + `skills/` = 执行会话;`03-路线图` = 执行会话(规划会话只读)
3. **建议工具**:**文档库 git 提交常态化**(每次改完 commit、**不 push**)→ 下一方能看到"谁刚改了什么"、冲突可检测;可选给 `docs-sync-check.sh` 加"近 10 分钟改动"提示
4. **今天验证有效的一条**:**共享文件用 Edit(精确 old→new)而非 Write** —— 别人改了同一处时 **Edit 会失败** = **天然的冲突检测**(我今天两次 Edit 失败正是它起作用:一次是我记错内容、一次正是需要先读再改)
**⚠️ 待用户决策**:是否让文档库**开始提交**(现有 25 项未提交);提交边界仍是"未明确要求不 push"。
## 会话收尾盘点(08:49-09:15)
**用户问**:「需要执行的任务完成了吗」。逐项核对本会话全部指令。
**⚠️ 重大发现:另一会话不仅在做 T03,还独立写了一个比我更强的防冲突工具**
- **`scripts/handoff-guard.sh`**(它 08:52 新增,只读 + `--claim/--release`):把"防冲突"从**文字约定**变成**一条命令 + 退出码**——① 占用锁硬判定 ② 越界改动(推送前,防 `git add -A` 带上别人的半成品)③ 热点提示 ④ 双端一致性。**它明确指出「mtime 只作提示、不作判定(分不清谁改的)」** —— 这点比我的方案**更严谨**(我把 mtime 当判据)。
- 它的占位机制:`mkdir 交接单/.doing-<单号>`(mkdir 原子:成功=拿到,`File exists`=别人在做 → 停手),完工 `rmdir`。
- 它 08:52 占过 T03、08:53 释放;`交接单/README.md` 被它连续改三次(08:41→08:45→08:53→最终 11,048 字节)。
- **它保留了我在 08:41 加的「写者协议第 0 条」并整编进它的体系**(grep 命中 1);并把我写的 T02 成果准确登记为「✅ 已完成并归档(2026-09-12,并行执行会话)」,还记了它自己的事故:**"把我已归档移走的 T02 又推回服务器,制造幽灵文件"**。
- **结论:防冲突应以它的 `handoff-guard.sh` 为准,我的文字约定收敛过去**(两套并存反而易混)。
**本会话我的任务盘点(全部完成,除 T01)**:
| 用户要求 | 状态 | 产出 |
|---|---|---|
| 内存为何占这么多 | ✅ | 62 MiB 全员共享 / 私有 106~117 MiB 分解 |
| 内存优化 + 512 能否降 | ✅ | 档案 58(NODE_OPTIONS + 编译缓存 + 384M,已上线)|
| 42 文件删除根因 | ✅ | USN 时间线 + 排除 git/杀软/文件系统 |
| 教训写红线 | ✅ | R7/R8(文档库 README+SKILL、工作区 MEMORY、**用户级 MEMORY**)|
| 越界自查 | ✅ | 5 项越界 + 7 项流程缺失 |
| 官方包核验 | ✅ | 24,923 文件全为 09-08,**零改动** |
| WorkBuddy 迁 E 盘 | ✅ | 脚本 + 用户执行 + 验收零遗漏 |
| 待办盘点 | ✅ | 全景清单(A/B/C/D/E/F 六类)|
| 插件页列表加高 + 200px | ✅ | 已上线;**档案 61 已补**(08:49,2914 字节)|
| A:ensure 脚本姿势对齐 | ✅ | 2 脚本(跑过 skip 验证,未中断用户)|
| B:T02 | ✅ | 消歧 + INDEX 28,809→7,468 + 归档 |
| C:同步缺口 | ✅ | 交接单 + 脚本(双端一致)|
| 冲突解决方案 | ✅ | 写者协议(已被对方整合)+ **采纳其 handoff-guard.sh** |
| **T01**(实例内「我的技能」)| ⏳ **未做** | 决策已定(扩展 business-plugins);**按串行要求等 T03 完成** |
**未提交**(双方均未提交):文档库 25+ 项、代码仓库 11 项。
**最终状态**:`docs-sync-check.sh` → **双端一致 110/110** ✓;`docs-audit.py` 退出码 **0** ✓。
## 提交完成 + 插件目录缓存可见化(09:0x-09:30)
### 提交(用户「确认提交和执行」)
| 仓库 | 提交 | 结果 |
|---|---|---|
| 文档库 | `96f8ef8`(档案 57-61 + T02 + handoff-guard)→ `5d2a5de`(档案 61 二次修正)→ `be42155`(档案 62)→ `b06f7dd`(manifest 刷新)| ✅ 工作树 0 项 |
| 代码仓库 | `3567226`(内存优化/重连动画/分区改名/列表自适应 + 4 新脚本)→ `0e141a4`(目录缓存可见化)| ✅ 工作树 0 项 |
**均只 commit、未 push**(按约定推送需用户明确说)。
**踩坑**:① git 是 Windows 原生的,`git commit -F` 必须给 **Windows 路径**(MSYS `/c/...` 不认);② 代码仓库**没配 git 身份** → 沿用历史提交者 `maogeigei <[email protected]>` 设了**仓库级**配置。
### 档案 61 的两次修正(插件页列表高度)
用户连报两次:①「列表都超出屏幕了」②「还是有页面滚动条,应该只有列表滚动条才对」。
- **根因**:第一版 `clamp(560px, 100vh-260px, 900px)` + **`padding-bottom: 200px`** ⇒ 页面总高 1252px > 视口 900px。
- **第一轮修正**:列表改 `calc(100vh - 420px)`、移除 padding-bottom。**仍然滚动** —— 因为我**只算了列表上方(372px),漏算下方 116px**(按钮行 50 + card padding 18 + **`#view` padding-bottom 48**)。
- **第二轮修正(最终)**:`max-height: calc(100vh - 520px)`(372+116=488,再留 32px 余量)。视口 900 → 列表 380px。
- **教训**:算"视口自适应高度"必须**上下都算**,不能只看列表上方。
### 档案 62:插件目录缓存状态可见化(用户「拉取的官方目录可以缓存,不用每次都拉取,增加一个主动刷新开关」)
**取证结论:功能早已存在,只是完全看不出来** —— `src/web/routes/whitelist.ts` 里已有:
- 磁盘缓存 `<dataRoot>/whitelist-cache/index.json`|**TTL 6 小时**(TTL 内 `getIndex()` 直接返回缓存、**不联网**)|`POST /api/plugins/whitelist/refresh`(强制拉取)|拉取失败降级用旧缓存并标 `stale`|`GET` **已返回 `fetchedAt` + `stale`**。
**前端三处误导**:① 加载提示写「**拉取**官方目录中…(首次约数秒)」② `wlInfo` 只显示 `stale`、**不显示 `fetchedAt`** ③ 按钮叫「刷新清单」看不出是"绕过缓存重拉"。
**改动(仅前端 4 处,13 增 4 删;后端零改动、无需重启)**:
- 按钮「刷新清单」→「**重新拉取目录**」+ title 说明("平时打开本页不会下载,直接读本地缓存")
- 新增 `relTime()`;`wlInfo` 增显「**目录缓存更新于 X 前(6 小时内直接复用,不联网)**」
- 加载文案 → 「加载目录中…(首次会从官方站下载一次,之后读本地缓存)」
- 流程提示明确化
**验证**:门户 `curl` 命中;静态文件即时生效。**已提交 `0e141a4`**。
**待确认**:若还要「自动更新:开/关」toggle(关掉后连 TTL 到期也不联网)→ 需给 `GET` 加 `cacheOnly=1` → **后端改动 + 重启平台(R8 须知会)**,本次未做。
### 协作状态(仍在进行中)
- **另一会话持续活跃**:`交接单/README.md` mtime 到 **09:23:41** 仍在变;它还写了 `scripts/handoff-guard.sh`(并行冲突预检:占用锁/越界改动/热点/双端一致性,**明确"mtime 只作提示不作判定"**,比我的文字约定严谨)。
- **一次虚惊**:收尾三件套报 audit 退出码 1,悬空 `['3','6']` in `交接单/README.md` → 复现时已**命中 0**、重跑 audit **退出码 0** ⇒ 那是**对方改文件过程中的过渡状态**,非我的问题。
- **我的真问题**:刷新了本机 `docs-manifest.json` 却**忘了 scp** → 对账报"内容不一致 1";已补传并提交。
- **最终**:`docs-sync-check.sh` **双端一致 112/112** ✓、`docs-audit.py` 退出码 **0** ✓。
- **防冲突**:后续应以对方的 **`handoff-guard.sh`** 为准(我的文字约定已被其整合)。
## ⚠️ 事故 63:我的"清理残留"断掉了 profile 依赖(09:28-10:00)
**用户报障**(附截图):「设置中功能管理 插件信息需要有限显示插件用途,还有**刚才启用插件失败了,失败了插件状态还是已启用**」。
### 用户的两个需求(均已改,**待实例重启生效**)
1. **列表显示插件用途** —— 改 `poc/business-plugins/lib/client.js` 渲染:名字行下方加 **description 副行**(数据来自 `/api/plugins/mine` 的 `description`,实测有值;缺失则不渲染)。**版本 0.2.2 → 0.2.3**。
2. **失败后状态未回滚(bug)** —— `pollTask` 的**成功分支有 `load()`、失败分支只 `setMsg`** ⇒ 本地 `plugins` 停留在用户勾选后的样子,徽章仍显示「已启用」,与「安装失败」自相矛盾。**修法:失败分支补 `load()` + 文案"(已回滚到改动前的状态)"**。实测 `/api/plugins/mine` 当时返回 `enabled: false` ⇒ **后端回滚是好的,纯粹是前端没刷新**。
### ⭐⭐ 但"安装失败"的真根因是我自己造成的(重要教训)
**故障链**:
1. **档案 60** 我把 ws 里的安装残留 tgz 移入 trash(含 `business-plugins-0.2.2.tgz`、`workspace-scoped-picker-0.1.4.tgz`);
2. 而 profile 的 `dependencies` 正写着 **`file:<ws>/business-plugins-0.2.2.tgz`**、**`file:<ws>/workspace-scoped-picker-0.1.4.tgz`**;
3. ⇒ 此后**任何 `pnpm add` 都在解析阶段 ENOENT 失败**(实测两个用户全中,用户侧就是「安装失败」)。
**这正是档案 57 §五.2 预警过的隐患,我清理时没想到会引爆它。**
**修复(自愈,不是把 tgz 放回 ws)**:给 `ensure-biz-plugins.cjs` 加 **`pruneBrokenFileDeps()`** —— 安装前遍历 `dependencies`,**只删 `file:` 且目标确实不存在**的条目(registry 依赖不动),随后 add 新包会写入正确的新路径。实测两用户各清理 2 个断裂依赖后**安装成功、`ws 保持干净`**。
### ⚠️ 连带发现并修复一个更严重的问题(R5 安全收敛失效)
`prune` 清掉 picker 的 dep 后,**`reconcileBundles` 的过滤规则**(`bundles.filter(b => b.startsWith('@deepseek-ai/') || deps.includes(b))`)把它**从 bundles 里一并剔除** ⇒ **`bundles` 从 5 掉到 4** ⇒ **档案 18 的「目录选择器收敛为仅见自有目录」(R5 安全收敛)失效**。
而 **`ensure-workspace-picker.cjs` 没有 reconcile 逻辑**(且它检测到"已装"就 `continue` 跳过),**补不回来** ⇒ 手工修:直接改 profile 的 `package.json` **补回 dep + bundles**(dep 指向 `<home>/.dsh-stage/…` 而非 `/opt/dsh/artifacts/` —— 后者是 `drwx------ root`,用户读不到,违反档案 52 规范)。
**最终验证**(两用户一致):`dependencies` 3 个包全指向 `.dsh-stage` ✓ | `bundles` 5 项(含 3 个 `@dsh-local`)✓ | `node_modules/@dsh-local` 3 个 ✓ | 属主归用户 ✓。
### 待办(未做)
1. **`workspace-scoped-picker` 脚本同样需要 `pruneBrokenFileDeps` + `reconcileBundles`** —— 否则下次它升级时会重蹈覆辙(本次是手工修的)。
2. **实例重启才生效**(client bundle 在实例启动时打包)—— 两处前端改动待生效;**按 R8 须先知会**。
3. **档案 63 未写**(本次事故 + 两处 UI 修改);**代码未提交**。
**教训**:**移动/清理任何"看似残留"的文件前,必须先确认没有 profile / 配置指向它**(`grep -r "<文件名>" <userRoot>`)。这次是我在档案 60 里"顺手清理"埋的雷。
## T03 开工:前置核查完成(09:49-10:05)
**用户指令**:「确认执行 按照串行顺序」→ 按 README 建议顺序 **T03 → T01 →(容量治理新需求)**,从 T03 起。
**① 状态确认(无冲突)**
- **无锁** ✓;单子状态 `⏳ 待执行(已规划,未开工)` ✓;产物目录**无 `dsh-plugin-mcn-suite`** ✓ → 未动工
- 另一会话近 25 分钟在改 `skills/dsh-decision-method/SKILL.md`(**不是 T03**)✓
- **已用对方工具占锁**:`bash scripts/handoff-guard.sh --claim T03 "exec-session-A(本会话)"` ✓
**② 关键发现:5 个决策点用户已全部拍板**(单子 §四 开头即写明,**不必再问**)
1. `social-workbench` **不进包**(Windows 本地服务 + `127.0.0.1` 被封 → 平台必然不可用)
2. `voxemw-cloud` **进包**(凭据走 env、无硬编码)
3. 入口形态 **A**(保留 `__mcnEntries` 多入口并列)
4. **业务技能随包投放**(用户明确要求「不分开管理」→ 推翻规划会话原"走门户分开投"的建议)
5. 包名 **`dsh-plugin-mcn-suite` v0.3.0**(版本必须每次递增)
**③ 结构与工作量的关键认知(单子 §2.1)**
**7 个包不是平行的,而是「1 个宿主壳 + 6 个功能页」**:`dsh-plugin-mcn` 注册 25+ 条 `/mcn/api/*` 路由、提供 `window.__mcnEntries`(功能页注册表)与 `__mcnNav`(页内路由),其余 6 包全靠往它注册;三个 douyin 包的 host 面只有 9 行空壳。⇒ **拆开"逐个启用"本身违背设计**(缺 mcn 则其余是死链),**整合是回归正确形态**。
**④ §五 平台化 P0 清单(8 项)**:① `homedir()/.dsh` → `$DSH_HOME`(mcn 14 处 + mcn-schedule 3 处)② 技能路径硬编码 → **只报技能名** ③ `spawn("powershell")` = Windows only → Linux 改法 ④ MCP `npx -y myai-mcp` 每次现拉 → 预装 ⑤ `.bak` 剔除 ⑥ 上传扫描 P0 自检 ⑦ **技能原文凭据扫描**(`scripts/mcp-config.json` 实测含 `MYAI_FEISHU_APP_ID=cli_a84d0a47f93e1013` + 私域 URL)⑧ §五#8 层级误判已更正(技能实际有 `subskills/mcn-data-insight/subskills/douyin-top-account/`,规划会话首轮 `-maxdepth 5` 差一层误判"缺失")
**⑤ 第 1 步「前置只读核查」完成** —— 事实清单:
| 项 | 单子预期 | 实测 |
|---|---|---|
| 技能树 `SKILL.md` / 文件数 / 体积 | 36 / 711 / 11 MB | **36 / 711 / 11 MB** ✓ 全对齐 |
| 一级子技能 | 5 个 | browser-harness、mcn-data-insight、mcn-dou-analysis、mcn-script-review、mcn-video-prompt ✓ |
| 门户候选池 | (需下架旧 7 包)| **只有 2 个第三方包**(`@liustack/modlens`、`dsh-univer-office`,均禁用)→ **7 个 MCN 包从未上传,切换成本更低** |
| 平台代码 HEAD | 取当前值 | `0e141a4` |
| `/opt/dsh/artifacts/` | 看命名与 `package/` 前缀 | business-plugins-0.2.3 / portal-entry-0.5.1 / workspace-scoped-picker-0.1.4 ✓ |
| 技能树源位置 | 单子未写明 | **`C:\Users\Administrator\.dsh\skills\mcn-short-video`**(**不在 `plugin_package` 下**;包内 `skills/` 是"要移进去的目标")|
**⚠️ ⑥ 前置核查发现的新风险(单子未提)**:**技能树 `~/.dsh/skills/mcn-short-video` 不在任何 git 仓库内** ⇒ 裁剪与改动**不可追溯、无回滚点** → **动手前必须先备份**。
**⑦ 剩余工作量(诚实评估)**:单子 §六 共 **13 步**,已完成第 1 步;剩余 12 步(建包骨架 → 移植 host 面 9 模块 → 合并 client 面 → P0 适配 8 项 → smoke → 打包 → 扫描 → 上传 → 切换 → 实测验收 → 归档)+ §6.1 技能随包 4 个阶段 + §6.2 两处文档漂移,**属数小时级工程,且含生产切换操作**。
**⭐ 建议**:**T03 交专门会话执行**(本会话已连续数十轮,上下文臃肿;T03 涉及打包/上传/实例切换等生产操作,需要清醒上下文以保证质量)。**锁已占位**,新会话 `bash scripts/handoff-guard.sh` 可直接看到占用状态并续做。
## 新建技能:dsh-decision-method(决策方法论)(09:32-)
**用户要求**:把本工作区所有会话里关于「改造 dsh 服务 / 优化功能交互 / UI 界面」的**用户有效决策 + AI 有效决策 + 如何确认最优解**,整合成一个**思考决策方法**的 skill。
**素材来源(只读)**:`04-调整方案/` 62 份档案(重点读 16/31/45/56 + 各档案头部「触发/用户裁定」)+ 五天工作日志(09-08~09-12)+ `BRIEF.md` / `交接单/README.md` / `06-工作台UI规范.md` / `README.md` / `INDEX.md`。
**注**:`conversation_search` 本次返回 **0 命中**(接口无结果),改走本地档案+日志取证,可靠性更高。
**产出**:`E:\ProgramData\.workbuddy\skills\dsh-decision-method\SKILL.md`(用户级技能,agent_created)。
结构 = 决策素材库(用户有效决策 **U1–U12** / AI 有效决策 **A1–A13** / 反例 **X1–X8**)+ **确认最优解**(判定矩阵 8 问 + 拍板前十问 + 验收口径分级 L1–L5)+ 决策流程十步 + **交互/UI 改造专项清单** + 决策语言对照表 + 决策记录模板 + 三层沉淀。
**与既有技能分工**:本技能管「怎么想、怎么定」,`dsh-change-workflow` 管「怎么落地」;先定案再执行。
**未做**:未 scp、未同步到 `dsh-server-docs/skills/`(技能必须本地加载才有用;入文档库归档需用户明确要求)、未 commit。
## 技能入服务器归档 + 加载确认(09:40-09:55)
**用户要求**:「同步到服务器,并且加载到 workbuddy skills目录中」。
### A. workbuddy 技能目录(本就在位,已核)
- 位置 = 用户级 `E:\ProgramData\.workbuddy\skills\dsh-decision-method\SKILL.md` —— **该目录即 WorkBuddy 扫描的技能目录**(与 `dsh-change-workflow` 同级)。28,029 B / 327 行 / UTF-8,frontmatter `name` 与目录名一致。
- ⚠️ **新技能不会在本会话的可用技能列表出现**(该列表在会话启动时构建)→ **需新开会话才会被识别**。
- 工作区级 `.workbuddy/skills/` **不存在**(工作区 `.workbuddy/` 下只有 `memory/`)→ 按默认只放用户级。
### B. 服务器归档(已完成,逐文件 md5 双端一致)
- 新增归档副本 `dsh-server-docs/skills/dsh-decision-method/SKILL.md`(与工作副本同 md5 `ee1861bb…`)
- scp → `/opt/dsh/docs/skills/dsh-decision-method/SKILL.md`,目录 **700** / 文件 **600**(对齐 `dsh-change-workflow` 的 drwx------ / -rw-------)
- 同批推送:`INDEX.md`(§二 加技能行)、`README.md`(模块一览加技能行)、`docs-manifest.json`(复跑刷新,83 条目)
- **对账 113/113 一致**(唯一"仅本地"= 并行会话刚占用的锁 `交接单/.doing-T03/OWNER`,非我的文件;**未用 `--push` 整批,逐文件 scp 避开幽灵文件**)
- **未 git commit / push**(用户未要求;红线)
### C. 途中修掉自己引入的一个悬空引用(重要)
- 首跑 `docs-audit.py` **退出码 1**:`skills/dsh-decision-method/SKILL.md 引用了不存在的档案号 ['2']`
- 根因:审计正则 `档案\s*(\d{1,2}[a-z]?)` 的 **`\s*` 会跨行** —— 我写的 `…固化进 skill 或档案` 行尾的"档案" + 换行后的列表项 `2.` 被读成裸号 `2`
- 修法:改写为 `…固化进 skill,或写进 \`04-调整方案/NN-*.md\` 改造档案(可复用的留 skill,一次性的归档)`(行尾不再紧邻数字);**两份副本同步改**
- 结果:`docs-audit.py` **退出码 0、结论「无 P0 级问题」**
- 📌 **沉淀:这是文档库已记坑(`档案`+字符类)的变体 —— 凡「档案」后换行紧跟有序列表数字都会误报。写文档时不要让「档案」落在行尾。**
### D. 发现但未处理(按 R7 先报告、后动手)
1. **`scripts/docs-manifest.py` 打印阶段崩溃**:`TypeError: %d format: a real number is required, not str`(第 100 行 `'%d' % i['num']`)—— T02 把 `num` 键改成字符串(支持 `37a`)时**漏改这一处**。JSON 在打印前已写出(条目 83、可解析),故不阻断收尾;**一行修复(`%d` → `%s`)即可,未擅自动手**。
2. **`INDEX.md` 头部「最后核对」数字已过期**:`md 78 份`(实测 **83**)、`档案已至 60`(实测 **62**)、代码 HEAD `ebe8075`(代码仓库今晨已到 `0e141a4`)。与本次改动无关,**未一并改**(避免混入无关修正)。
3. 服务器 `skills/dsh-change-workflow/` 下有一份本地没有的 `SKILL.md.bak-20260911-2055`(备份残留,对账不计)。
## 用户「确认无误后处理」→ 两项修正已落地(10:04-10:10)
**用户指令**:「确认无误后处理」(授权我上一轮报告的两项)。**先核实事实再动手**,结果**推翻了我自己上一轮的一个判断**。
### 核实(不凭记忆)
| 待改项 | 我上轮的说法 | **实测** | 结论 |
|---|---|---|---|
| md 份数 | 78 → 83 | `find` 计数 = **83** | ✅ 应改 |
| 档案已至 | 60 → 62 | `04-调整方案/*.md` = 64 文件(含 README)、最大编号 = **62** | ✅ 应改 |
| 代码 HEAD | 「今晨已到 `0e141a4`」→ 想改成它 | **服务器 `/opt/dshs` HEAD 就是 `ebe8075`**(权威值,未变);`0e141a4` 是**本机镜像**的 HEAD | ❌ **我错了 → 不改**(INDEX 原本就对) |
**代码仓库真实状态(重要,此前未记)**:本机镜像 `D:\github\dsh_shenxian` = `0e141a4`,**包含**服务器 HEAD `ebe8075` → 即 `3567226`/`0e141a4` 两个提交**只在本机、服务器还没落**;服务器工作树有 **7 M + 4 ??** 未提交(`portal.html`/`orchestrator.ts`/`proxy.ts`/`poc/*`/`ensure-*.cjs`)。→ **代码侧存在"本机领先、服务器未落"的落差**,属既有状态,本次未动。
### 已改(两处,均为最小改动)
1. **`scripts/docs-manifest.py` 第 100/103 行**:`%-3d` → `%-3s`(`num` 现为字符串,支持 `37a`;T02 漏改的就是这两处)。**行尾保持 LF(0 CRLF / 104 行)**。
- 验证:脚本**完整跑通、退出码 0**,hot 30 / warm 29 / cold 4 全部正常打印(`档案 38a` 正确显示)。
2. **`INDEX.md` 头部「最后核对」**:`md 78 份` → **83**;`档案已至 60` → **62**;`代码 HEAD ebe8075` **保持不变**(已核实为服务器权威值)。
### 验证与同步
- `docs-audit.py` → **退出码 0、结论「无 P0 级问题」**
- `docs-manifest.json` 内容**未变**(md5 仍 `10c3b9c4…`)→ 无需重推
- scp 推送 `scripts/docs-manifest.py`(755) + `INDEX.md`(600);**md5 双端逐文件一致**(`c1bf95be…` / `c124285c…`)
- 双端对账:**一致 113 / 内容不一致 0 / 仅服务器 0**(唯一"仅本地"= 并行会话的锁 `交接单/.doing-T03/OWNER`)
- **未 git commit**(用户未要求)
### 顺带发现(按 R7 只报告、未动手)
- `docs-sync-check.sh` **会把占用锁目录 `交接单/.doing-<单号>/OWNER` 算进"仅本地"** → 只要有会话持有锁,对账就恒报「存在差异 ❌」,容易被误读成"有文件没推"。建议把 `交接单/.doing-*` 加入排除(与 `handoff-guard.sh` 的【2】已有的 `grep -v` 一致)。**一行改动,未做。**
## 复盘「用户时间被技术问题吃掉」+ 新建 `dsh-feature-first`(11:16-11:35)
**用户原话**:「复盘工作空间内所有会话,感觉现在大多数时间都在沟通技术问题,我想把精力放到平台功能如何搭建上,AI 根据平台功能需求自己思考和解决技术相关问题 如何才能实现」。
### 复盘(取证,非估算)
对含「触发」字段的 **42 份**档案按来源分类(命令:`grep -Hn "触发" 04-调整方案/*.md`):
| 类别 | 份数 | 占比 |
|---|---|---|
| 用户的功能/交互需求(用户主场) | 15 | 36% |
| **技术类**(用户被拉进技术判断 / AI 技术排查) | 17 | **40%** |
| **用户报障**(用户只能看到现象,被迫当测试) | 10 | **24%** |
⇒ **技术 + 报障 = 64%**。
**五个根因**:① 技术问题被"决策化"上抛(用户没有判断依据只能点头);② 需求缺"规格层"(用户说现象 → AI 直接跳技术方案,中间规格没沉淀);③ 报障驱动(输入大量来自"坏了");④ 没有"技术默认值"= 没有 AI 自主决策的授权边界,每次重新分析重新上抛;⑤ 交付用技术语言(commit/文件/md5),用户只能靠技术语言参与验收。
### 落地:新技能 `dsh-feature-first`(功能优先协作协议)
核心 = **把"事前请示"改成"默认自主 + 事后可推翻"**。六块内容:
1. 用户输入收窄为**功能卡 4 问**(谁用 / 在哪用 / 做什么 / 怎样算成功)
2. **AI 自主决策 9 类白名单(永不问)**:技术选型 / 实现路径 / 命名结构 / 性能调参 / 部署同步 / 排查方法 / 版本依赖 / 兼容降级 / 文档技术内容。口诀 =「用户能否从功能视角判断这个选项的好坏」——不能就是 AI 的活
3. **只上抛 2 类**:功能语义分叉(选项间有用户能感知的差别)+ 红线门禁(R5 扩大 / R7 批量 / R8 中断)
4. **上抛语言转换表(强制)**:禁止出现包名/环境变量/路径/commit/API 路径,必须改写成"你能感知的差别"
5. **报障闭环前置五条**:错误给人话 + 等待有反馈 + 状态可自查 + 能自愈不报错 + 缓存状态可见。口诀 =「用户遇到这个情况会不会只能来问我」
6. **交付回执格式**:做了什么(功能)→ 你现在能看到什么 → **不用你决策的技术选择(已定,可推翻)** → 技术附录折叠
**双位置**:工作副本 `E:\ProgramData\.workbuddy\skills\dsh-feature-first\SKILL.md`(md5 `65e7531a…`)+ 归档副本 `dsh-server-docs/skills/dsh-feature-first/` → scp 到 `/opt/dsh/docs/skills/dsh-feature-first/`(700/600 ✅)。INDEX §二 + README 模块一览各加一行(**只放指针,不复制全文**)。
### 顺带校准:INDEX 头部「最后核对」绝对值已改成不易腐写法
- 实测:同日 83(10:04)→ 85(11:16)→ 87(11:22)**三次作废**(并行会话持续新增档案)
- 处置:**不再写死篇数/档案号**,改为「以 `python3 scripts/docs-manifest.py` 复跑为准」+ 代码 HEAD 给出取数命令(保留最后核对值 `ebe8075`);附一句实测证据说明为什么
- 理由:写一个明知数十分钟后就错的值,比不写更糟
### 本轮验证与同步
- `docs-manifest.py` **exit 0**;5 个文件 scp 后 **md5 逐文件双端一致**(SKILL.md / INDEX.md / README.md / docs-manifest.json / scripts/docs-manifest.py)
- 双端对账:**一致 114 / 内容不一致 0 / 仅服务器 0**;「仅本地 4」= **并行会话的 3 个新档案(64/65/66)+ 其占用锁**,非我的文件,不代推
- **未 git commit**(用户未要求)
### 发现(按 R7 只报告)
- ⚠️ **`docs-audit.py` 退出码 1,但不归属我**:`04-调整方案/64-接入AnySearch搜索provider.md 引用了不存在的档案号 ['63']` —— 并行会话跳号(62 → 64/65/66),64 里引用了不存在的 63。属其在建文件,**未替其修改**。
- 代码仓库落差(前一轮已记):本机镜像 `0e141a4` 领先服务器 `ebe8075` 两个提交未落。
## 让规则「默认生效」+ 补齐技术实现裁决顺序(11:45-12:05)
**用户两问**:① 能不能形成一套决策方法,后续技术实现让 AI 按方法找最优决策?② 如何让 workbuddy 的项目任务执行会话**默认**执行这套规则,**需要开启定时任务跟进吗**?
### 关键发现(真因):工作区 MEMORY.md 超限被截断
- 实测 `D:\AI技能\aliyun-dsh-server\.workbuddy\memory\MEMORY.md` = **10,242 字符 / 16,893 字节**
- **本次会话注入给我的内容只到 ~7,960 字符处被切断**(截断点正好落在「并发冲突防治」第二条 bullet)→ **R7/R8 红线、技能资产、实例机制全都没送达会话**
- ⇒ **"规则没有默认生效"的真因不是载体错,而是载体撑爆了**
**处置**:先备份 `MEMORY.md.bak-20260912-consolidate`(16,893 B)→ 重写为 **4,548 字符 / 7,939 字节**(原 44%,占推测上限 57%,有余量)。
新结构 = ①**默认工作规则(最前,含功能卡输入协议 + R1-R8 全量)** ②技能资产 ③仓库与推送约束 ④**现行事实→查单一来源(不再复制细节)** ⑤长期操作坑 6 条 ⑥实例关键机制 3 条。
> 被移出的细节全部**本来就有单一来源**(`BRIEF.md` / `INDEX.md` / `DEPLOY-本部署.md` / `06-工作台UI规范.md` / 各档案),故无信息丢失。
### 机制认知(回答"如何默认生效 / 要不要定时任务")
| 载体 | 是否自动注入 | 可靠性 | 用途 |
|---|---|---|---|
| **工作区 `.workbuddy/memory/MEMORY.md`** | ✅ 每会话注入 | **最高(但有长度上限)** | 默认规则、红线、约定 |
| `SOUL.md` / `USER.md`(用户级) | ✅ 每会话注入 | 高 | 全局姿势与用户偏好 |
| **技能**(用户级/项目级) | ❌ 模型按 description 判断触发 | 中(**是"按需",不是"默认"**) | 领域方法论 |
| `settings.json` | — | — | 已有 `sandbox.extraAllowWrite` / `enabledPlugins` / `claw`;**本项目未配 hooks** |
**结论:不需要定时任务** —— 定时任务解决"到点无人值守跑",解决不了"每次会话默认遵守"。默认生效靠**注入型载体**(MEMORY.md + SOUL.md),故本轮做的是 MEMORY.md 瘦身。
### 补齐:`dsh-decision-method` v1.0.0 → v1.1.0
新增 **§4.4 技术实现的默认裁决顺序(AI 自主用、不问用户)** —— 8 条按序自答的算法:
`① 既有机制能复用吗 → ② 有更小改动吗 → ③ 能用配置解决吗 → ④ 只改一层吗 → ⑤ 失败代价对称吗 → ⑥ 可验证吗 → ⑦ 是收窄还是扩大 → ⑧ 官方契约耦合面多大`
**两条硬约束**:③ 优先于 ②(能配置就不改码,改码要 build+重启会触 R8);任一条与红线冲突 → 红线赢。产出 = 写进档案「技术选择」段(含被否决选项与否决理由)→ 用户**事后可推翻、事前不被打扰**。自检清单加第 8 问。
同步:两份副本 md5 一致 `c5b3938e…`,已 scp 服务器(`/opt/dsh/docs/skills/dsh-decision-method/SKILL.md`),**双端一致**。
### 未做 / 待用户定
- **定时任务**:提议一个真正适合定时的用途(**每日/每周巡检**:双端文档对账 + `docs-audit.py` + 未释放的 `交接单/.doing-*` 占用锁 + 待办漂移)——今日已多次被这些坑到。**等用户点头再建**。
- 技能仍放**用户级**(`E:\ProgramData\.workbuddy\skills\`),未建项目级 `{workspace}/.workbuddy/skills/`(可选:让本项目的技能只在本项目可见)。
- 未 commit(用户未要求)。
## 「提问闸门」:在 AI 问用户之前强制先自判(11:54-12:10)
**用户原话**:「有没有办法 AI 问我决策时,能先根据方法自动判断,如果没办法判断我再决策」。
→ 要的不是"写进文档",而是**在提问动作发生的那一刻被拦住**。
### 机制:`PreToolUse` hook + matcher `^AskUserQuestion$`
**取证来源(权威)**:WorkBuddy 本地自带 CodeBuddy 官方 hooks 文档 `cli/dist/web-ui/docs/cn/cli/hooks.md`(27+ 事件,Beta);并用 grep 确认本机 CLI 构建**确实实现了** `PreToolUse` / `allowUntrustedFrontmatterHooks`。
**关键点**:`PreToolUse` 支持按**工具名**做 matcher,而 AI 向用户提问用的就是 **`AskUserQuestion`** 工具 → 可以精准拦在"问出去之前"。
- 事件触发:工具参数已生成、工具调用被处理**之前**
- hook `type: "prompt"` = 交给 lite 小模型做语义判断,返回 `{"ok": true|false, "reason": ...}`
- `ok:false` → **阻止该工具调用**,`reason` 传给 Agent(我)→ 我读到"这属于你自己该定的"就改为自判
### 已配置(`E:\ProgramData\.workbuddy\settings.json`)
```json
"hooks": { "PreToolUse": [ { "matcher": "^AskUserQuestion$",
"hooks": [ { "type": "prompt", "timeout": 30, "prompt": "<三分类判据>" } ] } ] }
```
prompt 让 lite 模型把提问分三类:**A 功能语义分叉**(选项间有用户能感知的差别)/ **B 红线门禁**(扩大权限·中断在线用户·批量>10 文件)→ 放行;**C 技术项**(选型/路径/命名/调参/部署/排查/版本/兼容/文档技术细节;**特征=出现包名·环境变量·路径·commit·端口·内存数值·代码标识符**)→ 拦截并给出 8 条裁决顺序要我自答;**无法确定 → 放行**(宁可问、不卡死)。
理由文本里内嵌了 8 条,**不依赖技能被加载**(换成别的项目也成立)。
- 备份:`settings.json.bak-20260912-hooks`(2172 B);改后 4049 B,`json.load` 通过,顶层键 = sandbox / claw / enabledPlugins / **hooks** / autoLaunchDesired
- 配置目录依据:CLI 含 `WORKBUDDY_CONFIG_DIR`(判定链 `WORKBUDDY_CONFIG_DIR ?? CODEBUDDY_CONFIG_DIR ?? ~/.workbuddy`)→ 即现有那个 settings.json
### ⚠️ 未验证 / 前提(必须如实说)
1. **是否真的生效未验证** —— hooks 是"**启动时快照**",且官方文档写明「外部修改 hooks 不会立即生效,需在 `/hooks` 面板审核后才应用」。**需重启 WorkBuddy(或新会话)+ 在 `/hooks` 看是否已注册**。
2. **语义判定无法离线自测** —— 判定由 lite 模型执行;我做过一次关键词自测但**结果无意义(判定逻辑太糙)**,不作数。
3. **作用域是用户级**(所有项目都会拦)。若在非 dsh 项目误拦,理由文本仍能指导自判,影响可控;如需只对本项目生效,改用 `<项目根>/.workbuddy/settings.json`(**该路径是否被 WorkBuddy 读取未验证**)。
4. **关闭方式**:删掉 `settings.json` 的 `hooks` 键,或直接还原 `settings.json.bak-20260912-hooks`。
### 兜底(今天即生效,不依赖重启)
工作区 `MEMORY.md §一.1` 增加 **⛔ 提问闸门(硬要求)** 一条:调用 `AskUserQuestion` 前先按 `dsh-decision-method §4.4` 自答,能定就不问。注入型载体**无需重启**,与 hook 互为保险。
## 边界落定:「方法管不到的还是要问」+ 方法演进不再上抛(11:58-12:10)
**用户原话**:「有超过现有决策方法边界的事情,还是需要问的,以后决策方法的问题就不需要再问了。」
**我读了两件事,都落成文字**(若读错请纠正):① **边界内 → 自决;边界外 → 必须问**;② **方法本身的修订也不再上抛**(发现缺口直接改、改完报一句)。
### 写进 `dsh-feature-first` v1.0.0 → v1.1.0
- **§3 标题**:「只准上抛的 2 类」→ **3 类**(新增 (c) 超出方法边界)
- **新增 §3.4「超出决策方法边界的事 —— 必须问」8 类**:① 业务目标与优先级(做不做/先做哪个)② 花钱与资源承诺 ③ 对外承诺与合规(备案/资质/合同)④ 需用户提供的账号凭据或审批 ⑤ 无客观优劣的体验偏好(审美/文案/默认值)⑥ 影响面超出本平台 ⑦ 红线门禁(R5/R7/R8)⑧ 方法确实判不准。
**统一判据 = 「有没有客观可判的优劣」:有 → 方法能判,自决;没有 → 用户的取向,必须问。**
⚠️ 并写明这条是 §2(9 类自决白名单)的**例外出口**,也是闸门 fail-open 的依据。
- **新增 §3.5「方法本身的演进 —— 不再上抛」**:边界内的一切判断不问;**方法修订也不问**(直接改 + 记录);**唯一例外** = 修订会**扩大 AI 自主权或收窄用户门禁** → 属边界外第 7 类,必须问。
- description 同步重写(含"边界定义"与"方法演进"两项);三处副本 md5 一致 `e25f7505…`,已 scp 服务器。
### 闸门判据同步升级(否则会误拦该问的事)
`settings.json` 的 hook prompt 从三分类 → **四分类**(783 字符):
- **A 功能语义分叉 / B 红线门禁 / D 超出方法边界 → 放行**(D 的八项已内嵌)
- **C 技术项 → 拦截**(特征:出现包名·环境变量·路径·commit·端口·内存数值·代码标识符)
- 末句加固统一判据:「**有没有客观可判的优劣?有 → C 类自己定;没有 → 用户的取向,放行去问。**」
- 被拦时的 reason 末尾改为「若你确认这属于 **A/B/D** 类,说明理由后重新提问一次」(原为 A/B)
### 核验
- `settings.json` **JSON 解析 ✓**、四分类特征串全部命中、4420 字节(原 2172;备份 `settings.json.bak-20260912-hooks`)
- `MEMORY.md` **5,246 字符 / 9,386 字节 = 推测注入上限的 66%**(仍有余量,但要留意继续增长)
- 技能三处(工作副本 / 归档副本 / 服务器)md5 一致
### 仍未变的前提
hook **是否真生效仍需重启 WorkBuddy + 在 `/hooks` 面板确认**(启动时快照 + 外部修改需审核)。在此之前,靠 `MEMORY.md` 的硬要求兜底。
## 核实「是否整理了所有历史会话」→ 结论:首版没有,已回补(12:00-12:25)
**用户要求**:「确认是整理了所有历史会话记录 沉淀的可复用决策方法」——要求核实,不能靠记忆答。
### 核查过程(真找到了会话记录在哪)
| 项 | 结果 |
|---|---|
| 会话记录位置 | `E:\ProgramData\.workbuddy\projects\d-AI技能-aliyun-dsh-server\`(**工作区 cwd 决定目录名**) |
| 会话文件 | **5 个** `.jsonl`(+ 各 1 个 `.file-rollback.ndjson` + `.meta.json`) |
| 规模 | **44 MB / ≈8,900 行** |
| 时间跨度 | 主线 `b2817961` = **09-08 20:38 → 09-12 10:11**(5,802 行 / 31 MB);其余 4 个为 09-11~09-12 |
| 行结构 | `{"type":"message","role":"user","content":[{"type":"input_text","text":...}]}`;另有 `reasoning`(1165) / `function_call`(1491) / `file_result` / `file-history-snapshot` |
| **用户真实发言** | **180 条**(剥掉 `<system-reminder>` 前言后)—— 主线 135 / 其余 45 |
### 诚实结论(**对用户不利的那一半也要说**)
- ❌ **首版 v1.0 没有读原始转录** —— 当时 `conversation_search` 两次返回 0 命中,素材只来自**62 份档案 + 五天工作日志**(即会话的"结论层 + 过程层"沉淀)。
- ✅ **但覆盖良好**:逐条比对后,**U1–U12 里 11 条能在原始发言中找到对应原话**(例:U1←msg63/67/71、U2←msg119、U5←msg99/106、U6←msg85、U8←msg40、U9←msg53、U10←msg102/107、U11←msg116)。→ 说明"档案+日志"这套沉淀**确实抓到了主要决策**。
- ⚠️ **确实漏了 7 条**(只在原始对话里看得见,档案/日志没显式记为"决策模式")→ 已补为 **U13–U19**:
- **U13** 我报的数字会被用户当事实基础(msg「当前实况:…212 MiB 和 329 MiB:为什么…」;档案 58 曾把字节当 KB)
- **U14** 「该不该留」的判据是**有没有复用价值**(「这些脚本基本都是根据某个对话任务产生,没有复用价值」)
- **U15** 用户盯**产品级容量约束**(「应该属于控制用户上限,不能让 10 个用户注册每个用户体验都差」)
- **U16** 用户给的"实现建议"是**意图**不是硬要求(鼠标移动→拉起实例,被论证 OOM 后接受否决)
- **U17** 用户当**执行手** → 必须给可直接粘贴的完整命令(「给我个命令去服务器上执行就行」)
- **U18** 用户会**主动关闭**一条线(「忘记这个项目把」「还没准备好 后面再说」)
- **U19** 能力认知类提问占大量往返 → 靠「能力清单」交付物消除
### 沉淀的可复用件
**`dsh-server-docs/scripts/extract-user-voice.py`**(只读,可复跑):抽出工作区**全部历史会话**的用户真实发言。
- 自动定位项目目录(**实测规则:盘符小写 + 分隔符换 `-`**,如 `D:\AI技能\aliyun-dsh-server` → `d-AI技能-aliyun-dsh-server`;**支持从子目录向上回溯 + 归一化模糊兜底**——首版按当前 cwd 推导失败过两次)
- 必须剥 `<system-reminder>` 前言才是用户原话;`--full` 全文 / `--needle 关键词` 查某个决策的来龙去脉
- ⚠️ **别把输出重定向进文档库目录**(会被 `docs-sync-check` 计成"仅本地")
### 结果
- `dsh-decision-method` **v1.1.0 → v1.2.0**:新增 **§0.1 素材来源与复跑方式(honest provenance)**、§1 扩到 **U1–U19**、description 更新
- 三处(工作副本 / 归档副本 / 服务器)md5 一致 `8b33d103…`;新脚本已 scp(755)
- `docs-audit.py` 退出码 1 **仍只来自并行会话的 `档案 64 → 63` 悬空引用**;**我的文件 0 引入**
## 诊断「为什么还在让我确认技术问题」(14:40-15:05)
**用户报**:「为什么和AI对话 还是在让我确认技术问题,你做的设置没有用呢」→ 要求看工作区「任务执行2」的最新对话。
### 定位「任务执行2」
从 `workbuddy.db` 的 `sessions` 表(`title` / `custom_title`)查到映射:
| 会话 | 名称 | 创建 | 最后活动 | 备注 |
|---|---|---|---|---|
| `6cd67b31` | **决策方法** | 09-12 09:32 | 14:42 | **本会话** |
| `4f40f882` | **任务执行2** | 09-12 **10:13** | 14:39 | ← 用户要看的 |
| `a0b34e9f` | 任务执行3 | 09-12 10:10 | 13:26 | anysearch 接入 |
| `ca58e09f` | 方案规划 | 09-11 23:52 | 13:25 | |
| `b2817961` | 任务执行 | 09-08 20:38 | 10:16 | 主线 |
### 诊断结论(两层,第一层是我的错,第二层更关键)
**① hook 确实没在那些会话生效** —— `settings.json`(含 hook)写入时间 **11:58**,而「任务执行2」**10:13 就创建了** → 会话的 hooks 是**启动时快照**,早于配置的会话**根本没有这道闸门**。我在上一轮说过"需重启/新会话",但**把宝押在 hook 上、没同时铺好注入型通道**,这是我的判断失误。
**② 但即使闸门生效,6 次上抛里也只有 1 次该被拦** —— 逐条核对「任务执行2」的 6 次 `AskUserQuestion`:
| 时间 | 问的什么 | 判定 |
|---|---|---|
| 10:34 | 21 处 Windows 指引怎么处理 | ❌ 纯技术项(该自己定) |
| 10:21 | 行尾 CRLF 怎么处理 | ✅ 该问(R7 批量换行符) |
| 11:16 + 11:42 | 验收用哪个实例/账号 | ✅ 该问,❌ **连问两次** |
| 13:32 | admin 崩溃怎么修 | ✅ 该问(R8),❌ 选项混了三种**技术路径** |
| 14:39 | 选 A/B 方案 **+** 要不要重启 | ✅ 红线该问,❌ 技术方案不该问 |
⇒ **"设置没用"的真正形态不是"问得太多",而是「把该问的红线问题和不该问的技术方案捆成一个提问」** —— 用户被迫先读懂两套技术方案,才能回答那个"要不要重启服务"。**体感就是"又在让我确认技术问题"。**
### 修正(三处)
1. **`dsh-feature-first` v1.1.0 → v1.2.0**:新增 **§3.6 拆包上抛** —— ① 红线问题**剥出来单独问**,只问"要不要现在动生产 / 影响谁 / 断多久 / 能否避开";② **技术形态自己定**,作为已定项陈述("我按 B 做…已定,可推翻");③ 一轮最多一个问题、**不许连问两次**。附该会话 6 次上抛的逐条判定 + 正确写法示例。三处 md5 一致 `c735b608…`。
2. **用户级 `~/.workbuddy/MEMORY.md`(第一次改这里)**:加上跨项目规则「不要拿技术项来问用户」+「只问两类」+「⛔ 不许捆包」+ 判据一句话。**这是每会话必注入的通道,新会话在任何项目都生效**(hook 之外最可靠)。体积 3,496 字符 / 7,020 字节。
3. **给用户一段可粘贴的会话内规则**(见交付回复)—— 因为**已开的会话收不到任何注入**,只能靠用户把这段话贴进去即时生效。
### 待用户定(我没替他决定)
「任务执行2」14:39 那个提问仍悬着:**admin 实例因 anysearch 插件不兼容崩溃熔断 → 要不要现在重启 `dshs`**(R8,影响当前在线用户)。属红线问题,**必须用户点头**,我不代答。