session-mechanism: 修复钩子静默失效 + 3 处判据缺陷;禁「变相征询」
1) stop-dialog-guard: session_budget() 早退路径返回 2 值、末尾返回 3 值,调用方按 3 值解包
⇒ transcript > 64 MiB 时每轮 ValueError。因 fail-open(异常仍 exit 0),
宿主零报错、install.py --verify 只判 rc=0 ⇒ 假绿;实测 86 条 EXCEPTION,
死掉的是整条(水位/收口、接续机制起点、预算告警、门禁自检、路径自检)。
2) session-rules-check 三处判据:
· hook_reg 按旧文件名找 ⇒ 合并成 prompt-guards.py 后每轮假红 ⇒ 改为一组可接受名
· snap_sync 拿 mtime 当内容判据 ⇒ 连续 4 天假红 ⇒ 改为复用抽取器本体比对内容
(变异对照:截断快照能报 fail,非恒绿)
· mem_ptr 只查全局技能根 ⇒ 工作区自带技能被判悬空 ⇒ 改查「全局 ∪ 工作区」
3) pitfalls 新增 P0-95(改判据必须重跑变异对照;fail-open + 只看 rc=0 = 假绿温床)
4) 回复排版核心块新增「变相征询同样禁止」(先只报不动/等你发话/我倾向X你看呢
这类不带选项的待定清单,一律按待拍板项写:问题+说明+各候选优缺点+倾向)
This commit is contained in:
1 parent
19101acd65
commit
64dd82073b
21 files changed
+8444
-4523
No files matched your search
@@ -13,6 +13,11 @@
|
||||
- **三禁**(⛔ 任一命中 = 该条回复**作废、重写后再发**):**表格** / **长散文** / **碎标签堆叠**。
|
||||
- **并列内容竖排**:多个候选、多项并列各占一段、逐条编号;⛔ 不横排、⛔ 不挤进一段、⛔ 不塞成表格的列。
|
||||
- **待拍板项**:放回复**最后一节**,逐条编号;每条写清「问题 + 说明(影响谁/断多久/花多少钱/有无不可逆)+ 各候选的优点与缺点 + 倾向」。
|
||||
- 🔴🔴 **「变相征询」同样禁止**(2026-10-06 用户据实况追认):凡是**要用户拿主意**的事 ——
|
||||
包括「**先只报不动**」「**等你发话**」「我倾向 X,你看呢」这类**不带选项的待定清单** ——
|
||||
**一律按上一条写成「待拍板项」**(问题 + 说明 + **各候选的优点与缺点** + 倾向)。
|
||||
⛔ 不许用一句"倾向"或"等你发话"**顶替**选项;⛔ 也不许把「没写选项的清单」当成"只是汇报"蒙过去。
|
||||
反过来:**已自决**的事写成陈述句(「我选了什么,可推翻」),⛔ 不要混进待拍板清单里充数。
|
||||
- ⛔ **不用征询句收尾**(「要我…吗/请确认/你看怎么办」);能自决策的直接做完,只留一句"我选了什么(可推翻)"。
|
||||
- ⚠️ 若**本工作区另有更新的定稿**(环境文件里有更细的排版节)⇒ **以那份为准**,本块是通用形态。
|
||||
<!-- REPLY-CORE:END -->
|
||||
@@ -0,0 +1,400 @@
|
||||
# 决策方法论(怎么想、怎么定)
|
||||
|
||||
<!-- ══════════════════════════════════════════════════════════════════════════
|
||||
🔴 搬运登记块(2026-10-06 · 技能 `session-mechanism` 侧维护,⛔ 不是原文内容)
|
||||
──────────────────────────────────────────────────────────────────────
|
||||
来源:`skills/dsh-decision/references/00-决策方法论.md`
|
||||
bytes=33197 | md5=ab06e86031a50df01ae16b58a533b2c9 | 376 行
|
||||
附件(同批搬入,逐字一致):
|
||||
`dsh-decision-method/素材库-U-用户决策.md` 24597 B md5=94c9e860148f4265f1e21e5322346f94
|
||||
`dsh-decision-method/素材库-A-AI推理.md` 19914 B md5=89fc178e671c989d9079c1def20591da
|
||||
`dsh-decision-method/素材库-反例-X.md` 5712 B md5=8bce93e8c1ce71d17e6d33aa9a2d7724
|
||||
|
||||
🔴 **为什么搬进来**:本包 `SKILL.md:395` 既定口径(2026-10-04)=
|
||||
「**判据实体就在本档正文里** ⇒ 只复制这一个技能到别的机器,这些功能全部可用,
|
||||
⛔ 不依赖任何其他技能」。而实测(2026-10-06):10-04 那次**只搬了
|
||||
`01-功能优先协作协议`(问不问)**,**决策方法论(U27/A6 那套)从未搬入**
|
||||
⇒ 本包正文里搜 `U27`/`A6` **零命中** ⇒ 口径落空。本次补齐。
|
||||
用户口径(2026-10-06):**「决策方法不是早就合并到 会话技能了吗」**
|
||||
|
||||
⚠️ **搬运纪律**:本档**逐字未改**(含原文里已过时的措辞),**唯一一处例外**见下。
|
||||
改判据请改**本包这一份**;`dsh-decision` 那份视为副本。
|
||||
🔧 **本包相对源件的唯一修正(1 处)**:第 54 行附件链接
|
||||
`素材库-U-提报用户.md` → `素材库-U-用户决策.md`
|
||||
(源件文件名实为「用户决策」;此为**源件既有断链**,一并修掉,⛔ 不留断链)
|
||||
══════════════════════════════════════════════════════════════════════════ -->
|
||||
|
||||
> **归属**:技能 `dsh-decision` · 详情档(主干 `../SKILL.md`)
|
||||
> **本档覆盖**:原技能 `dsh-decision-method` **全文**(正文 263 行 + frontmatter 变更历史)
|
||||
> **provenance**:本机版(WorkBuddy 实况)
|
||||
> **搬运方式**:**逐行未改**;内部附件链接已改写为 `dsh-decision-method/<附件名>`(附件在本目录下)
|
||||
> ⚠️ 原技能 `dsh-decision-method` **已合并退役** ⇒ 见到该名按本档读。
|
||||
|
||||
---
|
||||
|
||||
|
||||
# dsh-decision-method — 平台改造的思考与决策方法
|
||||
|
||||
> **一句话**:把「这个需求该怎么定」从**直觉**变成**可复用的判定**。
|
||||
> 材料来源 = 本工作区 `dsh-server-docs/04-调整方案/` 62 份档案 + `.workbuddy/memory/` 五天日志里的**真实决策痕迹**(含被驳回的)。
|
||||
> 每条模式都带**实例出处**,可以回溯核验,不是抽象原则。
|
||||
|
||||
---
|
||||
|
||||
## 0. 定位:和 `dsh-change-workflow` 的分工
|
||||
|
||||
| | 本技能 | `dsh-change-workflow` |
|
||||
|---|---|---|
|
||||
| 管什么 | **需求和方案怎么定**(选型 / 收敛 / 判方向 / 拍板) | **定了之后怎么落地**(六阶段 / 红线 / 档案模板) |
|
||||
| 什么时候用 | 用户刚提需求、问"最优方案"、要在选项间选、要判"该不该做" | 决策已定,开始改码 / 验证 / 归档 |
|
||||
| 产出 | **选项表 + 决策点 + 判定依据** | 代码改动 + 验证记录 + 档案 |
|
||||
|
||||
> 顺序:**先本技能定案 → 再 dsh-change-workflow 执行**。规划会话只做前者,执行会话只做后者(交接载体 = `dsh-server-docs/05-交接单/`)。
|
||||
|
||||
### 0.1 素材来源与复跑方式(**honest provenance,勿含糊**)
|
||||
|
||||
| 素材 | 位置 | 说明 |
|
||||
|---|---|---|
|
||||
| 改造档案 | `dsh-server-docs/04-调整方案/NN-*.md` | 每份含「触发 / 用户裁定 / 方案对比 / 事故踩坑」——**会话的结论层** |
|
||||
| 工作日志 | `.workbuddy/memory/YYYY-MM-DD.md` | 五天过程日志,含用户原话引用——**会话的过程层** |
|
||||
| 现行事实层 | `BRIEF.md` / `INDEX.md` / `README.md` / `01-规范/06-工作台UI规范.md` / `05-交接单/README.md` | 约定与红线 |
|
||||
| **原始会话转录** | `~/.workbuddy/projects/<工作区目录名>/*.jsonl` | **用户真实发言的原始记录**(含被否决、被纠正的内容) |
|
||||
|
||||
**复跑命令(只读)**:
|
||||
|
||||
```bash
|
||||
# 抽出本工作区全部历史会话里的「用户真实发言」(2026-09-12 实测 = 180 条,跨 09-08→09-12)
|
||||
python3 dsh-server-docs/07-scripts/extract-user-voice.py
|
||||
# 查某个决策的来龙去脉
|
||||
python3 dsh-server-docs/07-scripts/extract-user-voice.py --needle 复用价值
|
||||
```
|
||||
|
||||
> ⚠️ **本方法 v1.0 的素材边界(如实记录)**:首版只从**档案 + 日志**提炼(当时会话检索接口返回 0 命中)。
|
||||
> 2026-09-12 用上面的提取器回补核对 —— **U1–U12 里 11 条能在原始发言中找到对应原话**(覆盖良好),
|
||||
> 据此**补上了 U13–U19** 这 7 条只在原始对话里才看得见的模式。**以后迭代本技能,先跑这个脚本。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 决策素材库 · 用户的有效决策(U1–U28) → **`dsh-decision-method/素材库-U-用户决策.md`**
|
||||
|
||||
> **已被拆出本文件**(原占全文 55%)。本文件只留「**判决核心 + 指针**」:素材库是**查阅型**(看了更准、不看也不违规),判定核心才是每次都要用的。
|
||||
> **触发词 → 直接查哪条**(**必须去读**,别凭印象答用户口径):
|
||||
|
||||
| 你正在判断什么 | 去查 |
|
||||
|---|---|
|
||||
| 「这件事该不该问用户 / 我是不是又在提报用户了」 | **U20 · U21 · U22** + 本文件 §4.1 两条总闸 |
|
||||
| 「要不要自己开发 / 有没有现成的」 | **U23**(官方库优先 + 体检三关) |
|
||||
| 「多期方案 / 兼容性怎么定」 | **U24** |
|
||||
| 「要给用户看什么 / UI 怎么排」 | U5 · U7 · U11 + 本文件 §6 |
|
||||
| 「这个改动会不会让项目变差」 | **U28**(十维净变差即命中 ⇒ **停下复盘**;无正向做法 ⇒ **立即停止**)+ 红线 R11 |
|
||||
| 「要不要降级/延期/先这样跑」 | **U27**(要的是解决问题,不是将就妥协)+ A6 边界(目标不打折、路径取最小代价)|
|
||||
| 「方案有风险/问题,能不能先干着看」 | **U26**(先优化到「当下最优解」+ 残余风险写清,再走下一步)|
|
||||
| 「抢了锁之后怎么收口 / 能不能先放着」 | **U25**(锁的生命周期 = 任务的生命周期;带锁结束不算完成)+ 本文件 §4 判据 |
|
||||
| 「删 / 留 / 清理 / 收尾怎么定」 | U3 · U6 · U14 |
|
||||
| 「用户那句话到底是什么意思」 | 读全表(每条 = 原话 + 落地 + 判据) |
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 2. 决策素材库 · AI 的有效决策(A1–A22) → **`dsh-decision-method/素材库-A-AI推理.md`**
|
||||
|
||||
> **已被拆出本文件**。**触发词 → 直接查**:
|
||||
|
||||
| 你正在判断什么 | 去查 |
|
||||
|---|---|
|
||||
| 「我的证据够不够 / 结论能不能下」 | A1 · A4 · A5 · **A18**(静默失败会伪造结论)· **A19**(验收要含第二环境) |
|
||||
| 「我凭什么说这是限制 / 做不到」 | **A17**(配置项 / 已抽象层 / 真硬编码,三层取证) |
|
||||
| 「写状态 / 写支持度 / 交付回执」 | **A15**(三态词表:✅已验证 / ⚠️待开发验证 / ❌已知不支持) |
|
||||
| 「删除 / 迁移 / 回滚 / 替换」 | A8 · **A16**(伴随物清单)· **A20**(存量烂账选只增不改)· **A22**(先补位再退役) |
|
||||
| 「我做完了吗 / 能不能宣布完成」 | **A25**(本机改完 ≠ 交付:先画「改动层 → 生效链路」;四条"自我安慰"不算交付)|
|
||||
| 「我装的门禁/钩子到底管用吗」 | **A24**(拦截面必须覆盖真实行为面 —— 先核账再装)|
|
||||
| 「判据 / 分类 / 索引怎么设计」 | **A21**(必须报分布、要有区分度) |
|
||||
| 「失败面 / 报错 / 能力不确定」 | A10 · A11 |
|
||||
| 「流程走到哪一步了 / 我是不是跳步了」 | **A23**(流程类失效 = 触发词没命中;规则要进常驻层、触发用动作词)+ `dsh-change-workflow` 六阶段 |
|
||||
| 「拍板前还要问自己什么」 | A2(必含"不做")· A3(决策点)· A6 · A7 · A9 |
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 3. 反例库:被驳回 / 被纠正的决策(X1–X13) → **`dsh-decision-method/素材库-反例-X.md`**
|
||||
|
||||
> **已被拆出本文件**。**每条反例 = 一条避免规则**。**触发词 → 直接查**:
|
||||
|
||||
| 你正在判断什么 | 去查 |
|
||||
|---|---|
|
||||
| 「我刚被纠正了,同类还有哪些坑」 | X1(批量)· X4(归因)· X9(过度提报用户)· X10(答非所问)· X11(越界)· **X12**(把用户材料当权威)· **X13**(把自己的解析失败当成版本差异)· **X14**(一批改造拆成多次中断动作)|
|
||||
| **「这个库 / 方案成熟、star 高,所以选它」** | **§4.6**(选型判据轴:⛔ 热度≠安全/性能;先立轴再排序;必查默认值 + CVE 历史)|
|
||||
| 动手前的"别踩"清单 | 读全表 13 条 |
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 4. 如何确认最优解(本技能的核心)
|
||||
|
||||
### 4.1 判定矩阵:先给方案贴标签
|
||||
|
||||
> **⭐ 两条总闸(顺序在前:先问「是不是我的 lane」,再问「要不要停手」)**
|
||||
> **闸 1 · lane**:这件事**落在谁的 lane**?—— ① **我自己负责的**(我的插件源码/产物、该 profile 的依赖、我自己的临时脚本、我方案内的执行细节)⇒ **自己拍**;② **平台级 / 全局 / 别人 lane 的**(`/var/lib/**`、全局符号链接、别人的 profile、别人的产物)⇒ **只报告、不动手**,**哪怕改它能让自己流程跑通**(2026-09-13 用户原话:「谁让你去改这个的」「不是自己负责的任务相关文件不要去改」→ **X11**)。
|
||||
> **闸 2 · 门禁**:命中**真门禁**才停等确认 —— 现行只剩两条:① **不可逆破坏性操作**(删数据 / 迁 DB / 清目录)② **边界外**(业务目标与优先级 / 花钱与资源承诺 / 对外承诺与合规 / 需用户提供的凭据 / 无客观优劣的偏好 / 影响面超出本平台)。**其余一律自决策**(含部署上线、重启、改配置),事后一句「我选了什么(可推翻)」(**U20 / X9**)。
|
||||
> ⚠️ 两条闸**对称**:闸 1 治「**越界动手**」,闸 2 治「**过度提报用户**」—— 2026-09-13 两类各犯过一次。
|
||||
|
||||
| 判定问题 | 若答案是 | 处置 |
|
||||
|---|---|---|
|
||||
| 这次是**扩大**还是**收窄**可见面/权限?(R5) | 扩大 | **停手**,出「权限影响评估」四问 + 等确认 |
|
||||
| | 收窄 | 可直接做,但**遮蔽类必须真启动一次实例验证** |
|
||||
| 有没有**不扩大也能实现**的方案? | 有 | **必须先提**;提不出才说明为什么没有 |
|
||||
| 改动**影响多少文件**?(R7) | >10 或有"所有/整个/全库" | 先出**受影响清单** + 等确认;先 1 个对象单点验证 |
|
||||
| 会不会**中断在线用户**?(R8) | 会 | 先说明影响面 + 取得确认;能避开活跃时段就避开 |
|
||||
| 会不会**中断在线用户**?(R8)——**按实际影响面判,不按动作名字判** | **不会**(只换包 / 传产物 / 改静态页 / 投放候选池) | **属边界内的「部署与同步」⇒ 做完即上线,不要问**(U20 / X9);先做完,再用一句「我选了什么」交代 |
|
||||
| 这个改动**失败**会怎样? | 实例起不来 / 全站不可达 / 不可逆 | 必须有回滚点(备份路径 + 恢复命令)**先就位** |
|
||||
| **删除/迁移**的收益 vs 潜在破坏? | 收益小、破坏大 | **不删**——标注废弃 + 禁再加功能 |
|
||||
| **这个改动会让项目某一维度净变差吗?**(**R11 · 十维**:目标/方向/架构/功能/性能/安全/交互/UI/便利性/扩展性) | **会** | **立即停下复盘** → 找保住正向收益的做法;**拿不出 ⇒ 立即停止、只报告**(不许"先做着看",见 **U28**) |
|
||||
| 会不会造出**第二个漂移源**? | 会 | 改成**指针**(单一来源)——清单/待办/部署事实各只有一个权威文件 |
|
||||
|
||||
### 4.2 「确认最优解」十问(拍板前逐条答,答不出就是还没想清)
|
||||
|
||||
1. **一句话目标**是什么?做完了**没有**(可判定)?
|
||||
2. 这条结论我**用什么命令/证据**证明?(说不出 = 还在推断,见 A1)
|
||||
3. 有哪 **≥2 个选项**、以及**"不做"**这一条?(A2)
|
||||
4. 这个改动是**扩大**还是**收窄**?(U8 / R5)
|
||||
5. 有没有**更小**的改动达到同样目的?(A6)
|
||||
6. 会影响**谁**(全部租户 / 单租户 / 仅 admin)?会**断多久**?(R8)
|
||||
7. **回滚**怎么做?备份在哪?(写得出可执行命令才算数)
|
||||
8. 造出**第二个真相源**了吗?(单一来源原则)
|
||||
9. 用户**能不能感知到**(新入口 / 新反馈 / 新文案),还是只有后端变了?(U5)
|
||||
10. 谁来**验收**?我能不能给一个**第三方可复现**的命令 + 期望输出 + 退出码?
|
||||
|
||||
### 4.3 验收口径分级(越靠后越权威)
|
||||
|
||||
| 级别 | 手段 | 能证明什么 |
|
||||
|---|---|---|
|
||||
| L1 推断 | 读代码 / 读文档 | **什么都不能证明**(只用来生成假设) |
|
||||
| L2 命令 | `curl` 状态码 / `--dump-config` / 日志 grep | 机制是否被触达(**注意 `--dump-config` 不反映 bundle/patch 层**) |
|
||||
| L3 对账 | md5 双端 / `docs-sync-check.sh` / 可见面清单 diff / 工具清单前后对比 | 一致性、无回归 |
|
||||
| L4 端到端 | 铸造临时 session 实跑 → 越界用例(`../../etc/passwd` 应 400) | 安全与功能闭环 |
|
||||
| L5 用户实测 | 用户浏览器硬刷新 + 体感确认 | **最终验收**(前端渲染、动画、位置类只能到此为止) |
|
||||
|
||||
> **做不到就明说**:「未做浏览器渲染验证(本机无 Chromium,装它成本不成比例)→ 待用户硬刷新确认」是**合格交付**;把 L1 说成 L5 才是事故。
|
||||
|
||||
### 4.4 技术实现的默认裁决顺序(**AI 自主用,不问用户**)
|
||||
|
||||
> 这是「技术实现找最优解」的可执行算法:**按序自答,第一个"是"就是答案**。全部答"否"才说明确实需要新造东西。
|
||||
> 配套 `dsh-feature-first`:用户在技术层没有判断依据 → 这 8 条**不构成决策点**,不要提报用户。
|
||||
|
||||
| 序 | 自问 | 若"是" → 选它 |
|
||||
|---|---|---|
|
||||
| **1** | 有没有**既有机制 / 扩展点**能复用? | 扩展,**不新建**(U2:不做两套) |
|
||||
| **2** | 有没有**更小改动**达到同一效果? | 取**最小改动半径**(A6) |
|
||||
| **3** | 能不能**用配置解决**而不是改代码?(cordis patch / env / bundle 声明) | **配置优先** —— 不改码 = 免 build、免重启 |
|
||||
| **4** | 能不能**只改一层**?(门户静态页 / 编排器 / profile / bwrap / nginx) | **单层**;绝不"跨层顺手改" |
|
||||
| **5** | 失败代价**是否对称**? | 不对称 → 选**可回滚、可保留**的那条(删除/迁移类尤其,A8);**删除类先走 A14「删除前三问」** |
|
||||
| **6** | 结果**能不能被验证**?(命令 / 日志标记 / 端点) | 不可验证 → **顺手加可 grep 的标记或端点**(A5) |
|
||||
| **7** | 这个改动是**收窄**还是**扩大**可见面 / 权限? | 收窄可直接做;**扩大 → 回 R5 门禁,先取得确认** |
|
||||
| **8** | 与**官方契约的耦合面**有多大? | 耦合越小越好;**每一处耦合都要写进升级回归清单**(档案 26 六类) |
|
||||
|
||||
**三条硬约束**:
|
||||
1. **第 3 条优先于第 2 条** —— "能配置就不改码":改码要走 build + 重启,而重启**会中断在线用户**(触及 R8);配置改动(尤其静态页)常常即时生效。
|
||||
2. ⚠️ **2026-09-16 修正**:原表述「任一条与红线冲突 → 红线赢」**过宽**,是会话 `ddea70b7` 提报用户的诱因 —— 把"平台级 / 全局 ⇒ 只报告不动手"(R7-边界②)当红线读,于是"红线赢"⇒ **该自己做的事被推给用户**。正确表述:**与「真门禁」冲突 → 门禁赢**(真门禁只有两类 ✓ 见 §4.5);**与表述重叠/打架的规则冲突 → 按 §4.5 裁决顺序**。
|
||||
3. 🔀 **规则冲突时按 `R8 → §1 边界内自决策清单 → 其余红线` 取首个命中项**,⛔ **不许"自行取保守侧"**(详见 §4.5)。
|
||||
|
||||
### 4.5 规则冲突裁决顺序 + 提报给用户前三问(**2026-09-16 加,源自会话 `ddea70b7` 复盘**)
|
||||
|
||||
> **案例**:用户要求"完成 guest 迁移",AI 在结尾用「## 四、待你拍板」提了两问(① 106 旧控制面停/留 ② D1–D6 先做哪些)。用户 U6 回:「**D1–D6 先做哪些 按照你的规划执行,中间有问题参考决策方法**」,再两次(U5 / U7)自行给出"删除"的答案。
|
||||
> **代价**:AI 那两问**都不是真门禁** —— 用户不但没被"省事",还多花一轮把答案喂回来;且 AI 全程 `Skill` 调用 **0 次**(用户点名的方法没被取用)。
|
||||
|
||||
**A. 冲突裁决顺序(同一对象被多条规则给出相反结论时)**
|
||||
|
||||
| 序 | 取谁 | 命中即停 |
|
||||
|---|---|---|
|
||||
| 1 | **R8** | 开发环境服务器 ⇒ **该动就动**,只需动手前一句话说明;⛔ 不必等确认 |
|
||||
| 2 | **§1 边界内自决策清单** | 部署 / 重启 / 改配置 / nginx·nft / drain / 技术选型 / 命名 / 调参 ⇒ **自决策** |
|
||||
| 3 | **其余红线** | R5 权限扩大 / R7 批量写入 / R9 锁 / R10 uid —— **永远是硬约束**,不参与裁决 |
|
||||
|
||||
**B. "平台级" ≠ "别人的"**(本次误判根源)
|
||||
`dshs*`·`dsh-*` 单元、`/var/lib/dshs/**`、nginx·nft、端口,只要在**我们自己的 47 / 106 / 本工作区**上,就是**本平台自己的资源** ⇒ 按 §1 + R8 **直接做**。
|
||||
R7-边界② 的"只报告不动手"**只针对「别人的 / 归属不明」的对象**。**判据看"归属",不看"是不是平台组件"。**
|
||||
|
||||
**C. 提报给用户前三问 —— 任一条为"是"即自决策(不必三问全过)**
|
||||
|
||||
| # | 自问 | 结论 |
|
||||
|---|---|---|
|
||||
| 1 | 对象是**我们自己的**平台资源吗? | 是 ⇒ **自决策** |
|
||||
| 2 | 我**查证过**关键不确定点吗?(如"还有谁在用 / 有没有访问记录") | 没查 ⇒ **先查**,⛔ 不许把"我不确定"当提报用户理由 |
|
||||
| 3 | 候选按优劣排序后,**第一名是否明显更优**? | 是 ⇒ **自决策**(只有"各有优有劣、客观分不出高下"才算真取舍) |
|
||||
|
||||
⛔ **同时禁止**:把"我有倾向"降级成"建议 + 待你拍板" —— 有倾向 ⇒ 直接做完,写一句「我选了什么(可推翻)」。
|
||||
⛔ **冲突 ≠ 门禁**:两条规则打架**不构成**提报用户理由。
|
||||
|
||||
**产出**:把 1–8 的答案写进档案的「技术选择」段(一行一条,**含被否决的选项与否决理由**)。
|
||||
→ 这样用户**事后可推翻**、但**事前不被打扰**(对应 `dsh-feature-first` §5 的"默认自主 + 事后可推翻")。
|
||||
|
||||
---
|
||||
|
||||
### 4.6 技术选型:**先立判据轴,再排序**;⛔ 不许用 star / 年龄 / 生态当选型依据(**2026-09-16 加,源自覆盖网络 relay 选型**)
|
||||
|
||||
**反例(我当场犯的)**:把 `frp` 排「首选」,排查依据只有 **~10.6 万 star + 约一月一版 + 生态最好** —— 那是**「省心度」轴**,不是**「安全 / 性能」轴**。用户一句「**项目时间比较久,性能和安全性还真不一定是最好**」直接击穿,复查后**撤销排序**。
|
||||
复查出的**真实安全面**:`CVE-2026-40910`(认证绕过 + 未授权 DoS,**影响 ≥0.53.0**)|dashboard **默认 `admin:admin` 且口令明文存配置**|**`proxyBindAddr` 默认跟随 `bindAddr`**(官方自己写「**大多数指南遗漏的配置**」—— 不设则代理监听器**绑到公网**)|服务端**默认不强制 TLS**|`auth.token` 是**单一静态共享令牌**、frpc 明文存、`allowPorts` 白名单**默认关**(⇒ 一台客户端失陷可申请**任意**端口)。
|
||||
⇒ **"项目久"是双刃**:稳定 + 文档好 **vs 漏洞历史长 + 默认值停在历史约定(安全靠运维纪律补)**。
|
||||
|
||||
**四条硬规矩**
|
||||
|
||||
1. **⛔ 不用「star / fork / 项目年龄 / 发布频率 / 生态」做首轮排序** —— 它们度量的是**热度与省心度**,推不出"在本案里更安全 / 更快"。**只能当同分时的决胜项**,不能当**排序主依据**。
|
||||
2. **判据轴必须从"本案的真实约束"反推**,并且**每条都要能回答"这条轴上的差异会不会改变本项目的结论?"** —— 不会 ⇒ **该轴不参与选型**。
|
||||
· 本例立出六条:**① 认证模型(身份 > 每服务密钥 > 共享 token)② 默认拒绝还是默认放行 ③ 能否零新增入站 ④ 单节点失陷的爆炸半径 ⑤ 可观测 ⑥ 生态**。
|
||||
· 结果:**frp 在 ①②④ 三条里都最差一档**(共享 token / 默认放行 / 可申请任意端口),只在 ⑤⑥ 领先 ⇒ 排序翻转为 **证书身份型(OpenZiti / Nebula)> rathole(Noise_NK 双向认证 + 每服务 token 必填)> frp**。
|
||||
3. **性能轴先自证"它是不是本案瓶颈"**:本例**第一瓶颈是 presence 不是带宽**、量级是「每 worker 几十个 HTTP 会话」⇒ **吞吐 benchmark 不参与选型**(且多为厂商/二手自测)。**真要测就测链路本身**(RTT / jitter / 带宽)—— **任何 relay 的上限由链路决定,不由实现决定**。
|
||||
4. **老 / 流行项目必查两张单子**:① **默认值清单**(逐项问"**不设它会怎样**"—— 本例 5 项里任何一项漏设都会**静默**破掉既定安全目标)② **CVE / 安全公告历史**(编号 + 影响版本区间)。**"成熟" ≠ "默认安全"。**
|
||||
|
||||
**配套两条(本例同时验证)**
|
||||
|
||||
- **"可选性"优先于"选对"**:先把接口抽出来(`Reachability.via` + `Rendezvous` 注册表)⇒ **换实现是 env 级切换** ⇒ 选型**可以推迟**,选错也不致命。**能在不选的情况下保留选择权,就别为"一次选对"付引入成本。**
|
||||
- **替换 ≠ 无条件升级**:换第三方 = 用**我们不掌控的攻击面**替换**已收窄、且有系统补丁渠道的面**(例:sshd + `restrict,port-forwarding`)。⇒ **没有明确痛点之前,"维持现状"也是合法候选**,别把"换掉旧的"默认当成正向。
|
||||
|
||||
**判定触发器**:只要出现「成熟 / 久经考验 / 用得最多 / star 高 / 大家都在用」这类**热度型论据**给排序 ⇒ **立即反问三句**:① 这条论据落在**哪个轴**上?② 这个轴是**本案的瓶颈轴**吗?③ 它的**默认值**与 **CVE 历史**查过没有?
|
||||
|
||||
---
|
||||
|
||||
## 5. 决策流程十步(新需求到手照这个走)
|
||||
|
||||
| 步 | 动作 | 产出 |
|
||||
|---|---|---|
|
||||
| 1 | **判类型**:这是「方案请求」还是「任务明确直接执行」? | 方案请求 → 只输出方案,**未经明确授权不改文件** |
|
||||
| 2 | **开工前置检查**:先看已有技能/资产/记忆,"本机已有的能否满足?" | 决定"扩展还是新建"(→ U2) |
|
||||
| 3 | **取证**:源码级 / 命令级实证,先拿真实失败请求 | 事实清单(每条带命令 + 期望输出) |
|
||||
| 4 | **判方向**:扩大 / 收窄 / 中性 | 扩大 → 立即停手出四问 |
|
||||
| 5 | **出选项表**:≥2 选项 + "不做" + 影响/风险 + 推荐项 | 方案对比表 |
|
||||
| 6 | **选路径**:优先"最小代价合法路径""能一行代码就不要改平台""删除类判代价对称性" | 推荐方案 + 被否决方案的否决理由 |
|
||||
| 7 | **列决策点**:已定的标"已定(谁定的/依据)",未定的标"开跑前问用户" | 3–5 个决策点 |
|
||||
| 8 | **用户拍板** | 决策语言落成文字(见 §7) |
|
||||
| 9 | **小步落地 + 回滚点就位**(单点验证 → 再推广) | 备份路径 + 恢复命令 |
|
||||
| 10 | **可复现验收 + 沉淀** | 档案(需求→改动→验证→红线→回滚)+ 红线/技能/记忆三层沉淀 |
|
||||
|
||||
> **第 1 步和第 4 步是"停止点"** —— 这两步没结论就不要往下走。
|
||||
|
||||
---
|
||||
|
||||
## 6. 交互 / UI 改造专项决策清单
|
||||
|
||||
> 用户对本项目的界面要求有明确取向,以下是**已验证有效的取向**(源自档案 16/31/36/45/56/57/59/60/61/62 + `01-规范/06-工作台UI规范`)。
|
||||
|
||||
### 6.1 反馈与状态(最高频痛点)
|
||||
|
||||
| 场景 | 必须做到 | 实例 |
|
||||
|---|---|---|
|
||||
| 有任何等待(实例启动 / 拉目录 / 上传) | **可见进度**,且**导航路径与 XHR 路径都要有** | 档案 59:只有导航有 `wake.html` 动画,XHR 静默 20 秒 → 用户"以为死了" |
|
||||
| 长耗时 | **3 秒后才亮**覆盖层(短请求不打扰) | 同上:`SLOW_MS = 3000` |
|
||||
| 状态可缓存 | 页面明示「缓存更新于 X 前(6 小时内直接复用,不联网)」 | 档案 62:功能早已存在**但完全看不出来** |
|
||||
| 不可编辑 / 只读 | 明示原因,不要"点了没反应" | 档案 36 |
|
||||
| 失败 | 行内提示(`.toolbar-note` / `.empty`),给出**下一步** | 06 规范 §4.8 |
|
||||
|
||||
### 6.2 信息层级与术语
|
||||
|
||||
- **首列放用户读得懂的那一列**(说明 > 名称 > 技术标识);技术标识降副行(U7)
|
||||
- **内部术语不上页面**:「候选池」→「导入到平台」;并显式解释易误解的关系(「**投放 ≠ 生效**」)
|
||||
- **数值列右对齐 + `tabular-nums`**(否则滚动时数字跳动);超宽字段移出共享网格
|
||||
- **文件名/标题默认同正文色,hover 才变蓝**(避免整列花掉)
|
||||
- **图表类改动先看 `01-规范/06-工作台UI规范`**,冲突时以 `06` 的**实测 Token** 为准
|
||||
|
||||
### 6.3 布局与滚动(踩过的坑)
|
||||
|
||||
- `main#view` 高度 = `calc(100vh - 55px)`(**55 是实测值**,写 54 会多出 1px 第二层滚动条)
|
||||
- **"视口自适应高度"必须上下都算** —— 档案 61 第一次修正只算了列表上方 372px,漏了下方 116px(按钮行 50 + card padding 18 + `#view` padding-bottom 48)→ 仍然溢出。正解 `calc(100vh - 520px)`
|
||||
- `.modal-mask` 是 `display:flex` → **必须显式写** `[hidden] { display: none }`,否则弹窗关不掉
|
||||
- 同名类二次定义会互相覆盖(`.tab` 有胶囊式与下划线式两套)→ 新页面**另起类名**(如 `.pg-tab`)
|
||||
|
||||
### 6.4 危险与不可逆操作
|
||||
|
||||
- 确认弹窗 **必须写明后果**(「将重启实例,会话可能中断」)
|
||||
- 危险按钮用 `--danger` 系;保存/查看类靠**底色深浅**区分(保存=浅灰底深字 `.btn-import`,查看=白底蓝字 `.btn-view`)
|
||||
- **不静默提升权限**:档位过时只**提示**,不自动改(安全语义变更必须用户知情)→ 档案 45/56
|
||||
|
||||
### 6.5 UI 决策的验收口径
|
||||
|
||||
- 静态文件(`web/*.html`)改完**立即生效、无需重启**;只有 `src/**` 才 build + restart
|
||||
- 改完 `node --check` 内联 JS;用**独立 headless Chrome**(`--headless=new` + 独立 profile + CDP)验证,**绝不碰用户日常浏览器**
|
||||
- **`section` 名是运行时注册的,`curl` 抓不到** → 这类改动只能靠用户硬刷新确认,**如实标注"未做浏览器渲染验证"**
|
||||
|
||||
---
|
||||
|
||||
## 7. 决策语言对照表(用户怎么说 → 怎么落)
|
||||
|
||||
| 用户的话 | 真实含义 | 该怎么落 |
|
||||
|---|---|---|
|
||||
| 「按建议处理」 | **只授权那条建议本身** | 不做顺带优化;范围外的发现**先报告**(R7) |
|
||||
| 「是不是最优方案 / 还有更好的方式吗」 | 要**选项对比 + 依据 + 风险** | 出对比表 + 十问,不要直接开干 |
|
||||
| 「一次性优化到位」 | 同主题**做透**,别留尾巴 | 一次列全所有子项,附完成清单 |
|
||||
| 「不需要 / 是不需要的」 | 先**扫引用与依赖**再定范围 | 出"引用实测表",只剔真 0 引用的(U3) |
|
||||
| 「暂缓 / 还没准备好」 | **parked** | 保留侦察结论 + 列出"需你先办的事",**不再推进,等用户主动提起** |
|
||||
| 「确认开始执行」 | 决策已定,**可以动刀** | 立即执行;但 R7/R8 门禁仍生效 |
|
||||
| 「为什么要等我确认才部署呢」 | **部署 / 上线属执行细节** —— 不打断用户的动作不该提报用户 | 直接做完上线,让用户**看线上效果**判断需求是否被满足(U20 / X9) |
|
||||
| 「需要告诉我的是 是否已实现,如果未实现:为什么不能,需要我拍板可以问我」 | 要**结论三件套**,不要过程与自省 | 用 **U21** 四节骨架:判定 → 为什么不行(分层)→ 需你拍板(真需要才写)→ 我接着做(陈述句)|
|
||||
| 「谁让你去改这个的」 | **越界了** —— 动到了不是我 lane 的东西 | 立即停手 → 能撤就撤(并自证不依赖它)→ 报告;此后动手前先过 **U22 闸 1** |
|
||||
| 「推送 / 提交」 | 明确授权 git 操作 | 此前一律**不 commit 不 push**;提交也只用定向 `git add` |
|
||||
| 一行指令(无上下文) | 期望**自主拆解 + 排查到底** | 自己建任务链、自己做根因定位,别逐步问 |
|
||||
| 「为什么…?」(问现象) | 要**根因链**,不是复述现象 | 先取证(真实请求/日志/实测数),再给"现象→根因→修法"三段 |
|
||||
| 「有没有越过红线」 | 要**逐条对照全量红线**的结论 | 分"当时成文口径 / 新立口径"两种口径答(A13)|
|
||||
|
||||
---
|
||||
|
||||
## 8. 决策记录模板(写进档案的固定段落)
|
||||
|
||||
```markdown
|
||||
# <NN>-<标题>(<日期> 落地 / 调研)
|
||||
- 日期: / - 状态:✅已完成|🔄进行中|⏸暂缓|❌关闭 / - 触发:<用户原话或原始报障>
|
||||
> **TL;DR**|结论 / 关键 / 状态(紧贴头部,3 行内)
|
||||
|
||||
## 背景与动机 # 需求来源、真实失败请求、触发场景
|
||||
## 提报用户 # 关键分叉 + 选择 + 理由 + 日期(原文引用优先)
|
||||
## 方案对比 # 表格:方案 / 内容 / 判定 / 理由(含"不做")
|
||||
## 实现 # 改动文件清单 + commit + 关键片段
|
||||
## 验证记录 # 命令 + 输出 + 结论;**含失败尝试与假阴性**
|
||||
## 事故 / 踩坑记录 # 现象 → 根因 → 规避
|
||||
## 回滚 / 注意 # 回滚命令、副作用、后续待办
|
||||
```
|
||||
|
||||
**三层沉淀(每次决策收口都要做)**:
|
||||
1. **治本层**:机制与流程固化进 skill,或写进 `04-调整方案/NN-*.md` 改造档案(可复用的留 skill,一次性的归档)
|
||||
2. **失误层**:教训 append 到 `.workbuddy/memory/YYYY-MM-DD.md`(**append-only**,不改写历史)
|
||||
3. **记忆层**:长期约定/红线写 `MEMORY.md`(工作区级 + 用户级)
|
||||
|
||||
---
|
||||
|
||||
## 9. 与其他约束的关系
|
||||
|
||||
- **红线优先级高于本技能**:R1 不自动升级 dsh|R2 不改官方主程序与缓存|R3 client bundle 禁 `exports.default`|R4 不用真实账号做登录测试|**R5 权限只准收窄**|**R7 禁未经确认的批量/全仓写入**|**R8 中断在线用户须先知会** —— 任一条命中,**先停手**,本技能的效率论证不构成豁免。
|
||||
- **执行层**:决策定了之后走 `dsh-change-workflow`(六阶段 + 档案模板 + 并行调度协议)。
|
||||
- **规划/执行分离**:本技能属**规划侧**;产出交接单(`dsh-server-docs/05-交接单/`,8 段必填),规划会话**不 ssh、不改码、不重启、不 scp**。
|
||||
- **单一来源**:清单与状态 = `INDEX.md §二`;待办 = `01-规范/03-路线图与待办.md`;部署事实 = `DEPLOY-本部署.md`;UI 基线 = `01-规范/06-工作台UI规范.md`;现行事实 = `BRIEF.md`(首读)。
|
||||
- **可复跑判定工具**:`docs-audit.py`(歧义/编号/悬空引用,退出码非 0 即需处理)、`docs-sync-check.sh`(双端对账)、`docs-manifest.py`(机读清单)、`handoff-guard.sh`(并发预检,推送前 `PUSH=1`)。
|
||||
|
||||
---
|
||||
|
||||
## 附:本技能的自检(用完之后问自己)
|
||||
|
||||
1. 我有没有**先取证再下结论**?(A1)
|
||||
2. 我给的方案里有没有**"不做"**这一条?(A2)
|
||||
3. 未定的决策点,我是**问用户**了还是自己替他定了?(A3)
|
||||
4. 我的"最优解"能通过 §4.2 十问吗?
|
||||
5. 我的验收口径是 L1 还是 L5?**有没有把推断说成实测**?
|
||||
6. 这次操作**会不会命中红线 R5/R7/R8**?
|
||||
7. 收口时**三层沉淀**做了吗?有没有造出第二个漂移源?
|
||||
8. 技术实现我是**按 §4.4 的裁决顺序**自己定的吗?还是又把技术选项拿去问用户了?(若问了 → 违反 `dsh-feature-first`)
|
||||
9. 我这次「停手等确认」,是按**实际影响面**判的吗?还是只看到「部署 / 上线 / 生产」这类**词**就触发了门禁?(X9)
|
||||
10. 我的答复**第一句**是在答用户问的那件事吗?有没有把「我的失误 / 进度 / 计划」写在前两节?(X10 / U21)
|
||||
11. 动手前我过「**两条总闸**」了吗?—— ① **这落在谁的 lane**(不是我的 → 只报告,**X11**)② **命中真门禁了吗**(没命中 → 自己拍,别问,**U20 / X9**)
|
||||
12. 这条回复**能被扫吗**?—— 排版按 `dsh-feature-first §5.4`(首屏 3 行给判定 · 每节 ≤7 行 · 加粗只留关键词 · 表格 ≤5 列 · 一条信息只说一次)
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 变更历史(原 frontmatter · 逐字保留)
|
||||
|
||||
```text
|
||||
name: dsh-decision-method
|
||||
description: dsh 多租户平台(ai1net.com)「改造 / 优化功能交互 / UI 界面」的**决策方法论**。当用户提出一个新需求、问「这是不是最优方案 / 还有没有更好的做法」、要在多个方案里选型、要判断某个决策是否该做 / 该不该扩大范围、要**自主给技术实现选取最优解**、或者要复盘「为什么这么定」时使用。⛔ **用户点名「决策方法」/「参考决策方法」/「按你的规划」/「别问我」/「自行决策」/「自主决策」⇒ 必须立即加载本技能,不得凭记忆代替**(机制层由钩子 `dsh-server-docs/07-scripts/skill-load-guard.py` 强制注入加载提醒;2026-09-16 实证:用户点名后 AI 全程 `Skill` 调用 **0 次**)。核心 = 决策素材库(用户有效决策 **U1-U28** / AI 有效决策 A1-A25 / 反例 X1-X14,**素材源含 180 条用户真实发言**)+ 「如何确认最优解」的十问与判定矩阵 + **技术实现的默认裁决顺序(8 条,AI 自主用、不问用户)** + 决策流程十步 + 交互 UI 改造专项清单 + 决策语言对照表 + **复跑脚本 `extract-user-voice.py`**。**v2.0.0(2026-09-14)结构变更:素材库(U/A/X)已拆到 `references/`,按需读;本文件只留判定核心 + 触发词索引**(索引绑定可识别动作)。**与 dsh-change-workflow 分工:本技能管「怎么想、怎么定」,那个管「怎么落地」。** 与 dsh-feature-first 分工:那个管「谁定什么」,本技能管「怎么定得对」。
|
||||
version: 1.0.0
|
||||
updated_at: 2026-09-16
|
||||
created_from: 本工作区 62 份改造档案 + 5 天工作日志(2026-09-08 ~ 09-12)全量提炼
|
||||
last_change: 【2026-09-22 按要求统一版本号】frontmatter `version` → `1.0.0`(原 v2.8.0);正文与历史中的版本号为当时记录,未改动。
|
||||
agent_created: true
|
||||
```
|
||||
@@ -0,0 +1,165 @@
|
||||
# 素材库 · AI 的有效决策(A1–A22)
|
||||
|
||||
> **归属**:技能 `dsh-decision-method` 的素材库(**按需读**,不是每次都要读)。
|
||||
> **主文件 / 索引 / 判定核心** = `../SKILL.md`(§4 判定核心 · §5 流程 · §7 语言表 · 附 自检)。
|
||||
> **用法**:只在「要判某条是否属于既有口径」或「要引用用户原话」时读本文件;**别整段抄进答复**。
|
||||
> **维护**:条目**只增不改**(编号进位到末尾);用户原话**逐字**引用;每条必须带「实例出处 + 判据」。
|
||||
|
||||
---
|
||||
|
||||
## 2. 决策素材库 · AI 的有效决策(A1–A16)
|
||||
|
||||
> 这些是**被实践证明有效的推理方式**,不是结论。新任务遇到同类岔路时直接套用。
|
||||
|
||||
### A1|取证优先于推断:源码级 / 命令级,禁止只靠文档
|
||||
- **实例**:`--dump-config` 被证伪(它**不反映** bundle/profile patch 层,连已生效的行都不显示)→ 判定口径改为「加载标记 + 浏览器实测」;「手放 node_modules ≠ 安装」(lockfile 才是账本);「空闲回收」**从未生效**(全历史 `idle-reap` 仅 1 次)
|
||||
- **做法** → 结论前先问"这条我能用什么命令证明",写成**命令 + 期望输出**;文档只当线索
|
||||
|
||||
### A2|方案对比表:≥2 选项 + 影响/风险 + 建议,**必须含"不做"**
|
||||
- **实例**:档案 20 方案 A(加固,推荐)/ B(启 enablePatch,不推荐);档案 45 方案 A(会话迁移,不做)/ B(提示,采用);档案 16 §四 folder_plugins(查明后**建议废弃**)
|
||||
- **做法** → 表格四列:方案 / 内容 / 判定 / 理由;**推荐项置首并标注 "(Recommended)"**;给不出"不做"这条路说明分析还没做完
|
||||
|
||||
### A3|决策点显式列出,等用户拍板(不替用户决定)
|
||||
- **实例**:交接单 8 段里第 4 段就是「决策点」——**已定的写"已定(谁定的/依据)",未定的写"开跑前问用户"**
|
||||
- **做法** → 一单最多留 3–5 个决策点,每个给推荐项 + 代价;**未定的决策点不允许执行会话自行拍板**
|
||||
|
||||
### A4|能用 A/B 实测就 A/B,别写"应该会更快"
|
||||
- **实例**:`NODE_COMPILE_CACHE` 冷启动 **5.0s → 4.0s**(实测);反向教训也记:`--max-old-space-size` **不降稳态内存**(优化前后 cgroup 都 ~98 MiB)→ 它买的是**可诊断性**,不是省内存
|
||||
- **做法** → 性能/资源类结论必须给**前后两个数**;说不出第二个数就明说"未实测"
|
||||
|
||||
### A5|把"不可验证"改造成"可验证"
|
||||
- **实例**:给插件加**加载标记** `[workspace-scoped-picker] loaded root=…` → 把升级回归(C4)从"看 UI"变成"看日志";`GET /api/capabilities` 人机同源
|
||||
- **做法** → 一个改动如果只能靠"看起来生效了",就**顺手加一行可 grep 的日志/标记/端点** —— 这是最便宜的可验证性投资
|
||||
|
||||
### A6|选「最小代价的合法路径」,不选「最彻底的」
|
||||
- **实例**:档案 45 —— 根治方案是**改写存量会话的种子事件**(属 R5「扩大」+ 多帧 zstd append-only 日志重写,风险收益不成比例)→ 改选**一句提示文案**;档案 42 —— 想禁 `python3.6` 的"遮蔽"会让实例起不来 → 改选**文档引导**(成本 0、风险 0)
|
||||
- **判据** → 问三句:① 有没有更小的改动达到同样目的?② 这个改动**扩大**了吗?③ 失败时的后果对称吗?
|
||||
- ⚠️ **边界(U27)**:A6 只约束**路径**(实现取最小代价),**不约束目标** —— 不许把"选最小代价"读成"降低目标 / 延期 / 静默兜底"。**目标不打折,路径取最小代价。**
|
||||
|
||||
### A7|能一行代码解决,就不要改平台配置
|
||||
- **实例**:实例内 Python 抓 HTTPS 报 CA 错 → 正解是脚本里 `SSL_CERT_FILE=/etc/pki/tls/certs/ca-bundle.crt`,**不走 R5 注入 env**(因为注入 env = 扩大,而一行代码就够了)
|
||||
- **判据** → 平台级改动(env / 挂载 / nft / 配额)是**最后手段**,不是第一手段
|
||||
|
||||
### A8|遇到"要删/要迁移"先判代价对称性;不对称 → 保留
|
||||
- **实例**:`folder_plugins` / `workspaces` 表**加废弃注释保留**(跨 10 文件 + 含 k8s/PG 未验证路径 → 删除风险不对称);4 份 cold 档案不迁 archive(收益小);技能包裁剪则相反 —— 真 0 引用的才剔
|
||||
- **判据** → 删除的**收益 < 潜在破坏**时,选择"标注废弃 + 禁止再加功能",而不是删
|
||||
|
||||
### A9|明确「不做」并写明「打开条件」
|
||||
- **实例**:白名单源码安装 **不做**(与"平台不执行第三方构建脚本"红线冲突)→ 同时留「打开条件清单」(沙箱构建 / `--ignore-scripts` / 仅 admin / 审计 / 全量扫描);熔断实测、管理类插件化也都明确关闭
|
||||
- **做法** → 「关闭」必须写两句:**为什么不做** + **什么条件下可以重开**;只写"不做"会在下次被重新提起
|
||||
|
||||
### A10|失败面要留证据,不要吞错误
|
||||
- **实例**:插件探活失败**回传 dsh 真实错误**(`duplicate loader entry id` / `ERR_MODULE_NOT_FOUND`),不要泛化成"插件不兼容";坏包隔离并改名标注 `-BAD-missing-index.tgz`
|
||||
- **判据** → 报错信息是 admin 判断根因的**唯一线索**,泛化等于毁掉线索
|
||||
|
||||
### A11|不确定的能力显式抛 `unsupported`,不假装支持
|
||||
- **实例**:`K8sUserFs.readFile` **显式抛 `unsupported`**(sidecar 尚无端点)→ 「属未验证路径,**不假装支持**」
|
||||
- **判据** → 本地验证过的能力才写"支持";没验证的路径要么标注"未验证",要么直接拒绝
|
||||
|
||||
### A12|只读核对也要留痕(不改也要出结论)
|
||||
- **实例**:所有"核查 / 取证 / 评估"类任务都产出档案(编号 + 状态 + 触发 + 结论表),即使**一行代码都没改**
|
||||
- **判据** → 「核查完成」本身就是一个交付物;不落档的结论等于没发生(下次会重复发现)
|
||||
|
||||
### A13|自查要分「当时成文的口径」与「新立的口径」
|
||||
- **实例**:越界自查结论 = 按当时的 R1-R6 **未违反**;按当天新立的 R7/R8 则**5 次实质越界** —— 两种口径都给出,不粉饰
|
||||
- **判据** → 复盘/自查时**说明用的是哪一版标准**,否则结论不可信
|
||||
|
||||
|
||||
### A14|删除 / 移除 / 下线前,先查清楚再动手(用户 2026-09-12 明确)
|
||||
|
||||
- **实例(我的失手)**:我把服务器上两个文件报成"多余、待用户定是否删除",却**没先看它们是什么** —— 一查才发现三件事:
|
||||
① 本机 `scripts/` 里**都有**(我只 `ls` 了根目录就说"本机没有")
|
||||
② 服务器那两份**早已被并行会话清掉**(我把一个**已消失**的问题抛给了用户)
|
||||
③ 顺着 `grep -rn` 找到档案 73,一句话就看清用途 —— `lock-guard-hook.py` 是 **PreToolUse 强制钩子**
|
||||
- **删除前三问(没答完就不动)**:
|
||||
1. **它是什么** —— 读内容 / 读关联档案的 TL;DR,**不要凭文件名猜**。
|
||||
2. **被谁引用** —— `grep -rn <名> --include="*.md" --include="*.ts" --include="*.cjs"`;**全库 `find`,不要只看当前目录**。
|
||||
3. **删了影响谁** —— 是否有别的会话 / 服务 / cron 在用;**是不是唯一副本**。
|
||||
- **判据** → **未查明就不动**;查明后确认是"**放错位置的多余副本**"(正本在别处且 md5 一致)才可直接清理。
|
||||
- 与 **A8** 配合:删除是**风险不对称**动作(删错 = 丢失,留着 = 只占空间)→ **默认保留**,除非已查清。
|
||||
|
||||
### A15|写状态必须带「三态 + 级别」,禁止用「支持 / 可用」描述未验证项
|
||||
|
||||
- **实例**:开源文档把未验证的 Kubernetes 模式写成**方案 B** → 用户纠正:「模式 B · Kubernetes **去掉这个,根本没验证**,应该是**待开发验证**」。
|
||||
- **三态词表(强制)**:
|
||||
| 写法 | 什么时候能用 | 必须附 |
|
||||
|---|---|---|
|
||||
| ✅ **已验证** | 有**可复跑**的命令 / 日志 / 截图,且**取数时间**明确 | 命令 + 期望输出(§4.3 L2–L5) |
|
||||
| ⚠️ **待开发验证** | 代码 / 文档存在,但没跑过端到端 | 「未验证」三个字必须出现在**结论句**里 |
|
||||
| ❌ **已知不支持** | 实测证伪 | 失败证据 + 复现条件 |
|
||||
⛔ **禁用词**:「支持 / 可用 / 已实现 / 已落地」**不得**用于 ⚠️ 段;上一轮(档案 76 §10.7)就是**用文件名代替读包**,把「没这能力」说成了结论。
|
||||
- 落地:开源 README / 档案状态 / 能力清单 / 交付回执 **四处统一用这套词**。
|
||||
|
||||
---
|
||||
|
||||
### A16|回滚 / 改名 / 迁移类动作:先列「伴随物清单」,只改主体必留隐患
|
||||
|
||||
- **实例(同日两起)**:① **回滚只回滚了部署、没回滚源码** → 下次重建又把补丁带回来(0.2.19 误带堆限 ⇒ 0.2.20 才真修);② **改 SQLite 库名漏了 `-wal` / `-shm`** → 358 KB WAL 未被 replay、**丢了 2 条会话记录**(归位后 4→6 恢复)。
|
||||
- **伴随物清单(动手前逐项打勾)**:
|
||||
| 动作 | 主体 | **必须一起处理的伴随物** |
|
||||
|---|---|---|
|
||||
| 回滚 | 制品 / 部署 | **源码** + 构建缓存 + lockfile + 实例内已加载的 bundle |
|
||||
| 改名 / 迁移 | 主文件 | **旁路文件**(SQLite `-wal` `-shm`)· 目录 · 符号链接 · 所有引用点(`grep -rn`)· 运行中的进程 / 服务 |
|
||||
| 批量替换 | 命中文件 | 自引用 / 自赋值(`replace_all` 会命中刚插入的定义行)· 行尾风格 · 语法校验(用 build 当校验器) |
|
||||
- **判据** → 凡「一个名字 / 一份数据 / 一段制品」被改或退回,**先写出它的伴随物清单**再动手;**改完必须读回复核**(不靠「应该没问题」)。
|
||||
|
||||
|
||||
### A17|判「这是限制」之前先分层取证:配置项 / 已抽象层 / 真硬编码
|
||||
|
||||
- **实例(用户当场纠正我)**:我把「DB 是单文件 SQLite」列为集群化的限制 → 用户口径「**可以改为连接数据库集群,数据库不是限制**」;实测 `DSHS_DB_URL` 非空即切 PG(`db/index.ts:19`),`db/adapter.ts` 头注释已声明「routes depend only on this abstraction」⇒ **早有抽象,是配置项不是天花板**。
|
||||
- **判据** → 任何「做不到 / 是限制 / 是天花板」的结论,先把它归到三类之一并给出**代码行号或命令**:① 配置项(改 env/参数即可)② 已抽象层(换实现后端)③ 真硬编码(必须改码)。
|
||||
- 反面同时成立:**别把「能配置」当成「已经能用」** —— 同一次实测才发现 `dsh_instances` 归属表**只有 k8s 路径在写**(`LocalSpawner` 根本不收 db)⇒「换库单独做 = 零收益」。
|
||||
|
||||
### A18|静默失败会伪造结论:工具静默 + 降级静默,两头都要防
|
||||
|
||||
- **实例(同日两起,都差点骗了我)**:① `grep -v node_modules` 把**要查的行本身**也滤掉 ⇒ 得出"源仓 0 处"的**假结论**(改用 ripgrep 才看到真相);`rg` 在本机 PATH 不存在 + `2>/dev/null` ⇒ **静默返回空**,看起来像"扫干净了"。② `listCatalogProviders()` 的 readdir 抛错被 catch 吞掉返回 `[]`,注释还把降级写成特性 ⇒ **"没生效"和"没做"不可区分**,缺陷潜伏三轮。
|
||||
- **判据** → **断言"扫干净了 / 没有 / 全绿"之前,先自证工具真的跑了**:跑一次已知命中的探测、看退出码、别用 `2>/dev/null` 掩盖失败;排依赖目录用 `--exclude-dir`/`.gitignore`,**不要用行过滤**。
|
||||
- - ⚠️ **姊妹坑:把失败误读成成功**(2026-09-15 实证)—— 用管道截尾看命令输出时(`| grep` / `| tail`),**失败提示里也含成功关键词** ⇒ 假命中 ⇒ "以为抢到锁了"却在无锁状态改库。
|
||||
✅ **判据**:**先看退出码**(不要接管道),再**复读关键状态文件/OWNER 并断言**;"输出了像成功的话"**不等于**操作成功。
|
||||
|
||||
**降级必须留痕**:静默 catch 至少 `console.warn` 一次,或把「不可读 / 目录为空」**透出到状态端点**(本次已落地:`/api/me/model-providers` 的 `catalog{dir,readable,count}`)。
|
||||
|
||||
### A19|验收判据必须包含「第二环境」——同环境反复通过会掩盖跨环境从未验证
|
||||
|
||||
- **实例**:写死 `/usr/local/lib/node_modules` 在本机(npm 默认 prefix)**恰好是对的** ⇒ 端到端验收"38 家全绿"只证明了"**在这一台机器上**对";换 `/usr/lib` 布局(`install.sh` 部署的机器)则厂家目录读空、兼容性预检**整体失效**、目录选择器 import 即抛 —— 且**全都静默**。同一个未验证假设被**复制了三轮**(picker → plugin-compat → model-catalog)。
|
||||
- **判据** → ① 凡「读**别人**安装位置 / 版本 / 布局」的代码,路径**必须走解析层**,且**至少一条单测用假根**(已落地 `scripts/verify-dsh-install.mjs`,15 项断言);② 验收判据**显式包含"非本机布局"**(一句 env 注入即可);③ 前端验收**别用 fixture 桩**掩盖后端不可读(本次就是断言全绿而端点其实是空的)。
|
||||
- **🔑 信号识别**:注释里出现「**本部署事实 / 目前是 / 暂时**」⇒ **当场转成待验证项**(那是作者自己知道这是假设的痕迹)。
|
||||
|
||||
### A20|存量烂账(巨量重复 / 历史遗留):选「只增不改 + 库外视图」,不就地重写
|
||||
|
||||
- **实例**:档案 82 = 2024 行 / 89.1 KB,切 **224 块**后 **重复标题 22 个、冗余块 190 个(≈85%)**;但「八、口径提醒」有**两个内容不同的变体** ⇒ **不是纯复制,盲目去重会丢信息**。
|
||||
- **做法(零改写)**:原文**一字未改** → 文末追加「修正(日期)」小节(实测数据 + 视图路径 + 阅读建议)→ 生成**去重视图**(保留每组信息最全的一份,其余留占位注释)**只写库外** `.workbuddy/cache/dedupe-view/` → manifest 加 `dedupeView` 字段、检索命中时提示"优先读视图"。89.1 KB → 59.0 KB,**零风险**。
|
||||
- **判据** → ① 先做**变体检测(同名 ≠ 同内容)**再决定能不能去重;② **写入权留在原文**(历史冻结),派生物放库外;③ 根治(拆分)与止血(视图)**分开立项**,别用一次大改解决两件事。
|
||||
|
||||
### A21|任何自动判据都要报「分布」;失效就改,别让它假装有区分度
|
||||
|
||||
- **实例**:`tier` 判据原为"被引用次数 ≥8" ⇒ **hot 44/89 ≈ 一半**(等于没筛);改为「**谁在引**」四档(hot = 被 L1/L2 现行层引 ≥3 次)⇒ **hot 7/89(8%)** ✓。⚠️ 我第一版把 **L4 台账类**也算现行层 ⇒ hot 反升到 60,**更糟**(台账会顺带列出几乎所有档案号,**索引式提及 ≠ 要读**)。
|
||||
- **判据** → ① 判据上线时必须报**分布**(各档占比),一眼看出有没有区分度;② **区分"顺带列举"与"真的依赖"**(索引/台账/清单类文件的提及**不算**引用);③ 判据本身要定期体检(老判据会随规模失效)。
|
||||
|
||||
### A22|替换 / 退役类动作的顺序:先补位,再退役
|
||||
|
||||
- **实例**:univer 承担 ① AI 生成 docx/xlsx ② Office 导入导出 ③ `.univer` 协作预览(**独有**)⇒ 要弃用必须**先把 ① 换成 `dsh-office` 并验证**,再停 univer;「**顺序不能倒**」。同理 `@softspark/dsh-file-preview` 的退役**必须等平台升级(阶段 4)之后** —— 现在退 = 生产立刻失去预览。
|
||||
- **判据** → 动「下线 / 替换 / 摘除」之前先写三行:**它现在承担什么**(逐项列)→ **每一项换成什么 + 验证过没有** → **换完之前不许停**。
|
||||
- 与 **A16(伴随物清单)** 互补:A16 管"要一起改什么",本条管"**先做哪一步**"。
|
||||
|
||||
### A23|流程类失效多半不是「忘了」,而是「触发词没命中」
|
||||
|
||||
- **实例(2026-09-14 事故复盘,档案 95)**:改平台代码 / 铺插件 / 重启 `dshs` 时,AI **没把自己这次动作分类成"落地一次改造"** ⇒ 六阶段流程**整条不存在**(阶段 0 前置检查、阶段 2 方案确认、阶段 5 归档全缺)。自审原话:「**本技能就在本机,我一开始没加载;直到用户追问才加载**」。
|
||||
- **根因是结构性的**:流程只写在**按需加载的技能**里,而常驻层 `CODEBUDDY.md §2` 自己就写着「**技能的加载由模型判断相关性,不能保证**」 ⇒ **没加载 = 没有流程**。
|
||||
- **判据** → ① 凡「**动作前必须生效**」的规则,**必须写进常驻层**(项目根 `CODEBUDDY.md` / `MEMORY.md`),技能只放"需要时去拿的方法论";② 常驻层的**触发条件要用「动作词」**("要改平台代码 / 要铺插件 / 要重启服务"),**不要依赖模型自我分类**("我要做一次改造"这种判断本身就会失效);③ 自审时区分**"当时成文口径"与"新立口径"**(A13)—— 本次 95 的自审引的是**过期 R8**(要求"取得确认"),而 R8 已于 09-13 由用户改为"开发环境服务器不必等确认,只需动手前一句话说明"⇒ 两栏都要给,否则违规被高估。
|
||||
|
||||
### A24|拦截面必须覆盖「真实行为面」——装在工具上的闸门,拦不住正文里的行为
|
||||
|
||||
- **实例(2026-09-15 实测)**:昨天给「提问闸门」装了 `PreToolUse` + matcher `^AskUserQuestion$` 的 hook,想治"AI 老让用户确认简单问题"。今天核账:本工作区日志 `tool=AskUserQuestion` 调用数 = **09-12: 43 / 09-13: 3 / 09-14: 0 / 09-15: 0**(`UserQuestion`/`elicitation` 的命中全是 `--tools` 参数与 host capability 字符串,不是调用)⇒ **真实提报用户几乎全在正文里,hook 从装好那天起就 0 命中**。
|
||||
- **判据** → 设计任何"拦截 / 校验 / 门禁"之前,先**用日志或计数证明行为发生在哪一面**:
|
||||
① 统计**该面的真实发生率**(不是"应该有");② 若闸门装面上限远低于行为面,**闸门等于装饰**(还制造"已经治好了"的假安全感);
|
||||
③ 正文类行为(无法被工具 hook 拦)只能靠**常驻层的可执行自检动作**(详见 `CODEBUDDY.md §1` "回话前自检")或 **Stop hook 扫最后一条回复**。
|
||||
- **可复跑的核账命令**:`grep -c "tool=AskUserQuestion" <工作区宿主日志>`(宿主日志在 `~/.workbuddy/logs/<日期>/<工作区名>__*.log`,记录 `[ToolManager] execute | tool=X`)。
|
||||
|
||||
### A25|本机改完 ≠ 交付 —— 先画出「改动层 → 生效链路」再宣布完成
|
||||
|
||||
- **实例(同类 3 次,2026-09-13/14/15)**:① 只做到**本地打包、没部署** ⇒ 用户「点开看还是和之前一样」;② 平台登录页/运行时**只改本机、从没部署到服务器** ⇒ 用户看的是旧页面(原话:「**那你看的当然还是旧页面**」)。
|
||||
- **判据** → 宣布完成前逐项答三句:**① 改的是哪一层?② 这一层的生效链路是什么?③ 最后一步走了吗、在「用户可见面」验了吗?**
|
||||
链路清单(缺一步都不算交付)见 `dsh-change-workflow` **阶段 5 §0「交付门禁」**表格:静态页 = scp(含 CDN 缓存坑)|平台 TS = build + restart|插件 = tgz → 候选池 → 实例启用 → **重启实例**|文档库/技能 = scp + 对账|配置 = 改 + reload/restart。
|
||||
- **四条"自我安慰",一条都不算交付**:**本机改完了** · **build 通过了** · **本地打包完成** · **已 commit 了**。
|
||||
- 与 **A19**(验收要含第二环境)互补:**A19 管"在哪个环境验",本条管"链路走没走完"**;与 **U20 / X9** 互补:部署本身**不必问用户**,但**必须做**。
|
||||
@@ -0,0 +1,194 @@
|
||||
# 素材库 · 用户的有效决策(U1–U24)
|
||||
|
||||
> **归属**:技能 `dsh-decision-method` 的素材库(**按需读**,不是每次都要读)。
|
||||
> **主文件 / 索引 / 判定核心** = `../SKILL.md`(§4 判定核心 · §5 流程 · §7 语言表 · 附 自检)。
|
||||
> **用法**:只在「要判某条是否属于既有口径」或「要引用用户原话」时读本文件;**别整段抄进答复**。
|
||||
> **维护**:条目**只增不改**(编号进位到末尾);用户原话**逐字**引用;每条必须带「实例出处 + 判据」。
|
||||
|
||||
---
|
||||
|
||||
## 1. 决策素材库 · 用户的有效决策(U1–U22)
|
||||
|
||||
> 「有效」= 事后被证明正确、且已被落地验证。**这些是用户的稳定偏好,不是一次性指令** —— 新需求来时可以按此预判方向。
|
||||
|
||||
### U1|面向用户的东西只保留「用户视角」,不暴露平台内部
|
||||
- **原话**:「只允许在自己的目录下创建工作区」「**不要给用户看完整路径**」;「用户就只能访问(含读取)dsh 服务用户 id 对应的那个文件夹,**连读都不要读取**」
|
||||
- **落地**:picker 根固定 `<userRoot>/ws`、面包屑显示「我的工作区」、下载走平台代理不暴露宿主路径(档案 17/18/39/56)
|
||||
- **判据** → 任何 UI/接口会暴露**绝对路径、uuid、内部术语、宿主目录名**的,一律收敛;收敛不需确认,扩大才需要(见 R5)
|
||||
|
||||
### U2|不做两套实现,能扩展就不新建
|
||||
- **原话**:T01「实例内我的技能 → **扩展 business-plugins 不用做两套**」(否决了"新建 `@dsh-local/my-skills`")
|
||||
- **判据** → 已有扩展点能承载(哪怕要加一个 section / 一个路由)→ **优先扩展**;新建只在"语义完全不同 + 复用会耦合"时才提
|
||||
|
||||
### U3|删任何东西之前先扫引用("看起来像资料"≠"没被引用")
|
||||
- **原话**:「参考资料是不需要」(针对 MCN 技能包裁剪)
|
||||
- **AI 的正确处置**:扫描后发现三类"像资料"的其实是被引用的**功能件** —— `nuwa-skill-main/` 主体被引为"主方法论"、`references/样例/` 被 `06_生成账号设定卡片.md:67` 写"动手前必须先读" → **保留**;只剔真 0 引用的块;且**剔 `browser-harness/` 目录必须同步改文档**,否则留死引用(档案 T03 §4.1 裁剪表)
|
||||
- **判据** → 删除类需求的**第一步永远是引用扫描**(`grep -rIn` + 排除说明行),产出"引用实测表"再定取舍;**剔除目录 = 必须同改引用它的文档**
|
||||
|
||||
### U4|交付面越少越好(推翻架构洁癖)
|
||||
- **原话**:「**业务技能要打包进插件里一起安装使用,不要分开管理**」(推翻 AI 既有的"技能走平台共享技能层"结论)
|
||||
- **判据** → 用户的心智模型("我装一个插件就全有了")**优先于**架构上的"分层更干净";一个包能解决就别拆成两条投放链路
|
||||
|
||||
### U5|状态变化必须让用户感知到(无反馈 = 缺陷)
|
||||
- **原话**:「点重连成功,但**过程中没有任何加载动画**」;「**AI 生成的文件看不到、下不了**,本机地址浏览器打不开」
|
||||
- **落地**:XHR 挂起 3 秒上覆盖层(档案 59)、右下角「📁 我的文件 / 🧭 能力」、档位提示条(档案 56)
|
||||
- **判据** → 后端正确但用户"看不见 / 点不动 / 不知道在等什么" = **同等优先级的功能缺陷**;凡有等待、有状态、有产出的地方都要有可见反馈
|
||||
|
||||
### U6|同一主题一次性做透
|
||||
- **原话**:「**一次性优化到位**」;「AI 对话记录(sessions)保留时间**可以长些**」
|
||||
- **判据** → 用户讨厌"打补丁式小改";同主题一次列全(如清理策略一次落 5 项);用户给方向性偏好("长些")时**自己定量再回填**,不要反复问
|
||||
|
||||
### U7|信息层级要站在"看得懂"的角度,而不是开发者视角
|
||||
- **原话**:「**导入到候选池是什么意思**」「官方插件优先展示应该是**插件说明或中文名称**,需要**一眼知道这个插件是干什么的**」
|
||||
- **落地**:白名单首列由插件名改**中文说明**(2 行 clamp),技术标识降副行;「候选池」→「导入到平台」;加一句「**投放 ≠ 生效**」的说明(档案 31)
|
||||
- **判据** → 表格/列表首列放**用户能读懂的那一列**;内部术语不得直接上页面
|
||||
|
||||
### U8|权限方向只准收窄,扩大必须先确认
|
||||
- **原话**:(R5 由来)用户明确划定:收窄可直接做,**扩大一律先出「权限影响评估」四问**
|
||||
- **判据** → 任何改动先答「这次是**扩大**还是**收窄**」;命中扩大(新增挂载 / 放开遮蔽 / 暴露平台目录或 env / 放宽 ALLOWED_ENV / 放松 nft / 提档位 / 新增可读写路径 / 让 root 执行链路的对象变用户可控)→ **停手等确认**
|
||||
|
||||
### U9|明确「暂缓」也是决策
|
||||
- **实例**:档案 21 后续(禁 HMR / catch-all vhost)「用户已决定暂缓」;域名切换侦察后用户说"还没准备好" → **parked,不再推进,等用户主动提起**
|
||||
- **判据** → 前置条件在用户侧(备案 / 账号 / 供应商)时,**给出"需你先办的三件事"然后 parked**,不要反复追问或硬推
|
||||
|
||||
### U10|术语统一只改用户可见的那一层
|
||||
- **原话**:「将所有**业务插件**字段改为**功能插件**」→ 后来「将**功能插件**改为**功能管理**」
|
||||
- **AI 的正确收窄**:只改**显示文案/label**(zh+en 同步),**代码标识符、表名、包名、API 路径、文件名一律不动**;同一 locale 里描述"插件这个事物"的句子也**刻意不改**(分区叫「功能管理」,管的对象仍叫「功能插件」)
|
||||
- **判据** → 术语需求 = **label 级改动**;一旦要动标识符就是大范围重命名 → 回到 R7 先出清单
|
||||
|
||||
### U11|用户给的数值即使偏离规范也是硬约束
|
||||
- **原话**:「插件管理的官方插件管理 列表页高度增加 和页面底部间隔 **200PX** 即可」
|
||||
- **落地**:`#view.page-plugins { padding-bottom: 200px }`,**代码注释注明**「`01-规范/06-工作台UI规范` 常规区间是 14~24px,**200px 是用户明确指定的例外**」(档案 61)
|
||||
- **判据** → 用户点名数值 → **照做 + 注释固化来源**,防止日后被"按规范修正"回去;与规范冲突时在注释里写清是例外
|
||||
|
||||
### U12|危险操作要确认弹窗 + 明说后果
|
||||
- **原话/定稿**(档案 16 §2.2):批量启用禁用 → **必须点确认弹窗**,弹窗内写明「**将重启实例,会话可能中断**」
|
||||
- **判据** → 任何会打断用户当前状态的操作(重启实例 / 停会话 / 清数据)→ 前端确认 + 明写后果;后端配合「先备份再执行」
|
||||
|
||||
---
|
||||
|
||||
### U13–U19|2026-09-12 用原始会话转录回补核对后新增
|
||||
|
||||
> 前 12 条来自**档案 + 工作日志**(会话的结构化沉淀)。这 7 条是拿 `07-scripts/extract-user-voice.py` 抽出
|
||||
> **180 条用户真实发言**(跨 09-08→09-12、5 个会话)逐条比对后**补上的漏项**。
|
||||
|
||||
### U13|我报给用户的数字,会被他当作事实基础
|
||||
- **实例**:09-12 00:06 用户直接引用我的读数再追问 ——「当前实况:2 个实例在跑,占用 **212 MiB** 和 **329 MiB**:为什么一个用户要占用这么多内存」
|
||||
- **判据** → **报数必须准确、并带取数时间与口径**;分母/单位错一次就会被当成事实传下去(档案 58 曾把 `systemd` 的**字节**当 KB,读数放大 1024 倍)
|
||||
|
||||
### U14|判断「该不该留」用的判据是「**有没有复用价值**」
|
||||
- **原话**:「是不是搞错了,**AI 生成的代码和脚本等才是需要重点定期清理的**」「这些脚本基本都是根据某个对话任务产生,**没有复用价值**」
|
||||
- **判据** → 取舍类需求**先问"这东西有没有复用价值"**,而不是问"它看起来像什么"(对照 U3:先扫引用)
|
||||
|
||||
### U15|用户会盯**产品级容量约束**(能撑多少人)
|
||||
- **原话**:「这个应该属于**控制用户上限**,不能让 10 个用户注册每个用户体验都差」
|
||||
- **判据** → 用户提需求时**隐含容量期望**;凡涉及常驻资源 / 并发 / 注册量,**主动把容量影响算出来讲清**(引用档案 58 的实测:2 vCPU / 1870 MiB,并发上限 ≈ 3 实例)
|
||||
|
||||
### U16|用户给的「实现建议」是**意图表达**,不是硬要求
|
||||
- **实例**:09-12 09:39 用户提「检测鼠标移动/焦点自动拉起实例」→ 被论证「同时动鼠标会 OOM」后**他接受了否决**,并把话题转到容量上限(U15)
|
||||
- **判据** → 可以(也应该)用更优方案替代,**但必须说明为什么否决**;不要为了"照做"而实现一个坏方案
|
||||
|
||||
### U17|用户会充当**执行手** —— 必须给可直接粘贴的完整命令
|
||||
- **原话**:「还需要建立 ssh 链接 **端口号 32022**」「我的意思有些操作需要 ssh 执行」「**给我个命令去服务器上执行就行**」
|
||||
- **判据** → 凡需要用户动手的(服务器命令 / 浏览器验证 / 关应用再执行),**给一条完整可粘贴的命令 + 期望输出**,不要让用户拼命令;需要他关掉某程序时,要说清"为什么要关"
|
||||
|
||||
### U18|用户会明确「关闭」一条线 —— 关闭后不再推进
|
||||
- **原话**:「**忘记这个项目把**」(否决 my-deepseek-harness 二开路线);「**还没准备好 后面再说**」(域名切换 parked);「**档案 21(卡顿/流式)可以展缓**」
|
||||
- **判据** → 看到这类措辞**立即 parked**:保留已得结论、不再追问、不列入待办;**等用户主动提起**(同 U9,但这条是"用户主动关",U9 是"AI 建议暂缓")
|
||||
|
||||
### U19|用户大量时间花在**平台能力认知**类提问上
|
||||
- **原话**:「dsh 插件开发 不同的插件 代码都是独立的吗」「一个插件的功能都在一个文件夹中吗,是否可以像 SKILL 管理一样做一个插件管理页面」「插件可以热更新 热加载吗」
|
||||
- **判据** → 这类"**是什么 / 能不能**"的往返,**应由「能力清单」类交付物一次性消除**(档案 56 的 `platform-capabilities` 共享技能 + 实例页「能力」面板就是为此而生);**每做一次能力变更,同步更新能力清单**
|
||||
|
||||
### U20|「不打断用户的上线」不要问 —— 部署 / 上线属执行细节(2026-09-13 用户纠正)
|
||||
|
||||
- **原话**:「**为什么要等我确认才部署呢,我看线上效果才知道是否满足需求**」
|
||||
- **背景(真实失手)**:v0.2.8 已打好包,`ensure-biz-plugins.cjs --all` **只换 profile 里的包**(不重启、不停实例、**零中断**),AI 却按 R7「只做被明确要求的事」**停下等确认** ⇒ 用户看不到线上效果,**无法判断需求是否被满足**。
|
||||
- **判据** → **红线的触发按「实际影响面」判,不按「动作名字」判**:
|
||||
- R8 的**唯一**触发条件 = **会中断在线用户**(重启 `dshs` / 停实例 scope / drain / 改实例配额·env / 改 nginx·nft);
|
||||
- **不中断**的上线(传产物到 `/opt/dsh/artifacts`、换 profile 包、改静态页、候选池投放)= 边界内已列的「**部署与同步**」⇒ **做完即上线**,事后一句「我选了什么(可推翻)」交代即可。
|
||||
- **与 R7 的边界**:R7 管的是「**未经确认的批量 / 全仓写入**」和「**范围外的额外改动**」,**不管「该不该上线」**;把 R7 的精神套到上线动作上 = **过度套用**(见 X9)。
|
||||
|
||||
### U21|答复要「结论三件套」:是否已实现 → 为什么不行 → 要拍板什么(2026-09-13 用户纠正)
|
||||
|
||||
- **原话**:「**需要告诉我的是 是否已实现,如果未实现:为什么不能,需要我拍板可以问我**」
|
||||
- **背景(真实失手)**:AI 用「我自己的失误(一并交代)+ 探针怎么被污染 + 版本流水(0.2.19/0.2.20/0.2.23)+ 下一步三步计划」回答了「是否已实现」——用户要的结论**在第 5 段之后**才出现;收尾还问「要我现在接着做,说一声即可」。
|
||||
- **判据** → 回答「是否 / 能不能 / 为什么不行」类提问,**固定四节、顺序不变、没有的节整节删掉**:
|
||||
① **判定**(✅ 已实现 / ⚠️ 部分可用 / ❌ 未实现 + 一句话;用户列了多项就逐项给)
|
||||
② **为什么不行**(按层:已排除的原因 → 当前唯一卡点,最多 3 层)
|
||||
③ **我接着做**(**陈述句**,不是征询句)
|
||||
④ **需要你拍板**(**必须是整条回复的最后一节** —— 它后面不许再有任何节;**真需要才写**,不需要就删掉整节)
|
||||
- **四条铁律**:主位必须是**用户问的那件事**(AI 的进度 / 失误 / 计划不得占前两节)· 结论层**零技术标识** · **禁征询式收尾**(已定的下一步直接做)· **待拍板项置末**。
|
||||
- **修正(2026-09-15 用户明令 · 完整原话)**:「**能根据决策方法 自行决策的就自决策继续处理,不能决策的问题和需确认内容放在回复的最后,按照有序段落展示**」⇒ ③④ **对调**(原为 ③ 拍板 → ④ 接着做),且该节要**逐条编号**(有序段落,不写成散文)。⚠️ 分清三件事:**自决策**(能判的别问,直接做完并陈述)· **位置**(不能自决策的收到最后一节)· **形态**(陈述句列「选项 + 优缺点 + 我的倾向」,⛔ 不是征询句"要不要我…" / "说一声即可")。
|
||||
- **修正 2(2026-09-15 用户明令)**:「**需要我确认的方案需要说明优点和缺点,现在没法判断,假如只有优点或只有缺点那不需要我判断**」⇒ **提报给用户前先过「取舍筛」**:候选各写**优点 + 缺点** —— ① 某个**只有优点**(明显更优)或**只有缺点** ⇒ **不需要用户判断**,自己拍掉再陈述;② 只有**各有优有劣、客观标准分不出高下**(真取舍)才提报用户;③ 提报给用户时**必须逐项列出优点与缺点**(只写"可感知差别"**不算** —— 用户原话「现在没法判断」就是这么来的)。落地载体:`dsh-feature-first §5.3 铁律 5 / §5.4 硬约束 8 / 反模式 12`。
|
||||
- **修正 3(2026-09-15 用户明令)**:「**每个需要我决策的问题的潜在解决方案 A B C 也按照段落式排版,别横着排列**」⇒ 候选**竖排成段**(A / B / C **各占一行**),⛔ 不许写成 `A:… · B:…` 一行横排,⛔ 也不许把候选做成**表格的列**(表格是横向对比,与"段落式"正相反)。段内「优点…;缺点…」连写即可,不必每个字段再拆行(否则撞 §5.4 硬约束 3「每节 ≤7 行」)。落地载体:`dsh-feature-first §5.3 铁律 5 ④ / §5.4 硬约束 9 / 反模式 13`。⚠️ 触发它的正是**我自己的实际输出**(把三个候选写成 `A 维持现状 · B 按 50 KB 切分 · C 改成按月分片` 一行并列)。
|
||||
- 落地载体:`dsh-feature-first §5.1–§5.3`(含**可复制骨架**);与 **X10**、**U20 / X9** 同族(都是「别把该自己拍的推回去」)。
|
||||
|
||||
### U22|只碰自己 lane 的东西;平台级 / 全局 / 别人 lane 一律只报告(2026-09-13 用户明令)
|
||||
|
||||
- **原话**:「**谁让你去改这个的**」+「**不是自己负责的任务相关文件不要去改**」
|
||||
- **背景(真实越界)**:为打通自己任务的插件投放(撞 `ERR_PNPM_UNEXPECTED_STORE`),AI **自行创建了 `/var/lib/dshs` 全局符号链接** —— 无人授权,且属**平台级路径**。用户当场追问「谁让你去改这个的」;AI 随即自行撤销并确认实例不依赖它。
|
||||
- **判据** → **动手前先问「这在谁的 lane」**:
|
||||
- **我的 lane(可自己拍)**:① 我负责的插件源码 / 产物 ② 该 profile 的依赖安装 ③ 我自己的临时脚本 ④ 我方案内的执行细节(部署 / 上线 / 重启 / 改配置)
|
||||
- **不是我的 lane(只报告、不动手)**:平台级路径与全局文件(`/var/lib/**`、符号链接、systemd 单元、nginx·nft)· 别人的 profile / 产物 / lane · 与本次任务无关的文件
|
||||
- **与 R7 的关系**:R7 适用于「不是我的 lane」,**不适用**于「我 lane 内的执行细节」—— 两个方向都别套错(对称面见 **U20 / X9**)。
|
||||
- ⚠️ **动机不构成豁免**:「**改它能让我流程跑通**」正是越界的高发动机 ⇒ 越方便越要先问「这是谁的 lane」。
|
||||
|
||||
---
|
||||
|
||||
|
||||
### U23|不要重新开发:先查官方推荐库有没有现成的(2026-09-14 用户口径)
|
||||
|
||||
- **原话**:「**需要查官方推荐库是否有类似插件,是重新开发还是改造**」(背景:univer 太重,要"点对话里的文件在旁边窗口打开")
|
||||
- **结果**:官方推荐库里拿到 **`@softspark/dsh-file-preview` v2.0.0(65 KB tgz)** ⇒ 体积约 univer 的 **1/650**,且未动 univer 一处。
|
||||
- **判据** → 要加任何能力,**顺序固定**:① 本机/项目已有 ② **官方推荐库**(`Awesome-DeepSeek-Harness-Plugins`,源 = cordis.run 索引 331 个)③ npm `keywords:dsh-plugin` ④ 才考虑自研/改造。
|
||||
- **候选体检三关(缺一即否)**:① inject 依赖的**官方包存在吗** ② 有没有**被角色补丁禁**的包(⇒ 静默挂死)③ `peerDependencies` 是否**覆盖我们的 dsh 版本**。反例:`dsh-file-viewer` inject 含本平台不存在的 `dsh-client-runtime` ⇒ 装上即静默挂死。
|
||||
|
||||
### U24|分期方案必须互相兼容(2026-09-14 用户口径)
|
||||
|
||||
- **原话**:「**一/二期方案必须互相兼容**」(集群化改造 Manager/Worker)
|
||||
- **落地原则**:**分期只分「自动化程度与规模」,不分「机制 / 数据结构 / 协议」** —— 机制与结构**一期定死**,二期只加机器 / 加开关 / 加运维。
|
||||
- **可执行判据(7 维度兼容矩阵)**:Manager 数(同代码 1..N,**禁止"必须 2 台"的硬假设**)|Worker 数(一期就走 RemoteSpawner+agent,哪怕 Worker 在本机)|存储(一期就写能力探测 + 按目录分层)|DB(**一期必须 PG**,不能先用 SQLite 顶——租约依赖 PG 原子 `UPDATE…WHERE`)|自动接管(开关默认关,但 **lease+fencing+self-fencing 一期全实现**)|备份(一期就用同一套工具/格式,只调频率)|代理路由(零改动)。
|
||||
- **配套**:新增「**状态三分类**」表(用户数据 / 平台状态 / 机器基线)—— 机器基线(原生运行时、镜像、bwrap 白名单)**不能跟着用户迁移**。
|
||||
|
||||
### U25|锁是独占资源:抢到就必须还 ——「带锁结束」不算完成(2026-09-14 用户明令)
|
||||
|
||||
- **原话**:「抢到的锁一定要**执行完成后解锁**才算任务完成,**禁止抢锁执行一半不解锁就结束任务**」
|
||||
- **为什么是硬规则**:锁的意义就是**同一时刻只允许一个执行会话**(本库多会话并行是常态)⇒ **带锁结束 = 把所有其他会话挡在门外**;而本库**无心跳机制**、别人**没有任何判据**能确认你已停 ⇒ 只能空等,或被人误判"已死"而违规接管(**R9** 禁止)。这正是 R9 存在的原因。
|
||||
- **判据(三条配套)**:
|
||||
① **抢锁前先把收口步骤列出来**(落地 → 校验 → 推送/对账 → 收尾)—— 别做到一半才发现收不完;
|
||||
② **中途必须停**(等用户拍板 / 等外部窗口)⇒ **先释放锁再停**(锁是"正在动手"的凭证,不是"占位符");
|
||||
③ **结束语必须对锁状态负责**:要么写明「已释放」,要么**显式点名**「锁仍在 `<OWNER>`、未释放、原因、下一步」—— 后者**仅限"释放通道不可用"这类极端情形**;⛔ 「忘了 / 做不完就走」一律不允许。
|
||||
- 与 **U22(lane)** 互补:U22 管"**该不该动手**",本条管"**动手后必须收口**"。
|
||||
|
||||
### U26|决策中发现风险/问题 ⇒ **不许带着问题往下走**,先优化到「当前情境下的最优解」(2026-09-14/15 用户明令)
|
||||
|
||||
- **原话**:「**决策中发现方案有风险和问题,需要分析并优化到当前情况和状态下的最优解,然后进行下一步处理**,这个也要加入决策方法」
|
||||
- **为什么是硬规则**:带着已知风险进入下一步 = 把风险**转移给未来**(届时修更贵);而"最优"不是理想方案,是**当下条件(现有资源 / 时间 / 风险面 / 能否验证)下最好的那条**。
|
||||
- **判据(四步,缺一不可)**:
|
||||
① **列出来**:把发现的风险/问题**逐条写成清单**(不许只在脑子里);
|
||||
② **逐条处置**:每条给出**当前情境下可用**的处置 —— 能当场消掉的当场消(改设计/加缓解/降范围),**消不掉的写"残余风险 + 触发条件"**;
|
||||
③ **说清残余**:哪些是"已知但接受"、为什么不接受不行、什么信号出现就必须回头看;
|
||||
④ **然后**才进入下一步 —— 且在交付里把 ①②③ **一并写出来**(这就是 `dsh-feature-first §5.1` 骨架里"为什么不行 / 需要你拍板"两节的原料)。
|
||||
- **配套工具**:能不能消掉要靠 **A24**(先核账真实行为面)· **A18**(静默失败会伪造结论)· **A19**(第二环境)· **A25**(本机改完≠交付)去判;**"改小范围先落地"永远是合法候选**(§4.4 第 2/3 条)。
|
||||
- ⚠️ **反面**:把"有风险"当成"要不要问用户"(**过度提报用户**)或者"先干着看"(**风险转移**)—— 两者都不对:**先自己优化到当下最优,再带着残余风险请用户拍板是否接受**。
|
||||
|
||||
### U27|要的是**解决问题**,不是**得过且过、将就妥协**(2026-09-15 用户明令)
|
||||
|
||||
- **原话**:「**项目推进要的是解决问题 不是得过且过,将就妥协**」
|
||||
- **判据** → 面对发现的风险 / 缺陷,**默认目标是"解决"**;下面三种**都不算解决**,一律不许当成交付:
|
||||
① **降级目标**(把"要做到 A"悄悄改成"做到 A′ 也行");
|
||||
② **延期**("下次顺手再说 / 等窗口再补" —— 除非**客观不可逾越**且有证据);
|
||||
③ **静默兜底**("先这样也能跑",而风险与触发条件一个字没写)。
|
||||
- **唯一允许"暂时接受"的情形 = 客观不可逾越**(技术不可行 / 上游未支持 / 需要用户侧凭据或窗口)⇒ 必须写明**三项**:
|
||||
① **卡在哪**(证据)② **当前已做到哪一步** ③ **什么条件一出现就必须回头解决**。
|
||||
- **与 A6 的边界(别读成互相矛盾)**:**A6 管"路径"**(实现取最小代价、不追求最彻底);**U27 管"目标"**(目标不许打折)⇒ 一句话:**目标不打折,路径取最小代价**。
|
||||
- **与 U26 的关系**:U26 要求「发现问题先优化到当下最优解再走下一步」;**U27 补的是"最优解"里不许包含'降低目标'这个选项**。
|
||||
|
||||
### U28|🟢 红线:只做正向迭代 —— 命中「劣化风险」立即停下复盘,无正向做法则立即停止(2026-09-15 用户明令)
|
||||
|
||||
- **原话**:「**要确保所有决策是让项目正向迭代和提升**,如果遇到**纯在项目劣化风险**(目标,方向,架构,功能,性能,安全,交互,UI,便利性,扩展性等)需要**立即停下复盘**,如确实**无正向迭代方法**立即**停止**,**禁止继续执行**」
|
||||
- **判据(每次决策前过一遍十维)**:**目标 / 方向 / 架构 / 功能 / 性能 / 安全 / 交互 / UI / 便利性 / 扩展性** —— 任一维度**净变差**即命中。
|
||||
- **命中后的三步(一步都不许跳)**:① **立即停下**(不许"做完再看")② **复盘**:写清劣化在**哪一维**、**代价量级**(数字 / 证据)③ **找正向做法**(改小范围 / 换实现 / 分阶段)—— **拿不出来 ⇒ 立即停止、只报告,禁止继续执行**。
|
||||
- ⛔ **三种伪装**:把劣化说成"必要代价"/用"后续再优化"掩盖已知劣化/把劣化项藏进交付里不写。
|
||||
- 与 **R5** 互补:R5 只管**权限**(只准收窄);**R11 管全维度净收益**。与 **U27**(不将就妥协)· **A20**(代价不对称就保留)同族。
|
||||
@@ -0,0 +1,34 @@
|
||||
# 反例库 · 被驳回 / 被纠正的决策(X1–X13)
|
||||
|
||||
> **归属**:技能 `dsh-decision-method` 的素材库(**按需读**,不是每次都要读)。
|
||||
> **主文件 / 索引 / 判定核心** = `../SKILL.md`(§4 判定核心 · §5 流程 · §7 语言表 · 附 自检)。
|
||||
> **用法**:只在「要判某条是否属于既有口径」或「要引用用户原话」时读本文件;**别整段抄进答复**。
|
||||
> **维护**:条目**只增不改**(编号进位到末尾);用户原话**逐字**引用;每条必须带「实例出处 + 判据」。
|
||||
|
||||
---
|
||||
|
||||
## 3. 反例库:被驳回 / 被纠正的决策(X1–X11)
|
||||
|
||||
> 每条**反例 = 一条避免规则**。这些是本工作区里真实发生过的失手。
|
||||
|
||||
| # | 反例 | 根因 | 转为规则 |
|
||||
|---|---|---|---|
|
||||
| **X1** | 为"让 scp 文件行尾干净",用脚本把 **147 个文件** CRLF→LF;当期只被要求改一句 UI 字符串 | 把"顺手修"当效率;**没做单点验证就全库推广**;忘了本机镜像不是沙箱 | → **R7**:只做被明确要求的事;>10 文件先出清单;先单点验证;传播前 `git status` 比对待传清单 |
|
||||
| **X2** | 档案 58/59 连续两次重启 `dshs`,**把在线用户踢下线**并引发报障 | 把"改完即验"当完整闭环,漏了"改前先知会" | → **R8**:重启/drain/铺插件/改配额 env → 先说「影响谁、断多久、为何必须现在做」 |
|
||||
| **X3** | 把 mtime 当并发冲突判据 | mtime **分不清是谁改的**;本库长期不提交 → 无冲突检测 | → 冲突判定只认两个硬信号:**别人的占用锁** + **待推送清单里的未声明文件**;mtime 只作提示 |
|
||||
| **X4** | 由"空闲回收没生效"外推出"实例不会中断"(**被用户当面纠正**) | 把"某机制失效"误推成"该类现象不存在" | → 现象归因要**枚举全部可能来源再逐一实测**(中断真凶是服务重启 + 崩溃重启,与回收无关) |
|
||||
| **X5** | 按字面执行"参考资料不需要"去删 | "看起来像资料"与"实际被引用"是两件事 | → 见 **U3**:删除前先扫引用 |
|
||||
| **X6** | 用截断到 200 字符的 `grep` 输出当 `old_string` 去 Edit 长行 → **误删对方记录行首** | 拿不完整内容当精确锚点 | → **长行 Edit 前必须先用 Read 取全文**;共享文件只用 Edit 精确替换(失败即冲突信号),禁整文件 Write |
|
||||
| **X7** | 把用户设备上的"旧会话不好用"当成感受问题,未深挖 | 没做会话级取证 | → 报障第一步**先拿真实失败请求/真实状态**(`journalctl` 精确 URL+method+status),再归因 |
|
||||
| **X8** | "只注入 env 就以为配好了"(bundled 技能层实际未挂载) | 漏了"插件在实例内 `resolve()` + 读盘"这一层 | → 通用判据:**插件在实例内读盘的东西,必须真的出现在命名空间里**;env 只决定"去哪儿找" |
|
||||
| **X9** | **把 R7 按「动作名字」套到部署上** —— v0.2.8 只换 profile 里的包、**零中断**,却停下等确认;用户回「为什么要等我确认才部署呢」 | 红线被当成**关键词匹配**(见「部署 / 上线 / 生产」就触发门禁),没按**实际影响面**判 | → **按影响面判,不按动作名字判**(U20):R8 只认「会中断在线用户」;**不中断的上线 = 执行细节,做完即上线** |
|
||||
| **X10** | **答非所问:拿「我的失误 + 探针踩坑 + 版本流水 + 下一步计划」去答「是否已实现」** | 主位错位 —— 写的是**AI 的进度**,用户问的是**功能的可用性**;收尾「要我接着做,说一声即可」= 又把已定的执行细节提报用户 | → 用 **U21 结论三件套**(判定 → 为什么不行 → 要拍板什么 / 我接着做);失误只在 ①改变结论 ②用户问根因 时写(`dsh-feature-first §5.1–5.3`) |
|
||||
| **X11** | **为了让自己的流程走通,自行改了平台级路径**(建 `/var/lib/dshs` 全局符号链接,无人授权)→ 用户追问「谁让你去改这个的」 | **动机取代了边界判断** —— 「改它能让我流程跑通」被当成理由,没问「这落在谁的 lane」 | → **U22 闸 1**:不是我 lane 的(平台级 / 全局 / 别人 lane)**只报告不动手**;越方便越要先问 |
|
||||
|
||||
---
|
||||
|
||||
|
||||
| **X12** | **把用户给的材料当权威照抄**(他们扒的是新版 `0.1.5+` 源码,我们跑的是 `0.1.2-rc.1`) | 没先确认「**这份材料描述的是哪个版本**」 | → 用户给的素材要用**我们的实际版本**核对;本次 4 处纠正:包不存在 / 扩展点不存在 / 装上也静默挂死 / 投放通道不符。⚠️ 与 **U11**(用户给的**数值**是硬约束)区分:**数值口径是约束,事实陈述要核对** |
|
||||
| **X13** | **把自己的解析失败当成"版本差异"**(报「`__DSH_BOOT__` 结构变了」,其实是我的解析正则过时) | 差异归因时**先怀疑版本、没先怀疑自己** | → 报"两版不一样"之前,**必须在两边用同一解析都跑通一次**(或做 A/B 对照);档案 90 已追加更正防误导 |
|
||||
|
||||
| **X14** | **把「一批改造」的中断动作拆成多次执行**(一天连做 5 项改造 ⇒ 铺插件 4 次 + 重启 `dshs` 3 次,每次都让已打开页面手里的 `rev` 过期) | 只有"改一处→验一处"的单点思维,**没有"批处理窗口"概念**(R8 只说"先说明/取得确认",没说"攒批") | → **同一批改动的所有中断动作攒到一个窗口执行**;**窗口内 >1 次重启 = 违规信号**,停下来问"能不能并到一次"。⚠️ 这正是「Failed to load plugins」的直接成因(档案 95) |
|
||||
@@ -1,134 +1,172 @@
|
||||
# manifest · 包内文件清单
|
||||
|
||||
> 生成方式:逐文件 `compile()` / `json.loads` + md5 | **最近一次全量重算:2026-10-04 17:4x (2026-10-04 单包权威:02 档改为「本档即权威」(⛔ 不再指向外部技能当权威),保留来路说明;SKILL.md 撤回『必需外部依赖』声明改为自包含)**
|
||||
> ⛔ 本表**不含** `install.log`(运行日志)与 `references/manifest.md`(自引用,写完即失真)。
|
||||
> ⚠️ **provenance 列里的 `skills/multi-session-collab/…`、`skills/workbuddy-session-forensics/…` 已是历史路径**
|
||||
> —— 那两个目录 2026-10-01 已移到 `<工作区>/归档/技能-退役-20261001/`(⛔ 不在技能根了)。
|
||||
|
||||
文件总数:**49** | 语法 / 结构检查失败:**0**
|
||||
|
||||
## ✅ 已完成 · 2026-10-05 三代术语收敛(本节替代原「待办」)
|
||||
|
||||
- **已执行**:包内 + 两个工作区副本三方同步,md5 一致(`collabd.py`/`goalctl.py`/`board.py`/`board_ext.py`/
|
||||
`selftest.py`/`collabctl.py`/`guard.py`/`init_workspace.py`/`session-rules-check.py`/`board.html` 全部 OK)。
|
||||
`selftest.py` 基线 **PASS 97 / FAIL 0**(报告型 1 条不计入);改名的 5 条 `@case` 均能按新名字 `-k` 找到。
|
||||
- **⛔ 三类不动,是判据不是遗漏**(下一次改名前照抄):
|
||||
① **「」引述内容逐字不动**(含跨行引述块)—— 引用用户口径只写原话;
|
||||
② **历史段整段不动** —— `SKILL.md` 19–27 行代际表、含 `旧称/旧词/一代/二代/第三代` 的行、`<hN> 历史…` 段落
|
||||
(要讲清三代分别叫什么,就必须留着旧名);
|
||||
③ **`.py` 里 `目标检查` 一律不动** —— 它是**检查会话类别名**(`_CHECK_TAGS`/`_CHECK_TOPICS`、
|
||||
`[检查]-[结果检查/目标检查]`),并散在字面断言里(`CHECK_KINDS["queue-empty"][1] == "目标检查"`、
|
||||
`rows.append(...)`、`【目标检查】` prompt 头)⇒ 改了直接断判据。
|
||||
- ⚠️ **一处同改对**:`board.py::_ROLE_LABEL["worker"]` 与 `board.html` 的 `role==='…'` 是同一处判据的两侧。
|
||||
- ⚠️ **本条暴露的存量缺陷(已一并修)**:`selftest.py` 的期望串原写 `才建立一轮任务会话`,而 `SKILL.md`
|
||||
引述里逐字是 `才建立一轮执行会话` ⇒ 该子项**改前就是红的**(被基线里的 97/0 掩盖)。
|
||||
- 工具:`tmp/term-apply-v3-20261005.py`(dry-run/`--apply`,写盘前自动备份)+ `tmp/term-sync-20261005.py`。
|
||||
|
||||
|
||||
## 2026-10-04 新增文件(⛔ 由 manifest 重算登记)
|
||||
|
||||
- `references/01-文档索引.md` — 3604 B |md5 `825999a411e2a4f6b740063f81c01b03`
|
||||
- `scripts/judge_audit.py` — 13562 B |md5 `8f14a973fa5709a3b9a60b065dc22d7d`
|
||||
- `scripts/workspace_mirror.py` — 17263 B |md5 `60f104b37df3133785abb13f686eea4f`
|
||||
- `assets/start-supervise.ps1.tpl` — 5360 B |md5 `3805f1a82a1747269212287e9dfde369`
|
||||
- `assets/design-tokens.css` — 6364 B |md5 `0668feb3a4729f1022e579ac0c5d2569`
|
||||
|
||||
## 最近改动(⛔ 只记「什么时候改了什么」,不写流水账)
|
||||
|
||||
- **2026-10-02 07:0x · 开工第 0 步改名:会话「规划」→ 会话「规则机制」(本轮)**:
|
||||
① **用户纠正原话**:「**就应该是检查清楚 所有会话规则机制 是否配置完整且生效, 不是规划 是 规则**」
|
||||
⇒ 首版体检脚本**只查排期那一面**,当天实测出的三类失效(钩子注入指向已退役技能名 / 常驻快照写进幽灵目录 /
|
||||
每轮注入的记忆指针悬空)**一条都没覆盖** ⇒ 名字还叫「规划」=第二次「在册 ≠ 生效」。
|
||||
② **收敛成一个入口**:新增 `scripts/session-rules-check.py`(查 **三类十二项**:A 钩子在册·路径存在·
|
||||
注入技能名存在·闸门日志新鲜 | B 每轮注入记忆的技能指针·常驻快照不比权威旧 | C 周期钟·模型可用性·
|
||||
`cwds` 同形·投递心跳·活会话·`once` 从未运行的死排期);旧 `scripts/session-plan-check.py` **退役**
|
||||
到 `<WS>/归档/技能包-旧件-20261002/`,**能力不回退**。
|
||||
③ **状态标记改名**:`session-plan.json` → **`session-rules.json`**(旧的属过期件,⛔ 别拿来对照)。
|
||||
④ **判据收紧**:`cwds` 近失配原写成「同父目录 + 字面不同」⇒ 在 `AIProject/` 这种**多业务线平级目录**下
|
||||
把**别的线**报成失配(实跑当场 2 条假红)⇒ 改为「同父目录 + **名字去 `-`/`_` 后仍相同**」/「同名不同父目录」。
|
||||
⑤ **判据自验**:⑨⑫ 抽成**纯函数** + 合成样本夹具(`<WS>/tmp/rules-check-mutate.py`)—— 原版 10/0 绿、
|
||||
**四个变异体**逐一按预期报红。⚠️ 夹具**自己先红两次**(期望值写死:漏算样本 + 有序列表比中文名)。
|
||||
- **2026-10-01 18:5x · 外置根贯通 + 两处真缺陷(本轮)**:
|
||||
① `roots.env` 引导块从 9 份扩到 **16 份**(补齐 7 个非钩子脚本:`board` / `board_ext` / `collabd` /
|
||||
`deliver-gateway-token` / `goalctl` / `selftest` / `stop-collab`);
|
||||
② **盘符字面量清零**:配置目录兜底改 `~/.workbuddy`,工作区兜底改 `DSH_WS_ROOT`/cwd,
|
||||
覆盖网日志 glob 改 `DSH_OVERLAY_LOG_GLOB`(原为死路径 —— 本机 `E:/dsh-worker-dev` 不存在);
|
||||
③ 7 份加**输出编码兜底**;④ `roots.env` 增写 `CODEBUDDY_CONFIG_DIR`;
|
||||
⑤ 🔴 **修「钩子把技能包当工作区」**:`wb-result-hook.py` 的 `_WS_ROOT` 原按 `3×dirname(__file__)` 推,
|
||||
包内这份推出来=技能包自己 ⇒ 包里长出 `tmp/supervise-inbox/`;改为复用 `resolve_ws()`;
|
||||
⑥ 🔴 **修「重定向 + GBK ⇒ print 抛异常 ⇒ 顶层记 fatal、整轮失败」**(本机实测 4 次;
|
||||
这正是**常驻**跑不起来的拦路石 —— 常驻必须重定向 stdout);
|
||||
⑦ `install.py` 工作区模板路径纠错(原指 `scripts/collab/`,实际在 `scripts/`);
|
||||
⑧ `collabd.py` docstring + 两处活注释改**常驻定案**(上一轮漏传导);
|
||||
⑨ `lock/preflight-lock.sh` + `hooks/lock-guard-hook.py` 的盘符字面量清零;
|
||||
⑩ 新增 `install.py --manifest`(见下条);
|
||||
⑪ 🔴 **`scripts/selftest.py` 去掉最后一处项目绝对路径**:`t_tick_wired` 原先写死
|
||||
`<某工作区>/.workbuddy/tools/wb-result-hook.py` ⇒ 两处都不对:既违反「技能里只用相对路径」,
|
||||
又因宿主接线已改指**包内**那份而**恒走"文件不在,跳过"** ⇒ 看着绿、其实什么都没验(静默假绿)。
|
||||
现改按包内相对路径取 `hooks/wb-result-hook.py`,该用例从"跳过"变**真检**(4 项实跑通过)。
|
||||
- **2026-10-01 19:0x · `install.py --manifest`**:把「重算本表」固化成子命令
|
||||
(包一改表就过期 ⇒ 以前每轮临时手搓脚本、跑完即删,已因此误判两次)。
|
||||
只重写**表 + 计数行 + 重算时间**,⛔ 不碰上方散文;**行尾随原文件**(本表是 CRLF,写成 LF 会造成一次无声全文件 diff)。
|
||||
- **🔴 两份同源脚本「有意不一致」(⛔ 别当 bug 去修平)**:`preflight-lock.sh` 与 `lock-guard-hook.py` 在
|
||||
**技能包**与**文档库 `07-scripts/`** 各有一份。包内那份住在技能包里、**推不出文档库根** ⇒ 只能走
|
||||
`roots.env` +(`lock-guard-hook.py` 的)末位字面量兜底;库内那份住在 `<文档库>/07-scripts/` ⇒
|
||||
**按 `__file__` 往上两级即文档库根**。⇒ 包内有引导块、库内没有,是**位置决定的**,不是漏改。
|
||||
- **2026-10-01 18:2x · 瘦身(本轮)**:`references/collab-detail.md` 删去**原件 YAML 变更流水**(约 9.4 KB)+ 加**读法索引**+ 压缩 §12;
|
||||
`references/{manifest,taskgraph,pitfalls}.md` 去掉过期条目与旧抬头;包内 `__pycache__/`、`hooks/bak-*/`、`tmp/` 已清。
|
||||
**⛔ 本轮无机制代码改动。**
|
||||
- **2026-10-01 16:5x**:`scripts/hooks/session-log-guard.py` 新增「**硬档就地回收**」—— 到 8 MiB 先试**一次**把本会话
|
||||
`logs/<日期>/sdk/conversations/<sid>.log` 改名(后缀 `.recycled-<时间戳>`,⛔ 不删、⛔ 不以 `.log` 结尾故与清扫器不重叠)
|
||||
⇒ 宿主立刻重建并继续写 ⇒ **会话不必再因撞 10 MiB 而停手**;失败则**逐字退回**原「停手+建接续」口径。
|
||||
开关 `DSH_SLG_NO_RECYCLE=1`(只关回收、保留叫停)。⚠️ 文档库原件 `07-scripts/session-log-guard.py` **已同语义同步**。
|
||||
- **2026-10-01 16:0x**:原 `multi-session-collab` 的 `SKILL.md` 全文并入 `references/collab-detail.md`(治 8 处悬空引用:
|
||||
`§0.05` `§0.5.2` `§0.5.4` `§0.5.5` `§1.3` `§1.4a` `§3` `§6`);清掉 9 处旧技能路径/名的活文本;
|
||||
两个原技能目录移入 `<工作区>/归档/技能-退役-20261001/`。
|
||||
|
||||
## 逐文件清单
|
||||
|
||||
| 包内路径 | 字节 | md5 | 语法检查 |
|
||||
|---|---|---|---|
|
||||
| `SKILL.md` | 52451 | `c304346227e3d2b217e442a471b6c10d` | ok |
|
||||
| `assets/board.html` | 136715 | `bf0e560a0420c833e94f329958e64a3c` | ok |
|
||||
| `assets/design-tokens.css` | 6364 | `0668feb3a4729f1022e579ac0c5d2569` | ok |
|
||||
| `install.py` | 26132 | `9522ec34773385a638efdeb3df0090d2` | ok |
|
||||
| `references/00-动手前必过.md` | 3923 | `33bc86e442ccd4fcbb930c79c4ad0641` | ok |
|
||||
| `references/02-功能优先协作协议.md` | 30502 | `eeeab3dcad47ad01380c8b05fee6fb3f` | ok |
|
||||
| `references/03-回复排版-核心块.md` | 2187 | `201e7f112ee432b89e38f82f49301966` | ok |
|
||||
| `references/99-速查清单.md` | 9832 | `17cc8717649164fa3b9e26da3be9405b` | ok |
|
||||
| `references/architecture.md` | 119291 | `c78f5cba060efc79db5d160f7df0cca6` | ok |
|
||||
| `references/collab-detail.md` | 98760 | `6bd9cc7e28596789d55dcd3da22548fe` | ok |
|
||||
| `references/collab.md` | 16560 | `e7024a823d14c5aa808c7be3a7b00eda` | ok |
|
||||
| `references/deploy.md` | 16754 | `66342ae0e32ecb499b4c72e4ccfabb9b` | ok |
|
||||
| `references/forensics.md` | 6067 | `1fb6deca9bb05bebe950d4f4e3adf043` | ok |
|
||||
| `references/pitfalls.md` | 132523 | `9bd6509df320833a41313848009aeb9a` | ok |
|
||||
| `references/rules.md` | 6931 | `d654e9dac68a6f44b93898ba98e49221` | ok |
|
||||
| `references/supervise-persistence.md` | 19245 | `1d4bbb08f02a661124886578cb700af5` | ok |
|
||||
| `references/taskgraph.md` | 3521 | `be6c6540be86475bb3430688c2987afc` | ok |
|
||||
| `roots.env` | 624 | `ec38f15f9a4101d69c815aa2cdd7b477` | ok |
|
||||
| `scripts/board.py` | 123843 | `339d38fd579c602c20ce59f4aa106408` | ok |
|
||||
| `scripts/board_ext.py` | 45655 | `f138d944145b276e65f6aa86bd8baa07` | ok |
|
||||
| `scripts/collabd.config.example.json` | 1158 | `6655c15c411a84e3ca12fd136dbe2c60` | ok |
|
||||
| `scripts/collabd.py` | 355568 | `58ffc3e52a52445e5b0e782fc99d9323` | ok |
|
||||
| `scripts/deliver-gateway-token.py` | 5685 | `cbba9648d404ecd2683061e19dbdb24a` | ok |
|
||||
| `scripts/deploy_code.py` | 4391 | `c22969124dd937ddaa66db09738df4a4` | ok |
|
||||
| `scripts/forensics/proc-parent.py` | 2347 | `8cdfff2dbb88303298752c3777da7b20` | ok |
|
||||
| `scripts/goalctl.py` | 39314 | `b3c4428b3aa7e4e3093e96105d1bc4dd` | ok |
|
||||
| `scripts/guard.py` | 13653 | `378e2a388aa14bc55f83e17b5ea61053` | ok |
|
||||
| `scripts/hooks/_env.py` | 11082 | `d3a557f22286bffb62ff29ee85c71799` | ok |
|
||||
| `scripts/hooks/bash-output-guard.py` | 17741 | `3f2fdfa17f66f7fcac42e06853433a26` | ok |
|
||||
| `scripts/hooks/lock-guard-hook.py` | 20363 | `641457de0297ee7a812ccde57f67dc2b` | ok |
|
||||
| `scripts/hooks/reply-style-guard.py` | 10779 | `a05ca0d6ebef2be55a3d6f96a4c712da` | ok |
|
||||
| `scripts/hooks/session-log-guard.py` | 24636 | `0bd6865e1a3ab97315c64631f37963a3` | ok |
|
||||
| `scripts/hooks/skill-load-guard.py` | 19380 | `682019c18af80991b14c3f3505ecab26` | ok |
|
||||
| `scripts/hooks/stop-dialog-guard.py` | 40247 | `4e5f9889717d4ed37a6384c643b4d05e` | ok |
|
||||
| `scripts/hooks/wb-result-hook.py` | 65810 | `94bc3c781b43be6c2a4da645fe008639` | ok |
|
||||
| `scripts/init_workspace.py` | 8840 | `0581b3864d35461f2fd8f76ea4c66d4d` | ok |
|
||||
| `scripts/lock/handoff-guard.sh` | 34616 | `f38b2ec92fdc1dab9abdaca0e0bb001a` | ok |
|
||||
| `scripts/lock/handoff-status.py` | 3923 | `3edb20f9c4021ebe2323478860bf8f6f` | ok |
|
||||
| `scripts/lock/op-lock.sh` | 4690 | `1a31eda3642e23693a65e1519860c744` | ok |
|
||||
| `scripts/lock/preflight-lock.sh` | 8673 | `e985ec1cb853fae4c351cd03b171355d` | ok |
|
||||
| `scripts/selftest.py` | 281959 | `f68dcb48173f2321527d54bc30703bc5` | ok |
|
||||
| `scripts/session-rules-check.py` | 28650 | `484b4e7370ff7f8377e725471bdfd88a` | ok |
|
||||
| `scripts/stop-collab.py` | 10462 | `d8043bedd23b52b6642aaf7ec8b8c980` | ok |
|
||||
| `scripts/wake-session.py` | 11011 | `32c6038b541249730f322f933ee287c1` | ok |
|
||||
# manifest · 包内文件清单
|
||||
|
||||
> 生成方式:逐文件 `compile()` / `json.loads` + md5 | **最近一次全量重算:2026-10-06 05:10 (补 P0-85(工作区解析静默错归属)+P0-84 已修尾注)**
|
||||
> ⚠️ **2026-10-05 局部增量**:`references/pitfalls.md`(P0-77 拆条 + P0-73/P0-77 压缩)与
|
||||
> `scripts/goalctl.py`(`--switch-goal` 确认闸 + 旧目标归档)两行的 md5/大小已按当天实测值更新;**其余行仍是 10-04 基线**。
|
||||
> ⛔ 本表**不含** `install.log`(运行日志)与 `references/manifest.md`(自引用,写完即失真)。
|
||||
> ⚠️ **provenance 列里的 `skills/multi-session-collab/…`、`skills/workbuddy-session-forensics/…` 已是历史路径**
|
||||
> —— 那两个目录 2026-10-01 已移到 `<工作区>/归档/技能-退役-20261001/`(⛔ 不在技能根了)。
|
||||
|
||||
文件总数:**56** | 语法 / 结构检查失败:**0**
|
||||
|
||||
## ✅ 已完成 · 2026-10-05 「目标唯一性 + 换目标需确认」(用户口径落地)
|
||||
|
||||
> 用户原话逐字:**「一个工作区 同时只能执行一个目标,如果要切换目标,需要用户确认,然后切换和关注检查切换后的目标」**
|
||||
|
||||
- **改前取证(三条,全实测)**:① 载体 `goal.json` **本就是单文件** ⇒ 天然满足"同时一个";② **归档零实现**
|
||||
(`goalctl.py`/`collabd.py` 全文搜 `goals/` **零命中** ⇒ 那份归档件是**手工造的**);③ **确认闸零实现**
|
||||
(`declare` **直接覆盖** `title`,无任何准入判断)。
|
||||
- **修法(两道闸,均在 `goalctl.py::declare()`)**:① 标题变了 ⇒ **默认拒绝**(`rc=3`、**零写入**),
|
||||
必须带专用开关 `--switch-goal`(⛔ **不等于** `--yes`:前者=「用户已同意换目标」,后者只是「干跑转真写」,
|
||||
**混用 = 伪造用户授权**);② 确认后旧目标**整份**归档到 `goals/<旧标题≤40字>__<时间>.json` + 新目标留 `_前身目标`。
|
||||
- **验收(7 项全过)**:拒绝 rc=3 /同目标细化 rc=0 **不被拦** /归档 **32 字段 / 6186 B** 且与旧目标**同源** /
|
||||
**变异对照**(闸短路 ⇒ rc=0,还原 ⇒ rc=3,证判据非恒绿)/真区未污染 /副本 md5 全同。
|
||||
- ⚠️ **加闸带出的连带缺陷(已一并修)**:`declare` 没给 `--title` 时**回落成工作区名** ⇒ 把"纯细化"误判成
|
||||
"换目标" ⇒ 修成「**没给 ⇒ 保持现有标题**」(与 `--topics`/`--kpi` 同规矩)。
|
||||
- 📂 全文 ⇒ `references/pitfalls.md` **P0-78**;`lifecycle` 那条独立铁律 ⇒ **P0-79**(**从 P0-77 拆出**)。
|
||||
|
||||
### 📌 同批完成:`pitfalls.md` 沉淀纪律转绿(改前既有红,顺手修掉)
|
||||
|
||||
- 判据=「**单条 > 6 KB 且证据密度 < 4.0 ⇒ 判流水账**」。改前基线读数:`P0-73` 7590 B/2.8。
|
||||
- 修法(**两条腿**,⛔ 不靠删内容):① **拆条** —— P0-77 里"前缀改造"与"`lifecycle` 空转"是**两个主题**,
|
||||
拆出 **P0-79**(P0-77 7765→5107 B/P0-79 2141 B);② **删冗余展开**(P0-73 验收段的重复读数)7795→约 5.9 KB。
|
||||
- 结果:**沉淀纪律 ✓ 转绿**(5 项);自测 **`PASS 94/FAIL 3` → `PASS 95/FAIL 2`**(另 1 条报告型不计入)。
|
||||
- ⚠️ ⛔ 别为压体量**删判据要点** —— 判据自带关键词对账(`MUST` 表),删了就换一种方式报红。❗原编号 77 → 79,**不许再当 77 引用**
|
||||
|
||||
## ✅ 已完成 · 2026-10-05 三代术语收敛(本节替代原「待办」)
|
||||
|
||||
- **已执行**:包内 + 两个工作区副本三方同步,md5 一致(`collabd.py`/`goalctl.py`/`board.py`/`board_ext.py`/
|
||||
`selftest.py`/`collabctl.py`/`guard.py`/`init_workspace.py`/`session-rules-check.py`/`board.html` 全部 OK)。
|
||||
`selftest.py` 基线 **PASS 97 / FAIL 0**(报告型 1 条不计入);改名的 5 条 `@case` 均能按新名字 `-k` 找到。
|
||||
- **⛔ 三类不动,是判据不是遗漏**(下一次改名前照抄):
|
||||
① **「」引述内容逐字不动**(含跨行引述块)—— 引用用户口径只写原话;
|
||||
② **历史段整段不动** —— `SKILL.md` 19–27 行代际表、含 `旧称/旧词/一代/二代/第三代` 的行、`<hN> 历史…` 段落
|
||||
(要讲清三代分别叫什么,就必须留着旧名);
|
||||
③ **`.py` 里 `目标检查` 一律不动** —— 它是**检查会话类别名**(`_CHECK_TAGS`/`_CHECK_TOPICS`、
|
||||
`[检查]-[结果检查/目标检查]`),并散在字面断言里(`CHECK_KINDS["queue-empty"][1] == "目标检查"`、
|
||||
`rows.append(...)`、`【目标检查】` prompt 头)⇒ 改了直接断判据。
|
||||
- ⚠️ **一处同改对**:`board.py::_ROLE_LABEL["worker"]` 与 `board.html` 的 `role==='…'` 是同一处判据的两侧。
|
||||
- ⚠️ **本条暴露的存量缺陷(已一并修)**:`selftest.py` 的期望串原写 `才建立一轮任务会话`,而 `SKILL.md`
|
||||
引述里逐字是 `才建立一轮执行会话` ⇒ 该子项**改前就是红的**(被基线里的 97/0 掩盖)。
|
||||
- 工具:`tmp/term-apply-v3-20261005.py`(dry-run/`--apply`,写盘前自动备份)+ `tmp/term-sync-20261005.py`。
|
||||
|
||||
|
||||
## 2026-10-04 新增文件(⛔ 由 manifest 重算登记)
|
||||
|
||||
- `references/01-文档索引.md` — 3604 B |md5 `825999a411e2a4f6b740063f81c01b03`
|
||||
- `scripts/judge_audit.py` — 13562 B |md5 `8f14a973fa5709a3b9a60b065dc22d7d`
|
||||
- `scripts/workspace_mirror.py` — 17263 B |md5 `60f104b37df3133785abb13f686eea4f`
|
||||
- `assets/start-supervise.ps1.tpl` — 5360 B |md5 `3805f1a82a1747269212287e9dfde369`
|
||||
- `assets/design-tokens.css` — 6364 B |md5 `0668feb3a4729f1022e579ac0c5d2569`
|
||||
|
||||
## 最近改动(⛔ 只记「什么时候改了什么」,不写流水账)
|
||||
|
||||
- **2026-10-02 07:0x · 开工第 0 步改名:会话「规划」→ 会话「规则机制」(本轮)**:
|
||||
① **用户纠正原话**:「**就应该是检查清楚 所有会话规则机制 是否配置完整且生效, 不是规划 是 规则**」
|
||||
⇒ 首版体检脚本**只查排期那一面**,当天实测出的三类失效(钩子注入指向已退役技能名 / 常驻快照写进幽灵目录 /
|
||||
每轮注入的记忆指针悬空)**一条都没覆盖** ⇒ 名字还叫「规划」=第二次「在册 ≠ 生效」。
|
||||
② **收敛成一个入口**:新增 `scripts/session-rules-check.py`(查 **三类十二项**:A 钩子在册·路径存在·
|
||||
注入技能名存在·闸门日志新鲜 | B 每轮注入记忆的技能指针·常驻快照不比权威旧 | C 周期钟·模型可用性·
|
||||
`cwds` 同形·投递心跳·活会话·`once` 从未运行的死排期);旧 `scripts/session-plan-check.py` **退役**
|
||||
到 `<WS>/归档/技能包-旧件-20261002/`,**能力不回退**。
|
||||
③ **状态标记改名**:`session-plan.json` → **`session-rules.json`**(旧的属过期件,⛔ 别拿来对照)。
|
||||
④ **判据收紧**:`cwds` 近失配原写成「同父目录 + 字面不同」⇒ 在 `AIProject/` 这种**多业务线平级目录**下
|
||||
把**别的线**报成失配(实跑当场 2 条假红)⇒ 改为「同父目录 + **名字去 `-`/`_` 后仍相同**」/「同名不同父目录」。
|
||||
⑤ **判据自验**:⑨⑫ 抽成**纯函数** + 合成样本夹具(`<WS>/tmp/rules-check-mutate.py`)—— 原版 10/0 绿、
|
||||
**四个变异体**逐一按预期报红。⚠️ 夹具**自己先红两次**(期望值写死:漏算样本 + 有序列表比中文名)。
|
||||
- **2026-10-01 18:5x · 外置根贯通 + 两处真缺陷(本轮)**:
|
||||
① `roots.env` 引导块从 9 份扩到 **16 份**(补齐 7 个非钩子脚本:`board` / `board_ext` / `collabd` /
|
||||
`deliver-gateway-token` / `goalctl` / `selftest` / `stop-collab`);
|
||||
② **盘符字面量清零**:配置目录兜底改 `~/.workbuddy`,工作区兜底改 `DSH_WS_ROOT`/cwd,
|
||||
覆盖网日志 glob 改 `DSH_OVERLAY_LOG_GLOB`(原为死路径 —— 本机 `E:/dsh-worker-dev` 不存在);
|
||||
③ 7 份加**输出编码兜底**;④ `roots.env` 增写 `CODEBUDDY_CONFIG_DIR`;
|
||||
⑤ 🔴 **修「钩子把技能包当工作区」**:`wb-result-hook.py` 的 `_WS_ROOT` 原按 `3×dirname(__file__)` 推,
|
||||
包内这份推出来=技能包自己 ⇒ 包里长出 `tmp/supervise-inbox/`;改为复用 `resolve_ws()`;
|
||||
⑥ 🔴 **修「重定向 + GBK ⇒ print 抛异常 ⇒ 顶层记 fatal、整轮失败」**(本机实测 4 次;
|
||||
这正是**常驻**跑不起来的拦路石 —— 常驻必须重定向 stdout);
|
||||
⑦ `install.py` 工作区模板路径纠错(原指 `scripts/collab/`,实际在 `scripts/`);
|
||||
⑧ `collabd.py` docstring + 两处活注释改**常驻定案**(上一轮漏传导);
|
||||
⑨ `lock/preflight-lock.sh` + `hooks/lock-guard-hook.py` 的盘符字面量清零;
|
||||
⑩ 新增 `install.py --manifest`(见下条);
|
||||
⑪ 🔴 **`scripts/selftest.py` 去掉最后一处项目绝对路径**:`t_tick_wired` 原先写死
|
||||
`<某工作区>/.workbuddy/tools/wb-result-hook.py` ⇒ 两处都不对:既违反「技能里只用相对路径」,
|
||||
又因宿主接线已改指**包内**那份而**恒走"文件不在,跳过"** ⇒ 看着绿、其实什么都没验(静默假绿)。
|
||||
现改按包内相对路径取 `hooks/wb-result-hook.py`,该用例从"跳过"变**真检**(4 项实跑通过)。
|
||||
- **2026-10-01 19:0x · `install.py --manifest`**:把「重算本表」固化成子命令
|
||||
(包一改表就过期 ⇒ 以前每轮临时手搓脚本、跑完即删,已因此误判两次)。
|
||||
只重写**表 + 计数行 + 重算时间**,⛔ 不碰上方散文;**行尾随原文件**(本表是 CRLF,写成 LF 会造成一次无声全文件 diff)。
|
||||
- **🔴 两份同源脚本「有意不一致」(⛔ 别当 bug 去修平)**:`preflight-lock.sh` 与 `lock-guard-hook.py` 在
|
||||
**技能包**与**文档库 `07-scripts/`** 各有一份。包内那份住在技能包里、**推不出文档库根** ⇒ 只能走
|
||||
`roots.env` +(`lock-guard-hook.py` 的)末位字面量兜底;库内那份住在 `<文档库>/07-scripts/` ⇒
|
||||
**按 `__file__` 往上两级即文档库根**。⇒ 包内有引导块、库内没有,是**位置决定的**,不是漏改。
|
||||
- **2026-10-01 18:2x · 瘦身(本轮)**:`references/collab-detail.md` 删去**原件 YAML 变更流水**(约 9.4 KB)+ 加**读法索引**+ 压缩 §12;
|
||||
`references/{manifest,taskgraph,pitfalls}.md` 去掉过期条目与旧抬头;包内 `__pycache__/`、`hooks/bak-*/`、`tmp/` 已清。
|
||||
**⛔ 本轮无机制代码改动。**
|
||||
- **2026-10-01 16:5x**:`scripts/hooks/session-log-guard.py` 新增「**硬档就地回收**」—— 到 8 MiB 先试**一次**把本会话
|
||||
`logs/<日期>/sdk/conversations/<sid>.log` 改名(后缀 `.recycled-<时间戳>`,⛔ 不删、⛔ 不以 `.log` 结尾故与清扫器不重叠)
|
||||
⇒ 宿主立刻重建并继续写 ⇒ **会话不必再因撞 10 MiB 而停手**;失败则**逐字退回**原「停手+建接续」口径。
|
||||
开关 `DSH_SLG_NO_RECYCLE=1`(只关回收、保留叫停)。⚠️ 文档库原件 `07-scripts/session-log-guard.py` **已同语义同步**。
|
||||
- **2026-10-01 16:0x**:原 `multi-session-collab` 的 `SKILL.md` 全文并入 `references/collab-detail.md`(治 8 处悬空引用:
|
||||
`§0.05` `§0.5.2` `§0.5.4` `§0.5.5` `§1.3` `§1.4a` `§3` `§6`);清掉 9 处旧技能路径/名的活文本;
|
||||
两个原技能目录移入 `<工作区>/归档/技能-退役-20261001/`。
|
||||
|
||||
## 逐文件清单
|
||||
|
||||
| 包内路径 | 字节 | md5 | 语法检查 |
|
||||
|---|---|---|---|
|
||||
| `SKILL.md` | 110832 | `25aefce4ad7402c216ad7784ebed7b92` | — |
|
||||
| `assets/board-launch.py.tpl` | 4355 | `7e9dfe1c4845f20dbb89f599d80e167b` | — |
|
||||
| `assets/board-render-probe.js` | 14398 | `a21bd1905b34537436ce778c6bfbc288` | — |
|
||||
| `assets/board.html` | 151811 | `c597cd7f21543542e9cdbe486c5ccd79` | — |
|
||||
| `assets/design-tokens.css` | 6364 | `0668feb3a4729f1022e579ac0c5d2569` | — |
|
||||
| `assets/start-supervise.ps1.tpl` | 5778 | `4eae189c7c850e4748a0a62024f48127` | — |
|
||||
| `install.py` | 33311 | `ee11283cbcdbb4f821f021e86cff4498` | ok |
|
||||
| `references/00-动手前必过.md` | 7181 | `33bc86e442ccd4fcbb930c79c4ad0641` | — |
|
||||
| `references/01-文档索引.md` | 3604 | `825999a411e2a4f6b740063f81c01b03` | — |
|
||||
| `references/02-功能优先协作协议.md` | 30502 | `e241742b41cb25ff7d1b6447b9ee623e` | — |
|
||||
| `references/03-回复排版-核心块.md` | 2187 | `201e7f112ee432b89e38f82f49301966` | — |
|
||||
| `references/99-速查清单.md` | 9832 | `5c97728af7cb67e9be9a3e491bdc5fd9` | — |
|
||||
| `references/architecture.md` | 119622 | `d7f0990daeb4cd7d2d262646f67b8ffd` | — |
|
||||
| `references/collab-detail.md` | 98760 | `7b843b0072d8da8abe0a162a44a96eb7` | — |
|
||||
| `references/collab.md` | 16560 | `97aa751f86d9b4ba8db401b5ec592695` | — |
|
||||
| `references/deploy.md` | 16754 | `4e382f7876f31754ec9629925340c2d8` | — |
|
||||
| `references/forensics.md` | 6067 | `1fb6deca9bb05bebe950d4f4e3adf043` | — |
|
||||
| `references/pitfalls.md` | 281757 | `8e3c654a8ea824da2a066726305accde` | — |
|
||||
| `references/rules.md` | 8106 | `95af3566066d27c3c224ce681a82efc1` | — |
|
||||
| `references/supervise-persistence.md` | 27698 | `2e7ba3d89146881eb9a7ec5d2ada891b` | — |
|
||||
| `references/taskgraph.md` | 3521 | `be6c6540be86475bb3430688c2987afc` | — |
|
||||
| `roots.env` | 624 | `ec38f15f9a4101d69c815aa2cdd7b477` | — |
|
||||
| `scripts/board-launch.py` | 2794 | `998a66b9d335ab1863b5b871a527bf4f` | ok |
|
||||
| `scripts/board.py` | 146111 | `d90395d1f1a7c3f94419a33cdf444384` | ok |
|
||||
| `scripts/board_ext.py` | 45655 | `2319fb9d2d21bf961e03a42da9a1ad4b` | ok |
|
||||
| `scripts/collabctl.py` | 28124 | `827fe07da25b86b773a3f701e86db351` | ok |
|
||||
| `scripts/collabd.config.example.json` | 1158 | `6655c15c411a84e3ca12fd136dbe2c60` | ok |
|
||||
| `scripts/collabd.py` | 431355 | `955bd92009d7cd0cccc53d867f591b49` | ok |
|
||||
| `scripts/deliver-gateway-token.py` | 5685 | `cbba9648d404ecd2683061e19dbdb24a` | ok |
|
||||
| `scripts/deploy_code.py` | 5325 | `a79cf5e5ffb3e8c60a31b4d0d8845f40` | ok |
|
||||
| `scripts/forensics/proc-parent.py` | 2347 | `8cdfff2dbb88303298752c3777da7b20` | ok |
|
||||
| `scripts/goalctl.py` | 47839 | `0e8b1d05003342a9ab474cfbfde5d704` | ok |
|
||||
| `scripts/guard.py` | 13653 | `43f4e279896090c6c6c3fcbdb4fa95d6` | ok |
|
||||
| `scripts/hooks/_env.py` | 17767 | `7177d04805c607fa155831340267c49b` | ok |
|
||||
| `scripts/hooks/bash-output-guard.py` | 17741 | `3f2fdfa17f66f7fcac42e06853433a26` | ok |
|
||||
| `scripts/hooks/lock-guard-hook.py` | 20363 | `641457de0297ee7a812ccde57f67dc2b` | ok |
|
||||
| `scripts/hooks/reply-style-guard.py` | 10779 | `a05ca0d6ebef2be55a3d6f96a4c712da` | ok |
|
||||
| `scripts/hooks/session-log-guard.py` | 24636 | `4dd13b24d541d1afc7b4874dba6bb1eb` | ok |
|
||||
| `scripts/hooks/skill-load-guard.py` | 24261 | `21c3a3f8732698ef3a6f1a5c61aae343` | ok |
|
||||
| `scripts/hooks/stop-dialog-guard.py` | 40247 | `4e5f9889717d4ed37a6384c643b4d05e` | ok |
|
||||
| `scripts/hooks/supervise-ensure-hook.py` | 14308 | `dc6f62584a8384baba0a1f2460828013` | ok |
|
||||
| `scripts/hooks/wb-result-hook.py` | 37199 | `2d4f694acd031222bf03b98a859b6e90` | ok |
|
||||
| `scripts/init_workspace.py` | 35817 | `c8b6bbbae01f21939ea2fd8d294d2726` | ok |
|
||||
| `scripts/judge_audit.py` | 13562 | `8f14a973fa5709a3b9a60b065dc22d7d` | ok |
|
||||
| `scripts/keepalive.py` | 12265 | `b84c753917e0a34cf40800bda953e7a4` | ok |
|
||||
| `scripts/lock/handoff-guard.sh` | 34616 | `f38b2ec92fdc1dab9abdaca0e0bb001a` | — |
|
||||
| `scripts/lock/handoff-status.py` | 3923 | `3edb20f9c4021ebe2323478860bf8f6f` | ok |
|
||||
| `scripts/lock/op-lock.sh` | 4690 | `1a31eda3642e23693a65e1519860c744` | — |
|
||||
| `scripts/lock/preflight-lock.sh` | 8673 | `e985ec1cb853fae4c351cd03b171355d` | — |
|
||||
| `scripts/mut_run.py` | 13323 | `3bffc12e1e57d5efc743bac55e584b62` | ok |
|
||||
| `scripts/selftest.py` | 469482 | `dc0f4801b2e4fa76e71f649b03f2ed50` | ok |
|
||||
| `scripts/session-rules-check.py` | 37640 | `552c90b93a051d775299170d5ff49b56` | ok |
|
||||
| `scripts/stop-collab.py` | 10462 | `d8043bedd23b52b6642aaf7ec8b8c980` | ok |
|
||||
| `scripts/supervise-launch.py` | 2503 | `f416a2f197e5524a8859c1d227ba1d05` | ok |
|
||||
| `scripts/wake-session.py` | 11011 | `32c6038b541249730f322f933ee287c1` | ok |
|
||||
| `scripts/workspace_mirror.py` | 17263 | `60f104b37df3133785abb13f686eea4f` | ok |
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user