Files
dsh_ai1net_server/交付物/平台新增功能总盘点与插件化归属-20260926.md
admin c1b5e4d966 chore(工作区): 全量入库 + 补齐 .gitignore(以工作区为准)
- 变更规模:新增 514 / 修改 62 / 重命名 155 / 删除 4(归档重组与文档轮次)
- .gitignore 修:`归档/**/db-cwd归一-备份-*/` —— 原规则写绝对层级(归档/db-cwd归一-…),
  目录搬进 归档/配置与备份/ 后**静默失效**,43 MB 的 DB 备份又变成未跟踪
- .gitignore 补:嵌套 git 内部数据(归档/内嵌git-20261008/、归档/skills-git-旧线-20261007/dotgit-原样移出/)
- .gitignore 补:运行态与部署副本(.workbuddy/collab/、.workbuddy/tools/、.workbuddy/.load-pending、.workbuddy/tmp-*)
- .gitignore 补:备份件(*.bak-*)
- 未跟踪文件从 2190 降到 890(其余为 归档/ 归档件与 .workbuddy/memory/ 知识文件,按口径入库)
2026-10-10 23:13:22 +08:00

33 KiB
Raw Permalink Blame History

平台新增功能总盘点 × 插件化归属("基础服务插件"能不能做、能装哪些)

回答的问题(用户原话):「把现在开发的平台基于 DSH 主体新增的所有功能全部列出来,看一看哪些能整合到插件中,相当于是基础服务的插件。基于这个插件可以去使用现有新增能力。」 本件口径:先给一张能自己判断的口诀(§1),再给完整盘点表(§3–§8),最后给「基础服务插件应该长什么样」(§9)与不可进清单(§10)。 ⚠️ 盘点来源 = 平台自己的路由与目录清单(src/web/routes/ 15 个路由文件 + src/ 各目录)+ 本工作区在册记录;未逐行复核每个功能(见 §12)。


1 一句话判据(为什么"不能"—— 用这个自己判断,比记结论有用)

判据:这件事发生在「插件存在之前」还是「之后」? 之前 ⇒ 必须在引导层(不可插件化);之后 ⇒ 应该尽量放进插件。

「插件」是被装进去的东西 —— 而"把它装进去"这个动作,需要一个已经在跑的宿主。所以固定有四件事发生在它之前(§10)。除此之外几乎都能进插件。

两层心智模型(这是此前没讲清的地方):

层 是什么 谁写的 与 DSH 主程序的关系
L0 官方 DSH 进程、窗口与界面框架、插件机制与扩展点、会话与工具 官方 —
L1 平台自有服务 登录/门户/多租户编排/插件投放/数据面/协作内核/网络中继 我们自己 ⭐ 本来就不依赖 DSH(官方没有账号体系,这些都是独立进程)
L2 实例内 / 客户端内 界面扩展、平台能力的取用(读身份态、调平台接口、数据面、协作、启停插件) 我们自己 寄生于官方的扩展点

⇒ 用户想要的"基础服务插件" = 把 L2 收成一个包;L1 从来不需要"插件化"(它已经独立存在,客户端只是调用方);L0 的四件固定事拿不走。


2 判定图例

标记 含义
✅ 能进基础服务插件(客户端侧可承载:界面 + 调用)
⚠️ 半能:界面能进,但动作属引导层/服务端;或它本就是服务器页面
❌ 不能进插件(宿主四件 + 服务器侧服务/运维面)

3 官方 DSH 提供的基线(列出仅作对照,⛔ 不动)

功能组 官方基线 现在在哪 能进插件? 说明
实例宿主(进程/会话/工具/模型调用) 有 L0 ❌ 宿主本体
窗口与界面框架 + 插件机制与扩展点 有 L0 ❌ 插件机制不能在插件里
技能加载机制 有 L0 ❌ 平台新增的是"分层与投放管理"(§5)
本地插件安装命令 有(本地) L0 ❌ 平台新增的是"远程投放与分发"(§4)

4 平台新增 · 插件体系与分发(business-plugins.ts · plugin-data.ts · 本会话的版本机制)

