已开启
[Feature]: 应用级产物演进——从静态文件到平台可托管的交互应用(app artifact kind) #121
spaceWing创建于  26 天前
spaceWing
26 天前 创建

🚀 背景描述

1.1 现状:科学产物是静态文件

ScienceDiscovery 目前的产物形态是静态文件:图表(PNG/SVG)、看板(HTML)、数据集(CSV/JSON)、notebook。它们有三个共性限制:

  1. 只能看,不能交互——用户无法在产物上缩放、筛选、联动定位、现场复算;
  2. 数据要么外挂要么内嵌——外挂路径在沙箱预览里不可靠,内嵌则受单文件体积约束;
  3. 产物之间彼此孤立——一个产物看不到另一个产物的数据,跨 run 对比、跨实验聚合都做不到。

我们在开发"ML 训练异常检测"功能时直接撞上了这些限制。

1.2 我们已做的事:把报告做成应用(L1 基线,已实现)

我们把 ML 训练异常检测做成 skill(training-anomaly-detection,v1.7.0)。它的 worker 产出两层 manifest;加 --render 参数时同时产出 report_app.html——一个可交互的报告应用,直接在产物面板既有的 sandbox="allow-scripts" iframe 里运行:

  • 五个标签页:总览(六态结论横幅 + 八张指标卡)/ 交互曲线(白名单 tag 切换、滚轮缩放、拖拽平移、悬停 tooltip、异常事件红色虚线标记)/ 事件表(点击任一事件行,曲线视图跳转并定位到该 step,蓝色定位线停留 3 秒)/ 可信度复算(三个权重滑杆实时演算 judgementConfidence,与实际值对照显示一致或偏离)/ 根因排名(15 条候选根因库,确定性打分,每条候选带"证据 → 推断 → 建议核查"三段推理链)
  • 数据全部内嵌单文件:曲线每 tag ≤20000 点全量嵌入(典型训练 run 是全保真),超出时确定性等距降采样(保首末点)并在数据里显式标注
  • 零网络、零存储:不 fetch、不 XHR、不碰 localStorage——opaque origin 下天然安全
  • 零平台改造:现有 dashboard 预览机制原样可用

我们用与产物面板完全相同 sandbox 属性的 iframe 做过实测:所有交互可用;localStorage 按预期抛异常(opaque origin 行为),而应用从未依赖它。

1.3 我们撞到的天花板(为什么需要平台能力)

  1. 数据量:内嵌形态每 tag 上限数万点。全分辨率多 tag 训练 run(单序列 10 万点以上)被迫降采样,应用内的局部细节有损。
  2. 跨产物查询:一个应用实例只能看到自己内嵌的数据。"把这个 run 与同一实验最近 10 次 run 对比"在没有服务端数据通路的情况下做不到。
  3. 无法写回:用户在应用内做的标注、批注,无法作为结构化数据流回会话。
  4. 无服务端计算:超出内嵌数据的复算(例如用调整后的阈值对原始序列重跑检测器)需要全量数据加计算资源。

1.4 提案内容

我们提议在静态产物与完整服务之间开辟一个应用级产物(app artifact kind):自描述的应用包,平台可托管、可按需运行——带交互、可访问声明的输入数据、会话作用域生命周期——同时保持平台既有的溯源保障不变。

说明:这不是最终 RFC,而是提请社区讨论的方向性提案。设计与开放问题见下节,供讨论定形。


设计思路

2.1 app 产物 kind

新增一种产物类型,打包形态如 .app.zip,包含:

  • 入口文件与静态资源
  • app.manifest.json,声明:
    • 运行时类型:static-host(纯静态托管,无服务端)或 lightweight server(轻量服务端运行时)
    • 入口点
    • 声明的输入产物:以产物 id/版本引用其它产物,只读
    • 资源上限

packages/schema/src/scientific-artifact.ts 中的"扩展名 → kind"映射是干净的扩展点。

2.2 沙箱应用的数据注入

