Why: U0 (merged in RDM) rules that domain logic stays downstream and the base needs seven minimal generic capabilities; the formal four-element applications are the only legal path to base changes. Evidence: All current-state citations re-verified at Dev 34a2bbe (backend fe7c245); RDM requirement source pinned at RDM main ca72cfc. Impact: New proposal doc + one INDEX row; no code, no surface change in this PR. Refs: RDM U0 proposal section 5 / ruling D1; extension-compat-policy; phase-plan section 3.3.
13 KiB
13 KiB
EXT 申请包 · C1–C7:RDM 多人共享契约的基座最小扩展(EXT-6…EXT-12)
| 项目 | 内容 |
|---|---|
| 状态 | proposed(2026-10-08);owner:weichen;任务:Dev feature/ext-c1-c7-applications |
| 性质 | 扩展点申请包(extension-compat-policy 流程第 2 步:基座侧评审)。本文只立申请,不实施;各 EXT 实现另立任务卡 |
| 需求依据 | RDM 仓 U0 主记录 docs/proposals/2026-10-08-U0-baseline-and-shared-contracts.md §5 契约 C1–C7(RDM main ca72cfc 已合入,含 D1–D9 裁定);来源=用户 2026-10-08 会话批准的 U0 实施计划 |
| 现状证据 | 均为 SELF·源码级,引用对象:Dev 34a2bbe(backend gitlink fe7c245);RDM pin backend cb26e4c(v0.1.0)相同结论者已注明。运行态 NOT_RUN |
| 编号 | 按既有序列(EXT-1/3/4/5 在案)顺延 EXT-6…EXT-12;最终编号以受理评审为准 |
0. 总则
- 推荐路线(U0 裁定 D1,修订 V2.1 草稿 J-09「基座不改动」):领域规则(成员、角色、三权、 发布状态)住 RDM 下游仓;基座只补通用、无领域词汇的最小扩展面。每条申请遵守 INV-2: 基座代码与 diff 不出现 RDM 领域字样,全部以「资源授权/受管配置/投影过滤」等通用语义表述。
- 事实依据(为何纯下游组合不出来):基座一切资源访问按 owner 硬边界
(
internal/store/projects.go:22-34),EXT-1 Host 强制 owner 归属且无知识删除/更新 (pkg/extension/host.go:43-46、internal/app/hostcaps.go:101)。RDM 增加成员表不能改变 基座过滤;给每人复制知识库被 U0 §4 明确禁止。 - SurfaceVersion 影响:EXT-6/7/9 触及
pkg/extension导出面(Registry/Options/Host 方法), 属加法变更——按 extension-compat-policy 升 SurfaceVersion(2.0.0-experimental 内加法, surface.txt 同步);EXT-8/10/11/12 为 internal/HTTP 行为扩展,不动导出面。 - 分期建议(对齐 U0 §10):EXT-8(授权适配器)与 EXT-9(索引发布)为序 4「项目范围与 授权基础」的硬前置;EXT-6/EXT-12 支撑序 4–5;EXT-7/EXT-10 可随后。EXT-8 建议最先评审。
- 通用默认不变量:每条扩展的缺省行为=现状(未注册/未配置时与今日基座完全一致), RDM 产品部署显式启用;通用基座与既有下游不受影响。
1. EXT-6(←C1)可信身份:账号停用与会话吊销
- 场景:RDM R01 唯一管理员移交后旧凭证须立即失效;成员移除同理。现状基座账号只有
创建/改密/列表(
internal/server/accounts.go:184-261),无停用语义,撤销账号后其 API key 与会话仍有效到自然过期。 - 期望公开面:①
POST /api/admin/users/{owner}/disable|enable(requireAdmin 保护); ②users 表加disabled布尔(迁移,default false);③认证链(API key 校验与会话校验,internal/server/auth.go:29-64)与requireAdmin拒绝 disabled 账号并吊销其在途会话。 「全局唯一管理员」由 RDM 产品策略约束(部署约定+台账),不强制基座单管理员。 - 为何组合不出:无任何现有端点或设置键能改变账号认证状态;RDM 无法经 EXT-1 Host 触达 认证层(Host 无账号域能力,也不应有一—属平台面)。
- 兼容方式:纯加法(新端点+新列 default false);未停用=现状。SurfaceVersion 不变 (不动 pkg/extension)。
- 验收:停用后该账号 API key 与 cookie 即刻 401;管理员功能不受影响;启用可恢复。
2. EXT-7(←C2)受管系统配置:最终生效值受策略约束
- 场景:RDM R01——模型端点/密钥、工具上限、系统插件由管理员控制;个人偏好保留。现状
设置链
defaults → system(启动注入) → user → project(internal/settings/settings.go:131-147), user/project 可覆盖一切;system 层不落库且组合根只注入 dataDir (internal/app/app.go:130)——只藏设置页或只禁今后写入都处理不了既有覆盖。 - 期望公开面:①
extension.Options增受管注入:ManagedSettings map[string]any(键集+ 值,由宿主二进制启动注入);②设置服务按受管键集跳过 user/project 覆盖(Effective 尊重 策略);③受控键的 user/project 写入返回结构化拒绝并附依据;④GET /api/settings标注 哪些键受管。RDM 在自有二进制 main 里以管理员配置注入。 - 为何组合不出:Options 无注入口;
SetSystemOverride是组合根私有;下游无法让 Effective 忽略 user/project 的既有覆盖。 - 兼容方式:
ManagedSettings缺省 nil=现状(无受管键,行为不变);pkg/extension Options 加字段=导出面加法,SurfaceVersion 与 surface.txt 同步升。 - 验收:预置 user 覆盖的受控键,注入策略后生效值=受管值;普通用户写受控键被拒且
GET /api/settings可解释;未受管键的个人偏好不受影响。
3. EXT-8(←C4)资源授权适配器:项目共享的读取通道 ⭐关键路径
- 场景:RDM R03/R04/R05——成员 B 依 RDM 成员表读取成员 A 提交的项目资料(工件原件、
检索、引用、下载、图查询);撤销后停止。现状一切资源入口按 owner 过滤
(
internal/store/projects.go:22-34;工件/知识/卡片同理),Host 读取族同样强制本人 owner(pkg/extension/host.go:43-46)。 - 期望公开面:①基座提供授权适配器注册点(HTTP 组合根):
RegisterResourceAuthorizer( func(owner, resourceProjectID core.ID) (allow bool, err error))形态的进程内回调,经extension.Options或 Registry 注入(具体挂点评审定);②资源入口(项目/工件/知识检索/ 卡片读取的 HTTP 层与 Host 读取族)在 owner 自有判定未命中时回调适配器:返回 true 则按 「项目共享」放行,false/未注册=现状 NotFound(不泄露存在性);③适配器只回答布尔, 不接触基座内部状态;④放行日志入审计(owner×resource×decision)。 - 为何组合不出:owner 过滤在 SQL 层硬编码;无任何回调或配置可改变跨 owner 可见性; 回环 HTTP 模拟他人身份被认证中间件阻止(V1.1 教训,10 号方案已证)。
- 兼容方式:未注册适配器=现状零差异;回调失败按拒绝(fail-closed)。pkg/extension 加法→SurfaceVersion 升。注意:本 EXT 使基座首次具备跨 owner 授权读取语义,评审须 重点核对回调契约的最小性(仅 owner×projectID 两参,不透出对象细粒度——细粒度由 RDM 在自己的命令层做)。
- 验收:同项目两人+另一项目一人(RDM 成员表桩):共享资源四入口(原件/检索/引用/下载) 一致放行;跨项目与替换引用拒绝且 NotFound 不泄露;撤销成员后新访问立即拒绝;审计可查。
4. EXT-9(←C5)索引发布与撤销:留存 ≠ 可检索
- 场景:RDM R07——存疑资料确认前不得进入任何正式检索;发布有稳定版本、撤销即时生效。
现状基座上传端点在下游相关性判定之前即写检索索引
(
internal/server/server.go:1039-1046;RDM pin 相同);Host 知识面只有KnowledgeWrite(强制 owner),无删除/更新(pkg/extension/host.go:43-46)。 - 期望公开面:①基座上传预索引开关(
Options或项目设置键uploads.autoIndex,缺省 true=现状;RDM 部署关闭,索引决定移交其命令层);②Host 增KnowledgeDelete(owner, sourcePrefix string, versions …) / KnowledgeUpdate(或等价发布令牌语义:写入带稳定PublishID,删除按 PublishID 幂等);③删除仅作用于插件来源(Source前缀plugin:<id>),公共 manual 来源不可被插件删。 - 为何组合不出:检索索引无删除面;上传索引行为硬编码;RDM 无法撤回已入索引的存疑内容。
- 兼容方式:开关缺省现状;Host 删除方法为导出面加法(surface.txt/SurfaceVersion 同步)。
- 验收:相关/存疑/拒绝三份样本:仅获准发布版本可检索;重试不重复建索引;撤销后检索与 上下文注入立即停止(含 Host 读取族);manual 来源不可删。
5. EXT-10(←C3)分发前校验钩子与会话归属
- 场景:RDM R18——对话/按钮/卡片/API 四入口同源且对象-会话-项目关联可校验;旧卡片/
重复确认不得操作新版本。现状
POST /api/commands/{id}不校验 conversationId 归属 (internal/server/server.go:823-836),确认卡锚定客户端自报会话 (internal/cmdbus/cmdbus.go:294-316);插件命令注册不写 slash 别名,对话入口不可达rdm.*(cmdbus.go:145-153,v0.1.0 与 main 同——阶段总案 §2.3 已登记)。 - 期望公开面:①分发前校验钩子:
RegisterDispatchGuard(func(owner, conversationID string) error)(未注册=现状放行;RDM 注入「会话属该项目且属于该 owner」判定);②RegisterPluginCommand增可选 slash 别名参数(或 manifest 字段),对话入口/rdm.*可解析;③别名与 intents 命中路由到插件命令的打通(阶段总案既有缺口,并入本 EXT 或 单列由评审定)。 - 为何组合不出:execCommand 对 conversationId 零校验也无回调点;slash 表只由内置与
用户命令登记写入(
cmdbus.go:109-127),插件路径不写。 - 兼容方式:钩子/别名均缺省=现状;internal 行为扩展为主(Registry 签名若变则属 pkg/extension 加法,SurfaceVersion 升)。
- 验收:伪造他人会话/项目引用的命令被拒;
/rdm.ping在对话入口可达且回执与按钮入口 同源(同一审计信封);陈旧卡片确认不生效(既有 ErrNotAwaiting 之上叠加对象版本校验)。
6. EXT-11(←C6)按 owner 重建受限 Host:后台任务恢复
- 场景:RDM R10/R21——慢任务跨重启不丢不重;撤权后不越权续跑。现状 RDM 慢通道是进程
内存队列并把分发时 Host 句柄留在队列(RDM
internal/rdmapp/slow.go:53,66,重启即丢、 撤权不重验);基座任务台账仅记账(pkg/extension/host.go:48-50)。 - 期望公开面:基座侧缺口小——提供「按 owner+pluginID 构造受限 Host」的公开工厂
(如
extension.NewScopedHost(owner, pluginID)形态或 Registry 上的查询),供下游在 恢复任务时重建执行上下文;任务体、输入版本、幂等与重验策略由 RDM 自管(U0 §7)。 不序列化旧 Host——重建受限上下文,天然以当前权限为准(配合 EXT-8 的授权适配器, 撤权即拒绝)。 - 为何组合不出:inprocHost 是 internal 类型按分发请求私有构造
(
internal/app/compiled.go:42);下游无任何入口可在分发期之外获得合法句柄。 - 兼容方式:纯加法工厂函数;不改变分发期语义。pkg/extension 加法→SurfaceVersion 升。
- 验收:下游以工厂重建的 Host 执行读/写,owner 作用域与分发期一致;重启后同任务不重复 执行(RDM 侧幂等)+ 撤权后重建 Host 的读取被适配器拒绝。
7. EXT-12(←C7)卡片/事件投影过滤:私人事件与公共投影分离
- 场景:RDM R04/R18——私人会话卡不得进项目公共流;公共投影只含获准发布的状态;撤权
后重放不泄露。现状会话卡全量镜像到项目频道(
internal/cardsvc/cardsvc.go:41-60, 注释自述「全量镜像换取口径简单」)——单 owner 下无害,多人项目即隐私泄露路径。 - 期望公开面:卡片镜像策略可配置:①按卡属性过滤(kind/来源)的内置开关,或②复用
EXT-8 适配器语义的投影可见性回调(
func(owner, card) bool)——评审择一,倾向①最小。 RDM 部署关闭会话卡镜像,只用项目级卡承载公共投影。 - 为何组合不出:emitCard 镜像逻辑硬编码;无配置面。
- 兼容方式:缺省=现状全量镜像;internal/设置键扩展,不动导出面。
- 验收:关闭镜像后会话卡仅出现在本人会话流;项目流只含项目级卡;既有单用户部署行为 不变;SSE 重放遵循同一过滤。
8. 不在本申请包(显式排除)
- 需求条目化/模板/法规双通道/三权流程等 RDM 领域能力(U0 §2 R08–R16)——全部住下游。
- 飞书渠道 EXT-3:既有在案申请,节奏不变(MS4 前)。
- 命令审计跨租户修复:不是扩展,是缺陷修复,已另行(Backend PR #104 + Dev PR #262)。
9. 受理建议
| EXT | 前置的 U0 序 | 建议评审优先级 | SurfaceVersion |
|---|---|---|---|
| EXT-8 授权适配器 | 序 4 硬前置 | P0 最先 | 升(加法) |
| EXT-9 索引发布/撤销 | 序 4 硬前置 | P0 | 升(加法) |
| EXT-6 账号停用 | 序 4–5 | P1 | 不变 |
| EXT-11 Host 工厂 | 序 4 | P1 | 升(加法) |
| EXT-10 分发守卫/别名 | 序 3 剩余半边(基座侧) | P1 | 视形状 |
| EXT-7 受管配置 | 序 4–5(R01) | P2 | 升(加法) |
| EXT-12 投影过滤 | 序 5 | P2 | 不变 |
每条受理后按 extension-compat-policy 走「基座任务卡实现→发版→RDM 升钉」;预计随 v0.2.0 之后的 v0.3.x 分批落地(对齐 RDM 阶段总案 §3.3 与风险 R-5)。