功能 官方有? 现在在哪 能进插件? 依据 / 卡点
候选池 → 投放 → 共享包库 无 L1 服务 ✅ 管理界面可进 客户端只做"看得到、点得动"
把包拉下来并装进实例 无 引导层 ❌ "装"本身不能由被装的那个包做(先有鸡还是先有蛋)
插件启停 / 装配 部分(本地) 装配在引导层 · 台账在 L1 ⚠️ 启停界面可进;装配动作在引导层
插件数据面(一插件一库) 无 L1 网关 + 插件侧 SDK ✅ 本来就是给插件用的 ⇒ 天然属于基础服务插件
版本归档 / 通道 / 定向钉版 / 全局矩阵(本会话新落) 无 L1 服务 ✅ 矩阵与钉版管理界面可进
↑ 同上的拉取器 无 引导层 ❌ 与"装插件"同源

5 平台新增 · 身份与账号(auth.ts · admin.ts · admin-user-ops.ts · whitelist.ts)

功能 官方有? 现在在哪 能进插件? 依据 / 卡点
注册 / 登录 / 会话凭据 无 L1 服务 ⚠️ 登录动作必须发生在"插件存在之前"(引导层);身份态展示 / 账号设置可进插件
角色与用户管理 无 L1 服务 ✅ 管理界面 + 调接口
准入白名单 无 L1 服务 ✅ 同上

6 平台新增 · 多租户与实例(src/supervisor/ 12 文件 · isolation.ts · src/fs/)

功能 官方有? 现在在哪 能进插件? 依据 / 卡点
实例编排 / 守护 / 自愈 / 配额 无 服务器侧服务 ❌ 概念上不适用 客户端是调用方;插件里只做入口与展示
沙箱隔离 无 服务器侧服务 ❌ 同上 —
用户文件系统(按用户隔离读写) 无 服务器侧服务 ⚠️ 界面可 动作走服务接口

⚠️ 本组是此前"为什么不能"的主要误会来源:这些不是客户端的客户端功能,而是服务器提供的能力。插件在这里的角色是入口,不是实现。


7 平台新增 · 网络与协作(src/net/ · overlay*.ts · src/im/ 12 文件)

功能 官方有? 现在在哪 能进插件? 依据 / 卡点
入网拨号 / 中继 / 寻址 / 组密钥 / 打洞 无 引导层(原生守护) ❌ 拨号必须发生在界面与插件之前(桌面线已有定论:网络载体是新写的原生守护)
设备授权(换设备凭据) 无 L1 服务 + 引导层 ⚠️ 授权动作在引导层(要已登录);状态展示可进插件
节点 / 设备矩阵(谁在线、哪个版本) 无 L1 服务 ✅ 展示
协作内核(房间 / 消息 / 发言规则) 无 L1 进程 ❌ 客户端侧是插件,不是内核
插件 SDK / 扩展点 / 回调桥 无 插件侧 ✅ 本身就是给插件用的 ⇒ 天然属于基础服务插件
会话与工作区分组 部分 L1 服务 ✅ 列表 / 切换界面可进;存储在服务

8 平台新增 · 能力资产、界面与运维(skills.ts · dsh.ts · domain.ts · src/nginx/)

功能 官方有? 现在在哪 能进插件? 依据 / 卡点
技能分层与统一投放 机制有 L1 服务 + 实例内加载 ✅ 管理界面可进
共享模型逐用户授权 无 L1 服务 ✅ 展示 / 申请入口可进
用户自配模型凭据 部分 L1 保管 + 实例内落盘 ⚠️ 写凭据在实例内(插件可做),保管在服务
门户六页 / 登录页 无 L1 服务器页面(我们的页面) ⚠️ 不建议搬 ⛔ 搬进插件 ⇒ 与"与服务器版本一模一样"冲突、出现两份 UI 漂移(详见 §11)
工作台 UI / 窄档响应式 部分 插件 / 适配层 ✅ 插件本来就是干这个的
审计 / 日志 / 健康 无 L1 服务 ✅ 展示
部署 / 回滚 / 备份 / 域名 / 证书 无 运维面 ❌ 不在客户端

9 「基础服务插件」应该长什么样

一个包,两个半(形态与既有先例同源:本地代理包就是"一个自研包两个入口"):

