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

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

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

56 lines
13 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DSH 平台 — 记忆(**状态层**)
> **判据**:不看它会不会导致「违规」或「事故」?会 ⇒ 写实体;只"更慢更绕" ⇒ 只留指针。
> **落点**:动作前必须生效的规则 → 根 `CODEBUDDY.md`(**不重复**)|会变的状态 → 本文件|方法论 → 技能|一次性事实·命令原文 → `PLAYBOOK` / `04/<NN>`|当天流水 → `memory/YYYY-MM-DD.md`|跨项目偏好 → `~/.workbuddy/MEMORY.md`。
> 📄 **详版 = `.workbuddy/memory/PLAYBOOK-实例与插件坑.md`**(**报障第一件事就开它**,§1–12)。
> ⚠️ **注入上限(超了会被截断)** ⇒ 新增**按序插入对应小节,⛔ 别追加到末尾**;**体积只减不增**。
## 一、状态速查(会变的都在这)
| 项 | 状态 |
|---|---|
| **在途单** | **交接单 v2 待执行** = 覆盖网络线(工作区根 `交接单_覆盖网络落地执行_20260916.md`,**须另开会话**);T01–T08 已归档 |
| **生产形态** | 47 = **Manager**(cluster;控制面库 = 47 的 PG13 `127.0.0.1:15432`,单元 `dshs-pg`)+本地 Worker `w-47`(19100);**106 = Worker `w-106`**(19000)。存量锚 `w-47`、新用户按容量落 `w-106`(**粘性优先**)。⚠️ **权威库 = 47 的 PG**(`/var/lib/dshs/dshs.db` 仅回滚用)。⛔ 47 兼作 Worker 是**有意设计**。**回滚** = 删 drop-in `dshs.service.d/cluster.conf` → `daemon-reload` → `restart dshs`(cluster 配置在**这个 drop-in 里**,⛔ 不在 `/etc/dshs.env`) |
| **106 节点** | 实例能力已补齐(`users/` 权限**必须 711**,700 ⇒ 实例必崩)。⏳ **provisioner 未铺**;⚠️ 旧控制面 `dsh-users-platform.service`(3080) 待清 |
| **覆盖网络线** | 入口 = `接续入口_覆盖网络线_20260916.md`。**P1–P3 已完成验收**(证据 = 交接单 §8):P1 47 对齐 `640813e`|P2 `dsh_hosts.via`(v8;w-47=`local`/w-106=`manager-ssh`)|P3 端口区间隔离(w-47 20000+/w-106 21000+)⇒ 修掉「跨 worker 同号 ⇒ 静默拨到别人实例」真 bug。🔴 **P4(SSH 版中继 / 32023)已判「不做」**——SSH 反向隧道**不是"不安全"**(专用非特权账号 + `PermitOpen` + 限速是业界标准做法),但**不该长期做数据面**;它想要的(与宝塔 sshd 解耦、甩掉 root 凭据)**frp 里同样拿到** ⇒ 两步合一。🔴 **传输方向已定**(用户问"开放端口能否解决 / SSH 是否临时方案"):**worker 永远只拨出、不开任何入站端口**(106 入站口 = **0 个**)⇒ **摆脱 SSH 的正解 = 自研 relay + 单端口出向长连接**(**不需新开公网口**,与 S5「443/TCP 兜底」合并做);⛔ 别再把"在 106 开 agent 端口"当方案(暴露面 O(1)→O(N),且 agent 只有共享 token 认证)。**终态 relay 实现「未定」**:**frp 已撤销**(用户质疑「项目久 ≠ 最好」是对的)—— 它有 **5 项默认姿态缺陷**(认证绕过 CVE-2026-40910 / 默认 `admin:admin` / 默认绑公网 / 静态 token 明文 / 不强制 TLS),按 6 条判据(**认证模型·默认姿态·零入站·爆炸半径·可观测·生态**)**前三条最差一档**;候选 = **OpenZiti / Nebula(证书身份)> rathole(Noise_NK + 每服务 token)> frp**。⇒ **本轮不引入第三方 relay**,先做 **R0 = 六条判据打分表 + 测链路画像(RTT/jitter/带宽)**;**性能不作为选型轴**(第一瓶颈是 **presence** 不是带宽)。⚠️ 换第三方 = 用**不掌控的攻击面**替换**已收窄的 sshd 面** ⇒ **不是无条件升级**。🔑 `Reachability.via` + `Rendezvous` 已抽好 ⇒ **换实现 = env 级切换**。详见 `覆盖网络_传输方案取舍_开放端口与自研relay_20260916.md`。🔴 **勘误**:**`proxy.ts:109` 是上游 Host 头**(改它 = `/api` 全 403;连接目标 `:136-137`)|**「回环别名」实测证伪**;**S4 异地中继仍缺一跳**(6 条全文在交接单 §0.2 / 方案 §9)。⚠️ `dsh_instances.status` **非实时** ⇒ 看 worker agent `/status/:userId`。⚠️ 47=`/opt/dshs/lib/`、106=`/opt/dshs-cluster/lib/`;**47 部署 = 本机 build 后 scp `lib/`**(⛔ 非 git pull);47 的 PG **只能 TCP**;`npm test` 必须 Node 22。🟢 本机作「客户端类型」测试节点(Win soft 模式 = **目标模式**) |
| **代码分层** | ✅ P0 已立:代码仓 `docs/architecture.md`(`①入口→②领域→③能力→④基础` + R1–R4)。🔴 旧结论「3 处反向依赖」**已勘误为 0 处** ⇒ 剩 P1 `src/domain/*` / P2 模块头注释 |
| 集群化 | 单一来源 = 项目根 `集群化改造方案_Manager-Worker_20260914.md`;D1–D5 已定,⏳ 仅 D6(不阻塞) |
| 实例内存(档案 96) | 与插件开关**解耦**:`MemoryHigh=MIN=448`+`MemoryMax=MAX=1024`;`/api/dsh/status` 带 `quota{...}`。⚠️ `MEM_TABLE` **仅预估、不驱动配额** |
| 归档编号 | 至 **112**(103–112 = 覆盖网络线);**63 空号**,勿补占 |
| 熔断 / MCN / univer | 熔断 78:冷却 6h + 双通道告警已上线,**L1 实测未做**|MCN 0.3.10 已铺发,`mcn-task` 重复建组未解|univer = **内存探针,有意保留 ⇒ 勿下架** |
| **提交基线** | HEAD **`640813e`**(已 push);✅ 工作区 0 改动。🔑 **本机 `refs/remotes/**` 写不进** ⇒ `git fetch` **静默失败** ⇒ 分叉判定**必须** `git ls-remote origin refs/heads/master` 取**裸 sha** + `git merge-base --is-ancestor`;推前 `--dry-run`、推后重验。🗣 **「本机」= 跑 WorkBuddy 的开发机** |
## 二、本机铁律(⛔ 违反即事故)
- 🔴 **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 模式验收。
- 🔴 **集群化数据分层判据**:① 归属/租约 ⇒ **只有 Manager 能写**(双写 = 脑裂)② 跟着用户走 ⇒ 放**实例 home** ③ 本机运维用 ⇒ **Worker 本地库**。
- 🔴 **hook 脚本必须走 `sys.stdout.buffer.write(bytes)`** —— 文本层 `sys.stdout.write` + 文案含 `⛔` ⇒ 宿主 stdout 非 UTF-8 ⇒ `UnicodeEncodeError` ⇒ **stdout 空 ⇒ 静默放行**。判据 = **"写日志 + emit"双动作且 emit 走 buffer**。⛔ 别再写"hook 拦不住"。📂 自证日志 = `D:\github\dsh_shenxian\.workbuddy\lock-hook.log`。⇒ PB §10。
- 🔴 **两条命令坑**:① `pkill -f` 要匹配"实际 argv" ⇒ ✅ `ss -lntpH 'sport = :PORT' | grep -oP 'pid=\K[0-9]+'`。② **`fetch` 静默丢 `Host` 头**(undici)⇒ 多租户验证落"无租户"路由、**假 404/200** ⇒ ✅ `curl -H "Host: …"`。
- 🔴 **两条取数坑**:① **本机 `md5sum` 输出 `hash *path`(二进制)、远端是 `hash path`(文本)** ⇒ 直接 `diff` 得"**所有文件都不同**"的**假象**(59/59 全红其实只差 7 个)⇒ 先归一化路径字段。② **`ssh '…'` 单引号里不能出现单引号**(SQL 字面量)⇒ `'local'` 被本地 shell 吃掉 ⇒ ✅ 用 `cat > f <<"EOF"` 落文件,或本地 `echo` 管道给远端 `psql -f -`。
- 🔴 **「单机自用」≠「不需要互联」**(用户原话:「**单机用也要互联,这正是建立覆盖网络的目的**」):**租户维度收窄与网络维度收窄正交** ⇒ ⛔ 别再用"单机自用所以没流量要互联"当前提。
- 🔴 **覆盖网络按异构设计**:① 中继按 **45% 设计、55% 留余量**(⛔ 别用同构的 15%)② **必须补 443/TCP 兜底** ③ 有公网 IP 的节点自动升格为中继候选,但**权威状态单点 Manager** ④ VPN/代理类**检测即降级中继**、不重试 ⑤ 节点自报网络画像。
- 🔴 **方案只做技术实现,合规不进方案**(用户原话:「**方案只考虑技术实现,跨境数据合规是谁用谁自己考虑**」)⇒ ⛔ 不再把合规/数据主权/备案当前置条件或上抛项。
- 🔴 **接手前人结论,先做一次最小取证**(同日踩两次):① `proxy.ts:109` 实为**上游 Host 头**;② "3 处反向依赖" 实为 **0 处**。⛔ 别拿上一份文档的结论当既成事实。
- 🔔 **技能加载闸门**:`scripts/skill-load-guard.py` —— 命中「决策方法/按你的规划/别问我/自行决策」⇒ 注入"必须先加载 `dsh-decision-method`"(急停 `DSH_SKILL_GUARD_OFF=1`)。⚠️ **需完全重启**。
- ⚠️ **本机执行环境**:**Python stdin/stdout 必走 `buffer` 显式 UTF-8**|改文件**必用 `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`|`ls` 被 MSYS 搞坏 ⇒ 先 `cd` 再相对路径。⇒ PB §10。
- ⚠️ **行尾只信字节级**(`grep -c $'\r$'` 会误报)⇒ Python `b.count(b'\r')`。BRIEF/README/`skills/**`/`memory/**` = 纯 LF;**`INDEX.md` = 混合** ⇒ 字节级单行插入;⛔ 别对它跑 `git checkout --`。
- ⚠️ **引用用户口径只写原话**|**含反引号的内容一律用 Write/Edit 写**|**进程替换 `diff <(a) <(b)` 不可用**|**`Edit` 是替换不是追加**。
- ⚠️ **打包与改名**:`npm pack` 前核断言锚点、先删 `lib/*.bak` 与 `*.tgz`、每包必须有 `.npmignore`;改名三件套 = SQLite `.db`+`-wal`+`-shm` 一起改 / 压缩包内 grep-sed 够不到 ⇒ 解压→改→重压 / 改完真环境跑一次。
- 浏览器只准 `agent-browser` / `browser-harness`(CDP 9223);⛔ **Playwright 全面禁止**。
## 三、成本与自动化(09-16 实测)
- 🔴 **成本公式**:**积分 ≈ 单价 × 一轮内工具调用次数**。单价随水位涨(<10 万 ≈**0.10**、15 万 ≈**0.41** 分/次,受控实测 **4 倍**)⇒ **成本全由"次数"累出来**。**真杠杆 = ① 一轮工具次数(主导)→ ② 水位 → ③ 固定注入 35,192 tok(缓存命中 99.5%,很轻)**。⛔ **「切会话能归零」错** —— 自动化**全新会话首轮**烧 **8.93 / 10.05 / 13.82** 分。
- 🔴 **自动化会话为什么贵**:**不是"自动化"这个身份**(手动会话也可更贵)。根因 = ① **一条 prompt 塞 N 件事** ② **无人能打断**(实证:`b08b1c35` 用户只说"先确认待办",**第 28 次调用已在写代码**)③ 规则本身制造调用。**修法**:prompt 必写「本轮只做一件事,做完即停,⛔ 不许顺手做别的」+「取证最多 3 个命令,要动代码先停下报告」。⇒ `会话接续规范_20260916.md §3.2.1/§6`。
- ⚠️ **自动化 = 开新会话的唯一通道**;**钩子无创建/切换会话能力** ⇒ 自动接续**只能半自动**:钩子注入收口指令 → **模型调 `automation_update`** 登记 +2min 一次性自动化。⛔ 钩子不得绕过 `automation_update` 写库。🔴 **09-16 补**:① 开机**第 0 步 = 跑 `state.py`**;② prompt **⛔ 不许抄任务细节**;③ 三级注入 = "**登记一次性 automation**";④ **多线并行**:口令**必带线名**、`[入口]` 已**列全各线**、登记前先看 `automation_runtime_state.running`、抢不到锁 = 正常信号只报告。⑤ 🔴 **登记 automation 后必须在给用户的回复里用陈述句告知**("已登记自动接续,约 N 分钟后自动开新会话,不用你操作;接续点 = X")—— 新建会话是**用户可感知的状态变更**,**只登记不告知 = 缺陷**(实证:会话 `408636f2` 登记了自动化但末条回复一字未提,用户两小时后自己发现才追问)。
## 四、仓库 / 推送 / 授权
- 📦 **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`);**释放了再想继续写就得重抢**。
- 📄 **「去查」索引 = PLAYBOOK §11**(权限档位 / 插件启停 / UI·univer / 个人技能 / docx / `business-plugins` 升级 / admin 跨用户 / 加新能力 / dsh 版本 / 开源导出)。
- 🔒 **授权类**:文件已全部移除(不得再列为待办或上抛)。上游 MIT、**不得对上游代码附加限制**;**对外发布前先放回那三份**(`_授权归档_发布时再放回\`)。