Files
dsh_ai1net_server/.workbuddy/memory/MEMORY.md.bak-trunc-20260917-1115
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

55 lines
14 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)。
> ⚠️ **注入上限(超了会被截断)** ⇒ 新增**按序插入对应小节,⛔ 别追加到末尾**;**体积只减不增**;**历史叙事一律不进本文件**(进交接单 §8 / 当天日志)。
## 一、状态速查(会变的都在这)
| 项 | 状态 |
|---|---|
| **在途单** | **下一棒 = 序 ⑦ · 规划棒**(主题 = **中继失败切流**,产物 = `交接单_中继失败切流_20260917.md`);automation = **`f9acaf5a`**(09-17 10:58)。序 ①–⑥ 全收官,⛔ 不要重做。⚠️ **唯一未过项** = 序⑥ **E9 后半「杀掉任一台中继 ⇒ 客户端不自动切另一台」**(根因与判据见参数表 §9 第 5 行;判为**新功能**)。⚠️ 两条老待办随轮带过来(细节见入口 §2):① guest(w-106) 实例页 **502**;② 🔴 **106 agent 面不吃引导链**(`worker/agent.ts` 把 `DSHS_RENDEZVOUS_URL` **当 relay URL 用**;撤掉 ⇒ `tunnel===undefined` ⇒ **已判不执行**)。⚠️ `/opt/dshs/mksess*.cjs` 已失效 ⇒ 开临时 session 用 **PG 直插**。⛔ 非 presence(第 7 步) |
| **生产形态** | 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) 待清。🔴 **106 的 nginx 归宝塔托管**(`bt.service`,master = `/www/server/nginx/sbin/nginx`)⇒ `systemctl is-active nginx` = `inactive` **是正常态**,⛔ 任何"用 systemctl 判 106 nginx 死活"的脚本都会误判 |
| **覆盖网络线 · 形态** | 入口 = `接续入口_覆盖网络线_20260916.md`(**§2「🎯 本轮动作」= 唯一执行依据**)。序 ①–⑥ **全收官**(证据在各单 **§8**:R2-R4/R6/一机一钥/443/参数表 §8.9/最小形态),⛔ 不要重做。**已落**:自研 relay **两台**(47+106,只绑回环 `20080`;106 复用既有 443);w-106 `via='relay'`;sshd 反向隧道**已下线且不可能重建**(`32022` 回收);R5 ⇒「Manager 必须与 relay 同机」**已不成立**。⛔ **P4(SSH 版中继/32023)判「不做」**;**worker 永远只拨出**(106 入站 = 0);relay = **自研**,⛔ 别走选型;⛔ **不做打洞实现**(`src/` 零 UDP/穿透代码,只测"网络能不能打洞") |
| **覆盖网络线 · 判据 / 路径(🔴 假绿假红都在这)** | ① `http2 on` ⇒ curl **必 `--http1.1`**(否则假 404)② 端点翻译**失败关闭**,判据取 `dsh_hosts.via` 原文(⛔ 非 `reachability.via`)③ 静默失效靠**判别器**(relay `DIAL`)④ 路由未命中 ⇒ **先补齐再失败关闭**(⛔ 绝不静默回退默认机)⑤ 47 上无 session 直连实例页**一律 401** ⇒ 验收须开临时 session。🔴 `--max-hosts`:主单元 ExecStart 已有显式 `--max-hosts 0` 且 **CLI 优先于 env** ⇒ 只设 `Environment=` 被**静默忽略** ⇒ 必须 **drop-in 重写 ExecStart**(现 47/106 = 7515)。🔴 **探针值格必须纯数字**(`KEY_RE` 取整格 ⇒ 夹注 ⇒ `NaN` ⇒ **`OBS-02` 假红**)。🔴 新开 `server` 块**不生效**(`server_name` 同名 ⇒ 老块优先 = 404)。🔴 47 云安全组**拦 UDP 入站**(nft 是 `accept`,别误判)。🔴 relay 内存端点表**留离线条目且各占 1 个本地监听** ⇒ 探针残留使监听口 79→81(**重启即复原,非泄漏**)。路径:47=`/opt/dshs/lib/`、106=`/opt/dshs-cluster/lib/`、**relay 真身=`/opt/dsh-relay/lib/`**(两处都要铺)|**部署=本机 build 后 scp**|47 的 PG **只能 TCP**|`npm test` 必须 Node 22(`npm.cmd test`)|残留安全组 `32022`。观测 = `scripts/overlay-probe.cjs`(`OBS-01..12`,**阈值全从工作区根 `参数表_覆盖网络_20260917.md` 读**,脚本内零数字字面量)。**参数表 = 单一来源**(§10 指纹口径 = `sed '/^## §10 指纹/,$d' … \| md5sum`) |
| **代码分层** | ✅ 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 空号勿补占**|熔断 78:冷却 6h+双通道告警已上线,**L1 实测未做**|MCN 0.3.10 已铺发,`mcn-task` 重复建组未解|univer = **内存探针,有意保留 ⇒ 勿下架** |
| **提交基线** | HEAD **`640813e`**(已 push);⚠️ 工作区**有未提交改动**(覆盖网络线各序产物,⛔ 未获授权不 commit/push)。🔑 **本机 `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 -`,或 `ssh host 'bash -s' < 本地脚本`。
- 🔴 **「单机自用」≠「不需要互联」**(用户原话:「**单机用也要互联,这正是建立覆盖网络的目的**」):**租户维度收窄与网络维度收窄正交** ⇒ ⛔ 别再用"单机自用所以没流量要互联"当前提。
- 🔴 **覆盖网络按异构设计**:① 中继按 **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` 再相对路径|🔴 **`cat X >> Y` 实测写到 Y 的「开头」** ⇒ 追加 .md 后**必核「在末尾」+「整块 `decode('utf-8')` 合法」**(几个非法字节 ⇒ 检测走偏 ⇒ **整份读出来全乱码**)⇒ PB §10.1。
- ⚠️ **行尾只信字节级**(`grep -c $'\r$'` 会误报)⇒ Python `b.count(b'\r')`。BRIEF/README/`skills/**`/`memory/**` = 纯 LF;**`INDEX.md` = 混合** ⇒ 字节级单行插入;⛔ 别对它跑 `git checkout --`。
- ⚠️ **引用用户口径只写原话**|**含反引号的内容一律用 Write/Edit 写** —— 含 **`python -c "…"` 内联**这条最隐蔽的变体:反引号会被**外层 shell 先当命令替换**吃掉(09-17 实测:`s.replace('`x`','…')` 被替换成空串 ⇒ 变成"每字符之间插一段"⇒ 一次写入 25,761 段垃圾串;当场发现并完整回滚)⇒ **凡要传给 Python 的字符串里有反引号,先 `Write` 落成 `.py`/`.md` 再跑,或用 `chr(96)`**|**进程替换 `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 倍**)⇒ **真杠杆 = 一轮工具次数**;⛔「切会话能归零」**错**(自动化全新会话首轮就烧 8.9–13.8 分)。**三条硬纪律**:❶ 大输出先落盘只读关键行 ❷ 命令层限流(`\| head -30` / `--max-hosts`→`grep -c`)❸ 让脚本内部聚合只 print 摘要 —— ⛔ 禁 `cat` 大文件、无 `head` 的 `grep -r`、`ls -laR`。
- 🔴 **自动化会话为什么贵**:① **一条 prompt 塞 N 件事**(prompt 必写「**本轮只做一件事,做完即停**」+「**取证最多 3 命令,要动代码先停下报告**」)② **无人能打断** ⇒ 规则本身不许制造调用。⇒ `会话接续规范_20260916.md §3.2.1/§6`。
- ⚠️ **自动化 = 开新会话的唯一通道**;**钩子无创建/切换会话能力** ⇒ 接续**只能半自动**:钩子注入收口指令 → **模型调 `automation_update`** 登记 +2min 一次性自动化。⛔ 钩子不得绕过它写库。🔴 **四条**:① 开机**第 0 步 = 跑 `state.py`**;② prompt **⛔ 不许抄任务细节**;③ 多线并行时口令**必带线名**、登记前先看 `automation_runtime_state.running`、抢不到锁 = 正常信号只报告;④ 🔴 **登记 automation 后必须在回复里用陈述句告知**("已登记自动接续,约 N 分钟后自动开新会话,不用你操作;接续点 = X")—— **只登记不告知 = 缺陷**(实证:会话 `408636f2` 只登记未提及,用户两小时后自己发现)。
## 四、仓库 / 推送 / 授权
- 📦 **09-15 文档库已并入代码仓** ⇒ **`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` 登记跟着改**;同步前先抢锁。📄 其余"去查"索引 = PLAYBOOK §11。
- ⚠️ **改任何文件前先抢全局执行锁**(`--claim-exec`);**释放了再想继续写就得重抢**。
- 🔒 **授权类**:文件已全部移除(不得再列为待办或上抛)。上游 MIT、**不得对上游代码附加限制**;**对外发布前先放回那三份**(`_授权归档_发布时再放回\`)。