半 装什么
服务端半 平台能力的统一入口:身份态、可用插件与启停、数据面、协作、技能清单、模型授权态、网络与设备状态、更新检查
界面半 全部落在官方已有槽位(设置 → 插件 / 能力管理 …),各类各一页;⛔ 不新造页面体系

⇒ 用户那句「基于这个插件可以去使用现有新增能力」—— ✅ 成立。而且这正是把这些能力统一出口的正确做法。


10 ⛔ 不可进清单(只有 4 件,全在引导层)

  1. 起实例(把官方宿主进程跑起来)
  2. 起窗口 / 渲染首屏
  3. 取身份(登录 + 设备授权 —— 必须早于插件)
  4. 把包拉下来并装进去(含它的版本管理与拉取器)

+ 服务器侧服务(多租户编排、隔离、协作内核、中继、门户、运维)—— 它们不是"不能进插件",而是"本来就不依赖 DSH"(官方没有账号体系 ⇒ 这部分从第一天就是我们的独立进程)。⛔ 把它们算作"插件的候选"是范畴错误。


11 一处我不建议,但可推翻

门户六页(含登录页)不要搬进插件。 理由:桌面线已定的口径是「套壳 + 同步服务器代码」「UI 与服务器版本一模一样」—— 门户是服务器页面,浏览器里就是它。若在插件里再实现一份,就会出现两份 UI,此后每次改页面都要改两处、必然漂移(属负向迭代)。⇒ 建议:门户保持服务器页面,插件只做入口与内嵌。


12 收益预期与不确定项(照实说)

收益预期:把 §4–§8 标 ✅ 的收进一个基础服务插件 ⇒ 客户端里"能改的功能"约九成都随插件更新,不必重发安装包;剩下的引导层(§10 四件)建议冻结到最薄,因为它一变就要重发安装包。

不确定项(⛔ 不假装确定):

  1. 本盘点由路由与目录清单 + 在册记录归纳而成,未逐行复核每个功能;若某行要驱动开工,先补该行的最小取证(具名到文件与行号)。
  2. 表格里 ⚠️ 的拆分("界面可进 / 动作不可进")是按判据推演的,仍需在实施时逐条落到扩展点上验证。
  3. 「约九成」是按功能组计数的粗估,不是行级精算。

12.5 追问链结论速览(§13–§15 四问四答 · 可直接拿去决策)

本节只是 §13–§15 的索引与判定,⛔ 不复述论证;每条都指向原文小节。

你问的 判定 关键边界 详见
只装官方 DSH + 加我们的插件,能不能拿到 L1 与 L2? ⚠️ 部分可行 L2 全部 ✅;L1 只用不搬 §13
登录/身份能不能做进插件? ✅ 能做 包「登录后才拿得到」⇒ 身份成为信任链起点 §13.2
装完后用户自选角色:当节点提供服务 / 只当用户设备? ⚠️ 分三档 用户设备 ✅ · 轻节点 ✅ · 重节点 ❌ §14
自选接入哪个节点(106 接入 47,接入后可用其功能)? ⚠️ 只有"无状态归属"能切 A 内容 ✅ · B 网络 ✅ · C 承载 ⚠️ 只能迁移 §15
「当节点」到底能不能选?为什么不行? ⚠️ 只能选一半 当 Worker ✅ 自选角色 · 当 Manager ❌ 换控制面,不是角色 §16

四条硬约束(换任何形态都逃不掉):① 首装的包必须匿名可取(否则"拿到身份之前拉不到包"死循环)② 平台自有服务(L1)只被使用、不搬进插件 ③ 系统级能力(起实例 / 沙箱 / 网络编排)不可插件化 ④ 权威必须唯一 —— 判决者(谁托管谁、谁能进、谁是设备)不能由被判决的一方自己选(双写 = 脑裂 ⇒ 数据损坏)。

🟡 唯一待拍板项(仍等你定):「设备要不要获得读取平台插件包的权限」—— 它决定"轻节点当内容副本 / 设备当消费者"这条路走不走得通。


13 追问:只装官方 DSH + 加我们的插件,能不能拿到 L1 与 L2?(2026-09-26 08:2x)

用户原话:「用户只需要安装一个官方的 DSH 主程序,然后把我们的插件加进去就能实现 L1 和 L2 的功能,然后用户登录这个功能去使用相应的能力和模块。」