opaque origin 是结构性约束:sandbox="allow-scripts" iframe 里的应用无法 fetch 平台 API(跨源、无认证态)。可选方向三个,供讨论:

  • a. 只读挂载:把声明的输入产物只读挂载进应用沙箱——是 runner 现有 workspace 文件挂载机制的自然延伸;
  • b. postMessage 数据桥:带类型 schema 的消息通道(应用在 manifest 里声明需要什么,面板注入快照);
  • c. 受控只读内容端点:按应用粒度发 token 的受限读端点——更重,且与认证模型交互。

2.3 生命周期

按需启动(用户点开产物时)、会话作用域、空闲回收。关键溯源立场:

应用包是不可变、带版本、CAS 寻址的产物;运行实例是临时的,永不进入溯源链。应用产生的输出(用户标注、导出物)经 declare_artifact 作为常规产物回流。

这保住了平台"同输入 → 同字节"的既有语义——应用形态升级,可复现性承诺不缩水。

2.4 网络

默认零出网;按应用粒度的域名白名单 opt-in,复用 runner 既有的 egress-bridge 机制(services/runner/src/egress-bridge.ts)——与 worker 同一套安全模型。

2.5 安全评审门槛

与 worker 相同:任何服务端运行时一律 bwrap + seccomp。

2.6 曾考虑过的替代方案

  • 维持静态 HTML + 内嵌数据(现状 L1):已实现且零平台改造,但上述四个天花板是内嵌形态的物理边界,无法靠优化前端突破——这正是本提案的动机。
  • 用户自带服务 + 外链跳转:绕开平台沙箱,但丢失溯源(数据与产物脱离 CAS 链)且引入安全面,与平台安全模型冲突。
  • 平台内置通用图表增强(加固现有 dashboard 预览):能满足曲线缩放一类通用交互,但无法承载领域逻辑(如本例的"事件表 → 曲线定位联动 + 可信度滑杆复算 + 根因推理链")——应用的价值恰在于领域交互逻辑由生产者定义,平台只管托管与安全。

2.7 讨论问题(供评审聚焦)

  1. app 应该是新 kind,还是 html 加 opt-in 服务端的演进?边界在哪里?
  2. 数据注入三选:挂载 / postMessage 桥 / 受控端点——哪个符合平台方向?
  3. 生命周期作用域:仅会话级,还是项目级(更长命的看板)?
  4. 应用输出的溯源语义——origin=app_output 的一等产物?
  5. 服务端运行时的评审门槛——直接复用 worker 安全评审?

涉及到的对外API

proposal 阶段:不新增、不变更任何已发布对外 API;以下为落地时可能涉及的接触面(供评估周边影响):

接触面 预期变化 周边影响
declare_artifact 产物 kind 枚举扩展 app(新 kind,向后兼容) 消费方按未知 kind 忽略即可;schema 包 packages/schema 需版本升级
产物预览(Web 产物面板) app kind 渲染为托管运行时入口(而非静态 iframe) 仅前端面板;静态产物渲染路径不动
产物内容端点 值得平台明确设计的一处:当前内容端点被 iframe src 直接引用,内容分发不要求请求方认证头——静态产物下良性;应用运行时使访问模型需要一个明确答案(我们理解认证已在产品化路线图上,这只是一个额外输入) 与认证模型、产品化路线交互
runner / egress-bridge 若采用"只读挂载"或"服务端运行时"方案,复用既有挂载与出网白名单机制,无新网络面 与 worker 同一套安全模型
CAS 应用包按既有 CAS 寻址存储,无布局变更 无

与其他模块的相关性描述

