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

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

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

61 lines
14 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DSH 平台 — 记忆(**状态层**)
> **判据**:不看它会不会导致「违规」或「事故」?会 ⇒ 写实体;只"更慢更绕" ⇒ 只留指针。
> **落点**:动作前必须生效的规则 → 根 `CODEBUDDY.md`(**不在此重复**)|**会变的状态**(在途单/版本/基线/位置)→ 本文件|方法论 → 技能|一次性事实·复盘·命令原文 → `PLAYBOOK` / `04/<NN>`|当天流水 → `memory/YYYY-MM-DD.md`|跨项目偏好 → `~/.workbuddy/MEMORY.md`。
> 📄 **详版 = `.workbuddy/memory/PLAYBOOK-实例与插件坑.md`**(**报障第一件事就开它**)。§ 速查:1 插件边界|2 GLIBC|3 插件加载失败三真因|4 铺插件陷阱|5 ETag|6 技术债|7 K8s 清理|8 兼容收口|9 实例取数四坑 + UI 分区三步定位 + 部署硬规矩|10 本机 Python 编码坑|11 去查索引|12 省积分。
> ⚠️ **本文件有注入上限(会截断)** ⇒ **新增内容按「越靠前越常驻」插入,⛔ 别追加到末尾**;体积**只减不增**(2026-09-16 已按此压过一轮)。
## 一、最近闭环(只留"还在影响今天"的)
- **09-16 覆盖网络线**:10 份规划 → 档案 **103–112**(`4e3a1a4`)+ 会合/中继拆分方案(S0–S4);同日 **S0 落地**(见 §二)。
- **09-15 T08 集群化 + 生产整体切换**(Manager 47 / Worker `w-47`+`w-106`)|档案 96 实例内存与插件开关解耦|档案 100/101 实例内「我的技能」→ 改名「能力管理」+ 页内 tab|档案 102 语言切换搬入「用户设置」。
- 🔑 **「用户设置」= 我们自己的 `@dsh-local/portal-entry`**(id `user-settings`);label 存**转义 unicode** ⇒ 按 UTF-8 grep 搜不到。⇒ `07-实例UI分区登记表.md`;🔧 `node scripts/find-ui.mjs [关键词]`。
- 交互规则(待拍板项**置末 + 逐条编号 + 候选竖排成段 + 必写优缺点**)已固化进 `dsh-change-workflow §5`。
## 二、状态速查
| 项 | 状态 |
|---|---|
| **在途单** | **无在途**(`T01–T08` 全完成归档)。T08 残留见 `03-路线图 §二` 🟡 |
| **生产形态** | 47 = **Manager**(cluster;控制面库 = 47 上 PG13,单元 `dshs-pg`,`127.0.0.1:15432`)+ 本地 Worker `w-47`(19100);**106 = Worker `w-106`**(19000,经 SSH 反向隧道)。存量用户锚 `w-47`、新用户按容量落 `w-106`(**粘性优先**);`guest` 已于 09-16 迁 `w-106`(epoch 4)。⚠️ **权威库 = 47 的 PG**(`/var/lib/dshs/dshs.db` 仅回滚用)。⛔ 47 兼作 Worker 是**有意设计**。**回滚** = 删 `/etc/systemd/system/dshs.service.d/cluster.conf` + `daemon-reload` + `restart dshs`(cluster 配置在这个 **drop-in** 里,不在 `/etc/dshs.env`) |
| **106 节点** | 实例运行能力已补齐(dsh 0.1.5-rc.1 + `/usr/local/dsh-runtime` + `/var/lib/dshs/*` + **`users/` 权限必须 711** —— 原 700 **会致实例必崩**);ffmpeg/ffprobe 用内网源 dnf 装。⏳ **provisioner 未铺**(新用户落 106 无人建号);⚠️ 旧控制面 `dsh-users-platform.service`(3080) 待清 ⇒ `跨节点迁移与节点自举_完整流程方案_20260916.md` |
| 集群化 | 单一来源 = 项目根 `集群化改造方案_Manager-Worker_20260914.md`;D1–D5 已定,⏳ 仅 **D6**(不阻塞);数据分层判据见 §三 |
| 实例内存(档案 96) | 与插件开关**解耦**:`MemoryHigh=MIN=448` + `MemoryMax=MAX=1024`;`/api/dsh/status` 带 `quota{...}`。⚠️ `MEM_TABLE` **仅预估、不驱动配额** |
| **覆盖网络线** | 入口 = 工作区根 `接续入口_覆盖网络线_20260916.md`(**唯一入口,先读它**)。**S0 ✅ 本机、未部署**(与 S1 合并上线;依据 = 零行为变化、部署零收益却要重启)。🔴 **方案 §8 三处勘误**,最要命一条:**`proxy.ts:109` 是发给上游 dsh 的 Host 头、不是中继连接目标**(dsh `/api` 信任栅栏要求 loopback),改它 = `/api` 全量 403;另一条:**S2 回填 `via` 不能一刀切**(w-47=`local` / w-106=`manager-ssh`)。⏳ 唯一待拍板 = 骨干服务范围(档案 **105 §七**,倾向 A→B 渐进,**不阻塞** S0–S4)。🟢 本机已获许可作「客户端类型」测试节点(Windows 无 bwrap ⇒ 只能 soft 模式,**正是客户端目标模式、不是降级**) |
| **代码分层** | ✅ **P0 已立(09-16)**:代码仓 `docs/architecture.md`(四层 `①入口 → ②领域 → ③能力 → ④基础`,`net/*` = 能力层一员 + **R1–R4 判据**)。🔴 旧结论「有 3 处基础层反向依赖」**已勘误为 0 处** —— 那几处是**入口层 `cli.ts`** 的合法依赖(`①→③`)⇒ 剩 **P1 补 `src/domain/*`**(行为敏感重构,先出清单)/ P2 模块头注释 |
| 归档编号 | 至 **112**(103–112 = 覆盖网络线 10 份);**63 空号**,勿补占 |
| 熔断 / MCN / univer | 熔断 78:冷却 6h + 双通道告警已上线,**L1 实测未做**|MCN 0.3.10 已铺发,`mcn-task` 重复建组未解|univer = **内存探针,有意保留 ⇒ 勿以下架** |
**提交基线**:代码仓 **`59f1a89`** —— 09-16 13:0x 已 push,远端 `master` 一致,**工作区全干净**。
🔑 **本机 `refs/remotes/**` 写不进去** ⇒ `git fetch` **静默失败**、`origin/master` **不可用** ⇒ **分叉判定必须** `git ls-remote origin refs/heads/master` 取**裸 sha** + `git merge-base --is-ancestor <sha> HEAD`(用本地 ref 会得到**假"非快进"**、白白停手)。推前 `--dry-run`、推后重 `ls-remote` 复核。
🗣 **称谓**:**「本机」只能指跑 WorkBuddy 的开发机**;47 / 106 一律写「远程服务器」或用 IP。
## 三、本机铁律(CODEBUDDY.md 未覆盖的部分)
- 🔴 **R10 实例起不来先查属主 / EACCES,别先怀疑 OOM** —— root 跑 `dsh --profile` ⇒ 属主变 root ⇒ 崩溃循环 / 404。修 `find <home> -user root -exec chown <uid>:<uid> {} +` → 重启。⚠️ 用户 home 是 watch 域 ⇒ 读不了的文件同样致命 ⇒ 平台侧备份一律 `/opt/dsh/backups/`。
- 🔴 **改 bwrap 参数前先看目标机 bubblewrap 版本**(**47 = 0.4.0 / 106 = 0.11.0**):`--perms` 属 0.5+ ⇒ 47 上 `Unknown option` ⇒ **沙箱起不来 = 所有实例全挂**;要权限**用 `--tmpfs`**。⚠️ `smoke-isolation` **不能**作 account 模式验收。⇒ `交接单/T08-§10`。
- 🔴 **集群化数据分层判据**(用户原话:「不一定 worker 不连数据库…」):① 归属/租约 ⇒ **只有 Manager 能写**(双写 = 脑裂)② 跟着用户走 ⇒ 放**实例 home**,别塞控制面 PG ③ 本机运维用 ⇒ **Worker 本地库**。⇒ 设计文档 §1.3。
- 🔴 **hook 脚本必须走 `sys.stdout.buffer.write(bytes)`** —— 文本层 `sys.stdout.write` + 文案含 `⛔` ⇒ 宿主 stdout 非 UTF-8 ⇒ `UnicodeEncodeError` ⇒ **stdout 空 ⇒ 静默放行**(日志却写 deny ⇒ 表现成"判了但拦不住")。判据 = **"写日志 + emit"双动作且 emit 走 buffer**。`PreToolUse` 的 `deny` **确有效**;锁主力仍是三把锁 + `handoff-guard.sh` + 约定,hook 是加固层。⛔ 别再写"hook 拦不住"。📂 自证日志真路径 = `D:\github\dsh_shenxian\.workbuddy\lock-hook.log`(跟 `DOCS_ROOT` 走)。⇒ PB §10。
- 🔔 **技能加载闸门(09-16 装)**:钩子 `dsh-server-docs/scripts/skill-load-guard.py` —— 命中「决策方法 / 参考决策 / 按你的规划 / 别问我 / 自行决策 / 自主决策」⇒ 自动注入"必须先加载 `dsh-decision-method`"(急停 `DSH_SKILL_GUARD_OFF=1` 或 `.workbuddy/skill-guard.disabled`)。⚠️ **需完全重启才加载**。
- 🔴 **两条命令坑**:① `pkill -f` 要匹配"实际 argv" ⇒ ✅ 按端口定位 `ss -lntpH 'sport = :PORT' | grep -oP 'pid=\K[0-9]+' | head -1`。② **`fetch` 静默丢 `Host` 头**(undici)⇒ 多租户验证落到"无租户"路由、**假 404/200** ⇒ ✅ `curl -H "Host: …"`、别跨用户测、判据别只看状态码。
- 🔴 **「单机自用」≠「不需要互联」**(09-16 用户原话:「**单机用也要互联,这正是建立覆盖网络的目的**」):**租户维度收窄(1 个用户)与网络维度收窄(1 台机器)正交** ⇒ ⛔ 不得再用"单机自用所以没流量要互联"当前提(推演 v1 因此作废、已重写 v2)。
- 🔴 **覆盖网络按异构设计**:① **中继按 45% 设计、55% 留余量**(⛔ 别用同构假设的 15%)② **必须补 443/TCP 兜底**(否则封 UDP 的整类节点进不来)③ 有公网 IP 的节点自动升格为中继候选,但**权威状态仍必须单点 Manager** ④ VPN/代理类**检测即降级中继**,不重试 ⑤ **节点自报网络画像**。
- 🔴 **方案只做技术实现,合规不进方案**(09-16 用户原话:「**方案只考虑技术实现,跨境数据合规是谁用谁自己考虑**」)⇒ ⛔ 不再把合规 / 数据主权 / 备案当前置条件、约束或上抛项。多区域就近 = **性能**最优,不是合规动作。
- 🔴 **接手前人结论,先做一次最小取证**(09-16 同日踩两次):① 方案说 `proxy.ts:109` 是中继落点 ⇒ 实为**上游 Host 头**;② 评估文档说"3 处基础层反向依赖" ⇒ 实为**入口层 `cli.ts` 的合法依赖,违规 0 处**。⛔ 别拿上一份文档的结论当既成事实直接执行。
- ⚠️ **本机执行环境**:**Python stdin/stdout 必须走 `buffer` 显式 UTF-8**(`-E` 屏蔽 `PYTHONUTF8=1` ⇒ cp936 ⇒ 含中文静默炸)|改文件**必用 `newline=""`(读也要)**|**ESM**|bash **PATH 被 shim 重置** ⇒ 先 `export PATH=<PortableGit>/usr/bin:…:/c/Windows/System32:/c/Windows:$PATH`|**Python 原生 exe 不认 `/e/…`** ⇒ 传参 `E:/…`|bash 内联 `\` 被 MSYS 改写 ⇒ 含 Windows 路径的 Python **落成 .py 再跑**|`tar czf E:/…` 加 `--force-local`|**bash 的 `cd` 认中文路径、`ls` 等被 MSYS 编码搞坏** ⇒ 先 `cd` 再用相对路径。⇒ PB §10。
- ⚠️ **行尾只信字节级**(`grep -c $'\r$'` 会误报)⇒ Python `b.count(b'\r')`。BRIEF/README/`skills/**`/`memory/**` = 纯 LF;**`INDEX.md` = 混合** ⇒ 改它走**字节级单行插入**;⛔ 别对它跑 `git checkout --`。⚠️ **源仓 `refs/remotes/**` 写不进去**(报成功但引用不存在 ⇒ `[gone]`)⇒ 对账一律 `git ls-remote origin refs/heads/master`;`git` 走 SSH 加 `GIT_SSH_COMMAND="ssh -o BatchMode=yes -o ConnectTimeout=15 -o StrictHostKeyChecking=accept-new"`。
- ⚠️ **引用用户口径只写原话**|**含反引号的内容一律用 Write/Edit 写**|**进程替换 `diff <(a) <(b)` 不可用**|**`Edit` 是替换不是追加**。⇒ PB §12。
- 🔴 **成本公式(09-16 实测 `workbuddy.db` 原始计费字段,勿再凭直觉)**:**省积分四招** = 批量活写脚本 / 拦大输出(`bash-output-guard.py`)/ 命令限流 / 切会话 —— 但**四招效力天差地别**,判据是:**积分 ≈ 单价 × 一轮内工具调用次数**;单价随水位涨(<10 万 ≈**0.10**、15 万 ≈**0.41** 积分/次,同会话受控实测 **4 倍**)。⛔ **「切会话能归零」是错的** —— 三个自动化**全新会话的首轮**分别烧 **8.93 / 10.05 / 13.82** 积分(因首轮跑了 31–54 次工具调用)⇒ **切会话只压单价膨胀、压不了次数**。**真杠杆排序 = ① 一轮工具次数(线性、主导)→ ② 水位 → ③ 固定注入 35,192 tok(缓存命中 99.5%,很轻)**。数据源 = `session_usage.credit_json` + `automation_runs.runs_json`。
- ⚠️ **自动化 = 开新会话的唯一通道**(取证:`automation_runs.metadata_json` 每次运行都带**新** `sessionId`);**钩子无创建/切换会话能力**(输出只有「注入上下文」与「拦工具」)⇒ 自动接续**只能半自动**:钩子注入收口指令 → **模型调 `automation_update`** 登记 +2min 一次性自动化。⛔ 钩子脚本**不得**绕过 `automation_update` 写库建自动化。
- ⚠️ **打包与改名**(`npm pack` 前核断言锚点、先删 `lib/*.bak` 与 `*.tgz`、升号前确认号没用过、每包必须有 `.npmignore` 排除 `*.tgz`;`--force` 只准替换自己那一段;改名三件套 = SQLite `.db`+`-wal`+`-shm` 一起改 / 压缩包内 grep-sed 够不到 ⇒ 解压→改→重压 / 改完真环境跑一次)。⇒ PB。
- 浏览器只准 `agent-browser` / `browser-harness`(CDP 9223);⛔ **Playwright 全面禁止**。
## 四、仓库 / 推送 / 授权
- 📦 **09-15 文档库已并入代码仓**(R4 选 a)⇒ **`D:\github\dsh_shenxian\dsh-server-docs\`**(git = `D:/github/dsh_shenxian/.git`)。锁脚本 = `…\dsh-server-docs\scripts\handoff-guard.sh`。镜像 `/opt/dsh/docs` 不变。⚠️ hooks 路径改动要**完全重启**才生效。
- 代码仓 `D:\github\dsh_shenxian` → `…dsh_shenxian.git`(master)|**推送只能从本机**;服务器改码走 `git bundle`。文档库 `autocrlf=false` + `.gitattributes(* -text)` **必须保持**。
- ⚠️ **技能是「三处」**:本机 `.workbuddy/skills/<name>/` ← 文档库 `skills/<name>/` ← 镜像 `/opt/dsh/docs/skills/`。**验收 = 两副本 md5 一致 + 镜像一致 + `README.md` / `INDEX.md` 登记跟着改**;同步前先抢全局执行锁。
- ⚠️ **改任何文件前先抢全局执行锁**(`--claim-exec`),**释放了再想继续写就得重抢** —— 一次抢锁只对"本轮任务"有效,跨轮必须重抢(09-16 实测:释放后下一轮直接 Write 被钩子拦下)。
- 📄 **「去查」索引 = PLAYBOOK §11**(权限档位 / 插件启停 / UI·univer / 个人技能 / docx / `business-plugins` 升级 / admin 跨用户 / 加新能力 / dsh 版本 / 开源导出)。
- 🔒 **授权类**:文件已全部移除(不属改造范围、不得再列为待办或上抛)。上游 MIT、**不得对上游代码附加限制**;**对外发布前先放回那三份**(`_授权归档_发布时再放回\`)。