13.1 判定(逐条)

用户的三步 判定
只装一个官方 DSH 主程序 ✅ 可行 —— 这正是平台节点用户的现有形态(官方主程序 + 注入层 + 插件)
把我们的插件加进去 ✅ 可行 —— 官方本来就有插件安装命令与来源机制;我们要做的只是提供一个可安装的包地址
就实现了 L1 与 L2 的功能 ⚠️ L2 全部 ✅;L1 是"使用面"✅、"实现面"❌ 不搬过来(见 13.3-2)
用户登录这个功能去使用相应能力 ✅ 可行 —— 登录可以就做在这个插件里(服务端半做登录界面 + 存凭据 + 校验)

13.2 ⚠️ 更正我之前的三句话(诚实,具名)

我之前说 在这个形态下的更正
「登录必须在插件之前,做成插件会死锁」 🔴 在"官方 DSH 当宿主"下不成立:官方页面先渲染,插件在里面提供一个登录/身份区块 ⇒ 登录由插件提供完全可行。原论证的前提是桌面自研壳的既定形态(壳要决定"进实例页还是登录页")—— 换宿主,前提就变了
「必须有薄壳 + 引导层」 🔴 本形态下不需要自研壳:官方 DSH 自己就是引导层。用户装官方程序 + 装插件,就够了
「拉取器必须在引导层,⛔ 不能进插件」 🔴 收缩为"只在首装时成立":第一次装上来需要一个安装动作;此后所有更新都可以由插件自己做(插件拉新包 → 换装配 → 提示重启)⇒ "插件更新 = 功能更新"在首装之后成立 —— 这正是用户要的效果

13.3 三条硬约束(不满足就不成立)

  1. 首装包必须匿名可取(不能要求先登录,否则才是真死锁)⇒ 需要一条公开的包分发渠道。⚠️ 因此我之前说的「未登录 = 既没功能也没代码」只对后续增量包成立,对首装包不成立。
  2. L1 只是"被使用",不会搬到用户机器上:多租户编排、沙箱隔离、配额、中继服务器、协作内核这些是服务器角色,继续在平台侧跑;插件是客户端。⇒ 用户机器上不会有"一个小平台",只会有一个通往平台的入口。
  3. 系统级能力仍不可插件化:要在用户机器上跑"平台服务器那套"(容器/沙箱/多租户/端口)需要系统权限 ⇒ 插件给不了(且平台已定"不开端口")。⇒ 想"本地全自足"属另一个产品形态(单机/私有部署),不是这个插件。

13.4 这个形态的得失(诚实,供推翻)

得:⛔ 不再需要自研客户端 ⇒ "客户端更新 = 插件更新" 100% 成立;成本最低;用户只装官方程序。 失:① 界面受官方槽位限制(你看到的是官方界面 + 我们加进去的能力 —— 其实正合"与服务器版本一致"的口径);② 官方接口升级时插件要跟;③ 实例的启动策略(自启、离线兜底、窄档响应式)由官方决定,我们插不上手 —— 这正是桌面线当初自研壳换来的东西。 ⇒ 判据:若接受"用户看到的是官方 DSH 界面、能力由插件加进去",则此形态是最优解,而且它已经是平台节点用户的现有形态(把同一套插件发给单机用户即可)。

13.5 落地清单(补 5 件,逐项标状态)

# 事项 状态
1 把"基础服务插件"做成一个可安装包(服务端半 + 界面半) 🔜 新做
2 公开可取的首装渠道(匿名) 🔜 新做(共享包库可复用,需加一条匿名首装口)
3 插件内的登录与身份态(登录界面 + 存凭据 + 校验) 🔜 新做(平台侧登录与设备授权接口已具备)
4 入网拨号放进插件(异步拉起拨号子进程,走 443 拨出) 🔜 可做:无需 root、无需新端口;⚠️ 与桌面线"网络载体是原生守护"不冲突——那是桌面壳口径,此处宿主是官方 DSH
5 插件自更新(拉新包 → 换装配 → 提示重启) ✅ 机制已就绪(本会话)+ 落点从引导层移进插件