模块 关联点
产物面板(apps/web) app kind 的预览入口与生命周期 UI(启动中/运行中/空闲回收);数据注入桥(若选 postMessage 方案)宿主
packages/schema 扩展名 → kind 映射扩展点(scientific-artifact.ts);app.manifest.json schema 定义
CAS / 溯源链 应用包入 CAS(不可变、版本化);运行实例不进溯源链;输出经 declare_artifact 回流——ExecutionRun/Claim-Evidence 语义不变
runner(services/runner) lightweight server 运行时的沙箱宿主(bwrap + seccomp);workspace 文件只读挂载的自然延伸(若选挂载方案)
egress-bridge(services/runner) 域名白名单 opt-in 复用,与 worker 同一安全模型
LLM 网关 / Agent 编排 间接相关:L3 方向(产物深链回会话、可问答)会与 Agent 会话上下文交互,本期不涉及
科学环境(scientific-envs) 无直接关联;应用运行时独立于科学环境(前端或轻量服务端,不占科学环境算力)

场景验证建议:以本提案的参考应用(训练异常报告应用)为第一个验证场景——L1 已实测跑通(沙箱 iframe 内五标签页全部可用),L2 各方案(挂载/桥/端点)都能直接在这个真实应用上验证,不需要 mockup。


测试设计与测试计划

5.1 已有测试资产(可复用为平台侧 app 契约检查)

我们的 skill 包已内置产物自包含契约测试(19 项,全部通过):

  • 不 fetch / 不 XHR / 不 localStorage(静态扫描 + 运行时行为双验证)
  • 内嵌数据与 worker 上下文字节一致(同一数据源单一出口)
  • 降采样标注(超限序列显式标注,不静默有损)
  • 容错与结构校验(字段缺失/类型错误的防御性渲染)

这些测试的断言方式可直接平移为平台侧 app kind 的准入契约:app 包声明 static-host 时必须通过"自包含 + 零网络 + 零存储"检查。

5.2 平台侧测试计划(按能力维度)

维度 验证内容 方法
功能 app kind 识别、manifest 校验(缺入口/缺运行时声明/资源上限非法时的报错);三种数据注入方案各自的数据可见性与只读性;生命周期(按需启动/会话作用域/空闲回收);输出经 declare_artifact 回流 单元 + 集成测试;参考应用端到端
兼容性 既有五种产物 kind 渲染零回归;未知 kind 的前向兼容(旧版本客户端遇到新 kind 优雅降级) 契约测试 + schema 版本矩阵
安全 沙箱逃逸尝试(fetch 平台 API、越权读未声明产物、跨 app 数据访问);服务端运行时 bwrap+seccomp 约束(文件系统/进程/网络);egress 白名单外域名阻断 渗透式用例 + 安全评审清单
性能 大数据量注入(10 万点级序列)的加载时延;空闲回收的资源释放;多 app 并发的资源上限执行 基准测试(参考应用真实数据规模)
可靠性 应用崩溃不影响面板与会话;生命周期异常(宿主重启后 app 状态);CAS 寻址的包完整性 故障注入
溯源 同输入 → 同字节(应用包 CAS 地址确定性);运行实例不泄漏进溯源链;输出产物 origin 标记正确 溯源链断言测试

5.3 验收口径

  • 端到端场景:真实训练 run 的 tfevents → 检测 → app 产物 → 面板点开 → 大数据量曲线不降采样可交互 → 用户标注回流为产物——全链路可回放。
  • 回归门禁:既有产物 kind 的全部契约测试零漂移。

其他信息

6.1 我们带来什么

  1. 一个已投产的 skill,其产物已经跑满 L1 全形态(交互、自包含、sandbox 实测验证)——是真实使用,不是 mockup;
  2. 产物自包含契约测试(不 fetch/XHR/localStorage、内嵌数据与 worker 上下文字节一致)——可直接复用为平台侧 app 契约检查;
  3. 共创意愿:愿意共同设计 manifest schema,并贡献参考应用(训练异常报告应用)作为第一个 app kind 公民。

6.2 L1 基线细节(现状证据,供核验)

以下能力全部已实现并在沙箱实测通过(skill v1.7.0)。

运行环境约束(代码实读 + 实测):

