2026-09-24 07:51:03 +08:00
|
|
|
|
# DSH 平台项目 — 项目指令(每次会话自动加载)
|
|
|
|
|
|
|
|
|
|
|
|
> **本文件只放两类东西**:① **动作前必须生效的规则**(不常驻就会出事)② **「什么时候去查什么」的指针**。
|
|
|
|
|
|
> 知识型内容一律**不在此复制** —— 按 §2 的触发条件**现查**。
|
|
|
|
|
|
|
|
|
|
|
|
### ⛔ 分层判定标准(防止把该常驻的东西做成指针)
|
|
|
|
|
|
|
|
|
|
|
|
> **这条内容如果不看,会不会导致「违规」或「事故」?**
|
|
|
|
|
|
> - **会 → 必须常驻实体内容**(写在本文件 / MEMORY.md 里,不许只给指针)
|
|
|
|
|
|
> - **只是"更慢、更绕" → 才可以只给指针**
|
|
|
|
|
|
|
|
|
|
|
|
**因此以下内容一律以实体形式常驻,任何"瘦身"都不得把它们降级为指针**:
|
|
|
|
|
|
§1 提问判据 · §3 红线 R1–R10(全表) · §4 提交边界 · §5 规划与执行分离 · §6 并发纪律 · §7 环境要点 · §8 会导致事故的实测事实。
|
|
|
|
|
|
**可以是指针的只有**:平台背景知识、UI 规范细节、档案模板、历史方案 —— 即"需要时才看、看了更准,不看也不违规"的那类。
|
|
|
|
|
|
|
|
|
|
|
|
> 加载顺序:用户级 `~/.codebuddy/CODEBUDDY.md` → 本文件 → `.codebuddy/rules/*.md`(条件规则)→ `D:\github\dsh_shenxian\dsh-server-docs\`(单一来源)。
|
|
|
|
|
|
> **改本文件需重启才会重载。**
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 1. 提问判据(唯一一条)
|
|
|
|
|
|
|
|
|
|
|
|
> **只问「超过现有判断方法边界」的问题。**(用户原话)
|
|
|
|
|
|
|
|
|
|
|
|
- **边界内 → 一律自决,不要问**:技术选型 / 实现路径 / 命名与数据结构 / 性能与资源调参 / 部署与同步 / 排查方法 / 版本与依赖 / 兼容与降级 / 方法内的方案取舍 / 文档与档案的技术内容。
|
|
|
|
|
|
- ⚠️ **「部署 / 上线」明确属于上面这一项**(2026-09-13 用户纠正原话:「为什么要等我确认才部署呢,**我看线上效果才知道是否满足需求**」):**不中断在线用户**的上线动作(`scp` 产物到 `/opt/dsh/artifacts` + `ensure-biz-plugins.cjs --all` 换包、静态页改动、候选池投放)**做完即上线,不要问** —— 用户要先看线上效果才能判断需求是否被满足。
|
|
|
|
|
|
- **⚠️ 2026-09-13 用户明令:「这个是开发环境服务器,不用担心中断用户」** ⇒ 上一条的「只有会中断在线用户的动作才走 R8 先知会」**改成**:重启 / 停实例 scope / drain / 改配额或 env / 改 nginx·nft **直接做**,只需**动手前一句话说明**在做什么(可回溯用)。**仍未放开**:不可逆的破坏性操作(删数据 / 迁 DB / 清目录)仍先出清单。
|
|
|
|
|
|
- **边界外 → 必须问**:① 业务目标与优先级(做不做、先做哪个)② 花钱与资源承诺 ③ 对外承诺(备案 / 资质 / 合同 —— ⚠️ 见下方"技术讨论里不谈法规")④ 需用户提供的账号凭据或审批 ⑤ 无客观优劣的体验偏好(审美 / 文案 / 默认值)⑥ 影响面超出本平台 ⑦ **红线门禁** ⑧ 方法确实判不准。
|
|
|
|
|
|
- 🔴 **技术讨论里不谈法规**(2026-09-19 用户明令 —— 起因:我在 relay/中继链讨论里反复引 237 号文并据此上抛。用户原话:「**后续禁止再提 237 号文件**」「**他妈老子是找你来普法的吗**」):
|
|
|
|
|
|
**⛔ 不引用法规条文当论据**(含条号、文号、判定"落入/不落入适用范围")|**⛔ 不主动提示合规风险**|**⛔ 不把合规写进技术方案的负面清单或验收判据**|**⛔ 不把"要不要做"的理由挂到合规上**。
|
|
|
|
|
|
✅ **只在两种情况下才谈**:① **你主动问起**;② 讨论对象本身就是"**对外承诺 / 资质 / 合同**"这类事。
|
|
|
|
|
|
⇒ 技术问题**只按技术判据答**(能力/成本/复杂度/可验证性/运维线);价值判断与后果由**你**决定。
|
|
|
|
|
|
📌 范围 = **本工作区全部线**(DSH 覆盖网络线 + 分布式数据链路线 + 后续新线)。⚠️ 与既有「**方案只做技术实现,合规不进方案**」是同一条,本条只是把它**扩到全部线并写成硬规则**。
|
|
|
|
|
|
- **判据**:这件事有没有**客观可判的优劣**?有 → 自己定;没有 → 问用户。
|
|
|
|
|
|
⚠️ **上抛门槛 = 存在「真取舍」**(2026-09-15 用户明令):「**需要我确认的方案需要说明优点和缺点,现在没法判断,假如只有优点或只有缺点那不需要我判断**」⇒ 把候选各写 **优点 + 缺点**:某个**只有优点**(明显更优)或**只有缺点** ⇒ **自己拍掉**;只有**各有优有劣、客观标准分不出高下**才上抛,且**必须逐项列出优点与缺点**。
|
|
|
|
|
|
- ⛔ **不许捆包**:要问红线就**只问那一句**(要不要现在动生产 / 影响谁 / 断多久 / 能否避开);技术方案自己定好、当**已定项**陈述("我按 X 做…已定,可推翻")。**一轮最多一个问题,同类不连问两次。**
|
|
|
|
|
|
- ✅ **回话前自检(发出任何回复前过一遍 · 2026-09-15 加)** —— 起因:**「提问闸门」hook 只能拦 `AskUserQuestion` 工具,而真实的上抛大多发生在正文里**。
|
|
|
|
|
|
**实证**:本工作区日志 `tool=AskUserQuestion` 调用数 = **09-12: 43 / 09-13: 3 / 09-14: 0 / 09-15: 0**(09-14 起该工具基本不用)⇒ **hook 那条路径几乎不被走到 ⇒ 拦不到正文里的征询**。
|
|
|
|
|
|
⛔ **禁止用征询句收尾**:出现「**要我…吗 / 是否要我 / 需要我…吗 / 要不要我 / 请确认 / 你看怎么办**」时,**先按上一条判据重判三问**:
|
|
|
|
|
|
① 命中**真门禁**吗(不可逆破坏性操作 / 边界外六类)?**没命中 → 删掉这句,自己做完,改成陈述句**("我接着做 X");
|
|
|
|
|
|
② 我是不是在**把已经定下来的事再问一遍**?是 → 删;
|
|
|
|
|
|
③ 我要问的这件事,**候选之间是「真取舍」吗**(各有优有劣、客观标准分不出高下)?—— 若某个**只有优点 / 只有缺点** ⇒ **自己拍掉**;是真取舍 → 才允许问,且**一轮只问这一句**、**逐项写出优点与缺点**。
|
|
|
|
|
|
📌 需要用户拍板时:**位置 = 整条回复的最后一节**(⛔ 不许埋在中间)、**按有序段落逐条编号**、**每个候选必须写「优点 / 缺点」两栏**、**候选竖排成段**(A / B / C **各占一行**,⛔ 不横排、⛔ 不做成表格的列)(2026-09-15 用户明令:「**能根据决策方法 自行决策的就自决策继续处理,不能决策的问题和需确认内容放在回复的最后,按照有序段落展示**」+「**需要我确认的方案需要说明优点和缺点,现在没法判断,假如只有优点或只有缺点那不需要我判断**」+「**每个需要我决策的问题的潜在解决方案 A B C 也按照段落式排版,别横着排列**」);**形态 = 陈述句**(问题 + 各候选优缺点 + 我的倾向),⛔ **不是**甩征询句("要不要我继续" / "说一声即可")。
|
|
|
|
|
|
- 📐 **排版按 `dsh-feature-first §5.4`**(可扫读九条 + 形态骨架 + 十三条反模式):**首屏 3 行给判定 · 层级 ≤3 · 每节 ≤7 行 · 加粗只留关键词 · 表格 ≤5 列 · 一条信息只说一次**;**待你拍板项落在最后一节、逐条编号、每个候选带「优点 / 缺点」且竖排成段(不横排、不做成表格的列)**;执行信息 / 报障 / 提问**各有现成骨架,不新造**;细节进「技术附录」,正文只留"能决定下一步"的信息。
|
|
|
|
|
|
- 🎯 **要的是解决问题,不是将就妥协**(2026-09-15 用户明令):面对风险/缺陷**默认目标是解决**;**降级目标 / 延期 / 静默兜底**三种**都不算解决**。只有**客观不可逾越**(技术不可行 / 上游未支持 / 需你提供凭据或窗口)才允许"暂时接受",且必须写明 ① 卡在哪(证据)② 已做到哪一步 ③ **什么条件一出现必须回头解决**。⚠️ 与 §2「最小代价路径」不矛盾:**目标不打折,路径取最小代价**(细节:素材库 **U27 / U26 / A6**)。
|
|
|
|
|
|
- 🟢 **只做正向迭代**(2026-09-15 用户明令,红线 **R11**):任何改动**只要让项目在某一维度净变差**(目标/方向/架构/功能/性能/安全/交互/UI/便利性/扩展性)⇒ **立即停下复盘**;**拿不出正向做法 ⇒ 立即停止、禁止继续执行**(细节:素材库 **U28**)。
|
|
|
|
|
|
- 🔀 **规则冲突裁决顺序**(2026-09-16 加 —— 起因:会话 `ddea70b7`「确认guest用户数据迁移」在"106 旧控制面要不要停"上停下来问用户,用户随后**两次**(U5 / U7)自行要求"删除";复盘见 `.workbuddy/memory/2026-09-16.md`):
|
|
|
|
|
|
**同一对象被 §1 / §2 指针 / §3 红线给出相反结论时**,按下序取**首个命中项**,⛔ 不再"自行取保守侧":
|
|
|
|
|
|
① **R8**(开发环境服务器 ⇒ 该动就动,只需动手前一句话说明)→ ② **§1 边界内自决清单**(部署 / 重启 / 改配置 / nginx·nft / drain / 技术选型)→ ③ **§3 其余红线**(R5 权限扩大 / R7 批量写入 / R9 锁 / R10 uid —— 这几条**永远是硬约束**,不参与裁决)。
|
|
|
|
|
|
⛔ **冲突 ≠ 门禁**:两条规则打架**不构成**上抛理由;门禁**只有 §1 列的"真门禁"两类**(不可逆破坏性操作 / 边界外六类)。
|
|
|
|
|
|
🔑 **"平台级" ≠ "别人的"**(本次误判的根源):**我们自己的 47 / 106 / 本工作区**上的 `dshs*`·`dsh-*` 单元、`/var/lib/dshs/**`、nginx·nft、端口 —— 都是**本平台自己的资源** ⇒ 按 §1 第 27 行 + R8 **直接做**;R7-边界② 说的"只报告不动手"**只针对"别人的 / 归属不明"的对象**。
|
|
|
|
|
|
⛔ **禁止把"我有倾向"降级成"建议 + 待你拍板"**:候选能排出优劣 ⇒ **直接做完**并写一句「我选了什么(可推翻)」。
|
|
|
|
|
|
📌 **上抛前必答三问**(任一条足以自决,缺一不可全答"否"才允许上抛):① 对象是**我们自己的平台资源**吗?→ 是 ⇒ 自决;② 我**查证过**关键不确定点了吗(如"还有谁在用")?→ 没查 ⇒ 先查,不许把"不确定"当上抛理由;③ 候选排完序,**第一名是否明显更优**?→ 是 ⇒ 自决。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2. 「什么时候去查什么」—— 动作触发的指针(**不要凭记忆答,先查**)
|
|
|
|
|
|
|
|
|
|
|
|
| 当你准备… | 去查 |
|
|
|
|
|
|
|---|---|
|
2026-09-24 08:25:34 +08:00
|
|
|
|
| **想知道"当前什么状态"(锁 / git 基线 / 待办 / 上次收口点)** | **先跑这一条**:`"E:/ProgramData/.workbuddy/binaries/python/versions/3.13.12/python.exe" "E:/ProgramData/AIProject/aliyun-dsh-server/state.py"`(约 30 行输出;`--online` 追加远端基线比对)。**它 1 次调用顶你十几轮探索** ⇒ ⛔ 跑完它之前**不许** Glob/Grep 全库摸底 |
|
2026-09-24 07:51:03 +08:00
|
|
|
|
| 回答"现在是什么状态 / 该读哪篇" | `D:\github\dsh_shenxian\dsh-server-docs\BRIEF.md`(现行事实,30 秒读完);**覆盖网络线**另有唯一入口 = 工作区根 `接续入口_覆盖网络线_20260916.md` |
|
|
|
|
|
|
| **改任何文件之前(第一步,不是"检查"是"抢")** | **先抢全局执行锁**:`bash D:\github\dsh_shenxian\dsh-server-docs\07-scripts/handoff-guard.sh --claim-exec "<你的会话名>"` —— **抢到之前不要动任何文件**;**抢不到 = 有会话在跑 = 停手**。抢到后再跑一次信息模式,看占用与越界改动 |
|
|
|
|
|
|
| 写 / 改前端页面(`web/*.html`、`.css`、client bundle) | `D:\github\dsh_shenxian\dsh-server-docs\01-规范\06-工作台UI规范.md`(**强制基线**;冲突时以其**实测 Token** 为准) |
|
|
|
|
|
|
| **改完 UI(尤其 client bundle)怎么验收 / 为什么"看不到变化"** | **`规范/06-工作台UI规范.md §7`**(生效链路四关 + 三段式验收 + 四个误判)。要点:client bundle 在**实例启动时**加载 ⇒ **改完必须重启实例**;浏览器侧由 dsh 的 `rev`(内容 hash)+ 平台代理层 `Cache-Control: no-cache` 保证自动更新 |
|
|
|
|
|
|
| **"我做完了吗"怎么判(本机改完 ≠ 交付)**(2026-09-15 加 —— 同类已 3 次) | 收尾前逐层走完**生效链路**并在**用户可见面**复验:静态页 → `scp`(⚠️ CDN/CF 缓存坑)|平台 TS → `build` + `systemctl restart dshs`|自研插件 → tgz → 候选池 → 实例启用 → **重启实例**|文档库/技能 → scp + 对账。⛔ **「本机改完了 / build 通过了 / 本地打包完成 / 已 commit」四条都不算交付**(清单:`dsh-change-workflow` **阶段 5 §0 交付门禁**;判据:素材库 **A25**)。⚠️ 但**别回头问"要不要部署"** —— 部署属我 lane 内执行细节(§3 R7-边界 + U20/X9),**直接做** |
|
|
|
|
|
|
| 新建改造档案 | `D:\github\dsh_shenxian\dsh-server-docs\05-交接单/README.md §二`(8 段模板)+ **先原子占号**(`mkdir <目录>/.lock-<NN>`) |
|
|
|
|
|
|
| 判断"某功能当时怎么改的" | `D:\github\dsh_shenxian\dsh-server-docs\调整方案/<NN>-<主题>.md`(先读**头部** TL;DR / 状态,再决定是否读全文) |
|
|
|
|
|
|
| 部署 / 构建 / 回滚 / 依赖版本 | `D:\github\dsh_shenxian\dsh-server-docs\DEPLOY-本部署.md` |
|
|
|
|
|
|
| 查待办 | 未规划 → `D:\github\dsh_shenxian\dsh-server-docs\01-规范\03-路线图与待办.md §二`;已规划待执行 → `D:\github\dsh_shenxian\dsh-server-docs\05-交接单/README.md §一` |
|
|
|
|
|
|
| **要动生产**(重启 `dshs` / drain scope / 铺插件 / 改实例 env 或配额 / 停别人留下的单元) | ⚠️ **2026-09-16 收口:与 §1 第 27 行 + R8 对齐 —— 直接做,动手前一句话说明在动什么即可,⛔ 不再"取得确认"**(旧表述"先按 R8 说清并取得确认"曾与 R8 本身矛盾,是会话 `ddea70b7` 上抛的诱因之一)。**只有"破坏性且不可逆"(删数据 / 迁 DB / 清目录)才先出清单** |
|
|
|
|
|
|
| **投放任何业务功能插件(第三方 / 自研)** | **只有一种方式:admin 在门户导入候选池 → 用户在实例「功能管理」里自助启用/禁用**(**不铺 profile**)。机制 / 边界 / 回滚见档案 16 / 36 / 65(**§8 有硬性说明**) |
|
|
|
|
|
|
| **推送到服务器之前** | `bash scripts/docs-sync-check.sh`(对账)+ `MINE="<我的文件>" PUSH=1 bash "D:\github\dsh_shenxian\dsh-server-docs\07-scripts\handoff-guard.sh"`(**幽灵文件硬判定**) |
|
|
|
|
|
|
| 做功能需求 / 方案决策 | 加载技能 `dsh-feature-first`(**谁定什么**)+ `dsh-decision-method`(**怎么定得对**,含 §4.4 技术实现裁决顺序)。⚠️ **用户点名「决策方法」/「参考决策方法」/「按决策方法」⇒ 必须立即 `Skill(dsh-decision-method)`,⛔ 不得凭记忆代替、不得只靠本文件 §1 判据**(2026-09-16 实证:会话 `ddea70b7` 用户 U6 明确点名后,AI 全程 `Skill` 调用 **0 次**,仍按旧判据上抛 → 复用本条) |
|
|
|
|
|
|
| **用户问「是否已实现 / 能不能 / 为什么不行」**(2026-09-13 用户要求) | 用 `dsh-feature-first **§5.1 结论骨架**`:**判定 → 为什么不行 → 需你拍板(真需要才写)→ 我接着做(陈述句)**。三条铁律见 §5.3:**主位是用户问的那件事**(AI 的进度/失误/计划不得占前两节)· **结论层零技术标识** · **禁征询式收尾**(已定的下一步直接做) |
|
|
|
|
|
|
| 落地一次改造 | 加载技能 `dsh-change-workflow`(六阶段 + 档案模板 + 并行调度) |
|
|
|
|
|
|
| **登记接续棒 / 排下一棒**(收尾四件套第 ② 件) | 技能 `dsh-auto-handoff-chain` **§3.1.1 排期两条铁律**:① **首个(唯一)接续棒 = 收口 + 5~8 分钟**(⛔ 不是"棒与棒之间")② **每条线同一时刻只挂一个**(下一棒由当棒收官时再排,⛔ 不预登记队列)。⚠️ 两条都已踩过(2026-09-18 用户当场纠正两次) |
|
|
|
|
|
|
| 复盘"用户到底怎么决策的" | `bash scripts/extract-user-voice.py`(抽全部历史会话的用户原话) |
|
|
|
|
|
|
| 判断"服务器文件是否等于我的改前基线" | `git hash-object`(**比 md5 可靠**,不受 CRLF/编码影响) |
|
|
|
|
|
|
|
|
|
|
|
|
> ⚠️ **技能的加载由模型判断相关性,不能保证**。所以:**凡"动作前必须生效"的规则,必须写在本文件里(§1/§3/§4/§5/§6);技能只承载"需要时去拿的方法论"。**
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 3. 红线 R1–R11(任一条命中 → **先停手**;效率论证不构成豁免)
|
|
|
|
|
|
|
|
|
|
|
|
| # | 红线 | 要点 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| **R1** | 不自动升级 dsh | 升级须走独立"测试 → 评估 → 修复"流程 |
|
|
|
|
|
|
| **R2** | 不改官方 dsh 主程序与缓存 | `@deepseek-ai/dsh` **零改动**;扩展只走 profile 层官方插件机制 |
|
|
|
|
|
|
| **R3** | client bundle 禁 `exports.default` | 只导出 `apply` + `inject` |
|
|
|
|
|
|
| **R4** | 不用真实账号测登录 | 用临时 session(`mksess.cjs` 直插),用完即删 |
|
|
|
|
|
|
| **R5** | **权限只准收窄** | 凡**扩大**(新挂载 / 放开遮蔽 / 暴露平台目录或 env / 放宽 nft / 提档位)→ 先出「权限影响评估」并取得确认 |
|
|
|
|
|
|
| **R6** | 先查已有资产再动手 | 可用技能 → 本机 / 项目已有技能与记忆 → "本机已有的能否满足" |
|
|
|
|
|
|
| **R7** | **禁未经确认的批量 / 全仓写入** | **只做被明确要求的事**;额外发现的问题**先报告、后动手**;禁全库遍历改写 / 通配符重写 / 批量 `chmod`·`chown` / **批量换行符转换** / `cp -r` 整目录覆盖 / `git add -A`;**可能影响 >10 文件 → 先出清单 + 确认**;先单点验证;**本机不是沙箱**(会经 scp 传导到生产) |
|
|
|
|
|
|
| **R7-边界** | **R7 只适用于「不是我的 lane」—— 两个方向都别套错**(2026-09-13 用户两处明令) | ① **不适用于「我 lane 内的执行细节」**:部署 / 上线(换包、传产物、改静态页、候选池投放)、重启服务、改配置、跑自己的脚本、改自己的插件源码与产物 ⇒ **别拿 R7 当挡箭牌去问,直接做**,事后一句「我选了什么(可推翻)」(原话:「为什么要等我确认才部署呢」)。② **适用于「平台级 / 全局 / 别人 lane」**:`/var/lib/**`、全局符号链接、systemd 单元、nginx·nft、别人的 profile / 产物 ⇒ **一律只报告、不动手**,**哪怕改它能让自己流程跑通**(原话:「谁让你去改这个的」+「不是自己负责的任务相关文件不要去改」)。<br>⚠️ **2026-09-16 收口(消除与 §1 第 27 行 / R8 的直接冲突):② 的适用对象 =「别人的 / 归属不明」的对象,⛔ 不含「我们自己的 47 / 106 / 本工作区」的资源** —— **本平台自己的** `dshs*`·`dsh-*` systemd 单元、`/var/lib/dshs/**`、nginx·nft、端口 **按 §1 + R8 直接做**(用户 2026-09-15/16 两次要求"删除 106 旧控制面"即为此)。原表述把"平台级 / 全局"与"别人 lane"并列,导致会话 `ddea70b7` 把**自己的 106 节点**读成"别人的东西"⇒ 只报告不动手 ⇒ 上抛。**判据看"归属",不看"是不是平台组件"** |
|
|
|
|
|
|
| **R8** | **中断在线用户的生产变更须先知会** | ⚠️ **2026-09-13 用户明令修正:服务器 `47.77.182.89` 是「开发环境服务器」,不用担心中断用户** —— 重启 `dshs` / 停实例 scope / drain / 改实例配额或 env / 改 nginx·nft **均可直接做**,不必再等确认。仅保留两条最低自律:① **动手前一句话说明**在重启/停了什么(便于出问题回溯)② **破坏性且不可逆**的动作(删数据 / 迁 DB / 清目录)仍先报清单。 |
|
|
|
|
|
|
| **R9** | **⛔⛔ 绝对禁止「人工删锁 / 接管」**(用户 2026-09-12 明令:"严格禁止这类操作") | **AI 一律不得**:`rm -rf 交接单/.exec-lock`、删 `交接单/.doing-*`、或以「持有者疑似已死 / 卡住 / 太久没动 / 只在只读分析没产出」为由**单方面接管**。锁**只能由持有者自己释放**(`--release-exec` / `--release`);**`handoff-guard.sh` 输出里的「或确认接管后人工删锁」不构成授权**。抢不到锁时 AI 的**唯一**合规动作 = **停手 + 报告用户** —— **锁的处置权只属于用户本人**(要删也只能用户自己动手)。**理由**:删锁 = 在**无法验证**对方死活的前提下单方面撤销互斥(**无心跳机制,AI 没有任何判据**)→ 一旦对方仍在跑,就**退回「两个会话同时改同一批文件」**,而这正是这把锁存在的理由。 |
|
|
|
|
|
|
| **R10** | **⛔ 绝不以 root(或非该实例 uid)运行 / 触碰用户实例的东西** | **实证(2026-09-14 事故)**:为量内存**用 root 手动起 admin 的 profile** ⇒ 它以 root 写入 `home/storages/workspace.json`(0.1.5 新增的 `@deepseek-ai/dsh-workspace` 状态文件)与 `home/.dsh/mcn-plugin.db` ⇒ **属主变 root** ⇒ 实例进程(uid 114801)`EACCES` ⇒ `plugin tree failed to load` ⇒ **exitCode 1 崩溃循环 ⇒ 页面 404**。**规则**:① 对用户实例的**一切验证 / 冒烟 / 探针必须以该 uid 运行**(`setpriv --reuid <uid> --regid <uid> --clear-groups`)或**照平台姿势进 bwrap 沙箱**;⛔ **禁止 root 直跑 `dsh --profile`**。② 确需临时以 root 跑(读全局配置等)⇒ **收尾必须** `find <home> -user root` 列出 + `-exec chown <uid>:<uid> {} +` 修正。③ 实例「起不来」排查**先看属主 / EACCES**,**不要先怀疑 OOM**(本次先后误判为 OOM,绕了 20 分钟)。**修复手法(实测 1 步恢复)**:`find <home> -user root -exec chown <uid>:<uid> {} +` → 重启平台 → 页面 200。 |
|
|
|
|
|
|
| **R11** | **⛔ 只做正向迭代:命中「劣化风险」→ 立即停下复盘;确实无正向做法 → 立即停止,禁止继续执行**(2026-09-15 用户明令) | **判据(每次决策前过一遍十维)**:这个改动是否让项目**任一维度净变差** —— **目标 / 方向 / 架构 / 功能 / 性能 / 安全 / 交互 / UI / 便利性 / 扩展性**?<br>**命中 ⇒ 立即停下复盘**(不许"先做着看"、不许将就):① 写清**劣化在哪一维、代价多大**(证据 / 量级)② 找出**能保住正向收益的做法**(改小范围 / 换实现 / 分阶段)③ **拿不出正向做法 ⇒ 立即停止、不再执行,只报告**。<br>⛔ **三种伪装禁止**:把劣化说成"必要代价"/用"后续再优化"掩盖已知劣化/把劣化项藏进交付不写。<br>与 **R5**(权限只准收窄)互补 —— R5 管**权限**,R11 管**全维度净收益**;与 **U27**(不将就妥协)同源。 |
|
|
|
|
|
|
|
2026-09-24 07:58:57 +08:00
|
|
|
|
## 9. 工作区卫生(2026-09-24 立)
|
|
|
|
|
|
|
|
|
|
|
|
> 起因:工作区 470 MB 中 411 MB 是过程产物(`tmp/` 1504 件、`待清理/` 1084 件、6 份 33.7 M 的 DB 副本)。
|
|
|
|
|
|
|
|
|
|
|
|
- 🔴 **收口必清本棒 tmp** —— 「收尾四件套」加第 ⑤ 件:本棒在 `tmp/` 下的过程目录,收口时自清(或确认无残留)。
|
|
|
|
|
|
- 🔴 **`tmp/` 保留期 = 7 天** —— 超期目录进 `归档/tmp-<日期>/`;可跑 `state.py --gc` 自动判定。
|
|
|
|
|
|
- 🔴 **不新建「待清理」类中间态目录** —— 二值决策:**归档**(要留)or **删除**(不留)。中间态 = 拖延。
|
|
|
|
|
|
- 🔴 **工作区已纳入 git**(`dsh_shenxian_workspace`)⇒ **入库只放文档与文件**:运行态、缓存、`*.db*`、`*.tar.gz`、过程目录一律 `.gitignore`。
|
|
|
|
|
|
- 🔴 **工作区不保留脚本副本** —— 一律**绝对路径**调文档库 `07-scripts/<name>`(`scripts/` 已撤,2026-09-24)。
|
|
|
|
|
|
- 🔴 **交界单正文落文档库** `05-交接单/`,工作区只放**指针**。
|
|
|
|
|
|
- ⚠️ **>60 KB 的单文件**:提交前须逐个判「是否文档 / 是否该提交」(2026-09-24 用户令)。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-09-24 07:51:03 +08:00
|
|
|
|
## 4. 提交边界
|
|
|
|
|
|
|
|
|
|
|
|
**未明确要求 → 不 commit / 不 push / 不同步仓库。** 用户说"提交 / 推送 / 同步"时才做,且**只 add 自己改的文件**。
|
|
|
|
|
|
|
|
|
|
|
|
**⛔ 三类内容禁止入库(2026-09-21 用户明令:「tmp 交接单 中间产物 禁止提交」)**
|
|
|
|
|
|
|
|
|
|
|
|
| 类别 | 涵盖 | `.gitignore` 兜法 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| **tmp** | `tmp/`(临时目录) | `/tmp/` |
|
|
|
|
|
|
| **中间产物** | `_tmp_seq*/`、`_中间产物_待清理/` 等 | `/_tmp*/`、`/_中间产物*/` |
|
|
|
|
|
|
| **交接单** | `dsh-server-docs/05-交接单/` 下的会话交接单 | `dsh-server-docs/05-交接单/` |
|
|
|
|
|
|
|
|
|
|
|
|
- 🔴 **不要用 `git status` 判"交接单要不要提交"** —— 被 ignore 之后它们**根本不会出现**在 status 里;
|
|
|
|
|
|
这是本条禁令的**预期行为**,不是"没生成"。确需入库只能显式 `git add -f`,且**先说明理由**。
|
|
|
|
|
|
- ✅ **落点与入库解耦**:交接单**照旧写到 `dsh-server-docs/05-交接单/`**(§5 的 8 段模板不变,全平台仍在同一路径找得到),
|
|
|
|
|
|
只是**不进 Git**、以本地未跟踪文件形态保留。中间产物则**一律留在 `tmp/` 内**,不要散到仓根。
|
|
|
|
|
|
- ⚠️ 仓内**已被跟踪**的 `dsh-server-docs/05-交接单/README.md`、`archive/**` **不受影响**(gitignore 不改已跟踪文件),仍可正常更新与提交。
|
|
|
|
|
|
- 🔴 **提交前自查**:`git diff --cached --name-only` 里出现以上三类 ⇒ **立即 `git reset` 撤出**,不要提交。
|
|
|
|
|
|
|
|
|
|
|
|
## 5. 规划与执行分离
|
|
|
|
|
|
|
|
|
|
|
|
规划会话**只产出交接单**(`D:\github\dsh_shenxian\dsh-server-docs\05-交接单/`,8 段必填:目标 / 只读前置 / 范围 / 决策点 / 步骤 / 验收 / 回滚 / 回报格式),**不 ssh、不改码、不重启、不 scp**;落地交另一个执行会话(**不读规划会话的上下文**)。
|
|
|
|
|
|
|
|
|
|
|
|
## 6. 并发纪律(本库多会话并行是常态)
|
|
|
|
|
|
|
|
|
|
|
|
- 共享文件**只用 Edit 做精确片段替换**(失败 = 天然冲突检测),**禁整文件 Write 覆盖**。
|
|
|
|
|
|
- **并行度按「冲突域是否重叠」定**(**2026-09-22 起,域锁取代"全局只放一个"**):域不重叠 ⇒ **可以真并行**;域重叠 ⇒ 串行。
|
|
|
|
|
|
⚠️ **底层框架 / 组件 / 机制层(`config`·`crypto`·`isolation`·`index`·`scripts`·`CODEBUDDY.md`·锁与钩子本身)仍然必须独占** —— 这类改动会打穿所有模块,不参与域并行。
|
|
|
|
|
|
- **🔒 开工门禁(2026-09-22 用户令:「会话执行任务前先判断,当前任务涉及范围是否都可锁定,确认锁定后开始处理」)**:
|
|
|
|
|
|
动手前**先判定本次任务涉及的文件是否都能锁定**,再抢锁开工。判定命令:
|
|
|
|
|
|
```bash
|
|
|
|
|
|
bash D:\github\dsh_shenxian\dsh-server-docs\07-scripts\preflight-lock.sh "<会话名>" <目标文件...>
|
|
|
|
|
|
```
|
|
|
|
|
|
输出【A】可独立锁定 /【B】秒级独占 /【E】机制层(须全局独占)/【C】共享资源 /【D】未归类。
|
|
|
|
|
|
⛔ **【D】或【E】非空 ⇒ 脚本 `rc=1` 拒开工**(2026-09-22 实测确认:**【E】也拒**,不是"提示可继续"):【D】= 有文件不在判据管辖内,先归类再动;【E】= 任务是机制层,**全平台共用 ⇒ 不得与其他会话并行**,仅当确认无其他会话在跑时才允许独占开工。
|
|
|
|
|
|
- **三把锁,顺序固定**(本平台多会话并行的唯一防线):
|
|
|
|
|
|
| 序 | 锁 | 命令 | 管什么 |
|
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
| ① | **域锁**(默认) | `bash …/handoff-guard.sh --claim-exec "<会话名>" --domains <域...>` | **声明我占哪些资源**;域不重叠即可并行 |
|
|
|
|
|
|
| ①' | 全局执行锁(旧行为,兜底) | `bash …/handoff-guard.sh --claim-exec "<会话名>"`(**不带 `--domains`**) | 无法声明域时退化为**独占**;机制层改动必须走这条 |
|
|
|
|
|
|
| ② | 单级占用锁(细) | `bash …/handoff-guard.sh --claim <单号> "<会话名>"` | 这个单归谁做(供台账与占用声明) |
|
|
|
|
|
|
| ③ | 服务器侧操作锁 | `bash scripts/op-lock.sh claim <操作名> "<影响面:谁会被断、断多久>"` | 谁正在动**生产**(重启 / drain / 改 env·配额 / 铺插件 / 改 nginx·nft) |
|
|
|
|
|
|
**域键格式** = `<锚点段>/<下一段>`(如 `src/im`、`dsh-server-docs/scripts`);多个域用**逗号**一次给:
|
|
|
|
|
|
```bash
|
|
|
|
|
|
--claim-exec "B线-IM开发" --domains "src/im,src/net"
|
|
|
|
|
|
```
|
|
|
|
|
|
🔴 **域键判据在 shell 与钩子两侧必须逐字一致**(锚点表见 `handoff-guard.sh` 的 `_ANCHOR_SEGS` 与 `lock-guard-hook.py` 的 `_DOMAIN_SEGS`)—— ⛔ 改一侧必须同步改另一侧,否则**域锁静默失效(假绿)**。
|
|
|
|
|
|
📋 查当前全部锁:`bash …/handoff-guard.sh --locks`。
|
|
|
|
|
|
**完工反序释放**:先 `--release <单>` / `op-lock.sh release`,最后 `--release-exec`。
|
|
|
|
|
|
- **秒级独占(`--claim-skeleton` / `--claim-publish`)**:动机制层 / 领取迁移号 / 挂载点等**极短操作**,不必全程持全局锁 —— 抢一把**秒级**锁、做完立刻放。
|
|
|
|
|
|
| 锁 | 命令 | 用途 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| 骨架锁 | `--claim-skeleton <资源名>` / `--release-skeleton` | 改机制层文件、领迁移号、改挂载点(**秒级**) |
|
|
|
|
|
|
| 发布锁 | `--claim-publish` / `--release-publish` | `commit` / `push` / `scp` / `build` 这类**全局串行**动作(**秒级**) |
|
|
|
|
|
|
- 🔍 **抢锁必须"校验结果",不能"看输出"**(2026-09-15 实证事故):把 `handoff-guard.sh --claim-exec` 的输出**用管道截尾**(`| grep` / `| tail`)时,**失败提示里也含关键词**(如"…必须 `--release-exec` 才算完成")⇒ `grep -q` 会**假命中** ⇒ 于是"以为抢到了"而**在无锁状态下改库**。
|
|
|
|
|
|
✅ **正确判据(二选一,缺一不可)**:① **检查退出码**(`if bash "D:\github\dsh_shenxian\dsh-server-docs\07-scripts\handoff-guard.sh" --claim-exec "X"; then … ; fi`,不要接管道);② **复读 `交接单/.locks/<会话名>/DOMAINS`**(域锁)或 `交接单/.exec-lock/OWNER`(全局锁)**并断言是自己的**。
|
|
|
|
|
|
⚠️ **`rc=1` 的两种成因要分清**:域冲突(要停手)vs `.gate` 临界区占用(重试即可)—— 看报错正文,⛔ 不要一律当"已完成"。
|
|
|
|
|
|
⛔ 事故版形态:`OUT=$(… --claim-exec … | grep 已持…)` —— **grep 吃掉了退出码,也吃掉了"抢不到"这个事实**。
|
|
|
|
|
|
- ⚠️ **「无锁」的正确读法 =「你快去抢」,不是「可以开工」** —— 2026-09-12 实证:两个会话把 guard 输出的「✓ 无全局锁」读成"环境干净"→ **同时改了本库**(无实际损害,属流程失效)。**看到"无锁" ⇒ 下一个动作就是 `--claim-exec`(带 `--domains`)**;**抢到才是开工许可**。
|
|
|
|
|
|
- 强制层(可选启用):`scripts/lock-guard-hook.py` + `~/.workbuddy/settings.json` 的 hooks —— **无锁时直接拒写**(见 `调整方案/73`)。
|
|
|
|
|
|
- ⛔ **抢不到锁就是终点,不是待办**:**不得人工删锁、不得接管**(见 **R9**,2026-09-12 用户明令)。唯一合规动作 = 等持有者自己释放,或**报告用户、由用户本人处置**;AI 不得以任何理由替用户判断"那把锁已经可以删"。
|
|
|
|
|
|
- ✅ **锁只约束「写」,不约束「读」**(2026-09-12 用户问清):读文档 / 读代码 / 只读命令(`git status|log|diff`、`journalctl`、`ls`、`grep`、只读 ssh)**随时可做,不需要锁** —— 被挡期间照样可以查清事实再报告。
|
|
|
|
|
|
⚠️ 但**会改本地状态的命令不算"读"**:`git fetch` / `checkout` / `stash` / `reset` / `switch` 等一律要持锁(它们会写 `.git/refs` 或工作树)。
|
|
|
|
|
|
- 🔓 **释放时机 = 整个交付闭环走完,不是"改完文件就放"**:`回填台账 → 四件套校验 → commit → 推送 + 对账 → 归档` 全部结束后才 `--release-exec`(**反序**:先 `--release`,最后 `--release-exec`)。
|
|
|
|
|
|
理由:中间放锁 = 别的会话可能在你 commit 前挤进来,让**你的半成品被它的提交带走**(本库实证过这类事故)。
|
|
|
|
|
|
- ⏸️ **持锁期间若需要等用户拍板(等窗口 / 等选择)→ 先释放锁,再等**:锁是"**正在动手**"的凭证,不是"先占着"。挂着锁空转会把所有会话挡在门外;确认完再重新 `--claim-exec`。
|
|
|
|
|
|
- 🔒 **锁的生命周期 = 任务的生命周期**(2026-09-14 用户明令):**抢到锁的任务,只有"执行完成 → 反序释放"才算完成**;⛔ **禁止"抢到锁、做一半、不解锁就结束回合 / 结束会话"** —— 锁是**独占资源**,带锁结束 = 把其他所有会话挡在门外,而本库**无心跳机制**、别人**没有任何判据**能确认你已停 ⇒ 会被迫空等,或被诱去违规接管(R9)。
|
|
|
|
|
|
三条硬性配套:① **抢锁前先把收口步骤列出来**(落地 → 校验 → 推送/对账 → 收尾),别做到一半才发现收不完;② **中途必须停**(等用户拍板 / 等外部窗口)⇒ **先释放锁再停**(上一条);③ **结束语必须对锁状态负责** —— 要么写明"**已释放**",要么**显式点名"锁仍在 `<OWNER>`、未释放、原因、下一步"**(仅限"释放通道不可用"这类极端情形);⛔ **"忘了 / 做不完就走"一律不允许**。
|
|
|
|
|
|
- 推送前复跑对账:**「仅本地」里若有不在你清单里的文件 → 立刻停手**(幽灵文件);**只推自己本次改的文件**。
|
|
|
|
|
|
- 单子里的基线数字**必须带取数时间 + 复核命令**,不写死绝对值(会被并行改动打穿)。
|
|
|
|
|
|
- **`~/.workbuddy/settings.json` 的 `hooks` 段 = 多会话共享配置** —— 多个会话各自加钩子时**只能 Edit 增删条目,禁止整段覆盖**(JSON 顶层键被覆盖会**静默**抹掉别人的钩子)。
|
|
|
|
|
|
2026-09-12 实证:两处独立钩子(提问闸门 / 锁闸门)各写一份配置文档,若各自按文档落盘 → **互相覆盖**;已合并为一段(`PreToolUse` 两条 + `SessionStart` 一条)。
|
|
|
|
|
|
**同一条也适用于用户级 `~/.workbuddy/MEMORY.md`。**
|
|
|
|
|
|
- ⚠️ **钩子命令「会话启动时快照」** —— 改 `~/.workbuddy/settings.json` 里的 hook,**对已在跑的会话无效**,必须**「完全重启」(彻底退出——关窗 ≠ 退出)或新开会话**才加载。**2026-09-13 实测定论**(本会话 06:47 启动 → 06:55 改配置 → 07:05 拆掉临时目录联接后,写操作报的**仍是旧路径**;此前那版「每次调用现读」是被那支临时联接掩盖的**误判**)。
|
|
|
|
|
|
- ⚠️ **脚本路径失配 = fail-closed**:hook 打不开脚本 → 报错 → 该机**所有会话**的 Write/Edit 全被拒(09-13 实际发生,连改 `settings.json` 本身都被拦)⇒ **迁移 / 改名后第一件事 = 核对 hooks 里的绝对路径**。
|
|
|
|
|
|
- **应急兜底(本钩子有意的安全阀)**:钩子**不拦 Bash** ⇒ 路径失配期间可用 shell 写文件过渡(09-13 实际走通)。
|
|
|
|
|
|
|
|
|
|
|
|
## 7. 环境要点(反复踩过 —— 条数不写死,加完就删旧的)
|
|
|
|
|
|
|
|
|
|
|
|
- **本机 bash 的 PATH 常丢**(`dirname`/`grep`/`ls` not found)→ 每条命令显式:
|
|
|
|
|
|
`export PATH="/e/ProgramData/.workbuddy/binaries/PortableGit/versions/1.2.0/usr/bin:/e/ProgramData/.workbuddy/binaries/PortableGit/versions/1.2.0/mingw64/bin:/c/Windows/System32:$PATH"`
|
|
|
|
|
|
(⚠️ **`mingw64/bin` 不能少 —— `git.exe` 只在那里**;2026-09-12 实测:只加 `usr/bin` 时 `git` 仍不可用。`usr/bin` 提供 `ls/grep/dirname/md5sum`。该 Git 安装目录**存在**,此前"路径已失效"的判断有误。)
|
|
|
|
|
|
- **插件安装 / 卸载 / 清理一律走 pnpm**(`pnpm add file:<tgz>` / `pnpm remove <pkg>` / `pnpm install` 自愈;**lockfile 才是账本**,手放 `node_modules` 无效)。
|
|
|
|
|
|
⛔ **禁 `rm -rf node_modules/<pkg>`** —— 手删**不会连带删它的依赖树**,会留下**孤儿包**并让 `node_modules` 与 pnpm 记录不一致。
|
|
|
|
|
|
(2026-09-12 实测:手删 `dsh-plugin-mcn-suite` 留下了 `xlsx` 的 7 个子依赖,最后靠 `pnpm install` 清掉 **15 个**包才复原。遇到 `pnpm remove` 报 `CANNOT_REMOVE_MISSING`(package.json 里已无该依赖)时,**正确动作是 `pnpm install`**,不是手删。)
|
|
|
|
|
|
- 同名同版本 tgz 改了内容**必须升版本号**。
|
|
|
|
|
|
- ⚠️ **语法检查别用 `python -m py_compile`**(2026-09-15 实证):它**必然**在脚本旁落 `__pycache__/*.pyc`,而文档库的 `docs-sync-check.sh` 会把它算成「**仅本地(待推送)**」⇒ 污染对账。
|
|
|
|
|
|
✅ 用**不落盘**的写法:`python -c "import ast,sys; ast.parse(open(p,encoding='utf-8').read()); print('OK')"`;若已经落了,收尾时 `find <库> -name __pycache__ -type d -exec rm -rf {} +` 并**复跑对账清零**。
|
|
|
|
|
|
- **会话取证**:dsh 实例会话 = **多帧 zstd**(按 magic `28 b5 2f fd` 切帧);WorkBuddy 自己的会话 = `~/.workbuddy/projects/<目录名>/*.jsonl`。
|
|
|
|
|
|
- **实例内禁 loopback**(`127.0.0.1` 不可达);取实例页 HTML 需 `curl -L --compressed -c jar -b jar -H "Accept: text/html"`(三条缺一注入就会被 gzip 挡掉)。
|
|
|
|
|
|
- ⚠️ **本机 → 服务器传文件必须先转 LF**(2026-09-12 实测,差点把 CRLF 带进生产):本机 `D:\github\dsh_shenxian` 的 `core.autocrlf=true` ⇒ **工作树是 CRLF**,而服务器 `/opt/dshs` 是 **LF**。直接 `scp` 会污染生产仓库(脚本照跑,但对账/三方对齐被破坏)。正解:`tr -d '\r' < 源文件 > /tmp/x` 再 `scp /tmp/x`,**只转本次要传的那一个文件**(R7 禁批量换行符转换)。判据用 `od -c` 看行尾(`\n` vs `\r\n`)—— **别用 `grep -c $'\r'`**,在 git bash 里会误报。
|
|
|
|
|
|
- ⚠️ **本机 Node 是 24,但项目原生模块(`better-sqlite3`)是按 Node 22 编译的** —— 用默认 `node`/`npm` 跑 `npm test` / `npm run verify` 会全线报 `ERR_DLOPEN_FAILED`(`NODE_MODULE_VERSION 127` vs `137`),**看起来像"我改坏了",其实是环境**(2026-09-13 实测)。跑单测/验收一律用 **Node 22**:`E:\ProgramData\.workbuddy\binaries\node\versions\22.22.2-3\node.exe`(服务器本来就是 22.23.2)。
|
|
|
|
|
|
- ⚠️ **核验"推送是否到位"要用 `git ls-remote origin refs/heads/<branch>`**(与本地 `git rev-parse --short HEAD` 对比)。本机两个仓库**都没有 remote-tracking ref** ⇒ `git log origin/main..HEAD` 直接报 `unknown revision`,**别把它的空输出当成"已全部推送"**(2026-09-13 实测)。
|
|
|
|
|
|
|
|
|
|
|
|
## 8. 会导致事故的实测事实(**常驻,不许只给指针**)
|
|
|
|
|
|
|
|
|
|
|
|
| 事实 | 不知道会怎样 |
|
|
|
|
|
|
|---|---|
|
|
|
|
|
|
| **实例权限档位是「会话创建时播种」的** —— 既有会话**不跟随平台默认**(平台默认 `danger-full-access`) | 会误判"平台坏了";更危险的是可能**自动去改档位** —— 那等于把受限会话静默提升为完全权限,**安全语义变更必须用户知情** → 只提示 + 建议新开会话 |
|
|
|
|
|
|
| **功能插件「禁用」= `pnpm remove`(真卸载)**,不是"保留包 + disabled" | 任何**硬绑定 provider** 的覆写段在用户禁用后会指向不存在的 provider;`web.searchProvider` **单选且无回落**,多 provider 又未显式配置 → `WEB_PROVIDER_AMBIGUOUS` 报错(平台已用 `syncWebProviderPatch()` 按当前 bundles 重算解决) |
|
|
|
|
|
|
| **实例配额** = `MemoryMax 384 MiB` / `CPUQuota 150%` / `TasksMax 128`;但 **V8 堆上限按宿主物理内存算(960 MiB)而非 cgroup** | ① `systemd` 的 `MemoryCurrent`/`MemoryMax` **单位是字节、不是 KB**(按 KB 算会放大 1024 倍)② 不注入 `NODE_OPTIONS=--max-old-space-size=256` → 实例会先撞**内核 SIGKILL**(无优雅退出、无日志,排查时无从下手) |
|
|
|
|
|
|
| **业务功能插件(第三方 + 自研)只有一种投放方式** = 「**admin 在门户导入候选池 → 用户在实例「功能管理」里自己启用/禁用**」(用户 2026-09-12 明确:三方插件**一律**按这个处理,**不需要铺什么**) | 若图省事改"直铺"(直接往用户 profile 装包 + 写 provider 覆写段),后果有三:① **绕过用户自决** —— 用户看不到、也关不掉;② 直铺覆写段与档案 65 的平台托管段**同属"整体替换 config"语义** → 两段并存**互相覆盖**,产生**难察觉的配置漂移**;③ 与托管段机制重复建设。**无例外** —— 连 AnySearch 最初走的直铺,也已由用户拍板改回候选池(档案 64 §8.3 修正)。⚠️ **例外只限平台基础设施插件**(`portal-entry` / `business-plugins` / `workspace-scoped-picker`):它们仍是平台级直铺、用户无感,见档案 16「插件三层归属」 |
|
|
|
|
|
|
| 🔴 **实例 home 写文件一律走 `UserFs`**;其文件名**白名单** `HOME_FILE_NAMES`(`src/fs/user-fs.ts`)是「**控制面 + worker agent 两端共用**」 | ① 绕过 `UserFs` 直接 `fs` 写 = **静默空操作**(读回空串、不报错)⇒ 以为"已落盘",实际什么都没有(档案 138 §五)。② 改白名单后**只重启一端**(如只 `systemctl restart dshs`)⇒ 另一端仍判非法,真跑报 `reason=…-unreadable:… bad_path`,**看起来像"功能没生效"**。⇒ 凡改该白名单,收尾清单必含**两个单元**:`dshs` + `dshs-worker` |
|
|
|
|
|
|
| 🔴 **PG 控制面库的 `users` 表身份键是 `id`(text uuid)** —— 同表另有一个 `uid`(**bigint** 序号);`audit_log` 的用户身份列名是 **`actor`** | 写"按 uid 查/删用户"的脚本会命中 `operator does not exist: bigint = text`,或**删不掉还当成功**(本坑 2026-09-20 序47 实测踩到一次)。⇒ 判身份一律用 `users.id` |
|
|
|
|
|
|
|
|
|
|
|
|
> 细节与当时实测:`调整方案/33`(权限档位)· `04-16`/`04-64`/`04-65`(插件与 provider)· `04-58`(内存与配额)。
|
|
|
|
|
|
|
|
|
|
|
|
## 9. 工作区目录规范(2026-09-19 立 · 详版 = 根 `README.md`)
|
|
|
|
|
|
|
|
|
|
|
|
- 🔴 **根目录白名单** —— ⛔ 不许移走,⛔ 不许在根新增散落文件:
|
|
|
|
|
|
`CODEBUDDY.md` · `state.py` · **`接续入口_*.md`** · `README.md` · `scripts/` · `.workbuddy/` · `.codebuddy/` · `.wbapp_*.genie` · 五大结构目录(`docs/` `交接单/` `tmp/` `待清理/` `归档/`)。
|
|
|
|
|
|
⛔ **线目录不进根** —— 一条工作线的多份配套方案放 `docs/<线名>/`(同级引用天然有效),冷却后整体移入 `归档/`。
|
|
|
|
|
|
⚠️ **`接续入口_*.md` 必须在根** —— `state.py` 用 `os.listdir(工作区根)` 扫描它;移走 ⇒ 新会话读到的**第一个信号就是错的**(事故级)。
|
|
|
|
|
|
- **落点**:正式文档 → `docs/<主题>/`(覆盖网络 · 集群与实例 · 客户端与桌面 · 会话与接续 · 插件与平台 · 外部接入 · 调研与审计)|交接单 / 接续包 → `交接单/`|一次性脚本与命令输出 → `tmp/<任务名>-<日期>/`|过程目录 → `tmp/历史过程目录/`|不再引用但留痕 → `归档/`|疑似可删 → `待清理/`(**列清单等确认才删**,删除不可逆)。
|
|
|
|
|
|
- **命名**:正式文档 `<主题>_<YYYYMMDD>.md`|线入口 `接续入口_<线名>_<日期>.md`|临时物 `_<用途>.<ext>`|过程目录 `_tmp_<序号>/`。日期一律 8 位无分隔。
|
|
|
|
|
|
- ⚠️ **改写文档内引用路径时,映射键必须收敛到「带 `_YYYYMMDD` 日期戳」的文件名** —— 通用名(`README.md`/`INDEX.md`/`architecture.md`)在任何文档里都可能指别处,映射它必然误伤(2026-09-19 实证)。
|
|
|
|
|
|
- **路径变更查法**:本次规整(119 项)的「旧 → 新」权威对照 = `tmp/本次整理-20260919/移动对照表.md`;一键回滚 = `python tmp/本次整理-20260919/rollback.py`。
|