14 追问:一个插件,用户装完后自选角色 —— 「当节点提供服务」还是「只当用户设备接入」?

用户原话:「用户在 DSH 主程序上加入插件后,他可以选择去当节点提供服务,还是可以选择自己只是一个用户设备去接入。」

14.1 判定

⚠️ "二选一的界面"可以做成插件;但"当节点"能不能成,不由勾选决定 —— 由别人能不能连到你 + 平台放不放行 决定。

角色 插件内能不能承载 卡点
用户设备(终端) ✅ 能,且已跑通 全程只拨出(走 443)⇒ 无需端口、无需 root;设备授权接口已在生产
轻节点(提供中继 / 带宽 / 内容副本) ✅ 能(插件可异步拉起守护子进程) ⚠️ 硬卡点 = 入向可达:别人得能连到你(NAT / 防火墙);同局域网零门槛。且走半自动升格(候选池 → 平台放行),⛔ 不是本地开关
重节点(替别人跑实例、承载他人数据) ❌ 不能靠插件 需要系统级隔离(容器 / 沙箱 / 独立账号)+ 常驻系统服务 ⇒ 属正式节点部署(原生守护 / 系统服务),不是插件能兜的

14.2 三条判据(为什么"选择"≠"生效")

  1. 物理判据优先于意愿:当节点 = 提供服务 = 别人能连到你。这是网络事实,插件只能探测并上报。平台既有口径:升格判据 = 入向可达实测。
  2. 平台放行是第二道门:节点提供的是对外能力(别人的流量 / 负载交给你)⇒ 必有治理:白名单(默认拒绝 ⇒ 加节点是平台侧配置动作)、上限(升格真上限 8 条)、半自动升格。⇒ 插件侧能做的只有「体检 → 上报候选 → 等放行」。
  3. 隔离是第三道门:若节点要承载他人实例,必须有沙箱与独立账号(Linux 上是 bubblewrap 那一套,要 root 级部署)⇒ 在"用户只装了官方 DSH"的机器上不具备(Windows 上更没有)。

14.3 ⇒ 建议落法:三步升格(选择权在用户,生效权在"网络 + 平台")

步 谁做 内容
① 体检 插件(本地) 探测入向可达性 / 带宽 / 是否同局域网 + 报告本机能力 ⇒ 出一张「能不能当节点」的体检单
② 申请 插件 用户主动点「申请成为节点」⇒ 体检单交给平台
③ 放行与下发 平台 半自动升格:放行 → 下发节点配置 → 插件按配置切换角色

⭐ 一个额外好处:单插件双角色 ⇒ 用户装一次、先当普通用户,条件成熟再升格 ⇒ 与既有「半自动升格」口径天然吻合,⛔ 不需要为节点另做一套客户端。

14.4 两个必须点名的代价

  1. 对外承诺与责任:当节点 = 你的机器承接他人的流量 / 数据 ⇒ 这是治理与责任问题,不是技术选择 ⇒ 界面上必须写清"当节点意味着什么",且必须能撤销(撤回授权即失效 —— 与设备授权同源)。
  2. "看起来能开其实开不了"的风险:若插件里直接放一个"当节点"的开关,而多数家用网络根本不可达,用户会以为平台坏了。⇒ 必须先体检、再显示;⛔ 不给假的可用开关(本平台反复踩过的一类事故:把"未知"显示成"已启用")。

14.5 与本会话已落地机制的衔接

  • 节点当「内容副本 / 分发源」不需要系统级隔离 ⇒ 这是插件可承载的节点形态之一,且与本会话落地的版本管理与拉取机制直接衔接(节点本来就在拉包)。
  • 设备当「内容消费者」⇒ 对接单已交付(AI1Net Desktop 工作区)。
  • 默认形态 = 终端(平台已定「先不开端口」);节点能力按需开,与覆盖网络线口径一致。

14.6 不确定项(⛔ 不假装确定)

  1. 「轻节点」具体提供哪些服务(中继 / 带宽 / 副本 / 只是在线心跳)—— 属业务目标,需你定方向后再设计;本件只判"能不能承载"。
  2. 家用网络下的真实可达率未取数;体检单的判据与阈值需实测标定。

