Files
dsh_shenxian/dsh-server-docs/04-调整方案/121-项目代码-分层范式与迭代风险评估.md
T
admin 04776af4b1 docs: 工作区根项目文档批量入仓(04-调整方案 113–128 / 交接单 T09–T21 / ops / archive)
起因:用户 2026-09-17 明确「所有文档都要同步,都放在开发仓库 docs 对应文件夹下」。
判据:工作区根 *.md 中在仓库(git ls-files --quotepath=false)搜不到的那些。

入仓 33 份(一律复制,工作区根原件保留不动,避免引用断链):
- 04-调整方案/113–128(16 份 · 原子占号后落盘):覆盖网络 传输方案取舍 / 应用场景与待完善清单 /
  插件化vs改内核 / 问题逐条推演 / 参数表与观测口径;会合中继拆分取证与改造方案;
  集群化改造方案 Manager-Worker;跨节点迁移与节点自举;项目代码分层范式与迭代风险评估;
  搬运与共享重建方案 guest w47→w106;方案规划方法提炼;文档无效信息审计报告;
  会话接续机制复盘与修复;会话接续规范;dsh 客户端化部署方案;dsh 桌面客户端开发方案
- 交接单/archive/交接单-已完成/T09–T21(13 份 · 覆盖网络线已完成单归档)
- ops/(2 份运行态指针:接续入口 / 接续包 · 覆盖网络线)
- archive/(2 份临时与内部简报)

已排除(无需重复入仓):覆盖网络线 10 份方案正文已入档案 103–112(文件名不同)。

登记:INDEX.md §二 新增 04-113–128 共 16 行 + §四 追加 T09–T21 说明 + 机器摘要行刷新
(⛔ 未跑 docs-index-stats.py --write:该脚本会按 \r\n 归一化全文件行尾,故改为字节级单行替换);
README.md 追加 1 条入仓指针;docs-manifest.json 复跑 scripts/docs-manifest.py 刷新。

验收:工作区根 47 份 .md —— 同名已入仓 8 / 本次内容一致 29 / 已知改名映射 10 / 未入仓 0;
git status 待提交清单只含本次新增与登记 3 件(未涉 src/ 与 relay 代码面)。
2026-09-17 18:24:19 +08:00

12 KiB
Raw Blame History

项目代码 · 分层范式与迭代风险评估(2026-09-16)

性质:只读架构评估(实测探针,非印象判断)。⛔ 未改任何代码。 取证:D:\github\dsh_shenxian\src 全量静态扫描(HEAD 4e3a1a4)—— 58 个 .ts、14,053 行;统计目录规模、文件扇出、跨目录依赖矩阵(探针脚本内部聚合,只输出摘要)。 一句话判定:范式方向是对的(按域分目录 + 依赖稀疏 + 扇出低),但有两类会被大规模迭代放大的隐患 —— ① 4 组双向依赖(含"基础层反向依赖业务层")② 缺领域层,导致业务规则沉进 route 文件。 关于"改一处要不要读全仓":现在还不用,但已经出现"改一处要连读 2–3 个大文件(约 2,500 行)"的模式;覆盖网络是最后一次能以低成本立规矩的机会。


一、实测数据

1.1 目录规模

目录 文件 行数 占比
web(routes + server + nginx) 24 5,593 40%
supervisor 11 3,295 23%
db 10 2,960 21%
(root)(config / isolation / crypto / cli / index) 5 836 6%
worker 2 708 5%
fs 6 661 5%
合计 58 14,053 —

1.2 最大的 12 个文件 —— 行数大 ≠ 耦合高

行数 文件 内部依赖数(扇出)
1,259 supervisor/orchestrator.ts 6
756 db/pg.ts 4
752 db/repo.ts 3
743 web/routes/business-plugins.ts 4
706 supervisor/proxy.ts 3
687 web/routes/skills.ts 3
514 worker/agent.ts 8
500 web/routes/whitelist.ts 4

⇒ 关键读数:1,259 行的文件只依赖 6 个模块。 说明它大是因为"同领域逻辑都塞在一个文件里",不是因为"牵扯面广"。对"改一处要不要读全仓"来说,这是好消息。

1.3 跨目录依赖矩阵(全部 23 条边)

from → to 次数 from → to 次数
web → supervisor 11 supervisor → worker 2
web → fs 9 supervisor → web 2 ⚠️
web → (root) 4 worker → supervisor 2 ⚠️
web → db 3 db → (root) 2
web → nginx 1 (root) → web 2 ⚠️
fs → web 3 ⚠️ (root) → fs 2
supervisor → db 3 (root) → db 1 ⚠️
worker → fs 3 fs → worker 1 ⚠️
worker → (root) 2 fs → (root) 1
supervisor → (root) 1 (root) → 其他 —