约束 证据 设计应对
iframe sandbox="allow-scripts"(无 allow-same-origin)→ opaque origin 产物面板组件 数据全内嵌是唯一可行形态(iframe 内 fetch 平台 API 一律跨源失败且无认证态)——不是设计偏好
localStorage 抛异常 opaque origin 特性 状态全内存,零持久化
iframe 高度固定 面板布局 标签页布局 + 内部滚动,不用长滚动页
平台缩放是 transform:scale 面板实现 应用自带滚轮缩放,不冲突
无 CSP 头(send 只设 nosniff) API 响应实现 脚本自由运行——交互能力确实在

数据契约(内嵌 JSON):var D = {...} 单一数据出口,Python 侧全部预计算(JS 只读不改写):

  • meta:结论 / 六态色 / grade / judgementConfidence / 权重 / 四维因子 / scores
  • tags + curves:每 tag {steps[], values[], ema[], nFinite, downsampled}——≤20000 点全量嵌入(真实样例 562~1000 点约 25~50KB),超出等距降采样(保首末点)并标注
  • events[]:detector / isAnomaly / eventStep(联动锚点)/ triggerRule / confidence / magnitude(NaN 过滤)/ missingInputs
  • causes:candidates[](id/category/pattern/likelihood/rank/evidence[]/reasoning/check)+ insufficient[] + basis

验收记录(2026-09-21 实测):

验收项 结果
契约测试 19 项全绿(v1.5 的 10 项 + 新增 9 项)——包内合计 53 passed
回归门禁 149/0/44 与契约一致,六态/grade 零漂移(worker 判定链零改动)
全量单测 tests/ 656 passed
真实样例端到端 崩溃样例:四件套产出,原因排名 5 候选,推理链完整
sandbox iframe 实测 与产物面板同款 sandbox 构造 iframe(http 服务承载),CDP 直连子 frame 验证:横幅/5 标签页/曲线 canvas/事件联动/滑杆复算/原因卡片全部可用;localStorage 确认抛异常,应用零依赖

已知边界(如实声明):

  1. 数据量天花板:>20000 点/tag 降采样后局部细节有损——L1 内嵌形态的物理边界,L2 服务端形态解决(本提案第一论据)
  2. 单文件无跨产物查询:一次训练一个应用,不能对比多次 run——L2 议题
  3. 根因排名是排查优先级不是结论:单序列信息有限,根因确认需人工按"建议核查"行动——basis 字段随页声明
  4. iframe 内无法回写平台:用户在应用内的标注/批注无法回传会话——L2/L3 议题

6.3 三层演进总览(定位图)

层 内容 状态 维护位
L1 交互报告应用 report_app.html:内嵌数据 + 原生 JS 交互(标签页/曲线缩放/事件联动/滑杆复算/根因排名) 已实现(skill v1.7.0,零平台改造) training-anomaly-detection skill 包
L2 平台应用级产物 app kind + 托管运行时 + 数据注入 + 生命周期 本提案(社区讨论) ScienceDiscovery 仓
L3 可问答产物 产物深链回会话(点开产物可向 Agent 提问) 远期方向(社区讨论) ScienceDiscovery 仓

L1 已落地意味着:社区讨论 L2 时不必从 mockup 开始——第一个参考应用已经存在,且它的每一项能力都经过沙箱实测。

6.4 结语

产物形态从"静态文件"到"应用"的演进,本质是把分析结论交付形态从"一次性快照"升级为"可探索、可复算、可对话的空间"。我们已经用 L1 证明了第一步在零平台改造下可行;L2 的平台能力(app kind、数据注入、生命周期、网络与安全模型)希望能与社区共同设计。欢迎在 issue 区讨论,也欢迎直接 review 我们的 L1 参考实现。

likedislike
SspaceWing
26 天前 添加了label:feature
openJiuwen-bot成员
26 天前 评论:

欢迎来到 openJiuwen 社区

Hey @spacewing , 感谢你对社区的贡献.

机器人使用手册

有关指令的使用,可以点击 此处 查看详情。开发人员可以在每个PR或Issue下方评论特定指令来触发机器人任务。

likedislike