15 追问:节点归属可选场景(47 当节点,其他用户可选"成为节点"或"接入某节点"如 106 接入 47,接入后即可用该节点功能与其提供的三方插件)

用户原话:「47服务器就是一个节点它加入了这个插件后,就可以选择成为一个节点。其他的用户加入了这个插件后也可以选择成为节点,也可以选择接入某个服务(106接入47)。接入后就可以使用节点对应的功能和提供的三方插件。」

15.1 判定:要把"接入"拆成三种,否则会得出一半对一半错的结论

「接入」指什么 现状对应什么 用户能自选吗
A 内容归属(从哪个节点拉插件与能力) 节点侧的拉取源地址 + 身份 + 对方放行 ✅ 能,且已实测跑通(106 接入 47:2 MB / 3,437 ms,就是本会话验的)
B 网络归属(属于哪个网络、走哪条中继) 覆盖网络:组密钥 + 中继候选 + 设备授权 ✅ 能(同局域网零门槛;跨公网需对方可达)
C 承载归属(实例跑在哪台机器上) 平台编排 + 沙箱 + 实例 home 与数据 ⚠️ 不能"一键切":它是有状态的(数据/文件都在原机)⇒ 切换 = 迁移;且当承载体需系统级部署

15.2 一句话结论

"插件内选角色 + 选接入谁"这个形态可行 —— 因为平台本来就是控制面联邦(每个节点自带内容源与承载体),"接入谁"在协议上就是一个可切换的归属。 但可自由切换的只有"无状态归属"(A 内容 / B 网络);"实例落在哪台机器"(C 承载)是有状态归属,只能迁移、不能切开关。

15.3 现状已经有的(⭐ 大部分构件已在生产上跑着,⛔ 别重造)

  • A 内容归属:已上机(本会话的节点拉取机制;106 → 47 实测)。
  • B 网络归属:已实测(登录 → 设备凭据 → 拨号入网;租约 24 h)。
  • 准入治理:中继/节点白名单默认拒绝 ⇒ 加节点 = 平台侧配置动作;半自动升格 + 上限。
  • 归属判据三条(⛔ 不许破):① 归属与租约只有 Manager 能写(双写 = 脑裂)② 跟用户走 ⇒ 实例 home ③ 本机运维 ⇒ Worker 本地库。

15.4 四条必须点名的

  1. 🔴 "节点"不等于"插件":节点 = 服务进程(我们那套服务)+ 插件两端;插件是节点的开关与入口,⛔ 不是节点本身。⇒ 「47 加入插件后成为节点」的准确表述是:47 侧本来就在跑服务,插件让它"可被选为接入点";只装插件不跑服务 ⇒ 它只是个客户端。
  2. 🔴 归属必须排他:一个实例/设备只能属于一个承担体(否则脑裂/双写)⇒ "用户自选"要落在一个明确归属上;切换 = 按迁移处理(不是改个开关)。
  3. 🔴 信任链:接入某节点 = 把"用谁的内容"交给它 ⇒ 包签名校验从"要件"升为必需(否则"接入"就等于"允许对方往你机器里塞代码")。跨线议题,本线只登记。
  4. ⚠️ 跨区可见性默认会被这条推翻:现状倾向"各区互不可见";若允许用户自由接入任意节点 ⇒ 该默认必须重新明确(属覆盖网络线口径)。

15.5 建议的最小可行版本(三步,与上一轮的"三步升格"同形)

步 内容
① 插件内"接入点选择" 列出可用节点 + 本地体检(可达性/带宽)+ 用户点"申请接入"
② 平台放行并下发归属 放行 → 下发内容源归属(A)+ 网络凭据(B)
③ 插件按归属切换 A / B 立即可用;C(承载)留到有迁移方案再开,⛔ 不先开"看起来能选其实切不动"的入口

15.6 不确定项(⛔ 不假装确定)

  1. 跨节点迁移(C)的机制未设计 —— 实例 home 搬迁属"不可逆操作"级的事,需单独立项。
  2. 「节点提供服务」的具体服务清单仍未定(与上一轮 §14.6-1 同一项)。
  3. 家用/机房网络的真实可达率未取数 ⇒ 体检判据与阈值要实测标定。

16 追问:「为什么不行」逐层拆解 —— 并把「当节点」拆成 Manager / Worker 两半(2026-09-26 09:0x)

