feat: initialize XAS test console with native execution
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
# 第一阶段验收记录
|
||||
|
||||
此文为最初回环预览的历史快照;用户后续免登录要求的当前状态见 [内网验收](acceptance-lan-2026-10-13.md)。
|
||||
|
||||
核对日期:2026-10-13(北京时间)。结论:受限网页预览与轻量流程验证通过;正式 GPU 测试尚未接入。
|
||||
|
||||
## 本轮变更
|
||||
|
||||
- 新建本地私有脚本库工作目录及空 Git 仓库,所有文件未暂存;提交数为 0,无远程仓库。
|
||||
- 新建服务器目录 `/adamwen-work-space/xas-test-library` 和容器 `adamwen-test-console`。
|
||||
- 网页使用 Rundeck 6.2.1,基础镜像摘要 `sha256:63d12aefbbd129a121d2af7d97abfaa64c3cbd7756063f74dbf3ab3377d136bd`。
|
||||
- 运行镜像 `adamwen/test-console:20261013-1`,镜像 ID `sha256:429dfa1322c8e72b25fb82d5a1a6452af4968f30f5dbb6ee6937825aadd38ab7`。
|
||||
- 镜像增加 Python 3.10.6-1~22.04.1、python3-bcrypt 3.2.0-1build1,宿主机运行时未升级。
|
||||
- 只导入一个轻量任务,UUID 为 `ef76123d-f532-42c7-b7f7-a78f9231c18d`。旧公司套件与两个试验目录只登记来源。
|
||||
|
||||
## 行为测试
|
||||
|
||||
| 验证环境 | 本轮最终结果 |
|
||||
|---|---|
|
||||
| 本地 Windows | 10 项中 6 通过、4 跳过;跳过原因是 Linux 进程组及当前账号无法创建目录链接 |
|
||||
| 00088 Linux | 10/10 通过,耗时 4.087 秒,无跳过 |
|
||||
|
||||
覆盖:成功日志和模拟结果、脚本非零退出、退出 0 但报告无效、重复编号不覆盖、路径穿越/无效参数拒绝、超时清理、取消父子进程、运行根目录和子目录链接拒绝。
|
||||
|
||||
新增代码先观察失败测试,再完成实现;独立审查指出的运行目录父链接问题已补回归测试并修复。修复后的全套 Linux 测试通过。没有未处理的审查发现。
|
||||
|
||||
## Rundeck 真实任务链路
|
||||
|
||||
| 执行编号 | 场景 | Rundeck 状态 | 业务状态 | 清理确认 |
|
||||
|---|---|---|---|---|
|
||||
| 1 | 成功 | succeeded | succeeded | true |
|
||||
| 2 | 主动失败 | failed | failed | true |
|
||||
| 3 | 无效报告 | failed | invalid_result | true |
|
||||
| 4 | 2 秒超时 | failed | timed_out | true |
|
||||
| 5 | 运行后取消 | aborted | cancelled | true |
|
||||
| 6 | 浏览器点击运行 | succeeded | succeeded | true |
|
||||
|
||||
前五项在 11:14:36 至 11:14:43 完成。第六项在 11:19:28 至 11:19:29 完成,运行器记录约 0.64 秒。以上均为 synthetic 流程验收数据,没有使用 GPU 或模型接口。
|
||||
|
||||
未登录 API 返回 403;普通操作角色执行任意命令返回 403;同一任务正在执行时再次提交返回 409。
|
||||
|
||||
## 真实浏览器
|
||||
|
||||
使用独立 Edge 浏览器上下文,通过 SSH 转发登录普通操作账号,核对任务列表和参数页;点击 Run Job Now 产生执行 6;核对完成页、三条进度日志和结构化结果。
|
||||
|
||||
页面的 Succeeded 文案由 CSS `::after` 生成,最初按 DOM 文字精确定位的自动等待超时。服务端记录与截图均成功,后续只读取已有执行 6,确认伪元素内容为 `"Succeeded"` 并打开日志页,没有因文字定位问题重复提交任务。
|
||||
|
||||
截图:[任务参数页](images/job.png)、[执行日志页](images/logs.png)。视口为 1440 × 1000。
|
||||
|
||||
## 共享服务与隔离证据
|
||||
|
||||
- 原有 `dengyuyun-joy-dsv41-trial` 容器 ID 为 `114ceebc787845e45e1abcb0a46ac962529c28a4b865894cd3581234cd729e1a`,仍为 running,启动时间为 2026-10-12 13:29:36(北京时间),RestartCount=0。它的启动时间早于本轮操作,未被本轮重启。
|
||||
- GPU 查询仍看到 VLLM::Worker_TP0~TP7;没有创建新的 GPU 任务。本轮没有调用模型接口,不能把进程存活当作模型业务质量验证。
|
||||
- 新容器 DeviceRequests=null、Devices=[]、Privileged=false,容器内 `/dev/nvidia*` 为空。
|
||||
- 所有绑定挂载都在本项目目录下;没有 `/dengyuyun-joy-work-space`、共享模型或 Docker socket 挂载。
|
||||
- 只发布 `127.0.0.1:14440 → 4440`,未改防火墙和旧端口。
|
||||
- 配置上限为 2 CPU、2 GiB 内存、256 进程。检查时新容器 CPU 约 0.06%、内存约 1.275 GiB;这是观察值,不是持续性能承诺。
|
||||
|
||||
## 过程中的问题与修复
|
||||
|
||||
- 首次启动登录页早于 API 就绪;将准备检查改为 API 的未认证响应,避免把加载页 HTTP 200 当作可用。
|
||||
- 权限验收请求最初缺少 project 参数,返回 400;补齐官方 API 参数后得到明确 403。
|
||||
- YAML 的固定标识改用 uuid,并与实际已创建任务对齐,保留同一任务;原 404 请求没有创建运行记录。
|
||||
- 浏览器输出使用 UTF-8;状态文字采用实际 CSS 和截图证据核验。
|
||||
- 独立审查发现运行目录父链接可跨出项目;已在任何 mkdir/chown/chmod 前核验完整运行路径。
|
||||
|
||||
## 交付边界
|
||||
|
||||
用户仍需通过 README 中的交互式工具设置自己的网页登录密码,明文不进入聊天、源码或参数。临时验收账号在交付收尾时撤销。
|
||||
|
||||
当前为单实例 H2 预览,未配置组织 SSO、正式数据库、自动备份、系统自启或公司网访问入口。运行日志与结果尚无自动清理;没有新增定时任务。
|
||||
|
||||
长时 GPU 压测、模型性能/质量、正式脚本停止语义与多人资源调度均未验证。公司仓库尚未建立,因此远程 Git 集成未验证。
|
||||
|
||||
恢复时只操作本项目容器及目录;保留数据库和结果。版本回退不自动恢复数据库,后续升级需另行备份并核验数据兼容性。
|
||||
|
||||
## 核对过的官方资料
|
||||
|
||||
- [Rundeck Docker 配置](https://docs.rundeck.com/docs/administration/configuration/docker.html)
|
||||
- [认证和可重载密码文件](https://docs.rundeck.com/docs/administration/security/authentication.html)
|
||||
- [API:导入、执行与取消](https://docs.rundeck.com/docs/api/)
|
||||
@@ -0,0 +1,35 @@
|
||||
# 按测试行为整理目录:验收记录
|
||||
|
||||
核对日期:2026-10-13 19:06(北京时间)。用户要求“一项测试为一个项目”,不把套件内部文件平铺。当前规则见 [ADR 0003](adr/0003-test-behavior-catalog.md)。
|
||||
|
||||
## 实际结果
|
||||
|
||||
- 正式地址仍为 `http://10.88.118.188:14440/#/scripts`。主列表 23 项业务测试,包含 8 项套件和 15 项单项测试。
|
||||
- GPU 综合验收套件只显示一项,详情关联 224 个文件,其内部 148 个验证文件不再作为独立项目。
|
||||
- 套件和同类测试的辅助模块、素材生成脚本及相关实现归入详情“相关文件”。文件可搜索和只读查看;选择文件不会变更执行入口。
|
||||
- 两个控制台验收样例默认隐藏,可在“项目用途 → 验收示例”查看。已接入的轻量检查保持可运行,其他业务测试仍待配置。
|
||||
- 扫描文件只更新文件清单,不自动生成测试卡片。测试入口由 `catalog/test-definitions.json` 明确登记;新上传的单入口脚本作为新测试。
|
||||
|
||||
## 本轮验证
|
||||
|
||||
隔离 Linux 环境 **37/37** 回归检查通过,其中新增 6 项覆盖:套件合并、刷新不提升辅助文件、内部文件服务端执行限制、上传与示例筛选、历史保留、测试名称与唯一入口排队。原有配置、日志、结果、版本和执行器回归一并通过。
|
||||
|
||||
真实浏览器在数据库副本预览与正式地址均完成只读验收:主列表 23 项,套件详情 224 个文件,源码只读,内部文件详情没有运行按钮,直接运行 API 返回 400,示例筛选 2 项,10 条历史记录保留。桌面和 390px 视口通过,浏览器无 JavaScript 错误。验收发现长路径卡片在小屏撑宽,已用网格子项 min-width 修复并复查。
|
||||
|
||||
本轮没有执行任何服务器测试脚本或调用实际模型。测试中的本机假上游与临时子进程只用于隔离回归,不是业务测试运行。
|
||||
|
||||
## 数据及共享资源
|
||||
|
||||
更新前后 scripts、versions、runs 三张表的完整数据摘要一致;SQLite 结构仍为 schema v1,没有结构迁移、回填、删除或历史重写。307 个原位置文件的 SHA-256 全部一致。
|
||||
|
||||
私有执行器进程 MainPID 仍为 2086920,没有重启;模型容器 ID 和 StartedAt 与更新前一致,没有重启或更改配置。只替换了本项目网页容器。正式地址执行器在线、活动任务 0、历史记录 10;目录预览容器已移除。
|
||||
|
||||
## 发布、回退和改动文件
|
||||
|
||||
正式镜像为 `adamwen/script-console:20261013-2`,摘要 `sha256:e163e0dcf1bc7bff05d0f42cb495732de6e7d97a8950f6ad64a7e6ccc40641f1`。切换前的网页容器停止保留为 `adamwen-script-console-before-catalog-20261013`。
|
||||
|
||||
备份位于 `runtime/backups/before-behavior-catalog-20261013/`,包括本轮改动前源码、SQLite 快照、原文件摘要、原网页/模型状态与执行器 PID。应用回退只需在无活动任务时停止并保留新网页,恢复旧网页容器原名后启动;旧镜像兼容同一 schema v1,无须覆盖数据库。恢复源码时逐文件核对后续改动,不能用整目录覆盖;数据快照恢复须另行确认,不自动丢弃新记录。故障回退路径未实际触发。
|
||||
|
||||
主要修改:`console/test_catalog.py`、`console/app.py`、`console/settings.py`、`console/static/` 相关页面、`catalog/test-definitions.json`、`tests/test_test_catalog.py`、既有测试入口夹具、部署镜像引用和维护文档。没有 Git 暂存、提交或推送。
|
||||
|
||||
脱敏证据:服务器 `runtime/behavior-catalog-acceptance.json`;本地 `.local/evidence/behavior-catalog-browser.json` 与 `.local/screenshots/behavior-*.png`。旧部署验收记录保留其原始时点,不作为本轮状态。
|
||||
@@ -0,0 +1,64 @@
|
||||
# 专用控制台验收记录
|
||||
|
||||
核对日期:2026-10-13;正式入口切换时间 17:32(北京时间),中断后再次核对时间 17:59。以下是本轮实际执行证据,不代表所有原有脚本或 GPU 测试已验收。
|
||||
|
||||
## 已交付
|
||||
|
||||
正式入口为 `http://10.88.118.188:14440/`,公司内网免登录。旧 `/project/xas-test-library/nodes` 等项目书签自动转到新脚本库。14442 预览已停止,旧 Rundeck 网页和代理容器停止保留,原数据没有删除或迁移覆盖。
|
||||
|
||||
支持脚本搜索/筛选、只读源码、上传新脚本及新版本、元数据与运行配置、单并发队列、实时标准输出/错误和 `.log`、取消、历史记录、结果预览/下载。排队记录固定版本和配置,历史上传版本不可覆盖。
|
||||
|
||||
当前共 310 项:公司套件 224 项、DeepSeek 试验目录 35 项、模型试验目录 48 项、托管脚本 3 项。307 个原位置文件包括执行入口和辅助模块,只登记,不批量复制。可运行的 3 项为复制的 DeepSeek 轻量检查、快速流程样例和网页上传演示;原位置条目仍待逐项配置。
|
||||
|
||||
## 自动检查与浏览器
|
||||
|
||||
- 最终候选版本在隔离 Linux 容器执行 **31/31** 项检查通过,包括历史运行器回归、上传版本、路径/链接限制、请求幂等、日志 UTF-8 分块、文件日志尾段、模型代理预算/禁止重定向、清理失败时记录与摘要一致性。
|
||||
- 本地 Windows 对相关检查通过;Linux 专属符号链接与 worker/进程检查在 Linux 补齐,未把平台跳过当成通过。
|
||||
- 真实浏览器完成上传、新版本、版本切换、只读源码、运行、日志、JSON 预览;390px 视口没有横向溢出。最终入口验证无浏览器 JavaScript 错误。
|
||||
- 错误 Origin 和缺少修改请求专用头均返回 403;生产不信任转发 IP 或身份头。
|
||||
- SQLite `PRAGMA integrity_check` 返回 `ok`。17:59 执行器在线,活动任务 0,本项目临时容器 0、tmpfs 挂载残留 0,共保留 10 条运行记录。
|
||||
|
||||
## 现场执行记录
|
||||
|
||||
| 场景 | 运行编号 | 实际结果 |
|
||||
|---|---|---|
|
||||
| 最初容器启动验证 | 45def157885d4228bb9c0fc8480dda00 | Docker 日志轮转 max-file=1 与压缩不兼容,脚本未启动;改为 2 后验证通过。保留失败记录。 |
|
||||
| 快速模拟成功 | 13caa662bf10489698b3d1bf4b567021 | succeeded,日志及 result.json 可见 |
|
||||
| 脚本主动失败 | 794e00e7dc35437ba29191c229db595b | failed,退出码 2,符合预期 |
|
||||
| 5 秒超时 | 3716cec9637143048220c6fe7b16abab | timed_out,测试容器清理 |
|
||||
| 运行中取消 | 92b38203e0cd42e3a585c8eb4f09c614 | cancelled |
|
||||
| 排队取消 | c2eafe168c09444e96f800fd1094e3e1 | cancelled,未启动脚本 |
|
||||
| 网页上传版本 2 | 8607ca8f5511498ca041b65ebfd4223d | succeeded,标准输出、application.log、result.json 可见;仅模拟数据 |
|
||||
| worker 意外退出 | bffd569a881d43d5a2e87fdef04c40b6 | interrupted;恢复后无任务容器/挂载残留,未补跑 |
|
||||
| 原始轻量模型检查 | fddc3dd84d36403cb8083c3303220ce7 | succeeded,真实请求见下 |
|
||||
| 正式入口最终快速验证 | 76478f6925d34c4eb3d3b613c558946a | succeeded,运行状态与下载摘要一致 |
|
||||
|
||||
失败、超时、取消和中断记录是有意验证的不同路径,除了最初已修复的容器配置错误,不应当作未解决的产品故障,也不作为模型质量统计。
|
||||
|
||||
## 一轮真实模型检查
|
||||
|
||||
使用复制的原始 smoke.sh,SHA-256 为 `be858e914d87454240791da773578cb3f80f380e740f919546db347b7715a13d`。原位置文件、本地副本与运行摘要相同。
|
||||
|
||||
一次模型列表 GET 和三个顺序问答 POST 全部 HTTP 200,没有重试或重定向。三个回答 `finish_reason=stop`,completion_tokens 分别为 99、100、300(合计 499);每次仍保留原脚本 max_tokens=512。算术问题返回 97,406,784,日志和完整响应报告 `smoke-response.json` 已在控制台查看。
|
||||
|
||||
本次只证明接口与控制台执行/记录链路可用,不是全面的回答质量、代码正确性、多卡性能或并发压力验收。没有执行模型返回的 Fibonacci 代码。
|
||||
|
||||
## 共享资源与恢复
|
||||
|
||||
`dengyuyun-joy-dsv41-trial` 的容器 ID 始终为 `114ceebc787845e45e1abcb0a46ac962529c28a4b865894cd3581234cd729e1a`,StartedAt 仍为 `2026-10-12T05:29:36.607636623Z`、RestartCount=0。未改原脚本、原目录权限、模型服务配置或 GPU 分配;仅向已运行的模型发出上述少量推理请求。
|
||||
|
||||
17:59 GPU 0–7 仍由既有模型占用,GPU 8–15 显存为 0;GPU 0–7 的显存快照相较 17:35 有变化,不能据此推断原因或声称整个共享服务器状态没有变化。本项目没有残留测试进程容器或额外模型服务。
|
||||
|
||||
正式网页镜像 `adamwen/script-console:20261013-1`,当前摘要 `sha256:7ba1cd10360271fad99975b599264a0c8a1d1458ae23a7b0f44387079aef9c3d`。基础 Python 镜像固定摘要,依赖版本固定。网页没有 Docker socket/GPU,根文件系统只读、capabilities 全部移除。
|
||||
|
||||
切换前已保存 `runtime/backups/before-dedicated-20261013/`,包含 SQLite 完整性检查通过的快照、library、runs 和切换元数据。旧容器和预览容器停止保留。实际故障回退/数据恢复未演练;操作步骤及必须保留快照后数据的限制见 [console-operations.md](console-operations.md)。
|
||||
|
||||
尚未接入多 GPU 分配、模型服务启停、通用依赖环境、更多原输出目录、个人账号、开机自启或自动清理。普通新上传脚本支持当前标准环境;原位置脚本需要确认配置和依赖后逐项启用。
|
||||
|
||||
## 改动与证据位置
|
||||
|
||||
主要改动为 `console/`、`tests/test_console*.py`、`deploy/console*`、`deploy/dedicated.py`、`deploy/cutover_console.py`、`scripts/console_example.py`、目录配置、README 和当前设计/操作文档。所有手写新增源码文件不超过 500 行。
|
||||
|
||||
本地浏览器证据保存在 `.local/evidence/console-browser.json`、`.local/evidence/final-console-browser.json` 和 `.local/screenshots/`;模型运行与幂等请求编号保存在 `.local/evidence/model-smoke-request.json`。服务器脱敏收尾证据为 `runtime/dedicated-acceptance.json`。这些运行材料均不进入 Git。
|
||||
|
||||
本项目仍没有提交历史,所有源代码未暂存、未提交、未推送。Git 仅配置了公司 origin,不自动拉取或部署。
|
||||
@@ -0,0 +1,51 @@
|
||||
# 内网免登录验收
|
||||
|
||||
核对日期:2026-10-13(北京时间)。本记录对应用户最新的公司内网免登录要求,替代最初的回环网页登录方式。
|
||||
|
||||
## 结果
|
||||
|
||||
- 入口:http://10.88.118.188:14440/project/xas-test-library/jobs ,全新浏览器无需登录。
|
||||
- 允许网段为 10.88.0.0/17 和 10.20.0.0/21,来自服务器网卡与当前电脑路由现场核对。
|
||||
- 访客可读取本项目、运行/停止登记任务及查看历史。
|
||||
- 伪造管理员身份头、跨站 Origin/Fetch-Site、错误 Host 和令牌参数均返回 403。
|
||||
- 修改同一任务定义得到 Unauthorized,没有成功更新。
|
||||
- 宿主机直连容器 IP:4440 失败;后端没有宿主机端口映射。
|
||||
- 来自 Docker 网桥的请求即使伪造办公网 X-Forwarded-For,仍被代理拒绝 403。
|
||||
|
||||
## 行为与浏览器
|
||||
|
||||
Linux 完整回归 14/14 通过,4.101 秒;Windows 10 通过、4 项平台相关跳过。
|
||||
|
||||
真实内网浏览器点击运行创建执行 7,身份为 xas-intranet,于北京时间 12:11:21~12:11:23 成功完成。浏览器核对 Succeeded 状态、三条进度日志及结构化结果。历史 API 返回 7 条记录,原 1~6 记录保留。未调用模型或使用 GPU。
|
||||
|
||||
截图:[免登录任务页](images/lan-jobs.png)、[执行日志](images/lan-logs.png)。
|
||||
|
||||
浏览器辅助 API 客户端携带会话 Cookie 时得到 404,而无 Cookie、明确 JSON 响应的直接查询返回真实记录。生命周期通过独立 HTTP 查询核验,浏览器核验真实页面、CSS 状态和日志,没有因验收工具问题重复提交任务。
|
||||
|
||||
## 隔离与原服务
|
||||
|
||||
12:11 只读核对:原 dengyuyun-joy-dsv41-trial 容器 ID、2026-10-12 的启动时间和 RestartCount=0 均不变;VLLM::Worker_TP0~TP7 的 PID 仍为 1578853~1578860。未修改其工作区、模型、容器或 GPU 任务。
|
||||
|
||||
后端镜像 ID:sha256:6b694273a33c449829f7dc5a777cb2b09c2df630c70035c45956673fa35953d9。
|
||||
代理摘要:sha256:0985e772fb9f729e6fa0980da05fca5d9c468e870eed43071545afa9d2e27d94,实际 nginx/1.30.5。
|
||||
|
||||
后端上限 2 CPU/2 GiB,无 GPU;代理上限 0.25 CPU/64 MiB。只对指定内网 IP 发布 14440,没有修改系统防火墙。
|
||||
|
||||
## 审查与修复
|
||||
|
||||
独立审查指出后端不发布端口仍能被宿主机直连伪造角色。新增 Docker 边界回归先失败,再改成共享命名空间和后端回环;现场 TCP 检查确认直连被阻断。
|
||||
|
||||
首次代理检查因默认临时目录与只读根文件系统冲突失败,指定 tmpfs 临时路径后 nginx -t 通过。当前电脑来源 10.20.1.3 最初被服务器网段名单拒绝,核对本地 /21 路由后加入对应办公网。历史所需 event/read 权限经 403→200 验证补齐,未增加管理权限。
|
||||
|
||||
## 备份与恢复
|
||||
|
||||
备份目录:/adamwen-work-space/xas-test-library/runtime/backups/before-lan-20261013/。
|
||||
|
||||
- source/:切换前源码与配置。
|
||||
- runtime-before-lan.tar.gz:旧预览停止后生成的数据库、日志、结果与配置快照。
|
||||
- metadata.json:旧容器、镜像与快照关联信息。
|
||||
- 旧容器 adamwen-test-console-before-lan-20261013 保持停止状态。
|
||||
|
||||
应用回退只停止本项目新后端与代理,保留当前数据,再恢复旧配置和旧容器名称。两版均为 Rundeck 6.2.1,本轮未改变数据库格式。恢复旧数据库快照需要单独确认,会移除快照之后的记录,不能默认执行。
|
||||
|
||||
未配置自启、定时备份或自动清理。正式 GPU 长测尚未接入。公司远程 Git 仓库待后续接入,未提交或推送。
|
||||
@@ -0,0 +1,68 @@
|
||||
# 原环境执行接入验收
|
||||
|
||||
核对日期:2026-10-13 23:37(北京时间)。用户已授权开放原测试,包括显示影响并逐次确认的资源/服务操作;本轮验收没有实际启动原 GPU、模型切换或长稳测试。
|
||||
|
||||
## 已交付行为
|
||||
|
||||
- 正式入口仍为 `http://10.88.118.188:14440/#/scripts`。23 项业务测试中,22 项原位置入口使用登记的原目录、解释器、配置、依赖和参数,复制版轻量检查保持既有容器模式。
|
||||
- 详情显示只读执行方案、账号、目录、解释器和影响;只开放方案声明的参数及最长 72 小时时限。原入口和相关文件只读,上传脚本继续容器隔离。
|
||||
- 普通原环境测试预检通过后排队;资源/服务测试必须每次确认。源码、依赖配置、方案或参数变化时旧确认失效。预检只检查路径、工具、摘要和本机 TCP 端口,不发推理、不启动模型、不预留 GPU。
|
||||
- 独立 systemd 服务运行原入口,页面接收标准输出、错误、登记的文件日志和归档结果。菜单支持数字选项/列表、y/n/q、回车,关闭回显,不保存输入历史。
|
||||
- worker 重启后继续跟踪同一次原环境任务;取消和超时等待本次本机进程收尾。Docker/tmux 分离任务和模型恢复需根据日志及资源变化核对,控制台不自动删除他人资源。
|
||||
|
||||
## 验证证据
|
||||
|
||||
| 验证层级 | 本轮结果 |
|
||||
|---|---|
|
||||
| Linux 自动回归 | 55/55 通过,包含参数/来源限制、确认失效、取消竞态、状态未知保留占位、凭据跨块/ANSI 脱敏、控制终端、300 个旧日志不遮蔽新日志 |
|
||||
| 真实 systemd 短进程 | 6/6 通过:成功、失败、超时、取消、交互、worker 重关联;仅独立样例,不调用模型/GPU |
|
||||
| 配置迁移 | 生产库隔离副本迁移 22 项、再次迁移幂等、逐条恢复后内容完全一致;runs/versions 不变 |
|
||||
| 已部署 API | 22 项原环境预检可调用;23 项业务目录、10 条旧运行、0 活动任务,worker 在线 |
|
||||
| 真实浏览器 | 1440px/390px 方案显示、72 小时上限、只读目录、逐次确认/取消、缺失端口拦截、返回及历史记录通过;无 JS 错误、无横向溢出、运行提交 0 次 |
|
||||
| 原项目保护 | 307 个原脚本 SHA-256 与升级前一致,10 条 runs 完整摘要一致;原模型容器 ID/StartedAt 不变、RestartCount=0 |
|
||||
|
||||
测试依赖产生既有 Starlette/httpx 弃用提示,不影响通过结果;本轮未升级依赖。
|
||||
|
||||
最终短进程证据在服务器 `runtime/native-final-validation-20261013/acceptance.json`,隔离于生产运行记录:
|
||||
|
||||
| 场景 | 运行编号 | 结果 |
|
||||
|---|---|---|
|
||||
| 正常退出 | eae879ee835c4b99948b48fdbeaa28da | succeeded / 0 |
|
||||
| 非零退出 | 6abb4c53215f4dcfa221aee43b4c4e0d | failed / 7 |
|
||||
| 时限到期 | e6e5142ccb7c411d9d6cfb34d21fb298 | timed_out / -15 |
|
||||
| 主动取消 | f5413e5e37144eb0bbfaf2651768273c | cancelled / -15 |
|
||||
| 菜单与控制终端 | f3dd72ef551e4f6c933a0e4af2f0d4fd | succeeded / 0 |
|
||||
| 同一服务重新跟踪 | bdb9fe7cd24a457aa79c2e7732778964 | succeeded / 0,未重放 |
|
||||
|
||||
已核验超时/取消子进程消失、假凭据不出现在平台日志及归档、菜单输入不回显、实际命令无运行编号占位、原样例文件摘要不变。完整模型业务的指标、质量及长稳效果仍未验收,页面保留提示。
|
||||
|
||||
## 原模型服务条件
|
||||
|
||||
23:27 的只读预检,22 项中 16 项满足登记条件;以下 6 项的原服务未监听,自动拦截。此快照不是永久可用性保证,真正点击运行时重新预检。
|
||||
|
||||
| 方案编号 | 缺失原端口 |
|
||||
|---|---|
|
||||
| deepseek-suite | 18101 |
|
||||
| throughput | 18106 |
|
||||
| replicas | 18110–18117 |
|
||||
| engine-comparison | 18106 |
|
||||
| model-suite | 18106 |
|
||||
| soak | 18106 |
|
||||
|
||||
这些入口已完成方案接入;准备好对应原服务后才能执行。未改为调用其他端口,也未擅自补启动命令。
|
||||
|
||||
## 发布与恢复
|
||||
|
||||
最终网页镜像 `adamwen/script-console:20261013-5`,摘要 `sha256:05ad7a7a332a1e26eaeebff790e53c16318e547d3ad936e67aee6ff11acd1710`。仅更新本项目网页和空闲 worker,访问网段、无账号安排、模型服务与 GPU 分配未改变。原环境宿主代码与网页方案来自当前同一项目目录;每次运行记录源码和计划摘要,Git 不参与运行时拉取。
|
||||
|
||||
升级前备份为 `runtime/backups/before-native-20261013/`,含旧源码、SQLite、原文件摘要与服务状态。配置迁移清单 `native-config-migration.json` 记录 22 项 before/after;数据库仍 schema v1。旧网页停止保留为 `adamwen-script-console-before-native-20261013`,首次接入镜像也保留为 `adamwen-script-console-native-initial-20261013`。
|
||||
|
||||
回退须停止接单、确认无活动 native unit 和排队/运行任务,再停 worker;使用迁移工具逐条恢复旧配置,核对并恢复匹配的旧 worker 源码,恢复旧网页后启动 worker。配置已发生后续变化时工具拒绝覆盖。保留新运行记录及所有结果,不能直接用旧 SQLite 覆盖。配置恢复已在隔离副本验证,生产故障回退未触发。
|
||||
|
||||
服务器证据:`runtime/native-deployment-acceptance.json`、`runtime/native-release-precheck.json`。本地浏览器证据:`.local/evidence/native-browser.json`、`.local/screenshots/native-*.png`。早期部署记录保留各自时点,不代表当前状态。
|
||||
|
||||
## 变更范围
|
||||
|
||||
核心新增 `console/native_{plans,io,rpc,files,job,executor}.py`、`console/static/native-ui.js`、`catalog/native-profiles.json`、`deploy/native_profiles.py`、3 个原环境测试文件及 ADR 0004。配套修改 API、目录描述、存储、worker、日志归档、运行/详情页面、部署镜像和维护文档。新手写文件均小于 500 行。
|
||||
|
||||
未暂存、提交、打标签或推送 Git。当前仓库尚无提交,所有实现继续留待用户审阅;运行数据、凭据和本机辅助证据不进入 Git。
|
||||
@@ -0,0 +1,13 @@
|
||||
# ADR 0001:内网免登录入口与固定操作权限
|
||||
|
||||
日期:2026-10-13。状态:已实施。
|
||||
|
||||
用户选择公司内网少数人使用、暂不设置账号。采用 Nginx 来源网段限制和固定操作身份,保留 Rundeck 服务端授权。任务维护继续通过受控源码和服务器维护流程完成。
|
||||
|
||||
仅不发布后端端口,宿主机仍可连接容器 IP 并伪造预认证角色。实际将后端与代理放入同一本项目网络命名空间,后端只监听其回环;代理覆盖所有受信身份头。宿主机 root / Docker 管理者处于信任边界内。
|
||||
|
||||
共享 xas-intranet 身份的代价是无法确定具体操作人。日志只保留来源 IP、方法、路径、状态与大小,不记录查询参数或会话信息。允许网段来自现场网络配置,不开放整个私有地址空间。
|
||||
|
||||
以后需要逐人权限或审计时,再将固定身份替换为真实认证;当前不提前建设账号系统。
|
||||
|
||||
依据:[Rundeck 预认证](https://docs.rundeck.com/docs/administration/security/authentication.html#preauthenticated-mode-using-headers)、[Docker 端口边界](https://docs.docker.com/engine/network/port-publishing/)、[Nginx 访问控制](https://nginx.org/en/docs/http/ngx_http_access_module.html)。
|
||||
@@ -0,0 +1,21 @@
|
||||
# ADR 0002:使用专用脚本管理控制台
|
||||
|
||||
日期:2026-10-13;状态:按用户确认方案实施,替代 Rundeck 作为日常入口。
|
||||
|
||||
## 原因
|
||||
|
||||
用户需要直接上传脚本、查看只读代码、上传新版本、配置执行参数,并在同一页面看到日志、结果和历史。Rundeck 的任务编辑/导入模型与这里的脚本文件管理存在额外映射,继续叠加集成会增加维护成本。
|
||||
|
||||
## 决策
|
||||
|
||||
网页/API 使用 FastAPI,SQLite 保存元数据与状态,文件系统保存不可变上传版本、日志和结果。数据库 `user_version=1` 为新控制台独立结构,不改写旧 H2。Git 保留应用源代码,不作为每次运行的自动拉取来源。
|
||||
|
||||
共享队列单并发,独立宿主 worker 拥有 Docker 管理能力,但没有网络监听入口。网页和任务容器没有 Docker socket、GPU、宿主 PID 或设备。网页需读取原目录的 root/0700 文件,使用容器 UID 0、移除全部 capabilities、只读根文件系统和来源挂载;不改变原目录属主或权限。网页仅绑定内网 IP,通过真实 peer IP、Host、Origin 和自定义请求头限制访问,不信任转发身份/IP头。
|
||||
|
||||
上传代码仍是不可信输入。任务放入受限容器;临时结果目录是宿主项目路径下的 128 MiB tmpfs,归档后卸载。允许的原输出目录可写,原文件不清理;其增长采用运行时软限制,不能当成文件系统硬配额。特定旧脚本认证仅存在专用代理进程内存中,stdin 注入,不修改原脚本或复制认证文件。
|
||||
|
||||
## 兼容和退出条件
|
||||
|
||||
旧容器、H2、日志和备份保留,但旧记录不转换或混入 SQLite。14440 上 `/project/xas-test-library/*` 的浏览器书签跳转到新脚本库;仅为已经发给用户的公开页面链接保留,在团队更新书签后可以移除。没有保留旧 API 或双写路径。
|
||||
|
||||
后续接入 GPU、服务管理脚本、额外依赖、更多输出目录或鉴权,需要单独明确资源和权限范围。当前服务不自动安装依赖,也不从任务容器停止其他维护者服务。
|
||||
@@ -0,0 +1,29 @@
|
||||
# ADR 0003:按实际测试行为组织目录
|
||||
|
||||
日期:2026-10-13。依据用户明确要求:一个测试为一项,一套测试的内部文件不再平铺。
|
||||
|
||||
## 调整原因与领域边界
|
||||
|
||||
原目录将递归发现的 .py/.sh 文件当成测试项目,307 个原位置文件中含辅助模块、套件自身验证、服务管理和历史场景脚本。扩展名只能识别源码文件,不能证明它是一项独立测试。
|
||||
|
||||
现在分为“文件清单”和“测试入口清单”:文件清单保留源码定位、摘要及版本;`catalog/test-definitions.json` 根据实际 README、脚本用途和调用关系,登记测试名称、执行入口、套件/单项类型及相关文件。公开目录和首页数量均来自测试入口清单;扫描新文件不会自动新增测试项目。用户主动上传的单入口脚本仍作为新测试登记。
|
||||
|
||||
本次整理 22 个现有测试入口,加上已接入的轻量模型检查,共 23 项业务测试;其中 8 项套件、15 项单项测试。两个本控制台验收样例默认隐藏,可通过“项目用途 → 验收示例”查看。公司 GPU 套件的 224 个文件归到统一入口,其 148 个内部验证文件不再进入主列表。同类测试的不同来源实现归入相关文件,不因为源文件数量增加重复卡片。
|
||||
|
||||
同一个文件既可以是套件的组成部分,也可以在确有独立测试用途时作为单项入口;这体现不同的测试行为,不为每个辅助文件建立入口。总入口与相应完整测试流程维持原样,不在本轮拼接、改写或实际运行测试链。
|
||||
|
||||
## 数据与执行不变量
|
||||
|
||||
- 原 SQLite schema v1、脚本/版本/运行 ID、历史名称和结果文件均保留。本轮不做数据库结构迁移、回填或历史重写。
|
||||
- 目录是对现有记录的只读整理。第一次显示使用清单中的业务名称;用户保存后的名称/说明优先。后续运行记录保存对应测试名称,执行仍只有原始入口文件。
|
||||
- 详情增加相关文件只读查看;内部文件不能通过旧详情链接或直接 API 被配置/启用/运行。现有记录查询、日志、结果下载与取消仍按原运行 ID 工作。
|
||||
- 未开启 GPU 或服务管理能力;未就绪项目保持待配置。清单不是执行授权,不能据此运行历史脚本中的启停或整机测试步骤。
|
||||
- 所有上传版本和原文件仍按原路径保存,没有批量复制、合并或删除。
|
||||
|
||||
## API 与维护方式
|
||||
|
||||
`GET /api/scripts` 现返回业务测试入口,`include_examples=true` 包含验收示例。原路径保留,条目增加 is_test/test_kind/category/file_count;`GET /api/scripts/{id}/files` 提供只读相关文件。`GET /api/scripts/{id}` 仍可读取内部文件,但 is_test=false;这类文件的修改/运行 API 明确拒绝。summary.scripts/ready 统计业务测试,新增 source_files/examples 说明其他数量。
|
||||
|
||||
维护者新增已有套件时,应先核对真实执行入口与测试目的,再编辑测试入口清单和相关文件映射。不能按目录名、所有 .py 文件或自动 import 扫描结果直接推断测试项目。新来源和新执行环境仍沿用原有权限与部署流程。
|
||||
|
||||
升级采用新镜像替换网页容器,私有 worker 与模型服务不重启。更新前备份原源码、镜像信息、SQLite,并记录历史/源文件摘要;验证失败恢复原网页容器,不回写备份数据库。旧版本可继续读取原 schema v1,应用回退无需数据恢复;数据快照恢复仍须单独确认并保留快照后记录。
|
||||
@@ -0,0 +1,25 @@
|
||||
# ADR 0004:可信原入口复用原环境,上传脚本保持隔离
|
||||
|
||||
日期:2026-10-13;状态:按用户明确授权实施。补充 ADR 0002 的执行边界。
|
||||
|
||||
## 目标与决策
|
||||
|
||||
现有测试依赖宿主 Python、原模型配置、Docker 和交互菜单,统一放进轻量容器无法保持原行为。网页登记固定原入口,参数只允许方案声明的类型和范围;不改原脚本、原配置或素材。`catalog/native-profiles.json` 是管理员维护的可信方案,上传代码不能使用宿主模式。
|
||||
|
||||
网页只负责展示、参数配置、逐次影响确认和记录。宿主 worker 通过私有 0600 Unix socket 校验入口、来源摘要、参数、计划摘要与确认,创建 `adamwen-native-<run_id>.service`。网页没有 Docker socket 或任意命令入口,既有 LAN 访问范围与无账号安排不变。
|
||||
|
||||
服务独立于 HTTP 连接和 worker 生命周期。worker 重启后关联同一服务;未确认结束时保留队列占位,不自动补跑。超时/取消等待本次 cgroup 收尾后释放占位。Docker daemon 或 tmux 分离任务需要另行核对;前后资源快照只是变化证据,不能据此自动删容器或声明恢复模型。当前控制台单并发不能阻止维护者在控制台之外同时运行任务。
|
||||
|
||||
菜单以有控制终端的 PTY 运行,关闭回显,只接收数字选项/列表、y/n/q、空行。禁止控制键和任意命令,避免菜单通道变成宿主终端。需要其他输入的高级维护操作不在本控制台范围内。
|
||||
|
||||
秘密仅在宿主内存读取;标准输出、文件日志及文本归档按已知秘密流式脱敏。输出保留在原处,平台归档新增/变更文件;固定文件名会覆盖历史的容量/成本方案先做本项目私有备份。保留采集/归档上限并显示未归档原因,不把归档当成整个原工作区备份。
|
||||
|
||||
## 数据迁移与恢复
|
||||
|
||||
SQLite 保持 schema v1,仅增加 JSON 配置和运行快照字段。`deploy/native_profiles.py` 对已有 22 个入口做单事务配置迁移,保留 ID、versions 和 runs;拒绝活动任务或并发配置变化。先备份 SQLite 和旧源码,再执行;逐条 before/after 保存在私有迁移清单。隔离生产库副本已验证迁移、幂等及精确配置恢复,历史记录不改变。
|
||||
|
||||
回退必须先停止接单并确认无排队/运行中的 native 服务,再停止 worker,按迁移清单恢复配置以及匹配的旧 worker 源码和网页镜像。若配置有后续修改,恢复工具拒绝覆盖,须人工核对。新运行历史和结果继续保留;应用回退不恢复旧数据库。不可让旧 worker 处理仍活动的新模式任务。
|
||||
|
||||
## 验证范围
|
||||
|
||||
方案接入、只读预检、参数/权限边界、模拟及真实短进程生命周期已验证。原项目的 GPU、长稳和模型切换业务不在本轮实际运行,页面如实提示。后续只有在用户实际发起并确认相应影响时才执行原项目测试。
|
||||
@@ -0,0 +1,67 @@
|
||||
# 当前控制台操作与维护
|
||||
|
||||
核对日期:2026-10-13。当前源代码入口为本项目 `console/`;部署根为 `/adamwen-work-space/xas-test-library`。历史 Rundeck 文档不再是日常维护入口。
|
||||
|
||||
## 日常使用
|
||||
|
||||
内网入口 `http://10.88.118.188:14440/`,不设置账号。允许 `10.88.0.0/17` 和 `10.20.0.0/21`。所有访问者共享管理与执行权限,运行记录保存来源 IP,不区分个人身份。
|
||||
|
||||
1. 在测试项目中按用途、套件/单项、来源和状态筛选。一项对应一个测试行为,详情的“执行入口”和“相关文件”均只读。
|
||||
2. 上传 `.py` 或 `.sh` 创建托管脚本;修改时上传新版本,旧版本保留。只接受 UTF-8,单文件最大 1 MiB。素材、模型、第三方包不会随脚本自动取得。
|
||||
3. 在详情修改名称、说明、已开放的参数和超时,再保存并运行。22 项已登记原入口使用原环境方案,工作目录、解释器、命令模板和输出规则只读。普通测试预检通过后提交;涉及资源占用或服务启停的测试须逐次确认影响。
|
||||
4. 运行页查看持续刷新的标准输出/错误与文件日志,结束后预览/下载 JSON、文本或其他报告。历史保留本次配置、版本和摘要。
|
||||
|
||||
托管脚本工作目录为本次独立 `/work`,通过 `XAS_RUN_DIR` 环境变量取得它;将输出写到此目录即可归档,其中 `.log` 的新增内容会进入实时日志。原环境测试直接使用原文件、目录、依赖和已登记配置,不修改原代码。原输出照常产生,平台仅归档本次观察到的新增/变更内容;多人同时写同一原文件时无法证明内容只来自本次测试。容量和成本链路会覆盖固定文件名,启动前把已存在的相关输出备份到本次 `previous-outputs/`;其他方案优先采用原入口支持的运行编号参数。
|
||||
|
||||
现有 307 个 `.py`/`.sh` 文件包括入口和辅助模块,按已核对的用途整理为 23 个测试项目,不再全部平铺。22 个原环境入口和已有复制版轻量检查已配置;两个控制台样例在“项目用途 → 验收示例”查看。相关文件不能单独启用或运行。原环境复用宿主环境,上传脚本继续使用 Python 标准库、Bash、curl 的受限容器,无 GPU;不自动安装依赖或启动缺失模型服务。
|
||||
|
||||
“已配置”表示有启动方案,不表示服务已在线或测试已通过。运行前只读预检核对入口摘要、原配置、工具、素材及所需 TCP 端口,不发模型推理、不预留 GPU。2026-10-13 23:27 有 6 项因原模型端口未监听被拦截。整机/服务测试的影响确认只对本次源码、参数和方案有效。长稳测试最高 72 小时;原菜单支持数字选项/列表、y/n/q、空行回车,输入不回显、不保存。不能通过菜单发送 shell 命令、控制键、密码或令牌。
|
||||
|
||||
“DeepSeek V4.1 轻量功能检查(已复制)”使用原始 smoke.sh,源码摘要固定,兼容环境不可在网页修改。一次最多 1 个 models GET 和 3 个 completion POST,固定模型、最多 512 token/问答;禁止重定向和重试。新代码不能直接沿用这个认证环境,应新建脚本后接入。
|
||||
|
||||
## 数据与配额
|
||||
|
||||
| 内容 | 服务器位置 |
|
||||
|---|---|
|
||||
| 数据库 | runtime/console-data/console.sqlite3 |
|
||||
| 上传脚本版本 | runtime/library/<脚本ID>/versions/<版本>/<文件名> |
|
||||
| 运行日志 | runtime/runs/<运行ID>/console.log |
|
||||
| 运行结果/源码快照 | runtime/runs/<运行ID>/artifacts/,下载名称由数据库映射 |
|
||||
| 容器临时文件 | runtime/runs/<运行ID>/work,128 MiB tmpfs,归档后卸载 |
|
||||
| 原环境运行与输出保护 | runtime/runs/<运行ID>/,原输出仍在原目录,固定名称旧结果另存 previous-outputs/ |
|
||||
| 原环境私有控制通道 | runtime/native-ipc/control.sock,0600,仅本机网页/worker 使用 |
|
||||
| 切换前快照 | runtime/backups/before-dedicated-20261013/ |
|
||||
|
||||
数据库没有保存完整脚本、完整日志或完整报告正文。容器任务有单文件源码快照;原环境任务保留源文件摘要、实际命令与方案快照,源文件留在原处。外部结果原文件保留,同时归档本次变化内容用于历史查询。历史归档不会因原文件下次覆盖而变化。
|
||||
|
||||
共享队列单并发、最多排队 20 项。容器任务限制 1 CPU、512 MiB、64 进程,时限 5–7200 秒;原环境任务不套用这些 CPU/内存限额,时限 5 秒至 72 小时,真实资源占用遵循原项目。平台日志最大 16 MiB;结果单文件最大 32 MiB、总归档约 64 MiB、最多 63 个文件另加摘要。原环境登记输出最多 4096 文件,超过时明确失败,不静默遍历整个磁盘。
|
||||
|
||||
超过归档限制的原位置文件保留;容器未归档临时结果随 tmpfs 释放,原环境工作目录保留。容器运行检查磁盘 10 GiB 下限及原输出增长 128 MiB 软限制;原环境不施加该增长限制,以免改变长稳行为。固定旧输出备份上限 64 GiB,且要求备份后仍有 10 GiB 余量。原环境对原目录没有硬配额,操作者需按原测试规模安排磁盘与 GPU。
|
||||
|
||||
容器任务取消/超时只管理本项目容器,worker 重启时旧容器任务标为中断、不补跑。原环境任务由独立 systemd 服务承载,worker 重启后继续跟踪同一任务;状态查询异常时保留占位,不误判结束。取消/超时终止本次本机进程,最多留 120 秒收尾,然后确认 cgroup 已结束再释放队列。
|
||||
|
||||
原脚本通过 Docker daemon 或 tmux 启动的分离任务可能继续运行,取消不等于恢复原模型,也不保证远端推理已停止。日志和结果保留前后资源变化供核对;控制台不据此自动删除容器或他人会话。正常菜单退出后如观察到新增 tmux 会话,继续跟踪其结束。退出码零仅表示入口进程正常退出,业务结论以报告为准。
|
||||
|
||||
## 部署与恢复
|
||||
|
||||
网页容器 `adamwen-script-console`;私有执行器 `adamwen-script-worker.service`;容器任务前缀 `adamwen-test-run-`;原环境服务前缀 `adamwen-native-`。初次部署使用 `deploy/dedicated.py`。`deploy/cutover_console.py` 是历史 Rundeck 切换工具,不适用于本次原环境升级。原环境方案由 `catalog/native-profiles.json` 管理,配置迁移使用 `deploy/native_profiles.py`;禁止在网页上传内容中定义宿主方案。
|
||||
|
||||
当前没有设置开机自启、定时任务或自动清理。整机重启后,按 00088 操作手册连接,核对共享资源,再启动本项目网页容器与 worker。日常可读检查 `docker logs --tail 100 adamwen-script-console`、`systemctl status adamwen-script-worker.service` 和运行摘要;不要输出模型认证文件。worker 配置只记录认证文件位置,秘密仅在内存中读取。
|
||||
|
||||
本次应用回退:先停止网页接单,确认无排队/运行任务及活动 native unit,再停止 worker。用 `deploy/native_profiles.py --restore --backup runtime/backups/before-native-20261013/native-config-migration.json` 恢复 22 项旧配置;有后续修改则工具拒绝覆盖,先核对。恢复匹配的旧 worker 源码以及保留的 `adamwen-script-console-before-native-20261013` 网页容器,再启动 worker。保留新运行记录与结果,不覆盖 SQLite;旧代码不能处理活动 native 任务。具体版本、备份与验证见原环境验收记录。回到更早 Rundeck/H2 是另一种迁移,不作为本轮普通回退路径。
|
||||
|
||||
数据恢复须另行明确:停止新网页/worker,保留故障数据副本,检查 SQLite 快照 `PRAGMA integrity_check`,将匹配时点的数据库、library、runs 作为一组恢复,验证文件摘要与引用。不能只覆盖数据库,不能自动丢弃快照后的运行。当前仅初始 schema v1,未来结构变更需新增可审查迁移,不改已执行历史迁移。
|
||||
|
||||
## 本地验证与源码管理
|
||||
|
||||
Python 3.12 隔离环境安装 `console/requirements-test.txt`,执行 `python -m unittest discover -s tests -v`。Linux 检查涵盖进程组、符号链接和 worker 收尾,Windows 会明确跳过不适用项。依赖已固定版本,网页无外部 CDN。
|
||||
|
||||
Git 远程为公司仓库 `https://code.it.aisuan.cn/wenhuadian/xas-test-library`,主分支 `main`。用户于 2026-10-14 明确授权首次提交和推送,后续 Git 历史操作仍需当前对话中的明确指令。`.local/`、`runtime/`、认证材料和服务器私有 worker 配置不进 Git;Git 不会自动拉取上传脚本或发布应用。原位置脚本按服务器路径引用,本仓库不是其他工作区的完整备份。
|
||||
|
||||
## 历史阶段:2026-10-13 20:25 导航与点击区域优化
|
||||
|
||||
项目详情顶部提供“返回测试项目”,运行详情提供“返回运行记录”;加载和错误页面同样可返回,长页面滚动时返回按钮保持可见。项目整张卡片和运行记录整行均为可点击入口;详情按钮至少 46px 高,返回按钮至少 44px 高,保留原生链接和键盘 Enter 操作。
|
||||
|
||||
修改限定于 `console/static/scripts.js`、`runs.js`、`styles.css` 及部署镜像引用。正式镜像为 `adamwen/script-console:20261013-3`,摘要 `sha256:62424bf4b9c34c986cc6831b8fc083e821fa78bbd5da8fbf89a1d9e897acd7fe`。1440px 和 390px 真实浏览器验证整卡/整行点击、返回、滚动、键盘及错误状态通过,没有页面横向溢出或 JavaScript 错误。
|
||||
|
||||
本轮未执行测试脚本或调用模型。历史记录仍为 10 条;scripts/versions/runs 数据摘要与更新前一致,worker PID 与原模型容器启动状态未改变。备份在 `runtime/backups/before-ui-navigation-20261013/`,旧网页容器 `adamwen-script-console-before-navigation-20261013` 停止保留。回退只需替换网页,不覆盖数据库或重启 worker;未实际触发回退。证据位于本地 `.local/evidence/navigation-browser.json` 和服务器 `runtime/navigation-acceptance.json`。
|
||||
@@ -0,0 +1,52 @@
|
||||
# 专用测试控制台实施方案
|
||||
|
||||
> 2026-10-13 目录展示已按用户后续确认改为“一项测试行为一个项目”,内部文件不平铺;清单与接口补充见 [ADR 0003](adr/0003-test-behavior-catalog.md)。本文其余存储和执行边界继续适用。
|
||||
|
||||
日期:2026-10-13。本文是当前维护入口,覆盖此前 Rundeck 方案的产品范围;历史验收记录继续保留。
|
||||
|
||||
## 已确认的行为
|
||||
|
||||
- 公司内网免登录;只读查看脚本代码,上传创建新脚本或不可变的新版本。
|
||||
- 登记三个已知测试目录内的 Python/Shell 脚本,不批量复制源文件。原脚本保持原位置、参数与工作目录。危险的服务管理脚本仅登记待配置。
|
||||
- 允许已登记测试按原逻辑写入原日志/结果目录;不修改源文件,不授权停止他人的模型服务。
|
||||
- 每次运行有独立记录、实时标准输出/错误、退出状态、源文件摘要和结果文件。文件型日志需登记路径才会采集。历史结果有独立归档,不覆盖原文件。
|
||||
- 数据库存元数据与状态,源文件/完整日志/报告存在文件系统,不把文件正文重复塞进数据库。
|
||||
- 上传目录 runtime/library/<脚本ID>/versions/<版本>/;运行目录 runtime/runs/<运行ID>/。
|
||||
- Git 管理控制台源码和部署配置,不在每次运行时拉取。没有提交、标签或推送授权。
|
||||
|
||||
## 架构与信任边界
|
||||
|
||||
FastAPI 提供网页/API,SQLite WAL 保存目录与队列;网页容器没有 Docker socket 或 GPU。独立宿主执行器处理单并发队列,启动有固定标签、限定资源、无 Docker socket 的临时容器。可配置的工作目录和输出路径必须位于已登记的来源目录,上传脚本只能写本次结果目录。源文件挂载只读,只有明确登记的输出目录可写。
|
||||
|
||||
所有内网用户共享权限,可上传和运行自己的代码,因此信任边界是允许访问的两个公司网段。执行容器限制宿主文件与设备,不能作为抵御恶意内网用户的完整安全平台。API 校验 Host、Origin、来源网段和专用请求头,拒绝跨站修改;不接收任意 shell 命令、环境变量、镜像或宿主挂载。
|
||||
|
||||
运行记录固定版本、配置快照与源码摘要;排队后原文件变动则拒绝执行。超时/取消只终止本次容器,不宣称远端模型推理已取消。执行器重启时只恢复/终止本项目标签容器,不自动补跑。日志、上传、结果大小与执行时长有上限。业务判定只在脚本提供明确报告时呈现;退出零只表示进程正常结束。
|
||||
|
||||
旧 smoke.sh 缺少当前服务要求的认证。为保留原代码,在其运行容器中放置仅服务本次进程的回环代理:凭据经 stdin 传递、只保留内存,固定上游地址、模型、1 次 models 与 3 次 completion,不重试。真实验收最多一轮,保留失败和截断输出。
|
||||
|
||||
## 实施和验收
|
||||
|
||||
1. 固定 API,先测试版本不可覆盖、目录边界、排队幂等与单并发、日志游标、归档和取消。
|
||||
2. 实现目录/上传/代码只读、历史、实时日志、文件下载;快速样例验证成功、失败、取消和结果。
|
||||
3. 只读扫描已知来源,配置一个轻量既有脚本。新端口 14442 并行部署,旧入口 14440 暂保留。
|
||||
4. 浏览器贯通上传、新版本、运行、日志、结果和历史;在模型服务仍正常的条件下执行一次有界 smoke。
|
||||
5. 验收后切换 14440 的项目入口,保留旧容器/数据和明确回退路径。未通过则保留新预览并如实报告。
|
||||
|
||||
## 前后端接口契约 v1
|
||||
|
||||
JSON 错误 `{detail: string}`。修改请求必须含 `X-XAS-Console: 1`。所有时间为 UTC ISO。
|
||||
|
||||
- GET `/api/summary`: `{scripts, ready, runs, active, worker:{online,last_seen}, storage:{run_bytes}, limits:{...}}`
|
||||
- GET `/api/scripts`: `{items:[Script]}`;GET `/api/scripts/{id}`: Script(含 versions)
|
||||
- Script: `{id,name,description,kind:'managed'|'external',language:'python'|'shell',source_path,source_group,status:'ready'|'needs_configuration'|'missing',enabled,reason,version,sha256,updated_at,config:{args:[],cwd:'',output_paths:[],timeout_seconds:300,profile:'standard'|'legacy_smoke'},versions:[{version,sha256,created_at,filename}]}`
|
||||
- GET `/api/scripts/{id}/code?version=`: `{code,filename,sha256,truncated,redacted}`;GET `/api/scripts/{id}/download?version=` 返回只读源文件(含秘密的文件拒绝下载)
|
||||
- POST `/api/scripts/upload`: multipart `file`, `name`, `description`(新建);POST `/api/scripts/{id}/versions`: multipart `file`(仅 managed);返回 Script。
|
||||
- PATCH `/api/scripts/{id}`: `{name?,description?,enabled?,config?:{args?,cwd?,output_paths?,timeout_seconds?}}`;不允许更新代码、profile、路径来源或版本。
|
||||
- POST `/api/discover`: 返回 `{registered,missing,total}`,仅扫描预设来源。
|
||||
- POST `/api/scripts/{id}/runs`: `{request_id:UUID}`,返回 Run;重复请求返回同一记录。运行采用当前登记配置和版本。
|
||||
- GET `/api/runs?script_id=&limit=100`: `{items:[Run]}`;GET `/api/runs/{id}`: Run。
|
||||
- Run: `{id,script_id,script_name,version,sha256,state:'queued'|'running'|'succeeded'|'failed'|'cancelled'|'timed_out'|'interrupted',created_at,started_at,finished_at,exit_code,message,config,artifacts:[{id,name,size,kind:'text'|'json'|'file'}],synthetic,source_ip}`。
|
||||
- POST `/api/runs/{id}/cancel`: 返回 Run;GET `/api/runs/{id}/log?offset=0`: `{text,next_offset,done,truncated}`。
|
||||
- GET `/api/runs/{id}/log/download`;GET `/api/runs/{id}/artifacts/{artifact_id}`(下载);GET 同路径加 `/preview`: `{text,truncated}`。
|
||||
|
||||
网页无需外部 CDN。中文、清晰加载/空/错误状态,脚本列表筛选,详情页源码只读、配置编辑、版本上传、运行记录。运行页轮询日志与状态,取消只对进行中的任务显示。结果区展示文件列表、文本预览/下载。默认突出真实状态,不把模拟验收算作模型测评。
|
||||
@@ -0,0 +1,31 @@
|
||||
# XAS 测试控制台设计
|
||||
|
||||
> 历史方案:以下为 Rundeck 阶段记录,已被 [专用控制台方案](console-plan.md) 和 [当前操作说明](console-operations.md) 覆盖。不要按本文重新部署旧控制台。
|
||||
|
||||
更新日期:2026-10-13(北京时间)。用户先授权网页脚本库,随后明确要求公司内网少数人使用、暂不设置账号。最新要求覆盖初始回环网页登录方案。
|
||||
|
||||
## 目标与范围
|
||||
|
||||
Rundeck 提供任务列表、参数表单、日志和历史,源码准备为公司私有 Git 脚本库。当前只开放无 GPU 的轻量验收。现有公司套件与其他维护者脚本只登记来源,不移动、修改或开放执行。
|
||||
|
||||
## 访问与信任边界
|
||||
|
||||
入口为 10.88.118.188:14440,允许已核对的 10.88.0.0/17 服务器网和 10.20.0.0/21 办公网。Nginx 固定注入 xas-intranet 身份和 xas-operator 角色,覆盖外来身份头,拒绝跨站来源、错误 Host 和 API 令牌查询参数。
|
||||
|
||||
所有人共享执行身份,无法逐人审计;代理保留来源 IP。访客仅有本项目历史读取和已登记验收任务的 read/run/kill 权限,没有任务编辑、任意命令或系统管理权限。
|
||||
|
||||
仅隐藏后端端口不能阻止宿主机直连容器 IP。后端实际加入代理的专用网络命名空间,并只监听内部 127.0.0.1:4440;代理是唯一网络入口。宿主机 root / Docker 管理权限仍是信任边界。
|
||||
|
||||
## 执行与数据
|
||||
|
||||
运行器接受固定模式和参数,使用独占结果目录、源码 SHA-256、UTC 时间和结构化结果。模拟数据标识 synthetic=true。退出 0 但结果无效仍失败,重复编号不能覆盖历史。每次创建独立进程组,超时和取消只清理本次组并核验后代退出。
|
||||
|
||||
Rundeck 状态与业务状态分别保留:超时为 failed / timed_out,取消为 aborted / cancelled。HTTP 成功或进程启动不代表任务完成。
|
||||
|
||||
## 部署与恢复
|
||||
|
||||
只使用 /adamwen-work-space/xas-test-library,容器使用 adamwen- 前缀。后端上限 2 CPU/2 GiB,代理上限 0.25 CPU/64 MiB。无 GPU、Docker socket 或其他维护者目录挂载。不修改 Linux 账号、SSH、旧服务、防火墙、模型或计划任务。
|
||||
|
||||
当前为 H2 单实例预览,没有自启、自动备份或清理。正式 GPU 测试和多人资源调度未验证。公司 Git 远程稍后接入,不创建提交、标签或推送。
|
||||
|
||||
切换前源码、停机数据库和历史已备份,旧容器保持停止状态。应用回退不自动覆盖数据;数据恢复需核对快照后的新增记录。正式脚本接入前逐项确认维护来源、权限、GPU/服务影响、停止语义、版本及结果判定。
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 71 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 125 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 63 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
@@ -0,0 +1,45 @@
|
||||
# XAS 测试控制台实施计划
|
||||
|
||||
> 历史计划:本文件只描述已完成的 Rundeck 阶段。当前实施入口是 [console-plan.md](console-plan.md)。
|
||||
|
||||
日期:2026-10-13。设计见 design.md。当前会话内执行,遵循用户不创建 Git 历史的规则。
|
||||
|
||||
## 验收要求
|
||||
|
||||
保留现有服务和其他工作区;不使用 GPU、不调用模型;代码和服务器运行数据分开;先实现轻量验收全流程。
|
||||
|
||||
## 任务
|
||||
|
||||
- [x] 1. 运行器与验收脚本:先写失败测试,覆盖成功、失败、报告异常、重复编号、输入拒绝、超时和 Linux 子进程取消,再实现最小功能。
|
||||
- 文件:scripts/run_smoke.py、scripts/smoke_task.py、tests/test_runner.py。
|
||||
- 接口:run_smoke.py --mode MODE --run-id ID --timeout SECONDS --results-root PATH。
|
||||
- 验证:python -m unittest discover -s tests -v;Linux 上进程测试不得跳过。
|
||||
- [x] 2. Rundeck 配置:固定版本、限制资源、回环绑定、专用数据目录;生成单一白名单任务定义与外部来源目录。
|
||||
- 文件:deploy/、catalog/、README.md。
|
||||
- 验证:服务运行身份、挂载和设备可见性;任务参数校验和非授权请求拒绝。
|
||||
- [x] 3. 服务器验证:复核资源后只部署本项目,验证 API 正常、失败、报告异常、超时、取消和运行记录。
|
||||
- 证据:脱敏汇总保存于 docs/acceptance-2026-10-13.md。
|
||||
- [x] 4. 浏览器与交付:核对登录、任务、参数、日志与历史页面;交代未验证范围、访问方式和恢复方式。
|
||||
|
||||
## 重点故障
|
||||
|
||||
- 运行编号复用、路径穿越和无效模式:在创建进程前拒绝。
|
||||
- 进程正常退出但报告无效:结果失败。
|
||||
- 取消、超时与正常结束:只清理本次进程组,并核验后代退出。
|
||||
- 管理页面与脚本输入:只有登记任务可执行,普通操作角色不能执行任意命令。
|
||||
- 新容器不能访问 GPU、其他维护者目录或 Docker socket。
|
||||
|
||||
## 执行记录
|
||||
|
||||
- 10:53 只读预检查:现有 DeepSeek 容器运行,GPU 0~7 占用显存;磁盘约 1.4 TiB 可用。现有 Docker 可通过正常 sudo 使用,未安装 Compose;直接使用项目部署脚本,不修改系统工具链。
|
||||
- Final: 独立审查的 runtime 父链接越界问题已修复;test_runtime_parent_link_cannot_escape_project 与相关测试 RED→GREEN,Linux 全套 10/10 通过。
|
||||
- UI/API: 实际执行 1~6 已核验;浏览器状态伪元素造成的自动定位问题仅重读已有执行,没有重跑业务任务。
|
||||
- 交付保留项:用户私密设置网页登录密码;公司远程 Git 仓库稍后接入;正式 GPU 脚本尚未开放。
|
||||
|
||||
## 后续内网免登录调整(用户最新要求)
|
||||
|
||||
- [x] 固定访客角色与核对过的网段限制,移除密码设置工具。
|
||||
- [x] 通过共享网络命名空间和后端回环阻止宿主机直连伪造角色;回归先失败再通过。
|
||||
- [x] 保存旧容器、源码与停机数据快照;验证权限拒绝、浏览器执行 7、日志及全部历史。
|
||||
- [x] 最终 Linux 14/14,更新 README、ADR 和当前验收。
|
||||
- 原“用户设置密码”保留项被最新要求取消;Git 远程与正式 GPU 脚本仍待后续接入。
|
||||
@@ -0,0 +1,35 @@
|
||||
# 单个旧脚本接入计划
|
||||
|
||||
> 已被新方案覆盖:没有实施本文的 Rundeck/UNIX socket 集成。当前采用专用控制台与私有执行器,见 [console-plan.md](console-plan.md)。原始副本仍保持不变。
|
||||
|
||||
日期:2026-10-13。用户已选择轻量功能检查,并明确只复制一份脚本,保留写死的 GPU、端口、路径,不修改其他维护者工作区;结果和日志需在控制台可见。
|
||||
|
||||
## 范围
|
||||
|
||||
只复制 20261010-dsv41-trial/scripts/smoke.sh,字节和 SHA-256 保持一致。它包含一次模型列表 GET 和三个顺序推理请求,每个请求原有 max_tokens=512。完整 functional_check.py 含长上下文,不纳入本次。
|
||||
|
||||
新增独立 CPU 执行容器,复用现有镜像的 Bash/curl/Python,不安装模型或开启 GPU 设备。容器内回环 18100 适配原脚本固定地址,转发到已有模型服务;代理只允许固定模型、固定路径及最多三个推理请求,不自动重试。原认证文件仅单文件只读挂载,在启动时读入内存后降为现有 UID 1000;不复制密钥、不写入环境或日志。
|
||||
|
||||
Rundeck 通过项目结果目录中的专用 UNIX socket 调用固定任务。任务定义由 Git 工作区中的客户端源文件生成后导入数据库,不从 Git 自动拉取。执行容器只运行原样副本,结果保存在本项目 runtime/results/legacy/<执行编号>,日志流和中文逐项汇总回传控制台。
|
||||
|
||||
## 行为约束
|
||||
|
||||
- 原脚本只复制一个;源工作区只读。
|
||||
- 不启动、停止、重启模型服务,不更改 GPU 分配。
|
||||
- 每次最多 1 个模型列表请求、3 个推理请求,顺序执行,无自动重试;总时限 180 秒。
|
||||
- 请求转发前持久化次数;同一执行编号不重复运行,服务重启不重置记录。
|
||||
- 同时只允许一个旧脚本任务,重复或并发请求拒绝。
|
||||
- 取消关闭本次客户端和进程组,阻止新请求;已提交的上游请求取消不能保证,记录结果未知。
|
||||
- 模型结果完整性和接口成功分别判断,不能把退出 0 或截断回答当作通过;不宣称完成标准模型质量评测。
|
||||
- 密钥和上游认证头不进入命令参数、文件、Git 或网页日志。
|
||||
|
||||
## 实施步骤
|
||||
|
||||
- [ ] 原样复制并核对哈希;备份本项目受影响配置。
|
||||
- [ ] 编写并验证请求预算、结果判定、日志脱敏和旧脚本进程生命周期。
|
||||
- [ ] 配置隔离执行容器和固定 UNIX socket 客户端,登记一个网页任务。
|
||||
- [ ] 在无网络隔离容器内用模拟上游验证原脚本、超时、取消、重复编号与恢复路径。
|
||||
- [ ] 真实调用只运行一轮:1 GET + 3 推理请求,不因模型失败自动重跑。
|
||||
- [ ] 浏览器核对日志与结果;记录请求次数、原脚本哈希、原模型容器状态;更新维护说明。
|
||||
|
||||
所有 Git 改动保持未暂存、未提交、未推送。测试结果真实失败时保留失败证据,不修改原脚本参数来制造通过。
|
||||
@@ -0,0 +1,45 @@
|
||||
# 原环境执行设计与实施计划
|
||||
|
||||
日期:2026-10-13。用户已明确同意开放测试入口,并采用“普通接口直接触发;启停服务/占整机的测试显示影响并逐次确认”的方式。不修改原项目的脚本、配置和素材;运行本身仍按原逻辑产生输出及副作用。本轮验证不自动执行整机压测或启停现有模型。
|
||||
|
||||
## 业务与执行边界
|
||||
|
||||
已有项目新增 native 原环境方案:在服务器原工作目录,以已登记的解释器和固定原入口运行,复用原配置文件及现有 Docker 工具。上传脚本继续在隔离容器中运行,网页不能把任意上传代码切换为宿主执行,也不能填写任意宿主命令、账号、解释器或环境变量。
|
||||
|
||||
每个方案明确:原入口、目录、可选参数类型/范围、环境和凭据来源、输出位置、预计影响及是否需要确认。登记可读元数据在 catalog/native-profiles.json;秘密只在宿主执行时读取并保留内存,不能进 API 响应、命令行、数据库或日志。
|
||||
|
||||
Native 运行使用独立的 systemd transient service,按运行编号关联,使用原账号和目录。不套用通用容器的 1 CPU/512 MiB 限制;仅限制同一控制台单任务和总时限。默认允许最长 72 小时,超过原先两小时限制的长稳测试可按需设置。工作进程/模型的实际 CPU/GPU 仍按原项目配置。
|
||||
|
||||
运行前预检是只读的:检查入口摘要、所需文件/工具、参数和目标服务端口(TCP 连接,不发推理请求)。预检返回计划摘要,影响确认绑定源码、参数与方案版本,变化后须重新确认。开始运行保存计划与确认记录。
|
||||
|
||||
菜单型入口使用 PTY,控制台仅接受数字选项/数字列表或 y/n/q,留空发送回车。不接受 shell 命令、控制键、密码或令牌;输入不写数据库,PTY 关闭回显。需要自由文本的原工具高级维护操作继续使用原维护入口,不通过此测试控制台发送。执行器只能向已启动的本项目交互式任务传入输入。
|
||||
|
||||
取消只针对本次 transient service 的进程组/cgroup,先给原脚本收尾时间,再强制结束残留本机进程。原脚本通过 Docker daemon 创建的容器不属于本机 cgroup,控制台不擅自清理或宣称已恢复原模型。保存运行前后容器状态差异并提示核对。worker 重启后重新关联仍存活的 native service,不重跑命令、不重置尝试次数。
|
||||
|
||||
数据库沿用 schema v1,在 JSON 记录增加可选 native_options 与 execution 字段。历史记录、版本、源码文件和 ID 不改写。新原环境登记是配置更新,保留旧记录和备份;恢复旧应用前须无活动 native 任务,不能让旧执行器误处理新任务。
|
||||
|
||||
## 模块职责与实施顺序
|
||||
|
||||
- [x] 清点并登记各入口的原参数、依赖、配置、影响及缺失项;不猜测凭据/启动命令。
|
||||
- [x] 先写参数、命令注入防护、来源限制、确认失效与原文件不变等测试,再实现原环境计划生成。
|
||||
- [x] 实现独立 transient service、日志脱敏、取消/超时、输入通道及 worker 重关联;用本项目短样例验证,不运行整机任务。
|
||||
- [x] 实现只读方案展示、原参数表单、预检与逐次影响确认、交互输入和原环境运行信息。
|
||||
- [x] 集成审查、回归及真实浏览器验证,备份后更新网页/worker,核验原文件摘要和当前模型服务。
|
||||
|
||||
所有新手写源码文件不超过 500 行,无 Git 暂存、提交或推送。现有仓库没有提交,继续在当前已确认工作目录增量修改,不创建包含用户未提交内容的额外 Git 历史。
|
||||
|
||||
## 前后端接口契约
|
||||
|
||||
Script 增加 `execution`:`{mode:'native'|'container', profile_id?, interpreter?, user?, cwd?, description?, impact:{level:'standard'|'resource'|'service',title,details:[],requires_confirmation}, parameters:[{key,label,type:'integer'|'number'|'select'|'text',default,min?,max?,options?:[{value,label}],required?,help?}], interactive:boolean, max_timeout_seconds:number}`。
|
||||
|
||||
native 项目的 config 增加 `native_options:{key:value}`。旧 args/cwd/output_paths 为方案计算值,不允许网页自由改写;网页显示只读启动目录、环境说明与输出规则。可编辑参数和 timeout_seconds,以及现有名称/说明/启用状态。PATCH 仍是 `/api/scripts/{id}`,新字段位于 `config.native_options`。
|
||||
|
||||
POST `/api/scripts/{id}/preflight`,JSON `{}`,含 X-XAS-Console:1。返回 `{ready:boolean,plan_token:string,mode,command_preview:string,cwd:string,user:string,checks:[{name,ok,message}],impact:{...},interactive:boolean,output_paths:[],notes:[]}`。没有副作用,不执行原脚本。原输出中的 `{run_id}` 保持占位,队列分配编号后再解析。
|
||||
|
||||
POST `/api/scripts/{id}/runs` 扩展 `{request_id:UUID,plan_token?:string,impact_acknowledged?:boolean}`。native 必须先预检;有影响的方案必须显式确认,计划变更返回 409/400,重新预检。普通容器脚本原调用仍可用。
|
||||
|
||||
Run 增加 `execution`:`{mode,profile_id?,command_preview?,cwd?,user?,impact?,impact_acknowledged?,interactive?,unit?,verification?:...}`。默认字段缺失的历史记录按 container 展示。运行仍单并发。
|
||||
|
||||
POST `/api/runs/{id}/input`,JSON `{text:string}`;仅 native、interactive、running 状态接受,单次 <=1024 UTF-8 字节,禁止 NUL;末尾自动换行。返回 `{accepted:true}`。无需把输入保存到历史记录。拒绝任意路径、其他任务或已结束运行。用户应只输入原菜单需要的选项,不输入密码或令牌。
|
||||
|
||||
日志和结果 API 沿用现有接口。native 结果包含原命令/环境引用、源码摘要、退出状态、取消/清理说明和容器状态差异。对未完成真实 GPU/长稳业务验证的项目,页面说明“启动方案已接入,未完成本轮业务验收”。
|
||||
Reference in New Issue
Block a user