⇒ 关键读数:整仓只有 23 条跨目录边,最粗的一条是 11 次。没有"上帝模块"。


二、范式评估

2.1 合理之处(4 条)

  1. 按域分目录:web(入口/HTTP)· supervisor(进程生命周期)· db(存储)· fs(用户文件)· worker(远程节点)—— 边界与职责对得上。
  2. 依赖稀疏:23 条边、最大 11 —— 远低于同类单体项目。
  3. 抽象缝存在:Spawner 接口把"后端"抽出来了,route 层只依赖接口。
  4. 文件头注释质量高(这一点被低估):agent.ts 头部 8 行讲清"它是什么 / 四条纪律 / 引用设计章节",spawner.ts 同理。这就是"不用读全仓"的现成机制 —— 它把"这个文件负责什么"变成可低成本获取的信息。

2.2 隐患(4 条,均有数据支撑)

# 隐患 数据 后果
1 双向依赖 4 组 web ↔ supervisor(11/2)· web ↔ fs(9/3)· supervisor ↔ worker(2/2)· fs ↔ worker(1/3) 改任一侧都要看另一侧 ⇒ 上下文成本翻倍;且无法单独测试
2 基础层反向依赖业务层 (root) → web 2 处 · (root) → db 1 处 · db → (root) 2 处 共享层(config 等)依赖上层 ⇒ 分层方向被破坏,这是最该修的一条
3 缺领域层 web 占 40% 行数;business-plugins.ts 743 行、skills.ts 687 行 业务规则沉在 route 文件里 ⇒ 改规则要读 route;同规则无法被 worker/CLI 复用;难以单测
4 web 层过重 24 文件 / 5,593 行 入口层变成事实上的"业务层",进一步加剧 #3

三、是否需要分层:需要补两层,但不需要重构

3.1 现状的实际分层(隐式)

web(routes)  ──►  supervisor / db / fs  ──►  (root: config / types)
     ▲                    ▲                        │
     └────────────────────┴────────────────────────┘
                    (反向边,违规)

3.2 建议的目标分层(方向规则要写下来)