用户原话:「还没有弄明白继续分析,为什么不行 1、选择当节点:还包括区分 manager 和 worker」

承上:§15 的结论是「承载归属 ⚠️ 不能一键切」。本节回答到底卡在哪一层,并补上用户新点出的「Manager / Worker 之分」。 ⚠️ 本节结论全部有代码级依据(文件名 + 机制名),⛔ 不是推演。

16.1 先把「节点」拆开 —— 它其实是两个进程、两个身份

Manager(控制面 · 判决者) Worker(承载体 · 执行体)
它是什么 平台的唯一权威:决定"谁托管谁、谁能进、谁是设备" 只负责"在这台机器上把实例起停好"
自己有库吗 ✅ 有(唯一权威库:用户/会话/工作区/实例归属与租约/插件池/域名/凭据/审计/网络) ❌ 没有 —— src/worker/ 全目录零 DB 引用(本次实测,非推测)
地址面 域名 + 证书 + 门户 + nginx + 向中继注册的拨号身份 一个内部 HTTP 服务,只被 Manager 拨入
对外动作 全平台 只有四个白名单动作;单向拨入 —— 不反连、不写控制面数据
怎么防双写 判据的唯一落点:原子 CAS + epoch(fencing token) 收到更高 epoch ⇒ 主动停掉该实例(self-fencing)
47 上是什么 dshs 进程 dshs-worker 进程(w-47)—— 同机、两进程、两身份

🔴 所以「47 是个节点」这句话本身就把两半压成了一半。 47 之所以"是个节点",是因为它同时跑了这两半。

依据:src/worker/agent.ts(模块头「它不做归属决策」+四条协议纪律)|src/db/schema.ts v7 集群化注释(为什么必须落 DB 原子 CAS、epoch 是 fencing token、抢占语义)|src/supervisor/lease.ts(三条不变量:单写者 / TTL>2×续租 / fencing 必须自杀)。

16.2 「选择当节点」⇒ 只能选 Worker 那一半

你想选的 能否由用户自选 为什么
当 Worker(出机器、承载实例) ✅ 能 它无库、不做归属决策,只是执行体 ⇒ 天然可水平增加、可替换
当 Manager(出权威) ❌ 不能 三条理由见下

为什么 Manager 那一半不能自选

  1. 🔴 它是"判决者",判决者不能由被判决的一方自己选出来。 现有防双写机制(原子 CAS + epoch fencing + 租约)整体假设只存在一个判决者;出现第二个 = 对同一份数据各写一次 = 脑裂,而脑裂的下游后果是"两个进程同时写同一个实例的家 ⇒ 会话日志 append 冲突 ⇒ 数据损坏"(schema.ts v7 注释原话)。
  2. 🔴 它同时是"引导层"。 插件装在实例里,而实例是 Manager 起的 ⇒ Manager 不可能由插件提供(与 §10 那条"包还没装、服务已经要跑"同一判据)。且本版平台没有"实例 → 平台"的身份通道,实例的入网凭据是控制面代签的(fs/user-fs.ts 明确写了)⇒ 签发者只能在上层。
  3. 🔴 换 Manager = 换锚点,下游全部要跟着改。 域名与证书、门户入口、nginx、向中继注册的拨号身份(hostId 必须同时在该中继的密钥文件与白名单里)、设备授权签发者 —— 客户端认的地址都变了。这不是"配置项",是换了一个平台。

⇒ 一句话:「当 Worker」是自选角色;「当 Manager」是换控制面(= 另一套部署、另一种治理关系),⛔ 不能做成插件里的一个开关。

16.3 「接入后连实例一起用」为什么不行 —— 卡在四个物理事实上

