- 变更规模:新增 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/ 知识文件,按口径入库)
33 KiB
平台新增功能总盘点 × 插件化归属("基础服务插件"能不能做、能装哪些)
回答的问题(用户原话):「把现在开发的平台基于 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 件,全在引导层)
- 起实例(把官方宿主进程跑起来)
- 起窗口 / 渲染首屏
- 取身份(登录 + 设备授权 —— 必须早于插件)
- 把包拉下来并装进去(含它的版本管理与拉取器)
+ 服务器侧服务(多租户编排、隔离、协作内核、中继、门户、运维)—— 它们不是"不能进插件",而是"本来就不依赖 DSH"(官方没有账号体系 ⇒ 这部分从第一天就是我们的独立进程)。⛔ 把它们算作"插件的候选"是范畴错误。
11 一处我不建议,但可推翻
门户六页(含登录页)不要搬进插件。 理由:桌面线已定的口径是「套壳 + 同步服务器代码」「UI 与服务器版本一模一样」—— 门户是服务器页面,浏览器里就是它。若在插件里再实现一份,就会出现两份 UI,此后每次改页面都要改两处、必然漂移(属负向迭代)。⇒ 建议:门户保持服务器页面,插件只做入口与内嵌。
12 收益预期与不确定项(照实说)
收益预期:把 §4–§8 标 ✅ 的收进一个基础服务插件 ⇒ 客户端里"能改的功能"约九成都随插件更新,不必重发安装包;剩下的引导层(§10 四件)建议冻结到最薄,因为它一变就要重发安装包。
不确定项(⛔ 不假装确定):
- 本盘点由路由与目录清单 + 在册记录归纳而成,未逐行复核每个功能;若某行要驱动开工,先补该行的最小取证(具名到文件与行号)。
- 表格里 ⚠️ 的拆分("界面可进 / 动作不可进")是按判据推演的,仍需在实施时逐条落到扩展点上验证。
- 「约九成」是按功能组计数的粗估,不是行级精算。
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 三条硬约束(不满足就不成立)
- 首装包必须匿名可取(不能要求先登录,否则才是真死锁)⇒ 需要一条公开的包分发渠道。⚠️ 因此我之前说的「未登录 = 既没功能也没代码」只对后续增量包成立,对首装包不成立。
- L1 只是"被使用",不会搬到用户机器上:多租户编排、沙箱隔离、配额、中继服务器、协作内核这些是服务器角色,继续在平台侧跑;插件是客户端。⇒ 用户机器上不会有"一个小平台",只会有一个通往平台的入口。
- 系统级能力仍不可插件化:要在用户机器上跑"平台服务器那套"(容器/沙箱/多租户/端口)需要系统权限 ⇒ 插件给不了(且平台已定"不开端口")。⇒ 想"本地全自足"属另一个产品形态(单机/私有部署),不是这个插件。
13.4 这个形态的得失(诚实,供推翻)
得:⛔ 不再需要自研客户端 ⇒ "客户端更新 = 插件更新" 100% 成立;成本最低;用户只装官方程序。 失:① 界面受官方槽位限制(你看到的是官方界面 + 我们加进去的能力 —— 其实正合"与服务器版本一致"的口径);② 官方接口升级时插件要跟;③ 实例的启动策略(自启、离线兜底、窄档响应式)由官方决定,我们插不上手 —— 这正是桌面线当初自研壳换来的东西。 ⇒ 判据:若接受"用户看到的是官方 DSH 界面、能力由插件加进去",则此形态是最优解,而且它已经是平台节点用户的现有形态(把同一套插件发给单机用户即可)。
13.5 落地清单(补 5 件,逐项标状态)
| # | 事项 | 状态 |
|---|---|---|
| 1 | 把"基础服务插件"做成一个可安装包(服务端半 + 界面半) | 🔜 新做 |
| 2 | 公开可取的首装渠道(匿名) | 🔜 新做(共享包库可复用,需加一条匿名首装口) |
| 3 | 插件内的登录与身份态(登录界面 + 存凭据 + 校验) | 🔜 新做(平台侧登录与设备授权接口已具备) |
| 4 | 入网拨号放进插件(异步拉起拨号子进程,走 443 拨出) | 🔜 可做:无需 root、无需新端口;⚠️ 与桌面线"网络载体是原生守护"不冲突——那是桌面壳口径,此处宿主是官方 DSH |
| 5 | 插件自更新(拉新包 → 换装配 → 提示重启) | ✅ 机制已就绪(本会话)+ 落点从引导层移进插件 |
14 追问:一个插件,用户装完后自选角色 —— 「当节点提供服务」还是「只当用户设备接入」?
用户原话:「用户在 DSH 主程序上加入插件后,他可以选择去当节点提供服务,还是可以选择自己只是一个用户设备去接入。」
14.1 判定
⚠️ "二选一的界面"可以做成插件;但"当节点"能不能成,不由勾选决定 —— 由别人能不能连到你 + 平台放不放行 决定。
| 角色 | 插件内能不能承载 | 卡点 |
|---|---|---|
| 用户设备(终端) | ✅ 能,且已跑通 | 全程只拨出(走 443)⇒ 无需端口、无需 root;设备授权接口已在生产 |
| 轻节点(提供中继 / 带宽 / 内容副本) | ✅ 能(插件可异步拉起守护子进程) | ⚠️ 硬卡点 = 入向可达:别人得能连到你(NAT / 防火墙);同局域网零门槛。且走半自动升格(候选池 → 平台放行),⛔ 不是本地开关 |
| 重节点(替别人跑实例、承载他人数据) | ❌ 不能靠插件 | 需要系统级隔离(容器 / 沙箱 / 独立账号)+ 常驻系统服务 ⇒ 属正式节点部署(原生守护 / 系统服务),不是插件能兜的 |
14.2 三条判据(为什么"选择"≠"生效")
- 物理判据优先于意愿:当节点 = 提供服务 = 别人能连到你。这是网络事实,插件只能探测并上报。平台既有口径:升格判据 = 入向可达实测。
- 平台放行是第二道门:节点提供的是对外能力(别人的流量 / 负载交给你)⇒ 必有治理:白名单(默认拒绝 ⇒ 加节点是平台侧配置动作)、上限(升格真上限 8 条)、半自动升格。⇒ 插件侧能做的只有「体检 → 上报候选 → 等放行」。
- 隔离是第三道门:若节点要承载他人实例,必须有沙箱与独立账号(Linux 上是 bubblewrap 那一套,要 root 级部署)⇒ 在"用户只装了官方 DSH"的机器上不具备(Windows 上更没有)。
14.3 ⇒ 建议落法:三步升格(选择权在用户,生效权在"网络 + 平台")
| 步 | 谁做 | 内容 |
|---|---|---|
| ① 体检 | 插件(本地) | 探测入向可达性 / 带宽 / 是否同局域网 + 报告本机能力 ⇒ 出一张「能不能当节点」的体检单 |
| ② 申请 | 插件 | 用户主动点「申请成为节点」⇒ 体检单交给平台 |
| ③ 放行与下发 | 平台 | 半自动升格:放行 → 下发节点配置 → 插件按配置切换角色 |
⭐ 一个额外好处:单插件双角色 ⇒ 用户装一次、先当普通用户,条件成熟再升格 ⇒ 与既有「半自动升格」口径天然吻合,⛔ 不需要为节点另做一套客户端。
14.4 两个必须点名的代价
- 对外承诺与责任:当节点 = 你的机器承接他人的流量 / 数据 ⇒ 这是治理与责任问题,不是技术选择 ⇒ 界面上必须写清"当节点意味着什么",且必须能撤销(撤回授权即失效 —— 与设备授权同源)。
- "看起来能开其实开不了"的风险:若插件里直接放一个"当节点"的开关,而多数家用网络根本不可达,用户会以为平台坏了。⇒ 必须先体检、再显示;⛔ 不给假的可用开关(本平台反复踩过的一类事故:把"未知"显示成"已启用")。
14.5 与本会话已落地机制的衔接
- 节点当「内容副本 / 分发源」不需要系统级隔离 ⇒ 这是插件可承载的节点形态之一,且与本会话落地的版本管理与拉取机制直接衔接(节点本来就在拉包)。
- 设备当「内容消费者」⇒ 对接单已交付(AI1Net Desktop 工作区)。
- 默认形态 = 终端(平台已定「先不开端口」);节点能力按需开,与覆盖网络线口径一致。
14.6 不确定项(⛔ 不假装确定)
- 「轻节点」具体提供哪些服务(中继 / 带宽 / 副本 / 只是在线心跳)—— 属业务目标,需你定方向后再设计;本件只判"能不能承载"。
- 家用网络下的真实可达率未取数;体检单的判据与阈值需实测标定。
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 四条必须点名的
- 🔴 "节点"不等于"插件":节点 = 服务进程(我们那套服务)+ 插件两端;插件是节点的开关与入口,⛔ 不是节点本身。⇒ 「47 加入插件后成为节点」的准确表述是:47 侧本来就在跑服务,插件让它"可被选为接入点";只装插件不跑服务 ⇒ 它只是个客户端。
- 🔴 归属必须排他:一个实例/设备只能属于一个承担体(否则脑裂/双写)⇒ "用户自选"要落在一个明确归属上;切换 = 按迁移处理(不是改个开关)。
- 🔴 信任链:接入某节点 = 把"用谁的内容"交给它 ⇒ 包签名校验从"要件"升为必需(否则"接入"就等于"允许对方往你机器里塞代码")。跨线议题,本线只登记。
- ⚠️ 跨区可见性默认会被这条推翻:现状倾向"各区互不可见";若允许用户自由接入任意节点 ⇒ 该默认必须重新明确(属覆盖网络线口径)。
15.5 建议的最小可行版本(三步,与上一轮的"三步升格"同形)
| 步 | 内容 |
|---|---|
| ① 插件内"接入点选择" | 列出可用节点 + 本地体检(可达性/带宽)+ 用户点"申请接入" |
| ② 平台放行并下发归属 | 放行 → 下发内容源归属(A)+ 网络凭据(B) |
| ③ 插件按归属切换 | A / B 立即可用;C(承载)留到有迁移方案再开,⛔ 不先开"看起来能选其实切不动"的入口 |
15.6 不确定项(⛔ 不假装确定)
- 跨节点迁移(C)的机制未设计 —— 实例 home 搬迁属"不可逆操作"级的事,需单独立项。
- 「节点提供服务」的具体服务清单仍未定(与上一轮 §14.6-1 同一项)。
- 家用/机房网络的真实可达率未取数 ⇒ 体检判据与阈值要实测标定。
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 那一半不能自选
- 🔴 它是"判决者",判决者不能由被判决的一方自己选出来。 现有防双写机制(原子 CAS +
epochfencing + 租约)整体假设只存在一个判决者;出现第二个 = 对同一份数据各写一次 = 脑裂,而脑裂的下游后果是"两个进程同时写同一个实例的家 ⇒ 会话日志 append 冲突 ⇒ 数据损坏"(schema.tsv7 注释原话)。 - 🔴 它同时是"引导层"。 插件装在实例里,而实例是 Manager 起的 ⇒ Manager 不可能由插件提供(与 §10 那条"包还没装、服务已经要跑"同一判据)。且本版平台没有"实例 → 平台"的身份通道,实例的入网凭据是控制面代签的(
fs/user-fs.ts明确写了)⇒ 签发者只能在上层。 - 🔴 换 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 不确定项(⛔ 不假装确定)
- 迁移(承载归属)的机制未设计 —— 与 §15.6-1 同一项,需单独立项。
- "当 Worker"的准入门槛未标定 —— 入向可达率、带宽、沙箱后端版本(实测 47 与 106 的 bubblewrap 版本不同)等体检项的阈值要实测。
- 多 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(节点与端全表 + 三个门 + 联通矩阵 + 数据/实例/插件四层关系)。