① 入口层      web/routes · cli        (只做 HTTP/CLI 编解码)
② 领域层      domain/*                ← 【新增】业务规则,纯函数优先
③ 能力层      supervisor · db · fs · worker · net/*
④ 基础层      config · types · crypto ← 【禁止反向依赖】
               依赖方向:① → ② → ③ → ④,单向,⛔ 不得回指
  • 补 ② 领域层:把"业务规则"从 route 抽出。收益 = route 瘦身 + 可单测 + 可被 worker/CLI 复用。
  • 补 net/ 作为能力层的一员(与 supervisor/db/fs 同级),不是新的一层 —— 这样覆盖网络不会变成一个"横跨所有层的特权模块"。
  • 把依赖方向写进架构文档/CODEBUDDY:现在规则是隐式的,靠自觉。

四、「改一处要读全仓」的风险评估(这是用户真正问的)

4.1 分规模档看

规模 读全仓的代价 结论
现在(58 文件 / 14k 行) 约 15 万字符 ≈ 4–5 万 token 可行但不必 —— 实际不需要读全仓
覆盖网络落地后(+34 目录 / +58k 行) 约 22k 行 ≈ 7–8 万 token ⚠️ 开始变贵,且依赖边会从 23 条涨到 40+
继续叠加(游戏 / 房间层 / 发布层) — 🔴 若不立规矩,会真变成"改一处读全仓"

4.2 真正的风险不在规模,在边界模糊

现在已经在发生:改 business-plugins.ts(743 行)时,你无法只靠它自己判断"这条规则属于插件管理还是实例生命周期" —— 因为没有领域层,规则一半在 route、一半在 orchestrator.ts(1,259 行)和 repo.ts(752 行)。 ⇒ 一次改动实际要连读 3 个大文件 ≈ 2,500 行,这才是成本所在,而与仓库总规模无关。

4.3 三条可落地的规矩(覆盖网络正好是载体)

  1. 单向依赖:net/* 不得依赖 web/*;web 可以依赖 net。先定规则再写第一行代码 —— 现在新增目录的成本最低。
  2. 契约前置:先写接口与类型,再写实现。会合中继拆分方案的 S0 已经是这个做法(纯新增 src/net/rendezvous.ts / reachability.ts,零行为变化)—— 把它变成制度,而不是一次性动作。
  3. 文件头注释制度化成"模块索引":现有头注释写得很好,只要规定"每个模块目录入口必须写明:职责 / 依赖谁 / 被谁依赖",就能把"读全仓"降级为"读索引 + 读相关模块"。
  4. ⛔ 禁止基础层反向依赖:config / types 不得 import web / db —— 现在有 3 处,趁早清掉。

4.4 一句话回答

现在不会"改一处读全仓";但已经会"改一处读 2–3 个大文件";覆盖网络之后如果不定依赖方向,就会真的变成读全仓。 ⇒ 需要做的不是重构,而是"立规矩 + 补一层 domain"。


五、本机纳入测试环境(你已给的许可)

定位:本机(Windows 开发机)= 客户端类型的第一个测试节点,正好补上可行性评估的缺口 1("dsh 在 Windows 上能否起实例 + 实例内 bash 是否可用"至今未实测)。

形态判定:Windows 无 bwrap / systemd / uid 隔离 ⇒ 只能走 soft 模式(实例 = 裸子进程)—— 而这正好就是客户端形态的目标模式,不是降级。

可先验的三件事(都不动服务器):

  1. 本机起一个实例(soft 模式)⇒ 实例页 200;
  2. 实例内跑一次 bash 工具 ⇒ 验证 dsh 在 Windows 的沙箱后端行为(这是全案唯一"尚无证据"的技术点);
  3. 本机与 47 / 106 之间的真实网络画像(NAT 类型 / 打洞可行性 / 与中继的 RTT 与 jitter)—— 直接填"最该先测的三项"里的两项。

⚠️ 两点注意:① 本机是唯一的开发机,起实例会占资源,建议用最小配额;② 本机作为"客户端节点"参与网络时,不得顺手把它接进现有生产链路(要独立形态、独立开关)。


六、我选了什么(可推翻)

  1. 不重构,只做两件事:补 domain 层 + 把"单向依赖"写成书面规则(四层:entry → domain → capability → base)。
  2. net/ 定位为能力层的一员(与 supervisor/db/fs 同级),不是特权跨层模块。
  3. 把 S0 的"契约前置"制度化 —— 每个新增模块先出接口与类型文件。
  4. 清掉 3 处基础层反向依赖((root) → web 2 + (root) → db 1),列为独立小任务。
  5. 本机作为第一个客户端测试节点,先做 §五 的三件验证。

七、本次未做

  • ⛔ 未改任何代码、未动服务器、未写文档库(全局执行锁被 修复轮-决策方法-2b 占用)。
  • 探针脚本落 _中间产物_待清理/_arch_probe.py(可复跑;结论已固化到本文件)。
  • 📌 未新增上抛项。

八、执行计划与实际落地(2026-09-16 13:2x 追加)

8.1 🔴 勘误:§2.2 隐患②「基础层反向依赖 3 处」不成立

复核命令(只读):

grep -n "from '\./\(web\|db\|fs\|supervisor\|worker\|net\)/" src/*.ts

只命中 src/cli.ts(5 条);config.ts / crypto.ts / isolation.ts / index.ts 零 import。

⇒ 根因:上一轮统计把 cli.ts 误算进了"基础层"。它是入口层① —— import db/fs/web 属 ① → ③ 的合法方向。 ⇒ 结论修正: ① 真实违规 = 0 处 ⇒ §4.3 第 4 条「清掉 3 处基础层反向依赖」撤销(没有可清的); ② §2.2 隐患② 应改写为「边界模糊」——真实成本在 web/routes 里沉着的业务规则(§4.2 那条),不在依赖方向。 ⇒ 教训与 S0 的两处勘误同类:接手前人结论,先做一次最小取证。

8.2 ✅ P0 已落地(本机 · 2 个文件)

文件 改动
docs/architecture.md 新增:四层定义 + 依赖方向 ①→②→③→④ 单向,⛔ 不得回指 + R1–R4 判据(怎么算违反)+ 三条工程纪律(契约前置 / 模块头注释 = 索引 / 动手前自查)+ §3 现状实测 + §4 优先级
README.md 文档表新增一行指向它("动手改 src/ 前读一遍")
  • 验收:规则可从 README → docs/architecture.md 两级直达;四层归属带可判定的判据,不是口号。
  • 回滚:删 docs/architecture.md + 删 README.md 那一行。
  • 为什么先做它:零代码风险,而"扩张期走丢方向"的回头成本高得多(§四 4.1 的风险分档)。
  • ⏳ 未做:git commit(未授权)。

8.3 剩下的两件(均需先出清单,命中 R7)

P1 · 补 src/domain/* —— 把 web/routes 里的业务规则抽出来。 ⚠️ 行为敏感重构(不是纯类型);影响面 >10 文件 ⇒ 动工前先出受影响清单。 判据(做它的唯一理由):让"改插件管理规则"不再需要连读 orchestrator.ts(1,259) + repo.ts(752)。

P2 · 模块头注释补全 —— 按 docs/architecture.md §2.2 给各模块入口补「职责 / 依赖谁 / 被谁依赖」。 批量改 >10 文件 ⇒ 同样先出清单。

顺序建议:P0 ✅ → 覆盖网络 S1–S4 → P1。 P1 不阻塞覆盖网络;反过来,覆盖网络的新模块(net/*)正好是「契约前置」的第一个样板。