# 事实 依据
1 实例的"家"是那台机器上的绝对路径,不是平台上的一个逻辑对象 fs/user-fs.ts 注释:⛔ 不许直接读该路径 —— 实例在别的机器上时,平台侧只会读到一个不存在的位置,返回空串而不报错(2026-09-19 实测:托管清单被清空、目标文件一个字节没动)
2 实例在 OS 层的真实载体是 systemd scope(形如 dsh-<uid>-<hash>.scope),启动参数就在 scope 描述里 supervisor/orchestrator.ts:「实例真实生命周期在 OS 层(systemd scope)」+ scope 名与 --reuid <uid> 交叉验证
3 实例的网络位置是全局分配的资源:端口按 worker 划互不重叠区间,而所有跨机隧道落点全挤在 Manager 的 127.0.0.1 supervisor/spawn.ts findFreePortInRange 注释:⛔ 用 listen(0) 会让两台 worker 撞号,ssh -R 失败被静默忽略 ⇒ Manager 仍按该端口拨 ⇒ 打到别人的实例(2026-09-16 实测)
4 实例还带着一串机器绑定的身份:Linux uid(每用户一个)、cgroup 内存配额、防火墙放行、到 Manager 的入向可达 isolation.ts(每用户确定性 uid)|orchestrator.ts(MemoryHigh 软限 + MemoryMax 硬限,V8 堆按配额推导)|supervisor/firewall.ts|net/reachability.ts(无可达信息即拒绝,不静默降级)

⇒ 「切换承载归属」等价于一次迁移,动作序列至少是:停实例 → 搬 home 与数据 → 在目标机按它的 uid/端口区间/配额重建 scope → 改归属行(host_id)→ 老机 self-fence。 这不是"改开关",是"不可逆操作级"的动作 ⇒ ⛔ 不先开"看起来能选、其实切不动"的入口(与 §15.5-③ 同款纪律)。

16.4 「接入」的正确切法(把 §15 的结论落到角色上)

用户动作 对着哪一半 判定
装插件 → 选"只当用户设备" 都不是 ✅
装插件 → 选"当 Worker(当节点)" Worker ✅ 能,但要有入向可达 + 平台放行(白名单默认拒绝)
装插件 → 选"接入某节点(用它的内容)" 内容归属 ✅ 已实测(106 → 47:2 MB / 3,437 ms)
装插件 → 选"接入某节点(进它的网)" 网络归属 ✅ 能(同局域网零门槛)
装插件 → 选"把我的实例挪到某节点跑" 承载归属 ⚠️ 只能迁移,见 16.3
装插件 → 选"我来当 Manager" Manager ❌ 不是角色,是换控制面,见 16.2

16.5 不确定项(⛔ 不假装确定)

  1. 迁移(承载归属)的机制未设计 —— 与 §15.6-1 同一项,需单独立项。
  2. "当 Worker"的准入门槛未标定 —— 入向可达率、带宽、沙箱后端版本(实测 47 与 106 的 bubblewrap 版本不同)等体检项的阈值要实测。
  3. 多 Manager(控制面联邦)的治理口径仍在覆盖网络线 —— 本节只回答"能不能由用户一键选",⛔ 不替代那边的架构定稿。

附 · 盘点来源(单一来源,⛔ 不复制正文)

  • 平台自己的路由清单:D:/github/dsh_shenxian/src/web/routes/(auth · admin · admin-user-ops · whitelist · business-plugins · plugin-data · skills · sessions · desktop · dsh · domain · im · overlay · overlay-device · overlay-nodes)。
  • 平台自有服务各层:src/supervisor/(12)· src/fs/(6)· src/im/(12)· src/db/(10)· src/net/ · src/worker/(3)· src/isolation.ts · src/config.ts · src/crypto.ts · src/platform-paths.ts · src/nginx/。
  • 形态与先例:E:/ProgramData/AIProject/dsh-ai1net-desktop/MEMORY.md §1(乙方案、"零 UI"口径)+ docs/S12_…_20260925.md §9。
  • 本会话机制与对接单:交付物/版本管理与包更新机制-执行报告-20260926.md · 交付物/平台能力插件化-形态判定与分层_20260926.md · E:/ProgramData/AIProject/dsh-ai1net-desktop/docs/对接单_桌面端接入版本管理与包更新机制_20260926.md。
  • 本件的两个成品下游(⛔ 本文只做分析,判定以它们为准):交付物/基础服务插件-能做不能做总清单与拍板路径-20260926.md(能做什么/不能做什么 + 拍板台账 P1–P4)· 交付物/节点与端-互联互通与调用关系-20260926.md(节点与端全表 + 三个门 + 联通矩阵 + 数据/实例/插件四层关系)。